Skip to content

Commit

Permalink
feat(web): add filter card
Browse files Browse the repository at this point in the history
  • Loading branch information
yjl9903 committed Sep 16, 2024
1 parent 3d74aed commit 301bce2
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 11 deletions.
22 changes: 12 additions & 10 deletions apps/frontend/web/app/layouts/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const MaxPaddingTop = 152;
const MaxPaddingBottom = 36;
const SearchHeight = NavHeight;

export default function Layout(props: { children?: React.ReactNode, rss?: string }) {
export default function Layout(props: { children?: React.ReactNode; rss?: string }) {
const { rss } = props;
const navigation = useNavigation();

Expand Down Expand Up @@ -119,7 +119,7 @@ function Hero(props: { rss?: string }) {
}

function Header(props: { rss?: string }) {
const {rss} = props;
const { rss } = props;

return (
<nav className="z-11 fixed w-full px-8 h-$nav-height flex gap-4 [&>div]:leading-$nav-height">
Expand All @@ -138,14 +138,16 @@ function Header(props: { rss?: string }) {
</div>
<div className="flex-auto"></div>
<div>
{ rss && <a
href={rss}
target="_blank"
className="inline cursor-pointer rounded-md p-2 text-[#ee802f] hover:(!text-[#ff7800] !border-b-[#ff7800] bg-neutral-200)"
>
<span className="i-carbon-rss mr1" />
<span>RSS</span>
</a> }
{rss && (
<a
href={rss}
target="_blank"
className="inline cursor-pointer rounded-md p-2 text-[#ee802f] hover:(!text-[#ff7800] !border-b-[#ff7800] bg-neutral-200)"
>
<span className="i-carbon-rss mr1" />
<span>RSS</span>
</a>
)}
</div>
</nav>
);
Expand Down
173 changes: 173 additions & 0 deletions apps/frontend/web/app/routes/resources.$page/Filter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import { format } from 'date-fns';

import { findFansub, type ResolvedFilterOptions, type ResourceType } from 'animegarden';

import { removeQuote } from '@/utils';
import { DisplayType, DisplayTypeColor, QueryType } from '@/constant';
import { NavLink } from '@remix-run/react';

export type DisplayResolvedFilterOptions = ReturnType<typeof resolveFilterOptions>;

export function resolveFilterOptions(filter: Omit<ResolvedFilterOptions, 'page'>) {
const fansubId = filter.fansubId;
const fansubs = fansubId
? fansubId.map((id) => {
const provider = 'dmhy';
const fs = findFansub(provider, id);
return fs ? fs : { provider, providerId: id, name: id };
})
: undefined;

const rawType = (
filter.type && filter.type in QueryType ? QueryType[filter.type] : filter.type
) as ResourceType | undefined;
const type = (rawType && rawType in DisplayType) ? DisplayType[rawType] : rawType ?? '動畫';

return {
publisher: filter.publisherId,
fansubs,
type: rawType
? {
name: type,
color: DisplayTypeColor[type as ResourceType] ?? DisplayTypeColor[rawType]
}
: undefined,
before: filter.before ? new Date(filter.before) : undefined,
after: filter.after ? new Date(filter.after) : undefined,
search: filter.search ? removeQuote(filter.search) : [],
include: filter.include ?? [],
keywords: filter.keywords ?? [],
exclude: filter.exclude ?? []
};
}


interface Props {
filter?: Omit<ResolvedFilterOptions, 'page'>;
feedURL?: string;
}

const safeFormat: typeof format = (...args) => {
try {
return format(...args);
} catch (error) {
console.log(error);
return '';
}
};

export function Filter(props: Props) {
const { filter } = props;

if (!filter) return;

const { type, fansubs, after, before, search, include, keywords, exclude } = resolveFilterOptions(filter);

if (!(type || search.length > 0 || include.length > 0 || before || after || fansubs)) return;

return <div className="mb4 p4 w-full bg-gray-100 rounded-md space-y-2">
{
type && (
<div className="space-x-2 text-0">
<span className="text-4 text-base-800 font-bold mr2 select-none keyword">类型</span>
<span className={`text-4 select-text text-base-600 ${type.color}`}>{type.name}</span>
</div>
)
}
{
fansubs && (
<div className="space-x-2 text-0">
<span className="text-4 text-base-800 font-bold mr2 select-none keyword">字幕组</span>
{fansubs.map((fansub) => (
<NavLink
to={`/resources/1?fansubId=${fansub.providerId}`}
className="text-4 select-text text-link"
>
{fansub.name}
</NavLink>
))}
</div>
)
}
{
after && (
<div className="space-x-2 select-none text-0">
<span className="text-4 text-base-800 font-bold mr2 keyword">搜索开始于</span>
<span className="text-4 select-text">{safeFormat(after, 'yyyy 年 M 月 d 日 hh:mm')}</span>
</div>
)
}
{
before && (
<div className="space-x-2 select-none text-0">
<span className="text-4 text-base-800 font-bold mr2 keyword">搜索结束于</span>
<span className="text-4 select-text">{safeFormat(before, 'yyyy 年 M 月 d 日 hh:mm')}</span>
</div>
)
}
{
search.length > 0 && (
<div className="space-x-2 text-0">
{/* prettier-ignore */}
<span className="text-4 select-none text-base-800 font-bold mr2 keyword">标题搜索</span>
{search.map((i) => (
<span className="text-4 select-text underline underline-dotted underline-gray-500">{i}</span>
))}
</div>
)
}
{
search.length === 0 && include.length > 0 && (
<div className="space-x-2 text-0">
{/* prettier-ignore */}
<span className="text-4 select-none text-base-800 font-bold mr2 keyword">标题匹配</span>
{include.map((i, idx) => (
<>
{idx > 0 && <span className="text-base-400 text-4 select-none">|</span>}
{/* prettier-ignore */}
<span className="text-4 select-text underline underline-dotted underline-gray-500">{i}</span>
</>
))}
</div>
)
}
{
search.length === 0 && keywords.length > 0 && (
<div className="space-x-2 select-none text-0">
<span className="text-4 text-base-800 font-bold mr2 keyword">包含关键词</span>
{keywords.map((i, idx) => (
<>
{idx > 0 && <span className="text-base-400 text-4 select-none">&</span>}
{/* prettier-ignore */}
<span className="text-4 select-text underline underline-dotted underline-gray-500">{i}</span>
</>
))}
</div>
)
}
{
search.length === 0 && exclude.length > 0 && (
<div className="space-x-2 text-0">
{/* prettier-ignore */}
<span className="text-4 select-none text-base-800 font-bold mr2 inline-block">排除关键词</span>
{exclude.map((i) => (
<span className="text-4 select-text">{i}</span>
))}
</div>
)
}
{/* {
(search.length !== 0 || include.length !== 0 || keywords.length !== 0) && (
<div className="flex items-center gap4 pt-4">
<Button client:load variant="default" size="sm" className="copy-rss" data-rss={feedURL}>
复制 RSS 订阅链接
</Button>
<Button client:load size="sm" className="add-collection">
添加到收藏夹
</Button>
<SearchTooltip />
</div>
)
} */}
</div>
}
5 changes: 4 additions & 1 deletion apps/frontend/web/app/routes/resources.$page/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import Layout from '@/layouts/Layout';
import Resources from '@/components/Resources';
import { fetchResources } from '@/utils';

import { Filter } from './Filter';

export const meta: MetaFunction = () => {
return [
{ title: 'Anime Garden 動漫花園資源網第三方镜像站' },
Expand All @@ -26,11 +28,12 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
};

export default function ResourcesIndex() {
const { ok, resources, timestamp } = useLoaderData<typeof loader>();
const { ok, resources, filter, timestamp } = useLoaderData<typeof loader>();

return (
<Layout>
<div className="w-full pt-12 pb-24">
<Filter filter={filter as any}></Filter>
<Resources resources={resources}></Resources>
</div>
</Layout>
Expand Down

0 comments on commit 301bce2

Please sign in to comment.