Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions .github/workflows/test-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@ on:
jobs:
test-deploy:
name: Test deployment
runs-on: ubuntu-latest
runs-on: [self-hosted, unicorn]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 22
cache: yarn

- name: Install dependencies
run: yarn install
- name: Test build website
run: yarn build
- name: Build website
run: DOCUSAURUS_IGNORE_SSG_WARNINGS=true yarn build
18 changes: 2 additions & 16 deletions docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,20 +132,10 @@ const config = {
type: 'localeDropdown',
position: 'right',
},
{
label: 'GitHub',
position: 'right',
href: 'https://github.com/DocsaidLab',
},
{
label: '支持我們',
position: 'right',
href: 'https://buymeacoffee.com/docsaid',
},
{
label: '關於我們',
href: '/aboutus',
position: 'right',
position: 'left',
},

],
Expand Down Expand Up @@ -196,11 +186,7 @@ const config = {
{
label: '工作日誌',
href: '/worklog',
},
{
label: '支持我們',
href: 'https://buymeacoffee.com/docsaid',
},
}
],
copyright: `Copyright © ${new Date().getFullYear()} DOCSAID.`,
},
Expand Down
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
},
"dependencies": {
"@algolia/client-search": "^4.9.1",
"@ant-design/charts": "^2.2.6",
"@ant-design/pro-card": "^2.9.6",
"@ant-design/pro-layout": "^7.22.3",
"@docsearch/react": "^3.6.0",
"@docusaurus/core": "^3.7.0",
"@docusaurus/faster": "^3.7.0",
Expand All @@ -32,15 +35,17 @@
"antd": "^5.22.2",
"apexcharts": "^4.2.0",
"axios": "^1.6.8",
"chart.js": "4.4.6",
"chart.js": "4.4.8",
"clsx": "^2.0.0",
"d3": "^7.9.0",
"fft-js": "^0.0.12",
"fourier-transform": "^1.1.2",
"framer-motion": "^12.4.7",
"gh-pages": "^6.1.0",
"hull.js": "^1.0.6",
"i18next": "^23.15.1",
"mathjs": "^14.0.1",
"moment": "^2.30.1",
"prism-react-renderer": "^2.3.0",
"react": "^19.0.0",
"react-apexcharts": "^1.7.0",
Expand All @@ -56,7 +61,8 @@
"remark-math": "6",
"search-insights": "^1",
"simple-git": "^3.27.0",
"typescript": "^5.6.3"
"typescript": "^5.6.3",
"zxcvbn": "^4.4.2"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.7.0",
Expand Down
115 changes: 115 additions & 0 deletions src/components/AuthModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// /src/components/AuthModal.js
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import { Divider, Modal, Tabs, Typography } from "antd";
import React, { useEffect, useState } from "react";
import useAuthHandler from "../hooks/useAuthHandler";
import ForgotPasswordForm from "./forms/ForgotPasswordForm";
import LoginForm from "./forms/LoginForm";
import RegisterForm from "./forms/RegisterForm";

/**
* 簡易字典,可根據專案需求擴充
*/
const i18nTexts = {
"zh-hant": {
modalTitle: "會員中心",
loginTab: "登入",
registerTab: "註冊",
backToLogin: "回到登入",
},
en: {
modalTitle: "Member Center",
loginTab: "Login",
registerTab: "Register",
backToLogin: "Back to Login",
},
ja: {
modalTitle: "会員センター",
loginTab: "ログイン",
registerTab: "新規登録",
backToLogin: "ログインに戻る",
},
};

export default function AuthModal({ visible, onCancel }) {
const { login, register, loading } = useAuthHandler();
const {
i18n: { currentLocale },
} = useDocusaurusContext();
const lang = currentLocale;
const texts = i18nTexts[lang] || i18nTexts.en; // 預設英語
const [mode, setMode] = useState("login");

// 當 modal 關閉時,自動重置模式為 "login"
useEffect(() => {
if (!visible) {
setMode("login");
}
}, [visible]);

const goToForgotPassword = () => setMode("forgotPassword");
const goToLogin = () => setMode("login");
const goToRegister = () => setMode("register");

const renderLoginContent = () => (
<LoginForm
onLogin={login}
loading={loading}
onSuccess={onCancel}
onToggleForgotPassword={goToForgotPassword}
/>
);

const renderRegisterContent = () => (
<RegisterForm
onLogin={login}
onRegister={register}
loading={loading}
onSuccess={onCancel}
/>
);

const renderForgotPasswordContent = () => (
<>
<ForgotPasswordForm onSuccess={onCancel} />
<Divider />
<Typography.Text
style={{ cursor: "pointer", color: "#1890ff" }}
onClick={goToLogin}
>
{texts.backToLogin}
</Typography.Text>
</>
);

return (
<Modal
open={visible}
title={texts.modalTitle} // 動態顯示標題
onCancel={onCancel}
footer={null}
>
{/* 若當前是忘記密碼模式,就不使用 Tabs */}
{mode === "forgotPassword" ? (
renderForgotPasswordContent()
) : (
<Tabs
activeKey={mode}
onChange={(key) => setMode(key)}
items={[
{
key: "login",
label: texts.loginTab, // 動態顯示「登入」
children: renderLoginContent(),
},
{
key: "register",
label: texts.registerTab, // 動態顯示「註冊」
children: renderRegisterContent(),
},
]}
/>
)}
</Modal>
);
}
48 changes: 48 additions & 0 deletions src/components/Dashboard/ApiDocs/ApiUsageExamples.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// src/components/Dashboard/ApiDocs/ApiUsageExamples.jsx
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import { Card, Collapse, Divider, Tabs, Tag, Typography } from "antd";
import React from "react";
import DocAligner from "./apis/DocAligner";
import MrzScanner from "./apis/MrzScanner";
import styles from "./index.module.css"; // 確保引入新的 CSS
import ParamList from "./ParamList";

const { Panel } = Collapse;
const { Paragraph, Text } = Typography;

export default function ApiUsageExamples() {
const {
i18n: { currentLocale },
} = useDocusaurusContext();

// 從各個 API 檔案根據當前語系取得定義
const apiDefinitions = [DocAligner(currentLocale), MrzScanner(currentLocale)];

return (
<Collapse style={{ marginTop: 24 }} accordion defaultActiveKey={[apiDefinitions[0].key]}>
{apiDefinitions.map((apiDef) => (
<Panel
key={apiDef.key}
header={
<div className={styles.panelHeaderWrapper}>
<Text strong>{apiDef.title}</Text>
<Tag color="blue">{apiDef.route}</Tag>
</div>
}
>
<Card styles={{ body: { padding: "16px 24px" } }}>
<Paragraph>{apiDef.overview}</Paragraph>
<Divider orientation="left" style={{ marginTop: 24 }}>
{apiDef.text.parameters}
</Divider>
<ParamList data={apiDef.params} text={apiDef.text} />
<Divider orientation="left" style={{ marginTop: 32 }}>
{apiDef.text.codeExamples}
</Divider>
<Tabs defaultActiveKey={apiDef.codeExamples[0].key} size="small" items={apiDef.codeExamples} />
</Card>
</Panel>
))}
</Collapse>
);
}
55 changes: 55 additions & 0 deletions src/components/Dashboard/ApiDocs/CodeBlock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// src/components/Dashboard/ApiDocs/CodeBlock.jsx
import { CopyOutlined } from "@ant-design/icons";
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import { Button, Tooltip } from "antd";
import React, { useState } from "react";
import styles from "./index.module.css";

const i18n = {
"zh-hant": {
copy: "複製程式碼",
copied: "已複製",
},
en: {
copy: "Copy Code",
copied: "Copied",
},
ja: {
copy: "コードをコピー",
copied: "コピー済み",
},
};

export default function CodeBlock({ codeStr }) {
const {
i18n: { currentLocale },
} = useDocusaurusContext();
const localeText = i18n[currentLocale] || i18n.en;
const [copied, setCopied] = useState(false);

const handleCopy = async () => {
try {
await navigator.clipboard.writeText(codeStr);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch (error) {
console.error("複製失敗", error);
}
};

return (
<div className={styles.codeBlockContainer}>
<Tooltip title={copied ? localeText.copied : localeText.copy} placement="top">
<Button
className={styles.copyButton}
type="text"
icon={<CopyOutlined />}
onClick={handleCopy}
/>
</Tooltip>
<pre className={styles.codeBlock}>
<code>{codeStr}</code>
</pre>
</div>
);
}
38 changes: 38 additions & 0 deletions src/components/Dashboard/ApiDocs/ParamList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// src/components/Dashboard/ApiDocs/ParamList.jsx
import { List, Tag, Typography } from "antd";
import React from "react";
import styles from "./index.module.css";

const { Text } = Typography;

export default function ParamList({ data, text }) {
return (
<List
className={styles.paramList} // 可在 CSS 中定義 margin-top 等間距
itemLayout="vertical"
dataSource={data}
renderItem={(item) => {
const { name, type, required, default: defaultVal, desc } = item;
return (
<List.Item key={name} className={styles.paramListItem}>
<List.Item.Meta
title={
<span className={styles.paramTitle}>
<Text code>{name}</Text>{" "}
{type && <Tag color="blue">{type}</Tag>}
{required && <Tag color="red">{text.requiredLabel}</Tag>}
{defaultVal && defaultVal !== "-" && (
<Tag color="green">
{text.defaultLabel}: {defaultVal}
</Tag>
)}
</span>
}
description={<span className={styles.paramDesc}>{desc}</span>}
/>
</List.Item>
);
}}
/>
);
}
Loading