@adaas/are-html 0.0.22 → 0.0.24
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/dist/browser/index.d.mts +194 -10
- package/dist/browser/index.mjs +696 -245
- package/dist/browser/index.mjs.map +1 -1
- package/dist/node/{AreBinding.attribute-doUvtOjc.d.mts → AreBinding.attribute-BWzEIw6H.d.mts} +45 -0
- package/dist/node/{AreBinding.attribute-Bm5LlOyE.d.ts → AreBinding.attribute-GpT-5Qmf.d.ts} +45 -0
- package/dist/node/attributes/AreBinding.attribute.d.mts +1 -1
- package/dist/node/attributes/AreBinding.attribute.d.ts +1 -1
- package/dist/node/attributes/AreDirective.attribute.d.mts +1 -1
- package/dist/node/attributes/AreDirective.attribute.d.ts +1 -1
- package/dist/node/attributes/AreEvent.attribute.d.mts +1 -1
- package/dist/node/attributes/AreEvent.attribute.d.ts +1 -1
- package/dist/node/attributes/AreStatic.attribute.d.mts +1 -1
- package/dist/node/attributes/AreStatic.attribute.d.ts +1 -1
- package/dist/node/directives/AreDirectiveFor.directive.d.mts +18 -1
- package/dist/node/directives/AreDirectiveFor.directive.d.ts +18 -1
- package/dist/node/directives/AreDirectiveFor.directive.js +57 -9
- package/dist/node/directives/AreDirectiveFor.directive.js.map +1 -1
- package/dist/node/directives/AreDirectiveFor.directive.mjs +57 -9
- package/dist/node/directives/AreDirectiveFor.directive.mjs.map +1 -1
- package/dist/node/directives/AreDirectiveIf.directive.d.mts +18 -2
- package/dist/node/directives/AreDirectiveIf.directive.d.ts +18 -2
- package/dist/node/directives/AreDirectiveIf.directive.js +29 -6
- package/dist/node/directives/AreDirectiveIf.directive.js.map +1 -1
- package/dist/node/directives/AreDirectiveIf.directive.mjs +29 -6
- package/dist/node/directives/AreDirectiveIf.directive.mjs.map +1 -1
- package/dist/node/directives/AreDirectiveShow.directive.d.mts +1 -1
- package/dist/node/directives/AreDirectiveShow.directive.d.ts +1 -1
- package/dist/node/engine/AreHTML.compiler.d.mts +4 -2
- package/dist/node/engine/AreHTML.compiler.d.ts +4 -2
- package/dist/node/engine/AreHTML.compiler.js +11 -4
- package/dist/node/engine/AreHTML.compiler.js.map +1 -1
- package/dist/node/engine/AreHTML.compiler.mjs +11 -4
- package/dist/node/engine/AreHTML.compiler.mjs.map +1 -1
- package/dist/node/engine/AreHTML.constants.d.mts +33 -1
- package/dist/node/engine/AreHTML.constants.d.ts +33 -1
- package/dist/node/engine/AreHTML.constants.js +166 -0
- package/dist/node/engine/AreHTML.constants.js.map +1 -1
- package/dist/node/engine/AreHTML.constants.mjs +165 -1
- package/dist/node/engine/AreHTML.constants.mjs.map +1 -1
- package/dist/node/engine/AreHTML.context.d.mts +66 -0
- package/dist/node/engine/AreHTML.context.d.ts +66 -0
- package/dist/node/engine/AreHTML.context.js +98 -0
- package/dist/node/engine/AreHTML.context.js.map +1 -1
- package/dist/node/engine/AreHTML.context.mjs +98 -0
- package/dist/node/engine/AreHTML.context.mjs.map +1 -1
- package/dist/node/engine/AreHTML.interpreter.d.mts +3 -0
- package/dist/node/engine/AreHTML.interpreter.d.ts +3 -0
- package/dist/node/engine/AreHTML.interpreter.js +66 -10
- package/dist/node/engine/AreHTML.interpreter.js.map +1 -1
- package/dist/node/engine/AreHTML.interpreter.mjs +66 -10
- package/dist/node/engine/AreHTML.interpreter.mjs.map +1 -1
- package/dist/node/engine/AreHTML.lifecycle.d.mts +1 -8
- package/dist/node/engine/AreHTML.lifecycle.d.ts +1 -8
- package/dist/node/engine/AreHTML.lifecycle.js +29 -44
- package/dist/node/engine/AreHTML.lifecycle.js.map +1 -1
- package/dist/node/engine/AreHTML.lifecycle.mjs +29 -44
- package/dist/node/engine/AreHTML.lifecycle.mjs.map +1 -1
- package/dist/node/engine/AreHTML.tokenizer.d.mts +1 -1
- package/dist/node/engine/AreHTML.tokenizer.d.ts +1 -1
- package/dist/node/engine/AreHTML.tokenizer.js +7 -1
- package/dist/node/engine/AreHTML.tokenizer.js.map +1 -1
- package/dist/node/engine/AreHTML.tokenizer.mjs +7 -1
- package/dist/node/engine/AreHTML.tokenizer.mjs.map +1 -1
- package/dist/node/engine/AreHTML.transformer.d.mts +1 -1
- package/dist/node/engine/AreHTML.transformer.d.ts +1 -1
- package/dist/node/index.d.mts +4 -3
- package/dist/node/index.d.ts +4 -3
- package/dist/node/index.js +7 -0
- package/dist/node/index.mjs +1 -0
- package/dist/node/instructions/AddStaticHTML.instruction.d.mts +8 -0
- package/dist/node/instructions/AddStaticHTML.instruction.d.ts +8 -0
- package/dist/node/instructions/AddStaticHTML.instruction.js +31 -0
- package/dist/node/instructions/AddStaticHTML.instruction.js.map +1 -0
- package/dist/node/instructions/AddStaticHTML.instruction.mjs +24 -0
- package/dist/node/instructions/AddStaticHTML.instruction.mjs.map +1 -0
- package/dist/node/instructions/AreHTML.instructions.constants.d.mts +1 -0
- package/dist/node/instructions/AreHTML.instructions.constants.d.ts +1 -0
- package/dist/node/instructions/AreHTML.instructions.constants.js +1 -0
- package/dist/node/instructions/AreHTML.instructions.constants.js.map +1 -1
- package/dist/node/instructions/AreHTML.instructions.constants.mjs +1 -0
- package/dist/node/instructions/AreHTML.instructions.constants.mjs.map +1 -1
- package/dist/node/instructions/AreHTML.instructions.types.d.mts +9 -1
- package/dist/node/instructions/AreHTML.instructions.types.d.ts +9 -1
- package/dist/node/lib/AreDirective/AreDirective.component.d.mts +1 -1
- package/dist/node/lib/AreDirective/AreDirective.component.d.ts +1 -1
- package/dist/node/lib/AreDirective/AreDirective.types.d.mts +1 -1
- package/dist/node/lib/AreDirective/AreDirective.types.d.ts +1 -1
- package/dist/node/lib/AreHTML/AreHTML.tokenizer.d.mts +1 -1
- package/dist/node/lib/AreHTML/AreHTML.tokenizer.d.ts +1 -1
- package/dist/node/lib/AreHTMLAttribute/AreHTML.attribute.d.mts +1 -1
- package/dist/node/lib/AreHTMLAttribute/AreHTML.attribute.d.ts +1 -1
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.d.mts +1 -1
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.d.ts +1 -1
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.js +51 -0
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.js.map +1 -1
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.mjs +51 -0
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.mjs.map +1 -1
- package/dist/node/lib/AreRoot/AreRoot.component.js.map +1 -1
- package/dist/node/lib/AreRoot/AreRoot.component.mjs.map +1 -1
- package/dist/node/nodes/AreComment.d.mts +1 -1
- package/dist/node/nodes/AreComment.d.ts +1 -1
- package/dist/node/nodes/AreComponent.d.mts +1 -1
- package/dist/node/nodes/AreComponent.d.ts +1 -1
- package/dist/node/nodes/AreInterpolation.d.mts +1 -1
- package/dist/node/nodes/AreInterpolation.d.ts +1 -1
- package/dist/node/nodes/AreRoot.d.mts +1 -1
- package/dist/node/nodes/AreRoot.d.ts +1 -1
- package/dist/node/nodes/AreText.d.mts +1 -1
- package/dist/node/nodes/AreText.d.ts +1 -1
- package/examples/dashboard/concept.ts +1 -1
- package/examples/dashboard/dist/index.html +1 -1
- package/examples/dashboard/dist/{mqh9ryml-xat335.js → mqiw5sqa-ypckmj.js} +403 -57
- package/examples/for-perf/dist/index.html +1 -1
- package/examples/for-perf/dist/{mqh9ryfo-6a8d0o.js → mqp8i2py-vltsx0.js} +3030 -2474
- package/examples/lazy-loading/README.md +76 -0
- package/examples/lazy-loading/concept.ts +55 -0
- package/examples/lazy-loading/containers/UI.container.ts +215 -0
- package/examples/lazy-loading/dist/app.js +3803 -0
- package/examples/{for-perf/dist/mqh9ryfq-4pf5cv.js → lazy-loading/dist/chunks/chunk-6K72IBO4.js} +2708 -5476
- package/examples/lazy-loading/dist/index.html +36 -0
- package/examples/lazy-loading/dist/lazy/about-page.js +59 -0
- package/examples/lazy-loading/dist/lazy/reports-page.js +65 -0
- package/examples/lazy-loading/dist/lazy/settings-page.js +54 -0
- package/examples/lazy-loading/public/index.html +36 -0
- package/examples/lazy-loading/src/components/AppShell.component.ts +44 -0
- package/examples/lazy-loading/src/components/HomePage.component.ts +59 -0
- package/examples/lazy-loading/src/components/LazyOutlet.component.ts +108 -0
- package/examples/lazy-loading/src/components/NavBar.component.ts +98 -0
- package/examples/lazy-loading/src/concept.ts +116 -0
- package/examples/lazy-loading/src/lazy/AboutPage.component.ts +54 -0
- package/examples/lazy-loading/src/lazy/ReportsPage.component.ts +56 -0
- package/examples/lazy-loading/src/lazy/SettingsPage.component.ts +45 -0
- package/examples/lazy-loading/src/runtime/ComponentManifest.fragment.ts +61 -0
- package/examples/lazy-loading/src/runtime/LazyComponentResolver.fragment.ts +77 -0
- package/examples/os-desktop/README.md +91 -0
- package/examples/os-desktop/concept.ts +54 -0
- package/examples/os-desktop/containers/OS.container.ts +198 -0
- package/examples/os-desktop/containers/apps/AppBackend.ts +29 -0
- package/examples/os-desktop/containers/apps/GanttApp.backend.ts +56 -0
- package/examples/os-desktop/containers/apps/MarketingApp.backend.ts +68 -0
- package/examples/os-desktop/dist/app.js +4410 -0
- package/examples/os-desktop/dist/apps/gantt/app.js +271 -0
- package/examples/os-desktop/dist/apps/marketing/app.js +346 -0
- package/examples/{for-perf/dist/mqh9ryde-m243t8.js → os-desktop/dist/chunks/chunk-6K72IBO4.js} +2708 -5476
- package/examples/os-desktop/dist/chunks/chunk-EIIGUL6N.js +30 -0
- package/examples/os-desktop/dist/chunks/chunk-WOH7L5UR.js +30 -0
- package/examples/os-desktop/dist/index.html +33 -0
- package/examples/os-desktop/public/index.html +33 -0
- package/examples/os-desktop/src/apps/gantt/GanttApp.component.ts +41 -0
- package/examples/os-desktop/src/apps/gantt/GanttChart.component.ts +126 -0
- package/examples/os-desktop/src/apps/gantt/GanttStore.ts +47 -0
- package/examples/os-desktop/src/apps/gantt/GanttToolbar.component.ts +73 -0
- package/examples/os-desktop/src/apps/gantt/index.ts +13 -0
- package/examples/os-desktop/src/apps/marketing/MarketingApp.component.ts +53 -0
- package/examples/os-desktop/src/apps/marketing/MarketingStore.ts +34 -0
- package/examples/os-desktop/src/apps/marketing/PostEditor.component.ts +153 -0
- package/examples/os-desktop/src/apps/marketing/PostPreview.component.ts +110 -0
- package/examples/os-desktop/src/apps/marketing/index.ts +16 -0
- package/examples/os-desktop/src/concept.ts +126 -0
- package/examples/os-desktop/src/os/AppStage.component.ts +112 -0
- package/examples/os-desktop/src/os/AppWindow.component.ts +102 -0
- package/examples/os-desktop/src/os/Desktop.component.ts +106 -0
- package/examples/os-desktop/src/os/Dock.component.ts +174 -0
- package/examples/os-desktop/src/os/Hud.component.ts +83 -0
- package/examples/os-desktop/src/os/Launchpad.component.ts +191 -0
- package/examples/os-desktop/src/os/MenuBar.component.ts +156 -0
- package/examples/os-desktop/src/runtime/AppComponentResolver.fragment.ts +121 -0
- package/examples/os-desktop/src/runtime/AppRegistry.fragment.ts +104 -0
- package/examples/os-desktop/src/signals/MouseState.signal.ts +34 -0
- package/examples/os-desktop/src/signals/OSRoute.signal.ts +37 -0
- package/examples/os-desktop/src/signals/SelectionState.signal.ts +34 -0
- package/examples/signal-routing/dist/index.html +1 -1
- package/examples/signal-routing/dist/{mqh9ryc9-dkcbkx.js → mqp8hgce-4d6rh0.js} +3196 -2640
- package/package.json +13 -9
- package/src/directives/AreDirectiveFor.directive.ts +99 -16
- package/src/directives/AreDirectiveIf.directive.ts +33 -4
- package/src/engine/AreHTML.compiler.ts +25 -2
- package/src/engine/AreHTML.constants.ts +142 -0
- package/src/engine/AreHTML.context.ts +112 -0
- package/src/engine/AreHTML.interpreter.ts +114 -13
- package/src/engine/AreHTML.lifecycle.ts +81 -74
- package/src/engine/AreHTML.tokenizer.ts +30 -1
- package/src/index.ts +1 -0
- package/src/instructions/AddStaticHTML.instruction.ts +23 -0
- package/src/instructions/AreHTML.instructions.constants.ts +1 -0
- package/src/instructions/AreHTML.instructions.types.ts +9 -0
- package/src/lib/AreHTMLNode/AreHTMLNode.ts +74 -0
- package/src/lib/AreRoot/AreRoot.component.ts +3 -3
- package/tests/PropPropagation.test.ts +181 -0
- package/tests/StaticIsland.test.ts +115 -0
- package/tests/jest.setup.ts +11 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { A_Caller, A_Inject } from "@adaas/a-concept";
|
|
2
|
+
import { A_SignalBus } from "@adaas/a-utils/a-signal";
|
|
3
|
+
import { Are, AreEvent, AreNode } from "@adaas/are";
|
|
4
|
+
import { AreHTMLNode } from "src";
|
|
5
|
+
import { AppRegistry } from "../runtime/AppRegistry.fragment";
|
|
6
|
+
import { OSRoute } from "../signals/OSRoute.signal";
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Dock — the bottom app launcher.
|
|
11
|
+
*
|
|
12
|
+
* Shows the currently installed apps plus a Launchpad (+) button. Clicking an
|
|
13
|
+
* app dispatches an {@link OSRoute} to focus it; the Dock itself also listens
|
|
14
|
+
* for OSRoute so a freshly installed app reveals its icon and the running app's
|
|
15
|
+
* running-dot lights up.
|
|
16
|
+
*
|
|
17
|
+
* Every available app gets a (hidden) button wired up front, so the engine
|
|
18
|
+
* binds its `@click` handler once at mount. Reacting to a route signal is then
|
|
19
|
+
* a cheap imperative DOM toggle — no subtree teardown, no re-binding.
|
|
20
|
+
*/
|
|
21
|
+
export class OsDock extends Are {
|
|
22
|
+
|
|
23
|
+
protected _route: string = document.location.pathname || '/';
|
|
24
|
+
|
|
25
|
+
@Are.Template
|
|
26
|
+
template(
|
|
27
|
+
@A_Inject(A_Caller) node: AreNode,
|
|
28
|
+
@A_Inject(AppRegistry) registry: AppRegistry,
|
|
29
|
+
) {
|
|
30
|
+
node.setContent(this.build(registry));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@Are.Signal(OSRoute)
|
|
34
|
+
onRoute(
|
|
35
|
+
@A_Inject(OSRoute) signal: OSRoute,
|
|
36
|
+
@A_Inject(AppRegistry) registry: AppRegistry,
|
|
37
|
+
) {
|
|
38
|
+
this._route = signal.path;
|
|
39
|
+
const activeId = this._route.match(/^\/app\/([^/]+)/)?.[1];
|
|
40
|
+
|
|
41
|
+
let anyVisible = false;
|
|
42
|
+
for (const app of registry.available()) {
|
|
43
|
+
const btn = document.getElementById(`dock-app-${app.id}`);
|
|
44
|
+
if (!btn) continue;
|
|
45
|
+
if (registry.isInstalled(app.id)) {
|
|
46
|
+
btn.hidden = false;
|
|
47
|
+
anyVisible = true;
|
|
48
|
+
}
|
|
49
|
+
btn.classList.toggle('running', app.id === activeId);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const sep = document.getElementById('dock-sep');
|
|
53
|
+
if (sep) sep.hidden = !anyVisible;
|
|
54
|
+
|
|
55
|
+
const lp = document.getElementById('dock-launchpad');
|
|
56
|
+
if (lp) lp.classList.toggle('running', this._route === '/launchpad');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@Are.EventHandler
|
|
60
|
+
open(
|
|
61
|
+
@A_Inject(AreEvent) event: AreEvent,
|
|
62
|
+
@A_Inject(A_SignalBus) bus: A_SignalBus,
|
|
63
|
+
) {
|
|
64
|
+
(event.get('native') as MouseEvent)?.preventDefault();
|
|
65
|
+
const id = event.get('args')?.[0] as string;
|
|
66
|
+
if (!id) return;
|
|
67
|
+
const path = `/app/${id}`;
|
|
68
|
+
history.pushState({}, '', path);
|
|
69
|
+
bus.next(new OSRoute(path));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@Are.EventHandler
|
|
73
|
+
launchpad(
|
|
74
|
+
@A_Inject(AreEvent) event: AreEvent,
|
|
75
|
+
@A_Inject(A_SignalBus) bus: A_SignalBus,
|
|
76
|
+
) {
|
|
77
|
+
(event.get('native') as MouseEvent)?.preventDefault();
|
|
78
|
+
history.pushState({}, '', '/launchpad');
|
|
79
|
+
bus.next(new OSRoute('/launchpad'));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
protected build(registry: AppRegistry): string {
|
|
83
|
+
const activeId = this._route.match(/^\/app\/([^/]+)/)?.[1];
|
|
84
|
+
|
|
85
|
+
const apps = registry.available().map(app => {
|
|
86
|
+
const installed = registry.isInstalled(app.id);
|
|
87
|
+
const running = app.id === activeId ? 'running' : '';
|
|
88
|
+
return `
|
|
89
|
+
<button id="dock-app-${app.id}" class="dock-item ${running}" @click="$open('${app.id}')" title="${app.name}"${installed ? '' : ' hidden'}>
|
|
90
|
+
<span class="dock-glyph" style="--accent:${app.accent}">${app.icon}</span>
|
|
91
|
+
<span class="dock-dot"></span>
|
|
92
|
+
</button>
|
|
93
|
+
`;
|
|
94
|
+
}).join('');
|
|
95
|
+
|
|
96
|
+
const anyInstalled = registry.installed().length > 0;
|
|
97
|
+
const launchpadActive = this._route === '/launchpad' ? 'running' : '';
|
|
98
|
+
|
|
99
|
+
return `
|
|
100
|
+
<div class="dock">
|
|
101
|
+
${apps}
|
|
102
|
+
<span class="dock-sep" id="dock-sep"${anyInstalled ? '' : ' hidden'}></span>
|
|
103
|
+
<button id="dock-launchpad" class="dock-item ${launchpadActive}" @click="$launchpad()" title="Launchpad — install apps">
|
|
104
|
+
<span class="dock-glyph dock-plus">+</span>
|
|
105
|
+
<span class="dock-dot"></span>
|
|
106
|
+
</button>
|
|
107
|
+
</div>
|
|
108
|
+
`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@Are.Styles
|
|
112
|
+
styles(@A_Inject(A_Caller) node: AreHTMLNode) {
|
|
113
|
+
node.setStyles(`
|
|
114
|
+
.dock {
|
|
115
|
+
position: absolute;
|
|
116
|
+
left: 50%;
|
|
117
|
+
bottom: 14px;
|
|
118
|
+
transform: translateX(-50%);
|
|
119
|
+
display: flex;
|
|
120
|
+
align-items: flex-end;
|
|
121
|
+
gap: 10px;
|
|
122
|
+
padding: 8px 12px;
|
|
123
|
+
border-radius: 22px;
|
|
124
|
+
background: rgba(30, 24, 48, 0.45);
|
|
125
|
+
backdrop-filter: blur(24px) saturate(180%);
|
|
126
|
+
-webkit-backdrop-filter: blur(24px) saturate(180%);
|
|
127
|
+
border: 1px solid rgba(255,255,255,0.12);
|
|
128
|
+
box-shadow: 0 18px 50px rgba(0,0,0,0.45);
|
|
129
|
+
z-index: 95;
|
|
130
|
+
}
|
|
131
|
+
.dock-item {
|
|
132
|
+
position: relative;
|
|
133
|
+
display: flex;
|
|
134
|
+
flex-direction: column;
|
|
135
|
+
align-items: center;
|
|
136
|
+
gap: 4px;
|
|
137
|
+
border: none;
|
|
138
|
+
background: none;
|
|
139
|
+
cursor: pointer;
|
|
140
|
+
padding: 0;
|
|
141
|
+
}
|
|
142
|
+
/* The HTML 'hidden' attribute must win over 'display: flex' so an
|
|
143
|
+
uninstalled app icon (and the separator) stays out of the dock. */
|
|
144
|
+
.dock-item[hidden], #dock-sep[hidden] { display: none !important; }
|
|
145
|
+
.dock-glyph {
|
|
146
|
+
width: 52px; height: 52px;
|
|
147
|
+
display: flex; align-items: center; justify-content: center;
|
|
148
|
+
font-size: 28px;
|
|
149
|
+
border-radius: 14px;
|
|
150
|
+
background: linear-gradient(160deg, color-mix(in srgb, var(--accent, #7c6fd6) 85%, white 0%), color-mix(in srgb, var(--accent, #7c6fd6) 70%, black 18%));
|
|
151
|
+
box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), 0 6px 14px rgba(0,0,0,0.35);
|
|
152
|
+
transition: transform 0.18s ease;
|
|
153
|
+
}
|
|
154
|
+
.dock-plus {
|
|
155
|
+
background: rgba(255,255,255,0.12);
|
|
156
|
+
color: #f5f5f7;
|
|
157
|
+
font-size: 26px;
|
|
158
|
+
font-weight: 300;
|
|
159
|
+
}
|
|
160
|
+
.dock-item:hover .dock-glyph { transform: translateY(-10px) scale(1.12); }
|
|
161
|
+
.dock-dot {
|
|
162
|
+
width: 4px; height: 4px; border-radius: 50%;
|
|
163
|
+
background: transparent;
|
|
164
|
+
}
|
|
165
|
+
.dock-item.running .dock-dot { background: rgba(245,245,247,0.85); }
|
|
166
|
+
.dock-sep {
|
|
167
|
+
width: 1px;
|
|
168
|
+
align-self: stretch;
|
|
169
|
+
margin: 6px 2px;
|
|
170
|
+
background: rgba(255,255,255,0.16);
|
|
171
|
+
}
|
|
172
|
+
`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { A_Caller, A_Inject } from "@adaas/a-concept";
|
|
2
|
+
import { Are, AreNode } from "@adaas/are";
|
|
3
|
+
import { AreHTMLNode } from "src";
|
|
4
|
+
import { MouseState } from "../signals/MouseState.signal";
|
|
5
|
+
import { SelectionState } from "../signals/SelectionState.signal";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Hud — a small translucent read-out pinned to the bottom-left corner.
|
|
10
|
+
*
|
|
11
|
+
* It exists purely to visualise that the bus carries more than route signals:
|
|
12
|
+
* - {@link MouseState} → live X / Y coordinates (high-frequency, throttled).
|
|
13
|
+
* - {@link SelectionState} → the number of characters currently selected.
|
|
14
|
+
*
|
|
15
|
+
* Because this is the only component that re-renders on every (throttled) mouse
|
|
16
|
+
* move, the cost of the high-frequency signal is isolated to a tiny subtree.
|
|
17
|
+
*/
|
|
18
|
+
export class OsHud extends Are {
|
|
19
|
+
|
|
20
|
+
protected _x: number = 0;
|
|
21
|
+
protected _y: number = 0;
|
|
22
|
+
protected _selection: number = 0;
|
|
23
|
+
|
|
24
|
+
@Are.Template
|
|
25
|
+
template(@A_Inject(A_Caller) node: AreNode) {
|
|
26
|
+
node.setContent(this.build());
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@Are.Signal(MouseState)
|
|
30
|
+
onMouse(@A_Inject(MouseState) signal: MouseState) {
|
|
31
|
+
this._x = signal.x;
|
|
32
|
+
this._y = signal.y;
|
|
33
|
+
const x = document.getElementById('hud-x');
|
|
34
|
+
const y = document.getElementById('hud-y');
|
|
35
|
+
if (x) x.textContent = String(this._x);
|
|
36
|
+
if (y) y.textContent = String(this._y);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@Are.Signal(SelectionState)
|
|
40
|
+
onSelection(@A_Inject(SelectionState) signal: SelectionState) {
|
|
41
|
+
this._selection = signal.length;
|
|
42
|
+
const sel = document.getElementById('hud-sel');
|
|
43
|
+
if (sel) sel.textContent = String(this._selection);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
protected build(): string {
|
|
47
|
+
return `
|
|
48
|
+
<div class="hud">
|
|
49
|
+
<span class="hud-row"><b>signals</b></span>
|
|
50
|
+
<span class="hud-row">MouseState <i>x</i> <span id="hud-x">${this._x}</span> <i>y</i> <span id="hud-y">${this._y}</span></span>
|
|
51
|
+
<span class="hud-row">SelectionState <i>len</i> <span id="hud-sel">${this._selection}</span></span>
|
|
52
|
+
</div>
|
|
53
|
+
`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@Are.Styles
|
|
57
|
+
styles(@A_Inject(A_Caller) node: AreHTMLNode) {
|
|
58
|
+
node.setStyles(`
|
|
59
|
+
.hud {
|
|
60
|
+
position: absolute;
|
|
61
|
+
left: 16px;
|
|
62
|
+
bottom: 104px;
|
|
63
|
+
display: flex;
|
|
64
|
+
flex-direction: column;
|
|
65
|
+
gap: 2px;
|
|
66
|
+
padding: 10px 14px;
|
|
67
|
+
border-radius: 12px;
|
|
68
|
+
background: rgba(12, 10, 24, 0.5);
|
|
69
|
+
backdrop-filter: blur(14px);
|
|
70
|
+
-webkit-backdrop-filter: blur(14px);
|
|
71
|
+
border: 1px solid rgba(255,255,255,0.08);
|
|
72
|
+
font-size: 11px;
|
|
73
|
+
font-family: ui-monospace, 'SF Mono', Menlo, monospace;
|
|
74
|
+
color: rgba(245,245,247,0.85);
|
|
75
|
+
z-index: 90;
|
|
76
|
+
pointer-events: none;
|
|
77
|
+
}
|
|
78
|
+
.hud b { color: #c9b8ff; text-transform: uppercase; letter-spacing: 0.08em; font-size: 10px; }
|
|
79
|
+
.hud i { color: #8b7fb0; font-style: normal; }
|
|
80
|
+
.hud-row { white-space: nowrap; }
|
|
81
|
+
`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { A_Inject } from "@adaas/a-concept";
|
|
2
|
+
import { A_SignalBus } from "@adaas/a-utils/a-signal";
|
|
3
|
+
import { A_Logger } from "@adaas/a-utils/a-logger";
|
|
4
|
+
import { Are, AreEvent, AreNode } from "@adaas/are";
|
|
5
|
+
import { A_Caller } from "@adaas/a-concept";
|
|
6
|
+
import { AreHTMLNode } from "src";
|
|
7
|
+
import { AppRegistry } from "../runtime/AppRegistry.fragment";
|
|
8
|
+
import { AppComponentResolver } from "../runtime/AppComponentResolver.fragment";
|
|
9
|
+
import { OSRoute } from "../signals/OSRoute.signal";
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Launchpad — the OS "App Store" overlay.
|
|
14
|
+
*
|
|
15
|
+
* Lists every app the backend offers. For an app the user has not installed it
|
|
16
|
+
* shows **Install**; installing it:
|
|
17
|
+
* 1. records the app in the {@link AppRegistry} (it now shows up in the dock),
|
|
18
|
+
* 2. warms its bundle via {@link AppComponentResolver.preload} — i.e. "adding
|
|
19
|
+
* the app loads all its components" (one network fetch for the whole app),
|
|
20
|
+
* 3. routes to `/app/<id>`, opening the freshly installed app.
|
|
21
|
+
*
|
|
22
|
+
* Already-installed apps show **Open** and simply route to them. The engine
|
|
23
|
+
* registers each component lazily on first render (instant, since preload
|
|
24
|
+
* already fetched the bundle).
|
|
25
|
+
*/
|
|
26
|
+
export class OsLaunchpad extends Are {
|
|
27
|
+
|
|
28
|
+
@Are.Template
|
|
29
|
+
template(
|
|
30
|
+
@A_Inject(A_Caller) node: AreNode,
|
|
31
|
+
@A_Inject(AppRegistry) registry: AppRegistry,
|
|
32
|
+
) {
|
|
33
|
+
node.setContent(this.build(registry));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@Are.EventHandler
|
|
37
|
+
async install(
|
|
38
|
+
@A_Inject(AreEvent) event: AreEvent,
|
|
39
|
+
@A_Inject(A_SignalBus) bus: A_SignalBus,
|
|
40
|
+
@A_Inject(AppRegistry) registry: AppRegistry,
|
|
41
|
+
@A_Inject(AppComponentResolver) resolver: AppComponentResolver,
|
|
42
|
+
@A_Inject(A_Logger) logger: A_Logger,
|
|
43
|
+
) {
|
|
44
|
+
(event.get('native') as MouseEvent)?.preventDefault();
|
|
45
|
+
const id = event.get('args')?.[0] as string;
|
|
46
|
+
const app = id ? registry.get(id) : undefined;
|
|
47
|
+
if (!app) return;
|
|
48
|
+
|
|
49
|
+
registry.install(app.id);
|
|
50
|
+
|
|
51
|
+
// Fetch the app's entire bundle now — "installing loads all its
|
|
52
|
+
// components". The window will then mount instantly from memory.
|
|
53
|
+
try {
|
|
54
|
+
await resolver.preload(app);
|
|
55
|
+
logger.log('green', `Installed "${app.name}" (${app.components.length} components loaded).`);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
logger.error(error);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const path = `/app/${app.id}`;
|
|
61
|
+
history.pushState({}, '', path);
|
|
62
|
+
bus.next(new OSRoute(path));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@Are.EventHandler
|
|
66
|
+
open(
|
|
67
|
+
@A_Inject(AreEvent) event: AreEvent,
|
|
68
|
+
@A_Inject(A_SignalBus) bus: A_SignalBus,
|
|
69
|
+
) {
|
|
70
|
+
(event.get('native') as MouseEvent)?.preventDefault();
|
|
71
|
+
const id = event.get('args')?.[0] as string;
|
|
72
|
+
if (!id) return;
|
|
73
|
+
const path = `/app/${id}`;
|
|
74
|
+
history.pushState({}, '', path);
|
|
75
|
+
bus.next(new OSRoute(path));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@Are.EventHandler
|
|
79
|
+
close(
|
|
80
|
+
@A_Inject(AreEvent) event: AreEvent,
|
|
81
|
+
@A_Inject(A_SignalBus) bus: A_SignalBus,
|
|
82
|
+
) {
|
|
83
|
+
(event.get('native') as MouseEvent)?.preventDefault();
|
|
84
|
+
history.pushState({}, '', '/desktop');
|
|
85
|
+
bus.next(new OSRoute('/desktop'));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
protected build(registry: AppRegistry): string {
|
|
89
|
+
const tiles = registry.available().map(app => {
|
|
90
|
+
const installed = registry.isInstalled(app.id);
|
|
91
|
+
const action = installed
|
|
92
|
+
? `<button class="lp-btn lp-open" @click="$open('${app.id}')">Open</button>`
|
|
93
|
+
: `<button class="lp-btn lp-install" @click="$install('${app.id}')">Install</button>`;
|
|
94
|
+
|
|
95
|
+
const chips = app.components
|
|
96
|
+
.map(c => `<code><${c.tag}></code>`)
|
|
97
|
+
.join('');
|
|
98
|
+
|
|
99
|
+
return `
|
|
100
|
+
<article class="lp-tile" style="--accent:${app.accent}">
|
|
101
|
+
<div class="lp-icon">${app.icon}</div>
|
|
102
|
+
<h3 class="lp-name">${app.name}</h3>
|
|
103
|
+
<p class="lp-tagline">${app.tagline}</p>
|
|
104
|
+
<div class="lp-meta">
|
|
105
|
+
<span class="lp-bundle">${app.bundle}</span>
|
|
106
|
+
<div class="lp-components">${chips}</div>
|
|
107
|
+
</div>
|
|
108
|
+
${action}
|
|
109
|
+
</article>
|
|
110
|
+
`;
|
|
111
|
+
}).join('');
|
|
112
|
+
|
|
113
|
+
return `
|
|
114
|
+
<div class="lp-backdrop" @click.self="$close()">
|
|
115
|
+
<div class="lp">
|
|
116
|
+
<header class="lp-head">
|
|
117
|
+
<h1>Launchpad</h1>
|
|
118
|
+
<p>Each app is an independent bundle with its own backend and its own set of components. Install one to add it to your dock and load its code.</p>
|
|
119
|
+
</header>
|
|
120
|
+
<div class="lp-grid">${tiles}</div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
@Are.Styles
|
|
127
|
+
styles(@A_Inject(A_Caller) node: AreHTMLNode) {
|
|
128
|
+
node.setStyles(`
|
|
129
|
+
.lp-backdrop {
|
|
130
|
+
position: absolute;
|
|
131
|
+
inset: 0;
|
|
132
|
+
display: flex;
|
|
133
|
+
align-items: center;
|
|
134
|
+
justify-content: center;
|
|
135
|
+
background: rgba(8, 6, 18, 0.55);
|
|
136
|
+
backdrop-filter: blur(26px) saturate(160%);
|
|
137
|
+
-webkit-backdrop-filter: blur(26px) saturate(160%);
|
|
138
|
+
animation: lp-fade 0.2s ease;
|
|
139
|
+
}
|
|
140
|
+
@keyframes lp-fade { from { opacity: 0; } to { opacity: 1; } }
|
|
141
|
+
.lp { width: min(900px, 88vw); max-height: 80vh; overflow: auto; }
|
|
142
|
+
.lp-head { text-align: center; margin-bottom: 30px; }
|
|
143
|
+
.lp-head h1 { font-size: 30px; font-weight: 800; letter-spacing: -0.02em; }
|
|
144
|
+
.lp-head p { margin-top: 10px; color: rgba(245,245,247,0.7); font-size: 14px; max-width: 560px; margin-left: auto; margin-right: auto; line-height: 1.6; }
|
|
145
|
+
.lp-grid {
|
|
146
|
+
display: grid;
|
|
147
|
+
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
|
148
|
+
gap: 18px;
|
|
149
|
+
}
|
|
150
|
+
.lp-tile {
|
|
151
|
+
display: flex;
|
|
152
|
+
flex-direction: column;
|
|
153
|
+
align-items: flex-start;
|
|
154
|
+
gap: 8px;
|
|
155
|
+
padding: 22px;
|
|
156
|
+
border-radius: 18px;
|
|
157
|
+
background: rgba(30, 24, 48, 0.5);
|
|
158
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
159
|
+
}
|
|
160
|
+
.lp-icon {
|
|
161
|
+
width: 56px; height: 56px;
|
|
162
|
+
display: flex; align-items: center; justify-content: center;
|
|
163
|
+
font-size: 30px;
|
|
164
|
+
border-radius: 15px;
|
|
165
|
+
background: linear-gradient(160deg, color-mix(in srgb, var(--accent) 85%, white 0%), color-mix(in srgb, var(--accent) 65%, black 20%));
|
|
166
|
+
box-shadow: inset 0 1px 0 rgba(255,255,255,0.35);
|
|
167
|
+
margin-bottom: 4px;
|
|
168
|
+
}
|
|
169
|
+
.lp-name { font-size: 17px; font-weight: 700; }
|
|
170
|
+
.lp-tagline { font-size: 13px; color: rgba(245,245,247,0.7); line-height: 1.5; }
|
|
171
|
+
.lp-meta { width: 100%; margin: 8px 0 6px; }
|
|
172
|
+
.lp-bundle { font-size: 11px; font-family: ui-monospace, monospace; color: #8b7fb0; }
|
|
173
|
+
.lp-components { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 8px; }
|
|
174
|
+
.lp-components code { font-size: 10px; padding: 2px 6px; border-radius: 6px; background: rgba(255,255,255,0.08); color: #c9b8ff; }
|
|
175
|
+
.lp-btn {
|
|
176
|
+
margin-top: auto;
|
|
177
|
+
align-self: stretch;
|
|
178
|
+
padding: 9px 14px;
|
|
179
|
+
border: none;
|
|
180
|
+
border-radius: 10px;
|
|
181
|
+
font-size: 13px;
|
|
182
|
+
font-weight: 600;
|
|
183
|
+
cursor: pointer;
|
|
184
|
+
transition: filter 0.15s;
|
|
185
|
+
}
|
|
186
|
+
.lp-btn:hover { filter: brightness(1.12); }
|
|
187
|
+
.lp-install { background: var(--accent); color: white; }
|
|
188
|
+
.lp-open { background: rgba(255,255,255,0.14); color: #f5f5f7; }
|
|
189
|
+
`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { A_Caller, A_Inject } from "@adaas/a-concept";
|
|
2
|
+
import { Are, AreNode } from "@adaas/are";
|
|
3
|
+
import { AreHTMLNode } from "src";
|
|
4
|
+
import { AppRegistry } from "../runtime/AppRegistry.fragment";
|
|
5
|
+
import { OSRoute } from "../signals/OSRoute.signal";
|
|
6
|
+
import { SelectionState } from "../signals/SelectionState.signal";
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* MenuBar — the translucent top bar.
|
|
11
|
+
*
|
|
12
|
+
* Demonstrates a component that reacts to TWO independent signal types via
|
|
13
|
+
* typed `@Are.Signal(...)` handlers:
|
|
14
|
+
* - {@link OSRoute} → the active application's name (left side).
|
|
15
|
+
* - {@link SelectionState} → a "N selected" chip (right side).
|
|
16
|
+
*
|
|
17
|
+
* Each handler patches the rendered DOM imperatively, so reacting to a
|
|
18
|
+
* high-frequency selection or route change never tears down and rebuilds the
|
|
19
|
+
* bar's subtree.
|
|
20
|
+
*/
|
|
21
|
+
export class MenuBar extends Are {
|
|
22
|
+
|
|
23
|
+
protected _route: string = document.location.pathname || '/';
|
|
24
|
+
protected _selectionLength: number = 0;
|
|
25
|
+
protected _clockTimer?: ReturnType<typeof setInterval>;
|
|
26
|
+
|
|
27
|
+
@Are.Template
|
|
28
|
+
template(
|
|
29
|
+
@A_Inject(A_Caller) node: AreNode,
|
|
30
|
+
@A_Inject(AppRegistry) registry: AppRegistry,
|
|
31
|
+
) {
|
|
32
|
+
node.setContent(this.build(registry));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@Are.onAfterMount
|
|
36
|
+
onMount() {
|
|
37
|
+
this._clockTimer = setInterval(() => {
|
|
38
|
+
const clock = document.getElementById('mb-clock');
|
|
39
|
+
if (clock) clock.textContent = this.now();
|
|
40
|
+
}, 15000);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Are.onBeforeUnmount
|
|
44
|
+
onUnmount() {
|
|
45
|
+
if (this._clockTimer) clearInterval(this._clockTimer);
|
|
46
|
+
this._clockTimer = undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@Are.Signal(OSRoute)
|
|
50
|
+
onRoute(
|
|
51
|
+
@A_Inject(OSRoute) signal: OSRoute,
|
|
52
|
+
@A_Inject(AppRegistry) registry: AppRegistry,
|
|
53
|
+
) {
|
|
54
|
+
this._route = signal.path;
|
|
55
|
+
const el = document.getElementById('mb-active');
|
|
56
|
+
if (el) {
|
|
57
|
+
const { icon, name } = this.activeTitle(registry);
|
|
58
|
+
el.textContent = `${icon ? icon + ' ' : ''}${name}`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@Are.Signal(SelectionState)
|
|
63
|
+
onSelection(@A_Inject(SelectionState) signal: SelectionState) {
|
|
64
|
+
this._selectionLength = signal.length;
|
|
65
|
+
const chip = document.getElementById('mb-chip');
|
|
66
|
+
if (!chip) return;
|
|
67
|
+
if (this._selectionLength > 0) {
|
|
68
|
+
chip.hidden = false;
|
|
69
|
+
chip.textContent = `\u2702 ${this._selectionLength} selected`;
|
|
70
|
+
} else {
|
|
71
|
+
chip.hidden = true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
protected now(): string {
|
|
76
|
+
return new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
protected activeTitle(registry: AppRegistry): { icon: string; name: string } {
|
|
80
|
+
const match = this._route.match(/^\/app\/([^/]+)/);
|
|
81
|
+
if (match) {
|
|
82
|
+
const app = registry.get(match[1]);
|
|
83
|
+
if (app) return { icon: app.icon, name: app.name };
|
|
84
|
+
}
|
|
85
|
+
if (this._route === '/launchpad') {
|
|
86
|
+
return { icon: '🚀', name: 'Launchpad' };
|
|
87
|
+
}
|
|
88
|
+
return { icon: '', name: 'Finder' };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
protected build(registry: AppRegistry): string {
|
|
92
|
+
const { icon, name } = this.activeTitle(registry);
|
|
93
|
+
const hasSel = this._selectionLength > 0;
|
|
94
|
+
|
|
95
|
+
return `
|
|
96
|
+
<div class="menubar">
|
|
97
|
+
<div class="mb-left">
|
|
98
|
+
<span class="mb-logo"></span>
|
|
99
|
+
<span class="mb-active" id="mb-active">${icon ? icon + ' ' : ''}${name}</span>
|
|
100
|
+
<span class="mb-menu">File</span>
|
|
101
|
+
<span class="mb-menu">Edit</span>
|
|
102
|
+
<span class="mb-menu">View</span>
|
|
103
|
+
<span class="mb-menu">Window</span>
|
|
104
|
+
</div>
|
|
105
|
+
<div class="mb-right">
|
|
106
|
+
<span class="mb-chip" id="mb-chip"${hasSel ? '' : ' hidden'}>✂ ${this._selectionLength} selected</span>
|
|
107
|
+
<span class="mb-icon"></span>
|
|
108
|
+
<span class="mb-clock" id="mb-clock">${this.now()}</span>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@Are.Styles
|
|
115
|
+
styles(@A_Inject(A_Caller) node: AreHTMLNode) {
|
|
116
|
+
node.setStyles(`
|
|
117
|
+
.menubar {
|
|
118
|
+
position: absolute;
|
|
119
|
+
top: 0; left: 0; right: 0;
|
|
120
|
+
height: 28px;
|
|
121
|
+
display: flex;
|
|
122
|
+
align-items: center;
|
|
123
|
+
justify-content: space-between;
|
|
124
|
+
padding: 0 14px;
|
|
125
|
+
background: rgba(20, 16, 32, 0.55);
|
|
126
|
+
backdrop-filter: blur(18px) saturate(160%);
|
|
127
|
+
-webkit-backdrop-filter: blur(18px) saturate(160%);
|
|
128
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
|
129
|
+
font-size: 13px;
|
|
130
|
+
z-index: 100;
|
|
131
|
+
}
|
|
132
|
+
.mb-left, .mb-right { display: flex; align-items: center; gap: 16px; }
|
|
133
|
+
.mb-logo {
|
|
134
|
+
width: 14px; height: 14px;
|
|
135
|
+
background: #f5f5f7;
|
|
136
|
+
-webkit-mask: radial-gradient(circle at 70% 22%, transparent 22%, #000 23%) 0 0/100% 100%;
|
|
137
|
+
mask: radial-gradient(circle at 70% 22%, transparent 22%, #000 23%) 0 0/100% 100%;
|
|
138
|
+
clip-path: path('M7 0C3 0 0 3.4 0 7.6c0 3.4 2.2 6.4 5.2 6.4 1 0 1.8-.6 2.8-.6s1.6.6 2.6.6c3 0 5.4-3 5.4-6.4C16 3.4 12.8 0 9 0 8 0 7.6.4 7 .4 6.6.4 8 0 7 0z');
|
|
139
|
+
opacity: 0.9;
|
|
140
|
+
}
|
|
141
|
+
.mb-active { font-weight: 700; }
|
|
142
|
+
.mb-menu { color: rgba(245,245,247,0.82); font-weight: 500; }
|
|
143
|
+
.mb-menu:first-of-type { margin-left: 2px; }
|
|
144
|
+
.mb-icon { opacity: 0.85; }
|
|
145
|
+
.mb-clock { font-variant-numeric: tabular-nums; font-weight: 500; }
|
|
146
|
+
.mb-chip {
|
|
147
|
+
font-size: 11px;
|
|
148
|
+
font-weight: 600;
|
|
149
|
+
padding: 2px 9px;
|
|
150
|
+
border-radius: 999px;
|
|
151
|
+
color: #ffe5a3;
|
|
152
|
+
background: rgba(255, 196, 84, 0.18);
|
|
153
|
+
}
|
|
154
|
+
`);
|
|
155
|
+
}
|
|
156
|
+
}
|