@master/internal-site 0.1.0 → 0.1.1

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 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
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@master/internal-site",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "description": "First-party Astro and Svelte website framework for Master sites.",
6
6
  "engines": {
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. The homepage leaves it to the compact header. -->
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 app.communityNavs ?? [] as { Icon, disabled, fullName, ...eachLink } (eachLink.name)}
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 app.communityNavs?.length}<span class="ui-header-divider" aria-hidden="true"></span>{/if}
85
- <LanguageButton />
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>
@@ -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>
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 > site-island > .ui-toc) {
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 > site-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 > site-island > .ui-toc) { display: none; } }
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 {
@@ -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; }