diff --git a/package-lock.json b/package-lock.json index 1a78914..4898f6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "sanitize-html": "^2.13.0", "tailwindcss": "^3.4.9", "tiny-decode": "^0.1.3", + "tippy.js": "^6.3.7", "toml": "^3.0.0", "typescript": "^5.5.4" }, @@ -1686,6 +1687,16 @@ "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz", "integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==" }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.13.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", @@ -6737,6 +6748,15 @@ "entities": "^4.4.0" } }, + "node_modules/tippy.js": { + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", + "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==", + "license": "MIT", + "dependencies": { + "@popperjs/core": "^2.9.0" + } + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", diff --git a/package.json b/package.json index 493010b..4255bd0 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "sanitize-html": "^2.13.0", "tailwindcss": "^3.4.9", "tiny-decode": "^0.1.3", + "tippy.js": "^6.3.7", "toml": "^3.0.0", "typescript": "^5.5.4" }, diff --git a/src/content/tag-categories/9-type-of-content.yaml b/src/content/tag-categories/9-type-of-content.yaml index 1c12c00..83677fe 100644 --- a/src/content/tag-categories/9-type-of-content.yaml +++ b/src/content/tag-categories/9-type-of-content.yaml @@ -6,6 +6,6 @@ tags: - name: commission description: Stories made as part of a commission to someone else. - name: { en: flash fiction, tok: lipu lili } - description: Short-format stories of no more than 2,500 words. + description: Short-format stories with no more than 2,500 words. - name: toki pona description: Stories written in toki pona, the language of good. diff --git a/src/layouts/GalleryLayout.astro b/src/layouts/GalleryLayout.astro index 6d90491..ab1a9b2 100644 --- a/src/layouts/GalleryLayout.astro +++ b/src/layouts/GalleryLayout.astro @@ -143,6 +143,7 @@ const isCurrentRoute = (path: string) => </main> </div> </BaseLayout> + <style> nav ul li a, nav ul li button { @@ -159,3 +160,17 @@ const isCurrentRoute = (path: string) => height: 1ex; } </style> + +<script> + import tippy from "tippy.js"; + import "tippy.js/dist/tippy.css"; + + const clipboardItems = document.querySelectorAll<HTMLElement>("[data-clipboard]"); + + tippy(clipboardItems, { + content: (el) => (el as HTMLElement).dataset.clipboard!, + theme: "bm", + }); + + clipboardItems.forEach((el) => el.removeAttribute("title")); +</script> diff --git a/src/layouts/PublishedContentLayout.astro b/src/layouts/PublishedContentLayout.astro index edca29a..3480126 100644 --- a/src/layouts/PublishedContentLayout.astro +++ b/src/layouts/PublishedContentLayout.astro @@ -82,6 +82,10 @@ const tags = props.tags.map<{ id: string; name: string }>((tag) => { const thumbnail = props.thumbnail && (await getImage({ src: props.thumbnail, width: props.thumbnailWidth, height: props.thumbnailHeight })); + +const returnTo = series + ? t(props.lang, "published_content/return_to_series", series.data.name) + : props.labelReturnTo.title; --- <BaseLayout pageTitle={props.title} lang={props.lang}> @@ -115,39 +119,24 @@ const thumbnail = <div class="pointer-events-auto sticky top-6 flex rounded-full bg-white px-1 py-1 shadow-md dark:bg-black print:hidden" > - <a - href={series ? series.data.link : props.labelReturnTo.link} - class="text-link my-1 p-2" - aria-labelledby="label-return-to" - > + <a href={series ? series.data.link : props.labelReturnTo.link} class="text-link my-1 p-2" aria-label={returnTo}> <IconArrowBack width="1.25rem" height="1.25rem" /> - <span class="sr-only select-none" id="label-return-to" - >{ - series ? t(props.lang, "published_content/return_to_series", series.data.name) : props.labelReturnTo.title - }</span - > </a> <a href="#description" class="text-link my-1 border-l border-stone-300 p-2 dark:border-stone-700" - aria-labelledby="label-go-to-description" + aria-label={t(props.lang, "published_content/go_to_description")} > <IconCircleInfo width="1.25rem" height="1.25rem" /> - <span class="sr-only select-none" id="label-go-to-description" - >{t(props.lang, "published_content/go_to_description")}</span - > </a> <button data-dark-mode style={{ display: "none" }} class="text-link my-1 border-l border-stone-300 p-2 dark:border-stone-700" - aria-labelledby="label-toggle-dark-mode" + aria-label={t(props.lang, "published_content/toggle_dark_mode")} > <IconSun width="1.25rem" height="1.25rem" class="hidden dark:block" /> <IconMoon width="1.25rem" height="1.25rem" class="block dark:hidden" /> - <span class="sr-only select-none" id="label-toggle-dark-mode" - >{t(props.lang, "published_content/toggle_dark_mode")}</span - > </button> </div> </div> @@ -195,15 +184,15 @@ const thumbnail = } <h1 id="section-title" - class="p-name px-1 pt-4 font-serif text-4xl font-semibold text-stone-800 dark:text-stone-100" + class="p-name px-1 pt-4 font-serif text-4xl font-medium text-stone-800 dark:text-stone-200" aria-label={props.labelTitleSection} > {props.title} </h1> - <hr class="mb-3 ml-[2px] mt-2 h-[4px] w-1/2 rounded-sm bg-stone-800 dark:bg-stone-100" /> + <hr class="mb-3 ml-[2px] mt-2 h-[4px] w-1/2 rounded-sm bg-stone-800 dark:bg-stone-200" /> <section id="section-information" - class="p-summary mt-1 space-y-2 px-2 font-serif font-light italic text-stone-600 dark:text-stone-200" + class="p-summary mt-1 space-y-2 px-2 font-serif font-light italic text-stone-700 dark:text-stone-300" aria-label={props.labelInformationSection} > <slot name="section-information" /> @@ -402,3 +391,14 @@ const thumbnail = </div> </div> </BaseLayout> + +<script> + import tippy from "tippy.js"; + import "tippy.js/dist/tippy.css"; + + tippy("#toolbox-buttons :is(a, button)[aria-label]", { + content: (el) => el.getAttribute("aria-label")!, + placement: "bottom", + theme: "bm", + }); +</script> diff --git a/src/pages/games.astro b/src/pages/games.astro index 39c0529..aec365e 100644 --- a/src/pages/games.astro +++ b/src/pages/games.astro @@ -30,6 +30,7 @@ const games = await Promise.all( class="u-url text-link hover:underline focus:underline" href={`/games/${game.slug}`} title={t(game.data.lang, "game/warnings", game.data.platforms, game.data.contentWarning)} + data-clipboard={t(game.data.lang, "game/warnings", game.data.platforms, game.data.contentWarning)} > {game.data.thumbnail ? ( <div class="flex aspect-[630/500] max-w-[288px] justify-center"> diff --git a/src/pages/index.astro b/src/pages/index.astro index a22865d..b3733c6 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -102,7 +102,12 @@ const latestItems: LatestItemsEntry[] = await Promise.all( { latestItems.map((entry) => ( <li class="h-entry break-inside-avoid" lang={entry.lang}> - <a class="u-url text-link hover:underline focus:underline" href={entry.href} title={entry.altText}> + <a + class="u-url text-link hover:underline focus:underline" + href={entry.href} + title={entry.altText} + data-clipboard={entry.altText} + > {entry.thumbnail ? ( <div class="flex aspect-square max-w-[192px] justify-center"> <Image diff --git a/src/pages/stories/[page].astro b/src/pages/stories/[page].astro index 618b49c..493fb12 100644 --- a/src/pages/stories/[page].astro +++ b/src/pages/stories/[page].astro @@ -88,6 +88,7 @@ const totalPages = Math.ceil(page.total / page.size); class="u-url text-link hover:underline focus:underline" href={`/stories/${story.slug}`} title={t(story.data.lang, "story/warnings", story.data.wordCount, story.data.contentWarning)} + data-clipboard={t(story.data.lang, "story/warnings", story.data.wordCount, story.data.contentWarning)} > {story.data.thumbnail ? ( <div class="flex aspect-square max-w-[192px] justify-center"> diff --git a/src/pages/tags.astro b/src/pages/tags.astro index 58a2c89..8aff2ce 100644 --- a/src/pages/tags.astro +++ b/src/pages/tags.astro @@ -102,6 +102,7 @@ if (uncategorizedTagsSet.size > 0) { class="rounded-full bg-bm-300 px-3 py-1 text-sm text-black shadow-sm hover:underline focus:underline dark:bg-bm-600 dark:text-white" href={`/tags/${id}`} title={description} + data-clipboard={description} > {name} </a> diff --git a/src/styles/base.css b/src/styles/base.css index 1676347..4586750 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -4,19 +4,19 @@ /* Tippy tooltips */ .tippy-box[data-theme~="bm"] { - @apply bg-stone-800 font-sans text-sm text-stone-50 dark:bg-zinc-900 dark:text-zinc-100; + @apply bg-stone-900 font-sans text-sm text-stone-50 dark:bg-zinc-700 dark:text-zinc-50; } .tippy-box[data-theme~="bm"][data-placement^="top"] > .tippy-arrow::before { - @apply border-t-stone-800 dark:border-t-zinc-900; + @apply border-t-stone-900 dark:border-t-zinc-700; } .tippy-box[data-theme~="bm"][data-placement^="bottom"] > .tippy-arrow::before { - @apply border-b-stone-800 dark:border-b-zinc-900; + @apply border-b-stone-900 dark:border-b-zinc-700; } .tippy-box[data-theme~="bm"][data-placement^="left"] > .tippy-arrow::before { - @apply border-l-stone-800 dark:border-l-zinc-900; + @apply border-l-stone-900 dark:border-l-zinc-700; } .tippy-box[data-theme~="bm"][data-placement^="right"] > .tippy-arrow::before { - @apply border-r-stone-800 dark:border-r-zinc-900; + @apply border-r-stone-900 dark:border-r-zinc-700; } @layer components { diff --git a/tailwind.config.mjs b/tailwind.config.mjs index 9724321..83c4dbf 100644 --- a/tailwind.config.mjs +++ b/tailwind.config.mjs @@ -70,5 +70,5 @@ export default { }), }, }, - plugins: [require("@tailwindcss/typography")], + plugins: [typography], };