This commit is contained in:
Philip Cheung 2024-10-08 19:08:37 +08:00
parent b844c2a509
commit 98c1a28dfb
29 changed files with 156 additions and 39 deletions

View File

@ -3,6 +3,7 @@ import ResponsiveNav from "@/components/Navbar/ResponsiveNav";
import { fetchCourses, fetchSettings, fetchAboutus } from "@/utils"; import { fetchCourses, fetchSettings, fetchAboutus } from "@/utils";
import {AboutusProps } from "@/types"; import {AboutusProps } from "@/types";
import Home from '@/components/Aboutus/Home'; import Home from '@/components/Aboutus/Home';
async function getCourses() { async function getCourses() {
const courses = await fetchCourses(); const courses = await fetchCourses();
return courses; return courses;
@ -31,6 +32,7 @@ export default async function Page() {
return ( return (
<div className='bg-[#F6E8E9]'> <div className='bg-[#F6E8E9]'>
<ResponsiveNav courses={courses} settings={settings} /> <ResponsiveNav courses={courses} settings={settings} />
<Home settings={settings} aboutus={aboutus} /> <Home settings={settings} aboutus={aboutus} />

View File

@ -1,6 +0,0 @@
module.exports = {
colors:{
},
api_link: "http://localhost/api/v1/",
}

View File

@ -2,6 +2,7 @@ import React from 'react'
import ResponsiveNav from "@/components/Navbar/ResponsiveNav"; import ResponsiveNav from "@/components/Navbar/ResponsiveNav";
import { fetchCourses, fetchCourse, fetchSettings } from "@/utils"; import { fetchCourses, fetchCourse, fetchSettings } from "@/utils";
import dynamic from 'next/dynamic' import dynamic from 'next/dynamic'
const DynamicComponent = dynamic(() => import('@/components/Course/Course'), { const DynamicComponent = dynamic(() => import('@/components/Course/Course'), {
ssr: false, ssr: false,
}) })
@ -19,10 +20,6 @@ async function getSettings() {
return settings; return settings;
} }
export const metadata = {
title: "All In One",
description: "**",
}
export default async function Page({ params }: { params: { slug: string } }) { export default async function Page({ params }: { params: { slug: string } }) {
const courses = await getCourses(); const courses = await getCourses();
@ -34,6 +31,7 @@ export default async function Page({ params }: { params: { slug: string } }) {
} }
return ( return (
<div className='bg-[#F6E8E8]'> <div className='bg-[#F6E8E8]'>
<ResponsiveNav courses={courses} settings={settings} /> <ResponsiveNav courses={courses} settings={settings} />
<DynamicComponent course={course} settings={settings} /> <DynamicComponent course={course} settings={settings} />
</div> </div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -15,6 +15,20 @@
.mainColor{ .mainColor{
color: #D60050; color: #D60050;
} }
.navigation-loader {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: flex;
align-items: center;
justify-content: center;
background: #0006;
color: #fff;
font-size: 18px;
font-weight: 700;
}
.dots { .dots {
li{ li{

View File

@ -1,6 +1,8 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
import localFont from "next/font/local"; import localFont from "next/font/local";
import "./globals.css"; import "./globals.css";
import Head from 'next/head';
import NextTopLoader from 'nextjs-toploader';
import { Toaster } from "react-hot-toast"; import { Toaster } from "react-hot-toast";
const geistSans = localFont({ const geistSans = localFont({
src: "./fonts/GeistVF.woff", src: "./fonts/GeistVF.woff",
@ -13,9 +15,31 @@ const geistMono = localFont({
weight: "100 900", weight: "100 900",
}); });
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Create Next App", title: "All And One Music",
description: "Generated by create next app", description: "發掘你的音樂之路",
icons: [
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
url: '/favicon/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
url: '/favicon/favicon-16x16.png',
},
{
rel: 'apple-touch-icon',
sizes: '180x180',
url: '/favicon/apple-touch-icon.png',
},
],
}; };
export default function RootLayout({ export default function RootLayout({
@ -26,9 +50,12 @@ export default function RootLayout({
}>) { }>) {
return ( return (
<html lang="en"> <html lang="en">
<body <body
className={`${geistSans.variable} ${geistMono.variable} antialiased bg-[#F6E5E9]`} className={`${geistSans.variable} ${geistMono.variable} antialiased bg-[#F6E5E9]`}
> >
<link rel="icon" href="/favicon.ico" sizes="any" />
<NextTopLoader color="#D60050" height={5} />
<Toaster position="bottom-center" /> <Toaster position="bottom-center" />
{children} {children}

View File

@ -1,7 +1,7 @@
import Home from "../components/Home/Home"; import Home from "../components/Home/Home";
import { fetchCourses, fetchSettings } from "../utils/index"; import { fetchCourses, fetchSettings } from "../utils/index";
import ResponsiveNav from "../components/Navbar/ResponsiveNav"; import ResponsiveNav from "../components/Navbar/ResponsiveNav";
import Head from "next/head";
async function getCourses() { async function getCourses() {
const courses = await fetchCourses(); const courses = await fetchCourses();
@ -14,8 +14,11 @@ async function getSettings(){
} }
export const metadata = { export const metadata = {
title: "All In One", title: "All And One Music",
description: "**", description: "**",
icons: {
icon: '/favicon.ico',
},
} }
export default async function HomePage() { export default async function HomePage() {
@ -23,6 +26,8 @@ export default async function HomePage() {
const settings = await getSettings(); const settings = await getSettings();
return ( return (
<div> <div>
<link rel="icon" href="/favicon.ico" />
<ResponsiveNav courses={courses} settings={settings} /> <ResponsiveNav courses={courses} settings={settings} />
<Home courses={courses} settings={settings} /> <Home courses={courses} settings={settings} />
</div> </div>

View File

@ -75,7 +75,7 @@ const AboutusContent = ({ aboutus }: { aboutus: AboutusProps[] }) => {
/> />
</div> </div>
<div className="relative flex flex-col lg:mt-0 mt-8"> <div className="relative flex flex-col lg:mt-0 mt-8">
<p className="lg:text-4xl text-3xl"> <p className="lg:text-4xl text-2xl">
{item.title} {item.title}
</p> </p>
{/* <p className="text-base overflow-hidden mt-8"> {/* <p className="text-base overflow-hidden mt-8">

View File

@ -7,7 +7,7 @@ const Banner = () => {
<div className='flex-col flex lg:ml-48 ml-4 z-10'> <div className='flex-col flex lg:ml-48 ml-4 z-10'>
<p className='text-black lg:text-5xl text-3xl font-bold text-center'> <p className='text-black lg:text-5xl text-2xl font-bold text-center'>
{"關於我們"} {"關於我們"}
</p> </p>
<img src={"/images/line.png"} className='lg:w-[35vh] h-auto object-cover mt-2' /> <img src={"/images/line.png"} className='lg:w-[35vh] h-auto object-cover mt-2' />

View File

@ -55,7 +55,7 @@ const ContactForm = ({ startLoading, stopLoading }: Props) => {
<div className="grid lg:grid-cols-10 "> <div className="grid lg:grid-cols-10 ">
<form onSubmit={handleSubmit(onSubmit)} className="flex rounded-tl-3xl rounded-bl-3xl h-auto lg:col-span-6 items-center justify-center"> <form onSubmit={handleSubmit(onSubmit)} className="flex rounded-tl-3xl rounded-bl-3xl h-[62vh] max-sm:h-auto lg:col-span-6 items-center justify-center">
<div className="space-y-3 w-full mx-11 h-auto"> <div className="space-y-3 w-full mx-11 h-auto">
<div className="grid md:grid-cols-2 space-y-3"> <div className="grid md:grid-cols-2 space-y-3">

View File

@ -39,7 +39,7 @@ const Accordion = async ({ courseData }: { courseData: CoursesProps }) => {
<Collapse title='課程資訊' children={courseData.information} /> <Collapse title='課程資訊' children={courseData.information} />
<Collapse title='課程內容' children={courseData.contant} info={true} info_images={courseData.info_images} /> <Collapse title='課程內容' children={courseData.contant} info={true} info_images={courseData.info_images} />
<Collapse title='備註' children={courseData.remark} /> <Collapse title='備註' children={courseData.remark} />
<p className='text-5xl text-center mt-48'> <p className='lg:text-5xl text-2xl font-bold text-center mt-48'>
{"課程時間表"} {"課程時間表"}
</p> </p>
{ {

View File

@ -6,7 +6,7 @@ const Banner = ({ courseData }: { courseData: CoursesProps }) => {
<div className='relative flex w-full h-[40vh] lg:h-[70vh] bg-gradient-to-r from-[#FDB2B8] to-[#FEB3BA] items-center'> <div className='relative flex w-full h-[40vh] lg:h-[70vh] bg-gradient-to-r from-[#FDB2B8] to-[#FEB3BA] items-center'>
<div className='flex-col flex lg:ml-48 ml-4 z-10'> <div className='flex-col flex lg:ml-48 ml-4 z-10'>
<p className='text-black lg:text-5xl text-3xl font-bold text-center'> <p className='text-black lg:text-5xl text-2xl font-bold text-center'>
{courseData?.title} {courseData?.title}
</p> </p>
<img src={"/images/line.png"} className='lg:w-[35vh] w-[20vh] h-auto object-cover mt-2' /> <img src={"/images/line.png"} className='lg:w-[35vh] w-[20vh] h-auto object-cover mt-2' />

View File

@ -89,7 +89,7 @@ const Collapse: React.FC<CollapseProps> = ({ title, children, className, info, i
className={`flex justify-between items-center w-full p-6 text-left ${isOpen ? "rounded-t-lg bg-mainColor" : "rounded-lg bg-[#F2D6D5] "}`} className={`flex justify-between items-center w-full p-6 text-left ${isOpen ? "rounded-t-lg bg-mainColor" : "rounded-lg bg-[#F2D6D5] "}`}
onClick={() => setIsOpen(!isOpen)} onClick={() => setIsOpen(!isOpen)}
> >
<span className={`text-xl font-bold ml-3 ${isOpen ? "text-white " : " text-black"}`}>{title}</span> <span className={`lg:text-xl text-lg font-bold ml-3 ${isOpen ? "text-white " : " text-black"}`}>{title}</span>
{isOpen ? ( {isOpen ? (
<VscChromeMinimize className='text-white mr-3' /> <VscChromeMinimize className='text-white mr-3' />
) : ( ) : (
@ -153,7 +153,7 @@ const Collapse: React.FC<CollapseProps> = ({ title, children, className, info, i
: :
(<div></div>)} (<div></div>)}
<div <div
className='px-12 py-14 [&_*]:!text-[1.5rem] [&_*]:!text-gray-600 [&_*]:!bg-transparent' className='px-12 py-14 lg:[&_*]:!text-[1.5rem] [&_*]:!text-[1.0rem] [&_*]:!text-gray-600 [&_*]:!bg-transparent'
dangerouslySetInnerHTML={{ __html: children || '' }} dangerouslySetInnerHTML={{ __html: children || '' }}
/> />

View File

@ -125,7 +125,7 @@ const CourseImagesSilder = ({ courseData }: { courseData: CoursesProps }) => {
{courseData.images.map((image, index) => { {courseData.images.map((image, index) => {
return ( return (
<div key={index} className="px-4"> <div key={index} className="px-4">
<div key={index} className="relative h-[38vw] transition-all justify-items-center mb-16"> <div key={index} className="relative h-[45vw] transition-all justify-items-center mb-16">
<img <img
src={`${process.env.NEXT_PUBLIC_IMAGE_URL}${image.image}`} src={`${process.env.NEXT_PUBLIC_IMAGE_URL}${image.image}`}
alt={`Course Image ${index + 1}`} alt={`Course Image ${index + 1}`}

View File

@ -4,11 +4,11 @@ const LongDesc = ({ courseData }: { courseData: CoursesProps }) => {
return ( return (
<div className='w-full h-auto lg:mt-64 mt-20'> <div className='w-full h-auto lg:mt-64 mt-20'>
<div className='flex flex-col items-center justify-center mx-[5vw] lg:mx-[20vw]'> <div className='flex flex-col items-center justify-center mx-[5vw] lg:mx-[20vw]'>
<p className='text-5xl text-center'> <p className='lg:text-5xl text-xl text-center'>
{courseData.title} {courseData.title}
</p> </p>
<div <div
className='mt-10 [&_*]:!text-[1.5rem] [&_*]:!text-gray-600 [&_*]:!text-center [&_*]:!bg-transparent' className='mt-10 lg:[&_*]:!text-[1.5rem] [&_*]:!text-[1.0rem] [&_*]:!text-gray-600 [&_*]:!text-center [&_*]:!bg-transparent'
dangerouslySetInnerHTML={{ __html: courseData.long_description }} dangerouslySetInnerHTML={{ __html: courseData.long_description }}
/> />
</div> </div>

View File

@ -51,7 +51,7 @@ const ScheduleCollapse: React.FC<CollapseProps> = ({ title, rerganizedSchedule }
<div className='px-12 py-14'> <div className='px-12 py-14'>
{rerganizedSchedule.schedules.map((schedule, index) => ( {rerganizedSchedule.schedules.map((schedule, index) => (
<div key={index} className='mb-4'> <div key={index} className='mb-4'>
<h3 className='text-xl font-bold'> <h3 className='text-base font-bold'>
{ moment.utc(schedule.date).format("MM月DD日")} { moment.utc(schedule.date).format("MM月DD日")}
</h3> </h3>
<p className='text-gray-600'>{schedule.title}</p> <p className='text-gray-600'>{schedule.title}</p>

View File

@ -5,6 +5,7 @@ import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css"; import "slick-carousel/slick/slick-theme.css";
import Slider from "react-slick"; import Slider from "react-slick";
import './slick.css' import './slick.css'
import Link from "next/link";
//npm i --save-dev @types/react-slick //npm i --save-dev @types/react-slick
@ -62,12 +63,13 @@ const CoursesSilder = ({ courses }: { courses: CoursesProps[] }) => {
{course.sort_description} {course.sort_description}
</p> </p>
<div> <div>
<button <Link
className={`mt-16 middle none center rounded-full bg-[#D60050] h-12 w-28 text-base text-white shadow-md shadow-pink-500/20 transition-all hover:shadow-lg hover:shadow-pink-500/40`} className={`mt-16 flex items-center justify-center rounded-full bg-[#D60050] px-6 py-3 text-base text-white shadow-md shadow-pink-500/20 transition-all hover:shadow-lg hover:shadow-pink-500/40`}
data-ripple-light="true" data-ripple-light="true"
href={`/courses/${course.id}`}
> >
{"了解更多"} {"了解更多"}
</button> </Link>
</div> </div>
</div> </div>
</div> </div>
@ -86,12 +88,13 @@ const CoursesSilder = ({ courses }: { courses: CoursesProps[] }) => {
<p className="text-base line-clamp-3 overflow-hidden text-center mb-8"> <p className="text-base line-clamp-3 overflow-hidden text-center mb-8">
{course.sort_description} {course.sort_description}
</p> </p>
<button <Link
className="rounded-full bg-white h-12 w-28 text-sm text-black shadow-md shadow-gray-400/20 transition-all hover:shadow-lg hover:shadow-gray-500/40" href={`/courses/${course.id}`}
className="flex items-center justify-center rounded-full bg-white h-12 w-28 text-sm text-black shadow-md shadow-gray-400/20 transition-all hover:shadow-lg hover:shadow-gray-500/40"
data-ripple-light="true" data-ripple-light="true"
> >
{"了解更多"} {"了解更多"}
</button> </Link>
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,24 @@
"use client"
import React, { useState, useEffect } from 'react'
import { usePathname, useSearchParams } from 'next/navigation'
import Loading from './Loading'
// const Loader = () => (
// <div className="fixed top-0 left-0 w-screen h-screen z-[99999999999999] flex items-center justify-center bg-black/40">
// <div className="animate-spin rounded-full h-32 w-32 border-t-2 border-b-2 border-white"></div>
// </div>
// );
export default function RouteLoader() {
const pathname = usePathname()
const searchParams = useSearchParams()
const [loading, setLoading] = useState<boolean>(false)
useEffect(() => {
setLoading(true)
const timer = setTimeout(() => setLoading(false), 300) // Adjust timeout as needed
return () => clearTimeout(timer)
}, [pathname, searchParams])
return loading ? <Loading /> : null
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

25
package-lock.json generated
View File

@ -20,6 +20,7 @@
"moment": "^2.30.1", "moment": "^2.30.1",
"next": "14.2.13", "next": "14.2.13",
"nextjs-cors": "^2.2.0", "nextjs-cors": "^2.2.0",
"nextjs-toploader": "^3.7.15",
"react": "^18", "react": "^18",
"react-animate-on-scroll": "^2.1.9", "react-animate-on-scroll": "^2.1.9",
"react-dom": "^18", "react-dom": "^18",
@ -3899,6 +3900,24 @@
"next": "^8.1.1-canary.54 || ^9.0.0 || ^10.0.0-0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0" "next": "^8.1.1-canary.54 || ^9.0.0 || ^10.0.0-0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0"
} }
}, },
"node_modules/nextjs-toploader": {
"version": "3.7.15",
"resolved": "https://registry.npmjs.org/nextjs-toploader/-/nextjs-toploader-3.7.15.tgz",
"integrity": "sha512-DvvXEJVRPfE2j1HVXgFhmPl8pRcLb/4mvyVBDuYdMdkbEY7KJghp0fG5iOZ002cV6awbBw9j/Di7vQL8LRazxQ==",
"license": "MIT",
"dependencies": {
"nprogress": "^0.2.0",
"prop-types": "^15.8.1"
},
"funding": {
"url": "https://buymeacoffee.com/thesgj"
},
"peerDependencies": {
"next": ">= 6.0.0",
"react": ">= 16.0.0",
"react-dom": ">= 16.0.0"
}
},
"node_modules/normalize-path": { "node_modules/normalize-path": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@ -3909,6 +3928,12 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/nprogress": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
"integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==",
"license": "MIT"
},
"node_modules/object-assign": { "node_modules/object-assign": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",

View File

@ -21,6 +21,7 @@
"moment": "^2.30.1", "moment": "^2.30.1",
"next": "14.2.13", "next": "14.2.13",
"nextjs-cors": "^2.2.0", "nextjs-cors": "^2.2.0",
"nextjs-toploader": "^3.7.15",
"react": "^18", "react": "^18",
"react-animate-on-scroll": "^2.1.9", "react-animate-on-scroll": "^2.1.9",
"react-dom": "^18", "react-dom": "^18",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
public/favicon/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -0,0 +1,21 @@
{
"name": "MyWebSite",
"short_name": "MySite",
"icons": [
{
"src": "/web-app-manifest-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/web-app-manifest-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB