xs-dev 0.24.4 → 0.24.5

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.
@@ -1,13 +1,12 @@
1
1
  import { defineConfig } from 'astro/config'
2
2
 
3
- import lit from '@astrojs/lit'
4
- import preact from '@astrojs/preact'
5
3
  import tailwind from '@astrojs/tailwind'
6
4
  import sitemap from '@astrojs/sitemap'
5
+ import solidJs from "@astrojs/solid-js";
7
6
 
8
7
  // https://astro.build/config
9
8
  export default defineConfig({
10
- integrations: [preact(), lit(), tailwind(), sitemap()],
9
+ integrations: [solidJs(), tailwind(), sitemap()],
11
10
  site: 'https://hipsterbrown.github.io',
12
11
  base: '/xs-dev',
13
12
  })
@@ -1,49 +1,47 @@
1
- import type { FunctionalComponent } from 'preact';
2
- import { h } from 'preact';
1
+ import type { Component } from 'solid-js';
3
2
  import './LanguageSelect.css';
4
3
  import { KNOWN_LANGUAGES, langPathRegex } from '../../languages';
5
4
 
6
- const LanguageSelect: FunctionalComponent<{ lang: string }> = ({ lang }) => {
7
- return (
8
- <div class="language-select-wrapper">
9
- <svg
10
- aria-hidden="true"
11
- focusable="false"
12
- role="img"
13
- xmlns="http://www.w3.org/2000/svg"
14
- viewBox="0 0 88.6 77.3"
15
- height="1.2em"
16
- width="1.2em"
17
- >
18
- <path
19
- fill="currentColor"
20
- d="M61,24.6h7.9l18.7,51.6h-7.7l-5.4-15.5H54.3l-5.6,15.5h-7.2L61,24.6z M72.6,55l-8-22.8L56.3,55H72.6z"
21
- />
22
- <path
23
- fill="currentColor"
24
- d="M53.6,60.6c-10-4-16-9-22-14c0,0,1.3,1.3,0,0c-6,5-20,13-20,13l-4-6c8-5,10-6,19-13c-2.1-1.9-12-13-13-19h8 c4,9,10,14,10,14c10-8,10-19,10-19h8c0,0-1,13-12,24l0,0c5,5,10,9,19,13L53.6,60.6z M1.6,16.6h56v-8h-23v-7h-9v7h-24V16.6z"
25
- />
26
- </svg>
27
- <select
28
- class="language-select"
29
- value={lang}
30
- onChange={(e) => {
31
- const newLang = e.target.value;
32
- let actualDest = window.location.pathname.replace(langPathRegex, '/');
33
- if (actualDest == '/') actualDest = `/introduction`;
34
- window.location.pathname = '/' + newLang + actualDest;
35
- }}
36
- >
37
- {Object.keys(KNOWN_LANGUAGES).map((key) => {
38
- return (
39
- <option value={KNOWN_LANGUAGES[key]}>
40
- <span>{key}</span>
41
- </option>
42
- );
43
- })}
44
- </select>
45
- </div>
46
- );
5
+ const LanguageSelect: Component<{ lang: string }> = ({ lang }) => {
6
+ return (
7
+ <div class="language-select-wrapper">
8
+ <svg
9
+ aria-hidden="true"
10
+ role="img"
11
+ xmlns="http://www.w3.org/2000/svg"
12
+ viewBox="0 0 88.6 77.3"
13
+ height="1.2em"
14
+ width="1.2em"
15
+ >
16
+ <path
17
+ fill="currentColor"
18
+ d="M61,24.6h7.9l18.7,51.6h-7.7l-5.4-15.5H54.3l-5.6,15.5h-7.2L61,24.6z M72.6,55l-8-22.8L56.3,55H72.6z"
19
+ />
20
+ <path
21
+ fill="currentColor"
22
+ d="M53.6,60.6c-10-4-16-9-22-14c0,0,1.3,1.3,0,0c-6,5-20,13-20,13l-4-6c8-5,10-6,19-13c-2.1-1.9-12-13-13-19h8 c4,9,10,14,10,14c10-8,10-19,10-19h8c0,0-1,13-12,24l0,0c5,5,10,9,19,13L53.6,60.6z M1.6,16.6h56v-8h-23v-7h-9v7h-24V16.6z"
23
+ />
24
+ </svg>
25
+ <select
26
+ class="language-select"
27
+ value={lang}
28
+ onChange={(e) => {
29
+ const newLang = e.currentTarget.value;
30
+ let actualDest = window.location.pathname.replace(langPathRegex, '/');
31
+ if (actualDest == '/') actualDest = `/introduction`;
32
+ window.location.pathname = '/' + newLang + actualDest;
33
+ }}
34
+ >
35
+ {Object.keys(KNOWN_LANGUAGES).map((key) => {
36
+ return (
37
+ <option value={KNOWN_LANGUAGES[key]}>
38
+ {key}
39
+ </option>
40
+ );
41
+ })}
42
+ </select>
43
+ </div>
44
+ );
47
45
  };
48
46
 
49
47
  export default LanguageSelect;
@@ -1,34 +1,30 @@
1
- import type { FunctionalComponent } from 'preact'
2
- import { h, Fragment } from 'preact'
3
- import { useEffect, useRef, useState } from 'preact/hooks'
1
+ import { type Component, createSignal, For, onMount } from 'solid-js';
4
2
  import Fuse from 'fuse.js'
5
3
  import './Search.css'
6
4
 
7
- const SearchForm: FunctionalComponent = () => {
8
- const fuse = useRef(null)
9
- const [results, setResults] = useState([])
5
+ const SearchForm: Component = () => {
6
+ let fuse: null | Fuse<{ url: string, title: string }> = null;
7
+ const [results, setResults] = createSignal([]);
10
8
 
11
9
  const searchContent = (event: SubmitEvent) => {
12
10
  event.preventDefault()
13
- const data = Object.fromEntries(
11
+ const { search } = Object.fromEntries(
14
12
  new FormData(event.currentTarget as HTMLFormElement)
15
13
  )
16
- const result = fuse.current.search(data.search)
14
+ const result = fuse.search(search as string)
17
15
  setResults(result.map(({ item }) => item))
18
16
  }
19
17
 
20
- useEffect(() => {
21
- fetch('/xs-dev/search-index.json')
18
+ onMount(async () => {
19
+ const content = await fetch('/xs-dev/search-index.json')
22
20
  .then((res) => res.json())
23
- .then((content) => {
24
- const options = { keys: ['title', 'description', 'content'] }
25
- fuse.current = new Fuse(content, options)
26
- })
27
- }, [])
21
+ const options = { keys: ['title', 'description', 'content'] }
22
+ fuse = new Fuse(content, options)
23
+ })
28
24
 
29
25
  return (
30
26
  <div class="flex flex-column SearchContainer">
31
- <form method="GET" id="search-form" onSubmit={searchContent}>
27
+ <form method="get" id="search-form" onSubmit={searchContent}>
32
28
  <div role="search" class="flex flex-row">
33
29
  <input
34
30
  type="search"
@@ -44,19 +40,19 @@ const SearchForm: FunctionalComponent = () => {
44
40
  </div>
45
41
  </form>
46
42
  <ul
47
- class={`SearchContainer-list ${
48
- results.length > 0 ? 'has-results' : undefined
49
- }`}
43
+ classList={{ 'SearchContainer-list': true, 'has-results': results().length > 0 }}
50
44
  aria-live="assertive"
51
45
  aria-atomic="true"
52
46
  >
53
- {results.map((result) => (
54
- <li class="SearchContainer-list_item">
55
- <a href={result.url} class="SearchContainer-link">
56
- {result.title}
57
- </a>
58
- </li>
59
- ))}
47
+ <For each={results()}>
48
+ {(result) => (
49
+ <li class="SearchContainer-list_item">
50
+ <a href={result.url} class="SearchContainer-link">
51
+ {result.title}
52
+ </a>
53
+ </li>
54
+ )}
55
+ </For>
60
56
  </ul>
61
57
  </div>
62
58
  )
@@ -1,44 +1,43 @@
1
- import type { FunctionalComponent } from 'preact';
2
- import { h, Fragment } from 'preact';
3
- import { useState, useEffect } from 'preact/hooks';
1
+ import { type Component, createSignal, createEffect } from 'solid-js';
4
2
 
5
- const MenuToggle: FunctionalComponent = () => {
6
- const [sidebarShown, setSidebarShown] = useState(false);
3
+ const MenuToggle: Component = () => {
4
+ const [sidebarShown, setSidebarShown] = createSignal(false);
7
5
 
8
- useEffect(() => {
9
- const body = document.getElementsByTagName('body')[0];
10
- if (sidebarShown) {
11
- body.classList.add('mobile-sidebar-toggle');
12
- } else {
13
- body.classList.remove('mobile-sidebar-toggle');
14
- }
15
- }, [sidebarShown]);
6
+ createEffect(() => {
7
+ const [body] = document.getElementsByTagName('body');
8
+ const showSidebar = sidebarShown();
9
+ if (showSidebar) {
10
+ body.classList.add('mobile-sidebar-toggle');
11
+ } else {
12
+ body.classList.remove('mobile-sidebar-toggle');
13
+ }
14
+ });
16
15
 
17
- return (
18
- <button
19
- type="button"
20
- aria-pressed={sidebarShown ? 'true' : 'false'}
21
- id="menu-toggle"
22
- onClick={() => setSidebarShown(!sidebarShown)}
23
- >
24
- <svg
25
- xmlns="http://www.w3.org/2000/svg"
26
- width="1em"
27
- height="1em"
28
- fill="none"
29
- viewBox="0 0 24 24"
30
- stroke="currentColor"
31
- >
32
- <path
33
- stroke-linecap="round"
34
- stroke-linejoin="round"
35
- stroke-width="2"
36
- d="M4 6h16M4 12h16M4 18h16"
37
- />
38
- </svg>
39
- <span className="sr-only">Toggle sidebar</span>
40
- </button>
41
- );
16
+ return (
17
+ <button
18
+ type="button"
19
+ aria-pressed={sidebarShown() ? 'true' : 'false'}
20
+ id="menu-toggle"
21
+ onClick={() => setSidebarShown(current => !current)}
22
+ >
23
+ <svg
24
+ xmlns="http://www.w3.org/2000/svg"
25
+ width="1em"
26
+ height="1em"
27
+ fill="none"
28
+ viewBox="0 0 24 24"
29
+ stroke="currentColor"
30
+ >
31
+ <path
32
+ stroke-linecap="round"
33
+ stroke-linejoin="round"
34
+ stroke-width="2"
35
+ d="M4 6h16M4 12h16M4 18h16"
36
+ />
37
+ </svg>
38
+ <span class="sr-only">Toggle sidebar</span>
39
+ </button>
40
+ );
42
41
  };
43
42
 
44
43
  export default MenuToggle;
@@ -1,39 +1,36 @@
1
- import type { FunctionalComponent } from 'preact'
2
- import { h, Fragment } from 'preact'
3
- import { useState, useEffect, useRef } from 'preact/hooks'
1
+ import { type Component, createSignal, onMount, onCleanup } from 'solid-js';
4
2
  import type { MarkdownHeading } from 'astro'
5
3
 
6
- const TableOfContents: FunctionalComponent<{ headings: MarkdownHeading[] }> = ({
4
+ const TableOfContents: Component<{ headings: MarkdownHeading[] }> = ({
7
5
  headings = [],
8
6
  }) => {
9
- const itemOffsets = useRef([])
10
- const [activeId] = useState<string>(undefined)
11
-
12
- useEffect(() => {
13
- const getItemOffsets = () => {
14
- const titles = document.querySelectorAll('article :is(h1, h2, h3, h4)')
15
- itemOffsets.current = Array.from(titles).map((title) => ({
16
- id: title.id,
17
- topOffset: title.getBoundingClientRect().top + window.scrollY,
18
- }))
19
- }
20
-
7
+ let itemOffsets = []
8
+ const [activeId] = createSignal<string>(undefined)
9
+ const getItemOffsets = () => {
10
+ const titles = document.querySelectorAll('article :is(h1, h2, h3, h4)')
11
+ itemOffsets = Array.from(titles).map((title) => ({
12
+ id: title.id,
13
+ topOffset: title.getBoundingClientRect().top + window.scrollY,
14
+ }))
15
+ }
16
+ onMount(() => {
21
17
  getItemOffsets()
22
18
  window.addEventListener('resize', getItemOffsets)
19
+ })
23
20
 
24
- return () => {
21
+ onCleanup(() => {
22
+ if (typeof window !== 'undefined' && 'removeEventListener' in window) {
25
23
  window.removeEventListener('resize', getItemOffsets)
26
24
  }
27
- }, [])
25
+ })
28
26
 
29
27
  return (
30
28
  <>
31
29
  <h2 class="heading">On this page</h2>
32
30
  <ul>
33
31
  <li
34
- class={`header-link depth-2 ${
35
- activeId === 'overview' ? 'active' : ''
36
- }`.trim()}
32
+ class={`header-link depth-2 ${activeId() === 'overview' ? 'active' : ''
33
+ }`.trim()}
37
34
  >
38
35
  <a href="#overview">Overview</a>
39
36
  </li>
@@ -41,9 +38,8 @@ const TableOfContents: FunctionalComponent<{ headings: MarkdownHeading[] }> = ({
41
38
  .filter(({ depth }) => depth > 1 && depth < 4)
42
39
  .map((header) => (
43
40
  <li
44
- class={`header-link depth-${header.depth} ${
45
- activeId === header.slug ? 'active' : ''
46
- }`.trim()}
41
+ class={`header-link depth-${header.depth} ${activeId() === header.slug ? 'active' : ''
42
+ }`.trim()}
47
43
  >
48
44
  <a href={`#${header.slug}`}>{header.text}</a>
49
45
  </li>
@@ -1,83 +1,75 @@
1
- import type { FunctionalComponent } from 'preact';
2
- import { h, Fragment } from 'preact';
3
- import { useState, useEffect } from 'preact/hooks';
1
+ import { type Component, createSignal, createEffect } from 'solid-js';
4
2
  import './ThemeToggleButton.css';
5
3
 
6
- const themes = ['light', 'dark'];
4
+ const themes = ['light', 'dark'] as const;
7
5
 
8
6
  const icons = [
9
- <svg
10
- xmlns="http://www.w3.org/2000/svg"
11
- width="20"
12
- height="20"
13
- viewBox="0 0 20 20"
14
- fill="currentColor"
15
- >
16
- <path
17
- fillRule="evenodd"
18
- d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"
19
- clipRule="evenodd"
20
- />
21
- </svg>,
22
- <svg
23
- xmlns="http://www.w3.org/2000/svg"
24
- width="20"
25
- height="20"
26
- viewBox="0 0 20 20"
27
- fill="currentColor"
28
- >
29
- <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
30
- </svg>,
7
+ <svg
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ width="20"
10
+ height="20"
11
+ viewBox="0 0 20 20"
12
+ fill="currentColor"
13
+ >
14
+ <path
15
+ fill-rule="evenodd"
16
+ d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"
17
+ clip-rule="evenodd"
18
+ />
19
+ </svg>,
20
+ <svg
21
+ xmlns="http://www.w3.org/2000/svg"
22
+ width="20"
23
+ height="20"
24
+ viewBox="0 0 20 20"
25
+ fill="currentColor"
26
+ >
27
+ <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
28
+ </svg>,
31
29
  ];
32
30
 
33
- const ThemeToggle: FunctionalComponent = () => {
34
- const [theme, setTheme] = useState(() => {
35
- if (import.meta.env.SSR) {
36
- return undefined;
37
- }
38
- if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
39
- return localStorage.getItem('theme');
40
- }
41
- if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
42
- return 'dark';
43
- }
44
- return 'light';
45
- });
31
+ const ThemeToggle: Component = () => {
32
+ let [theme, setTheme] = createSignal('light');
33
+ if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
34
+ [theme, setTheme] = createSignal(localStorage.getItem('theme'))
35
+ } else if (typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
36
+ [theme, setTheme] = createSignal('dark')
37
+ }
46
38
 
47
- useEffect(() => {
48
- const root = document.documentElement;
49
- if (theme === 'light') {
50
- root.classList.remove('theme-dark');
51
- } else {
52
- root.classList.add('theme-dark');
53
- }
54
- }, [theme]);
39
+ createEffect(() => {
40
+ const root = document.documentElement;
41
+ if (theme() === 'light') {
42
+ root.classList.remove('theme-dark');
43
+ } else {
44
+ root.classList.add('theme-dark');
45
+ }
46
+ });
55
47
 
56
- return (
57
- <div class="theme-toggle">
58
- {themes.map((t, i) => {
59
- const icon = icons[i];
60
- const checked = t === theme;
61
- return (
62
- <label className={checked ? ' checked' : ''}>
63
- {icon}
64
- <input
65
- type="radio"
66
- name="theme-toggle"
67
- checked={checked}
68
- value={t}
69
- title={`Use ${t} theme`}
70
- aria-label={`Use ${t} theme`}
71
- onChange={() => {
72
- localStorage.setItem('theme', t);
73
- setTheme(t);
74
- }}
75
- />
76
- </label>
77
- );
78
- })}
79
- </div>
80
- );
48
+ return (
49
+ <div class="theme-toggle">
50
+ {themes.map((t, i) => {
51
+ const icon = icons[i];
52
+ const checked = t === theme();
53
+ return (
54
+ <label class={checked ? ' checked' : ''}>
55
+ {icon}
56
+ <input
57
+ type="radio"
58
+ name="theme-toggle"
59
+ checked={checked}
60
+ value={t}
61
+ title={`Use ${t} theme`}
62
+ aria-label={`Use ${t} theme`}
63
+ onChange={() => {
64
+ localStorage.setItem('theme', t);
65
+ setTheme(t);
66
+ }}
67
+ />
68
+ </label>
69
+ );
70
+ })}
71
+ </div>
72
+ );
81
73
  };
82
74
 
83
75
  export default ThemeToggle;
@@ -12,6 +12,7 @@
12
12
  "noEmit": true,
13
13
  // Add type definitions for our Vite runtime.
14
14
  "types": ["vite/client"],
15
- "jsx": "preserve"
15
+ "jsx": "preserve",
16
+ "jsxImportSource": "solid-js"
16
17
  }
17
18
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xs-dev",
3
- "version": "0.24.4",
3
+ "version": "0.24.5",
4
4
  "description": "CLI for automating the setup and usage of Moddable XS tools",
5
5
  "types": "build/types/types.d.ts",
6
6
  "bin": {
@@ -46,17 +46,18 @@
46
46
  "gluegun": "^5.1.2",
47
47
  "serialport": "^10.3.0",
48
48
  "serve-handler": "^6.1.3",
49
+ "solid-js": "^1.4.3",
49
50
  "tar-fs": "^2.1.1",
50
51
  "unzip-stream": "^0.3.1",
51
52
  "usb": "^2.2.0",
52
53
  "windows-shortcuts": "^0.1.6"
53
54
  },
54
55
  "devDependencies": {
55
- "@astrojs/lit": "^1.1.2",
56
- "@astrojs/mdx": "^0.16.0",
57
- "@astrojs/preact": "^2.0.2",
58
- "@astrojs/sitemap": "^1.0.1",
59
- "@astrojs/tailwind": "^3.0.1",
56
+ "@astrojs/mdx": "^0.16.2",
57
+ "@astrojs/sitemap": "^1.2.1",
58
+ "@astrojs/solid-js": "^2.1.0",
59
+ "@astrojs/tailwind": "^3.1.1",
60
+ "@babel/core": ">=7.20.12 <8.0.0",
60
61
  "@changesets/cli": "^2.19.0",
61
62
  "@release-it/conventional-changelog": "^5.1.1",
62
63
  "@types/jest": "^27.4.0",
@@ -67,7 +68,7 @@
67
68
  "@typescript-eslint/eslint-plugin": "^4.33.0",
68
69
  "@typescript-eslint/parser": "^4.33.0",
69
70
  "@webcomponents/template-shadowroot": "^0.1.0",
70
- "astro": "^2.0.6",
71
+ "astro": "^2.1.5",
71
72
  "eslint": "^7.32.0",
72
73
  "eslint-config-prettier": "^8.3.0",
73
74
  "eslint-config-standard-with-typescript": "^21.0.1",
@@ -76,9 +77,6 @@
76
77
  "eslint-plugin-promise": "^5.2.0",
77
78
  "fuse.js": "^6.6.2",
78
79
  "jest": "^27.4.7",
79
- "lit": "^2.2.5",
80
- "preact": "^10.7.3",
81
- "preact-render-to-string": "^5.2.0",
82
80
  "prettier": "^2.5.1",
83
81
  "release-it": "^15.6.0",
84
82
  "rollup": "^2.78.1",