@master/internal-site 0.1.0 → 0.1.2
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 +13 -0
- package/dist/config.d.mts +5 -0
- package/package.json +1 -1
- package/src/config.ts +2 -0
- package/src/docs-shell/components/DocHeader.svelte +13 -7
- package/src/docs-shell/components/DocMenuButton.svelte +1 -0
- package/src/docs-shell/components/Footer.svelte +2 -2
- package/src/docs-shell/components/FooterLink.svelte +17 -0
- package/src/docs-shell/components/HeaderNav.svelte +2 -0
- package/src/home/HomeFooter.svelte +2 -2
- package/src/home/home.css +5 -1
- package/src/styles/docs-shell/docs.css +3 -3
- package/src/styles/docs-shell/footer-link.css +5 -0
- package/src/styles/docs-shell/header.css +4 -0
package/README.md
CHANGED
|
@@ -23,6 +23,8 @@ export default defineConfig({ integrations: [masterSite(site)] })
|
|
|
23
23
|
|
|
24
24
|
`site.config.ts` exports `defineSite(...)` from `@master/internal-site/config`. It declares the site's origin, content directory, app module, locale policy and section module URLs. Optional document layouts, category sources, styles and a server-only highlighter are also URLs. Keep route content lazy: do not import a complete page or specimen catalog into the configuration.
|
|
25
25
|
|
|
26
|
+
Optional `header.communityNavs` selects the links shown beside search without removing community links from the compact menu or footer. Set `header.searchOnHome` to show search in the desktop homepage header. When available, the language switch follows the community links and a divider.
|
|
27
|
+
|
|
26
28
|
The app module exports its logo component, navigation, version links and source/feedback URLs using the `SiteApp` contract. Consumers retain their own content and homepage composition. Ordinary documents use `content/<section>/<slug>/content.mdx` and `metadata.ts`; a local `page.astro` can override the generated entry. Dynamic routes enumerate params from lightweight `params.ts` files. The integration owns generated routes, page asset collection and the Astro/Svelte renderer setup.
|
|
27
29
|
|
|
28
30
|
```css
|
|
@@ -65,3 +67,14 @@ The CSS-specific subpaths require the matching optional compiler, tooling, schem
|
|
|
65
67
|
From the Master repository, run `bun run build:packages`, `bun run --cwd packages/internal-site type-check` and `bun run --cwd packages/internal-site test`. Astro checks `.astro` implementations and Svelte checks interactive components separately. The root `build` builds the Node entrypoints before the site.
|
|
66
68
|
|
|
67
69
|
Before publishing, inspect the tarball, install it in the Master CSS consumer and validate both sites, including local CSS imports, themes, mobile navigation and lazy page styles. Publish an immutable version, update exact consumer pins and lockfiles, then deploy preview builds. Roll back by restoring the previous dependency version and deployment; do not unpublish a release in use.
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
## Publishing
|
|
73
|
+
|
|
74
|
+
Master's `publish.yml` workflow validates the site and packages, retains the
|
|
75
|
+
packed archives, then publishes those exact bytes through npm Trusted Publishing.
|
|
76
|
+
The trusted publisher is GitHub repository `master-co/master`, workflow
|
|
77
|
+
`publish.yml`, with no GitHub environment. Versions are committed before dispatch;
|
|
78
|
+
consumers upgrade exact pins after registry integrity verification. No npm token
|
|
79
|
+
is stored in GitHub. Master remains private, so these releases use OIDC
|
|
80
|
+
without public provenance attestations.
|
package/dist/config.d.mts
CHANGED
|
@@ -13,6 +13,11 @@ export interface SiteApp {
|
|
|
13
13
|
Logotype: Component<any>;
|
|
14
14
|
navs: AppNavItem[];
|
|
15
15
|
communityNavs?: AppNavItem[];
|
|
16
|
+
/** Header controls can be quieter than the full community menu and footer. */
|
|
17
|
+
header?: {
|
|
18
|
+
communityNavs?: AppNavItem[];
|
|
19
|
+
searchOnHome?: boolean;
|
|
20
|
+
};
|
|
16
21
|
sourceBaseURL?: string;
|
|
17
22
|
feedbackURL?: string;
|
|
18
23
|
versions: {
|
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -15,6 +15,8 @@ export interface SiteApp {
|
|
|
15
15
|
Logotype: Component<any>
|
|
16
16
|
navs: AppNavItem[]
|
|
17
17
|
communityNavs?: AppNavItem[]
|
|
18
|
+
/** Header controls can be quieter than the full community menu and footer. */
|
|
19
|
+
header?: { communityNavs?: AppNavItem[], searchOnHome?: boolean }
|
|
18
20
|
sourceBaseURL?: string
|
|
19
21
|
feedbackURL?: string
|
|
20
22
|
versions: { name: string, href: string }[]
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
import HeaderNav from './HeaderNav.svelte'
|
|
22
22
|
import LanguageButton from './LanguageButton.svelte'
|
|
23
23
|
import IconChevronDown from '@tabler/icons-svelte-runes/icons/chevron-down'
|
|
24
|
+
import IconArrowUpRight from '@tabler/icons-svelte-runes/icons/arrow-up-right'
|
|
24
25
|
import IconSearch from '@tabler/icons-svelte-runes/icons/search'
|
|
25
26
|
import DocVersionSelect from './DocVersionSelect.svelte'
|
|
26
27
|
import Link from './Link.svelte'
|
|
@@ -31,9 +32,11 @@
|
|
|
31
32
|
import { getSite } from '../site'
|
|
32
33
|
|
|
33
34
|
let { class: className, stickable, transitionAtTop, documentNavigation, documentNavigationTitle }: DocHeaderProps = $props()
|
|
34
|
-
const { t, locale, pathname } = getSite()
|
|
35
|
+
const { t, locale, pathname, i18n } = getSite()
|
|
35
36
|
const tw = locale === 'tw'
|
|
36
37
|
const home = pathname === (tw ? '/tw' : '/')
|
|
38
|
+
const headerCommunityNavs = app.header?.communityNavs ?? app.communityNavs ?? []
|
|
39
|
+
const showLanguage = i18n.locales.length > 1
|
|
37
40
|
const version = import.meta.env.PUBLIC_VERSION ? `v${import.meta.env.PUBLIC_VERSION}` : ''
|
|
38
41
|
</script>
|
|
39
42
|
|
|
@@ -60,13 +63,13 @@
|
|
|
60
63
|
{#if eachLink.date && isDateWithinSevenDays(eachLink.date)}<small>{t('New')}</small>{/if}
|
|
61
64
|
</HeaderNav>{/each}
|
|
62
65
|
</nav>
|
|
63
|
-
<div class="ui-header-end">
|
|
64
|
-
<!-- Search leads the end group as a quiet pill: the glass and its shortcut.
|
|
65
|
-
<SearchButton class="ui-header-search" data-compact={home ? '' : undefined}>
|
|
66
|
+
<div class="ui-header-end" data-home-controls={app.header?.searchOnHome ? 'full' : undefined}>
|
|
67
|
+
<!-- Search leads the end group as a quiet pill: the glass and its shortcut. Homepages may opt into the same desktop search control. -->
|
|
68
|
+
<SearchButton class="ui-header-search" data-compact={home && !app.header?.searchOnHome ? '' : undefined}>
|
|
66
69
|
<IconSearch size={16} stroke={1.5} aria-hidden="true" />
|
|
67
70
|
<kbd class="ui-kbd" aria-hidden="true">⌘K</kbd>
|
|
68
71
|
</SearchButton>
|
|
69
|
-
{#each
|
|
72
|
+
{#each headerCommunityNavs as { Icon, disabled, fullName, ...eachLink } (eachLink.name)}
|
|
70
73
|
<Link
|
|
71
74
|
{...eachLink}
|
|
72
75
|
aria-label={fullName || eachLink.name}
|
|
@@ -78,10 +81,13 @@
|
|
|
78
81
|
{disabled}
|
|
79
82
|
>
|
|
80
83
|
{#if Icon}<Icon size={18} stroke={1.5} aria-hidden="true" />{/if}
|
|
84
|
+
{#if eachLink.href?.startsWith('http')}<IconArrowUpRight class="ui-header-external" size={10} stroke={1.5} aria-hidden="true" />{/if}
|
|
81
85
|
<span class="ui-tooltip" data-side="bottom" aria-hidden="true">{fullName || eachLink.name}</span>
|
|
82
86
|
</Link>
|
|
83
87
|
{/each}
|
|
84
|
-
{#if
|
|
85
|
-
|
|
88
|
+
{#if showLanguage}
|
|
89
|
+
{#if headerCommunityNavs.length}<span class="ui-header-divider" aria-hidden="true"></span>{/if}
|
|
90
|
+
<LanguageButton />
|
|
91
|
+
{/if}
|
|
86
92
|
</div>
|
|
87
93
|
</Header>
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
<nav class="ui-nav-group" aria-label={tw ? '主要導覽' : 'Main navigation'}>
|
|
73
73
|
{#each app.navs as { Icon, disabled, fullName, ...link } (link.name)}<Link class="ui-nav-link" current="true" ambiguous {...link} {disabled} onclick={close}>
|
|
74
74
|
{#if Icon}<Icon size={18} stroke={1.5} aria-hidden="true" />{/if}{t(fullName || link.name)}
|
|
75
|
+
{#if link.href?.startsWith('http')}<IconArrowUpRight size={14} stroke={1.5} aria-hidden="true" />{/if}
|
|
75
76
|
</Link>{/each}
|
|
76
77
|
</nav>
|
|
77
78
|
{#if documentNavigation?.length}<details class="ui-disclosure" data-variant="rule" open>
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
<script lang="ts">
|
|
24
24
|
import '../../styles/docs-shell/footer.css'
|
|
25
25
|
import clsx from 'clsx'
|
|
26
|
-
import
|
|
26
|
+
import FooterNavLink from './FooterLink.svelte'
|
|
27
27
|
import LanguageSelect from './LanguageSelect.svelte'
|
|
28
28
|
import ThemeSelect from './ThemeSelect.svelte'
|
|
29
29
|
import { useThemeMode } from '../contexts/theme-mode.svelte'
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
<ul>
|
|
54
54
|
{#each group.links as link (link.href || link.name)}
|
|
55
55
|
<li>
|
|
56
|
-
<
|
|
56
|
+
<FooterNavLink href={link.href} disabled={link.disabled}>{t(link.name)}</FooterNavLink>
|
|
57
57
|
</li>
|
|
58
58
|
{/each}
|
|
59
59
|
</ul>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte'
|
|
3
|
+
import IconArrowUpRight from '@tabler/icons-svelte-runes/icons/arrow-up-right'
|
|
4
|
+
import Link from './Link.svelte'
|
|
5
|
+
import '../../styles/docs-shell/footer-link.css'
|
|
6
|
+
|
|
7
|
+
let { href, disabled, class: className, children }: {
|
|
8
|
+
href?: string
|
|
9
|
+
disabled?: boolean
|
|
10
|
+
class?: string
|
|
11
|
+
children?: Snippet
|
|
12
|
+
} = $props()
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<Link {href} {disabled} class={className}>
|
|
16
|
+
<span>{@render children?.()}{#if href?.startsWith('http') && !disabled}<span class="ui-footer-link-mark" aria-hidden="true"><IconArrowUpRight size={10} stroke={1.5} /></span>{/if}</span>
|
|
17
|
+
</Link>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte'
|
|
3
|
+
import IconArrowUpRight from '@tabler/icons-svelte-runes/icons/arrow-up-right'
|
|
3
4
|
import Link from './Link.svelte'
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
@@ -15,4 +16,5 @@
|
|
|
15
16
|
|
|
16
17
|
<Link {...props} current="true" ambiguous>
|
|
17
18
|
{@render children?.()}
|
|
19
|
+
{#if props.href?.startsWith('http')}<IconArrowUpRight class="ui-header-external" size={10} stroke={1.5} aria-hidden="true" />{/if}
|
|
18
20
|
</Link>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import IconMoon from '@tabler/icons-svelte-runes/icons/moon'
|
|
7
7
|
import IconSun from '@tabler/icons-svelte-runes/icons/sun'
|
|
8
8
|
import LanguageSelect from '@master/internal-site/components/LanguageSelect.svelte'
|
|
9
|
-
import
|
|
9
|
+
import FooterNavLink from '../docs-shell/components/FooterLink.svelte'
|
|
10
10
|
import ThemeSelect from '@master/internal-site/components/ThemeSelect.svelte'
|
|
11
11
|
import { useThemeMode } from '@master/internal-site/contexts/theme-mode.svelte'
|
|
12
12
|
import { getSite } from '@master/internal-site/site'
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<ul class="home-footer-links">
|
|
33
33
|
{#each group.links as link (link.href)}
|
|
34
34
|
<li>
|
|
35
|
-
<
|
|
35
|
+
<FooterNavLink class="home-footer-link" href={link.href} disabled={link.disabled}>{t(link.name)}</FooterNavLink>
|
|
36
36
|
</li>
|
|
37
37
|
{/each}
|
|
38
38
|
</ul>
|
package/src/home/home.css
CHANGED
|
@@ -81,10 +81,14 @@
|
|
|
81
81
|
max-width: 95rem;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
.home-header[data-background="transparent"] :is(.ui-header-nav, .ui-header-end > :not(a[aria-label="GitHub"])) {
|
|
84
|
+
.home-header[data-background="transparent"] :is(.ui-header-nav, .ui-header-end:not([data-home-controls="full"]) > :not(a[aria-label="GitHub"])) {
|
|
85
85
|
display: none;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
@media (width < 64rem) {
|
|
89
|
+
.home-header[data-background="transparent"] .ui-header-end > :not(a[aria-label="GitHub"]) { display: none; }
|
|
90
|
+
}
|
|
91
|
+
|
|
88
92
|
/* The compact header keeps the brand centred: GitHub takes the search button's end, as wide as the menu button. */
|
|
89
93
|
.home-header[data-background="transparent"] .ui-header-end {
|
|
90
94
|
justify-content: flex-end;
|
|
@@ -62,12 +62,12 @@
|
|
|
62
62
|
.ui-pager > a { min-width: 0; overflow-wrap: anywhere; }
|
|
63
63
|
|
|
64
64
|
/* The contents rail stands still beside the article; a long list scrolls inside it. */
|
|
65
|
-
:is(.ui-docs-body > .ui-toc, .ui-docs-body >
|
|
65
|
+
:is(.ui-docs-body > .ui-toc, .ui-docs-body > astro-island > .ui-toc) {
|
|
66
66
|
position: sticky; top: var(--docs-header); display: flex; flex: none; flex-direction: column; align-self: start; width: var(--docs-rail); max-height: calc(100dvh - var(--docs-header));
|
|
67
67
|
padding: 3.5rem var(--ui-space-lg) var(--ui-space-xl) 0;
|
|
68
68
|
}
|
|
69
|
-
:is(.ui-docs-body > .ui-toc, .ui-docs-body >
|
|
70
|
-
@media (width < 80rem) { :is(.ui-docs-body > .ui-toc, .ui-docs-body >
|
|
69
|
+
:is(.ui-docs-body > .ui-toc, .ui-docs-body > astro-island > .ui-toc) > ol { flex: 0 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: none; }
|
|
70
|
+
@media (width < 80rem) { :is(.ui-docs-body > .ui-toc, .ui-docs-body > astro-island > .ui-toc) { display: none; } }
|
|
71
71
|
@container docs-main (width < 48rem) { .ui-toc[data-rail] { display: none; } }
|
|
72
72
|
|
|
73
73
|
@media print {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
/* Keep the raised mark with its text inside both inline and flex footer links. */
|
|
3
|
+
.ui-footer-link-mark { display: inline-block; width: .625rem; height: .625rem; margin-inline-start: .1875rem; vertical-align: .25em; line-height: 0; }
|
|
4
|
+
.ui-footer-link-mark > svg { display: block; width: 100%; height: 100%; }
|
|
5
|
+
}
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
.ui-header .ui-version > svg { width: 12px; height: 12px; color: var(--ui-text-muted); }
|
|
23
23
|
.ui-header .ui-version:hover { color: var(--ui-text-strong); }
|
|
24
24
|
.ui-header-nav > a > .ui-badge { margin-left: var(--ui-space-2xs); }
|
|
25
|
+
/* External destinations carry a small raised arrow beside the label or icon. */
|
|
26
|
+
.ui-header-nav > a:has(.ui-header-external) { position: relative; padding-right: 1.125rem; }
|
|
27
|
+
.ui-header-nav > a > .ui-header-external, .ui-header-end > .ui-button > .ui-header-external { position: absolute; top: .375rem; right: .125rem; width: .625rem; height: .625rem; pointer-events: none; }
|
|
28
|
+
.ui-header-end > .ui-button > .ui-header-external { top: .125rem; right: 0; }
|
|
25
29
|
.ui-header-end > .ui-button[data-disabled] { color: var(--ui-text-disabled); pointer-events: none; }
|
|
26
30
|
/* The community and preference icons are words in the bar, not buttons: ink under the pointer, no material. */
|
|
27
31
|
.ui-header-end > .ui-button[data-shape="icon"] { width: 2.25rem; min-height: 2.25rem; }
|