Add Tippy.js tooltips to focusable elements
This commit is contained in:
parent
a2fbf908aa
commit
09934a9f8e
11 changed files with 73 additions and 29 deletions
20
package-lock.json
generated
20
package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
},
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -70,5 +70,5 @@ export default {
|
|||
}),
|
||||
},
|
||||
},
|
||||
plugins: [require("@tailwindcss/typography")],
|
||||
plugins: [typography],
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue