diff --git a/.github/workflows/deploy-aiat.yml b/.github/workflows/deploy-aiat.yml index b9ce2f3..e144e08 100644 --- a/.github/workflows/deploy-aiat.yml +++ b/.github/workflows/deploy-aiat.yml @@ -4,9 +4,9 @@ on: push: branches: [main] paths: + - 'icon/**' - 'web/src/sites/aiat.json' - - 'web/src/assets/aiat/**' - - 'web/src/assets/common/**' + - 'web/src/assets/**' - 'web/src/content/**' - 'web/src/templates/**' - 'web/src/types.ts' @@ -24,6 +24,8 @@ jobs: - uses: actions/setup-node@v4 with: node-version: '20' + - name: Copy icons + run: mkdir -p web/src/assets/aiat && cp icon/ai.syui.at.png web/src/assets/aiat/icon.png - run: npm install working-directory: web - run: npm run build diff --git a/.github/workflows/deploy-aicard.yml b/.github/workflows/deploy-aicard.yml index 00a555d..68c672c 100644 --- a/.github/workflows/deploy-aicard.yml +++ b/.github/workflows/deploy-aicard.yml @@ -4,9 +4,9 @@ on: push: branches: [main] paths: + - 'icon/**' - 'web/src/sites/aicard.json' - - 'web/src/assets/aicard/**' - - 'web/src/assets/common/**' + - 'web/src/assets/**' - 'web/src/content/**' - 'web/src/templates/**' - 'web/src/types.ts' @@ -24,6 +24,8 @@ jobs: - uses: actions/setup-node@v4 with: node-version: '20' + - name: Copy icons + run: mkdir -p web/src/assets/aicard && cp icon/ai.syui.card.png web/src/assets/aicard/icon.png - run: npm install working-directory: web - run: npm run build diff --git a/.github/workflows/deploy-airse.yml b/.github/workflows/deploy-airse.yml index 1042dc8..bca5177 100644 --- a/.github/workflows/deploy-airse.yml +++ b/.github/workflows/deploy-airse.yml @@ -4,6 +4,7 @@ on: push: branches: [main] paths: + - 'icon/**' - 'rse/**' workflow_dispatch: @@ -16,6 +17,8 @@ jobs: steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 + - name: Copy icons + run: mkdir -p rse/public/service && cp icon/ai.syui.at.png icon/ai.syui.card.png icon/ai.syui.rse.png rse/public/service/ - run: npm install working-directory: rse - run: npm run build diff --git a/README.md b/README.md index e69de29..1d2f8e8 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,12 @@ +## app + +|icon|name|id|text|url| +|---|---|---|---|---| +||aiat|ai.syui.at|atproto client|https://at.syui.ai| +||aicard|ai.syui.card|card game|https://card.syui.ai| +||airse|ai.syui.rse|open world game|https://rse.syui.ai| + +## privacy + +`https://${APP}.syui.ai/privacy` + diff --git a/web/src/assets/aiat/icon.png b/icon/ai.syui.at.png similarity index 100% rename from web/src/assets/aiat/icon.png rename to icon/ai.syui.at.png diff --git a/rse/public/service/ai.syui.card.png b/icon/ai.syui.card.png similarity index 100% rename from rse/public/service/ai.syui.card.png rename to icon/ai.syui.card.png diff --git a/rse/public/service/ai.syui.rse.png b/icon/ai.syui.rse.png similarity index 100% rename from rse/public/service/ai.syui.rse.png rename to icon/ai.syui.rse.png diff --git a/rse/public/account/index.html b/rse/public/account/index.html deleted file mode 100644 index 5c9fc00..0000000 --- a/rse/public/account/index.html +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - Account | Airse - - - - - - - - - - -
-
-

Account

-
-

Your SNS account is your game account.

-
-

Sign In

-
-

Sign in with your Bluesky account to access your game data.

-

Account data is managed through the AT Protocol.

-
-
-

Check Game Data

-
-

Access https://syui.ai/ and search by your username (handle).

-

For example, if your name is syui.ai, the URL will be:

-

https://syui.ai/@syui.ai/at/rse

-
-
-

Delete Game Data

-
-

Log in at https://syui.ai/, then delete the ai.syui.rse.user service.

- Bluesky OAuth -

For example, if your name is syui.ai, you can delete it from the following URL (login required):

-

https://syui.ai/@syui.ai/at/collection/ai.syui.rse.user/self

-
-
-
- - - - diff --git a/rse/public/privacy/index.html b/rse/public/privacy/index.html deleted file mode 100644 index c93ad7f..0000000 --- a/rse/public/privacy/index.html +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - Privacy Policy | Airse - - - - - - - - - - -
-
-

Privacy Policy

-
-

Airse is an open-world action game that utilizes the AT Protocol for account authentication. This Privacy Policy explains how we handle your information when you use our game.

-
-

Information Collection

-
-

We do not collect any personal information.

-

Airse does not track, store, or analyze any user data, gameplay statistics, or personal information. Your gaming experience remains private.

-
-
-

Account Authentication

-
-

Airse uses AT Protocol for account login functionality. When you log in:

-
    -
  • We only use your AT Protocol identity for authentication purposes.
  • -
  • No additional data is collected or stored beyond what is necessary for login.
  • -
  • Your credentials are handled securely through the AT Protocol.
  • -
-
-
-

syu.is Service Users

-
-
    -
  • The service operator reserves the right to suspend or terminate (ban) accounts at their discretion.
  • -
  • This may occur in cases of terms of service violations or inappropriate behavior.
  • -
  • Account suspension decisions are final.
  • -
-
-
-

Third-Party Services

-
-

Airse relies on AT Protocol infrastructure. Please refer to the privacy policies of your AT Protocol provider (PDS) for information about how they handle your data.

-
-
-

Changes to This Policy

-
-

We may update this Privacy Policy from time to time. Any changes will be posted on this page with an updated revision date.

-
-
-

Contact

-
-

If you have any questions about this Privacy Policy, please contact the developer.

-

https://github.com/syui

-
-
-
- - - - diff --git a/rse/public/service/ai.syui.at.png b/rse/public/service/ai.syui.at.png deleted file mode 100644 index b9c9eca..0000000 Binary files a/rse/public/service/ai.syui.at.png and /dev/null differ diff --git a/rse/public/support/index.html b/rse/public/support/index.html deleted file mode 100644 index dc001ca..0000000 --- a/rse/public/support/index.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - Support | Airse - - - - - - - - - - -
-
-

Support

-
-

If you have questions, feedback, or need help with Airse, please reach out through the following channels.

-
-

GitHub

-
-

Source code and issue tracker.

-

https://github.com/syui

-
-
-

Bluesky

-
-

@syui.ai

-
-
-
- - - - diff --git a/rse/public/terms/index.html b/rse/public/terms/index.html deleted file mode 100644 index 06b3343..0000000 --- a/rse/public/terms/index.html +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - Terms | Airse - - - - - - - - - - -
-
-

Terms

-
- -
-
- - - - diff --git a/rse/src/subpages.ts b/rse/src/subpages.ts new file mode 100644 index 0000000..d650259 --- /dev/null +++ b/rse/src/subpages.ts @@ -0,0 +1,290 @@ +export interface SubpageSection { + title?: { en: string; ja: string } + texts?: { en: string; ja: string }[] + list?: { en: string; ja: string }[] + html?: string +} + +export interface SubpageData { + path: string + titleEn: string + titleJa: string + introEn?: string + introJa?: string + sections: SubpageSection[] +} + +export const subpages: SubpageData[] = [ + { + path: 'account', + titleEn: 'Account', + titleJa: 'アカウント', + introEn: 'Your SNS account is your game account.', + introJa: 'SNSアカウントがゲームアカウントになります。', + sections: [ + { + title: { en: 'Sign In', ja: 'サインイン' }, + texts: [ + { en: 'Sign in with your Bluesky account to access your game data.', ja: 'Blueskyアカウントでサインインしてゲームデータにアクセスできます。' }, + { en: 'Account data is managed through the AT Protocol.', ja: 'アカウントデータはAT Protocolを通じて管理されます。' }, + ], + }, + { + title: { en: 'Check Game Data', ja: 'ゲームデータの確認' }, + texts: [ + { en: "Access https://syui.ai/ and search by your username (handle).", ja: "https://syui.ai/ にアクセスして、自分のusername(handle)で検索します。" }, + { en: "For example, if your name is syui.ai, the URL will be:", ja: "例えば、syui.aiという名前なら以下のURLになります。" }, + ], + html: '

https://syui.ai/@syui.ai/at/rse

', + }, + { + title: { en: 'Delete Game Data', ja: 'ゲームデータの削除' }, + texts: [ + { en: "Log in at https://syui.ai/, then delete the ai.syui.rse.user service.", ja: "https://syui.ai/ からログインします。そして、ai.syui.rse.userのサービスを削除します。" }, + ], + html: `Bluesky OAuth +

For example, if your name is syui.ai, you can delete it from the following URL (login required):

+

https://syui.ai/@syui.ai/at/collection/ai.syui.rse.user/self

`, + }, + ], + }, + { + path: 'privacy', + titleEn: 'Privacy Policy', + titleJa: 'プライバシーポリシー', + introEn: 'Airse is an open-world action game that utilizes the AT Protocol for account authentication. This Privacy Policy explains how we handle your information when you use our game.', + introJa: 'Airseは、AT Protocolをアカウント認証に利用するオープンワールドアクションゲームです。本プライバシーポリシーは、ゲーム利用時における情報の取り扱いについて説明します。', + sections: [ + { + title: { en: 'Information Collection', ja: '情報の収集' }, + texts: [ + { en: 'We do not collect any personal information.', ja: '個人情報は一切収集しません。' }, + { en: 'Airse does not track, store, or analyze any user data, gameplay statistics, or personal information. Your gaming experience remains private.', ja: 'Airseはユーザーデータ、ゲームプレイ統計、個人情報の追跡・保存・分析を行いません。ゲーム体験はプライベートに保たれます。' }, + ], + }, + { + title: { en: 'Account Authentication', ja: 'アカウント認証' }, + texts: [ + { en: 'Airse uses AT Protocol for account login functionality. When you log in:', ja: 'AirseはAT Protocolをアカウントログインに使用します。ログイン時:' }, + ], + list: [ + { en: 'We only use your AT Protocol identity for authentication purposes.', ja: 'AT Protocolのアイデンティティは認証目的のみに使用します。' }, + { en: 'No additional data is collected or stored beyond what is necessary for login.', ja: 'ログインに必要な範囲を超えたデータの収集・保存は行いません。' }, + { en: 'Your credentials are handled securely through the AT Protocol.', ja: '認証情報はAT Protocolを通じて安全に処理されます。' }, + ], + }, + { + title: { en: 'syu.is Service Users', ja: 'syu.isサービス利用者' }, + list: [ + { en: 'The service operator reserves the right to suspend or terminate (ban) accounts at their discretion.', ja: 'サービス運営者は、自身の裁量でアカウントの停止または終了(BAN)を行う権利を有します。' }, + { en: 'This may occur in cases of terms of service violations or inappropriate behavior.', ja: '利用規約違反や不適切な行為があった場合に行われることがあります。' }, + { en: 'Account suspension decisions are final.', ja: 'アカウント停止の判断は最終的なものです。' }, + ], + }, + { + title: { en: 'Third-Party Services', ja: '第三者サービス' }, + texts: [ + { en: 'Airse relies on AT Protocol infrastructure. Please refer to the privacy policies of your AT Protocol provider (PDS) for information about how they handle your data.', ja: 'AirseはAT Protocolのインフラに依存しています。データの取り扱いについては、ご利用のAT Protocolプロバイダー(PDS)のプライバシーポリシーをご参照ください。' }, + ], + }, + { + title: { en: 'Changes to This Policy', ja: 'ポリシーの変更' }, + texts: [ + { en: 'We may update this Privacy Policy from time to time. Any changes will be posted on this page with an updated revision date.', ja: '本プライバシーポリシーは随時更新されることがあります。変更は本ページに更新日とともに掲載されます。' }, + ], + }, + { + title: { en: 'Contact', ja: 'お問い合わせ' }, + texts: [ + { en: 'If you have any questions about this Privacy Policy, please contact the developer.', ja: '本プライバシーポリシーについてご質問がある場合は、開発者にお問い合わせください。' }, + ], + html: '

https://github.com/syui

', + }, + ], + }, + { + path: 'terms', + titleEn: 'Terms', + titleJa: '利用規約', + sections: [ + { + list: [ + { en: 'The service may be terminated at any time.', ja: 'サービスは終了することがあります。' }, + { en: 'Game data may be lost.', ja: 'ゲームデータは失われることがあります。' }, + { en: 'Accounts created on syu.is may be lost.', ja: 'syu.isに作成されたアカウントは失われることがあります。' }, + ], + }, + ], + }, + { + path: 'support', + titleEn: 'Support', + titleJa: 'サポート', + introEn: 'If you have questions, feedback, or need help with Airse, please reach out through the following channels.', + introJa: 'Airseについてのご質問、フィードバック、サポートが必要な場合は、以下からご連絡ください。', + sections: [ + { + title: { en: 'GitHub', ja: 'GitHub' }, + texts: [ + { en: 'Source code and issue tracker.', ja: 'ソースコードとイシュートラッカー。' }, + ], + html: '

https://github.com/syui

', + }, + { + title: { en: 'Bluesky', ja: 'Bluesky' }, + html: '

@syui.ai

', + }, + ], + }, +] + +const menuItems = [ + { path: '/', labelEn: 'Airse', labelJa: 'Airse' }, + { path: '/account', labelEn: 'Account', labelJa: 'アカウント' }, + { path: '/privacy', labelEn: 'Privacy', labelJa: 'プライバシー' }, + { path: '/terms', labelEn: 'Terms', labelJa: '利用規約' }, + { path: '/support', labelEn: 'Support', labelJa: 'サポート' }, +] + +function renderSection(s: SubpageSection): string { + let html = '
' + if (s.title) { + html += `

${s.title.en}

` + html += '
' + } + if (s.texts) { + for (const t of s.texts) { + html += `

${t.en}

` + } + } + if (s.list) { + html += '' + } + if (s.html) { + html += s.html + } + html += '
' + return html +} + +function renderMenu(activePath: string): string { + return menuItems.map(m => { + const active = `/${activePath}` === m.path ? ' menu-option-active' : '' + const langAttrs = m.path === '/' + ? '' + : ` data-lang-en="${m.labelEn}" data-lang-ja="${m.labelJa}"` + return `${m.labelEn}` + }).join('\n ') +} + +export function renderSubpage(page: SubpageData): string { + const intro = page.introEn + ? `

${page.introEn}

` + : '' + + const sections = page.sections.map(renderSection).join('\n ') + + return ` + + + + + + ${page.titleEn} | Airse + + + + + + + + + + +
+
+

${page.titleEn}

+
+ ${intro} + ${sections} +
+
+ + + +` +} diff --git a/rse/vite.config.ts b/rse/vite.config.ts index 8da042d..61cf812 100644 --- a/rse/vite.config.ts +++ b/rse/vite.config.ts @@ -1,4 +1,5 @@ import { defineConfig } from 'vite' +import { subpages, renderSubpage } from './src/subpages' export default defineConfig({ publicDir: 'public', @@ -6,16 +7,30 @@ export default defineConfig({ assetsInlineLimit: 0, }, appType: 'mpa', - plugins: [{ - name: 'clean-urls', - configureServer(server) { - server.middlewares.use((req, _res, next) => { - const url = req.url?.split('?')[0] ?? '' - if (url.match(/^\/[a-z]+$/) && !url.includes('.')) { - req.url = url + '/index.html' - } - next() - }) + plugins: [ + { + name: 'clean-urls', + configureServer(server) { + server.middlewares.use((req, _res, next) => { + const url = req.url?.split('?')[0] ?? '' + if (url.match(/^\/[a-z]+$/) && !url.includes('.')) { + req.url = url + '/index.html' + } + next() + }) + }, }, - }], + { + name: 'generate-subpages', + generateBundle() { + for (const page of subpages) { + this.emitFile({ + type: 'asset', + fileName: `${page.path}/index.html`, + source: renderSubpage(page), + }) + } + }, + }, + ], }) diff --git a/web/src/assets/aicard/icon.png b/web/src/assets/aicard/icon.png deleted file mode 100644 index 69a6840..0000000 Binary files a/web/src/assets/aicard/icon.png and /dev/null differ diff --git a/web/src/assets/common/favicon.png b/web/src/assets/common/favicon.png deleted file mode 100644 index b90f209..0000000 Binary files a/web/src/assets/common/favicon.png and /dev/null differ diff --git a/web/src/templates/layout.ts b/web/src/templates/layout.ts index f386faf..9df9ef7 100644 --- a/web/src/templates/layout.ts +++ b/web/src/templates/layout.ts @@ -8,7 +8,7 @@ export function layout(site: SiteConfig, title: string, content: string): string ${title} - ${site.name} - +