@fikar-ai/design 1.5.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/README.md +1379 -0
- package/brand/apps/account.svg +4 -0
- package/brand/apps/chat.svg +3 -0
- package/brand/apps/cost-calculator.svg +12 -0
- package/brand/apps/crs.svg +9 -0
- package/brand/apps/dictionary.svg +5 -0
- package/brand/apps/platform.svg +11 -0
- package/brand/apps/super-admin.svg +9 -0
- package/brand/favicon/apple-touch-icon.png +0 -0
- package/brand/favicon/favicon-16x16.png +0 -0
- package/brand/favicon/favicon-32x32.png +0 -0
- package/brand/favicon/favicon-48x48.png +0 -0
- package/brand/favicon/favicon.ico +0 -0
- package/brand/favicon/favicon.svg +11 -0
- package/brand/favicon/icon-192.png +0 -0
- package/brand/favicon/icon-512.png +0 -0
- package/brand/favicon/manifest.webmanifest +8 -0
- package/brand/fikar-loader.svg +10 -0
- package/brand/fikar-logo-mono.svg +6 -0
- package/brand/fikar-logo-reversed.svg +9 -0
- package/brand/fikar-logo.svg +15 -0
- package/components.css +577 -0
- package/fonts/Charter-license.txt +3 -0
- package/fonts/charter_bold.woff2 +0 -0
- package/fonts/charter_bold_italic.woff2 +0 -0
- package/fonts/charter_italic.woff2 +0 -0
- package/fonts/charter_regular.woff2 +0 -0
- package/fonts.css +37 -0
- package/logo.css +24 -0
- package/package.json +68 -0
- package/preset.d.ts +5 -0
- package/preset.js +67 -0
- package/recipes/brand-loader.html +4 -0
- package/recipes/detail-panel.html +35 -0
- package/recipes/empty-state.html +6 -0
- package/recipes/entity-badge.html +6 -0
- package/recipes/filter-chip.html +5 -0
- package/recipes/launcher.html +24 -0
- package/recipes/list-row.html +21 -0
- package/recipes/search-results.html +43 -0
- package/recipes/search.html +18 -0
- package/recipes/segmented.html +7 -0
- package/recipes/shell-no-sidebar.html +60 -0
- package/recipes/shell.html +89 -0
- package/recipes/status-badge.html +10 -0
- package/recipes/theme-menu.html +21 -0
- package/recipes/time.html +9 -0
- package/recipes/user-menu.html +21 -0
- package/shell.js +324 -0
- package/templates/jinja/launcher.html +45 -0
- package/templates/jinja/shell.html +97 -0
- package/templates/jinja/theme-menu.html +27 -0
- package/templates/jinja/user-menu.html +55 -0
- package/tokens.css +122 -0
package/fonts.css
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/* @fikar-ai/design — Charter (serif) self-hosted @font-face.
|
|
2
|
+
Charter by Matthew Carter / Bitstream, redistributed by Matthew Butterick
|
|
3
|
+
(practicaltypography.com/charter.html). License: ./fonts/Charter-license.txt.
|
|
4
|
+
BITSTREAM CHARTER is a registered trademark of Bitstream Inc.
|
|
5
|
+
|
|
6
|
+
Import once per surface (e.g. in your global stylesheet) to enable the `serif`
|
|
7
|
+
family (`font-serif` in Tailwind apps via the @fikar-ai/design preset).
|
|
8
|
+
Inter + JetBrains Mono are loaded separately (Google Fonts) and stay the UI/mono faces. */
|
|
9
|
+
|
|
10
|
+
@font-face {
|
|
11
|
+
font-family: 'Charter';
|
|
12
|
+
font-style: normal;
|
|
13
|
+
font-weight: 400;
|
|
14
|
+
font-display: swap;
|
|
15
|
+
src: url('./fonts/charter_regular.woff2') format('woff2');
|
|
16
|
+
}
|
|
17
|
+
@font-face {
|
|
18
|
+
font-family: 'Charter';
|
|
19
|
+
font-style: italic;
|
|
20
|
+
font-weight: 400;
|
|
21
|
+
font-display: swap;
|
|
22
|
+
src: url('./fonts/charter_italic.woff2') format('woff2');
|
|
23
|
+
}
|
|
24
|
+
@font-face {
|
|
25
|
+
font-family: 'Charter';
|
|
26
|
+
font-style: normal;
|
|
27
|
+
font-weight: 700;
|
|
28
|
+
font-display: swap;
|
|
29
|
+
src: url('./fonts/charter_bold.woff2') format('woff2');
|
|
30
|
+
}
|
|
31
|
+
@font-face {
|
|
32
|
+
font-family: 'Charter';
|
|
33
|
+
font-style: italic;
|
|
34
|
+
font-weight: 700;
|
|
35
|
+
font-display: swap;
|
|
36
|
+
src: url('./fonts/charter_bold_italic.woff2') format('woff2');
|
|
37
|
+
}
|
package/logo.css
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/* @fikar-ai/design — Fikar logomark, theme-aware swap (framework-agnostic).
|
|
2
|
+
The mark is the open "C" arc + three trailing dots in the brand gradient.
|
|
3
|
+
Render BOTH variants and let the cascade show the right one:
|
|
4
|
+
<img class="fk-logo fk-logo--light" src=".../fikar-logo.svg" alt="Fikar">
|
|
5
|
+
<img class="fk-logo fk-logo--dark" src=".../fikar-logo-reversed.svg" alt="" aria-hidden>
|
|
6
|
+
Tailwind apps can skip this file and use `block dark:hidden` / `hidden dark:block` instead.
|
|
7
|
+
Dark is keyed on `.dark` (Tailwind class strategy). For Docusaurus, alias to [data-theme='dark']. */
|
|
8
|
+
|
|
9
|
+
.fk-logo {
|
|
10
|
+
display: block;
|
|
11
|
+
width: auto;
|
|
12
|
+
height: 1.25rem; /* default in-chrome height; override per use */
|
|
13
|
+
}
|
|
14
|
+
.fk-logo--dark {
|
|
15
|
+
display: none;
|
|
16
|
+
}
|
|
17
|
+
.dark .fk-logo--light,
|
|
18
|
+
[data-theme='dark'] .fk-logo--light {
|
|
19
|
+
display: none;
|
|
20
|
+
}
|
|
21
|
+
.dark .fk-logo--dark,
|
|
22
|
+
[data-theme='dark'] .fk-logo--dark {
|
|
23
|
+
display: block;
|
|
24
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fikar-ai/design",
|
|
3
|
+
"version": "1.5.0",
|
|
4
|
+
"description": "Fikar Ink design language — tokens, Tailwind preset + component layer. Single source of truth across all Fikar surfaces.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"private": false,
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/Kapture-AI/fikar-design.git"
|
|
14
|
+
},
|
|
15
|
+
"exports": {
|
|
16
|
+
"./tokens.css": "./tokens.css",
|
|
17
|
+
"./components.css": "./components.css",
|
|
18
|
+
"./logo.css": "./logo.css",
|
|
19
|
+
"./fonts.css": "./fonts.css",
|
|
20
|
+
"./brand/*": "./brand/*",
|
|
21
|
+
"./fonts/*": "./fonts/*",
|
|
22
|
+
"./recipes/*": "./recipes/*",
|
|
23
|
+
"./shell.js": "./shell.js",
|
|
24
|
+
"./templates/*": "./templates/*",
|
|
25
|
+
"./preset": {
|
|
26
|
+
"types": "./preset.d.ts",
|
|
27
|
+
"default": "./preset.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"tokens.css",
|
|
32
|
+
"components.css",
|
|
33
|
+
"logo.css",
|
|
34
|
+
"fonts.css",
|
|
35
|
+
"brand/",
|
|
36
|
+
"fonts/",
|
|
37
|
+
"recipes/shell.html",
|
|
38
|
+
"recipes/shell-no-sidebar.html",
|
|
39
|
+
"recipes/launcher.html",
|
|
40
|
+
"recipes/user-menu.html",
|
|
41
|
+
"recipes/theme-menu.html",
|
|
42
|
+
"recipes/brand-loader.html",
|
|
43
|
+
"recipes/empty-state.html",
|
|
44
|
+
"recipes/entity-badge.html",
|
|
45
|
+
"recipes/search.html",
|
|
46
|
+
"recipes/search-results.html",
|
|
47
|
+
"recipes/filter-chip.html",
|
|
48
|
+
"recipes/segmented.html",
|
|
49
|
+
"recipes/detail-panel.html",
|
|
50
|
+
"recipes/list-row.html",
|
|
51
|
+
"recipes/status-badge.html",
|
|
52
|
+
"recipes/time.html",
|
|
53
|
+
"shell.js",
|
|
54
|
+
"templates/",
|
|
55
|
+
"preset.js",
|
|
56
|
+
"preset.d.ts",
|
|
57
|
+
"README.md"
|
|
58
|
+
],
|
|
59
|
+
"scripts": {
|
|
60
|
+
"test": "node --test"
|
|
61
|
+
},
|
|
62
|
+
"keywords": [
|
|
63
|
+
"fikar",
|
|
64
|
+
"design-tokens",
|
|
65
|
+
"tailwind-preset",
|
|
66
|
+
"ink"
|
|
67
|
+
]
|
|
68
|
+
}
|
package/preset.d.ts
ADDED
package/preset.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fikar-ai/design — Tailwind preset (Ink).
|
|
3
|
+
* Consume in tailwind.config.{ts,js}: presets: [fikarPreset]
|
|
4
|
+
* Then delete the app's own colors / fontFamily / borderRadius / keyframes — they live here now.
|
|
5
|
+
* Pair with `import "@fikar-ai/design/tokens.css"` in your global stylesheet for the CSS vars.
|
|
6
|
+
* Keep `plugins: [tailwindcssAnimate]` in the app; this preset is pure data, no plugins.
|
|
7
|
+
*
|
|
8
|
+
* @type {Partial<import('tailwindcss').Config>}
|
|
9
|
+
*/
|
|
10
|
+
const fikarPreset = {
|
|
11
|
+
darkMode: ['class'],
|
|
12
|
+
theme: {
|
|
13
|
+
extend: {
|
|
14
|
+
fontFamily: {
|
|
15
|
+
// UI chrome (buttons, labels, tables, controls) — the default.
|
|
16
|
+
sans: ['Inter', 'ui-sans-serif', 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'sans-serif'],
|
|
17
|
+
// Headings + body prose (reading surfaces). Needs `@import "@fikar-ai/design/fonts.css"`.
|
|
18
|
+
serif: ['Charter', 'ui-serif', 'Georgia', 'Cambria', 'Times New Roman', 'serif'],
|
|
19
|
+
// Numerals, IDs, code, numeric tables.
|
|
20
|
+
mono: ['JetBrains Mono', 'ui-monospace', 'SFMono-Regular', 'Menlo', 'monospace'],
|
|
21
|
+
},
|
|
22
|
+
colors: {
|
|
23
|
+
border: 'hsl(var(--border))',
|
|
24
|
+
input: 'hsl(var(--input))',
|
|
25
|
+
ring: 'hsl(var(--ring))',
|
|
26
|
+
background: 'hsl(var(--background))',
|
|
27
|
+
foreground: 'hsl(var(--foreground))',
|
|
28
|
+
primary: { DEFAULT: 'hsl(var(--primary))', foreground: 'hsl(var(--primary-foreground))' },
|
|
29
|
+
secondary: { DEFAULT: 'hsl(var(--secondary))', foreground: 'hsl(var(--secondary-foreground))' },
|
|
30
|
+
destructive: { DEFAULT: 'hsl(var(--destructive))', foreground: 'hsl(var(--destructive-foreground))' },
|
|
31
|
+
muted: { DEFAULT: 'hsl(var(--muted))', foreground: 'hsl(var(--muted-foreground))' },
|
|
32
|
+
accent: { DEFAULT: 'hsl(var(--accent))', foreground: 'hsl(var(--accent-foreground))' },
|
|
33
|
+
popover: { DEFAULT: 'hsl(var(--popover))', foreground: 'hsl(var(--popover-foreground))' },
|
|
34
|
+
card: { DEFAULT: 'hsl(var(--card))', foreground: 'hsl(var(--card-foreground))' },
|
|
35
|
+
success: { DEFAULT: 'hsl(var(--success))', foreground: 'hsl(var(--success-foreground))' },
|
|
36
|
+
warning: { DEFAULT: 'hsl(var(--warning))', foreground: 'hsl(var(--warning-foreground))' },
|
|
37
|
+
info: { DEFAULT: 'hsl(var(--info))', foreground: 'hsl(var(--info-foreground))' },
|
|
38
|
+
// data-viz ramp (recharts etc.)
|
|
39
|
+
chart: {
|
|
40
|
+
1: 'hsl(var(--fk-chart1))',
|
|
41
|
+
2: 'hsl(var(--fk-chart2))',
|
|
42
|
+
3: 'hsl(var(--fk-chart3))',
|
|
43
|
+
4: 'hsl(var(--fk-chart4))',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
borderRadius: {
|
|
47
|
+
lg: 'var(--radius)',
|
|
48
|
+
md: 'calc(var(--radius) - 2px)',
|
|
49
|
+
sm: 'calc(var(--radius) - 4px)',
|
|
50
|
+
},
|
|
51
|
+
keyframes: {
|
|
52
|
+
'accordion-down': { from: { height: '0' }, to: { height: 'var(--radix-accordion-content-height)' } },
|
|
53
|
+
'accordion-up': { from: { height: 'var(--radix-accordion-content-height)' }, to: { height: '0' } },
|
|
54
|
+
shimmer: { '100%': { transform: 'translateX(100%)' } },
|
|
55
|
+
'fade-in': { '0%': { opacity: '0', transform: 'translateY(4px)' }, '100%': { opacity: '1', transform: 'translateY(0)' } },
|
|
56
|
+
},
|
|
57
|
+
animation: {
|
|
58
|
+
'accordion-down': 'accordion-down 0.2s ease-out',
|
|
59
|
+
'accordion-up': 'accordion-up 0.2s ease-out',
|
|
60
|
+
shimmer: 'shimmer 2s infinite',
|
|
61
|
+
'fade-in': 'fade-in 200ms ease-out',
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export default fikarPreset;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<!-- Detail panel: the surface that describes one thing, such as a node in a graph or a source in an answer. A close button, a type line (a dot in the
|
|
2
|
+
entity colour and the type in words), a serif title, a description, then sections. Each section is a .detail-heading and rows, or chips.
|
|
3
|
+
A row is a block with its text and a .detail-row-meta at the right. When the whole row is the target it is an <a> or a <button> with the same classes (the
|
|
4
|
+
first row below), and when only a word in it is, that word is an <a> inside (the last section). A chip is a <span>, an <a> or a <button>.
|
|
5
|
+
.detail-dot-person, -organization, -event and -geo are the --entity-* roles, and a dot with none of them is muted. The panel is 340px wide and never
|
|
6
|
+
wider than its container, and fills it below 768px. The page places it (position, offsets, height). The title names the panel through aria-labelledby, so
|
|
7
|
+
its id is the page's and unique. Charter loads only on a page that imports fonts.css. -->
|
|
8
|
+
<aside class="detail-panel" aria-labelledby="detail-title">
|
|
9
|
+
<button class="detail-close" type="button" aria-label="Close">
|
|
10
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
11
|
+
<path d="M18 6 6 18M6 6l12 12"/>
|
|
12
|
+
</svg>
|
|
13
|
+
</button>
|
|
14
|
+
<p class="detail-type"><i class="detail-dot detail-dot-person" aria-hidden="true"></i>Person</p>
|
|
15
|
+
<h2 class="detail-title" id="detail-title">John</h2>
|
|
16
|
+
<p class="detail-desc">Prospect at Waterfield evaluating Fikar for support-desk knowledge, personal memory and live call support.</p>
|
|
17
|
+
<section class="detail-section">
|
|
18
|
+
<h3 class="detail-heading">Strongest connections</h3>
|
|
19
|
+
<a class="detail-row" href="#"><span>Fikar</span><span class="detail-row-meta">evaluating · 57</span></a>
|
|
20
|
+
<div class="detail-row"><span>Fayaz</span><span class="detail-row-meta">discussed with · 42</span></div>
|
|
21
|
+
<div class="detail-row"><span>Rana Waqas</span><span class="detail-row-meta">asked about transcripts · 23</span></div>
|
|
22
|
+
</section>
|
|
23
|
+
<section class="detail-section">
|
|
24
|
+
<h3 class="detail-heading">Said in 2 calls</h3>
|
|
25
|
+
<div class="detail-row"><span>Waterfield demo call <span class="detail-row-meta">· 30 Sep</span></span><a href="#">Open call</a></div>
|
|
26
|
+
<div class="detail-row"><span>COO Q2 close review <span class="detail-row-meta">· 12 Sep</span></span><a href="#">Open call</a></div>
|
|
27
|
+
</section>
|
|
28
|
+
<section class="detail-section">
|
|
29
|
+
<h3 class="detail-heading">Read the words</h3>
|
|
30
|
+
<div class="detail-chips">
|
|
31
|
+
<span class="detail-chip">4 passages</span>
|
|
32
|
+
<a class="detail-chip" href="#">Ask in chat</a>
|
|
33
|
+
</div>
|
|
34
|
+
</section>
|
|
35
|
+
</aside>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<!-- Entity type badges: the four kinds of thing in the knowledge graph. .badge plus one of .b-person, .b-organization, .b-event, .b-geo.
|
|
2
|
+
The colours are the --entity-* roles in tokens.css, so dark needs nothing more. The label is the type in words, not the upper case name the data uses. -->
|
|
3
|
+
<span class="badge b-person">Person</span>
|
|
4
|
+
<span class="badge b-organization">Organization</span>
|
|
5
|
+
<span class="badge b-event">Event</span>
|
|
6
|
+
<span class="badge b-geo">Geo</span>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<!-- Filter chips: .pill with .p-toggle on a <button>. aria-pressed is the state and the only style hook, so the page keeps it in step, "true" while the
|
|
2
|
+
filter is on. Shown off, then on. A chip changes what a list shows, so it is a toggle button and not a link or a checkbox. Put the group in a
|
|
3
|
+
wrapper that has a label (role="group" and aria-label) and lets the chips wrap. -->
|
|
4
|
+
<button class="pill p-toggle" type="button" aria-pressed="false">Person</button>
|
|
5
|
+
<button class="pill p-toggle" type="button" aria-pressed="true">Organization</button>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!-- App launcher: the grid button and a three column grid of tiles, one per app the signed-in person may open. Render nothing when the list is empty.
|
|
2
|
+
Each tile is a glyph over the app name. The glyph is picked by the app id from brand/apps/<id>.svg (chat, platform, crs, dictionary, cost-calculator,
|
|
3
|
+
super-admin, account), and an app with an id the package does not know shows the first letter of its name in the same .launcher-tile.
|
|
4
|
+
The panel needs the class launcher-apps to be a grid. Without it the rows stay a plain list, as in earlier versions. A hint is accepted by the React component and the macro, and not shown.
|
|
5
|
+
The current app has .current and aria-current="page". Items are plain links, because they leave the app.
|
|
6
|
+
This markup has no behaviour of its own. To hand it to shell.js, add data-fk-menu to the root (the shell recipes do), and remove
|
|
7
|
+
the page's own wiring first, since shell.js would otherwise handle the menu a second time. -->
|
|
8
|
+
<div class="launcher">
|
|
9
|
+
<button class="launcher-btn" type="button" aria-haspopup="menu" aria-expanded="false" aria-label="Switch app">
|
|
10
|
+
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
11
|
+
<circle cx="5" cy="5" r="2"/><circle cx="12" cy="5" r="2"/><circle cx="19" cy="5" r="2"/>
|
|
12
|
+
<circle cx="5" cy="12" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="19" cy="12" r="2"/>
|
|
13
|
+
<circle cx="5" cy="19" r="2"/><circle cx="12" cy="19" r="2"/><circle cx="19" cy="19" r="2"/>
|
|
14
|
+
</svg>
|
|
15
|
+
</button>
|
|
16
|
+
<div class="launcher-panel launcher-apps" role="menu">
|
|
17
|
+
<a class="launcher-item current" role="menuitem" href="https://chat.fikar.ai" aria-current="page">
|
|
18
|
+
<span class="launcher-tile" aria-hidden="true"><svg class="app-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg></span>Chat
|
|
19
|
+
</a>
|
|
20
|
+
<a class="launcher-item" role="menuitem" href="https://platform.fikar.ai">
|
|
21
|
+
<span class="launcher-tile" aria-hidden="true"><svg class="app-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="21" x2="14" y1="4" y2="4"/><line x1="10" x2="3" y1="4" y2="4"/><line x1="21" x2="12" y1="12" y2="12"/><line x1="8" x2="3" y1="12" y2="12"/><line x1="21" x2="16" y1="20" y2="20"/><line x1="12" x2="3" y1="20" y2="20"/><line x1="14" x2="14" y1="2" y2="6"/><line x1="8" x2="8" y1="10" y2="14"/><line x1="16" x2="16" y1="18" y2="22"/></svg></span>Platform
|
|
22
|
+
</a>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<!-- List rows grouped by day: a .day-sep label, then the rows under it. A row is a 13px title and a 12px muted line, both cut with an ellipsis, on an <a> when it
|
|
2
|
+
goes to an address or a <button type="button"> when it selects. The row the page is on has aria-current, "page" on a link and "true" on a button, and that
|
|
3
|
+
is the only thing that draws it (the first row below is the current one, and its line has a time in it, see time.html). The separator is an <h3>, one
|
|
4
|
+
level under the heading of the list, and the page decides the groups and their words. The list is a plain block, so a page can put it in a scroll area. -->
|
|
5
|
+
<div>
|
|
6
|
+
<h3 class="day-sep">Today</h3>
|
|
7
|
+
<a class="list-row" href="#" aria-current="page">
|
|
8
|
+
<span class="list-row-title">Waterfield demo call</span>
|
|
9
|
+
<span class="list-row-meta"><time class="fk-time" datetime="2026-09-30T08:16:00Z" title="30 Sep, 08:16">4 h ago</time> · 119 entities</span>
|
|
10
|
+
</a>
|
|
11
|
+
<h3 class="day-sep">22 Sep</h3>
|
|
12
|
+
<button class="list-row" type="button">
|
|
13
|
+
<span class="list-row-title">Daily catchup, Fayaz and Rana</span>
|
|
14
|
+
<span class="list-row-meta">86 s · 5 entities</span>
|
|
15
|
+
</button>
|
|
16
|
+
<h3 class="day-sep">12 Sep · imported</h3>
|
|
17
|
+
<a class="list-row" href="#">
|
|
18
|
+
<span class="list-row-title">September operating checkpoint</span>
|
|
19
|
+
<span class="list-row-meta">MS Teams · 22 entities</span>
|
|
20
|
+
</a>
|
|
21
|
+
</div>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<!-- Search results: a search box with its listbox open under it, then the same listbox with nothing to show.
|
|
2
|
+
The listbox is a .launcher-panel, so .search (already positioned) is its parent, and the page shows or hides it with `hidden` and keeps
|
|
3
|
+
aria-expanded on the input in step. Focus stays in the input. The row the page makes active is the one named by aria-activedescendant, and it also has
|
|
4
|
+
aria-selected="true", which is what draws it. The other rows have aria-selected="false". A row is the item's title, an optional entity badge
|
|
5
|
+
and count, and an optional one line description. The row ids are the page's, and unique on the page.
|
|
6
|
+
Below the box: the empty state is one disabled option inside the listbox, so the list stays valid. It is never the active row.
|
|
7
|
+
shell.js does not drive this list. Arrow keys, Enter and Escape are the page's, and @fikar-ai/design-react does them in SearchResults. -->
|
|
8
|
+
<div class="search search-bar">
|
|
9
|
+
<svg class="search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
10
|
+
<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>
|
|
11
|
+
</svg>
|
|
12
|
+
<input class="inp" type="search" value="a" placeholder="Search" aria-label="Search" autocomplete="off" data-fk-search
|
|
13
|
+
role="combobox" aria-expanded="true" aria-controls="search-results" aria-autocomplete="list" aria-activedescendant="search-result-aisha">
|
|
14
|
+
<button class="search-clear" type="button" aria-label="Clear search">
|
|
15
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
16
|
+
<path d="M18 6 6 18M6 6l12 12"/>
|
|
17
|
+
</svg>
|
|
18
|
+
</button>
|
|
19
|
+
<kbd class="search-kbd">/</kbd>
|
|
20
|
+
<div class="launcher-panel search-results" id="search-results" role="listbox" aria-label="Results">
|
|
21
|
+
<div class="search-row" id="search-result-aisha" role="option" aria-selected="true">
|
|
22
|
+
<span class="search-row-title">Aisha Rahman</span>
|
|
23
|
+
<span class="badge b-person">Person</span>
|
|
24
|
+
<span class="search-row-meta">12</span>
|
|
25
|
+
<span class="search-row-desc">Head of platform, owns the Q3 roadmap</span>
|
|
26
|
+
</div>
|
|
27
|
+
<div class="search-row" id="search-result-acme" role="option" aria-selected="false">
|
|
28
|
+
<span class="search-row-title">Acme Corp</span>
|
|
29
|
+
<span class="badge b-organization">Organization</span>
|
|
30
|
+
<span class="search-row-meta">8</span>
|
|
31
|
+
<span class="search-row-desc">Largest customer, renewal due in October</span>
|
|
32
|
+
</div>
|
|
33
|
+
<div class="search-row" id="search-result-planning" role="option" aria-selected="false">
|
|
34
|
+
<span class="search-row-title">Q3 planning</span>
|
|
35
|
+
<span class="badge b-event">Event</span>
|
|
36
|
+
<span class="search-row-meta">5</span>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div class="launcher-panel search-results" id="search-results-empty" role="listbox" aria-label="Results">
|
|
42
|
+
<div class="search-empty" role="option" aria-disabled="true" aria-selected="false">No matches</div>
|
|
43
|
+
</div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!-- Search box: a leading icon, the input, a clear button and a shortcut hint. Shown at the top bar size (.search-bar), empty.
|
|
2
|
+
.search-panel in its place fills a sidebar or panel, with a smaller icon and text. Every other part is the same.
|
|
3
|
+
The input needs a placeholder: CSS shows the hint while the box is empty and the clear button once there is text, from :placeholder-shown.
|
|
4
|
+
data-fk-search registers the input with shell.js, which focuses it on / and on Cmd-K or Ctrl-K. The first one in the document wins, so leave it off
|
|
5
|
+
any second box. The hint's text is the page's and shows what it registered. shell.js also clears the box and keeps focus in it when .search-clear is
|
|
6
|
+
pressed, and sends an input event so the page hears it. The icons ship inline, with no icon library. -->
|
|
7
|
+
<div class="search search-bar">
|
|
8
|
+
<svg class="search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
9
|
+
<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>
|
|
10
|
+
</svg>
|
|
11
|
+
<input class="inp" type="search" placeholder="Search" aria-label="Search" autocomplete="off" data-fk-search>
|
|
12
|
+
<button class="search-clear" type="button" aria-label="Clear search">
|
|
13
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
14
|
+
<path d="M18 6 6 18M6 6l12 12"/>
|
|
15
|
+
</svg>
|
|
16
|
+
</button>
|
|
17
|
+
<kbd class="search-kbd">/</kbd>
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<!-- Segmented control: a two mode switch such as Find or Ask. A radiogroup of buttons with role="radio", because exactly one is chosen.
|
|
2
|
+
aria-checked is the state and the only style hook. The page sets "true" on the chosen item and "false" on the rest, and does whatever the mode means.
|
|
3
|
+
The buttons are all in the tab order and Space or Enter chooses one. Name the group with aria-label. Any number of items fits, but it is meant for two or three. -->
|
|
4
|
+
<div class="segmented" role="radiogroup" aria-label="Search mode">
|
|
5
|
+
<button class="segmented-item" type="button" role="radio" aria-checked="true">Find</button>
|
|
6
|
+
<button class="segmented-item" type="button" role="radio" aria-checked="false">Ask</button>
|
|
7
|
+
</div>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<!-- App shell without a sidebar: a top bar and the content. Import the logos from @fikar-ai/design/brand/; the src values are placeholders.
|
|
2
|
+
The optional .shell-topbar-start goes between .brand and .cluster; leave it out when there is nothing for it. -->
|
|
3
|
+
<div class="shell with-topbar no-sidebar" id="shell">
|
|
4
|
+
<header class="shell-topbar">
|
|
5
|
+
<div class="brand"><img class="logo-light" src="/brand/fikar-logo.svg" alt=""><img class="logo-dark" src="/brand/fikar-logo-reversed.svg" alt=""><span class="word">FIKAR</span></div>
|
|
6
|
+
<div class="cluster">
|
|
7
|
+
<!-- Launcher (see launcher.html, with data-fk-menu), theme menu (see theme-menu.html), then the user menu (see user-menu.html), in that order.
|
|
8
|
+
Every menu here carries data-fk-menu, so shell.js runs all three. A page must not mix these with menus it wires itself. -->
|
|
9
|
+
<div class="launcher" data-fk-menu>
|
|
10
|
+
<button class="launcher-btn" type="button" aria-haspopup="menu" aria-expanded="false" aria-label="Switch app">
|
|
11
|
+
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
12
|
+
<circle cx="5" cy="5" r="2"/><circle cx="12" cy="5" r="2"/><circle cx="19" cy="5" r="2"/>
|
|
13
|
+
<circle cx="5" cy="12" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="19" cy="12" r="2"/>
|
|
14
|
+
<circle cx="5" cy="19" r="2"/><circle cx="12" cy="19" r="2"/><circle cx="19" cy="19" r="2"/>
|
|
15
|
+
</svg>
|
|
16
|
+
</button>
|
|
17
|
+
<div class="launcher-panel launcher-apps" role="menu">
|
|
18
|
+
<a class="launcher-item current" role="menuitem" href="https://chat.fikar.ai" aria-current="page">
|
|
19
|
+
<span class="launcher-tile" aria-hidden="true"><svg class="app-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg></span>Chat
|
|
20
|
+
</a>
|
|
21
|
+
<a class="launcher-item" role="menuitem" href="https://platform.fikar.ai">
|
|
22
|
+
<span class="launcher-tile" aria-hidden="true"><svg class="app-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="21" x2="14" y1="4" y2="4"/><line x1="10" x2="3" y1="4" y2="4"/><line x1="21" x2="12" y1="12" y2="12"/><line x1="8" x2="3" y1="12" y2="12"/><line x1="21" x2="16" y1="20" y2="20"/><line x1="12" x2="3" y1="20" y2="20"/><line x1="14" x2="14" y1="2" y2="6"/><line x1="8" x2="8" y1="10" y2="14"/><line x1="16" x2="16" y1="18" y2="22"/></svg></span>Platform
|
|
23
|
+
</a>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="launcher" data-fk-menu>
|
|
27
|
+
<button class="launcher-btn theme-menu-btn" type="button" aria-haspopup="menu" aria-expanded="false" aria-label="Choose theme">
|
|
28
|
+
<svg class="theme-icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
29
|
+
<circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/>
|
|
30
|
+
</svg>
|
|
31
|
+
<svg class="theme-icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
32
|
+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
|
33
|
+
</svg>
|
|
34
|
+
</button>
|
|
35
|
+
<div class="launcher-panel theme-menu-panel" role="menu" aria-label="Theme">
|
|
36
|
+
<button class="launcher-item theme-menu-item" type="button" role="menuitemradio" aria-checked="false" data-value="light">Light</button>
|
|
37
|
+
<button class="launcher-item theme-menu-item" type="button" role="menuitemradio" aria-checked="false" data-value="dark">Dark</button>
|
|
38
|
+
<button class="launcher-item theme-menu-item current" type="button" role="menuitemradio" aria-checked="true" data-value="system">System</button>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="launcher" data-fk-menu>
|
|
42
|
+
<button class="user-menu-btn" type="button" aria-haspopup="menu" aria-expanded="false" aria-label="Open account menu" data-initials="AM">
|
|
43
|
+
<span class="avatar" aria-hidden="true">AM</span>
|
|
44
|
+
</button>
|
|
45
|
+
<div class="launcher-panel user-menu-panel" role="menu">
|
|
46
|
+
<div class="user-menu-id">
|
|
47
|
+
<span class="user-menu-name">Alex Morgan</span>
|
|
48
|
+
<span class="user-menu-email">alex@example.com</span>
|
|
49
|
+
</div>
|
|
50
|
+
<div class="user-menu-sep" role="separator"></div>
|
|
51
|
+
<a class="launcher-item user-menu-item" role="menuitem" href="/account">Account settings</a>
|
|
52
|
+
<a class="launcher-item user-menu-item" role="menuitem" href="/workspace">Workspace settings</a>
|
|
53
|
+
<div class="user-menu-sep" role="separator"></div>
|
|
54
|
+
<a class="launcher-item user-menu-item" role="menuitem" href="/logout">Sign out</a>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</header>
|
|
59
|
+
<main class="main"><div class="content">Page content</div></main>
|
|
60
|
+
</div>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<!-- App shell, canonical markup. Import the logo from @fikar-ai/design/brand/; the src below is a placeholder. -->
|
|
2
|
+
<div class="shell with-topbar" id="shell">
|
|
3
|
+
<aside class="sidebar" id="sidebar">
|
|
4
|
+
<div class="brand">
|
|
5
|
+
<img class="logo-light" src="/brand/fikar-logo.svg" alt="">
|
|
6
|
+
<img class="logo-dark" src="/brand/fikar-logo-reversed.svg" alt="">
|
|
7
|
+
<span class="word">FIKAR</span>
|
|
8
|
+
<button class="shell-close iconbtn" type="button" aria-label="Close navigation">×</button>
|
|
9
|
+
</div>
|
|
10
|
+
<nav class="side" aria-label="Main">
|
|
11
|
+
<a class="nav-item active" href="/" title="Home" aria-current="page">
|
|
12
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 11l9-8 9 8"/><path d="M5 10v10h14V10"/></svg>
|
|
13
|
+
<span class="nav-label">Home</span>
|
|
14
|
+
</a>
|
|
15
|
+
<a class="nav-item" href="/settings" title="Settings">
|
|
16
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3"/></svg>
|
|
17
|
+
<span class="nav-label">Settings</span>
|
|
18
|
+
</a>
|
|
19
|
+
</nav>
|
|
20
|
+
<div class="side-foot">
|
|
21
|
+
<span class="avatar" aria-hidden="true">AM</span>
|
|
22
|
+
<div class="meta"><b>Alex Morgan</b><br><span>Admin</span></div>
|
|
23
|
+
</div>
|
|
24
|
+
<button class="shell-collapse" type="button" aria-controls="sidebar" aria-pressed="false" title="Collapse sidebar">
|
|
25
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
|
|
26
|
+
<span class="nav-label">Collapse</span>
|
|
27
|
+
</button>
|
|
28
|
+
</aside>
|
|
29
|
+
<header class="shell-topbar">
|
|
30
|
+
<button class="shell-menu" type="button" aria-label="Open navigation" aria-controls="sidebar" aria-expanded="false">
|
|
31
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16"/></svg>
|
|
32
|
+
</button>
|
|
33
|
+
<div class="brand"><img class="logo-light" src="/brand/fikar-logo.svg" alt=""><img class="logo-dark" src="/brand/fikar-logo-reversed.svg" alt=""><span class="word">FIKAR</span></div>
|
|
34
|
+
<div class="cluster">
|
|
35
|
+
<!-- Launcher (see launcher.html, with data-fk-menu), theme menu (see theme-menu.html), then the user menu (see user-menu.html), in that order.
|
|
36
|
+
Every menu here carries data-fk-menu, so shell.js runs all three. A page must not mix these with menus it wires itself. -->
|
|
37
|
+
<div class="launcher" data-fk-menu>
|
|
38
|
+
<button class="launcher-btn" type="button" aria-haspopup="menu" aria-expanded="false" aria-label="Switch app">
|
|
39
|
+
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
40
|
+
<circle cx="5" cy="5" r="2"/><circle cx="12" cy="5" r="2"/><circle cx="19" cy="5" r="2"/>
|
|
41
|
+
<circle cx="5" cy="12" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="19" cy="12" r="2"/>
|
|
42
|
+
<circle cx="5" cy="19" r="2"/><circle cx="12" cy="19" r="2"/><circle cx="19" cy="19" r="2"/>
|
|
43
|
+
</svg>
|
|
44
|
+
</button>
|
|
45
|
+
<div class="launcher-panel launcher-apps" role="menu">
|
|
46
|
+
<a class="launcher-item current" role="menuitem" href="https://chat.fikar.ai" aria-current="page">
|
|
47
|
+
<span class="launcher-tile" aria-hidden="true"><svg class="app-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg></span>Chat
|
|
48
|
+
</a>
|
|
49
|
+
<a class="launcher-item" role="menuitem" href="https://platform.fikar.ai">
|
|
50
|
+
<span class="launcher-tile" aria-hidden="true"><svg class="app-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="21" x2="14" y1="4" y2="4"/><line x1="10" x2="3" y1="4" y2="4"/><line x1="21" x2="12" y1="12" y2="12"/><line x1="8" x2="3" y1="12" y2="12"/><line x1="21" x2="16" y1="20" y2="20"/><line x1="12" x2="3" y1="20" y2="20"/><line x1="14" x2="14" y1="2" y2="6"/><line x1="8" x2="8" y1="10" y2="14"/><line x1="16" x2="16" y1="18" y2="22"/></svg></span>Platform
|
|
51
|
+
</a>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="launcher" data-fk-menu>
|
|
55
|
+
<button class="launcher-btn theme-menu-btn" type="button" aria-haspopup="menu" aria-expanded="false" aria-label="Choose theme">
|
|
56
|
+
<svg class="theme-icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
57
|
+
<circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/>
|
|
58
|
+
</svg>
|
|
59
|
+
<svg class="theme-icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
60
|
+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
|
61
|
+
</svg>
|
|
62
|
+
</button>
|
|
63
|
+
<div class="launcher-panel theme-menu-panel" role="menu" aria-label="Theme">
|
|
64
|
+
<button class="launcher-item theme-menu-item" type="button" role="menuitemradio" aria-checked="false" data-value="light">Light</button>
|
|
65
|
+
<button class="launcher-item theme-menu-item" type="button" role="menuitemradio" aria-checked="false" data-value="dark">Dark</button>
|
|
66
|
+
<button class="launcher-item theme-menu-item current" type="button" role="menuitemradio" aria-checked="true" data-value="system">System</button>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="launcher" data-fk-menu>
|
|
70
|
+
<button class="user-menu-btn" type="button" aria-haspopup="menu" aria-expanded="false" aria-label="Open account menu" data-initials="AM">
|
|
71
|
+
<span class="avatar" aria-hidden="true">AM</span>
|
|
72
|
+
</button>
|
|
73
|
+
<div class="launcher-panel user-menu-panel" role="menu">
|
|
74
|
+
<div class="user-menu-id">
|
|
75
|
+
<span class="user-menu-name">Alex Morgan</span>
|
|
76
|
+
<span class="user-menu-email">alex@example.com</span>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="user-menu-sep" role="separator"></div>
|
|
79
|
+
<a class="launcher-item user-menu-item" role="menuitem" href="/account">Account settings</a>
|
|
80
|
+
<a class="launcher-item user-menu-item" role="menuitem" href="/workspace">Workspace settings</a>
|
|
81
|
+
<div class="user-menu-sep" role="separator"></div>
|
|
82
|
+
<a class="launcher-item user-menu-item" role="menuitem" href="/logout">Sign out</a>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</header>
|
|
87
|
+
<div class="shell-scrim" hidden></div>
|
|
88
|
+
<main class="main"><div class="content">Page content</div></main>
|
|
89
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<!-- Status badges: .badge plus one of .b-success, .b-warning, .b-destructive or .b-muted. A dot in the status colour and the status as a plain word, so a
|
|
2
|
+
surface that shows a connection, a rebuild or a job says it the same way. The word is in the text colour and only the dot takes the role colour,
|
|
3
|
+
which is what keeps the word at 4.5:1 in both themes. The dot is there to be scanned and the word carries the status, so never leave the word out.
|
|
4
|
+
The five words below are the rebuild history's, and the class is the colour: Ready is success, Rebuilding and Interrupted are warning, Failed is
|
|
5
|
+
destructive and Skipped is muted. .b-risk, .b-action and .b-incident are different badges, tinted signal types, and stay as they are. -->
|
|
6
|
+
<span class="badge b-success">Ready</span>
|
|
7
|
+
<span class="badge b-warning">Rebuilding</span>
|
|
8
|
+
<span class="badge b-warning">Interrupted</span>
|
|
9
|
+
<span class="badge b-destructive">Failed</span>
|
|
10
|
+
<span class="badge b-muted">Skipped</span>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<!-- Theme menu: the sun or moon button and a panel of three choices, second in the top bar cluster, after the launcher and before the user menu.
|
|
2
|
+
Shown with System chosen. The chosen row has .current and aria-checked="true", and the other two have aria-checked="false".
|
|
3
|
+
Both icons are always in the button and the CSS shows the one that matches the theme on the root (.dark or [data-theme='dark']),
|
|
4
|
+
so the right icon is there on first paint and no script decides it. The menu stores nothing. Choosing a row lets shell.js mark it, then
|
|
5
|
+
it sends a bubbling fk-theme-change event from the root with the row's data-value in detail.value, and the page applies and saves the theme.
|
|
6
|
+
data-fk-menu opts in to the behaviour in shell.js; leave it off when the page wires the menu itself. -->
|
|
7
|
+
<div class="launcher" data-fk-menu>
|
|
8
|
+
<button class="launcher-btn theme-menu-btn" type="button" aria-haspopup="menu" aria-expanded="false" aria-label="Choose theme">
|
|
9
|
+
<svg class="theme-icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
10
|
+
<circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/>
|
|
11
|
+
</svg>
|
|
12
|
+
<svg class="theme-icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
13
|
+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
|
14
|
+
</svg>
|
|
15
|
+
</button>
|
|
16
|
+
<div class="launcher-panel theme-menu-panel" role="menu" aria-label="Theme">
|
|
17
|
+
<button class="launcher-item theme-menu-item" type="button" role="menuitemradio" aria-checked="false" data-value="light">Light</button>
|
|
18
|
+
<button class="launcher-item theme-menu-item" type="button" role="menuitemradio" aria-checked="false" data-value="dark">Dark</button>
|
|
19
|
+
<button class="launcher-item theme-menu-item current" type="button" role="menuitemradio" aria-checked="true" data-value="system">System</button>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<!-- Relative time: a <time> with class fk-time. The text is the short wording, the exact time is in title so a hover shows it, and datetime is the machine
|
|
2
|
+
value. The page writes all three, and FikarShell.formatRelative(datetime) and FikarShell.formatExact(datetime) give the two texts, so every surface
|
|
3
|
+
says "just now", "12 min ago", "4 h ago" and "22 Sep, 08:16" the same way. Below, one of each, for the moment 2026-09-30T12:16:00Z read in UTC.
|
|
4
|
+
The text stays as it was written until the page writes it again (@fikar-ai/design-react's RelativeTime does that on a timer). The exact time is a title
|
|
5
|
+
attribute and not .fk-tooltip, because .fk-tooltip has no script behind it on a plain page and a title needs none. -->
|
|
6
|
+
<time class="fk-time" datetime="2026-09-30T12:16:00Z" title="30 Sep, 12:16">just now</time>
|
|
7
|
+
<time class="fk-time" datetime="2026-09-30T12:04:00Z" title="30 Sep, 12:04">12 min ago</time>
|
|
8
|
+
<time class="fk-time" datetime="2026-09-30T08:16:00Z" title="30 Sep, 08:16">4 h ago</time>
|
|
9
|
+
<time class="fk-time" datetime="2026-09-22T08:16:00Z" title="22 Sep, 08:16">22 Sep, 08:16</time>
|