fake.modules transposition for aspect-oriented Dendritic Nix. with cross-aspect dependencies. Discussions: https://oeiuwq.zulipchat.com/join/nqp26cd4kngon6mo3ncgnuap/
dendrix.oeiuwq.com/Dendritic.html
dendritic
nix
aspect
oriented
1---
2import MobileMenuFooter from '@astrojs/starlight/components/MobileMenuFooter.astro';
3import SidebarPersister from '@astrojs/starlight/components/SidebarPersister.astro';
4import SidebarSublist from '@astrojs/starlight/components/SidebarSublist.astro';
5
6const { sidebar, id } = Astro.locals.starlightRoute;
7
8import { Icon } from '@astrojs/starlight/components';
9
10import TabbedContent from './tabs/TabbedContent.astro';
11import TabListItem from './tabs/TabListItem.astro';
12import TabPanel from './tabs/TabPanel.astro';
13
14/** Get the icon for a group. Update the icon names in the array to change the icons associated with a group. */
15const getIcon = (index: number) =>
16 (['nix', 'open-book', 'rocket', 'puzzle', 'information', 'setting'] as const)[index];
17
18/** Convert a group label to an `id` we can use to identify tab panels. */
19// The id is prefixed to avoid clashing with existing heading IDs on the page.
20const makeId = (label: string) => '__tab-' + label.toLowerCase().replaceAll(/\s+/g, '-');
21
22/** Determine if an array of sidebar items contains the current page. */
23const isCurrent = (sidebar: SidebarEntry[]): boolean =>
24 sidebar
25 .map((entry) => (entry.type === 'link' ? entry.isCurrent : isCurrent(entry.entries)))
26 .some((entry) => entry === true);
27
28---
29<SidebarPersister>
30 <TabbedContent class="tabbed-sidebar">
31 <Fragment slot="tab-list">
32 {
33 sidebar.map(({ label, entries }, index) => (
34 <TabListItem id={makeId(label)} initial={isCurrent(entries)} class="tab-item">
35 <Icon class="icon" name={getIcon(index)} /> {label}
36 </TabListItem>
37 ))
38 }
39 </Fragment>
40 {
41 sidebar.map(({ label, entries }) => (
42 <TabPanel id={makeId(label)} initial={isCurrent(entries)}>
43 <SidebarSublist sublist={entries} />
44 </TabPanel>
45 ))
46 }
47 </TabbedContent>
48</SidebarPersister>
49
50<div class="md:sl-hidden">
51 <MobileMenuFooter />
52</div>
53
54<style>
55 /** Add "EN" to the end of sidebar items with the `fallback` class. */
56 :global(.fallback)::after {
57 content: 'EN';
58 vertical-align: super;
59 font-size: 0.75em;
60 font-weight: 700;
61 }
62
63 /** Align sponsors at sidebar bottom when there is room. */
64 .desktop-footer {
65 margin-top: auto;
66 }
67
68 /** Always show the scrollbar gutter. */
69 :global(.sidebar-pane) {
70 overflow-y: scroll;
71 }
72
73 /* Styles for the custom tab switcher. */
74 .tabbed-sidebar {
75 /* Layout variables */
76 --tab-switcher-border-width: 1px;
77 --tab-switcher-padding: calc(0.25rem - var(--tab-switcher-border-width));
78 --tab-item-border-radius: 0.5rem;
79 --tab-switcher-border-radius: calc(
80 var(--tab-item-border-radius) + var(--tab-switcher-padding) + var(--tab-switcher-border-width)
81 );
82
83 /* Color variables */
84 --tab-switcher-border-color: var(--sl-color-hairline-light);
85 --tab-switcher-background-color: var(--sl-color-gray-7, var(--sl-color-gray-6));
86 --tab-switcher-text-color: var(--sl-color-gray-3);
87 --tab-switcher-text-color--active: var(--sl-color-white);
88 --tab-switcher-icon-color: var(--sl-color-gray-4);
89 --tab-switcher-icon-color--active: var(--sl-color-text-accent);
90 --tab-item-background-color--hover: var(--sl-color-gray-6);
91 --tab-item-background-color--active: var(--sl-color-black);
92 }
93 /* Dark theme variations */
94 :global([data-theme='dark']) .tabbed-sidebar {
95 --tab-switcher-text-color: var(--sl-color-gray-2);
96 --tab-switcher-icon-color: var(--sl-color-gray-3);
97 --tab-item-background-color--hover: var(--sl-color-gray-5);
98 }
99
100 @media (min-width: 50rem) {
101 /* Dark theme variations with the desktop sidebar visible */
102 :global([data-theme='dark']) .tabbed-sidebar {
103 --tab-switcher-background-color: var(--sl-color-black);
104 --tab-item-background-color--hover: var(--sl-color-gray-6);
105 --tab-item-background-color--active: var(--sl-color-gray-6);
106 }
107 }
108
109 .tabbed-sidebar.tab-list {
110 border: var(--tab-switcher-border-width) solid var(--tab-switcher-border-color);
111 border-radius: var(--tab-switcher-border-radius);
112 display: flex;
113 flex-direction: column;
114 gap: 0.25rem;
115 padding: var(--tab-switcher-padding);
116 background-color: var(--tab-switcher-background-color);
117 margin-bottom: 1.5rem;
118 }
119
120 .tab-item :global(a) {
121 border: var(--tab-switcher-border-width) solid transparent;
122 border-radius: var(--tab-item-border-radius);
123 display: flex;
124 align-items: center;
125 gap: 0.5rem;
126 padding: calc(0.5rem - var(--tab-switcher-border-width));
127 background-clip: padding-box;
128 line-height: var(--sl-line-height-headings);
129 text-decoration: none;
130 color: var(--tab-switcher-text-color);
131 font-weight: 600;
132 }
133
134 .tab-item :global(a:hover) {
135 color: var(--tab-switcher-text-color--active);
136 background-color: var(--tab-item-background-color--hover);
137 }
138 .tab-item :global(a[aria-selected='true']) {
139 border-color: var(--tab-switcher-border-color);
140 color: var(--tab-switcher-text-color--active);
141 background-color: var(--tab-item-background-color--active);
142 }
143
144 .icon {
145 margin: 0.25rem;
146 color: var(--tab-switcher-icon-color);
147 }
148 .tab-item :global(a:hover) .icon {
149 color: inherit;
150 }
151 .tab-item :global(a[aria-selected='true']) .icon {
152 color: var(--tab-switcher-icon-color--active);
153 }
154</style>