diff --git a/README.md b/README.md index 424e70b..37c28c8 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Based on the [@mantine/hooks](https://github.com/mantinedev/mantine/tree/master/ - [ ] use-document-visibility - [ ] use-event-listener - [ ] use-eye-dropper -- [ ] use-favicon +- [x] use-favicon - [ ] use-fetch - [ ] use-focus-return - [ ] use-focus-trap diff --git a/dev/components/examples/example-base.tsx b/dev/components/examples/example-base.tsx index 582f0ae..73a1831 100644 --- a/dev/components/examples/example-base.tsx +++ b/dev/components/examples/example-base.tsx @@ -12,9 +12,9 @@ export function ExampleBase(props: FlowProps) { const [viewing, setViewing] = createSignal<'code' | 'result'>('result'); return ( -
+
-

{props.title}

+

{props.title}

-

{props.description}

+ +

{props.description}

{props.children}
@@ -32,7 +33,7 @@ export function ExampleBase(props: FlowProps) {
{props.code}
diff --git a/dev/components/examples/use-favicon/use-favicon.code.mdx b/dev/components/examples/use-favicon/use-favicon.code.mdx new file mode 100644 index 0000000..34985ef --- /dev/null +++ b/dev/components/examples/use-favicon/use-favicon.code.mdx @@ -0,0 +1,12 @@ +```tsx + const [favicon, setFavicon] = createSignal('https://docs.solidjs.com/favicon.svg'); + const setXFavicon = () => setFavicon('https://x.com/favicon.ico'); + const setSolidFavicon = () => setFavicon('https://docs.solidjs.com/favicon.svg'); + + useFavicon(favicon); + + return ( + + + ) +``` diff --git a/dev/components/examples/use-favicon/use-favicon.example.tsx b/dev/components/examples/use-favicon/use-favicon.example.tsx new file mode 100644 index 0000000..05e46cd --- /dev/null +++ b/dev/components/examples/use-favicon/use-favicon.example.tsx @@ -0,0 +1,41 @@ +import { useFavicon } from 'src'; +import { ExampleBase } from '../example-base'; +import Code from './use-favicon.code.mdx'; + +import { createSignal } from 'solid-js'; +import { useMDXComponents } from 'solid-jsx'; + +export function UseFaviconExample() { + const [favicon, setFavicon] = createSignal('https://docs.solidjs.com/favicon.svg'); + const setXFavicon = () => setFavicon('https://x.com/favicon.ico'); + const setSolidFavicon = () => setFavicon('https://docs.solidjs.com/favicon.svg'); + + useFavicon(favicon); + + // @ts-ignore + const components: any = useMDXComponents(); + + return ( + } + > +
+ + + +
+
+ ); +} diff --git a/dev/components/markdown/markdown.context.tsx b/dev/components/markdown/markdown.context.tsx index 94e3eb7..ffe7465 100644 --- a/dev/components/markdown/markdown.context.tsx +++ b/dev/components/markdown/markdown.context.tsx @@ -54,8 +54,8 @@ export function MarkdownContextProvider(props: FlowProps) { fallback={} /> -
- {/* This will be replaced, but render it at first paint with opacity 0 so it takes up space. */} +
+ {/* This will be replaced with the code element, but render it at first paint with opacity 0 so it takes up space. */}
{props.children}
diff --git a/dev/pages/index/+Page.tsx b/dev/pages/index/+Page.tsx index 37abcc2..1a82df9 100644 --- a/dev/pages/index/+Page.tsx +++ b/dev/pages/index/+Page.tsx @@ -1,9 +1,9 @@ // import { createMemo, type Component } from 'solid-js'; // Hooks -import { ExampleBase } from 'dev/components/examples/example-base'; import { UseClickOutsideExample } from 'dev/components/examples/use-click-outside/use-click-outside.example'; import { UseElementSizeExample } from 'dev/components/examples/use-element-size/use-element-size.example'; +import { UseFaviconExample } from 'dev/components/examples/use-favicon/use-favicon.example'; import { UseHotkeysExample } from 'dev/components/examples/use-hotkeys/use-hotkeys.example'; import { UseHoverExample } from 'dev/components/examples/use-hover/use-hover.example'; import { UseIdleExample } from 'dev/components/examples/use-idle/use-idle.example'; @@ -12,21 +12,9 @@ import { UseNetworkExample } from 'dev/components/examples/use-network/use-netwo import { UseOsExample } from 'dev/components/examples/use-os/use-os.example'; import { UseResizeObserverExample } from 'dev/components/examples/use-resize-observer/use-resize-observer.example'; import { UseToggleExample } from 'dev/components/examples/use-toggle/use-toggle.example'; -import { MarkdownContextProvider } from 'dev/components/markdown/markdown.context'; import { IconLogo } from 'dev/icons'; -import { title } from 'process'; import { createMemo, createSignal, For } from 'solid-js'; -import { - useClickOutside, - useElementSize, - useHotkeys, - useHover, - useIdle, - useNetwork, - useOs, - useResizeObserver, - useToggle, -} from 'src'; +import { useOs } from 'src'; export default function HomePage() { // // let ref = useClickOutside(() => @@ -91,6 +79,10 @@ export default function HomePage() { title: 'useToggle', example: , }, + { + title: 'useFavicon', + example: , + }, ]; const filteredList = createMemo(() => { diff --git a/src/index.ts b/src/index.ts index ab5f38c..8a8dcd4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ export * from './use-click-outside/use-click-outside'; +export * from './use-favicon/use-favicon'; export * from './use-hotkeys/use-hotkeys'; export * from './use-hover/use-hover'; export * from './use-idle/use-idle'; diff --git a/src/use-favicon/use-favicon.tsx b/src/use-favicon/use-favicon.tsx new file mode 100644 index 0000000..699c08b --- /dev/null +++ b/src/use-favicon/use-favicon.tsx @@ -0,0 +1,38 @@ +import { Accessor, createEffect, createSignal } from 'solid-js'; + +const MIME_TYPES: Record = { + ico: 'image/x-icon', + png: 'image/png', + svg: 'image/svg+xml', + gif: 'image/gif', +}; + +/** + * A hook that sets the favicon of the page based on the url (accessor) passed. + */ +export function useFavicon(url: Accessor) { + const [linkRef, setLinkRef] = createSignal(); + + createEffect(() => { + if (!url()) { + return; + } + + if (!linkRef()) { + const existingElements = document.querySelectorAll('link[rel*="icon"]'); + existingElements.forEach(element => document.head.removeChild(element)); + + const element = document.createElement('link'); + element.rel = 'shortcut icon'; + setLinkRef(element); + document.querySelector('head')!.appendChild(element); + } + + const splittedUrl = url().split('.'); + linkRef()?.setAttribute( + 'type', + MIME_TYPES[splittedUrl?.[splittedUrl.length - 1]?.toLowerCase()!]!, + ); + linkRef()?.setAttribute('href', url()); + }); +}