@hyvor/design 0.0.51 → 0.0.53
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/dist/components/Base/Base.svelte +5 -1
- package/dist/components/Base/Base.svelte.d.ts +3 -1
- package/dist/components/ColorPicker/ColorPicker.svelte +5 -15
- package/dist/components/Internationalization/InternationalizationProvider.svelte +6 -4
- package/dist/components/Internationalization/InternationalizationProvider.svelte.d.ts +7 -2
- package/dist/components/Internationalization/LanguageToggle.svelte +51 -31
- package/dist/components/Internationalization/LanguageToggle.svelte.d.ts +9 -1
- package/dist/components/Internationalization/T.svelte +95 -3
- package/dist/components/Internationalization/T.svelte.d.ts +9 -1
- package/dist/components/Internationalization/i18n.d.ts +28 -13
- package/dist/components/Internationalization/i18n.js +60 -14
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +5 -0
- package/dist/marketing/Docs/Content/Content.svelte +32 -3
- package/dist/marketing/Docs/Docs.svelte +10 -4
- package/dist/marketing/Docs/Nav/Nav.svelte +121 -20
- package/dist/marketing/Docs/Sidebar/Sidebar.svelte +32 -0
- package/dist/marketing/Docs/Sidebar/Sidebar.svelte.d.ts +23 -0
- package/dist/marketing/Docs/Toc.svelte +141 -15
- package/dist/marketing/Header/Header.svelte +8 -0
- package/package.json +7 -2
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
import DarkProvider from "./../Dark/DarkProvider.svelte";
|
|
3
3
|
import "../../index.js";
|
|
4
4
|
import ToastProvider from "../Toast/ToastProvider.svelte";
|
|
5
|
+
export let dark = false;
|
|
5
6
|
</script>
|
|
6
7
|
|
|
7
8
|
<div id="base">
|
|
8
9
|
<slot />
|
|
9
10
|
</div>
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
{#if dark}
|
|
13
|
+
<DarkProvider />
|
|
14
|
+
{/if}
|
|
15
|
+
|
|
12
16
|
<ToastProvider />
|
|
13
17
|
<ConfirmModalProvider />
|
|
@@ -14,7 +14,7 @@ function handleClose() {
|
|
|
14
14
|
}
|
|
15
15
|
</script>
|
|
16
16
|
|
|
17
|
-
<span>
|
|
17
|
+
<span class="color-picker">
|
|
18
18
|
<button
|
|
19
19
|
style:width="{size}px"
|
|
20
20
|
style:height="{size}px"
|
|
@@ -23,7 +23,8 @@ function handleClose() {
|
|
|
23
23
|
></button>
|
|
24
24
|
|
|
25
25
|
{#if show}
|
|
26
|
-
<div
|
|
26
|
+
<div
|
|
27
|
+
class="color-picker-wrap"
|
|
27
28
|
use:clickOutside={{
|
|
28
29
|
callback: () => handleClose(),
|
|
29
30
|
}}
|
|
@@ -39,30 +40,19 @@ function handleClose() {
|
|
|
39
40
|
{/if}
|
|
40
41
|
</span>
|
|
41
42
|
|
|
42
|
-
<!-- <span>
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
<input
|
|
46
|
-
type="color"
|
|
47
|
-
bind:value={color}
|
|
48
|
-
bind:this={inputEl}
|
|
49
|
-
|
|
50
|
-
on:change
|
|
51
|
-
on:input
|
|
52
|
-
/>
|
|
53
|
-
</span> -->
|
|
54
|
-
|
|
55
43
|
<style>
|
|
56
44
|
span {
|
|
57
45
|
position: relative;
|
|
58
46
|
}
|
|
59
47
|
button {
|
|
60
48
|
border-radius: 50%;
|
|
49
|
+
border: 1px solid var(--border);
|
|
61
50
|
}
|
|
62
51
|
div {
|
|
63
52
|
position: absolute;
|
|
64
53
|
left: 0;
|
|
65
54
|
top: 100%;
|
|
66
55
|
width: 0;
|
|
56
|
+
z-index: 1000;
|
|
67
57
|
}
|
|
68
58
|
</style>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
<script>import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
<script>import { setContext } from "svelte";
|
|
2
|
+
import { InternationalizationService } from "./i18n.js";
|
|
3
|
+
export let languages;
|
|
4
|
+
const i18n = new InternationalizationService(languages);
|
|
5
|
+
setContext("i18n", i18n);
|
|
5
6
|
</script>
|
|
6
7
|
|
|
8
|
+
<slot />
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
+
import { type Language } from "./i18n.js";
|
|
2
3
|
declare const __propDef: {
|
|
3
|
-
props:
|
|
4
|
+
props: {
|
|
5
|
+
languages: Language[];
|
|
6
|
+
};
|
|
4
7
|
events: {
|
|
5
8
|
[evt: string]: CustomEvent<any>;
|
|
6
9
|
};
|
|
7
|
-
slots: {
|
|
10
|
+
slots: {
|
|
11
|
+
default: {};
|
|
12
|
+
};
|
|
8
13
|
};
|
|
9
14
|
export type InternationalizationProviderProps = typeof __propDef.props;
|
|
10
15
|
export type InternationalizationProviderEvents = typeof __propDef.events;
|
|
@@ -1,43 +1,63 @@
|
|
|
1
|
-
<script>import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
<script>import { getContext } from "svelte";
|
|
2
|
+
import Dropdown from "../Dropdown/Dropdown.svelte";
|
|
3
|
+
import Button from "../Button/Button.svelte";
|
|
4
|
+
import {} from "./i18n.js";
|
|
5
|
+
import ActionList from "../ActionList/ActionList.svelte";
|
|
6
|
+
import ActionListItem from "../ActionList/ActionListItem.svelte";
|
|
7
|
+
import Text from "../Text/Text.svelte";
|
|
8
|
+
import { IconCaretDown } from "@hyvor/icons";
|
|
9
|
+
import IconButton from "../IconButton/IconButton.svelte";
|
|
10
|
+
export let position = "bottom";
|
|
11
|
+
export let align = "start";
|
|
12
|
+
export let caret = IconCaretDown;
|
|
13
|
+
export let icon = false;
|
|
14
|
+
export let size = "medium";
|
|
15
|
+
const i18n = getContext("i18n");
|
|
16
|
+
const currentLanguage = i18n ? i18n.localeLanguage : void 0;
|
|
17
|
+
let show = false;
|
|
18
|
+
function handleClick(language) {
|
|
19
|
+
i18n.setLocale(language.code);
|
|
20
|
+
show = false;
|
|
21
|
+
}
|
|
6
22
|
</script>
|
|
7
23
|
|
|
8
24
|
|
|
9
|
-
{#if i18n}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
25
|
+
{#if i18n && $currentLanguage}
|
|
26
|
+
|
|
27
|
+
<Dropdown bind:show={show} {position} {align}>
|
|
28
|
+
<span slot="trigger">
|
|
29
|
+
{#if icon}
|
|
30
|
+
<IconButton color="input" {size}>
|
|
31
|
+
{$currentLanguage.flag}
|
|
32
|
+
</IconButton>
|
|
33
|
+
{:else}
|
|
34
|
+
<Button color="input" {size}>
|
|
35
|
+
<span slot="start">{$currentLanguage.flag}</span>
|
|
36
|
+
{$currentLanguage.name}
|
|
37
|
+
<svelte:component slot="end" this={caret} size={12} />
|
|
38
|
+
</Button>
|
|
39
|
+
{/if}
|
|
15
40
|
</span>
|
|
16
|
-
|
|
41
|
+
<ActionList slot="content">
|
|
42
|
+
{#each i18n.languages as language (language.code)}
|
|
43
|
+
<ActionListItem on:click={() => handleClick(language)}>
|
|
44
|
+
<span class="flag" slot="start">{language.flag}</span>
|
|
45
|
+
<span class="name">
|
|
46
|
+
{language.name}
|
|
47
|
+
</span>
|
|
48
|
+
<Text small light>
|
|
49
|
+
{language.region}
|
|
50
|
+
</Text>
|
|
51
|
+
</ActionListItem>
|
|
52
|
+
{/each}
|
|
53
|
+
</ActionList>
|
|
54
|
+
</Dropdown>
|
|
55
|
+
|
|
17
56
|
{/if}
|
|
18
57
|
|
|
19
58
|
<style>
|
|
20
|
-
.current {
|
|
21
|
-
padding: 4px 15px;
|
|
22
|
-
font-size: 15px;
|
|
23
|
-
display: flex;
|
|
24
|
-
align-items: center;
|
|
25
|
-
cursor: pointer;
|
|
26
|
-
box-shadow: var(--box-shadow);
|
|
27
|
-
border-radius: var(--box-radius);
|
|
28
|
-
background-color: var(--box-background);
|
|
29
|
-
transition: .2s box-shadow;
|
|
30
|
-
}
|
|
31
|
-
.current:hover {
|
|
32
|
-
box-shadow: var(--box-shadow-dark);
|
|
33
|
-
}
|
|
34
59
|
.flag {
|
|
35
60
|
margin-right: 6px;
|
|
36
61
|
font-size: 20px;
|
|
37
62
|
}
|
|
38
|
-
.icon {
|
|
39
|
-
margin-left: 8px;
|
|
40
|
-
display: inline-flex;
|
|
41
|
-
align-items: center;
|
|
42
|
-
}
|
|
43
63
|
</style>
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
+
import { type ComponentProps, type ComponentType } from "svelte";
|
|
3
|
+
import Dropdown from "../Dropdown/Dropdown.svelte";
|
|
2
4
|
declare const __propDef: {
|
|
3
|
-
props:
|
|
5
|
+
props: {
|
|
6
|
+
position?: ComponentProps<Dropdown>['position'];
|
|
7
|
+
align?: ComponentProps<Dropdown>['align'];
|
|
8
|
+
caret?: ComponentType | undefined;
|
|
9
|
+
icon?: boolean | undefined;
|
|
10
|
+
size?: "small" | "medium" | undefined;
|
|
11
|
+
};
|
|
4
12
|
events: {
|
|
5
13
|
[evt: string]: CustomEvent<any>;
|
|
6
14
|
};
|
|
@@ -1,5 +1,97 @@
|
|
|
1
|
-
<script>import {
|
|
2
|
-
|
|
1
|
+
<script>import { getContext, onMount, tick, afterUpdate } from "svelte";
|
|
2
|
+
import { getStringByKey, InternationalizationService } from "./i18n.js";
|
|
3
|
+
import { IntlMessageFormat } from "intl-messageformat";
|
|
4
|
+
import { browser } from "$app/environment";
|
|
5
|
+
export let key;
|
|
6
|
+
export let params = {};
|
|
7
|
+
let hasComponentParams = false;
|
|
8
|
+
function getParamsForBackend() {
|
|
9
|
+
let retParams = {};
|
|
10
|
+
for (let [key2, value] of Object.entries(params)) {
|
|
11
|
+
let newValue;
|
|
12
|
+
if (typeof value === "object" && value !== null && value.hasOwnProperty("component")) {
|
|
13
|
+
newValue = (chunks) => {
|
|
14
|
+
const children = typeof chunks === "string" ? chunks : chunks.join("");
|
|
15
|
+
return children;
|
|
16
|
+
};
|
|
17
|
+
hasComponentParams = true;
|
|
18
|
+
} else {
|
|
19
|
+
newValue = value;
|
|
20
|
+
}
|
|
21
|
+
retParams[key2] = newValue;
|
|
22
|
+
}
|
|
23
|
+
return retParams;
|
|
24
|
+
}
|
|
25
|
+
const componentBindings = /* @__PURE__ */ new Map();
|
|
26
|
+
function getParamsForFrontend() {
|
|
27
|
+
let retParams = {};
|
|
28
|
+
for (let [key2, value] of Object.entries(params)) {
|
|
29
|
+
let newValue;
|
|
30
|
+
if (typeof value === "object" && value !== null && value.hasOwnProperty("component")) {
|
|
31
|
+
const { component, props } = value;
|
|
32
|
+
newValue = (chunks) => {
|
|
33
|
+
const children = typeof chunks === "string" ? chunks : chunks.join("");
|
|
34
|
+
const id = key2 + "-" + Math.random().toString(36).substring(7) + "-" + Date.now().toString();
|
|
35
|
+
componentBindings.set(id, {
|
|
36
|
+
component,
|
|
37
|
+
props: {
|
|
38
|
+
...props,
|
|
39
|
+
children
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return '<span id="' + id + '">' + children + "</span>";
|
|
43
|
+
};
|
|
44
|
+
} else {
|
|
45
|
+
newValue = value;
|
|
46
|
+
}
|
|
47
|
+
retParams[key2] = newValue;
|
|
48
|
+
}
|
|
49
|
+
return retParams;
|
|
50
|
+
}
|
|
51
|
+
const i18n = getContext("i18n");
|
|
52
|
+
const locale = i18n.locale;
|
|
53
|
+
const strings = i18n.strings;
|
|
54
|
+
let message = getMessage(getParamsForBackend());
|
|
55
|
+
function getMessage(processedParams) {
|
|
56
|
+
const string = getStringByKey($strings, key);
|
|
57
|
+
if (string) {
|
|
58
|
+
const formatter = new IntlMessageFormat(string, $locale);
|
|
59
|
+
return formatter.format(processedParams);
|
|
60
|
+
}
|
|
61
|
+
return "";
|
|
62
|
+
}
|
|
63
|
+
function bindComponents() {
|
|
64
|
+
for (let [id, binding] of componentBindings) {
|
|
65
|
+
const el = document.getElementById(id);
|
|
66
|
+
if (el) {
|
|
67
|
+
el.innerHTML = "";
|
|
68
|
+
new binding.component({
|
|
69
|
+
target: el,
|
|
70
|
+
hydrate: true,
|
|
71
|
+
props: binding.props
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function renderFrontend() {
|
|
77
|
+
message = getMessage(getParamsForFrontend());
|
|
78
|
+
await tick();
|
|
79
|
+
if (hasComponentParams)
|
|
80
|
+
bindComponents();
|
|
81
|
+
}
|
|
82
|
+
let mounted = false;
|
|
83
|
+
$: {
|
|
84
|
+
$locale, $strings, params;
|
|
85
|
+
if (browser && mounted) {
|
|
86
|
+
renderFrontend();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
onMount(async () => {
|
|
90
|
+
mounted = true;
|
|
91
|
+
if (hasComponentParams) {
|
|
92
|
+
renderFrontend();
|
|
93
|
+
}
|
|
94
|
+
});
|
|
3
95
|
</script>
|
|
4
96
|
|
|
5
|
-
{
|
|
97
|
+
{@html message}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
+
import { type ComponentType } from "svelte";
|
|
3
|
+
import { type PrimitiveType } from 'intl-messageformat';
|
|
2
4
|
declare const __propDef: {
|
|
3
|
-
props:
|
|
5
|
+
props: {
|
|
6
|
+
key: string;
|
|
7
|
+
params?: Record<string, {
|
|
8
|
+
component: ComponentType;
|
|
9
|
+
props?: Record<string, any> | undefined;
|
|
10
|
+
} | PrimitiveType> | undefined;
|
|
11
|
+
};
|
|
4
12
|
events: {
|
|
5
13
|
[evt: string]: CustomEvent<any>;
|
|
6
14
|
};
|
|
@@ -1,18 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/// <reference types="svelte" />
|
|
2
|
+
import { type Readable, type Writable } from "svelte/store";
|
|
3
|
+
export type i18nLoaderType = () => Promise<any>;
|
|
4
|
+
interface LanguageBase {
|
|
4
5
|
name: string;
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
flag: string;
|
|
7
|
+
region: string;
|
|
8
|
+
code: string;
|
|
9
|
+
default?: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface LanguageWithStrings extends LanguageBase {
|
|
12
|
+
strings: Record<string, any>;
|
|
13
|
+
}
|
|
14
|
+
interface LanguageWithLoader extends LanguageBase {
|
|
15
|
+
loader: i18nLoaderType;
|
|
7
16
|
}
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
17
|
+
export type Language = LanguageWithStrings | LanguageWithLoader;
|
|
18
|
+
export declare class InternationalizationService {
|
|
19
|
+
languages: LanguageWithLoader[];
|
|
20
|
+
locale: Writable<string>;
|
|
21
|
+
localeLanguage: Readable<LanguageWithLoader>;
|
|
22
|
+
strings: Writable<{}>;
|
|
23
|
+
stringsCache: Map<string, Record<string, any>>;
|
|
24
|
+
defaultStrings: Record<string, any>;
|
|
25
|
+
constructor(languages: Language[]);
|
|
26
|
+
setStrings(code: string): void;
|
|
27
|
+
setLocale(code: string): void;
|
|
28
|
+
register(language: Language): void;
|
|
13
29
|
found(code: string): boolean;
|
|
14
|
-
languageByCode(code: string):
|
|
15
|
-
getCurrent(): Language | undefined;
|
|
16
|
-
load(code: string): Promise<any>;
|
|
30
|
+
languageByCode(code: string): LanguageWithLoader | undefined;
|
|
17
31
|
}
|
|
32
|
+
export declare function getStringByKey(messages: Record<string, any>, key: string): string | undefined;
|
|
18
33
|
export {};
|
|
@@ -1,15 +1,54 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { deepmerge } from "deepmerge-ts";
|
|
2
|
+
import { writable, derived } from "svelte/store";
|
|
3
|
+
export class InternationalizationService {
|
|
3
4
|
languages = [];
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
locale;
|
|
6
|
+
localeLanguage;
|
|
7
|
+
strings = writable({});
|
|
8
|
+
stringsCache = new Map();
|
|
9
|
+
defaultStrings;
|
|
10
|
+
constructor(languages) {
|
|
11
|
+
const defaultLanguage = languages.find(l => l.default);
|
|
12
|
+
if (!defaultLanguage) {
|
|
13
|
+
throw new Error('Default language not found');
|
|
14
|
+
}
|
|
15
|
+
const defaultStrings = defaultLanguage.strings || null;
|
|
16
|
+
if (!defaultStrings) {
|
|
17
|
+
throw new Error('Default strings not found for the default language');
|
|
18
|
+
}
|
|
19
|
+
this.locale = writable(defaultLanguage.code);
|
|
20
|
+
this.localeLanguage = derived(this.locale, $locale => this.languageByCode($locale));
|
|
21
|
+
this.defaultStrings = defaultStrings;
|
|
22
|
+
this.strings.set(this.defaultStrings);
|
|
23
|
+
this.stringsCache.set(defaultLanguage.code, this.defaultStrings);
|
|
24
|
+
for (const language of languages) {
|
|
25
|
+
this.register(language);
|
|
26
|
+
}
|
|
6
27
|
}
|
|
7
|
-
|
|
28
|
+
setStrings(code) {
|
|
29
|
+
const defaultStrings = this.defaultStrings;
|
|
30
|
+
const strings = this.stringsCache.get(code) || {};
|
|
31
|
+
const merged = deepmerge(defaultStrings, strings);
|
|
32
|
+
this.strings.set(merged);
|
|
33
|
+
}
|
|
34
|
+
setLocale(code) {
|
|
35
|
+
this.locale.set(code);
|
|
36
|
+
if (this.stringsCache.has(code)) {
|
|
37
|
+
this.setStrings(code);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
this.languageByCode(code)?.loader().then(({ default: strings }) => {
|
|
41
|
+
this.stringsCache.set(code, strings);
|
|
42
|
+
this.setStrings(code);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
register(language) {
|
|
8
47
|
this.languages.push({
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
48
|
+
...language,
|
|
49
|
+
loader: language.hasOwnProperty('strings') ?
|
|
50
|
+
() => Promise.resolve(language.strings) :
|
|
51
|
+
language.loader,
|
|
13
52
|
});
|
|
14
53
|
}
|
|
15
54
|
found(code) {
|
|
@@ -18,10 +57,17 @@ export class i18n {
|
|
|
18
57
|
languageByCode(code) {
|
|
19
58
|
return this.languages.find(l => l.code === code);
|
|
20
59
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
60
|
+
}
|
|
61
|
+
export function getStringByKey(messages, key) {
|
|
62
|
+
const keys = key.split('.');
|
|
63
|
+
let value = messages;
|
|
64
|
+
for (const key of keys) {
|
|
65
|
+
if (value && typeof value === 'object' && key in value) {
|
|
66
|
+
value = value[key];
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
return undefined; // Key not found or value is not an object
|
|
70
|
+
}
|
|
26
71
|
}
|
|
72
|
+
return value;
|
|
27
73
|
}
|
|
@@ -41,3 +41,7 @@ export { default as toast } from './Toast/toast.js';
|
|
|
41
41
|
export { default as Tooltip } from './Tooltip/Tooltip.svelte';
|
|
42
42
|
export { default as IconMessage } from './IconMessage/IconMessage.svelte';
|
|
43
43
|
export { clickOutside } from './directives/clickOutside.js';
|
|
44
|
+
export { default as InternationalizationProvider } from './Internationalization/InternationalizationProvider.svelte';
|
|
45
|
+
export { default as LanguageToggle } from './Internationalization/LanguageToggle.svelte';
|
|
46
|
+
export { default as T } from './Internationalization/T.svelte';
|
|
47
|
+
export { type Language as InternationalizationLanguage, InternationalizationService } from './Internationalization/i18n.js';
|
package/dist/components/index.js
CHANGED
|
@@ -42,3 +42,8 @@ export { default as Tooltip } from './Tooltip/Tooltip.svelte';
|
|
|
42
42
|
export { default as IconMessage } from './IconMessage/IconMessage.svelte';
|
|
43
43
|
// directives
|
|
44
44
|
export { clickOutside } from './directives/clickOutside.js';
|
|
45
|
+
// i18n
|
|
46
|
+
export { default as InternationalizationProvider } from './Internationalization/InternationalizationProvider.svelte';
|
|
47
|
+
export { default as LanguageToggle } from './Internationalization/LanguageToggle.svelte';
|
|
48
|
+
export { default as T } from './Internationalization/T.svelte';
|
|
49
|
+
export { InternationalizationService } from './Internationalization/i18n.js';
|
|
@@ -52,7 +52,7 @@ content :global(p), content :global(li) {
|
|
|
52
52
|
line-height: var(--line-height-content);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
content :global(h1) {
|
|
55
|
+
content :global(h1:first-child) {
|
|
56
56
|
margin-top: 0;
|
|
57
57
|
font-size: 36px;
|
|
58
58
|
font-weight: 600;
|
|
@@ -61,8 +61,7 @@ content :global(h1) {
|
|
|
61
61
|
position: relative;
|
|
62
62
|
display: table;
|
|
63
63
|
}
|
|
64
|
-
|
|
65
|
-
content :global(h1::after) {
|
|
64
|
+
content :global(h1:first-child):after {
|
|
66
65
|
position: absolute;
|
|
67
66
|
content: "";
|
|
68
67
|
bottom: -13px;
|
|
@@ -114,12 +113,32 @@ content :global(a.heading-anchor-link) {
|
|
|
114
113
|
align-items: center;
|
|
115
114
|
}
|
|
116
115
|
|
|
116
|
+
content :global(h1),
|
|
117
117
|
content :global(h2),
|
|
118
118
|
content :global(h3),
|
|
119
119
|
content :global(h4),
|
|
120
120
|
content :global(h5),
|
|
121
121
|
content :global(h6) {
|
|
122
122
|
position: relative;
|
|
123
|
+
margin: 20px 0;
|
|
124
|
+
}
|
|
125
|
+
content :global(h1) {
|
|
126
|
+
font-size: 2em;
|
|
127
|
+
}
|
|
128
|
+
content :global(h2) {
|
|
129
|
+
font-size: 1.5em;
|
|
130
|
+
}
|
|
131
|
+
content :global(h3) {
|
|
132
|
+
font-size: 1.3em;
|
|
133
|
+
}
|
|
134
|
+
content :global(h4) {
|
|
135
|
+
font-size: 1.2em;
|
|
136
|
+
}
|
|
137
|
+
content :global(h5) {
|
|
138
|
+
font-size: 1.1em;
|
|
139
|
+
}
|
|
140
|
+
content :global(h6) {
|
|
141
|
+
font-size: 1em;
|
|
123
142
|
}
|
|
124
143
|
|
|
125
144
|
content :global(.heading-anchor:hover + .heading-anchor-link) {
|
|
@@ -132,4 +151,14 @@ content :global(h5 a:not(.heading-anchor-link)),
|
|
|
132
151
|
content :global(h6 a:not(.heading-anchor-link)) {
|
|
133
152
|
text-decoration: none;
|
|
134
153
|
color: inherit;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
@media (max-width: 992px) {
|
|
157
|
+
.content-wrap {
|
|
158
|
+
padding-top: 0;
|
|
159
|
+
order: 2;
|
|
160
|
+
}
|
|
161
|
+
content {
|
|
162
|
+
padding: 20px 25px;
|
|
163
|
+
}
|
|
135
164
|
}</style>
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import
|
|
3
|
-
|
|
2
|
+
import Sidebar from "./Sidebar/Sidebar.svelte";
|
|
4
3
|
</script>
|
|
5
4
|
<div class="docs">
|
|
6
5
|
|
|
7
6
|
<slot name="nav" />
|
|
8
7
|
<slot name="content" />
|
|
9
|
-
<
|
|
10
|
-
|
|
8
|
+
<Sidebar />
|
|
11
9
|
</div>
|
|
12
10
|
|
|
13
11
|
<style>
|
|
@@ -22,4 +20,12 @@
|
|
|
22
20
|
/* min-height: calc(100vh - var(--header-height)); */
|
|
23
21
|
}
|
|
24
22
|
|
|
23
|
+
|
|
24
|
+
@media (max-width: 992px) {
|
|
25
|
+
.docs {
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
width: 100%;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
25
31
|
</style>
|
|
@@ -1,30 +1,131 @@
|
|
|
1
|
-
<script>import
|
|
1
|
+
<script>import { afterNavigate, onNavigate } from "$app/navigation";
|
|
2
|
+
import { page } from "$app/stores";
|
|
3
|
+
import { IconList } from "@hyvor/icons";
|
|
4
|
+
import { onMount } from "svelte";
|
|
5
|
+
import { clickOutside } from "../../../components/index.js";
|
|
6
|
+
let navEl;
|
|
7
|
+
let active = null;
|
|
8
|
+
function setActive() {
|
|
9
|
+
const activeEl = navEl?.querySelector("a.active");
|
|
10
|
+
if (!activeEl || !(activeEl instanceof HTMLElement)) {
|
|
11
|
+
active = null;
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const category = activeEl.closest(".nav-category")?.querySelector(".name")?.innerText || null;
|
|
15
|
+
active = {
|
|
16
|
+
name: activeEl.innerText,
|
|
17
|
+
category
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
onMount(() => {
|
|
21
|
+
setActive();
|
|
22
|
+
});
|
|
23
|
+
afterNavigate(() => {
|
|
24
|
+
setActive();
|
|
25
|
+
hideNavOnMobile();
|
|
26
|
+
});
|
|
27
|
+
let mobileNavShown = false;
|
|
28
|
+
function handleMobileClick(e) {
|
|
29
|
+
e.stopPropagation();
|
|
30
|
+
if (navEl.style.display !== "block") {
|
|
31
|
+
navEl.style.display = "block";
|
|
32
|
+
mobileNavShown = true;
|
|
33
|
+
} else {
|
|
34
|
+
navEl.style.display = "none";
|
|
35
|
+
mobileNavShown = false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function handleNavOutsideClick() {
|
|
39
|
+
if (mobileNavShown) {
|
|
40
|
+
navEl.style.display = "none";
|
|
41
|
+
mobileNavShown = false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function hideNavOnMobile() {
|
|
45
|
+
if (window.innerWidth < 992) {
|
|
46
|
+
navEl.style.display = "none";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
2
49
|
</script>
|
|
3
50
|
|
|
4
51
|
<div class="docs-nav">
|
|
5
52
|
|
|
6
|
-
|
|
7
|
-
<
|
|
8
|
-
|
|
53
|
+
{#if active}
|
|
54
|
+
<button class="mobile hds-box" on:click={handleMobileClick}>
|
|
55
|
+
<div class="left">
|
|
56
|
+
{#if active.category}
|
|
57
|
+
<span class="category">{active.category}</span> »
|
|
58
|
+
{/if}
|
|
59
|
+
<span class="name">{active.name}</span>
|
|
60
|
+
</div>
|
|
61
|
+
<IconList size={18} />
|
|
62
|
+
</button>
|
|
63
|
+
{/if}
|
|
9
64
|
|
|
65
|
+
<nav
|
|
66
|
+
class="hds-box nav-inner"
|
|
67
|
+
bind:this={navEl}
|
|
68
|
+
use:clickOutside={{
|
|
69
|
+
callback: handleNavOutsideClick
|
|
70
|
+
}}
|
|
71
|
+
>
|
|
72
|
+
<slot />
|
|
73
|
+
</nav>
|
|
10
74
|
</div>
|
|
11
75
|
|
|
12
|
-
<style
|
|
76
|
+
<style>.docs-nav {
|
|
77
|
+
width: 220px;
|
|
78
|
+
top: var(--header-height, 0);
|
|
79
|
+
padding: 25px 0;
|
|
80
|
+
position: sticky;
|
|
81
|
+
flex-shrink: 0;
|
|
82
|
+
align-self: flex-start;
|
|
83
|
+
max-height: calc(100vh - var(--header-height));
|
|
84
|
+
}
|
|
13
85
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
flex-shrink: 0;
|
|
20
|
-
align-self: flex-start;
|
|
21
|
-
max-height: calc(100vh - var(--header-height));
|
|
22
|
-
}
|
|
86
|
+
nav {
|
|
87
|
+
padding: 15px 0;
|
|
88
|
+
overflow-y: auto;
|
|
89
|
+
max-height: calc(100vh - var(--header-height) - 50px);
|
|
90
|
+
}
|
|
23
91
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
92
|
+
.mobile {
|
|
93
|
+
display: none;
|
|
94
|
+
padding: 10px 20px;
|
|
95
|
+
cursor: pointer;
|
|
96
|
+
}
|
|
97
|
+
.mobile:hover {
|
|
98
|
+
background-color: var(--hover);
|
|
99
|
+
}
|
|
100
|
+
.mobile .left {
|
|
101
|
+
flex: 1;
|
|
102
|
+
}
|
|
29
103
|
|
|
30
|
-
|
|
104
|
+
@media (max-width: 992px) {
|
|
105
|
+
.mobile {
|
|
106
|
+
display: flex;
|
|
107
|
+
width: 100%;
|
|
108
|
+
text-align: left;
|
|
109
|
+
}
|
|
110
|
+
.nav-inner {
|
|
111
|
+
display: none;
|
|
112
|
+
}
|
|
113
|
+
.docs-nav {
|
|
114
|
+
width: 100%;
|
|
115
|
+
position: relative;
|
|
116
|
+
top: 0;
|
|
117
|
+
padding: 0 15px;
|
|
118
|
+
margin: 20px 0;
|
|
119
|
+
max-height: initial;
|
|
120
|
+
order: 1;
|
|
121
|
+
}
|
|
122
|
+
nav {
|
|
123
|
+
padding: 0;
|
|
124
|
+
max-height: initial;
|
|
125
|
+
position: absolute;
|
|
126
|
+
width: calc(100% - 30px);
|
|
127
|
+
margin-top: 10px;
|
|
128
|
+
max-height: 500px;
|
|
129
|
+
z-index: 100;
|
|
130
|
+
}
|
|
131
|
+
}</style>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Toc from "../Toc.svelte";
|
|
3
|
+
|
|
4
|
+
</script>
|
|
5
|
+
<div class="sidebar">
|
|
6
|
+
<Toc />
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
<style>
|
|
11
|
+
|
|
12
|
+
.sidebar {
|
|
13
|
+
width: 220px;
|
|
14
|
+
top: var(--header-height, 0);
|
|
15
|
+
padding: 25px 0;
|
|
16
|
+
position: sticky;
|
|
17
|
+
flex-shrink: 0;
|
|
18
|
+
align-self: flex-start;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@media (max-width: 992px) {
|
|
22
|
+
.sidebar {
|
|
23
|
+
order: 1;
|
|
24
|
+
position: relative;
|
|
25
|
+
top: initial;
|
|
26
|
+
padding: 0 15px;
|
|
27
|
+
margin-bottom: 20px;
|
|
28
|
+
width: 100%;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
</style>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} SidebarProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} SidebarEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} SidebarSlots */
|
|
4
|
+
export default class Sidebar extends SvelteComponent<{
|
|
5
|
+
[x: string]: never;
|
|
6
|
+
}, {
|
|
7
|
+
[evt: string]: CustomEvent<any>;
|
|
8
|
+
}, {}> {
|
|
9
|
+
}
|
|
10
|
+
export type SidebarProps = typeof __propDef.props;
|
|
11
|
+
export type SidebarEvents = typeof __propDef.events;
|
|
12
|
+
export type SidebarSlots = typeof __propDef.slots;
|
|
13
|
+
import { SvelteComponent } from "svelte";
|
|
14
|
+
declare const __propDef: {
|
|
15
|
+
props: {
|
|
16
|
+
[x: string]: never;
|
|
17
|
+
};
|
|
18
|
+
events: {
|
|
19
|
+
[evt: string]: CustomEvent<any>;
|
|
20
|
+
};
|
|
21
|
+
slots: {};
|
|
22
|
+
};
|
|
23
|
+
export {};
|
|
@@ -1,23 +1,149 @@
|
|
|
1
|
-
<script>import
|
|
1
|
+
<script>import { afterNavigate } from "$app/navigation";
|
|
2
|
+
import { onMount } from "svelte";
|
|
3
|
+
import tocbot from "tocbot";
|
|
4
|
+
import Loader from "../../components/Loader/Loader.svelte";
|
|
5
|
+
import { IconCaretDown, IconCaretRight } from "@hyvor/icons";
|
|
6
|
+
import Button from "../../components/Button/Button.svelte";
|
|
7
|
+
let tocElement;
|
|
8
|
+
onMount(() => {
|
|
9
|
+
tocbot.init({
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
tocElement,
|
|
12
|
+
contentSelector: ".docs .content-wrap",
|
|
13
|
+
headingSelector: "h2, h3, h4, h5, h6",
|
|
14
|
+
orderedList: false,
|
|
15
|
+
hasInnerContainers: true,
|
|
16
|
+
headingsOffset: 75,
|
|
17
|
+
scrollSmooth: true,
|
|
18
|
+
scrollSmoothOffset: -75
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
afterNavigate(() => {
|
|
22
|
+
tocbot.refresh();
|
|
23
|
+
});
|
|
24
|
+
let mobileShown = false;
|
|
25
|
+
function handleMobileClick(e) {
|
|
26
|
+
e.stopPropagation();
|
|
27
|
+
if (!mobileShown) {
|
|
28
|
+
tocElement.style.display = "block";
|
|
29
|
+
mobileShown = true;
|
|
30
|
+
} else {
|
|
31
|
+
tocElement.style.display = "none";
|
|
32
|
+
mobileShown = false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
2
35
|
</script>
|
|
3
36
|
|
|
4
|
-
<div class="
|
|
37
|
+
<div class="wrap hds-box">
|
|
5
38
|
|
|
6
|
-
<
|
|
7
|
-
|
|
8
|
-
|
|
39
|
+
<div class="mobile">
|
|
40
|
+
<Button color="input" on:click={handleMobileClick}>
|
|
41
|
+
Table of Contents
|
|
42
|
+
<svelte:fragment slot="end">
|
|
43
|
+
{#if mobileShown}
|
|
44
|
+
<IconCaretDown size={14} />
|
|
45
|
+
{:else}
|
|
46
|
+
<IconCaretRight size={14} />
|
|
47
|
+
{/if}
|
|
48
|
+
</svelte:fragment>
|
|
49
|
+
</Button>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<div class="toc-wrap" bind:this={tocElement}>
|
|
53
|
+
<Loader block padding={30} size="small" />
|
|
54
|
+
</div>
|
|
9
55
|
|
|
10
56
|
</div>
|
|
11
57
|
|
|
12
|
-
<style
|
|
58
|
+
<style>.wrap {
|
|
59
|
+
padding: 25px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.toc-wrap {
|
|
63
|
+
align-self: flex-start;
|
|
64
|
+
overflow-y: auto;
|
|
65
|
+
}
|
|
66
|
+
.toc-wrap :global(&.toc) {
|
|
67
|
+
overflow-y: auto;
|
|
68
|
+
}
|
|
69
|
+
.toc-wrap :global(> .toc-list) {
|
|
70
|
+
overflow: hidden;
|
|
71
|
+
position: relative;
|
|
72
|
+
overflow: hidden;
|
|
73
|
+
position: relative;
|
|
74
|
+
margin: 0;
|
|
75
|
+
padding-left: 15px;
|
|
76
|
+
}
|
|
77
|
+
.toc-wrap :global(> .toc-list) :global(li) {
|
|
78
|
+
list-style: none;
|
|
79
|
+
}
|
|
80
|
+
.toc-wrap :global(.js-toc) {
|
|
81
|
+
overflow-y: hidden;
|
|
82
|
+
}
|
|
83
|
+
.toc-wrap :global(.toc-list) {
|
|
84
|
+
margin: 0;
|
|
85
|
+
padding-left: 15px;
|
|
86
|
+
}
|
|
87
|
+
.toc-wrap :global(.toc-list) :global(li) {
|
|
88
|
+
list-style: none;
|
|
89
|
+
}
|
|
90
|
+
.toc-wrap :global(a.toc-link) {
|
|
91
|
+
color: currentColor;
|
|
92
|
+
height: 100%;
|
|
93
|
+
display: inline-block;
|
|
94
|
+
padding: 3px 0;
|
|
95
|
+
}
|
|
96
|
+
.toc-wrap :global(a.toc-link):hover {
|
|
97
|
+
text-decoration: underline;
|
|
98
|
+
}
|
|
99
|
+
.toc-wrap :global(.is-collapsible) {
|
|
100
|
+
max-height: 1000px;
|
|
101
|
+
overflow: hidden;
|
|
102
|
+
transition: all 300ms ease-in-out;
|
|
103
|
+
}
|
|
104
|
+
.toc-wrap :global(.is-collapsed) {
|
|
105
|
+
max-height: 0;
|
|
106
|
+
}
|
|
107
|
+
.toc-wrap :global(.is-position-fixed) {
|
|
108
|
+
position: fixed !important;
|
|
109
|
+
top: 0;
|
|
110
|
+
}
|
|
111
|
+
.toc-wrap :global(.is-active-link) {
|
|
112
|
+
font-weight: 700;
|
|
113
|
+
}
|
|
114
|
+
.toc-wrap :global(.toc-link::before) {
|
|
115
|
+
background-color: #EEE;
|
|
116
|
+
content: " ";
|
|
117
|
+
display: inline-block;
|
|
118
|
+
height: inherit;
|
|
119
|
+
left: 0;
|
|
120
|
+
margin-top: -1px;
|
|
121
|
+
position: absolute;
|
|
122
|
+
width: 2px;
|
|
123
|
+
}
|
|
124
|
+
.toc-wrap :global(.is-active-link::before) {
|
|
125
|
+
background-color: var(--accent);
|
|
126
|
+
}
|
|
13
127
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
padding: 25px 0;
|
|
18
|
-
position: sticky;
|
|
19
|
-
flex-shrink: 0;
|
|
20
|
-
align-self: flex-start;
|
|
21
|
-
}
|
|
128
|
+
.mobile {
|
|
129
|
+
display: none;
|
|
130
|
+
}
|
|
22
131
|
|
|
23
|
-
|
|
132
|
+
@media (max-width: 992px) {
|
|
133
|
+
.wrap {
|
|
134
|
+
padding: 10px 15px;
|
|
135
|
+
}
|
|
136
|
+
.mobile {
|
|
137
|
+
display: block;
|
|
138
|
+
}
|
|
139
|
+
.toc-wrap {
|
|
140
|
+
display: none;
|
|
141
|
+
margin-top: 15px;
|
|
142
|
+
}
|
|
143
|
+
:global(.is-active-link) {
|
|
144
|
+
font-weight: normal !important;
|
|
145
|
+
}
|
|
146
|
+
:global(.is-active-link::before) {
|
|
147
|
+
background-color: #eee !important;
|
|
148
|
+
}
|
|
149
|
+
}</style>
|
|
@@ -195,4 +195,12 @@ header :global(nav) {
|
|
|
195
195
|
|
|
196
196
|
.mobile-content :global(.button) {
|
|
197
197
|
display: flex;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/*
|
|
201
|
+
Scroll padding top is used to prevent the content from being hidden behind the header
|
|
202
|
+
https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-padding-top
|
|
203
|
+
*/
|
|
204
|
+
:global(html) {
|
|
205
|
+
scroll-padding-top: calc(var(--header-height) + 20px);
|
|
198
206
|
}</style>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyvor/design",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.53",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"private": false,
|
|
6
6
|
"scripts": {
|
|
@@ -46,8 +46,13 @@
|
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@fontsource/readex-pro": "^5.0.8",
|
|
48
48
|
"@hyvor/icons": "^0.0.3",
|
|
49
|
+
"deepmerge-ts": "^5.1.0",
|
|
49
50
|
"highlight.js": "^11.9.0",
|
|
50
|
-
"
|
|
51
|
+
"i": "^0.3.7",
|
|
52
|
+
"intl-messageformat": "^10.5.11",
|
|
53
|
+
"npm": "^10.4.0",
|
|
54
|
+
"svelte-awesome-color-picker": "^3.0.4",
|
|
55
|
+
"tocbot": "^4.25.0"
|
|
51
56
|
},
|
|
52
57
|
"type": "module",
|
|
53
58
|
"publishConfig": {
|