From 02e764809df7273404b8ce9a3df6accdaa7f6e78 Mon Sep 17 00:00:00 2001 From: qwqcode Date: Sun, 9 Jun 2024 17:32:24 +0800 Subject: [PATCH 1/2] refactor(ui): fix linter issues for ui and docs --- .github/workflows/test-docs.yml | 3 + .github/workflows/test-frontend.yml | 5 +- docs/docs/.vitepress/theme/Artalk.vue | 6 +- docs/docs/.vitepress/theme/Artransfer.vue | 5 +- docs/docs/.vitepress/theme/index.ts | 2 +- docs/landing/scripts/update-readme.ts | 4 +- docs/landing/src/Features.ts | 220 +++++++++++++++++ .../src/components/Features/FullFeature.tsx | 2 +- .../components/Features/FullFeatureList.tsx | 233 +----------------- .../src/components/Features/FuncFeature.tsx | 16 +- .../src/components/Features/QuickFeature.tsx | 8 +- .../src/components/Features/SafeFeature.tsx | 6 +- .../src/components/Features/SlightFeature.tsx | 2 +- docs/landing/src/components/LearnMoreLink.tsx | 2 +- docs/landing/src/components/Reveal.tsx | 30 ++- docs/landing/src/components/Slogan.tsx | 4 +- eslint.config.mjs | 21 +- package.json | 9 +- scripts/frontend-e2e-test.sh | 2 +- ui/artalk-sidebar/src/App.vue | 2 +- .../src/components/ItemTextEditor.vue | 4 +- .../src/components/PageEditor.vue | 2 +- .../src/components/Pagination.vue | 8 +- .../src/components/PreferenceItem.vue | 4 +- .../src/components/SiteCreate.vue | 2 +- .../src/components/SiteEditor.vue | 2 +- .../src/components/SiteSwitcher.vue | 2 +- ui/artalk-sidebar/src/components/Tab.vue | 8 +- .../src/components/UserEditor.vue | 4 +- ui/artalk-sidebar/src/main.ts | 3 +- ui/artalk-sidebar/src/pages/comments.vue | 9 +- ui/artalk-sidebar/src/pages/login.vue | 4 +- ui/artalk-sidebar/src/pages/pages.vue | 4 +- ui/artalk-sidebar/src/pages/settings.vue | 2 +- ui/artalk-sidebar/src/pages/sites.vue | 8 +- ui/artalk-sidebar/src/pages/transfer.vue | 13 +- ui/artalk-sidebar/src/pages/users.vue | 6 +- ui/artalk-sidebar/src/stores/nav.ts | 2 +- ui/artalk-sidebar/src/stores/user.ts | 2 +- ui/artalk-sidebar/vite.config.ts | 11 + ui/artalk/package.json | 16 +- ui/artalk/scripts/build-i18n.ts | 2 +- ui/artalk/src/api/fetch.ts | 2 +- ui/artalk/src/api/handler.ts | 4 +- ui/artalk/src/artalk.ts | 2 +- ui/artalk/src/comment/actions.ts | 2 +- ui/artalk/src/comment/comment-node.ts | 6 +- ui/artalk/src/comment/render.ts | 2 +- ui/artalk/src/comment/renders/actions.ts | 2 +- ui/artalk/src/comment/renders/content.ts | 2 +- ui/artalk/src/comment/renders/header.ts | 2 +- ui/artalk/src/comment/renders/pending.ts | 2 +- ui/artalk/src/comment/renders/reply-to.ts | 2 +- ui/artalk/src/components/action-btn.ts | 10 +- ui/artalk/src/components/checker/admin.ts | 2 +- .../src/components/checker/captcha-renders.ts | 2 +- ui/artalk/src/components/checker/captcha.ts | 4 +- ui/artalk/src/components/checker/index.ts | 4 +- ui/artalk/src/components/dialog.ts | 2 +- ui/artalk/src/config.ts | 2 +- ui/artalk/src/context.ts | 17 +- ui/artalk/src/data.ts | 2 +- ui/artalk/src/editor/editor.ts | 2 +- ui/artalk/src/editor/state.ts | 4 +- ui/artalk/src/i18n/index.ts | 2 +- ui/artalk/src/layer/layer-manager.ts | 2 +- ui/artalk/src/layer/sidebar-layer.ts | 4 +- ui/artalk/src/layer/wrap.ts | 2 +- ui/artalk/src/lib/marked-renderer.ts | 10 +- ui/artalk/src/lib/marked.ts | 2 +- ui/artalk/src/lib/ui.ts | 2 +- ui/artalk/src/lib/utils.ts | 2 +- ui/artalk/src/list/layout/flat.ts | 2 +- ui/artalk/src/list/layout/index.ts | 4 +- ui/artalk/src/list/layout/nest.ts | 2 +- ui/artalk/src/list/list.ts | 8 +- ui/artalk/src/list/page.ts | 4 +- ui/artalk/src/list/paginator/index.ts | 2 +- ui/artalk/src/list/paginator/read-more.ts | 2 +- ui/artalk/src/list/paginator/up-down.ts | 2 +- ui/artalk/src/load.ts | 2 +- ui/artalk/src/plugins/editor-kit.ts | 4 +- ui/artalk/src/plugins/editor/_plug.ts | 2 +- ui/artalk/src/plugins/editor/closable.ts | 4 +- ui/artalk/src/plugins/editor/emoticons.ts | 4 +- ui/artalk/src/plugins/editor/header-user.ts | 4 +- ui/artalk/src/plugins/editor/index.ts | 2 +- ui/artalk/src/plugins/editor/local-storage.ts | 2 +- ui/artalk/src/plugins/editor/mover.ts | 2 +- ui/artalk/src/plugins/editor/preview.ts | 4 +- ui/artalk/src/plugins/editor/state-edit.ts | 6 +- ui/artalk/src/plugins/editor/state-reply.ts | 8 +- ui/artalk/src/plugins/editor/submit-add.ts | 2 +- ui/artalk/src/plugins/editor/submit-btn.ts | 2 +- ui/artalk/src/plugins/editor/submit.ts | 4 +- ui/artalk/src/plugins/editor/textarea.ts | 2 +- ui/artalk/src/plugins/editor/upload.ts | 4 +- ui/artalk/src/plugins/index.ts | 2 +- ui/artalk/src/plugins/list/dropdown.ts | 5 +- ui/artalk/src/plugins/list/error-dialog.ts | 2 +- ui/artalk/src/plugins/list/index.ts | 2 +- ui/artalk/src/service.ts | 2 +- ui/artalk/src/types/config.ts | 2 +- ui/artalk/src/types/context.ts | 12 +- ui/artalk/src/types/editor.ts | 2 +- ui/artalk/src/types/event.ts | 2 +- ui/artalk/vite.config.ts | 18 +- ui/plugin-kit/src/plugin/dev-page.ts | 1 - ui/plugin-kit/src/plugin/lint/export-lint.ts | 2 - ui/plugin-kit/src/plugin/main.ts | 5 +- 110 files changed, 480 insertions(+), 466 deletions(-) create mode 100644 docs/landing/src/Features.ts diff --git a/.github/workflows/test-docs.yml b/.github/workflows/test-docs.yml index 7bbdb2106..642742342 100644 --- a/.github/workflows/test-docs.yml +++ b/.github/workflows/test-docs.yml @@ -33,3 +33,6 @@ jobs: - name: Build Docs run: pnpm build:docs + + - name: Lint Docs + run: pnpm eslint docs && pnpm prettier --check docs diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml index 54c74f7d8..295468295 100644 --- a/.github/workflows/test-frontend.yml +++ b/.github/workflows/test-frontend.yml @@ -41,7 +41,10 @@ jobs: - name: Unit test run: pnpm test + - name: Lint + run: pnpm eslint ui && pnpm prettier --check ui + # https://github.com/arethetypeswrong/arethetypeswrong.github.io - name: "arethetypeswrong test" if: runner.os == 'ubuntu-latest' - run: pnpm -F artalk attw || true + run: pnpm -F artalk test:attw || true diff --git a/docs/docs/.vitepress/theme/Artalk.vue b/docs/docs/.vitepress/theme/Artalk.vue index 441c09b27..3ef6c73f9 100644 --- a/docs/docs/.vitepress/theme/Artalk.vue +++ b/docs/docs/.vitepress/theme/Artalk.vue @@ -75,8 +75,7 @@ function loadExtraFuncs() { linkEl.append(imgEl.cloneNode()) imgEl.replaceWith(linkEl) }) - // @ts-ignore - if (imgEls.length) lightGallery($content, { selector: '.atk-img-link' }) + if (imgEls.length && typeof window !== 'undefined' && typeof (window).lightGallery !== 'undefined') (window).lightGallery($content, { selector: '.atk-img-link' }) }) }) @@ -88,8 +87,7 @@ function loadExtraFuncs() { mList.forEach((m) => { if (m.attributeName !== 'class') return - // @ts-ignore - const darkMode = m.target.classList.contains('dark') + const darkMode = (m.target).classList.contains('dark') artalk.setDarkMode(darkMode) }) }).observe(document.querySelector('html'), { attributes: true }) diff --git a/docs/docs/.vitepress/theme/Artransfer.vue b/docs/docs/.vitepress/theme/Artransfer.vue index c20ee4b61..26bf73212 100644 --- a/docs/docs/.vitepress/theme/Artransfer.vue +++ b/docs/docs/.vitepress/theme/Artransfer.vue @@ -1,8 +1,8 @@ @@ -28,8 +28,7 @@ export default defineComponent({ mList.forEach((m) => { if (m.attributeName !== 'class') return - // @ts-ignore - const darkMode = m.target.classList.contains('dark') + const darkMode = (m.target).classList.contains('dark') setArtransferIframeDarkMode(darkMode) }) }).observe(document.querySelector('html'), { attributes: true }) diff --git a/docs/docs/.vitepress/theme/index.ts b/docs/docs/.vitepress/theme/index.ts index 6f995b56a..65e5994e6 100644 --- a/docs/docs/.vitepress/theme/index.ts +++ b/docs/docs/.vitepress/theme/index.ts @@ -1,8 +1,8 @@ import DefaultTheme from 'vitepress/theme' +import { Theme } from 'vitepress' import Layout from './Layout.vue' import Artalk from './Artalk.vue' import Artransfer from './Artransfer.vue' -import { Theme } from 'vitepress' export default { ...DefaultTheme, diff --git a/docs/landing/scripts/update-readme.ts b/docs/landing/scripts/update-readme.ts index e53512993..e01b379a9 100644 --- a/docs/landing/scripts/update-readme.ts +++ b/docs/landing/scripts/update-readme.ts @@ -1,9 +1,9 @@ import path from 'node:path' -import { FuncList } from '../src/components/Features/FullFeatureList.tsx' import { writeFileSync, readFileSync } from 'node:fs' +import { Features } from '../src/Features' const __dirname = new URL('.', import.meta.url).pathname -const features = FuncList.map(o => `* [${o.name}](${o.link}): ${o.desc}`).join('\n') +const features = Features.map(o => `* [${o.name}](${o.link}): ${o.desc}`).join('\n') const pathList = [ '../../../README.md', diff --git a/docs/landing/src/Features.ts b/docs/landing/src/Features.ts new file mode 100644 index 000000000..519bfdbb5 --- /dev/null +++ b/docs/landing/src/Features.ts @@ -0,0 +1,220 @@ +import { TbLayoutSidebarRightExpandFilled, TbMailFilled, TbEyeFilled, TbTransformFilled, TbLocationFilled, TbCardsFilled, TbPhotoSearch, TbMath, TbPlug, TbLanguage, TbTerminal, TbApi, TbSocial } from 'react-icons/tb' +import { BiSolidNotification, BiSolidBadgeCheck } from 'react-icons/bi' +import { RiLoader4Fill, RiPushpinLine, RiRobot2Fill, RiUpload2Fill } from 'react-icons/ri' +import { BsFillShieldLockFill } from 'react-icons/bs' +import { PiMoonFill, PiSmileyWinkBold } from 'react-icons/pi' +import { GrUpgrade } from 'react-icons/gr' +import { LuListTree, LuNewspaper } from 'react-icons/lu' +import { FaArrowTrendUp } from 'react-icons/fa6' +import { FaMarkdown, FaRegSave, FaSortAmountUpAlt } from 'react-icons/fa' +import { HiOutlineDocumentSearch } from 'react-icons/hi' +import { IoSearch, IoSend } from 'react-icons/io5' +import { IoMdLocate } from 'react-icons/io' + +export interface FeatureItem { + icon: React.FC + name: string + desc: string + link: string +} + +export const Features: FeatureItem[] = [ + { + icon: TbLayoutSidebarRightExpandFilled, + name: '侧边栏', + desc: '快速管理、直观浏览', + link: 'https://artalk.js.org/guide/frontend/sidebar.html' + }, + { + icon: TbSocial, + name: '社交登录', + desc: '通过社交账号快速登录', + link: 'https://artalk.js.org/guide/frontend/auth.html' + }, + { + icon: TbMailFilled, + name: '邮件通知', + desc: '多种发送方式、邮件模板', + link: 'https://artalk.js.org/guide/backend/email.html' + }, + { + icon: IoSend, + name: '多元推送', + desc: '多种推送方式、通知模版', + link: 'https://artalk.js.org/guide/backend/admin_notify.html' + }, + { + icon: BiSolidNotification, + name: '站内通知', + desc: '红点标记、提及列表', + link: 'https://artalk.js.org/guide/frontend/sidebar.html' + }, + { + icon: RiRobot2Fill, + name: '验证码', + desc: '多种验证类型、频率限制', + link: 'https://artalk.js.org/guide/backend/captcha.html' + }, + { + icon: BsFillShieldLockFill, + name: '评论审核', + desc: '内容检测、垃圾拦截', + link: 'https://artalk.js.org/guide/backend/moderator.html' + }, + { + icon: RiUpload2Fill, + name: '图片上传', + desc: '自定义上传、支持图床', + link: 'https://artalk.js.org/guide/backend/img-upload.html' + }, + { + icon: FaMarkdown, + name: 'Markdown', + desc: '支持 Markdown 语法', + link: 'https://artalk.js.org/guide/intro.html' + }, + { + icon: PiSmileyWinkBold, + name: '表情包', + desc: '兼容 OwO,快速集成', + link: 'https://artalk.js.org/guide/frontend/emoticons.html' + }, + { + icon: TbCardsFilled, + name: '多站点', + desc: '站点隔离、集中管理', + link: 'https://artalk.js.org/guide/backend/multi-site.html' + }, + { + icon: BiSolidBadgeCheck, + name: '管理员', + desc: '密码验证、徽章标识', + link: 'https://artalk.js.org/guide/backend/multi-site.html' + }, + { + icon: LuNewspaper, + name: '页面管理', + desc: '快速查看、标题一键跳转', + link: 'https://artalk.js.org/guide/frontend/sidebar.html', + }, + { + icon: TbEyeFilled, + name: '浏览量统计', + desc: '轻松统计网页浏览量', + link: 'https://artalk.js.org/guide/frontend/pv.html' + }, + { + icon: LuListTree, + name: '层级结构', + desc: '嵌套分页列表、滚动加载', + link: 'https://artalk.js.org/guide/frontend/config.html#nestmax', + }, + { + icon: FaArrowTrendUp, + name: '评论投票', + desc: '赞同或反对评论', + link: 'https://artalk.js.org/guide/frontend/config.html#vote', + }, + { + icon: FaSortAmountUpAlt, + name: '评论排序', + desc: '多种排序方式,自由选择', + link: 'https://artalk.js.org/guide/frontend/config.html#listsort', + }, + { + icon: IoSearch, + name: '评论搜索', + desc: '快速搜索评论内容', + link: 'https://artalk.js.org/guide/frontend/sidebar.html', + }, + { + icon: RiPushpinLine, + name: '评论置顶', + desc: '重要消息置顶显示', + link: 'https://artalk.js.org/guide/frontend/sidebar.html', + }, + { + icon: HiOutlineDocumentSearch, + name: '仅看作者', + desc: '仅显示作者的评论', + link: 'https://artalk.js.org/guide/frontend/config.html', + }, + { + icon: IoMdLocate, + name: '评论跳转', + desc: '快速跳转到引用的评论', + link: 'https://artalk.js.org/guide/intro.html', + }, + { + icon: FaRegSave, + name: '自动保存', + desc: '输入内容防丢功能', + link: 'https://artalk.js.org/guide/frontend/config.html', + }, + { + icon: TbLocationFilled, + name: 'IP 属地', + desc: '用户 IP 属地展示', + link: 'https://artalk.js.org/guide/frontend/ip-region.html' + }, + { + icon: TbTransformFilled, + name: '数据迁移', + desc: '自由迁移、快速备份', + link: 'https://artalk.js.org/guide/transfer.html' + }, + { + icon: TbPhotoSearch, + name: '图片灯箱', + desc: '图片灯箱快速集成', + link: 'https://artalk.js.org/guide/frontend/lightbox.html' + }, + { + icon: RiLoader4Fill, + name: '图片懒加载', + desc: '延迟加载图片,优化体验', + link: 'https://artalk.js.org/guide/frontend/img-lazy-load.html' + }, + { + icon: TbMath, + name: 'Latex', + desc: 'Latex 公式解析集成', + link: 'https://artalk.js.org/guide/frontend/latex.html' + }, + { + icon: PiMoonFill, + name: '夜间模式', + desc: '夜间模式切换', + link: 'https://artalk.js.org/guide/frontend/config.html#darkmode' + }, + { + icon: TbPlug, + name: '扩展插件', + desc: '创造更多可能性', + link: 'https://artalk.js.org/develop/plugin.html' + }, + { + icon: TbLanguage, + name: '多语言', + desc: '多国语言切换', + link: 'https://artalk.js.org/guide/frontend/i18n.html' + }, + { + icon: TbTerminal, + name: '命令行', + desc: '命令行操作管理能力', + link: 'https://artalk.js.org/guide/backend/config.html' + }, + { + icon: TbApi, + name: 'API 文档', + desc: '提供 OpenAPI 格式文档', + link: 'https://artalk.js.org/http-api.html' + }, + { + icon: GrUpgrade, + name: '程序升级', + desc: '版本检测,一键升级', + link: 'https://artalk.js.org/guide/backend/update.html' + } +] diff --git a/docs/landing/src/components/Features/FullFeature.tsx b/docs/landing/src/components/Features/FullFeature.tsx index 4f193422f..c1b0160a9 100644 --- a/docs/landing/src/components/Features/FullFeature.tsx +++ b/docs/landing/src/components/Features/FullFeature.tsx @@ -1,9 +1,9 @@ import React from 'react' import './FullFeature.scss' -import { FeatureBase } from './FeatureBase' import { FeatureTitle } from '../FeatureTitle' import { FeatureDesc } from '../FeatureDesc' import { Reveal } from '../Reveal' +import { FeatureBase } from './FeatureBase' import { FolderIcon } from './FullFeatureIcon' import { FullFeatureList } from './FullFeatureList' diff --git a/docs/landing/src/components/Features/FullFeatureList.tsx b/docs/landing/src/components/Features/FullFeatureList.tsx index 45123c09d..2fc10e399 100644 --- a/docs/landing/src/components/Features/FullFeatureList.tsx +++ b/docs/landing/src/components/Features/FullFeatureList.tsx @@ -1,228 +1,9 @@ import React from 'react' -import { TbLayoutSidebarRightExpandFilled, TbMailFilled, TbEyeFilled, TbTransformFilled, TbLocationFilled, TbCardsFilled, TbPhotoSearch, TbMath, TbPlug, TbLanguage, TbTerminal, TbApi, TbSocial } from 'react-icons/tb' -import { BiSolidNotification, BiSolidBadgeCheck } from 'react-icons/bi' -import { RiLoader4Fill, RiPushpinLine, RiRobot2Fill, RiUpload2Fill } from 'react-icons/ri' -import { BsFillShieldLockFill } from 'react-icons/bs' -import { PiMoonFill, PiSmileyWinkBold } from 'react-icons/pi' -import { GrUpgrade } from 'react-icons/gr' -import { LuListTree, LuNewspaper } from 'react-icons/lu' -import { FaArrowTrendUp } from 'react-icons/fa6' -import { FaMarkdown, FaRegSave, FaSortAmountUpAlt } from 'react-icons/fa' -import { HiOutlineDocumentSearch } from 'react-icons/hi' -import { IoSearch, IoSend } from 'react-icons/io5' -import { IoMdLocate } from 'react-icons/io' - -interface FuncItem { - icon: React.ReactNode - name: string - desc: string - link: string -} - -export const FuncList: FuncItem[] = [ - { - icon: , - name: '侧边栏', - desc: '快速管理、直观浏览', - link: 'https://artalk.js.org/guide/frontend/sidebar.html' - }, - { - icon: , - name: '社交登录', - desc: '通过社交账号快速登录', - link: 'https://artalk.js.org/guide/frontend/auth.html' - }, - { - icon: , - name: '邮件通知', - desc: '多种发送方式、邮件模板', - link: 'https://artalk.js.org/guide/backend/email.html' - }, - { - icon: , - name: '多元推送', - desc: '多种推送方式、通知模版', - link: 'https://artalk.js.org/guide/backend/admin_notify.html' - }, - { - icon: , - name: '站内通知', - desc: '红点标记、提及列表', - link: 'https://artalk.js.org/guide/frontend/sidebar.html' - }, - { - icon: , - name: '验证码', - desc: '多种验证类型、频率限制', - link: 'https://artalk.js.org/guide/backend/captcha.html' - }, - { - icon: , - name: '评论审核', - desc: '内容检测、垃圾拦截', - link: 'https://artalk.js.org/guide/backend/moderator.html' - }, - { - icon: , - name: '图片上传', - desc: '自定义上传、支持图床', - link: 'https://artalk.js.org/guide/backend/img-upload.html' - }, - { - icon: , - name: 'Markdown', - desc: '支持 Markdown 语法', - link: 'https://artalk.js.org/guide/intro.html' - }, - { - icon: , - name: '表情包', - desc: '兼容 OwO,快速集成', - link: 'https://artalk.js.org/guide/frontend/emoticons.html' - }, - { - icon: , - name: '多站点', - desc: '站点隔离、集中管理', - link: 'https://artalk.js.org/guide/backend/multi-site.html' - }, - { - icon: , - name: '管理员', - desc: '密码验证、徽章标识', - link: 'https://artalk.js.org/guide/backend/multi-site.html' - }, - { - icon: , - name: '页面管理', - desc: '快速查看、标题一键跳转', - link: 'https://artalk.js.org/guide/frontend/sidebar.html', - }, - { - icon: , - name: '浏览量统计', - desc: '轻松统计网页浏览量', - link: 'https://artalk.js.org/guide/frontend/pv.html' - }, - { - icon: , - name: '层级结构', - desc: '嵌套分页列表、滚动加载', - link: 'https://artalk.js.org/guide/frontend/config.html#nestmax', - }, - { - icon: , - name: '评论投票', - desc: '赞同或反对评论', - link: 'https://artalk.js.org/guide/frontend/config.html#vote', - }, - { - icon: , - name: '评论排序', - desc: '多种排序方式,自由选择', - link: 'https://artalk.js.org/guide/frontend/config.html#listsort', - }, - { - icon: , - name: '评论搜索', - desc: '快速搜索评论内容', - link: 'https://artalk.js.org/guide/frontend/sidebar.html', - }, - { - icon: , - name: '评论置顶', - desc: '重要消息置顶显示', - link: 'https://artalk.js.org/guide/frontend/sidebar.html', - }, - { - icon: , - name: '仅看作者', - desc: '仅显示作者的评论', - link: 'https://artalk.js.org/guide/frontend/config.html', - }, - { - icon: , - name: '评论跳转', - desc: '快速跳转到引用的评论', - link: 'https://artalk.js.org/guide/intro.html', - }, - { - icon: , - name: '自动保存', - desc: '输入内容防丢功能', - link: 'https://artalk.js.org/guide/frontend/config.html', - }, - { - icon: , - name: 'IP 属地', - desc: '用户 IP 属地展示', - link: 'https://artalk.js.org/guide/frontend/ip-region.html' - }, - { - icon: , - name: '数据迁移', - desc: '自由迁移、快速备份', - link: 'https://artalk.js.org/guide/transfer.html' - }, - { - icon: , - name: '图片灯箱', - desc: '图片灯箱快速集成', - link: 'https://artalk.js.org/guide/frontend/lightbox.html' - }, - { - icon: , - name: '图片懒加载', - desc: '延迟加载图片,优化体验', - link: 'https://artalk.js.org/guide/frontend/img-lazy-load.html' - }, - { - icon: , - name: 'Latex', - desc: 'Latex 公式解析集成', - link: 'https://artalk.js.org/guide/frontend/latex.html' - }, - { - icon: , - name: '夜间模式', - desc: '夜间模式切换', - link: 'https://artalk.js.org/guide/frontend/config.html#darkmode' - }, - { - icon: , - name: '扩展插件', - desc: '创造更多可能性', - link: 'https://artalk.js.org/develop/plugin.html' - }, - { - icon: , - name: '多语言', - desc: '多国语言切换', - link: 'https://artalk.js.org/guide/frontend/i18n.html' - }, - { - icon: , - name: '命令行', - desc: '命令行操作管理能力', - link: 'https://artalk.js.org/guide/backend/config.html' - }, - { - icon: , - name: 'API 文档', - desc: '提供 OpenAPI 格式文档', - link: 'https://artalk.js.org/http-api.html' - }, - { - icon: , - name: '程序升级', - desc: '版本检测,一键升级', - link: 'https://artalk.js.org/guide/backend/update.html' - } -] +import { Features, FeatureItem } from '../../Features' export const FullFeatureList: React.FC = () => { // let func list item group by every two items - const FuncListGrouped = FuncList.reduce((result, current, index) => { + const FuncListGrouped = Features.reduce((result, current, index) => { if (index % 3 === 0) result.push([current]) else result[result.length - 1].push(current) return result @@ -230,12 +11,12 @@ export const FullFeatureList: React.FC = () => { return (
- {FuncListGrouped.map((row) => ( -
- {row.map((item) => ( - + {FuncListGrouped.map((row, i) => ( +
+ {row.map((item, j) => ( +
- {item.icon} + {item.name}
diff --git a/docs/landing/src/components/Features/FuncFeature.tsx b/docs/landing/src/components/Features/FuncFeature.tsx index e27c2955f..0ae2ef037 100644 --- a/docs/landing/src/components/Features/FuncFeature.tsx +++ b/docs/landing/src/components/Features/FuncFeature.tsx @@ -1,10 +1,10 @@ import React from 'react' import './FuncFeature.scss' -import { FeatureBase } from './FeatureBase' +import { FaArrowRight } from 'react-icons/fa' import { FeatureTitle } from '../FeatureTitle' import { FeatureDesc } from '../FeatureDesc' import { Reveal } from '../Reveal' -import { FaArrowRight } from 'react-icons/fa' +import { FeatureBase } from './FeatureBase' const FuncGrps: {name: string, items: string[], link?: string}[] = [ { name: '社交登录', items: ['Github', 'GitLab', 'Twitter', 'Facebook', 'Mastodon', 'Google', 'Microsoft', 'Apple', 'Discord', 'Slack', 'Tiktok', 'Steam'], link: 'https://artalk.js.org/guide/frontend/auth.html' }, @@ -41,7 +41,7 @@ export const FuncFeature: React.FC = () => {
- {FuncGrps.map((grp) => ( -
+ {FuncGrps.map((grp, i) => ( +
{grp.link ? ( - {grp.name} + {grp.name} ) : (
{grp.name}
)}
- {grp.items.map((item) => ( -
{item}
+ {grp.items.map((item, j) => ( +
{item}
))}
diff --git a/docs/landing/src/components/Features/QuickFeature.tsx b/docs/landing/src/components/Features/QuickFeature.tsx index cc1000eb1..c68bcaca2 100644 --- a/docs/landing/src/components/Features/QuickFeature.tsx +++ b/docs/landing/src/components/Features/QuickFeature.tsx @@ -1,11 +1,11 @@ import React from 'react' import './QuickFeature.scss' import { FiArrowUpRight } from 'react-icons/fi' -import { FeatureBase } from './FeatureBase' import { FeatureTitle } from '../FeatureTitle' import { LearnMoreLink } from '../LearnMoreLink' import { FeatureDesc } from '../FeatureDesc' import { Reveal } from '../Reveal' +import { FeatureBase } from './FeatureBase' export const QuickFeature: React.FC = () => { const ArrowIcon = ( @@ -22,10 +22,10 @@ export const QuickFeature: React.FC = () => {
@@ -49,7 +49,7 @@ export const QuickFeature: React.FC = () => {
- + diff --git a/docs/landing/src/components/Features/SafeFeature.tsx b/docs/landing/src/components/Features/SafeFeature.tsx index bcbfba61e..4a12079d0 100644 --- a/docs/landing/src/components/Features/SafeFeature.tsx +++ b/docs/landing/src/components/Features/SafeFeature.tsx @@ -1,9 +1,9 @@ import React from 'react' import './SafeFeature.scss' -import { FeatureBase } from './FeatureBase' import { FeatureTitle } from '../FeatureTitle' import { FeatureDesc } from '../FeatureDesc' import { Reveal } from '../Reveal' +import { FeatureBase } from './FeatureBase' export const SafeFeature: React.FC = () => { return ( @@ -13,9 +13,9 @@ export const SafeFeature: React.FC = () => {
diff --git a/docs/landing/src/components/Features/SlightFeature.tsx b/docs/landing/src/components/Features/SlightFeature.tsx index 94a5dc76a..53d725104 100644 --- a/docs/landing/src/components/Features/SlightFeature.tsx +++ b/docs/landing/src/components/Features/SlightFeature.tsx @@ -1,9 +1,9 @@ import React, { useState } from 'react' import { FeatureTitle } from '../FeatureTitle' import { Reveal } from '../Reveal' +import { FeatureDesc } from '../FeatureDesc' import { FeatureBase } from './FeatureBase' import './SlightFeature.scss' -import { FeatureDesc } from '../FeatureDesc' export const SlightFeature: React.FC = () => { const [percent, setPercent] = useState(0) diff --git a/docs/landing/src/components/LearnMoreLink.tsx b/docs/landing/src/components/LearnMoreLink.tsx index ea4647e7d..48d173243 100644 --- a/docs/landing/src/components/LearnMoreLink.tsx +++ b/docs/landing/src/components/LearnMoreLink.tsx @@ -11,7 +11,7 @@ export const LearnMoreLink: React.FC = (props) => { return (
{props.prompt} - 了解更多 + 了解更多
) } diff --git a/docs/landing/src/components/Reveal.tsx b/docs/landing/src/components/Reveal.tsx index 8e437ed31..cb48e6cc0 100644 --- a/docs/landing/src/components/Reveal.tsx +++ b/docs/landing/src/components/Reveal.tsx @@ -20,36 +20,40 @@ export const Reveal: React.FC = (props) => { const elementRef = useRef(null) useEffect(() => { + const observerRefValue = elementRef.current + const observer = new IntersectionObserver((entries) => { if (entries[0].isIntersecting) { setIsVisible(true) - elementRef.current && observer.unobserve(elementRef.current) + observerRefValue && observer.unobserve(observerRefValue) } }, { threshold: props.threshold }) - elementRef.current && observer.observe(elementRef.current) + observerRefValue && observer.observe(observerRefValue) return () => { - elementRef.current && observer.unobserve(elementRef.current) + observerRefValue && observer.unobserve(observerRefValue) } }, [props.threshold]) useEffect(() => { - if (isVisible) { - elementRef.current?.classList.add('animate') + if (!isVisible) return - const animationEndHandler = () => { - elementRef.current?.classList.remove('animate') - elementRef.current?.classList.add('show') - } + const observerRefValue = elementRef.current - elementRef.current?.addEventListener('animationend', animationEndHandler) + observerRefValue?.classList.add('animate') - return () => { - elementRef.current?.removeEventListener('animationend', animationEndHandler) - } + const animationEndHandler = () => { + observerRefValue?.classList.remove('animate') + observerRefValue?.classList.add('show') + } + + observerRefValue?.addEventListener('animationend', animationEndHandler) + + return () => { + observerRefValue?.removeEventListener('animationend', animationEndHandler) } }, [isVisible]) diff --git a/docs/landing/src/components/Slogan.tsx b/docs/landing/src/components/Slogan.tsx index 87b7aed8b..aeca960f9 100644 --- a/docs/landing/src/components/Slogan.tsx +++ b/docs/landing/src/components/Slogan.tsx @@ -11,7 +11,7 @@ export const Slogan: React.FC = () => { A Self-hosted - +
@@ -20,7 +20,7 @@ export const Slogan: React.FC = () => {
diff --git a/eslint.config.mjs b/eslint.config.mjs index 82052c2cb..77c7cf89b 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,7 +1,6 @@ // @ts-check import path from 'node:path' import url from 'node:url' - import { fixupPluginRules } from '@eslint/compat' // eslint-disable-next-line import-x/namespace import { FlatCompat } from '@eslint/eslintrc' @@ -88,17 +87,12 @@ export default eslintTs.config( ...pluginImportX.configs.recommended.rules, '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-unsafe-declaration-merging': 'off', + 'vue/multi-word-component-names': 'off', 'import-x/no-named-as-default-member': 'off', - 'import-x/default': 'off', // FIXME: No default export found in imported module "react", SEE https://github.com/import-js/eslint-plugin-import/issues/1800 - 'import-x/order': [ - 'warn', - { - 'newlines-between': 'always', - alphabetize: { - order: 'asc', - }, - }, - ], + 'import-x/no-named-as-default': 'off', + 'import-x/default': 'off', // fix https://github.com/import-js/eslint-plugin-import/issues/1800 + 'import-x/order': 'warn', // 'import-x/no-default-export': 'warn' }, settings: { @@ -145,14 +139,14 @@ export default eslintTs.config( useRouter: 'readonly', useStore: 'readonly', useI18n: 'readonly', + nextTick: 'readonly', }, }, - rules: {}, }, /* React */ { - files: ['**/*.tsx'], + files: ['docs/landing/**/*.tsx'], plugins: { react: pluginReact, // @ts-expect-error SEE https://github.com/facebook/react/issues/28313 @@ -164,6 +158,7 @@ export default eslintTs.config( ...pluginReact.configs['jsx-runtime'].rules, ...pluginReactHooks.configs.recommended.rules, 'react-refresh/only-export-components': 'warn', + 'react/prop-types': 'off', }, languageOptions: { ...pluginReact.configs.recommended.languageOptions, diff --git a/package.json b/package.json index d91fdb7de..db5f6a5a4 100644 --- a/package.json +++ b/package.json @@ -6,15 +6,18 @@ "scripts": { "dev": "pnpm -F artalk dev", "dev:sidebar": "pnpm -F @artalk/artalk-sidebar dev", + "dev:docs": "pnpm -F=docs dev:docs", + "dev:landing": "pnpm -F=docs-landing dev", "build": "pnpm -F artalk build", "build:sidebar": "pnpm -F @artalk/artalk-sidebar build", "build:auth": "pnpm -F @artalk/plugin-auth build", "build:all": "pnpm build && pnpm build:sidebar", "build:docs": "pnpm build && pnpm -F=docs-landing build && pnpm -F=docs-swagger swagger:build && pnpm -F=docs build:docs && pnpm patch:docs", "patch:docs": "cp -rf docs/landing/dist/* docs/swagger/dist/* docs/docs/.vitepress/dist", - "lint": "pnpm lint:prettier && pnpm lint:eslint", - "lint:eslint": "eslint -c eslint.config.mjs", - "lint:prettier": "prettier --check --write .", + "lint:eslint": "eslint .", + "lint:prettier": "prettier --check .", + "lint": "pnpm lint:eslint && pnpm lint:prettier", + "lint:fix": "pnpm lint:eslint --fix && pnpm lint:prettier --write", "test": "pnpm -F artalk test" }, "devDependencies": { diff --git a/scripts/frontend-e2e-test.sh b/scripts/frontend-e2e-test.sh index d8ea96253..26d2881cc 100755 --- a/scripts/frontend-e2e-test.sh +++ b/scripts/frontend-e2e-test.sh @@ -25,5 +25,5 @@ pnpm -F artalk run test:e2e # if args contains `--show-report` then open report if [[ $* == *--show-report* ]]; then - pnpm -F artalk run test:report + pnpm -F artalk run test:e2e-report fi diff --git a/ui/artalk-sidebar/src/App.vue b/ui/artalk-sidebar/src/App.vue index 6e45cb099..376da326a 100644 --- a/ui/artalk-sidebar/src/App.vue +++ b/ui/artalk-sidebar/src/App.vue @@ -1,8 +1,8 @@