nibbles-and-bites 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nibbles-and-bites",
3
3
  "description": "A composable and accessible component framework",
4
- "version": "0.1.2",
4
+ "version": "0.1.3",
5
5
  "homepage": "https://github.com/AliciaBytes/nibbles-and-bites#readme",
6
6
  "type": "module",
7
7
  "exports": {
@@ -23,9 +23,11 @@
23
23
  ],
24
24
  "license": "(Apache-2.0 OR MIT)",
25
25
  "devDependencies": {
26
- "astro": "^5.7.5"
26
+ "astro": "^5.7.5",
27
+ "solid-js": "^1.9.5"
27
28
  },
28
29
  "peerDependencies": {
29
- "astro": "^5.7.0"
30
+ "astro": "^5.7.0",
31
+ "solid-js": "^1.9.5"
30
32
  }
31
33
  }
@@ -0,0 +1 @@
1
+ <svg height="21" viewBox="0 0 21 21" width="21" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" transform="translate(2 1)"><path d="m6.5 17.5h4"/><path d="m8.5 4c2.4852814 0 4.5 2.01471863 4.5 4.5 0 1.7663751-1.017722 3.2950485-2.4987786 4.031633l-.0012214.968367c0 1.1045695-.8954305 2-2 2s-2-.8954305-2-2l-.00021218-.9678653c-1.48160351-.7363918-2.49978782-2.2653584-2.49978782-4.0321347 0-2.48528137 2.01471863-4.5 4.5-4.5z"/><path d="m8.5 1.5v-1"/><path d="m13.5 3.5 1-1"/><path d="m2.5 3.5 1-1" transform="matrix(-1 0 0 1 6 0)"/><path d="m13.5 13.5 1-1" transform="matrix(1 0 0 -1 0 26)"/><path d="m2.5 13.5 1-1" transform="matrix(-1 0 0 -1 6 26)"/><path d="m1.5 7.5h-1"/><path d="m16.5 7.5h-1"/></g></svg>
@@ -0,0 +1 @@
1
+ <svg height="21" viewBox="0 0 21 21" width="21" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" transform="translate(-1 -1)"><path d="m14.517 3.5 4.983 5v6l-4.983 5h-6.017l-5-5v-6l5-5z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/><path d="m11.5 12.5v-5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/><circle cx="11.5" cy="15.5" fill="currentColor" r="1"/></g></svg>
@@ -0,0 +1 @@
1
+ <svg height="21" viewBox="0 0 21 21" width="21" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><path d="m9.5.5 9 16h-18z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/><path d="m9.5 10.5v-5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/><circle cx="9.5" cy="13.5" fill="currentColor" r="1"/></g></svg>
@@ -0,0 +1,52 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+ import InfoSVG from "../../assets/warning-hex.svg";
4
+
5
+ interface Props extends HTMLAttributes<"aside"> {
6
+ backgroundColor?: string;
7
+ color?: string;
8
+ highlightColor?: string;
9
+ title: string;
10
+ }
11
+
12
+ const {
13
+ backgroundColor,
14
+ color,
15
+ highlightColor = "var(--color-red)",
16
+ title = "Danger",
17
+ } = Astro.props;
18
+ ---
19
+
20
+ <aside>
21
+ <p>
22
+ <InfoSVG class="aside-icon" />
23
+ {title}
24
+ </p>
25
+ <div>
26
+ <slot />
27
+ </div>
28
+ </aside>
29
+
30
+ <style define:vars={{ color, highlightColor, backgroundColor }}>
31
+ @layer nb.component {
32
+ p {
33
+ display: inline-flex;
34
+ gap: 3px;
35
+ align-items: center;
36
+ }
37
+ .aside-icon {
38
+ height: 1.5em;
39
+ width: 1.5em;
40
+ }
41
+ aside {
42
+ color: var(--color);
43
+ background-color: var(
44
+ --backgroundColor,
45
+ oklch(from var(--highlightColor) calc(l * 0.33) c h)
46
+ );
47
+ border-left: 6px solid var(--highlightColor);
48
+ padding: 9px 0px;
49
+ padding-left: 18px;
50
+ }
51
+ }
52
+ </style>
@@ -0,0 +1,52 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+ import InfoSVG from "../../assets/lightbulb.svg";
4
+
5
+ interface Props extends HTMLAttributes<"aside"> {
6
+ backgroundColor?: string;
7
+ color?: string;
8
+ highlightColor?: string;
9
+ title: string;
10
+ }
11
+
12
+ const {
13
+ backgroundColor,
14
+ color,
15
+ highlightColor = "var(--color-lavender)",
16
+ title = "Hint",
17
+ } = Astro.props;
18
+ ---
19
+
20
+ <aside>
21
+ <p>
22
+ <InfoSVG class="aside-icon" />
23
+ {title}
24
+ </p>
25
+ <div>
26
+ <slot />
27
+ </div>
28
+ </aside>
29
+
30
+ <style define:vars={{ color, highlightColor, backgroundColor }}>
31
+ @layer nb.component {
32
+ p {
33
+ display: inline-flex;
34
+ gap: 3px;
35
+ align-items: center;
36
+ }
37
+ .aside-icon {
38
+ height: 1.5em;
39
+ width: 1.5em;
40
+ }
41
+ aside {
42
+ color: var(--color);
43
+ background-color: var(
44
+ --backgroundColor,
45
+ oklch(from var(--highlightColor) calc(l * 0.33) c h)
46
+ );
47
+ border-left: 6px solid var(--highlightColor);
48
+ padding: 9px 0px;
49
+ padding-left: 18px;
50
+ }
51
+ }
52
+ </style>
@@ -3,22 +3,24 @@ import type { HTMLAttributes } from "astro/types";
3
3
  import InfoSVG from "../../assets/info_circle.svg";
4
4
 
5
5
  interface Props extends HTMLAttributes<"aside"> {
6
+ backgroundColor?: string;
6
7
  color?: string;
7
8
  highlightColor?: string;
8
- backgroundColor?: string;
9
+ title: string;
9
10
  }
10
11
 
11
12
  const {
13
+ backgroundColor,
12
14
  color,
13
15
  highlightColor = "var(--color-sky)",
14
- backgroundColor,
16
+ title = "Information",
15
17
  } = Astro.props;
16
18
  ---
17
19
 
18
20
  <aside>
19
21
  <p>
20
22
  <InfoSVG class="aside-icon" />
21
- Information
23
+ {title}
22
24
  </p>
23
25
  <div>
24
26
  <slot />
@@ -0,0 +1,10 @@
1
+ ---
2
+ import { InlineSpoiler as SolidInlineSpoiler } from "../solid/InlineSpoiler.tsx";
3
+ const { content_note, ...props } = Astro.props;
4
+ ---
5
+
6
+ <!-- htmlmin:ignore -->
7
+ <SolidInlineSpoiler client:load {content_note} {...props}
8
+ ><slot /></SolidInlineSpoiler
9
+ >
10
+ <!-- htmlmin:ignore -->
@@ -0,0 +1,34 @@
1
+ ---
2
+ import {
3
+ default as NavigationLink,
4
+ Props as NavigationElement,
5
+ } from "./NavigationLink.astro";
6
+
7
+ interface Props {
8
+ navigation: Array<NavigationElement>;
9
+ }
10
+
11
+ const { navigation } = Astro.props;
12
+ ---
13
+
14
+ <nav>
15
+ <ul role="list">
16
+ {
17
+ navigation.map((element) => (
18
+ <li>
19
+ <NavigationLink slug={element.slug} title={element.title} />
20
+ </li>
21
+ ))
22
+ }
23
+ </ul>
24
+ </nav>
25
+
26
+ <style>
27
+ @layer nb.component {
28
+ ul {
29
+ display: grid;
30
+ grid-template-columns: repeat(auto-fit, minmax(min(10ch, 100%), 1fr));
31
+ margin: 0;
32
+ }
33
+ }
34
+ </style>
@@ -0,0 +1,30 @@
1
+ ---
2
+ export interface Props {
3
+ slug: string;
4
+ title: string;
5
+ }
6
+ const { slug, title } = Astro.props;
7
+ const url = Astro.url;
8
+ const pathname = url.pathname;
9
+ ---
10
+
11
+ {
12
+ pathname === slug ? (
13
+ <a class="tap-target" href={slug} aria-current="page">
14
+ {title}
15
+ </a>
16
+ ) : (
17
+ <a class="tap-target" href={slug}>
18
+ {title}
19
+ </a>
20
+ )
21
+ }
22
+
23
+ <style>
24
+ @layer nb.component {
25
+ a {
26
+ display: grid;
27
+ place-content: center;
28
+ }
29
+ }
30
+ </style>
@@ -0,0 +1,44 @@
1
+ ---
2
+ const {
3
+ caption,
4
+ class: className,
5
+ fallbackFormat = "webp",
6
+ formats = ["avif"],
7
+ height,
8
+ quality = "mid",
9
+ src,
10
+ width,
11
+ ...rest
12
+ } = Astro.props;
13
+
14
+ import { Picture } from "astro:assets";
15
+ ---
16
+
17
+ <figure>
18
+ <Picture
19
+ alt=""
20
+ {fallbackFormat}
21
+ {formats}
22
+ {height}
23
+ {quality}
24
+ {src}
25
+ {width}
26
+ {...rest}
27
+ />
28
+ <figcaption>{caption}</figcaption>
29
+ </figure>
30
+
31
+ <style>
32
+ @layer nb.component {
33
+ figure {
34
+ margin: 6px 0;
35
+ }
36
+
37
+ figcaption {
38
+ width: 100%;
39
+ padding: 0 2.5%;
40
+ text-align: center;
41
+ color: var(--color-subtext1);
42
+ }
43
+ }
44
+ </style>
@@ -0,0 +1,13 @@
1
+ ---
2
+
3
+ ---
4
+
5
+ <hr />
6
+
7
+ <style>
8
+ @layer nb.component {
9
+ hr {
10
+ margin: 9px 0 0 0;
11
+ }
12
+ }
13
+ </style>
@@ -0,0 +1,11 @@
1
+ <details>
2
+ <slot />
3
+ </details>
4
+
5
+ <style>
6
+ @layer nb.component {
7
+ details {
8
+ background-color: var(--color-surface0);
9
+ }
10
+ }
11
+ </style>
@@ -0,0 +1,121 @@
1
+ ---
2
+ // Based on https://fossheim.io/writing/posts/accessible-theme-picker-html-css-js/
3
+ ---
4
+
5
+ <div id="theme-switcher" data-visible="false">
6
+ <button class="tap-target" aria-pressed="false" data-theme="catppuccin-latte"
7
+ >Latte</button
8
+ >
9
+ <button class="tap-target" aria-pressed="false" data-theme="catppuccin-frappe"
10
+ >Frappé</button
11
+ >
12
+ <button
13
+ class="tap-target"
14
+ aria-pressed="false"
15
+ data-theme="catppuccin-macchiato">Macchiato</button
16
+ >
17
+ <button class="tap-target" aria-pressed="false" data-theme="catppuccin-mocha"
18
+ >Mocha</button
19
+ >
20
+ </div>
21
+
22
+ <script>
23
+ const screenMediaQuerry = window.matchMedia("screen");
24
+ const applyTheme = (theme: string) => {
25
+ if (!screenMediaQuerry.matches) {
26
+ theme = "catppuccin-latte";
27
+ }
28
+ const target = document.querySelector(`[data-theme="${theme}"]`);
29
+
30
+ document.documentElement.setAttribute("data-selected-theme", theme);
31
+
32
+ document
33
+ .querySelector('[data-theme][aria-pressed="true"]')
34
+ ?.setAttribute("aria-pressed", "false");
35
+
36
+ target?.setAttribute("aria-pressed", "true");
37
+ };
38
+
39
+ const handleThemeSelection = (event: Event) => {
40
+ const target = event.currentTarget as HTMLButtonElement;
41
+ const isPressed = target.getAttribute("aria-pressed");
42
+
43
+ /* if clicked theme is different from current theme */
44
+ if (isPressed !== "true") {
45
+ const theme = target.getAttribute("data-theme");
46
+ applyTheme(theme);
47
+ localStorage.setItem("selected-theme", theme);
48
+ }
49
+ };
50
+
51
+ const handleMediaChannge = (mq: MediaQueryList) => {
52
+ if (!mq.matches) {
53
+ return applyTheme("catpuccin-latte");
54
+ }
55
+
56
+ let savedTheme = localStorage.getItem("selected-theme");
57
+ if (
58
+ savedTheme === null ||
59
+ ![
60
+ "catppuccin-latte",
61
+ "catppuccin-frappe",
62
+ "catppuccin-macchiato",
63
+ "catppuccin-mocha",
64
+ ].includes(savedTheme)
65
+ ) {
66
+ savedTheme = "catppuccin-mocha";
67
+ }
68
+
69
+ applyTheme(savedTheme);
70
+ };
71
+
72
+ let savedTheme = localStorage.getItem("selected-theme");
73
+ if (
74
+ savedTheme === null ||
75
+ ![
76
+ "catppuccin-latte",
77
+ "catppuccin-frappe",
78
+ "catppuccin-macchiato",
79
+ "catppuccin-mocha",
80
+ ].includes(savedTheme)
81
+ ) {
82
+ savedTheme = "catppuccin-mocha";
83
+ }
84
+
85
+ applyTheme(savedTheme);
86
+
87
+ const themeSwitcher = document.querySelector("#theme-switcher");
88
+ const buttons = themeSwitcher?.querySelectorAll("button");
89
+
90
+ buttons?.forEach((button) => {
91
+ button.addEventListener("click", handleThemeSelection);
92
+ });
93
+ screenMediaQuerry.addEventListener("change", handleMediaChannge, {
94
+ passive: true,
95
+ });
96
+ </script>
97
+
98
+ <style>
99
+ @layer nb.component {
100
+ :global(.no-js) #theme-switcher,
101
+ #theme-switcher[data-visible="false"] {
102
+ display: none;
103
+ }
104
+
105
+ #theme-switcher {
106
+ display: grid;
107
+ margin: 9px 0 0 0;
108
+ gap: 12px;
109
+ grid-template-columns: repeat(auto-fit, minmax(min(10ch, 100%), 1fr));
110
+ }
111
+
112
+ button {
113
+ border-color: var(--color-overlay0);
114
+ }
115
+
116
+ button[aria-pressed="true"] {
117
+ background: var(--color-text);
118
+ color: var(--color-base);
119
+ }
120
+ }
121
+ </style>
@@ -0,0 +1,33 @@
1
+ ---
2
+
3
+ ---
4
+
5
+ <button class="tap-target" id="theme-switcher-toggle">Theme Switcher</button>
6
+
7
+ <script>
8
+ const handleThemeToggling = (event: Event) => {
9
+ const themeSwitcher = document.querySelector(
10
+ "#theme-switcher"
11
+ ) as HTMLDivElement;
12
+ const oppositeVisibility =
13
+ themeSwitcher.getAttribute("data-visible") === "true" ? "false" : "true";
14
+
15
+ themeSwitcher.setAttribute("data-visible", oppositeVisibility);
16
+ };
17
+
18
+ const themeSwitcherToggle = document.querySelector(
19
+ "#theme-switcher-toggle"
20
+ ) as HTMLButtonElement;
21
+
22
+ themeSwitcherToggle.addEventListener("click", handleThemeToggling);
23
+ </script>
24
+
25
+ <style>
26
+ @layer nb.component {
27
+ button {
28
+ border-color: var(--color-overlay0);
29
+ display: grid;
30
+ place-content: center;
31
+ }
32
+ }
33
+ </style>
@@ -0,0 +1,52 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+ import InfoSVG from "../../assets/warning-triangle.svg";
4
+
5
+ interface Props extends HTMLAttributes<"aside"> {
6
+ backgroundColor?: string;
7
+ color?: string;
8
+ highlightColor?: string;
9
+ title: string;
10
+ }
11
+
12
+ const {
13
+ backgroundColor,
14
+ color,
15
+ highlightColor = "var(--color-rosewater)",
16
+ title = "Warning",
17
+ } = Astro.props;
18
+ ---
19
+
20
+ <aside>
21
+ <p>
22
+ <InfoSVG class="aside-icon" />
23
+ {title}
24
+ </p>
25
+ <div>
26
+ <slot />
27
+ </div>
28
+ </aside>
29
+
30
+ <style define:vars={{ color, highlightColor, backgroundColor }}>
31
+ @layer nb.component {
32
+ p {
33
+ display: inline-flex;
34
+ gap: 3px;
35
+ align-items: center;
36
+ }
37
+ .aside-icon {
38
+ height: 1.5em;
39
+ width: 1.5em;
40
+ }
41
+ aside {
42
+ color: var(--color);
43
+ background-color: var(
44
+ --backgroundColor,
45
+ oklch(from var(--highlightColor) calc(l * 0.33) c h)
46
+ );
47
+ border-left: 6px solid var(--highlightColor);
48
+ padding: 9px 0px;
49
+ padding-left: 18px;
50
+ }
51
+ }
52
+ </style>
@@ -1,2 +1,12 @@
1
+ export { default as Danger } from "./astro/Danger.astro"
2
+ export { default as Hint } from "./astro/Hint.astro"
1
3
  export { default as Information } from "./astro/Information.astro"
4
+ export { default as InlineSpoiler } from "./astro/InlineSpoiler.astro"
5
+ export { default as Navigation } from "./astro/Navigation.astro"
6
+ export { default as PictureFigure } from "./astro/PictureFigure.astro"
2
7
  export { default as RemoteSVG } from "./astro/RemoteSVG.astro"
8
+ export { default as SectionDivider } from "./astro/SectionDivider.astro"
9
+ export { default as Spoiler } from "./astro/Spoiler.astro"
10
+ export { default as ThemeSwitcher } from "./astro/ThemeSwitcher.astro"
11
+ export { default as ThemeToggle } from "./astro/ThemeToggle.astro"
12
+ export { default as Warning } from "./astro/Warning.astro"
@@ -1 +1,2 @@
1
- export * as Astro from "./astro.js"
1
+ export * as Astro from "./astro.js";
2
+ export * as Solid from "./solid.js";
@@ -0,0 +1,15 @@
1
+ @layer nb.component {
2
+ .inline_spoiler {
3
+ display: contents;
4
+ }
5
+
6
+ .inline_spoiler * {
7
+ display: inline;
8
+ background-color: var(--color-surface0);
9
+ }
10
+
11
+ .spoiler_text[aria-hidden="true"] {
12
+ color: transparent;
13
+ user-select: none;
14
+ }
15
+ }
@@ -0,0 +1,38 @@
1
+ import type { Component, JSXElement } from "solid-js";
2
+ import { createSignal, children, Show } from "solid-js";
3
+
4
+ import styles from "../internal/css/modules/solid/InlineSpoiler.module.css";
5
+
6
+ export interface InlineSpoilerProps {
7
+ content_note?: string;
8
+ children: JSXElement;
9
+ }
10
+
11
+ export const InlineSpoiler: Component<InlineSpoilerProps> = (
12
+ props: InlineSpoilerProps
13
+ ) => {
14
+ const safeChildren = children(() => props.children);
15
+ const [status, setStatus] = createSignal<boolean>(false);
16
+ return (
17
+ <button
18
+ class={styles.inline_spoiler}
19
+ role="switch"
20
+ aria-pressed={status()}
21
+ aria-live="polite"
22
+ aria-label="Spoiler"
23
+ onClick={() => setStatus(!status())}
24
+ >
25
+ {" "}
26
+ <span tabIndex={0}>
27
+ <Show when={props.content_note} keyed>
28
+ <span>(CN: {props.content_note}) </span>
29
+ </Show>
30
+ <span class={styles.spoiler_text} aria-hidden={!status()}>
31
+ {safeChildren()}
32
+ </span>
33
+ </span>{" "}
34
+ </button>
35
+ );
36
+ };
37
+
38
+ export default InlineSpoiler;
@@ -0,0 +1 @@
1
+ export { default as InlineSpoiler } from "./solid/InlineSpoiler.tsx";