diff --git a/package-lock.json b/package-lock.json index 143cad9b..bf39951b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,6 @@ "@solid-primitives/share": "2.0.4", "@solid-primitives/storage": "^3.5.0", "@solid-primitives/upload": "0.0.115", - "@solidjs/meta": "0.29.3", "@thisbeyond/solid-select": "0.14.0", "@tiptap/core": "2.2.3", "@tiptap/extension-blockquote": "2.2.3", @@ -4106,15 +4105,6 @@ "solid-js": "^1.6.12" } }, - "node_modules/@solidjs/meta": { - "version": "0.29.3", - "resolved": "https://registry.npmjs.org/@solidjs/meta/-/meta-0.29.3.tgz", - "integrity": "sha512-R2uirgjgyh3FPFh+rb840plF701N6GvM5w81/QeI61QwjXb4QzLkyI/uzXfC5UW8favpUn9KK9ILQeoTl6pX0A==", - "dev": true, - "peerDependencies": { - "solid-js": ">=1.8.4" - } - }, "node_modules/@thisbeyond/solid-select": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@thisbeyond/solid-select/-/solid-select-0.14.0.tgz", diff --git a/package.json b/package.json index f58b980a..707221bc 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,6 @@ "@solid-primitives/share": "2.0.4", "@solid-primitives/storage": "^3.5.0", "@solid-primitives/upload": "0.0.115", - "@solidjs/meta": "0.29.3", "@thisbeyond/solid-select": "0.14.0", "@tiptap/core": "2.2.3", "@tiptap/extension-blockquote": "2.2.3", diff --git a/src/components/App.tsx b/src/components/App.tsx index f8f9a6c5..55a56f81 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1,6 +1,6 @@ import type { PageProps, RootSearchParams } from '../pages/types' -import { Meta, MetaProvider } from '@solidjs/meta' +import { Meta, MetaProvider } from '../context/meta' import { Component, createEffect, createMemo } from 'solid-js' import { Dynamic } from 'solid-js/web' diff --git a/src/components/Article/FullArticle.tsx b/src/components/Article/FullArticle.tsx index 94f4eff9..78bcca55 100644 --- a/src/components/Article/FullArticle.tsx +++ b/src/components/Article/FullArticle.tsx @@ -2,7 +2,7 @@ import type { Author, Shout, Topic } from '../../graphql/schema/core.gen' import { getPagePath } from '@nanostores/router' import { createPopper } from '@popperjs/core' -import { Link, Meta } from '@solidjs/meta' +import { Link, Meta } from '../../context/meta' import { clsx } from 'clsx' import { install } from 'ga-gtag' import { For, Show, createEffect, createMemo, createSignal, on, onCleanup, onMount } from 'solid-js' diff --git a/src/components/Views/AllAuthors/AllAuthors.tsx b/src/components/Views/AllAuthors/AllAuthors.tsx index 5464891d..c3027d2c 100644 --- a/src/components/Views/AllAuthors/AllAuthors.tsx +++ b/src/components/Views/AllAuthors/AllAuthors.tsx @@ -1,6 +1,6 @@ import type { Author } from '../../../graphql/schema/core.gen' -import { Meta } from '@solidjs/meta' +import { Meta } from '../../../context/meta' import { clsx } from 'clsx' import { For, Show, createMemo, createSignal } from 'solid-js' diff --git a/src/components/Views/AllTopics/AllTopics.tsx b/src/components/Views/AllTopics/AllTopics.tsx index ae76c775..ecf35fd3 100644 --- a/src/components/Views/AllTopics/AllTopics.tsx +++ b/src/components/Views/AllTopics/AllTopics.tsx @@ -1,6 +1,6 @@ import type { Topic } from '../../../graphql/schema/core.gen' -import { Meta } from '@solidjs/meta' +import { Meta } from '../../../context/meta' import { clsx } from 'clsx' import { For, Show, createEffect, createMemo, createSignal } from 'solid-js' import { useLocalize } from '../../../context/localize' diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index ff307500..8bc68e37 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -1,7 +1,7 @@ import type { Author, Reaction, Shout, Topic } from '../../../graphql/schema/core.gen' import { getPagePath } from '@nanostores/router' -import { Meta, Title } from '@solidjs/meta' +import { Meta, Title } from '../../../context/meta' import { clsx } from 'clsx' import { For, Match, Show, Switch, createEffect, createMemo, createSignal, on, onMount } from 'solid-js' diff --git a/src/components/Views/Feed/Feed.tsx b/src/components/Views/Feed/Feed.tsx index 283ebb72..f73fdf46 100644 --- a/src/components/Views/Feed/Feed.tsx +++ b/src/components/Views/Feed/Feed.tsx @@ -1,5 +1,5 @@ import { getPagePath } from '@nanostores/router' -import { Meta } from '@solidjs/meta' +import { Meta } from '../../../context/meta' import { clsx } from 'clsx' import { For, Show, createEffect, createMemo, createSignal, on, onMount } from 'solid-js' diff --git a/src/components/Views/Topic.tsx b/src/components/Views/Topic.tsx index 1a295bcb..76fcb30f 100644 --- a/src/components/Views/Topic.tsx +++ b/src/components/Views/Topic.tsx @@ -1,6 +1,6 @@ import { LoadShoutsOptions, Shout, Topic } from '../../graphql/schema/core.gen' -import { Meta } from '@solidjs/meta' +import { Meta } from '../../context/meta' import { clsx } from 'clsx' import { For, Show, createEffect, createMemo, createSignal, on, onMount } from 'solid-js' diff --git a/src/components/_shared/Image/Image.tsx b/src/components/_shared/Image/Image.tsx index 413f66c8..6b4d8346 100644 --- a/src/components/_shared/Image/Image.tsx +++ b/src/components/_shared/Image/Image.tsx @@ -1,6 +1,6 @@ import type { JSX } from 'solid-js' -import { Link } from '@solidjs/meta' +import { Link } from '../../../context/meta' import { splitProps } from 'solid-js' import { getImageUrl } from '../../../utils/getImageUrl' diff --git a/src/components/_shared/PageLayout.tsx b/src/components/_shared/PageLayout.tsx index 1cd7abc9..71692348 100644 --- a/src/components/_shared/PageLayout.tsx +++ b/src/components/_shared/PageLayout.tsx @@ -1,6 +1,6 @@ import type { JSX } from 'solid-js' -import { Title } from '@solidjs/meta' +import { Title } from '../../context/meta' import { clsx } from 'clsx' import { Show, createEffect, createSignal } from 'solid-js' diff --git a/src/context/meta.tsx b/src/context/meta.tsx new file mode 100644 index 00000000..fdea7dca --- /dev/null +++ b/src/context/meta.tsx @@ -0,0 +1,139 @@ +import { + Component, + createContext, + createRenderEffect, + createSignal, + JSX, + onCleanup, + ParentComponent, + useContext, +} from 'solid-js' +import { isServer, spread } from 'solid-js/web' + +export const MetaContext = createContext() + +interface TagDescription { + tag: string + props: Record + cleanup?: () => void +} + +export interface MetaContextType { + addTag: (tag: TagDescription) => void + removeTag: (tag: TagDescription) => void +} + +function initClientProvider() { + const tags = new Map() + + function addTag(tag: TagDescription) { + const key = getTagKey(tag) + tags.set(key, tag) + + const el = document.createElement(tag.tag) + spread(el, tag.props) + document.head.appendChild(el) + + tag.cleanup = () => { + document.head.removeChild(el) + tags.delete(key) + } + } + + function removeTag(tag: TagDescription) { + const key = getTagKey(tag) + const existingTag = tags.get(key) + if (existingTag) { + if (existingTag.cleanup) existingTag.cleanup() + tags.delete(key) + } + } + + return { addTag, removeTag } +} + +function initServerProvider() { + const tags: TagDescription[] = [] + + function addTag(tagDesc: TagDescription) { + tags.push(tagDesc) + } + + function removeTag(tag: TagDescription) { + const index = tags.findIndex((t) => getTagKey(t) === getTagKey(tag)) + if (index !== -1) { + tags.splice(index, 1) + } + } + + return { addTag, removeTag } +} + +export const MetaProvider: ParentComponent = (props) => { + const actions = isServer ? initServerProvider() : initClientProvider() + const [tags, setTags] = createSignal([]) + + const addTag = (tag: TagDescription) => { + actions.addTag(tag) + setTags([...tags(), tag]) + } + + const removeTag = (tag: TagDescription) => { + actions.removeTag(tag) + setTags(tags().filter((t) => getTagKey(t) !== getTagKey(tag))) + } + + onCleanup(() => { + for (const tag of tags()) { + tag.cleanup?.() + } + }) + + return {props.children} +} + +const getTagKey = (tag: TagDescription) => { + const props = Object.entries(tag.props) + .filter(([k]) => k !== 'children') + .sort() + + return `${tag.tag}${JSON.stringify(props)}` +} + +export function useHead(tagDesc: TagDescription) { + const c = useContext(MetaContext) + if (!c) throw new Error(' should be in the tree') + + createRenderEffect(() => { + c.addTag(tagDesc) + + return () => { + c.removeTag(tagDesc) + } + }) +} + +const MetaTag = (tag: string, props: Record) => { + useHead({ tag, props }) + + return null +} + +export const Title: Component> = (props) => + MetaTag('title', props as Record) + +export const Style: Component> = (props) => + MetaTag('style', props as Record) + +export const Meta: Component> = (props) => + MetaTag('meta', props as Record) + +export const Link: Component> = (props) => + MetaTag('link', props as Record) + +export const Base: Component> = (props) => + MetaTag('base', props as Record) + +export const Stylesheet: Component, 'rel'>> = (props) => ( + +) diff --git a/src/pages/about/discussionRules.page.tsx b/src/pages/about/discussionRules.page.tsx index f6b2019b..917beb61 100644 --- a/src/pages/about/discussionRules.page.tsx +++ b/src/pages/about/discussionRules.page.tsx @@ -1,4 +1,4 @@ -import { Meta } from '@solidjs/meta' +import { Meta } from '../../context/meta' import { StaticPage } from '../../components/Views/StaticPage' import { useLocalize } from '../../context/localize' diff --git a/src/pages/about/dogma.page.tsx b/src/pages/about/dogma.page.tsx index 8fa5130b..ada689a5 100644 --- a/src/pages/about/dogma.page.tsx +++ b/src/pages/about/dogma.page.tsx @@ -1,4 +1,4 @@ -import { Meta } from '@solidjs/meta' +import { Meta } from '../../context/meta' import { StaticPage } from '../../components/Views/StaticPage' import { useLocalize } from '../../context/localize' diff --git a/src/pages/about/guide.page.tsx b/src/pages/about/guide.page.tsx index 95e34f5f..c2cba232 100644 --- a/src/pages/about/guide.page.tsx +++ b/src/pages/about/guide.page.tsx @@ -1,4 +1,4 @@ -import { Meta } from '@solidjs/meta' +import { Meta } from '../../context/meta' import { StaticPage } from '../../components/Views/StaticPage' import { useLocalize } from '../../context/localize' diff --git a/src/pages/about/help.page.tsx b/src/pages/about/help.page.tsx index 5a0733f3..18a5a642 100644 --- a/src/pages/about/help.page.tsx +++ b/src/pages/about/help.page.tsx @@ -1,4 +1,4 @@ -import { Meta } from '@solidjs/meta' +import { Meta } from '../../context/meta' import { Donate } from '../../components/Discours/Donate' import { StaticPage } from '../../components/Views/StaticPage' diff --git a/src/pages/about/manifest.page.tsx b/src/pages/about/manifest.page.tsx index fdcbd20d..7599bdce 100644 --- a/src/pages/about/manifest.page.tsx +++ b/src/pages/about/manifest.page.tsx @@ -1,4 +1,4 @@ -import { Meta } from '@solidjs/meta' +import { Meta } from '../../context/meta' import { Feedback } from '../../components/Discours/Feedback' import { Modal } from '../../components/Nav/Modal' diff --git a/src/pages/about/partners.page.tsx b/src/pages/about/partners.page.tsx index 64038137..7277cbb3 100644 --- a/src/pages/about/partners.page.tsx +++ b/src/pages/about/partners.page.tsx @@ -1,4 +1,4 @@ -import { Meta } from '@solidjs/meta' +import { Meta } from '../../context/meta' import { StaticPage } from '../../components/Views/StaticPage' import { useLocalize } from '../../context/localize' diff --git a/src/pages/about/principles.page.tsx b/src/pages/about/principles.page.tsx index a5f102ea..d8b10b63 100644 --- a/src/pages/about/principles.page.tsx +++ b/src/pages/about/principles.page.tsx @@ -1,4 +1,4 @@ -import { Meta } from '@solidjs/meta' +import { Meta } from '../../context/meta' import { StaticPage } from '../../components/Views/StaticPage' import { useLocalize } from '../../context/localize' diff --git a/src/pages/about/termsOfUse.page.tsx b/src/pages/about/termsOfUse.page.tsx index 7811ed96..a5082158 100644 --- a/src/pages/about/termsOfUse.page.tsx +++ b/src/pages/about/termsOfUse.page.tsx @@ -1,4 +1,4 @@ -import { Meta } from '@solidjs/meta' +import { Meta } from '../../context/meta' import { StaticPage } from '../../components/Views/StaticPage' import { useLocalize } from '../../context/localize' diff --git a/src/pages/about/thanks.page.tsx b/src/pages/about/thanks.page.tsx index 0fccade7..4336174d 100644 --- a/src/pages/about/thanks.page.tsx +++ b/src/pages/about/thanks.page.tsx @@ -1,4 +1,4 @@ -import { Meta } from '@solidjs/meta' +import { Meta } from '../../context/meta' import { StaticPage } from '../../components/Views/StaticPage' import { useLocalize } from '../../context/localize' diff --git a/src/pages/create.page.tsx b/src/pages/create.page.tsx index ea5c27f2..65ebe26d 100644 --- a/src/pages/create.page.tsx +++ b/src/pages/create.page.tsx @@ -1,5 +1,5 @@ import { redirectPage } from '@nanostores/router' -import { Meta } from '@solidjs/meta' +import { Meta } from '../context/meta' import { clsx } from 'clsx' import { AuthGuard } from '../components/AuthGuard'