Skip to content

Commit c3205eb

Browse files
committed
feat: Added use-local-storage.
1 parent 1ed0d82 commit c3205eb

File tree

9 files changed

+398
-7
lines changed

9 files changed

+398
-7
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
```tsx
2+
const [value, setValue] = useLocalStorage({
3+
key: 'color-scheme',
4+
defaultValue: 'dark',
5+
});
6+
7+
// Value is set both to state and localStorage at 'color-scheme'
8+
setValue('light');
9+
10+
// You can also use callback like in useState hook to set value
11+
setValue(current => (current === 'dark' ? 'light' : 'dark'));
12+
13+
return <div>{value()}</div>;
14+
```
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { useLocalStorage } from 'src';
2+
import { ExampleBase } from '../example-base';
3+
import Code from './use-local-storage.code.mdx';
4+
5+
import { FlowProps } from 'solid-js';
6+
import { useMDXComponents } from 'solid-jsx';
7+
8+
export function UseLocalStorageExample() {
9+
const [value, setValue] = useLocalStorage({
10+
key: 'favorite-fruit',
11+
defaultValue: 'apple',
12+
});
13+
14+
// @ts-ignore
15+
const components: any = useMDXComponents();
16+
17+
return (
18+
<ExampleBase
19+
title="useLocalStorage"
20+
description="A hook that allows using value from the localStorage as a signal The hook works the same way as createSignal, but also writes the value to the localStorage."
21+
code={<Code components={components} />}
22+
>
23+
<div class="flex h-full w-full flex-col items-center justify-center gap-3 rounded-md border p-3 py-10 text-center transition-colors">
24+
<div class="flex flex-wrap gap-3">
25+
<Key activated={value() === 'apple'} onClick={() => setValue('apple')}>
26+
🍎 apple
27+
</Key>
28+
<Key activated={value() === 'orange'} onClick={() => setValue('orange')}>
29+
🍊 orange
30+
</Key>
31+
<Key activated={value() === 'grape'} onClick={() => setValue('grape')}>
32+
🍇 grape
33+
</Key>
34+
<Key activated={value() === 'kiwi'} onClick={() => setValue('kiwi')}>
35+
🥝 kiwi{' '}
36+
</Key>
37+
</div>
38+
39+
<span class="text-neutral-500">Favorite Fruit: {value()}</span>
40+
</div>
41+
</ExampleBase>
42+
);
43+
}
44+
45+
function Key(props: FlowProps<{ activated: boolean; onClick: () => void }>) {
46+
return (
47+
<button onClick={props.onClick} class="relative text-xs">
48+
<div class="absolute inset-0 rounded-md bg-neutral-200 transition"></div>
49+
<div
50+
class="relative transform rounded-md border bg-neutral-50 px-2 py-1.5 transition-transform"
51+
style={{
52+
transform: props.activated ? 'translateY(0px)' : 'translateY(-5px)',
53+
}}
54+
>
55+
{props.children}
56+
</div>
57+
</button>
58+
);
59+
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
```tsx
2-
const [value, toggle] = useToggle(['apple', 'orange', 'grape', 'kiwi'] as const);
2+
const [value, toggle] = useToggle(
3+
['apple', 'orange', 'grape', 'kiwi'] as const
4+
);
35

46
return <div>{value()}</div>;
57
```

dev/icons/github.tsx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { JSX, VoidProps } from 'solid-js';
2+
3+
export default function IconGithub(props: VoidProps<JSX.SvgSVGAttributes<SVGSVGElement>>) {
4+
return (
5+
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" {...props}>
6+
<mask id="lineMdGithubLoop0" width="24" height="24" x="0" y="0">
7+
<g fill="#fff">
8+
<ellipse cx="9.5" cy="9" rx="1.5" ry="1" />
9+
<ellipse cx="14.5" cy="9" rx="1.5" ry="1" />
10+
</g>
11+
</mask>
12+
<g
13+
fill="none"
14+
stroke="currentColor"
15+
stroke-linecap="round"
16+
stroke-linejoin="round"
17+
stroke-width="2"
18+
>
19+
<path
20+
stroke-dasharray="32"
21+
stroke-dashoffset="32"
22+
d="M12 4c1.67 0 2.61 0.4 3 0.5c0.53 -0.43 1.94 -1.5 3.5 -1.5c0.34 1 0.29 2.22 0 3c0.75 1 1 2 1 3.5c0 2.19 -0.48 3.58 -1.5 4.5c-1.02 0.92 -2.11 1.37 -3.5 1.5c0.65 0.54 0.5 1.87 0.5 2.5c0 0.73 0 3 0 3M12 4c-1.67 0 -2.61 0.4 -3 0.5c-0.53 -0.43 -1.94 -1.5 -3.5 -1.5c-0.34 1 -0.29 2.22 0 3c-0.75 1 -1 2 -1 3.5c0 2.19 0.48 3.58 1.5 4.5c1.02 0.92 2.11 1.37 3.5 1.5c-0.65 0.54 -0.5 1.87 -0.5 2.5c0 0.73 0 3 0 3"
23+
>
24+
<animate fill="freeze" attributeName="stroke-dashoffset" dur="0.7s" values="32;0" />
25+
</path>
26+
<path
27+
stroke-dasharray="10"
28+
stroke-dashoffset="10"
29+
d="M9 19c-1.406 0-2.844-.563-3.688-1.188C4.47 17.188 4.22 16.157 3 15.5"
30+
>
31+
<animate
32+
attributeName="d"
33+
dur="3s"
34+
repeatCount="indefinite"
35+
values="M9 19c-1.406 0-2.844-.563-3.688-1.188C4.47 17.188 4.22 16.157 3 15.5;M9 19c-1.406 0-3-.5-4-.5-.532 0-1 0-2-.5;M9 19c-1.406 0-2.844-.563-3.688-1.188C4.47 17.188 4.22 16.157 3 15.5"
36+
/>
37+
<animate
38+
fill="freeze"
39+
attributeName="stroke-dashoffset"
40+
begin="0.8s"
41+
dur="0.2s"
42+
values="10;0"
43+
/>
44+
</path>
45+
</g>
46+
<rect width="8" height="4" x="8" y="11" fill="currentColor" mask="url(#lineMdGithubLoop0)">
47+
<animate
48+
attributeName="y"
49+
dur="10s"
50+
keyTimes="0;0.45;0.46;0.54;0.55;1"
51+
repeatCount="indefinite"
52+
values="11;11;7;7;11;11"
53+
/>
54+
</rect>
55+
</svg>
56+
);
57+
}

dev/icons/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export { default as IconCheck } from './check';
22
export { default as IconCode } from './code';
33
export { default as IconCopy } from './copy';
4+
export { default as IconGithub } from './github';
45
export { default as IconLogo } from './logo';

dev/pages/index/+Page.tsx

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ import { UseFaviconExample } from 'dev/components/examples/use-favicon/use-favic
77
import { UseHotkeysExample } from 'dev/components/examples/use-hotkeys/use-hotkeys.example';
88
import { UseHoverExample } from 'dev/components/examples/use-hover/use-hover.example';
99
import { UseIdleExample } from 'dev/components/examples/use-idle/use-idle.example';
10+
import { UseLocalStorageExample } from 'dev/components/examples/use-local-storage/use-local-storage.example';
1011
import { UseMountedExample } from 'dev/components/examples/use-mounted/use-mounted.example';
1112
import { UseNetworkExample } from 'dev/components/examples/use-network/use-network.example';
1213
import { UseOsExample } from 'dev/components/examples/use-os/use-os.example';
1314
import { UseResizeObserverExample } from 'dev/components/examples/use-resize-observer/use-resize-observer.example';
1415
import { UseToggleExample } from 'dev/components/examples/use-toggle/use-toggle.example';
15-
import { IconLogo } from 'dev/icons';
16-
import { createMemo, createSignal, For } from 'solid-js';
17-
import { useOs } from 'src';
16+
import { IconCheck, IconCopy, IconGithub, IconLogo } from 'dev/icons';
17+
import { createMemo, createSignal, For, Show } from 'solid-js';
18+
import { useOs, useToggle } from 'src';
1819

1920
export default function HomePage() {
2021
// // let ref = useClickOutside(() =>
@@ -83,14 +84,35 @@ export default function HomePage() {
8384
title: 'useFavicon',
8485
example: <UseFaviconExample />,
8586
},
87+
{
88+
title: 'useLocalStorage',
89+
example: <UseLocalStorageExample />,
90+
},
8691
];
8792

8893
const filteredList = createMemo(() => {
8994
return LIST.filter(item => item.title.toLowerCase().includes(searchInput().toLowerCase()));
9095
});
9196

97+
const [copied, setCopied] = createSignal(false);
98+
const [pkgManager, togglePkgManager] = useToggle(['npm', 'bun', 'pnpm', 'yarn'] as const);
99+
const pkgManagerColor = createMemo(() => {
100+
if (pkgManager() === 'npm') return '#E5312F';
101+
if (pkgManager() === 'bun') return '#FBF0DF';
102+
if (pkgManager() === 'pnpm') return '#F9AD00';
103+
if (pkgManager() === 'yarn') return '#2C8EBB';
104+
return undefined;
105+
});
106+
92107
return (
93-
<div class="flex flex-col items-start gap-y-5">
108+
<div class="relative flex flex-col items-start gap-y-5">
109+
<a
110+
href="https://github.com/Blankeos/bagon-hooks"
111+
target="_blank"
112+
class="absolute right-0 top-0 m-5 p-1 transition active:scale-95"
113+
>
114+
<IconGithub class="h-6 w-6 text-white" />
115+
</a>
94116
<div class="mx-auto flex w-full max-w-4xl flex-col gap-y-5 px-4 py-20">
95117
<IconLogo width={80} height={80} variant="inverted" class="self-center" />
96118

@@ -100,8 +122,34 @@ export default function HomePage() {
100122
some improvements.
101123
</p>
102124

103-
<div class="mx-auto rounded-md border border-neutral-950 bg-neutral-800 p-4 text-muted">
104-
npm install bagon-hooks
125+
<div class="class mx-auto flex items-center gap-x-4 rounded-md border border-neutral-950 bg-neutral-800 p-4 text-muted">
126+
<span>
127+
<span class="text-green-500">{'>'}</span>{' '}
128+
<button
129+
class="rounded-md border bg-opacity-50 px-1.5 font-semibold"
130+
style={{ 'border-color': pkgManagerColor() }}
131+
onClick={togglePkgManager}
132+
>
133+
{pkgManager()}
134+
</button>{' '}
135+
install bagon-hooks
136+
</span>
137+
<button
138+
class="transition active:scale-90"
139+
onClick={() => {
140+
navigator.clipboard.writeText(`${pkgManager()} install bagon-hooks`);
141+
setCopied(true);
142+
setTimeout(() => {
143+
setCopied(false);
144+
}, 800);
145+
}}
146+
>
147+
<Show
148+
when={copied()}
149+
fallback={<IconCopy width={23} height={23} />}
150+
children={<IconCheck width={23} height={23} />}
151+
/>
152+
</button>
105153
</div>
106154

107155
<input

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export * from './use-favicon/use-favicon';
33
export * from './use-hotkeys/use-hotkeys';
44
export * from './use-hover/use-hover';
55
export * from './use-idle/use-idle';
6+
export * from './use-local-storage/use-local-storage';
67
export * from './use-mounted/use-mounted';
78
export * from './use-network/use-network';
89
export * from './use-os/use-os';

0 commit comments

Comments
 (0)