├── src ├── lib │ ├── api │ │ ├── error.ts │ │ ├── config.ts │ │ ├── hooks │ │ │ ├── common.ts │ │ │ ├── index.ts │ │ │ ├── userClient.ts │ │ │ ├── user.ts │ │ │ ├── useScriptWatch.ts │ │ │ ├── userSettings.ts │ │ │ └── notification.ts │ │ ├── index.ts │ │ └── services │ │ │ ├── scripts │ │ │ ├── index.ts │ │ │ ├── statistics.ts │ │ │ └── favorites.ts │ │ │ ├── resource.ts │ │ │ └── notification.ts │ ├── utils │ │ ├── semdate.ts │ │ ├── dayjs-config.ts │ │ ├── utils.ts │ │ ├── script-manager.ts │ │ └── error.ts │ ├── cookies.ts │ └── swr-config.tsx ├── app │ ├── favicon.ico │ ├── [locale] │ │ ├── scripts │ │ │ └── create │ │ │ │ └── page.tsx │ │ ├── users │ │ │ ├── settings │ │ │ │ ├── components │ │ │ │ │ ├── index.ts │ │ │ │ │ └── SettingsClient.tsx │ │ │ │ └── page.tsx │ │ │ ├── [id] │ │ │ │ ├── layout.tsx │ │ │ │ ├── page.tsx │ │ │ │ └── favorites │ │ │ │ │ └── page.tsx │ │ │ └── favorites │ │ │ │ └── [id] │ │ │ │ └── page.tsx │ │ ├── script-show-page │ │ │ └── [id] │ │ │ │ ├── issue │ │ │ │ ├── create │ │ │ │ │ ├── page.tsx │ │ │ │ │ └── CreateIssueClient.tsx │ │ │ │ ├── components │ │ │ │ │ └── IssueLabel.tsx │ │ │ │ ├── [issueId] │ │ │ │ │ └── page.tsx │ │ │ │ └── page.tsx │ │ │ │ ├── page.tsx │ │ │ │ ├── statistic │ │ │ │ └── page.tsx │ │ │ │ ├── comment │ │ │ │ ├── components │ │ │ │ │ └── rating │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── utils.ts │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ ├── ReplyItem.tsx │ │ │ │ │ │ ├── RatingOverview.tsx │ │ │ │ │ │ └── RatingList.tsx │ │ │ │ └── page.tsx │ │ │ │ ├── code │ │ │ │ ├── components │ │ │ │ │ └── ScriptCodeClient.tsx │ │ │ │ └── page.tsx │ │ │ │ ├── update │ │ │ │ └── page.tsx │ │ │ │ ├── manage │ │ │ │ ├── logs │ │ │ │ │ └── page.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── components │ │ │ │ │ └── ManageClientLayout.tsx │ │ │ │ └── page.tsx │ │ │ │ ├── components │ │ │ │ ├── ScriptLayoutProvider.tsx │ │ │ │ ├── ScriptContext.tsx │ │ │ │ ├── ScriptLayout.tsx │ │ │ │ └── ScriptNavigation.tsx │ │ │ │ ├── version │ │ │ │ └── page.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── diff │ │ │ │ ├── components │ │ │ │ │ └── ScriptDiffClient.tsx │ │ │ │ └── page.tsx │ │ │ │ ├── metadata.ts │ │ │ │ └── utils.ts │ │ ├── error.tsx │ │ ├── layout.tsx │ │ ├── notifications │ │ │ └── page.tsx │ │ └── search │ │ │ └── page.tsx │ └── globals.css ├── components │ ├── UserProfile │ │ └── index.tsx │ ├── MarkdownView │ │ ├── markdown.css │ │ └── index.tsx │ ├── NotificationBell.tsx │ ├── DayjsLocaleProvider.tsx │ ├── StatCard.tsx │ ├── GoogleAd │ │ ├── script.tsx │ │ └── index.tsx │ ├── NavigationProgress.tsx │ ├── MonacoEditor │ │ ├── DiffEditor.tsx │ │ └── index.tsx │ ├── ScriptEditor │ │ ├── ScriptCreateWrapper.tsx │ │ └── ScriptUpdateWrapper.tsx │ ├── UserAuth.tsx │ ├── layout │ │ └── MainLayout │ │ │ └── ThemeToggle.tsx │ ├── DebounceSelect.tsx │ ├── ScriptListCard.tsx │ ├── LocalizedServerThemeWrapper.tsx │ └── FavoriteEditModal.tsx ├── middleware.ts ├── contexts │ ├── ThemeContext.tsx │ ├── ScriptSettingContext.tsx │ └── UserContext.tsx ├── types │ ├── favorites.ts │ ├── api.ts │ └── global.d.ts └── i18n │ ├── request.ts │ └── routing.ts ├── public ├── locales │ └── vi-VN │ │ └── translations.json ├── ads.txt ├── favicon.ico ├── assets │ └── logo.png ├── robot.txt └── prismjs │ └── themes │ ├── prism-tomorrow.min.css │ └── prism.min.css ├── .prettierrc ├── deploy ├── gateway │ ├── README.md │ ├── values.yaml │ ├── Chart.yaml │ ├── templates │ │ └── gateway.yaml │ └── _helpers.tpl ├── helm │ ├── templates │ │ ├── serviceaccount.yaml │ │ ├── service.yaml │ │ ├── tests │ │ │ └── test-connection.yaml │ │ ├── hpa.yaml │ │ ├── NOTES.txt │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ └── ingress.yaml │ ├── .helmignore │ ├── Chart.yaml │ └── values.yaml └── docker │ └── Dockerfile ├── postcss.config.mjs ├── crowdin.yml ├── tsconfig.node.json ├── next.config.ts ├── tsconfig.json ├── .gitignore ├── .env.example ├── .dockerignore ├── scripts ├── prebuild.tsx └── crowdin-download.js ├── docs └── prompt.md ├── eslint.config.mjs ├── README.md ├── .github └── copilot-instructions.md ├── package.json └── tailwind.config.ts /src/lib/api/error.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/locales/vi-VN/translations.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } -------------------------------------------------------------------------------- /deploy/gateway/README.md: -------------------------------------------------------------------------------- 1 | # 灰度发布 2 | 3 | 灰度发布helm -------------------------------------------------------------------------------- /public/ads.txt: -------------------------------------------------------------------------------- 1 | google.com, pub-8009073269666226, DIRECT, f08c47fec0942fa0 -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptscat/scriptlist-frontend/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptscat/scriptlist-frontend/HEAD/src/app/favicon.ico -------------------------------------------------------------------------------- /public/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptscat/scriptlist-frontend/HEAD/public/assets/logo.png -------------------------------------------------------------------------------- /public/robot.txt: -------------------------------------------------------------------------------- 1 | # 2 | # robots.txt for ScriptCat 3 | # 4 | 5 | User-agent: * 6 | Allow: / 7 | Disallow: /ach-UG/ -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | plugins: ["@tailwindcss/postcss"], 3 | }; 4 | 5 | export default config; 6 | -------------------------------------------------------------------------------- /src/components/UserProfile/index.tsx: -------------------------------------------------------------------------------- 1 | export { default as UserProfileLayout } from './UserProfileLayout'; 2 | export { default as UserFavorites } from './UserFavorites'; 3 | -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | project_id: '823562' 2 | api_token_env: CROWDIN_PERSONAL_TOKEN 3 | preserve_hierarchy: true 4 | 5 | files: 6 | # JSON 翻译文件 7 | - source: /public/locales/zh-CN/**/* 8 | translation: /public/locales/%locale%/**/%original_file_name% 9 | -------------------------------------------------------------------------------- /src/app/[locale]/scripts/create/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ScriptCreateWrapper from '@/components/ScriptEditor/ScriptCreateWrapper'; 3 | 4 | export default function ScriptCreatePage() { 5 | return ; 6 | } 7 | -------------------------------------------------------------------------------- /src/app/[locale]/users/settings/components/index.ts: -------------------------------------------------------------------------------- 1 | export { default as WebhookSettings } from './WebhookSettings'; 2 | export { default as NotificationSettings } from './NotificationSettings'; 3 | export { default as SettingsClient } from './SettingsClient'; 4 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strictNullChecks": true, 4 | "module": "NodeNext", 5 | "jsx": "react", 6 | "esModuleInterop": true 7 | }, 8 | "include": [ 9 | "next-env.d.ts", 10 | "**/*.ts", 11 | "**/*.tsx" 12 | ] 13 | } -------------------------------------------------------------------------------- /deploy/gateway/values.yaml: -------------------------------------------------------------------------------- 1 | # 项目名 需要使用 2 | project: scriptlist-frontend 3 | 4 | nameOverride: "" 5 | fullnameOverride: "" 6 | 7 | istio: 8 | hosts: 9 | - scriptcat.org 10 | match: 11 | canary: 12 | enabled: false 13 | match: # 染色规则 14 | - headers: 15 | cookie: 16 | regex: "^(.*?;)?(token=.+?)(;.*)?$" 17 | 18 | -------------------------------------------------------------------------------- /src/components/MarkdownView/markdown.css: -------------------------------------------------------------------------------- 1 | /* 基础 markdown 样式 */ 2 | .markdown-body { 3 | background-color: unset !important; 4 | } 5 | 6 | .markdown-body ul { 7 | list-style: disc; 8 | } 9 | 10 | .markdown-body ol { 11 | list-style: decimal; 12 | } 13 | 14 | .markdown-body img, 15 | svg, 16 | video, 17 | canvas, 18 | audio, 19 | iframe, 20 | embed, 21 | object { 22 | display: inline; 23 | vertical-align: baseline; 24 | } -------------------------------------------------------------------------------- /deploy/helm/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "scriptcat-list-frontend.serviceAccountName" . }} 6 | labels: 7 | {{- include "scriptcat-list-frontend.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /src/lib/api/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * API配置 3 | */ 4 | export const API_CONFIG = { 5 | // 使用现有的环境变量配置 6 | baseURL: 7 | process.env.APP_API_URL || 8 | process.env.NEXT_PUBLIC_APP_URL + '/api/v2' || 9 | '', 10 | timeout: 20000, 11 | defaultHeaders: { 12 | 'Content-Type': 'application/json', 13 | }, 14 | // 添加默认请求配置 15 | defaultRequestInit: { 16 | credentials: 'include' as RequestCredentials, // 包含Cookie 17 | }, 18 | } as const; 19 | -------------------------------------------------------------------------------- /deploy/helm/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /deploy/helm/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "scriptcat-list-frontend.fullname" . }} 5 | labels: 6 | {{- include "scriptcat-list-frontend.labels" . | nindent 4 }} 7 | spec: 8 | type: {{ .Values.service.type }} 9 | ports: 10 | - port: {{ .Values.service.port }} 11 | targetPort: http 12 | protocol: TCP 13 | name: http 14 | selector: 15 | {{- include "scriptcat-list-frontend.selectorLabels" . | nindent 4 }} 16 | -------------------------------------------------------------------------------- /next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from 'next'; 2 | import createNextIntlPlugin from 'next-intl/plugin'; 3 | 4 | const withNextIntl = createNextIntlPlugin('./src/i18n/request.ts'); 5 | 6 | const nextConfig: NextConfig = { 7 | env: {}, 8 | output: 'standalone', 9 | async rewrites() { 10 | return [ 11 | { 12 | source: '/api/v2/:path*', 13 | destination: `${process.env.APP_API_PROXY}/:path*`, 14 | }, 15 | ]; 16 | }, 17 | }; 18 | 19 | export default withNextIntl(nextConfig); 20 | -------------------------------------------------------------------------------- /deploy/helm/templates/tests/test-connection.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: "{{ include "scriptcat-list-frontend.fullname" . }}-test-connection" 5 | labels: 6 | {{- include "scriptcat-list-frontend.labels" . | nindent 4 }} 7 | annotations: 8 | "helm.sh/hook": test 9 | spec: 10 | containers: 11 | - name: wget 12 | image: busybox 13 | command: ['wget'] 14 | args: ['{{ include "scriptcat-list-frontend.fullname" . }}:{{ .Values.service.port }}'] 15 | restartPolicy: Never 16 | -------------------------------------------------------------------------------- /src/middleware.ts: -------------------------------------------------------------------------------- 1 | import createMiddleware from 'next-intl/middleware'; 2 | import { routing } from './i18n/routing'; 3 | 4 | export default createMiddleware({ 5 | ...routing, 6 | // 启用自动语言检测 7 | localeDetection: true, 8 | }); 9 | 10 | export const config = { 11 | // Match only internationalized pathnames 12 | matcher: [ 13 | '/', 14 | '/(zh-CN|zh-TW|ach-UG|en)/:path*', 15 | '/((?!api|_next/static|_next/image|favicon.ico|public|assets|locales|styles|robot.txt|ads.txt|sitemap.xml|manifest.json).*)', 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /src/contexts/ThemeContext.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ThemeClientProvider } from './ThemeClientContext'; 3 | import type { ThemeMode } from '@/lib/cookies'; 4 | 5 | interface ThemeProviderProps { 6 | children: React.ReactNode; 7 | initialMode?: ThemeMode; 8 | } 9 | 10 | export const ThemeProvider: React.FC = ({ 11 | children, 12 | initialMode, 13 | }) => { 14 | return ( 15 | 16 | {children} 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /src/lib/api/hooks/common.ts: -------------------------------------------------------------------------------- 1 | import useSWR from 'swr'; 2 | import type { APIError } from '@/types/api'; 3 | import type { RequestOptions } from '../client'; 4 | import { apiClient } from '../client'; 5 | 6 | /** 7 | * 通用API请求Hook 8 | * @param path - API路径 9 | * @param config - 请求配置 10 | * @returns SWR返回值 11 | */ 12 | export function useRequest(path: string, config: RequestOptions = {}) { 13 | return useSWR( 14 | [path, config], 15 | ([path, config]: [string, RequestOptions]) => 16 | apiClient.request(path, config), 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/components/NotificationBell.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { Badge } from 'antd'; 4 | import { BellOutlined } from '@ant-design/icons'; 5 | import { Link } from '@/i18n/routing'; 6 | import { useUnreadCount } from '@/lib/api/hooks/notification'; 7 | 8 | export default function NotificationBell() { 9 | const { data: unreadCount } = useUnreadCount(); 10 | 11 | return ( 12 | 13 | 14 | 15 | 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/lib/api/hooks/index.ts: -------------------------------------------------------------------------------- 1 | // 通用hooks 2 | export { useRequest } from './common'; 3 | 4 | // 脚本相关hooks(包括用户组相关的hooks,因为它们都使用scriptService) 5 | export { 6 | useInviteList, 7 | useAccessRoleList, 8 | useScriptGroupList, 9 | useGroupMemberList, 10 | useCategoryList, 11 | useScoreList, 12 | useMyScore, 13 | } from './script'; 14 | 15 | // 脚本关注hooks 16 | export { useScriptWatch } from './useScriptWatch'; 17 | 18 | // 脚本收藏hooks 19 | export { useScriptFavorite } from './useScriptFavorite'; 20 | 21 | // 用户相关hooks 22 | export { useUserDetail, useUserList } from './user'; 23 | -------------------------------------------------------------------------------- /src/app/[locale]/script-show-page/[id]/issue/create/page.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next'; 2 | import { generateScriptMetadata } from '../../metadata'; 3 | import type { ScriptDetailPageProps } from '../../types'; 4 | import CreateIssueClient from './CreateIssueClient'; 5 | 6 | export async function generateMetadata({ 7 | params, 8 | }: ScriptDetailPageProps): Promise { 9 | const { id, locale } = await params; 10 | return generateScriptMetadata(id, 'issue', locale); 11 | } 12 | 13 | export default function Create() { 14 | return ; 15 | } 16 | -------------------------------------------------------------------------------- /src/app/[locale]/script-show-page/[id]/page.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next'; 2 | import type { ScriptDetailPageProps } from './types'; 3 | import ScriptDetailClient from './components/ScriptDetailClient'; 4 | import { generateScriptMetadata } from './metadata'; 5 | 6 | export default function ScriptDetailPage() { 7 | return ; 8 | } 9 | 10 | export async function generateMetadata({ 11 | params, 12 | }: ScriptDetailPageProps): Promise { 13 | const { id, locale } = await params; 14 | return generateScriptMetadata(id, 'detail', locale); 15 | } 16 | -------------------------------------------------------------------------------- /src/app/[locale]/script-show-page/[id]/statistic/page.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next'; 2 | import type { ScriptDetailPageProps } from '../types'; 3 | import ScriptStatsClient from './components/ScriptStatsClient'; 4 | import { generateScriptMetadata } from '../metadata'; 5 | 6 | export default function ScriptStatsPage() { 7 | return ; 8 | } 9 | 10 | export async function generateMetadata({ 11 | params, 12 | }: ScriptDetailPageProps): Promise { 13 | const { id, locale } = await params; 14 | return generateScriptMetadata(id, 'stats', locale); 15 | } 16 | -------------------------------------------------------------------------------- /src/components/DayjsLocaleProvider.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useEffect } from 'react'; 4 | import { useLocale } from 'next-intl'; 5 | import { setDayjsLocale } from '@/lib/utils/dayjs-config'; 6 | 7 | /** 8 | * dayjs 语言环境初始化组件 9 | * 用于在客户端根据当前语言环境初始化 dayjs 10 | */ 11 | export function DayjsLocaleProvider({ 12 | children, 13 | }: { 14 | children: React.ReactNode; 15 | }) { 16 | const locale = useLocale(); 17 | setDayjsLocale(locale); 18 | 19 | useEffect(() => { 20 | // 当语言环境变化时,更新 dayjs 的语言设置 21 | setDayjsLocale(locale); 22 | }, [locale]); 23 | 24 | return <>{children}; 25 | } 26 | -------------------------------------------------------------------------------- /src/components/StatCard.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { Card, Typography } from 'antd'; 4 | 5 | const { Title, Text } = Typography; 6 | 7 | interface StatCardProps { 8 | value: string; 9 | label: string; 10 | color: string; 11 | } 12 | 13 | export default function StatCard({ value, label, color }: StatCardProps) { 14 | return ( 15 | 16 | 17 | {value} 18 | 19 | 20 | {label} 21 | 22 | 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /src/lib/api/index.ts: -------------------------------------------------------------------------------- 1 | // 导出API客户端 2 | export { apiClient, APIClient } from './client'; 3 | 4 | // 导出配置 5 | export { API_CONFIG } from './config'; 6 | 7 | // 导出服务 8 | export { userService } from './services/user'; 9 | export { resourceService } from './services/resource'; 10 | 11 | // 导出所有API相关类型 12 | export * from '@/types/api'; 13 | 14 | // 导入apiClient用于向后兼容 15 | import { apiClient } from './client'; 16 | 17 | // 向后兼容的API导出 18 | export const api = { 19 | get: apiClient.get.bind(apiClient), 20 | post: apiClient.post.bind(apiClient), 21 | put: apiClient.put.bind(apiClient), 22 | delete: apiClient.delete.bind(apiClient), 23 | }; 24 | -------------------------------------------------------------------------------- /src/app/[locale]/script-show-page/[id]/comment/components/rating/index.ts: -------------------------------------------------------------------------------- 1 | // 评分相关组件导出 2 | export { default as RatingOverview } from './RatingOverview'; 3 | export { default as UserRatingForm } from './UserRatingForm'; 4 | export { default as RatingList } from './RatingList'; 5 | export { default as RatingItem } from './RatingItem'; 6 | export { default as ReplyItem } from './ReplyItem'; 7 | 8 | // 工具函数导出 9 | export { getRatingText } from './utils'; 10 | 11 | // 类型导出 12 | export type { 13 | SortOption, 14 | RatingStats, 15 | RatingOverviewProps, 16 | UserRatingFormProps, 17 | RatingListProps, 18 | RatingItemProps, 19 | ReplyItemProps, 20 | } from './types'; 21 | -------------------------------------------------------------------------------- /src/app/[locale]/script-show-page/[id]/code/components/ScriptCodeClient.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { Card } from 'antd'; 4 | import React from 'react'; 5 | import MonacoEditor from '@/components/MonacoEditor'; 6 | import type { ScriptInfo } from '../../types'; 7 | 8 | type ScriptCodeClientProps = { 9 | script: ScriptInfo; 10 | }; 11 | 12 | export default function ScriptCodeClient({ script }: ScriptCodeClientProps) { 13 | return ( 14 | 15 | 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /src/components/GoogleAd/script.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { usePathname } from 'next/navigation'; 4 | import Script from 'next/script'; 5 | 6 | const GoogleAdScript: React.FC = () => { 7 | const pathname = usePathname(); 8 | 9 | // 如果pathname匹配/script-show-page/\d+/ 10 | if (!/\/script-show-page\/\d+[/]?$/.test(pathname)) { 11 | return <>; 12 | } 13 | 14 | return ( 15 |