Skip to content

Commit

Permalink
feat(ui): tool header
Browse files Browse the repository at this point in the history
  • Loading branch information
CorentinTh committed Oct 6, 2024
1 parent 161b9e6 commit 00fd51a
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 57 deletions.
30 changes: 30 additions & 0 deletions packages/app/src/modules/tools/components/tool-header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { Component, ParentComponent } from 'solid-js';
import { cn } from '@/modules/ui/utils/cn';

export const ToolHeader: ParentComponent<{ name: string; description: string; icon: string }> = (props) => {
return (
<div>
<div class="w-full bg-[linear-gradient(to_right,#80808010_1px,transparent_1px),linear-gradient(to_bottom,#80808010_1px,transparent_1px)] bg-[size:48px_48px] pt-12">

<div class="flex gap-4 mb-8 max-w-1200px mx-auto px-6 items-start flex-col md:flex-row md:items-center">
<div class="bg-card p-4 rounded-lg">
<div class={cn(props.icon, 'size-8 md:size-12 text-muted-foreground')} />
</div>

<div>
<h1 class="text-xl font-semibold">
{props.name}
</h1>
<div class="text-muted-foreground text-base">
{props.description}
</div>
</div>
</div>

<div class="bg-gradient-to-t dark:from-background to-transparent h-24 mt-12 mb--24"></div>
</div>

{props.children}
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,45 @@ import type { Component } from 'solid-js';
import { CopyButton } from '@/modules/shared/copy/copy-button';
import { createRefreshableSignal } from '@/modules/shared/signals';
import { Button } from '@/modules/ui/components/button';
import { Card, CardContent, CardHeader } from '@/modules/ui/components/card';
import { ToolHeader } from '../../components/tool-header';
import { useCurrentTool } from '../../tools.provider';
import defaultDictionary from './locales/en.json';
import { generateRandomPort } from './random-port-generator.services';

const RandomPortGenerator: Component = () => {
const [getPort, refreshPort] = createRefreshableSignal(generateRandomPort);
const { t } = useCurrentTool({ defaultDictionary });
const { t, getTool } = useCurrentTool({ defaultDictionary });

return (
<div class="mx-auto max-w-1200px p-6">
<div>
{getPort()}
</div>
<div>
<ToolHeader {...getTool()} />

<div class="max-w-600px mx-auto px-6">
<Card>
<CardHeader class="flex justify-between items-center">
<div class="my-6 text-center">

<div class="text-base text-muted-foreground mb-2">
Random port:
</div>

<div class="text-4xl font-mono">

{getPort()}
</div>
</div>

<div class="flex gap-4 mt-4">
<Button onClick={refreshPort} variant="outline">
<div class="i-tabler-refresh mr-2 text-base text-muted-foreground" />
{t('refresh')}
</Button>
<div class="flex gap-2 md:gap-4 mt-4 flex-col md:flex-row w-full justify-center">
<Button onClick={refreshPort} variant="outline">
<div class="i-tabler-refresh mr-2 text-base text-muted-foreground" />
{t('refresh')}
</Button>

<CopyButton textToCopy={getPort} toastMessage={t('copy-toast')} />
<CopyButton textToCopy={getPort} toastMessage={t('copy-toast')} />
</div>
</CardHeader>
</Card>
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { CopyButton } from '@/modules/shared/copy/copy-button';
import { createRefreshableSignal } from '@/modules/shared/signals';
import { Button } from '@/modules/ui/components/button';
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/modules/ui/components/card';
import { Switch, SwitchControl, SwitchLabel, SwitchThumb } from '@/modules/ui/components/switch';
import { TextArea } from '@/modules/ui/components/textarea';
import { TextFieldRoot } from '@/modules/ui/components/textfield';
import { type Component, createSignal } from 'solid-js';
import { ToolHeader } from '../../components/tool-header';
import { useCurrentTool } from '../../tools.provider';
import defaultDictionary from './locales/en.json';
import { createToken } from './token-generator.models';
Expand All @@ -13,57 +18,90 @@ const TokenGeneratorTool: Component = () => {
const [getUseSpecialCharacters, setUseSpecialCharacters] = createSignal(false);
const [getLength] = createSignal(64);

const { t } = useCurrentTool({ defaultDictionary });
const { t, getTool } = useCurrentTool({ defaultDictionary });

const getToken = () => createToken({
const [getToken, refreshToken] = createRefreshableSignal(() => createToken({
withUppercase: getUseUpperCase(),
withLowercase: getUseLowerCase(),
withNumbers: getUseNumbers(),
withSymbols: getUseSpecialCharacters(),
length: getLength(),
});
}));

return (
<div class="space-y-2 mx-auto max-w-1200px p-6">
<Switch class="flex items-center space-x-2" checked={getUseUpperCase()} onChange={setUseUpperCase}>
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<SwitchLabel class="text-sm font-medium leading-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-70">
{t('uppercase')}
</SwitchLabel>
</Switch>

<Switch class="flex items-center space-x-2" checked={getUseLowerCase()} onChange={setUseLowerCase}>
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<SwitchLabel class="text-sm font-medium leading-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-70">
{t('lowercase')}
</SwitchLabel>
</Switch>

<Switch class="flex items-center space-x-2" checked={getUseNumbers()} onChange={setUseNumbers}>
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<SwitchLabel class="text-sm font-medium leading-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-70">
{t('numbers')}
</SwitchLabel>
</Switch>

<Switch class="flex items-center space-x-2" checked={getUseSpecialCharacters()} onChange={setUseSpecialCharacters}>
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<SwitchLabel class="text-sm font-medium leading-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-70">
{t('symbols')}
</SwitchLabel>
</Switch>

<TextFieldRoot>
<TextArea placeholder="Your token will appear here" value={getToken()} readonly />
</TextFieldRoot>
<div>
<ToolHeader {...getTool()} />

<div class="mx-auto max-w-1200px p-6 flex flex-col gap-4 md:flex-row items-start">
<Card>
<CardHeader class="border-b border-border">
<CardTitle class="text-muted-foreground">
Configuration
</CardTitle>
</CardHeader>

<CardContent class="pt-6 flex flex-col gap-2">
<Switch class="flex items-center gap-2" checked={getUseUpperCase()} onChange={setUseUpperCase}>
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<SwitchLabel class="text-sm font-medium leading-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-70">
{t('uppercase')}
</SwitchLabel>
</Switch>

<Switch class="flex items-center gap-2" checked={getUseLowerCase()} onChange={setUseLowerCase}>
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<SwitchLabel class="text-sm font-medium leading-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-70">
{t('lowercase')}
</SwitchLabel>
</Switch>

<Switch class="flex items-center gap-2" checked={getUseNumbers()} onChange={setUseNumbers}>
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<SwitchLabel class="text-sm font-medium leading-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-70">
{t('numbers')}
</SwitchLabel>
</Switch>

<Switch class="flex items-center gap-2" checked={getUseSpecialCharacters()} onChange={setUseSpecialCharacters}>
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<SwitchLabel class="text-sm font-medium leading-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-70">
{t('symbols')}
</SwitchLabel>
</Switch>
</CardContent>

</Card>

<Card class="flex-1">
<CardHeader class="border-b border-border flex justify-between flex-row py-3 items-center">
<CardTitle class="text-muted-foreground">
Your token
</CardTitle>

<div class="flex justify-center items-center gap-2">
<Button onClick={refreshToken} variant="outline">
<div class="i-tabler-refresh mr-2 text-base text-muted-foreground" />
Refresh token
</Button>

<CopyButton textToCopy={getToken} toastMessage={t('copy-toast')} />
</div>
</CardHeader>

<CardContent class="pt-6 text-center">
{getToken()}
</CardContent>

</Card>
</div>
</div>
);
};
Expand Down
13 changes: 11 additions & 2 deletions packages/app/src/modules/tools/pages/tool.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { getToolDefinitionBySlug } from '../tools.registry';

export const ToolPage: Component = () => {
const params = useParams();
const { getLocale } = useI18n();
const { getLocale, t } = useI18n();

const toolDefinition = getToolDefinitionBySlug({ slug: params.toolSlug });
const ToolComponent = lazy(toolDefinition.entryFile);
Expand All @@ -25,7 +25,16 @@ export const ToolPage: Component = () => {
return (
<Show when={toolDict()}>
{toolLocaleDict => (
<CurrentToolProvider toolLocaleDict={toolLocaleDict}>
<CurrentToolProvider
toolLocaleDict={toolLocaleDict}
tool={() => ({
icon: toolDefinition.icon,
dirName: toolDefinition.dirName,
createdAt: toolDefinition.createdAt,
name: t(`tools.${toolDefinition.slug}.name` as any),
description: t(`tools.${toolDefinition.slug}.description` as any),
})}
>
<ToolComponent />
</CurrentToolProvider>
)}
Expand Down
7 changes: 6 additions & 1 deletion packages/app/src/modules/tools/tools.provider.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import type { Accessor, ParentComponent } from 'solid-js';
import type { ToolDefinition } from './tools.types';
import { flatten, translator } from '@solid-primitives/i18n';
import { merge } from 'lodash-es';
import { createContext, useContext } from 'solid-js';

type ToolProviderContext = {
toolLocaleDict: Accessor<Record<string, string>>;
tool: Accessor<Pick<ToolDefinition, 'icon' | 'dirName' | 'createdAt'> & { name: string; description: string }>;
};

const CurrentToolContext = createContext<ToolProviderContext>();
Expand All @@ -16,8 +18,11 @@ export function useCurrentTool<T>({ defaultDictionary }: { defaultDictionary: T
throw new Error('useCurrentTool must be used within a CurrentToolProvider');
}

const { toolLocaleDict, tool } = context;

return {
t: translator(() => flatten(merge({}, defaultDictionary, context.toolLocaleDict()))),
t: translator(() => flatten(merge({}, defaultDictionary, toolLocaleDict()))),
getTool: tool,
};
}

Expand Down
3 changes: 3 additions & 0 deletions packages/app/src/modules/tools/tools.types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import type { Flatten, Translator } from '@solid-primitives/i18n';
import type { defineTool } from './tools.models';

export type ToolI18nFactory = <T extends Record<string, string>>(args: { defaultDictionary: T }) => { t: Translator<Flatten<T>> };

export type ToolDefinition = ReturnType<typeof defineTool>;

0 comments on commit 00fd51a

Please sign in to comment.