From abf350aa6b2f690a890bf5e26c70367e6c283f5d Mon Sep 17 00:00:00 2001 From: hansoo Date: Tue, 14 Apr 2026 00:16:59 +0900 Subject: [PATCH] feat: added reject image and migrated to tailwindcss feat: made it smartphone friendly --- build.sh | 2 +- nextjs/next.config.mjs | 3 - nextjs/package.json | 7 +- nextjs/postcss.config.js | 6 + nextjs/src/app/(site)/about/page.tsx | 21 +- nextjs/src/app/(site)/page.tsx | 50 +- nextjs/src/app/(site)/players/page.tsx | 34 +- .../[tournament_key]/players/page.tsx | 36 +- .../[tournament_key]/scoreboard/page.tsx | 6 +- .../archive/ArchiveAdminClient.tsx | 61 +- .../(dashboard)/guide/GuideAdminClient.tsx | 76 ++- nextjs/src/app/admin/(dashboard)/page.tsx | 34 +- .../players/PlayersAdminClient.tsx | 92 +-- .../admin/(dashboard)/qa/QaAdminClient.tsx | 58 +- .../(dashboard)/users/UsersAdminClient.tsx | 28 +- nextjs/src/app/admin/layout.tsx | 22 +- nextjs/src/app/admin/login/page.tsx | 22 +- nextjs/src/app/admin/no-access/page.tsx | 8 +- nextjs/src/app/admin/pending/page.tsx | 8 +- nextjs/src/app/admin/register/page.tsx | 24 +- nextjs/src/app/globals.css | 29 +- nextjs/src/app/layout.tsx | 1 - nextjs/src/components/ArchiveVideoList.tsx | 14 +- nextjs/src/components/ContactList.tsx | 17 +- nextjs/src/components/GuideVideoList.tsx | 14 +- nextjs/src/components/PlayersList.tsx | 108 ++- nextjs/src/components/SiteLayout.tsx | 122 ++-- nextjs/src/components/admin/LogoutButton.tsx | 4 +- nextjs/src/lib/adminUi.ts | 54 ++ nextjs/src/lib/characterPortrait.ts | 32 + nextjs/src/lib/data.ts | 72 +- nextjs/src/lib/siteContentClasses.ts | 19 + nextjs/src/styles/admin.module.scss | 141 ---- nextjs/src/styles/web.module.scss | 623 ------------------ nextjs/tailwind.config.ts | 47 ++ 35 files changed, 788 insertions(+), 1107 deletions(-) create mode 100644 nextjs/postcss.config.js create mode 100644 nextjs/src/lib/adminUi.ts create mode 100644 nextjs/src/lib/characterPortrait.ts create mode 100644 nextjs/src/lib/siteContentClasses.ts delete mode 100644 nextjs/src/styles/admin.module.scss delete mode 100644 nextjs/src/styles/web.module.scss create mode 100644 nextjs/tailwind.config.ts diff --git a/build.sh b/build.sh index 822f9fa..d65fe7b 100644 --- a/build.sh +++ b/build.sh @@ -1,2 +1,2 @@ -APP_VERSION=1.0.2 +APP_VERSION=1.0.3 docker buildx build --platform linux/arm64 -f nextjs/Dockerfile -t cfc-web:$APP_VERSION . \ No newline at end of file diff --git a/nextjs/next.config.mjs b/nextjs/next.config.mjs index 9e53c8e..50cab61 100644 --- a/nextjs/next.config.mjs +++ b/nextjs/next.config.mjs @@ -7,9 +7,6 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)); const nextConfig = { output: 'standalone', outputFileTracingRoot: path.join(__dirname, '..'), - sassOptions: { - includePaths: ['src/styles'], - }, }; export default nextConfig; diff --git a/nextjs/package.json b/nextjs/package.json index 555eab5..25d7a4d 100644 --- a/nextjs/package.json +++ b/nextjs/package.json @@ -17,17 +17,18 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-i18next": "^14.1.0", - "react-youtube": "^10.1.0", - "semantic-ui-css": "^2.5.0" + "react-youtube": "^10.1.0" }, "devDependencies": { "@types/bcryptjs": "^2.4.6", "@types/node": "^20.14.10", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", + "autoprefixer": "^10.4.27", "eslint": "^8.57.0", "eslint-config-next": "^15.5.14", - "sass": "^1.77.8", + "postcss": "^8.4.31", + "tailwindcss": "^3.4.19", "typescript": "^5.5.4" } } diff --git a/nextjs/postcss.config.js b/nextjs/postcss.config.js new file mode 100644 index 0000000..33ad091 --- /dev/null +++ b/nextjs/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/nextjs/src/app/(site)/about/page.tsx b/nextjs/src/app/(site)/about/page.tsx index b9bc992..354be86 100644 --- a/nextjs/src/app/(site)/about/page.tsx +++ b/nextjs/src/app/(site)/about/page.tsx @@ -1,12 +1,12 @@ -import style from '@/styles/web.module.scss'; +import { guideBody } from '@/lib/siteContentClasses'; export default function AboutPage() { return ( -
-

About

+
+

About


-
-
+
+

Covid-19 の影響で、オフライン大会の実施なども困難であるため、オンラインによるランキングバトル(通称:ストレイシープ杯)を開催することになりました。 @@ -22,9 +22,14 @@ export default function AboutPage() { もっとこうしてみては?次の大会から参加したい!などございましたら問い合わせフォームからご意見下さい!

それでは、楽しんでいくめぇ。~

-
-
- +
+ diff --git a/nextjs/src/app/(site)/page.tsx b/nextjs/src/app/(site)/page.tsx index fe86754..3148a63 100644 --- a/nextjs/src/app/(site)/page.tsx +++ b/nextjs/src/app/(site)/page.tsx @@ -1,27 +1,41 @@ -import style from '@/styles/web.module.scss'; - export default function HomePage() { return ( -
-
-
-
-
-
-
- -   - +
+
+
+
+
+
+
+
+
- -
-
+
+
; +type PageProps = { + searchParams: Promise<{ page?: string }>; +}; + +export default async function PlayersPage({ searchParams }: PageProps) { + const { page: pageRaw } = await searchParams; + const parsed = parseInt(pageRaw ?? '1', 10); + const page = Number.isFinite(parsed) && parsed >= 1 ? Math.floor(parsed) : 1; + + const { players, total } = await getAllPlayersPaged(page); + const totalPages = Math.max(1, Math.ceil(total / PLAYERS_PAGE_SIZE)); + + if (page > totalPages) { + redirect(totalPages <= 1 ? '/players' : `/players?page=${totalPages}`); + } + + return ( + + ); } diff --git a/nextjs/src/app/(site)/tournaments/[tournament_key]/players/page.tsx b/nextjs/src/app/(site)/tournaments/[tournament_key]/players/page.tsx index 07cd7ba..3abe018 100644 --- a/nextjs/src/app/(site)/tournaments/[tournament_key]/players/page.tsx +++ b/nextjs/src/app/(site)/tournaments/[tournament_key]/players/page.tsx @@ -1,19 +1,43 @@ -import { notFound } from 'next/navigation'; +import { notFound, redirect } from 'next/navigation'; import { PlayersList } from '@/components/PlayersList'; -import { getPlayersForTournament } from '@/lib/data'; +import { getPlayersForTournamentPaged, PLAYERS_PAGE_SIZE } from '@/lib/data'; export const dynamic = 'force-dynamic'; type PageProps = { params: Promise<{ tournament_key: string }>; + searchParams: Promise<{ page?: string }>; }; -export default async function TournamentPlayersPage({ params }: PageProps) { +export default async function TournamentPlayersPage({ params, searchParams }: PageProps) { const { tournament_key } = await params; - const players = await getPlayersForTournament(tournament_key); - if (players === null) { + const { page: pageRaw } = await searchParams; + const parsed = parseInt(pageRaw ?? '1', 10); + const page = Number.isFinite(parsed) && parsed >= 1 ? Math.floor(parsed) : 1; + + const result = await getPlayersForTournamentPaged(tournament_key, page); + if (result === null) { notFound(); } - return ; + + const { players, total } = result; + const totalPages = Math.max(1, Math.ceil(total / PLAYERS_PAGE_SIZE)); + const basePath = `/tournaments/${encodeURIComponent(tournament_key)}/players`; + + if (page > totalPages) { + redirect(totalPages <= 1 ? basePath : `${basePath}?page=${totalPages}`); + } + + return ( + + ); } diff --git a/nextjs/src/app/(site)/tournaments/[tournament_key]/scoreboard/page.tsx b/nextjs/src/app/(site)/tournaments/[tournament_key]/scoreboard/page.tsx index 7264a23..465b4e5 100644 --- a/nextjs/src/app/(site)/tournaments/[tournament_key]/scoreboard/page.tsx +++ b/nextjs/src/app/(site)/tournaments/[tournament_key]/scoreboard/page.tsx @@ -1,9 +1,9 @@ -import style from '@/styles/web.module.scss'; +import { mainBody } from '@/lib/siteContentClasses'; export default function ScoreboardPage() { return ( -
-
+
+
); } diff --git a/nextjs/src/app/admin/(dashboard)/archive/ArchiveAdminClient.tsx b/nextjs/src/app/admin/(dashboard)/archive/ArchiveAdminClient.tsx index 01d5c53..a8df75c 100644 --- a/nextjs/src/app/admin/(dashboard)/archive/ArchiveAdminClient.tsx +++ b/nextjs/src/app/admin/(dashboard)/archive/ArchiveAdminClient.tsx @@ -4,7 +4,20 @@ import { useCallback, useEffect, useState } from 'react'; import Link from 'next/link'; -import style from '@/styles/admin.module.scss'; +import { + btn, + btnDanger, + card, + error as errorClass, + formWide, + hr, + input, + label, + rowActions, + sectionBlock, + sectionTitle, + title, +} from '@/lib/adminUi'; type ArchiveRow = { id: number; @@ -16,7 +29,7 @@ export function ArchiveAdminClient() { const [items, setItems] = useState([]); const [error, setError] = useState(''); const [loading, setLoading] = useState(true); - const [title, setTitle] = useState(''); + const [titleVal, setTitleVal] = useState(''); const [youtubeId, setYoutubeId] = useState(''); const load = useCallback(async () => { @@ -75,70 +88,68 @@ export function ArchiveAdminClient() { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', - body: JSON.stringify({ title, youtube_id: youtubeId }), + body: JSON.stringify({ title: titleVal, youtube_id: youtubeId }), }); const data = await res.json().catch(() => ({})); if (!res.ok) { setError((data as { error?: string }).error ?? 'Create failed'); return; } - setTitle(''); + setTitleVal(''); setYoutubeId(''); await load(); } return ( -
+

← Dashboard

-

Archive

- {error ?

{error}

: null} +

Archive

+ {error ?

{error}

: null} {loading ?

Loading…

: null} {!loading && items.map((row) => ( -
-