@nubisco/docs-sdk 0.0.0-stage → 0.0.0
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/LICENSE +20 -0
- package/README.md +101 -2
- package/THIRD_PARTY_NOTICES.md +100 -0
- package/dist/cli.js +33 -0
- package/dist/index.d.ts +78 -0
- package/dist/index.js +361 -0
- package/package.json +122 -4
- package/src/plugins/mermaid/Mermaid.vue +93 -0
- package/src/plugins/mermaid/index.ts +66 -0
- package/src/plugins/mermaid/mermaid-markdown.ts +34 -0
- package/src/plugins/mermaid/mermaid-plugin.ts +46 -0
- package/src/plugins/mermaid/mermaid.ts +21 -0
- package/src/plugins/tabs/components/ContentTab.vue +41 -0
- package/src/plugins/tabs/components/ContentTabs.vue +150 -0
- package/src/plugins/tabs/components/index.ts +10 -0
- package/src/plugins/tabs/components/useStabilizeScrollPosition.ts +36 -0
- package/src/plugins/tabs/components/useTabLabels.ts +18 -0
- package/src/plugins/tabs/components/useTabsSelectedState.ts +95 -0
- package/src/plugins/tabs/components/useTabsSingleState.ts +22 -0
- package/src/plugins/tabs/index.ts +1 -0
- package/src/plugins/tabs/markdown/index.ts +1 -0
- package/src/plugins/tabs/markdown/markdownPlugin.ts +47 -0
- package/src/plugins/tabs/markdown/ruleBlockTab.ts +97 -0
- package/src/theme/Layout.vue +32 -0
- package/src/theme/Nubisco.vue +480 -0
- package/src/theme/components/DocHeader.vue +599 -0
- package/src/theme/components/DocOutline.vue +235 -0
- package/src/theme/components/DocsControls.vue +173 -0
- package/src/theme/components/DocsSidebarNav.vue +313 -0
- package/src/theme/custom.css +591 -0
- package/src/theme/index.ts +33 -0
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="nb-layout">
|
|
3
|
+
<DocHeader
|
|
4
|
+
:title="frontmatter.title"
|
|
5
|
+
:intro="frontmatter.intro"
|
|
6
|
+
:status="frontmatter.status"
|
|
7
|
+
:source="frontmatter.source"
|
|
8
|
+
:edit-link="editLink"
|
|
9
|
+
:tabs="headerTabs"
|
|
10
|
+
@select="activeTab = $event"
|
|
11
|
+
/>
|
|
12
|
+
|
|
13
|
+
<div class="nb-layout__main">
|
|
14
|
+
<main ref="body" class="nb-layout__body">
|
|
15
|
+
<Content />
|
|
16
|
+
</main>
|
|
17
|
+
<aside class="nb-layout__aside">
|
|
18
|
+
<div class="nb-layout__aside-inner">
|
|
19
|
+
<DocOutline :root="body" :watch-key="activeTab" />
|
|
20
|
+
</div>
|
|
21
|
+
</aside>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<!-- Footer: prev/next navigation + meta -->
|
|
25
|
+
<footer class="nb-layout__footer">
|
|
26
|
+
<nav v-if="prev || next" class="nb-footer__nav">
|
|
27
|
+
<a
|
|
28
|
+
v-if="prev"
|
|
29
|
+
:href="withBase(prev.link)"
|
|
30
|
+
class="nb-footer__nav-item nb-footer__nav-item--prev"
|
|
31
|
+
>
|
|
32
|
+
<span class="nb-footer__nav-label">Previous</span>
|
|
33
|
+
<span class="nb-footer__nav-title">{{ prev.text }}</span>
|
|
34
|
+
</a>
|
|
35
|
+
<span v-else class="nb-footer__nav-spacer" />
|
|
36
|
+
|
|
37
|
+
<a
|
|
38
|
+
v-if="next"
|
|
39
|
+
:href="withBase(next.link)"
|
|
40
|
+
class="nb-footer__nav-item nb-footer__nav-item--next"
|
|
41
|
+
>
|
|
42
|
+
<span class="nb-footer__nav-label">Next</span>
|
|
43
|
+
<span class="nb-footer__nav-title">{{ next.text }}</span>
|
|
44
|
+
</a>
|
|
45
|
+
<span v-else class="nb-footer__nav-spacer" />
|
|
46
|
+
</nav>
|
|
47
|
+
|
|
48
|
+
<div class="nb-footer__bar">
|
|
49
|
+
<a :href="withBase('/')" class="nb-footer__brand">
|
|
50
|
+
<NbNubiscoMark :size="24" class="nb-footer__logo" />
|
|
51
|
+
<span class="nb-footer__brand-name">Nubisco</span>
|
|
52
|
+
</a>
|
|
53
|
+
|
|
54
|
+
<div class="nb-footer__meta">
|
|
55
|
+
<a
|
|
56
|
+
v-if="editLink"
|
|
57
|
+
:href="editLink"
|
|
58
|
+
target="_blank"
|
|
59
|
+
rel="noreferrer"
|
|
60
|
+
class="nb-footer__edit-link"
|
|
61
|
+
>
|
|
62
|
+
Edit this page on GitHub
|
|
63
|
+
</a>
|
|
64
|
+
<!-- eslint-disable vue/no-v-html -->
|
|
65
|
+
<span
|
|
66
|
+
v-if="theme.footer?.copyright"
|
|
67
|
+
class="nb-footer__copyright"
|
|
68
|
+
v-html="theme.footer.copyright"
|
|
69
|
+
/>
|
|
70
|
+
<span v-else class="nb-footer__copyright">
|
|
71
|
+
Copyright © Nubisco
|
|
72
|
+
</span>
|
|
73
|
+
<span
|
|
74
|
+
v-if="theme.footer?.message"
|
|
75
|
+
class="nb-footer__copyright"
|
|
76
|
+
v-html="theme.footer.message"
|
|
77
|
+
/>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</footer>
|
|
81
|
+
</div>
|
|
82
|
+
</template>
|
|
83
|
+
|
|
84
|
+
<script lang="ts" setup>
|
|
85
|
+
import { ref, computed, provide, watch } from 'vue'
|
|
86
|
+
import { useData, withBase } from 'vitepress'
|
|
87
|
+
import DocHeader from './components/DocHeader.vue'
|
|
88
|
+
import type { IDocHeaderTab } from './components/DocHeader.vue'
|
|
89
|
+
import DocOutline from './components/DocOutline.vue'
|
|
90
|
+
import { NbNubiscoMark } from '@nubisco/ui'
|
|
91
|
+
|
|
92
|
+
const { frontmatter, page, theme, site } = useData()
|
|
93
|
+
const body = ref<HTMLElement | null>(null)
|
|
94
|
+
|
|
95
|
+
/*
|
|
96
|
+
* Two kinds of tab.
|
|
97
|
+
*
|
|
98
|
+
* A component page is split into one route per tab (`/components/x/usage`,
|
|
99
|
+
* `/code`, ...), and lists its siblings in `pageTabs`. Those tabs are links.
|
|
100
|
+
*
|
|
101
|
+
* A few other pages still switch sections in place, with `<doc-tab>` blocks
|
|
102
|
+
* named in `tabs`. Those tabs are buttons, and the active one is provided to
|
|
103
|
+
* the blocks below.
|
|
104
|
+
*/
|
|
105
|
+
const TAB_LABEL: Record<string, string> = {
|
|
106
|
+
usage: 'Usage',
|
|
107
|
+
style: 'Style',
|
|
108
|
+
code: 'Code',
|
|
109
|
+
accessibility: 'Accessibility',
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const inPageTabs = computed<string[]>(() =>
|
|
113
|
+
frontmatter.value.pageTabs ? [] : (frontmatter.value.tabs ?? []),
|
|
114
|
+
)
|
|
115
|
+
const activeTab = ref<string>(inPageTabs.value[0] ?? '')
|
|
116
|
+
|
|
117
|
+
watch(inPageTabs, (next) => {
|
|
118
|
+
activeTab.value = next[0] ?? ''
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
provide('nb-active-tab', activeTab)
|
|
122
|
+
|
|
123
|
+
/** The page's folder, for a page split into tab routes. */
|
|
124
|
+
const tabDir = computed(() =>
|
|
125
|
+
frontmatter.value.pageTabs
|
|
126
|
+
? '/' + page.value.relativePath.replace(/\/[^/]+\.md$/, '')
|
|
127
|
+
: null,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
const headerTabs = computed<IDocHeaderTab[]>(() => {
|
|
131
|
+
const routeTabs: string[] = frontmatter.value.pageTabs ?? []
|
|
132
|
+
if (routeTabs.length) {
|
|
133
|
+
const ext = site.value.cleanUrls ? '' : '.html'
|
|
134
|
+
return routeTabs.map((key) => ({
|
|
135
|
+
key,
|
|
136
|
+
label: TAB_LABEL[key] ?? key,
|
|
137
|
+
href: withBase(`${tabDir.value}/${key}${ext}`),
|
|
138
|
+
active: key === frontmatter.value.tab,
|
|
139
|
+
}))
|
|
140
|
+
}
|
|
141
|
+
return inPageTabs.value.map((key) => ({
|
|
142
|
+
key,
|
|
143
|
+
label: key === 'Api' ? 'API' : key,
|
|
144
|
+
active: key === activeTab.value,
|
|
145
|
+
}))
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
// ── Footer: sidebar navigation ───────────────────────────────────────────
|
|
149
|
+
interface SidebarLink {
|
|
150
|
+
text: string
|
|
151
|
+
link: string
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function flattenSidebar(items: any[]): SidebarLink[] {
|
|
155
|
+
const result: SidebarLink[] = []
|
|
156
|
+
for (const item of items) {
|
|
157
|
+
if (item.link) result.push({ text: item.text ?? '', link: item.link })
|
|
158
|
+
if (item.items?.length) result.push(...flattenSidebar(item.items))
|
|
159
|
+
}
|
|
160
|
+
return result
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const allLinks = computed<SidebarLink[]>(() => {
|
|
164
|
+
const sidebar = theme.value.sidebar
|
|
165
|
+
if (!sidebar) return []
|
|
166
|
+
if (Array.isArray(sidebar)) return flattenSidebar(sidebar)
|
|
167
|
+
return Object.values(sidebar).flatMap((group: any) =>
|
|
168
|
+
Array.isArray(group) ? flattenSidebar(group) : [],
|
|
169
|
+
)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
const currentPath = computed(() => {
|
|
173
|
+
return (
|
|
174
|
+
'/' + page.value.relativePath.replace(/\.md$/, '').replace(/\/index$/, '/')
|
|
175
|
+
)
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
// Every tab of a split page is the same entry in the sidebar, the one that
|
|
179
|
+
// links its first tab, so the footer offers the same neighbours on each.
|
|
180
|
+
const currentIndex = computed(() =>
|
|
181
|
+
allLinks.value.findIndex((l) =>
|
|
182
|
+
tabDir.value
|
|
183
|
+
? l.link.replace(/\/[^/]+$/, '') === tabDir.value
|
|
184
|
+
: l.link === currentPath.value,
|
|
185
|
+
),
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
const prev = computed(() =>
|
|
189
|
+
currentIndex.value > 0 ? allLinks.value[currentIndex.value - 1] : null,
|
|
190
|
+
)
|
|
191
|
+
const next = computed(() =>
|
|
192
|
+
currentIndex.value >= 0 && currentIndex.value < allLinks.value.length - 1
|
|
193
|
+
? allLinks.value[currentIndex.value + 1]
|
|
194
|
+
: null,
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
const editLink = computed(() => {
|
|
198
|
+
const pattern = theme.value.editLink?.pattern
|
|
199
|
+
if (!pattern) return null
|
|
200
|
+
return pattern.replace(':path', page.value.relativePath)
|
|
201
|
+
})
|
|
202
|
+
</script>
|
|
203
|
+
|
|
204
|
+
<style lang="scss" scoped>
|
|
205
|
+
@use '@nubisco/ui/variables' as v;
|
|
206
|
+
|
|
207
|
+
.nb-layout {
|
|
208
|
+
display: flex;
|
|
209
|
+
flex-direction: column;
|
|
210
|
+
min-height: 100vh;
|
|
211
|
+
|
|
212
|
+
&__main {
|
|
213
|
+
flex: 1;
|
|
214
|
+
display: grid;
|
|
215
|
+
grid-template-columns: minmax(0, 1fr);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
&__aside {
|
|
219
|
+
display: none;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
@media (min-width: 1280px) {
|
|
223
|
+
&__main {
|
|
224
|
+
grid-template-columns: minmax(0, 1fr) 15rem;
|
|
225
|
+
column-gap: calc(var(--nb-base-unit) * 4);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
&__aside {
|
|
229
|
+
display: block;
|
|
230
|
+
padding: calc(var(--nb-base-unit) * 6) calc(var(--nb-base-unit) * 3) 0 0;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
&__aside-inner {
|
|
234
|
+
position: sticky;
|
|
235
|
+
// Under the site header and the page's own sticky bar.
|
|
236
|
+
top: calc(var(--vp-nav-height, 64px) + 96px + 24px);
|
|
237
|
+
max-height: calc(100vh - var(--vp-nav-height, 64px) - 140px);
|
|
238
|
+
overflow-y: auto;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
&__body {
|
|
243
|
+
flex: 1;
|
|
244
|
+
padding: calc(var(--nb-base-unit) * 4);
|
|
245
|
+
|
|
246
|
+
/* Content spacing: handle VitePress wrapper divs and markdown paragraphs */
|
|
247
|
+
:deep(p) {
|
|
248
|
+
margin-top: 0.5em;
|
|
249
|
+
margin-bottom: 1.5em;
|
|
250
|
+
line-height: 1.6;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/*
|
|
254
|
+
* Section headings at Carbon's weight: large and regular rather than
|
|
255
|
+
* large and bold, so a long page of them reads as a sequence of sections
|
|
256
|
+
* and not as a sequence of shouts. The page title above is the one heavy
|
|
257
|
+
* thing.
|
|
258
|
+
*/
|
|
259
|
+
:deep(h2) {
|
|
260
|
+
margin-top: 1.5em;
|
|
261
|
+
margin-bottom: 0.75em;
|
|
262
|
+
font-size: 2rem;
|
|
263
|
+
font-weight: 400;
|
|
264
|
+
line-height: 1.25;
|
|
265
|
+
letter-spacing: 0;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
:deep(h3) {
|
|
269
|
+
margin-top: 1.25em;
|
|
270
|
+
margin-bottom: 0.5em;
|
|
271
|
+
font-size: 1.375rem;
|
|
272
|
+
font-weight: 600;
|
|
273
|
+
line-height: 1.3;
|
|
274
|
+
letter-spacing: 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
:deep(ul),
|
|
278
|
+
:deep(ol) {
|
|
279
|
+
margin-bottom: 1.5em;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
:deep(li) {
|
|
283
|
+
margin-bottom: 0.5em;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* Prose tables only. Component demos render their own tables (NbDataTable,
|
|
287
|
+
NbSpreadsheet) whose scoped rules lose to this one on specificity
|
|
288
|
+
(0,2,2 vs 0,2,0), which silently overrode their cell padding and made
|
|
289
|
+
every density look identical. Anything carrying an `nb-` class styles
|
|
290
|
+
itself. */
|
|
291
|
+
:deep(table:not([class*='nb-'])) {
|
|
292
|
+
width: 100%;
|
|
293
|
+
border-collapse: collapse;
|
|
294
|
+
margin-top: 1.5em;
|
|
295
|
+
margin-bottom: 1.5em;
|
|
296
|
+
|
|
297
|
+
/*
|
|
298
|
+
* Prose tables follow the theme.
|
|
299
|
+
*
|
|
300
|
+
* These were a literal `--nb-c-white` header row and two black-alpha
|
|
301
|
+
* rules, all of which assume a light page: in dark mode the header row
|
|
302
|
+
* stayed white under light text, and the row rules disappeared into the
|
|
303
|
+
* background entirely.
|
|
304
|
+
*/
|
|
305
|
+
thead tr {
|
|
306
|
+
background: var(--nb-c-layer-1);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
th {
|
|
310
|
+
font-weight: 600;
|
|
311
|
+
text-align: left;
|
|
312
|
+
padding: 12px 16px;
|
|
313
|
+
border-bottom: 1px solid var(--nb-c-border);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
td {
|
|
317
|
+
padding: 12px 16px;
|
|
318
|
+
border-bottom: 1px solid var(--nb-c-layer-border-1);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
tbody tr:last-child td {
|
|
322
|
+
border-bottom: none;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/* Inline code, everywhere except inside syntax-highlighted fences */
|
|
327
|
+
:deep(:not(pre) > code) {
|
|
328
|
+
font-family: var(--nb-font-family-mono, 'Courier New', monospace);
|
|
329
|
+
font-size: 0.875em;
|
|
330
|
+
// A tint of the surface, not of black: a black wash is invisible on a
|
|
331
|
+
// dark page.
|
|
332
|
+
background: var(--nb-c-layer-2);
|
|
333
|
+
color: var(--nb-c-text);
|
|
334
|
+
padding: 2px 6px;
|
|
335
|
+
border-radius: 4px;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
:deep(blockquote) {
|
|
339
|
+
margin-top: 1.5em;
|
|
340
|
+
margin-bottom: 1.5em;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
:deep(.custom-block) {
|
|
344
|
+
margin-bottom: 1.5em;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
:deep(pre) {
|
|
348
|
+
margin-top: 1.5em;
|
|
349
|
+
margin-bottom: 1.5em;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
&__footer {
|
|
354
|
+
background: var(--nb-c-black);
|
|
355
|
+
color: var(--nb-c-white);
|
|
356
|
+
border-top: none;
|
|
357
|
+
padding: 40px;
|
|
358
|
+
margin-top: auto;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/* On a phone the body takes the same 16px gutter as the page header above it,
|
|
363
|
+
so the text lines up with the title instead of stepping in under it. */
|
|
364
|
+
@include v.phone {
|
|
365
|
+
.nb-layout__body {
|
|
366
|
+
padding: calc(var(--nb-base-unit) * 3) calc(var(--nb-base-unit) * 2);
|
|
367
|
+
|
|
368
|
+
/* A prose table wider than the screen scrolls inside itself rather than
|
|
369
|
+
widening the whole page sideways. */
|
|
370
|
+
:deep(table:not([class*='nb-'])) {
|
|
371
|
+
display: block;
|
|
372
|
+
max-width: 100%;
|
|
373
|
+
overflow-x: auto;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/* ── Footer: prev/next navigation ────────────────────────────────────────── */
|
|
379
|
+
.nb-footer__nav {
|
|
380
|
+
display: grid;
|
|
381
|
+
grid-template-columns: 1fr 1fr;
|
|
382
|
+
gap: 12px;
|
|
383
|
+
margin-bottom: 32px;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.nb-footer__nav-item {
|
|
387
|
+
display: flex;
|
|
388
|
+
flex-direction: column;
|
|
389
|
+
gap: 6px;
|
|
390
|
+
padding: 16px 20px;
|
|
391
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
392
|
+
background: rgba(255, 255, 255, 0.05);
|
|
393
|
+
text-decoration: none;
|
|
394
|
+
transition:
|
|
395
|
+
border-color 0.15s,
|
|
396
|
+
background 0.15s;
|
|
397
|
+
|
|
398
|
+
&:hover {
|
|
399
|
+
border-color: var(--nb-c-magenta);
|
|
400
|
+
background: rgba(255, 255, 255, 0.08);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
&--next {
|
|
404
|
+
text-align: right;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.nb-footer__nav-spacer {
|
|
409
|
+
display: block;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.nb-footer__nav-label {
|
|
413
|
+
font-size: 12px;
|
|
414
|
+
font-weight: 500;
|
|
415
|
+
color: rgba(255, 255, 255, 0.6);
|
|
416
|
+
text-transform: uppercase;
|
|
417
|
+
letter-spacing: 0.06em;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.nb-footer__nav-title {
|
|
421
|
+
font-size: 14px;
|
|
422
|
+
font-weight: 600;
|
|
423
|
+
color: var(--nb-c-white);
|
|
424
|
+
line-height: 1.4;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/* ── Footer: bar ─────────────────────────────────────────────────────────── */
|
|
428
|
+
.nb-footer__bar {
|
|
429
|
+
display: flex;
|
|
430
|
+
align-items: center;
|
|
431
|
+
justify-content: space-between;
|
|
432
|
+
gap: 16px;
|
|
433
|
+
flex-wrap: wrap;
|
|
434
|
+
padding-top: 24px;
|
|
435
|
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
436
|
+
padding-bottom: 0;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.nb-footer__brand {
|
|
440
|
+
display: flex;
|
|
441
|
+
align-items: center;
|
|
442
|
+
gap: 8px;
|
|
443
|
+
text-decoration: none;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
.nb-footer__logo {
|
|
447
|
+
width: 24px;
|
|
448
|
+
height: 24px;
|
|
449
|
+
flex-shrink: 0;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
.nb-footer__brand-name {
|
|
453
|
+
font-size: 14px;
|
|
454
|
+
font-weight: 600;
|
|
455
|
+
color: var(--nb-c-white);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.nb-footer__meta {
|
|
459
|
+
display: flex;
|
|
460
|
+
align-items: center;
|
|
461
|
+
gap: 20px;
|
|
462
|
+
flex-wrap: wrap;
|
|
463
|
+
justify-content: flex-end;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.nb-footer__edit-link {
|
|
467
|
+
font-size: 12px;
|
|
468
|
+
color: var(--nb-c-magenta);
|
|
469
|
+
text-decoration: none;
|
|
470
|
+
|
|
471
|
+
&:hover {
|
|
472
|
+
text-decoration: underline;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.nb-footer__copyright {
|
|
477
|
+
font-size: 12px;
|
|
478
|
+
color: rgba(255, 255, 255, 0.6);
|
|
479
|
+
}
|
|
480
|
+
</style>
|