diff --git a/src/routes/about/+page.svelte b/src/routes/about/+page.svelte
index 775cc7ed0..f7c6d18ec 100644
--- a/src/routes/about/+page.svelte
+++ b/src/routes/about/+page.svelte
@@ -1,174 +1,26 @@
-
- 特長
-
- {#each features as feature}
- {feature.description}
- {/each}
-
-
-
-
- 予備知識
-
-
-
- の
-
- まで、独力でこなせる文章読解力と基礎学力がある。
-
-
-
-
-
- 対象ユーザ
-
-
- 記事
-
- を読み、問題集
-
- を解いた。
-
- 茶色コーダー (レーティング400 — 799) を目指している。さらに上位を目指したい。
- 問題の解答状況を自分で記録・確認したい。
-
-
-
-
-
- 使い方
-
- (初回のみ) ユーザ名とパスワードを入力して、アカウントを作成します。
-
- ログインします。お試し用のアカウント (ユーザ名: guest、パスワード: Hell0Guest)
- を利用することもできます。
-
-
- 問題集や問題一覧で、グレードおよび問題を選び、回答欄の「更新」をクリックもしくはタップします。
-
- 該当する回答状況 (デフォルトは「未挑戦」)を選択し、「回答を更新」ボタンを押します。
-
-
-
-
-
-
- 用語集
-
-
-
- グレード (難易度)
-
-
-
-
- (易しい) 11Q、10Q、9Q、8Q、7Q、6Q、5Q、4Q、3Q、2Q、1Q、1D、2D、3D、4D、5D、6D (難しい)
-
- 注: 公開後に予告なく修正される場合があります。
-
-
-
- 回答状況の例
-
- AC:正解した
- 解説AC:公式もしくは有志の解説を読んで正解した
- 挑戦中:不正解もしくは考察中
- 未挑戦:これから問題を解く
-
-
-
-
-
-
- プライバシーポリシー
-
-
-
- 本サイトでは、アクセス解析ツール
-
- を利用しています。
-
-
-
- 同ツールでは、トラフィックデータの収集のためにCookieを使用しております。データは匿名で収集されており、個人を特定するものではありません。利用規約、および、プライバシーポリシーに関する説明は、
-
- をご覧ください。
-
-
-
- また、収集されたデータは、本サイトのサービスを改善する目的以外で利用することはありません。
-
-
-
-
-
-
-
-
-
- 開発・運営メンバー
-
-
- {#each members as member}
-
-
-
- {/each}
-
-
+ {@render sectionWithTitle('特長', coreFeatures)}
+ {@render sectionWithTitle('予備知識', requirements)}
+ {@render sectionWithTitle('対象ユーザ', targetUsers)}
+ {@render sectionWithTitle('使い方', usage)}
+ {@render sectionWithTitle('用語集', glossary)}
+ {@render sectionWithTitle('プライバシーポリシー', privacyPolicy)}
+
+ {@render sectionWithTitle('開発・運営メンバー', developmentMembers)}
diff --git a/src/routes/about/SectionSnippets.svelte b/src/routes/about/SectionSnippets.svelte
new file mode 100644
index 000000000..2ebcd44ef
--- /dev/null
+++ b/src/routes/about/SectionSnippets.svelte
@@ -0,0 +1,146 @@
+
+
+
+
+
+
+
+
+{#snippet sectionWithTitle(title: string, children: Snippet)}
+
+ {title}
+
+ {@render children()}
+
+{/snippet}
+
+
+{#snippet coreFeatures()}
+
+ {#each features as feature}
+ {feature.description}
+ {/each}
+
+{/snippet}
+
+{#snippet requirements()}
+
+
+
+ の
+
+ まで、独力でこなせる文章読解力と基礎学力がある。
+
+
+{/snippet}
+
+{#snippet targetUsers()}
+
+
+ 記事
+
+ を読み、問題集
+
+ を解いた。
+
+ 茶色コーダー (レーティング400 — 799) を目指している。さらに上位を目指したい。
+ 問題の解答状況を自分で記録・確認したい。
+
+{/snippet}
+
+{#snippet usage()}
+
+ (初回のみ) ユーザ名とパスワードを入力して、アカウントを作成します。
+
+ ログインします。お試し用のアカウント (ユーザ名: guest、パスワード: Hell0Guest)
+ を利用することもできます。
+
+
+ 問題集や問題一覧で、グレードおよび問題を選び、回答欄の「更新」をクリックもしくはタップします。
+
+ 該当する回答状況 (デフォルトは「未挑戦」)を選択し、「回答を更新」ボタンを押します。
+
+{/snippet}
+
+{#snippet glossary()}
+
+
グレード (難易度)
+
+
+
+ (易しい) 11Q、10Q、9Q、8Q、7Q、6Q、5Q、4Q、3Q、2Q、1Q、1D、2D、3D、4D、5D、6D (難しい)
+ 注: 公開後に予告なく修正される場合があります。
+
+
+
+
回答状況の例
+
+ AC:正解した
+ 解説AC:公式もしくは有志の解説を読んで正解した
+ 挑戦中:不正解もしくは考察中
+ 未挑戦:これから問題を解く
+
+{/snippet}
+
+{#snippet privacyPolicy()}
+
+
+ 本サイトでは、アクセス解析ツール
+
+ を利用しています。
+
+
+
+ 同ツールでは、トラフィックデータの収集のためにCookieを使用しております。データは匿名で収集されており、個人を特定するものではありません。利用規約、および、プライバシーポリシーに関する説明は、
+
+ をご覧ください。
+
+
+
+ また、収集されたデータは、本サイトのサービスを改善する目的以外で利用することはありません。
+
+
+{/snippet}
+
+{#snippet developmentMembers()}
+
+ {#each members as member}
+
+
+
+ {/each}
+
+{/snippet}
diff --git a/src/routes/problems/+page.svelte b/src/routes/problems/+page.svelte
index 9a469ec6c..d17326912 100644
--- a/src/routes/problems/+page.svelte
+++ b/src/routes/problems/+page.svelte
@@ -1,5 +1,5 @@
@@ -25,7 +25,7 @@
-
+
diff --git a/src/routes/problems/[slug]/+page.svelte b/src/routes/problems/[slug]/+page.svelte
index 57212ccbf..890f31a6f 100644
--- a/src/routes/problems/[slug]/+page.svelte
+++ b/src/routes/problems/[slug]/+page.svelte
@@ -1,18 +1,24 @@
+
+
+
diff --git a/src/routes/users/[username]/+page.svelte b/src/routes/users/[username]/+page.svelte
index a114b7f4b..1ab9698b5 100644
--- a/src/routes/users/[username]/+page.svelte
+++ b/src/routes/users/[username]/+page.svelte
@@ -3,7 +3,7 @@
import HeadingOne from '$lib/components/HeadingOne.svelte';
import TaskListSorted from '$lib/components/TaskListSorted.svelte';
- export let data;
+ let { data } = $props();
let username = data.username;
let atcoder_username = data.atcoder_username;
diff --git a/src/routes/users/edit/+page.svelte b/src/routes/users/edit/+page.svelte
index 586de66b5..f9054c4c0 100644
--- a/src/routes/users/edit/+page.svelte
+++ b/src/routes/users/edit/+page.svelte
@@ -1,5 +1,5 @@
@@ -148,7 +160,7 @@
出典
一言
-
+
{#each workBookTasks as workBookTask}
+ import { Breadcrumb, BreadcrumbItem } from 'svelte-5-ui-lib';
import { superForm } from 'sveltekit-superforms/client';
- import { Breadcrumb, BreadcrumbItem } from 'flowbite-svelte';
import {
WorkBookType,
@@ -10,6 +10,7 @@
import type { Task } from '$lib/types/task';
import { preventEnterKey } from '$lib/actions/prevent_enter_key';
+
import HeadingOne from '$lib/components/HeadingOne.svelte';
import WorkBookInputFields from '$lib/components/WorkBooks/WorkBookInputFields.svelte';
import WorkBookTasksTable from '$lib/components/WorkBookTasks/WorkBookTasksTable.svelte';
@@ -17,7 +18,7 @@
import InputFieldWrapper from '$lib/components/InputFieldWrapper.svelte';
import SubmissionButton from '$lib/components/SubmissionButton.svelte';
- export let data;
+ let { data } = $props();
// See:
// https://superforms.rocks/concepts/nested-data
@@ -33,7 +34,11 @@
$form.isOfficial = data.isAdmin;
$form.workBookType = $form.isOfficial ? WorkBookType.CURRICULUM : WorkBookType.CREATED_BY_USER;
- $: workBookTasksForTable = [] as WorkBookTaskCreate[];
+ let workBookTasksForTable: WorkBookTaskCreate[] = $state([]);
+
+ $effect((): void => {
+ workBookTasksForTable = [] as WorkBookTaskCreate[];
+ });
const tasksMapByIds: Map = data.tasksMapByIds;
diff --git a/src/routes/workbooks/edit/[slug]/+page.server.ts b/src/routes/workbooks/edit/[slug]/+page.server.ts
index 029c95ac8..8901a2dbf 100644
--- a/src/routes/workbooks/edit/[slug]/+page.server.ts
+++ b/src/routes/workbooks/edit/[slug]/+page.server.ts
@@ -81,7 +81,7 @@ export const actions = {
}
try {
- await workBooksCrud.updateWorkBook(workBookId, workBook);
+ await workBooksCrud.updateWorkBook(workBookId, { ...workBook, id: workBookId });
} catch (e) {
console.error(`Failed to update WorkBook with id ${workBookId}:`, e);
error(
diff --git a/src/routes/workbooks/edit/[slug]/+page.svelte b/src/routes/workbooks/edit/[slug]/+page.svelte
index 1ecda4f1f..cf99c4038 100644
--- a/src/routes/workbooks/edit/[slug]/+page.svelte
+++ b/src/routes/workbooks/edit/[slug]/+page.svelte
@@ -1,6 +1,8 @@
{#if canView}
diff --git a/svelte.config.js b/svelte.config.js
index b9f921ff9..5d7bf05ac 100644
--- a/svelte.config.js
+++ b/svelte.config.js
@@ -24,6 +24,23 @@ const config = {
'$lib/*': resolve('./src/lib/*'),
},
},
+
+ compilerOptions: {
+ runes: true,
+ },
+
+ // [Work around]
+ // SuperDebug.svelte: Cannot use `export let` in runes mode — use `$props()` instead.
+ //
+ // See:
+ // https://github.com/ciscoheat/sveltekit-superforms/issues/306#issuecomment-1891015986
+ vitePlugin: {
+ dynamicCompileOptions({ filename }) {
+ if (filename.includes('node_modules')) {
+ return { runes: undefined }; // or false, check what works
+ }
+ },
+ },
};
export default config;
diff --git a/tailwind.config.mjs b/tailwind.config.ts
similarity index 88%
rename from tailwind.config.mjs
rename to tailwind.config.ts
index 9714cf925..8380200f6 100644
--- a/tailwind.config.mjs
+++ b/tailwind.config.ts
@@ -1,18 +1,20 @@
import forms from '@tailwindcss/forms';
import flowbitePlugin from 'flowbite/plugin';
+// TODO: stwui は事実上開発が終了したと思われるため、別のライブラリに移行
import stwuiPlugin from 'stwui/plugin';
+import type { Config } from 'tailwindcss';
+
const config = {
content: [
'./src/**/*.{html,js,svelte,ts}',
- './node_modules/flowbite-svelte/**/*.{html,js,svelte,ts}',
- './node_modules/flowbite-svelte-icons/**/*.{html,js,svelte,ts}',
+ './node_modules/svelte-5-ui-lib/**/*.{html,js,svelte,ts}',
'./node_modules/stwui/**/*.{svelte,js,ts,html}',
],
plugins: [forms, flowbitePlugin, stwuiPlugin],
- darkMode: 'class',
+ darkMode: 'selector',
theme: {
extend: {
@@ -85,6 +87,6 @@ const config = {
},
},
},
-};
+} as Config;
export default config;