xs-dev 0.25.4 → 0.25.6
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/README.md +27 -1
- package/docs/astro.config.mjs +39 -8
- package/docs/public/favicon.ico +0 -0
- package/docs/public/favicon.svg +25 -0
- package/docs/src/assets/Chip.svg +25 -0
- package/docs/src/assets/Chip.webp +0 -0
- package/docs/src/assets/Logo.svg +113 -0
- package/docs/src/assets/Logo.webp +0 -0
- package/docs/src/assets/houston.webp +0 -0
- package/docs/src/components/YoutubeEmbed.astro +13 -0
- package/docs/src/content/config.ts +7 -0
- package/docs/src/{pages/en → content/docs}/features/doctor.md +0 -1
- package/docs/src/{pages/en → content/docs}/features/include.md +0 -1
- package/docs/src/{pages/en → content/docs}/features/init.md +0 -1
- package/docs/src/{pages/en → content/docs}/features/run.md +0 -1
- package/docs/src/{pages/en → content/docs}/features/scan.md +0 -1
- package/docs/src/{pages/en → content/docs}/features/setup.md +1 -2
- package/docs/src/{pages/en → content/docs}/features/teardown.md +0 -1
- package/docs/src/{pages/en → content/docs}/features/update.md +0 -1
- package/docs/src/{pages/en → content/docs}/guide/00-prepare.md +1 -2
- package/docs/src/{pages/en → content/docs}/guide/01-hello-console.md +0 -1
- package/docs/src/{pages/en → content/docs}/guide/02-blinky.md +2 -1
- package/docs/src/content/docs/index.mdx +66 -0
- package/docs/src/env.d.ts +2 -1
- package/docs/tsconfig.json +1 -16
- package/package.json +7 -10
- package/docs/public/make-scrollable-code-focusable.js +0 -3
- package/docs/public/run-hello-world.png +0 -0
- package/docs/src/components/Footer/AvatarList.astro +0 -149
- package/docs/src/components/Footer/Footer.astro +0 -16
- package/docs/src/components/HeadCommon.astro +0 -38
- package/docs/src/components/HeadSEO.astro +0 -28
- package/docs/src/components/Header/Header.astro +0 -133
- package/docs/src/components/Header/LanguageSelect.css +0 -47
- package/docs/src/components/Header/LanguageSelect.tsx +0 -47
- package/docs/src/components/Header/Search.css +0 -39
- package/docs/src/components/Header/Search.tsx +0 -61
- package/docs/src/components/Header/SidebarToggle.tsx +0 -43
- package/docs/src/components/Header/SkipToContent.astro +0 -22
- package/docs/src/components/LeftSidebar/LeftSidebar.astro +0 -118
- package/docs/src/components/PageContent/PageContent.astro +0 -40
- package/docs/src/components/RightSidebar/MoreMenu.astro +0 -78
- package/docs/src/components/RightSidebar/RightSidebar.astro +0 -26
- package/docs/src/components/RightSidebar/TableOfContents.tsx +0 -52
- package/docs/src/components/RightSidebar/ThemeToggleButton.css +0 -37
- package/docs/src/components/RightSidebar/ThemeToggleButton.tsx +0 -75
- package/docs/src/config.ts +0 -48
- package/docs/src/languages.ts +0 -10
- package/docs/src/layouts/MainLayout.astro +0 -122
- package/docs/src/pages/en/introduction.md +0 -82
- package/docs/src/pages/index.astro +0 -5
- package/docs/src/pages/search-index.json.ts +0 -18
- package/docs/src/styles/index.css +0 -382
- package/docs/src/styles/theme.css +0 -125
- package/docs/tailwind.config.cjs +0 -7
|
Binary file
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// fetch all commits for just this page's path
|
|
3
|
-
const path = 'docs/' + Astro.props.path;
|
|
4
|
-
const url = `https://api.github.com/repos/hipsterbrown/xs-dev/commits?path=${path}`;
|
|
5
|
-
const commitsURL = `https://github.com/hipsterbrown/xs-dev/commits/main/${path}`;
|
|
6
|
-
|
|
7
|
-
async function getCommits(url) {
|
|
8
|
-
try {
|
|
9
|
-
const token = import.meta.env.PUBLIC_GITHUB_TOKEN;
|
|
10
|
-
if (!token) {
|
|
11
|
-
throw new Error('Cannot find "PUBLIC_GITHUB_TOKEN" used for escaping rate-limiting.');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const auth = `Basic ${Buffer.from(token, 'binary').toString('base64')}`;
|
|
15
|
-
|
|
16
|
-
const res = await fetch(url, {
|
|
17
|
-
method: 'GET',
|
|
18
|
-
headers: {
|
|
19
|
-
Authorization: auth,
|
|
20
|
-
'User-Agent': 'astro-docs/1.0',
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
const data = await res.json();
|
|
25
|
-
|
|
26
|
-
if (!res.ok) {
|
|
27
|
-
throw new Error(
|
|
28
|
-
`Request to fetch commits failed. Reason: ${res.statusText}
|
|
29
|
-
Message: ${data.message}`
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return data;
|
|
34
|
-
} catch (e) {
|
|
35
|
-
console.warn(`[error] /src/components/AvatarList.astro
|
|
36
|
-
${e?.message ?? e}`);
|
|
37
|
-
return new Array();
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function removeDups(arr) {
|
|
42
|
-
if (!arr) {
|
|
43
|
-
return new Array();
|
|
44
|
-
}
|
|
45
|
-
let map = new Map();
|
|
46
|
-
|
|
47
|
-
for (let item of arr) {
|
|
48
|
-
let author = item.author;
|
|
49
|
-
// Deduplicate based on author.id
|
|
50
|
-
map.set(author.id, { login: author.login, id: author.id });
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return Array.from(map.values());
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const data = await getCommits(url);
|
|
57
|
-
const unique = removeDups(data);
|
|
58
|
-
const recentContributors = unique.slice(0, 3); // only show avatars for the 3 most recent contributors
|
|
59
|
-
const additionalContributors = unique.length - recentContributors.length; // list the rest of them as # of extra contributors
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
<!-- Thanks to @5t3ph for https://smolcss.dev/#smol-avatar-list! -->
|
|
63
|
-
<div class="contributors">
|
|
64
|
-
<ul class="avatar-list" style={`--avatar-count: ${recentContributors.length}`}>
|
|
65
|
-
{recentContributors.map((item) => (
|
|
66
|
-
<li>
|
|
67
|
-
<a href={`https://github.com/${item.login}`}>
|
|
68
|
-
<img alt={`Contributor ${item.login}`} title={`Contributor ${item.login}`} width="64" height="64" src={`https://avatars.githubusercontent.com/u/${item.id}`} />
|
|
69
|
-
</a>
|
|
70
|
-
</li>
|
|
71
|
-
))}
|
|
72
|
-
</ul>
|
|
73
|
-
{additionalContributors > 0 && (
|
|
74
|
-
<span>
|
|
75
|
-
<a href={commitsURL}>{`and ${additionalContributors} additional contributor${additionalContributors > 1 ? 's' : ''}.`}</a>
|
|
76
|
-
</span>
|
|
77
|
-
)}
|
|
78
|
-
{unique.length === 0 && <a href={commitsURL}>Contributors</a>}
|
|
79
|
-
</div>
|
|
80
|
-
|
|
81
|
-
<style>
|
|
82
|
-
.avatar-list {
|
|
83
|
-
--avatar-size: 2.5rem;
|
|
84
|
-
--avatar-count: 3;
|
|
85
|
-
|
|
86
|
-
display: grid;
|
|
87
|
-
list-style: none;
|
|
88
|
-
/* Default to displaying most of the avatar to
|
|
89
|
-
enable easier access on touch devices, ensuring
|
|
90
|
-
the WCAG touch target size is met or exceeded */
|
|
91
|
-
grid-template-columns: repeat(var(--avatar-count), max(44px, calc(var(--avatar-size) / 1.15)));
|
|
92
|
-
/* `padding` matches added visual dimensions of
|
|
93
|
-
the `box-shadow` to help create a more accurate
|
|
94
|
-
computed component size */
|
|
95
|
-
padding: 0.08em;
|
|
96
|
-
font-size: var(--avatar-size);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
@media (any-hover: hover) and (any-pointer: fine) {
|
|
100
|
-
.avatar-list {
|
|
101
|
-
/* We create 1 extra cell to enable the computed
|
|
102
|
-
width to match the final visual width */
|
|
103
|
-
grid-template-columns: repeat(calc(var(--avatar-count) + 1), calc(var(--avatar-size) / 1.75));
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.avatar-list li {
|
|
108
|
-
width: var(--avatar-size);
|
|
109
|
-
height: var(--avatar-size);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
.avatar-list li:hover ~ li a,
|
|
113
|
-
.avatar-list li:focus-within ~ li a {
|
|
114
|
-
transform: translateX(33%);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
.avatar-list img,
|
|
118
|
-
.avatar-list a {
|
|
119
|
-
display: block;
|
|
120
|
-
border-radius: 50%;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
.avatar-list a {
|
|
124
|
-
transition: transform 180ms ease-in-out;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
.avatar-list img {
|
|
128
|
-
width: 100%;
|
|
129
|
-
height: 100%;
|
|
130
|
-
object-fit: cover;
|
|
131
|
-
background-color: #fff;
|
|
132
|
-
box-shadow: 0 0 0 0.05em #fff, 0 0 0 0.08em rgba(0, 0, 0, 0.15);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
.avatar-list a:focus {
|
|
136
|
-
outline: 2px solid transparent;
|
|
137
|
-
/* Double-layer trick to work for dark and light backgrounds */
|
|
138
|
-
box-shadow: 0 0 0 0.08em var(--theme-accent), 0 0 0 0.12em white;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
.contributors {
|
|
142
|
-
display: flex;
|
|
143
|
-
align-items: center;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
.contributors > * + * {
|
|
147
|
-
margin-left: 0.75rem;
|
|
148
|
-
}
|
|
149
|
-
</style>
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import AvatarList from './AvatarList.astro';
|
|
3
|
-
const { path } = Astro.props;
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
<footer>
|
|
7
|
-
<AvatarList {path} />
|
|
8
|
-
</footer>
|
|
9
|
-
|
|
10
|
-
<style>
|
|
11
|
-
footer {
|
|
12
|
-
margin-top: auto;
|
|
13
|
-
padding: 2rem 0;
|
|
14
|
-
border-top: 3px solid var(--theme-divider);
|
|
15
|
-
}
|
|
16
|
-
</style>
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import '../styles/theme.css'
|
|
3
|
-
import '../styles/index.css'
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
<!-- Global Metadata -->
|
|
7
|
-
<meta charset="utf-8" />
|
|
8
|
-
<meta name="viewport" content="width=device-width" />
|
|
9
|
-
|
|
10
|
-
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
11
|
-
<link rel="alternate icon" type="image/x-icon" href="/favicon.ico" />
|
|
12
|
-
|
|
13
|
-
<link rel="sitemap" href="/sitemap.xml" />
|
|
14
|
-
|
|
15
|
-
<!-- Preload Fonts -->
|
|
16
|
-
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
17
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
18
|
-
<link
|
|
19
|
-
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital@0;1&display=swap"
|
|
20
|
-
rel="stylesheet"
|
|
21
|
-
/>
|
|
22
|
-
|
|
23
|
-
<!-- Scrollable a11y code helper -->
|
|
24
|
-
<script src="/make-scrollable-code-focusable.js" is:inline></script>
|
|
25
|
-
|
|
26
|
-
<!-- This is intentionally inlined to avoid FOUC -->
|
|
27
|
-
<script is:inline>
|
|
28
|
-
const root = document.documentElement
|
|
29
|
-
const theme = localStorage.getItem('theme')
|
|
30
|
-
if (
|
|
31
|
-
theme === 'dark' ||
|
|
32
|
-
(!theme && window.matchMedia('(prefers-color-scheme: dark)').matches)
|
|
33
|
-
) {
|
|
34
|
-
root.classList.add('theme-dark')
|
|
35
|
-
} else {
|
|
36
|
-
root.classList.remove('theme-dark')
|
|
37
|
-
}
|
|
38
|
-
</script>
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import { SITE, OPEN_GRAPH } from '../config.ts';
|
|
3
|
-
export interface Props {
|
|
4
|
-
content: any;
|
|
5
|
-
site: any;
|
|
6
|
-
canonicalURL: URL | string;
|
|
7
|
-
}
|
|
8
|
-
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
|
|
9
|
-
const { content = {} } = Astro.props;
|
|
10
|
-
const formattedContentTitle = content.title ? `${content.title} 🚀 ${SITE.title}` : SITE.title;
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
<!-- Page Metadata -->
|
|
14
|
-
<link rel="canonical" href={canonicalURL} />
|
|
15
|
-
|
|
16
|
-
<!-- OpenGraph Tags -->
|
|
17
|
-
<meta property="og:title" content={formattedContentTitle} />
|
|
18
|
-
<meta property="og:type" content="article" />
|
|
19
|
-
<meta property="og:url" content={canonicalURL} />
|
|
20
|
-
<meta property="og:locale" content={content.ogLocale ?? SITE.defaultLanguage} />
|
|
21
|
-
<meta name="description" property="og:description" content={content.description ? content.description : SITE.description} />
|
|
22
|
-
<meta property="og:site_name" content={SITE.title} />
|
|
23
|
-
|
|
24
|
-
<!-- Twitter Tags -->
|
|
25
|
-
<meta name="twitter:card" content="summary_large_image" />
|
|
26
|
-
<meta name="twitter:site" content={OPEN_GRAPH.twitter} />
|
|
27
|
-
<meta name="twitter:title" content={formattedContentTitle} />
|
|
28
|
-
<meta name="twitter:description" content={content.description ? content.description : SITE.description} />
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import { getLanguageFromURL, KNOWN_LANGUAGE_CODES } from '../../languages.ts';
|
|
3
|
-
import * as CONFIG from '../../config.ts';
|
|
4
|
-
import SkipToContent from './SkipToContent.astro';
|
|
5
|
-
import SidebarToggle from './SidebarToggle.tsx';
|
|
6
|
-
import LanguageSelect from './LanguageSelect.tsx';
|
|
7
|
-
import Search from './Search.tsx';
|
|
8
|
-
|
|
9
|
-
const { currentPage } = Astro.props;
|
|
10
|
-
const lang = currentPage && getLanguageFromURL(currentPage);
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
<header>
|
|
14
|
-
<SkipToContent />
|
|
15
|
-
<nav class="nav-wrapper" title="Top Navigation">
|
|
16
|
-
<div class="menu-toggle">
|
|
17
|
-
<SidebarToggle client:idle />
|
|
18
|
-
</div>
|
|
19
|
-
<div class="logo flex">
|
|
20
|
-
<a href={import.meta.env.BASE_URL}>
|
|
21
|
-
<h1>{CONFIG.SITE.title ?? "Documentation"}</h1>
|
|
22
|
-
</a>
|
|
23
|
-
</div>
|
|
24
|
-
<div style="flex-grow: 1;"></div>
|
|
25
|
-
{KNOWN_LANGUAGE_CODES.length > 1 && <LanguageSelect lang={lang} client:idle />}
|
|
26
|
-
</nav>
|
|
27
|
-
<Search client:idle />
|
|
28
|
-
</header>
|
|
29
|
-
|
|
30
|
-
<style>
|
|
31
|
-
header {
|
|
32
|
-
z-index: 11;
|
|
33
|
-
height: var(--theme-navbar-height);
|
|
34
|
-
width: 100%;
|
|
35
|
-
background-color: var(--theme-navbar-bg);
|
|
36
|
-
display: flex;
|
|
37
|
-
align-items: center;
|
|
38
|
-
justify-content: center;
|
|
39
|
-
position: sticky;
|
|
40
|
-
top: 0;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.logo {
|
|
44
|
-
flex: 1;
|
|
45
|
-
display: flex;
|
|
46
|
-
overflow: hidden;
|
|
47
|
-
width: 30px;
|
|
48
|
-
font-size: 2rem;
|
|
49
|
-
flex-shrink: 0;
|
|
50
|
-
font-weight: 600;
|
|
51
|
-
line-height: 1;
|
|
52
|
-
color: hsla(var(--color-base-white), 100%, 1);
|
|
53
|
-
gap: 0.25em;
|
|
54
|
-
z-index: -1;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.logo a {
|
|
58
|
-
display: flex;
|
|
59
|
-
padding: 0.5em 0.25em;
|
|
60
|
-
margin: -0.5em -0.25em;
|
|
61
|
-
text-decoration: none;
|
|
62
|
-
font-weight: bold;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
.logo a {
|
|
66
|
-
transition: color 100ms ease-out;
|
|
67
|
-
color: var(--theme-text);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.logo a:hover,
|
|
71
|
-
.logo a:focus {
|
|
72
|
-
color: var(--theme-text-accent);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
.logo h1 {
|
|
76
|
-
display: none;
|
|
77
|
-
font: inherit;
|
|
78
|
-
color: inherit;
|
|
79
|
-
margin: 0;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.nav-wrapper {
|
|
83
|
-
display: flex;
|
|
84
|
-
align-items: center;
|
|
85
|
-
justify-content: flex-end;
|
|
86
|
-
gap: 1em;
|
|
87
|
-
width: 100%;
|
|
88
|
-
max-width: 82em;
|
|
89
|
-
padding: 0 1rem;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
@media (min-width: 50em) {
|
|
93
|
-
header {
|
|
94
|
-
position: static;
|
|
95
|
-
padding: 2rem 0rem;
|
|
96
|
-
}
|
|
97
|
-
.logo {
|
|
98
|
-
width: auto;
|
|
99
|
-
margin: 0;
|
|
100
|
-
z-index: 0;
|
|
101
|
-
}
|
|
102
|
-
.logo h1 {
|
|
103
|
-
display: initial;
|
|
104
|
-
}
|
|
105
|
-
.menu-toggle {
|
|
106
|
-
display: none;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/** Style Algolia */
|
|
111
|
-
:root {
|
|
112
|
-
--docsearch-primary-color: var(--theme-accent);
|
|
113
|
-
--docsearch-logo-color: var(--theme-text);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.search-item {
|
|
117
|
-
display: none;
|
|
118
|
-
position: relative;
|
|
119
|
-
z-index: 10;
|
|
120
|
-
flex-grow: 1;
|
|
121
|
-
padding-right: 0.7rem;
|
|
122
|
-
display: flex;
|
|
123
|
-
max-width: 200px;
|
|
124
|
-
}
|
|
125
|
-
:global(.search-item > *) {
|
|
126
|
-
flex-grow: 1;
|
|
127
|
-
}
|
|
128
|
-
@media (min-width: 50em) {
|
|
129
|
-
.search-item {
|
|
130
|
-
max-width: 400px;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
</style>
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
.language-select {
|
|
2
|
-
flex-grow: 1;
|
|
3
|
-
width: 48px;
|
|
4
|
-
box-sizing: border-box;
|
|
5
|
-
margin: 0;
|
|
6
|
-
padding: 0.33em 0.5em;
|
|
7
|
-
overflow: visible;
|
|
8
|
-
font-weight: 500;
|
|
9
|
-
font-size: 1rem;
|
|
10
|
-
font-family: inherit;
|
|
11
|
-
line-height: inherit;
|
|
12
|
-
background-color: var(--theme-bg);
|
|
13
|
-
border-color: var(--theme-text-lighter);
|
|
14
|
-
color: var(--theme-text-light);
|
|
15
|
-
border-style: solid;
|
|
16
|
-
border-width: 1px;
|
|
17
|
-
border-radius: 0.25rem;
|
|
18
|
-
outline: 0;
|
|
19
|
-
cursor: pointer;
|
|
20
|
-
transition-timing-function: ease-out;
|
|
21
|
-
transition-duration: 0.2s;
|
|
22
|
-
transition-property: border-color, color;
|
|
23
|
-
-webkit-font-smoothing: antialiased;
|
|
24
|
-
padding-left: 30px;
|
|
25
|
-
padding-right: 1rem;
|
|
26
|
-
}
|
|
27
|
-
.language-select-wrapper .language-select:hover,
|
|
28
|
-
.language-select-wrapper .language-select:focus {
|
|
29
|
-
color: var(--theme-text);
|
|
30
|
-
border-color: var(--theme-text-light);
|
|
31
|
-
}
|
|
32
|
-
.language-select-wrapper {
|
|
33
|
-
color: var(--theme-text-light);
|
|
34
|
-
position: relative;
|
|
35
|
-
}
|
|
36
|
-
.language-select-wrapper > svg {
|
|
37
|
-
position: absolute;
|
|
38
|
-
top: 7px;
|
|
39
|
-
left: 10px;
|
|
40
|
-
pointer-events: none;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
@media (min-width: 50em) {
|
|
44
|
-
.language-select {
|
|
45
|
-
width: 100%;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import type { Component } from 'solid-js';
|
|
2
|
-
import './LanguageSelect.css';
|
|
3
|
-
import { KNOWN_LANGUAGES, langPathRegex } from '../../languages';
|
|
4
|
-
|
|
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
|
-
);
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export default LanguageSelect;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
.flex-column {
|
|
2
|
-
flex-direction: column;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
.SearchContainer {
|
|
6
|
-
position: relative;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
.SearchContainer-input {
|
|
10
|
-
border: 1px solid #333333;
|
|
11
|
-
padding: 0.5rem 1rem;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.SearchContainer-button {
|
|
15
|
-
border-radius: 0px;
|
|
16
|
-
padding: 0.5rem;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.SearchContainer-list {
|
|
20
|
-
background: white;
|
|
21
|
-
top: 2.6rem;
|
|
22
|
-
display: flex;
|
|
23
|
-
flex-direction: column;
|
|
24
|
-
left: 0;
|
|
25
|
-
position: absolute;
|
|
26
|
-
width: 100%;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.SearchContainer-list.has-results {
|
|
30
|
-
border: 1px solid #333333;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.SearchContainer-list_item {
|
|
34
|
-
padding: 0.5rem 1rem;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.SearchContainer-link {
|
|
38
|
-
color: blue;
|
|
39
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { type Component, createSignal, For, onMount } from 'solid-js';
|
|
2
|
-
import Fuse from 'fuse.js'
|
|
3
|
-
import './Search.css'
|
|
4
|
-
|
|
5
|
-
const SearchForm: Component = () => {
|
|
6
|
-
let fuse: null | Fuse<{ url: string, title: string }> = null;
|
|
7
|
-
const [results, setResults] = createSignal([]);
|
|
8
|
-
|
|
9
|
-
const searchContent = (event: SubmitEvent) => {
|
|
10
|
-
event.preventDefault()
|
|
11
|
-
const { search } = Object.fromEntries(
|
|
12
|
-
new FormData(event.currentTarget as HTMLFormElement)
|
|
13
|
-
)
|
|
14
|
-
const result = fuse.search(search as string)
|
|
15
|
-
setResults(result.map(({ item }) => item))
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
onMount(async () => {
|
|
19
|
-
const content = await fetch('/search-index.json')
|
|
20
|
-
.then((res) => res.json())
|
|
21
|
-
const options = { keys: ['title', 'description', 'content'] }
|
|
22
|
-
fuse = new Fuse(content, options)
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
return (
|
|
26
|
-
<div class="flex flex-column SearchContainer">
|
|
27
|
-
<form method="get" id="search-form" onSubmit={searchContent}>
|
|
28
|
-
<div role="search" class="flex flex-row">
|
|
29
|
-
<input
|
|
30
|
-
type="search"
|
|
31
|
-
id="search"
|
|
32
|
-
name="search"
|
|
33
|
-
aria-label="search documentation content"
|
|
34
|
-
placeholder="search documentation content"
|
|
35
|
-
class="SearchContainer-input"
|
|
36
|
-
/>
|
|
37
|
-
<button type="submit" class="SearchContainer-button">
|
|
38
|
-
Search
|
|
39
|
-
</button>
|
|
40
|
-
</div>
|
|
41
|
-
</form>
|
|
42
|
-
<ul
|
|
43
|
-
classList={{ 'SearchContainer-list': true, 'has-results': results().length > 0 }}
|
|
44
|
-
aria-live="assertive"
|
|
45
|
-
aria-atomic="true"
|
|
46
|
-
>
|
|
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>
|
|
56
|
-
</ul>
|
|
57
|
-
</div>
|
|
58
|
-
)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export default SearchForm
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { type Component, createSignal, createEffect } from 'solid-js';
|
|
2
|
-
|
|
3
|
-
const MenuToggle: Component = () => {
|
|
4
|
-
const [sidebarShown, setSidebarShown] = createSignal(false);
|
|
5
|
-
|
|
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
|
-
});
|
|
15
|
-
|
|
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
|
-
);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export default MenuToggle;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
<a href="#article" class="sr-only focus:not-sr-only skiplink"><span>Skip to Content</span></a>
|
|
2
|
-
|
|
3
|
-
<style>
|
|
4
|
-
.skiplink,
|
|
5
|
-
.skiplink:focus,
|
|
6
|
-
.skiplink:focus-visible {
|
|
7
|
-
position: absolute;
|
|
8
|
-
padding: 0.25em;
|
|
9
|
-
font-size: larger;
|
|
10
|
-
top: 0;
|
|
11
|
-
left: 0;
|
|
12
|
-
right: 0;
|
|
13
|
-
z-index: 9;
|
|
14
|
-
display: block;
|
|
15
|
-
text-align: center;
|
|
16
|
-
background-color: var(--theme-text-accent);
|
|
17
|
-
color: var(--theme-bg);
|
|
18
|
-
border-radius: 0.25em;
|
|
19
|
-
outline: var(--theme-bg) solid 1px;
|
|
20
|
-
outline-offset: 0;
|
|
21
|
-
}
|
|
22
|
-
</style>
|