refactor: deep link for faq

This commit is contained in:
鲁树人
2025-05-19 09:23:14 +09:00
parent 3ab73d8369
commit 3541af7a96
19 changed files with 300 additions and 149 deletions

View File

@@ -13,6 +13,8 @@ import { FaqTab } from '~/tabs/FaqTab';
import { SETTINGS_TABS } from '~/features/settings/settingsTabs';
import { Bounce, ToastContainer } from 'react-toastify';
import { SettingsHome } from '~/features/settings/SettingsHome';
import { FAQ_PAGES } from '~/faq/FAQPages';
import { FaqHome } from '~/faq/FaqHome';
// Private to this file only.
const store = setupStore();
@@ -49,7 +51,12 @@ export function AppRoot() {
<Route key={key} path={key} Component={Tab} />
))}
</Route>
<Route path="/questions" Component={FaqTab} />
<Route path="/questions" Component={FaqTab}>
<Route index Component={FaqHome} />
{FAQ_PAGES.map(({ id, Component }) => (
<Route key={id} path={id} Component={Component} />
))}
</Route>
</Routes>
</main>

View File

@@ -0,0 +1,9 @@
import { RiLink } from 'react-icons/ri';
export function HeaderAnchor({ id }: { id: string }) {
return (
<a href={`#${id}`} data-anchor={id} className="absolute -left-6 opacity-10 transition-opacity duration-200">
<RiLink className="max-h-[.75em]" />
</a>
);
}

View File

@@ -1,4 +1,5 @@
import React from 'react';
import { HeaderAnchor } from './HeaderAnchor';
export interface HeaderProps {
children: React.ReactNode;
@@ -6,9 +7,20 @@ export interface HeaderProps {
className?: string;
}
const commonHeaderClasses = 'relative flex items-center pt-3 pb-1 font-bold';
export function Header2({ children, className, id }: HeaderProps) {
return (
<h2 id={id} className={`${commonHeaderClasses} text-3xl border-b border-base-300 ${className}`}>
{id && <HeaderAnchor id={id} />}
{children}
</h2>
);
}
export function Header3({ children, className, id }: HeaderProps) {
return (
<h3 id={id} className={`text-2xl pt-3 pb-1 font-bold border-b border-base-300 ${className}`}>
<h3 id={id} className={`${commonHeaderClasses} text-2xl border-b border-base-300 ${className}`}>
{id && <HeaderAnchor id={id} />}
{children}
</h3>
);
@@ -16,7 +28,8 @@ export function Header3({ children, className, id }: HeaderProps) {
export function Header4({ children, className, id }: HeaderProps) {
return (
<h4 id={id} className={`text-xl pt-3 pb-1 font-semibold ${className}`}>
<h4 id={id} className={`${commonHeaderClasses} text-xl ${className}`}>
{id && <HeaderAnchor id={id} />}
{children}
</h4>
);
@@ -24,7 +37,8 @@ export function Header4({ children, className, id }: HeaderProps) {
export function Header5({ children, className, id }: HeaderProps) {
return (
<h5 id={id} className={`text-lg pt-3 pb-1 font-semibold ${className}`}>
<h5 id={id} className={`${commonHeaderClasses} text-lg ${className}`}>
{id && <HeaderAnchor id={id} />}
{children}
</h5>
);

View File

@@ -0,0 +1,43 @@
import classNames from 'classnames';
import { useRef } from 'react';
export interface ImageFigureProps {
srcSet: string;
alt: string;
className?: string;
loading?: 'lazy' | 'eager';
children?: React.ReactNode;
}
export function ImageFigure({ alt, srcSet, children, className, loading }: ImageFigureProps) {
const refDialog = useRef<HTMLDialogElement>(null);
return (
<figure className={classNames(className, 'inline-flex flex-col items-center')}>
<img
className={`rounded-md cursor-pointer border border-base-300 max-h-48`}
loading={loading}
srcSet={srcSet}
alt={alt}
onClick={() => refDialog?.current?.showModal()}
/>
{children && <figcaption className="text-sm text-base-content/70">{children}</figcaption>}
<dialog ref={refDialog} className="modal text-left">
<div className="modal-box max-w-[50vw]">
<form method="dialog">
<button className="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
</form>
<h3 className="font-bold text-lg"></h3>
<figure className="flex flex-col justify-center text-center">
<img srcSet={srcSet} alt={alt} />
{children && <figcaption className="text-sm text-base-content/70">{children}</figcaption>}
</figure>
</div>
<form method="dialog" className="modal-backdrop">
<button></button>
</form>
</dialog>
</figure>
);
}

View File

@@ -1,3 +1,4 @@
import classNames from 'classnames';
import React, { Fragment, useId } from 'react';
export type InstructionTab = {
@@ -8,19 +9,24 @@ export type InstructionTab = {
export interface InstructionsTabsProps {
tabs: InstructionTab[];
limitHeight?: boolean;
}
export function InstructionsTabs({ tabs }: InstructionsTabsProps) {
export function InstructionsTabs({ limitHeight = false, tabs }: InstructionsTabsProps) {
const id = useId();
return (
<div className="tabs tabs-lift max-h-[32rem] pb-4">
<div className={classNames('tabs tabs-lift pb-4', { 'max-h-[32rem]': limitHeight })}>
{tabs.map(({ id: _tabId, label, content }, index) => (
<Fragment key={_tabId}>
<label className="tab">
<input type="radio" name={id} defaultChecked={index === 0} />
{label}
</label>
<div className="tab-content border-base-300 bg-base-100 px-4 py-2 overflow-y-auto max-h-[30rem]">
<div
className={classNames('tab-content border-base-300 bg-base-100 px-4 py-2 overflow-y-auto', {
'max-h-[30rem]': limitHeight,
})}
>
{content}
</div>
</Fragment>