Skip to content

Commit

Permalink
added a search bar to zerochan modal
Browse files Browse the repository at this point in the history
improved the zerochan modal ux
  • Loading branch information
ker0olos committed Dec 5, 2023
1 parent 49ceb90 commit b22fc17
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 51 deletions.
35 changes: 11 additions & 24 deletions components/Characters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ export default (
) => {
const [, updateState] = useState({});

const zeroChanImages = useSignal<Image[]>([]);
const dialogRef = useRef<HTMLDivElement>(null);

const zeroChanModal = useSignal(false);

// used to force the entire component to redrew
Expand Down Expand Up @@ -82,33 +83,18 @@ export default (

const substringQuery = useSignal('');

const onZeroChan = useCallback(async () => {
zeroChanModal.value = true;

const data = await fetch('/api/zerochan', {
method: 'POST',
body: JSON.stringify(
{
query: [
primaryMediaRef?.title.english,
signal.value.name.english,
]
.filter(Boolean),
} satisfies Data,
),
});

const images: Image[] = await data.json();
const onZeroChan = () => zeroChanModal.value = true;

zeroChanImages.value = images;
}, [primaryMediaRef, signal]);

const dialogRef = useRef<HTMLDivElement>(null);
// reset zerochan
useEffect(() => {
zeroChanModal.value = false;
}, [signal.value]);

// reset dialog scroll y
useEffect(() => {
// deno-lint-ignore no-non-null-assertion
requestAnimationFrame(() => dialogRef.current!.scrollTop = 0);
}, [zeroChanModal.value]);
}, [signal.value, zeroChanModal.value]);

return (
<div class={visible ? '' : 'hidden'}>
Expand Down Expand Up @@ -238,7 +224,8 @@ export default (
? (
<ZeroChanModal
visible={zeroChanModal}
images={zeroChanImages}
character={signal.value.name.english}
media={primaryMediaRef?.title.english}
callback={(imageUrl) => {
signal.value.images = [{ url: imageUrl }];
onCharacterUpdate();
Expand Down
76 changes: 67 additions & 9 deletions components/ZeroChanModal.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,88 @@
import IconClose from 'icons/x.tsx';
import { useEffect, useMemo } from 'preact/hooks';

import { Signal } from '@preact/signals';
import { type Signal, useSignal } from '@preact/signals';

import type { Image } from '../routes/api/zerochan.ts';
import TextInput from './TextInput.tsx';

import IconLeft from 'icons/arrow-left.tsx';

import { i18n } from '../utils/i18n.ts';

import type { Data, Image } from '../routes/api/zerochan.ts';
import { useDebounce } from '../utils/useDebounce.tsx';

export const ZeroChanModal = (
{ visible, images, callback }: {
{ character, media, visible, callback }: {
media?: string;
character?: string;
visible: Signal<boolean>;
images: Signal<Image[]>;
callback: (imageUrl: string) => void;
},
) => {
const error = useSignal('');
const images = useSignal<Image[]>([]);

const [debouncedQuery, query, setQuery] = useDebounce('', 300);

useEffect(
() =>
setQuery([
media,
character,
// character?.replaceAll(':', '') + ` (${media?.replaceAll(':', '')})`,
].join(',')),
[media, character],
);

useEffect(() => {
if (!debouncedQuery) return;

error.value = '', images.value = [];

fetch('/api/zerochan', {
method: 'POST',
body: JSON.stringify({ query: debouncedQuery } satisfies Data),
})
.then((res) => {
if (res.status !== 200) {
error.value = res.statusText;
return;
}

return res.json();
})
.then((data: Image[]) => {
images.value = data ?? [];
});
}, [debouncedQuery]);

return (
<>
<div
class={'basis-full cursor-pointer'}
class={'w-full cursor-pointer'}
onClick={() => visible.value = false}
>
<IconClose class={'ml-auto w-[24px] h-[24px]'} />
<IconLeft class={'w-[24px] h-[24px]'} />
</div>

<div class={'flex flex-wrap justify-center gap-4'}>
<TextInput
placeholder={i18n('search')}
class={'border-b-2 border-grey border-solid rounded-[0px]'}
onInput={(value) => setQuery(value)}
value={query}
/>

<div class={'flex flex-wrap grow justify-center gap-4'}>
{error.value ? <span>{error}</span> : undefined}

{!error.value && images.value.length <= 0
? <span>{i18n('loading')}</span>
: undefined}

{images.value.map((image) => (
<img
key={image.id}
class={'w-auto h-[192px] object-cover object-center aspect-[90/127] cursor-pointer'}
class={'w-auto h-[192px] object-cover object-center aspect-[90/127] cursor-pointer hover:scale-95 hover:border-[3px] border-white border-solid'}
src={image.thumbnail}
onClick={() => {
callback(image.thumbnail);
Expand Down
2 changes: 2 additions & 0 deletions i18n/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export default {
searchCharactersPlaceholder: 'Search Characters',
searchMediaPlaceholder: 'Search Series',

loading: 'Loading...',

//
placeholderGender: 'Classified',
placeholderAge: 'Ancient',
Expand Down
2 changes: 2 additions & 0 deletions i18n/es-ES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export default {
searchCharactersPlaceholder: 'Search Characters',
searchMediaPlaceholder: 'Search Series',

loading: 'Loading...',

//
placeholderGender: 'Clasificado',
placeholderAge: 'Ancestral',
Expand Down
8 changes: 6 additions & 2 deletions islands/Manage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import IconApply from 'icons/check.tsx';
import IconAdjustments from 'icons/adjustments-horizontal.tsx';
import IconCheckmark from 'icons/check.tsx';
import IconClipboard from 'icons/clipboard-text.tsx';
import IconWorld from 'icons/world.tsx';
import IconLock from 'icons/lock.tsx';

import nanoid from '../utils/nanoid.ts';
import compact from '../utils/compact.ts';
Expand Down Expand Up @@ -413,7 +415,8 @@ export default (props: {
' ',
)}
/>
<span>{i18n('publicPackNotice')}</span>
<span class={'grow'}>{i18n('publicPackNotice')}</span>
<IconWorld class={'w-6 h-6'} />
</button>
<button
onClick={() => privacy.value = true}
Expand All @@ -424,7 +427,8 @@ export default (props: {
' ',
)}
/>
<span>{i18n('privatePackNotice')}</span>
<span class={'grow'}>{i18n('privatePackNotice')}</span>
<IconLock class={'w-6 h-6'} />
</button>
</div>
</div>
Expand Down
40 changes: 24 additions & 16 deletions routes/api/zerochan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import nanoid from '../../utils/nanoid.ts';

import type { Handlers } from '$fresh/server.ts';

const endpoint = 'https://www.zerochan.net/api';
const endpoint = 'https://www.zerochan.net';

export interface Data {
query: string[];
after?: number;
query: string;
// after?: number;
}

export interface Image {
Expand All @@ -24,21 +24,29 @@ export const handler: Handlers = {
const data: Data = await req.json();

const limit = 10;
const after = data.after || 0;

const res = await fetch(
`${endpoint}/${
data.query.join(',')
}?l=${limit}&p=${after}&d=portrait&json`,
{
headers: {
'User-Agent': `Fable Discord Bot Packs Integration - user${nanoid()}`,
},
const after = 0;

const url = `${endpoint}/${
encodeURIComponent(data.query)
}?l=${limit}&p=${after}&d=portrait&json`;

console.log(url);

const res = await fetch(url, {
headers: {
'User-Agent': `Fable Discord Bot Packs Integration - user${nanoid()}`,
},
);
});

if (res.status === 200) {
const { items: images }: { items: Image[] } = await res.json();

const { items: images }: { items: Image[] } = await res.json();
return new Response(JSON.stringify(images));
}

return new Response(JSON.stringify(images));
return new Response(undefined, {
status: res.status,
statusText: res.statusText,
});
},
};
21 changes: 21 additions & 0 deletions utils/useDebounce.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { type StateUpdater, useEffect, useState } from 'preact/hooks';

export const useDebounce = <T,>(
initialValue: T,
time: number,
): [T, T, StateUpdater<T>] => {
const [value, setValue] = useState<T>(initialValue);
const [debouncedValue, setDebouncedValue] = useState<T>(initialValue);

useEffect(() => {
const debounce = setTimeout(() => {
setDebouncedValue(value);
}, time);

return () => {
clearTimeout(debounce);
};
}, [value, time]);

return [debouncedValue, value, setValue];
};

0 comments on commit b22fc17

Please sign in to comment.