@askrjs/cli 0.0.11 → 0.0.13
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 +4 -2
- package/dist/analyze.js +1 -1
- package/dist/cli.js +1 -1
- package/dist/{guardrails-vH9lYg05.js → guardrails-D6KCKS-H.js} +1 -1
- package/dist/{runner-42nqhW9u.js → runner-BSs9Ow3t.js} +557 -16
- package/dist/{runner-tPGn2CQC.js → runner-DetGSvGf.js} +1 -1
- package/dist/templates/spa/src/pages/app/_layout.tsx +11 -8
- package/dist/templates/spa/src/pages/app/admin-home.tsx +142 -132
- package/dist/templates/spa/src/pages/app/agent-runs.tsx +33 -26
- package/dist/templates/spa/src/pages/public/home.tsx +12 -9
- package/dist/templates/ssg/src/components/site-shell.tsx +4 -3
- package/dist/templates/ssg/src/pages/about.tsx +14 -11
- package/dist/templates/ssg/src/pages/content.tsx +10 -7
- package/dist/templates/ssg/src/pages/home.tsx +6 -3
- package/dist/templates/startkit/src/components/app-sidebar.tsx +23 -18
- package/dist/templates/startkit/src/components/data-table.tsx +41 -39
- package/dist/templates/startkit/src/pages/workspace/dashboard.tsx +16 -13
- package/package.json +10 -2
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
SettingsIcon,
|
|
7
7
|
SunIcon,
|
|
8
8
|
} from '@askrjs/lucide';
|
|
9
|
+
import { For } from '@askrjs/askr/control';
|
|
9
10
|
import { Link, navigate } from '@askrjs/askr/router';
|
|
10
11
|
import { Button } from '@askrjs/themes/components';
|
|
11
12
|
import { Container, Inline, Stack } from '@askrjs/themes/components';
|
|
@@ -42,14 +43,16 @@ export default function AppLayout({ children }: { children?: unknown }) {
|
|
|
42
43
|
</Link>
|
|
43
44
|
</NavBrand>
|
|
44
45
|
<NavGroup label="Workspace">
|
|
45
|
-
{appNavItems
|
|
46
|
-
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
<For each={[...appNavItems]} by={(item) => item.href}>
|
|
47
|
+
{(item) => (
|
|
48
|
+
<NavLink href={item.href} match={item.match}>
|
|
49
|
+
<Inline as="span" gap="2" align="center">
|
|
50
|
+
{icons[item.icon]}
|
|
51
|
+
<span>{item.label}</span>
|
|
52
|
+
</Inline>
|
|
53
|
+
</NavLink>
|
|
54
|
+
)}
|
|
55
|
+
</For>
|
|
53
56
|
</NavGroup>
|
|
54
57
|
<NavGroup label="Session" align="end">
|
|
55
58
|
<NavLink href="/" match="exact">
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resource } from '@askrjs/askr/resources';
|
|
2
|
+
import { For, Show } from '@askrjs/askr/control';
|
|
2
3
|
import { createPlot } from '@askrjs/charts';
|
|
3
4
|
import { AlertCircleIcon, RefreshCwIcon } from '@askrjs/lucide';
|
|
4
5
|
import { Button } from '@askrjs/themes/components';
|
|
@@ -26,145 +27,154 @@ export default function AdminHomePage() {
|
|
|
26
27
|
const operations = resource(({ signal }) => loadOperations({ signal }), []);
|
|
27
28
|
const snapshot = operations.value;
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
<
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
);
|
|
40
|
-
}
|
|
30
|
+
const errorState = (
|
|
31
|
+
<Section>
|
|
32
|
+
<EmptyState
|
|
33
|
+
icon={<AlertCircleIcon size={24} aria-hidden="true" />}
|
|
34
|
+
title="Operations could not load"
|
|
35
|
+
description="The dashboard keeps failures recoverable. Retry the owning resource instead of hiding the error in a toast."
|
|
36
|
+
actions={<Button onPress={() => operations.refresh()}>Retry</Button>}
|
|
37
|
+
/>
|
|
38
|
+
</Section>
|
|
39
|
+
);
|
|
41
40
|
|
|
42
41
|
return (
|
|
43
|
-
<
|
|
44
|
-
<
|
|
45
|
-
<
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
{operations.pending && !snapshot ? (
|
|
62
|
-
<Block gap="md">
|
|
63
|
-
<Skeleton style="height: 8rem" />
|
|
64
|
-
<Skeleton style="height: 8rem" />
|
|
65
|
-
<Skeleton style="height: 8rem" />
|
|
66
|
-
</Block>
|
|
67
|
-
) : null}
|
|
42
|
+
<Show when={!operations.error || snapshot} fallback={errorState}>
|
|
43
|
+
<Stack gap="5">
|
|
44
|
+
<section class="page-heading">
|
|
45
|
+
<Stack gap="2">
|
|
46
|
+
<Badge>projection v{snapshot?.version ?? '...'}</Badge>
|
|
47
|
+
<h1>Workspace home</h1>
|
|
48
|
+
<p class="lead">
|
|
49
|
+
A consistency-aware dashboard for agent runs, queue health, and
|
|
50
|
+
event-sourced read models.
|
|
51
|
+
</p>
|
|
52
|
+
</Stack>
|
|
53
|
+
<Inline gap="2" align="center">
|
|
54
|
+
{operations.pending && snapshot ? <Badge>refreshing</Badge> : null}
|
|
55
|
+
<Button variant="secondary" onPress={() => operations.refresh()}>
|
|
56
|
+
<RefreshCwIcon size={14} aria-hidden="true" /> Refresh
|
|
57
|
+
</Button>
|
|
58
|
+
</Inline>
|
|
59
|
+
</section>
|
|
68
60
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
label={metric.label}
|
|
75
|
-
value={metric.value}
|
|
76
|
-
trend={metric.trend}
|
|
77
|
-
/>
|
|
78
|
-
))}
|
|
61
|
+
{operations.pending && !snapshot ? (
|
|
62
|
+
<Block gap="md">
|
|
63
|
+
<Skeleton style="height: 8rem" />
|
|
64
|
+
<Skeleton style="height: 8rem" />
|
|
65
|
+
<Skeleton style="height: 8rem" />
|
|
79
66
|
</Block>
|
|
67
|
+
) : null}
|
|
80
68
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
<
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
</CardHeader>
|
|
89
|
-
<CardContent>
|
|
90
|
-
<OperationsPlot.Root
|
|
91
|
-
data={snapshot.throughput}
|
|
92
|
-
rowKey="label"
|
|
93
|
-
label="Run throughput"
|
|
94
|
-
description="Accepted commands by work type."
|
|
95
|
-
>
|
|
96
|
-
<OperationsPlot.Bar x="label" y="value" />
|
|
97
|
-
</OperationsPlot.Root>
|
|
98
|
-
</CardContent>
|
|
99
|
-
</Card>
|
|
100
|
-
<Card>
|
|
101
|
-
<CardHeader>
|
|
102
|
-
<CardTitle>Projection lag</CardTitle>
|
|
103
|
-
<CardDescription>
|
|
104
|
-
Lower is better; stale states stay visible.
|
|
105
|
-
</CardDescription>
|
|
106
|
-
</CardHeader>
|
|
107
|
-
<CardContent>
|
|
108
|
-
<OperationsPlot.Root
|
|
109
|
-
data={snapshot.lag}
|
|
110
|
-
rowKey="label"
|
|
111
|
-
label="Projection lag"
|
|
112
|
-
description="Projection lag over the last hour."
|
|
69
|
+
<Show when={snapshot}>
|
|
70
|
+
{(currentSnapshot) => (
|
|
71
|
+
<>
|
|
72
|
+
<Block gap="md" class="metric-grid">
|
|
73
|
+
<For
|
|
74
|
+
each={currentSnapshot.metrics}
|
|
75
|
+
by={(metric) => metric.label}
|
|
113
76
|
>
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
77
|
+
{(metric) => (
|
|
78
|
+
<MetricCard
|
|
79
|
+
label={metric.label}
|
|
80
|
+
value={metric.value}
|
|
81
|
+
trend={metric.trend}
|
|
82
|
+
/>
|
|
83
|
+
)}
|
|
84
|
+
</For>
|
|
85
|
+
</Block>
|
|
86
|
+
|
|
87
|
+
<Block gap="md" align="stretch" class="chart-grid">
|
|
88
|
+
<Card>
|
|
89
|
+
<CardHeader>
|
|
90
|
+
<CardTitle>Run throughput</CardTitle>
|
|
91
|
+
<CardDescription>
|
|
92
|
+
Accepted commands by work type.
|
|
93
|
+
</CardDescription>
|
|
94
|
+
</CardHeader>
|
|
95
|
+
<CardContent>
|
|
96
|
+
<OperationsPlot.Root
|
|
97
|
+
data={currentSnapshot.throughput}
|
|
98
|
+
rowKey="label"
|
|
99
|
+
label="Run throughput"
|
|
100
|
+
description="Accepted commands by work type."
|
|
101
|
+
>
|
|
102
|
+
<OperationsPlot.Bar x="label" y="value" />
|
|
103
|
+
</OperationsPlot.Root>
|
|
104
|
+
</CardContent>
|
|
105
|
+
</Card>
|
|
106
|
+
<Card>
|
|
107
|
+
<CardHeader>
|
|
108
|
+
<CardTitle>Projection lag</CardTitle>
|
|
109
|
+
<CardDescription>
|
|
110
|
+
Lower is better; stale states stay visible.
|
|
111
|
+
</CardDescription>
|
|
112
|
+
</CardHeader>
|
|
113
|
+
<CardContent>
|
|
114
|
+
<OperationsPlot.Root
|
|
115
|
+
data={currentSnapshot.lag}
|
|
116
|
+
rowKey="label"
|
|
117
|
+
label="Projection lag"
|
|
118
|
+
description="Projection lag over the last hour."
|
|
119
|
+
>
|
|
120
|
+
<OperationsPlot.Line x="label" y="value" />
|
|
121
|
+
<OperationsPlot.Point x="label" y="value" />
|
|
122
|
+
</OperationsPlot.Root>
|
|
123
|
+
</CardContent>
|
|
124
|
+
</Card>
|
|
125
|
+
</Block>
|
|
120
126
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
+
{currentSnapshot.consistency !== 'fresh' ? (
|
|
128
|
+
<Alert variant="warning">
|
|
129
|
+
Read models are {currentSnapshot.consistency}. Last processed
|
|
130
|
+
event is {currentSnapshot.lastEventId}.
|
|
131
|
+
</Alert>
|
|
132
|
+
) : null}
|
|
127
133
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
134
|
+
<Card>
|
|
135
|
+
<CardHeader>
|
|
136
|
+
<CardTitle>Recent agent runs</CardTitle>
|
|
137
|
+
<CardDescription>
|
|
138
|
+
Run state is modeled as product state, not a single loading
|
|
139
|
+
boolean.
|
|
140
|
+
</CardDescription>
|
|
141
|
+
</CardHeader>
|
|
142
|
+
<CardContent>
|
|
143
|
+
<div class="run-table-wrap">
|
|
144
|
+
<table class="run-table">
|
|
145
|
+
<thead>
|
|
146
|
+
<tr>
|
|
147
|
+
<th>Run</th>
|
|
148
|
+
<th>Status</th>
|
|
149
|
+
<th>Owner</th>
|
|
150
|
+
<th>Updated</th>
|
|
151
|
+
</tr>
|
|
152
|
+
</thead>
|
|
153
|
+
<tbody>
|
|
154
|
+
<For each={currentSnapshot.runs} by={(run) => run.id}>
|
|
155
|
+
{(run) => (
|
|
156
|
+
<tr>
|
|
157
|
+
<td>
|
|
158
|
+
<strong>{run.title}</strong>
|
|
159
|
+
<span>{run.id}</span>
|
|
160
|
+
</td>
|
|
161
|
+
<td>
|
|
162
|
+
<StatusBadge status={run.status} />
|
|
163
|
+
</td>
|
|
164
|
+
<td>{run.owner}</td>
|
|
165
|
+
<td>{formatRelativeTime(run.updatedAt)}</td>
|
|
166
|
+
</tr>
|
|
167
|
+
)}
|
|
168
|
+
</For>
|
|
169
|
+
</tbody>
|
|
170
|
+
</table>
|
|
171
|
+
</div>
|
|
172
|
+
</CardContent>
|
|
173
|
+
</Card>
|
|
174
|
+
</>
|
|
175
|
+
)}
|
|
176
|
+
</Show>
|
|
177
|
+
</Stack>
|
|
178
|
+
</Show>
|
|
169
179
|
);
|
|
170
180
|
}
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
Clock3Icon,
|
|
5
5
|
ShieldAlertIcon,
|
|
6
6
|
} from '@askrjs/lucide';
|
|
7
|
+
import { For } from '@askrjs/askr/control';
|
|
7
8
|
import {
|
|
8
9
|
Badge,
|
|
9
10
|
Card,
|
|
@@ -18,12 +19,14 @@ import StatusBadge, {
|
|
|
18
19
|
} from '../../components/shared/status-badge';
|
|
19
20
|
|
|
20
21
|
const runs: Array<{
|
|
22
|
+
id: string;
|
|
21
23
|
title: string;
|
|
22
24
|
status: RunStatus;
|
|
23
25
|
event: string;
|
|
24
26
|
description: string;
|
|
25
27
|
}> = [
|
|
26
28
|
{
|
|
29
|
+
id: 'reconcile-billing-projection',
|
|
27
30
|
title: 'Reconcile billing projection',
|
|
28
31
|
status: 'running',
|
|
29
32
|
event: 'tool call: compare-ledger',
|
|
@@ -31,6 +34,7 @@ const runs: Array<{
|
|
|
31
34
|
'Streaming events are appended to the timeline and reconciled by event id.',
|
|
32
35
|
},
|
|
33
36
|
{
|
|
37
|
+
id: 'approve-enterprise-workspace',
|
|
34
38
|
title: 'Approve enterprise workspace',
|
|
35
39
|
status: 'requires-action',
|
|
36
40
|
event: 'approval requested',
|
|
@@ -38,6 +42,7 @@ const runs: Array<{
|
|
|
38
42
|
'Human gates are explicit product states, not hidden inside generated text.',
|
|
39
43
|
},
|
|
40
44
|
{
|
|
45
|
+
id: 'refresh-onboarding-cohort',
|
|
41
46
|
title: 'Refresh onboarding cohort',
|
|
42
47
|
status: 'succeeded',
|
|
43
48
|
event: 'projection caught up',
|
|
@@ -61,32 +66,34 @@ export default function AgentRunsPage() {
|
|
|
61
66
|
</section>
|
|
62
67
|
|
|
63
68
|
<Block gap="md" class="agent-grid">
|
|
64
|
-
{runs
|
|
65
|
-
|
|
66
|
-
<
|
|
67
|
-
<
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
<
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
69
|
+
<For each={runs} by={(run) => run.id}>
|
|
70
|
+
{(run) => (
|
|
71
|
+
<Card>
|
|
72
|
+
<CardHeader>
|
|
73
|
+
<Inline justify="between" align="start" gap="3">
|
|
74
|
+
<span class="card-icon">
|
|
75
|
+
{run.status === 'succeeded' ? (
|
|
76
|
+
<CheckCircle2Icon size={18} aria-hidden="true" />
|
|
77
|
+
) : run.status === 'requires-action' ? (
|
|
78
|
+
<ShieldAlertIcon size={18} aria-hidden="true" />
|
|
79
|
+
) : (
|
|
80
|
+
<BotIcon size={18} aria-hidden="true" />
|
|
81
|
+
)}
|
|
82
|
+
</span>
|
|
83
|
+
<StatusBadge status={run.status} />
|
|
84
|
+
</Inline>
|
|
85
|
+
<CardTitle>{run.title}</CardTitle>
|
|
86
|
+
<CardDescription>{run.description}</CardDescription>
|
|
87
|
+
</CardHeader>
|
|
88
|
+
<CardContent>
|
|
89
|
+
<Inline gap="2" align="center">
|
|
90
|
+
<Clock3Icon size={14} aria-hidden="true" />
|
|
91
|
+
<span>{run.event}</span>
|
|
92
|
+
</Inline>
|
|
93
|
+
</CardContent>
|
|
94
|
+
</Card>
|
|
95
|
+
)}
|
|
96
|
+
</For>
|
|
90
97
|
</Block>
|
|
91
98
|
</Stack>
|
|
92
99
|
);
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
CheckCircle2Icon,
|
|
6
6
|
ShieldCheckIcon,
|
|
7
7
|
} from '@askrjs/lucide';
|
|
8
|
+
import { For } from '@askrjs/askr/control';
|
|
8
9
|
import { Link } from '@askrjs/askr/router';
|
|
9
10
|
import { Button } from '@askrjs/themes/components';
|
|
10
11
|
import {
|
|
@@ -111,15 +112,17 @@ export default function HomePage() {
|
|
|
111
112
|
<Section paddingY="xl">
|
|
112
113
|
<Container size="xl">
|
|
113
114
|
<Block gap="md" class="feature-grid">
|
|
114
|
-
{capabilities
|
|
115
|
-
|
|
116
|
-
<
|
|
117
|
-
<
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
115
|
+
<For each={capabilities} by={(item) => item.title}>
|
|
116
|
+
{(item) => (
|
|
117
|
+
<Card>
|
|
118
|
+
<CardHeader>
|
|
119
|
+
<span class="card-icon">{item.icon}</span>
|
|
120
|
+
<CardTitle>{item.title}</CardTitle>
|
|
121
|
+
<CardDescription>{item.description}</CardDescription>
|
|
122
|
+
</CardHeader>
|
|
123
|
+
</Card>
|
|
124
|
+
)}
|
|
125
|
+
</For>
|
|
123
126
|
</Block>
|
|
124
127
|
</Container>
|
|
125
128
|
</Section>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { For } from '@askrjs/askr/control';
|
|
1
2
|
import { Link } from '@askrjs/askr/router';
|
|
2
3
|
import { Header } from '@askrjs/themes/components';
|
|
3
4
|
import {
|
|
@@ -35,9 +36,9 @@ export function SiteHeader() {
|
|
|
35
36
|
class="navbar-group"
|
|
36
37
|
data-align="end"
|
|
37
38
|
>
|
|
38
|
-
{navItems
|
|
39
|
-
<NavLink href={item.href}>{item.label}</NavLink>
|
|
40
|
-
|
|
39
|
+
<For each={[...navItems]} by={(item) => item.href}>
|
|
40
|
+
{(item) => <NavLink href={item.href}>{item.label}</NavLink>}
|
|
41
|
+
</For>
|
|
41
42
|
</Nav>
|
|
42
43
|
</Box>
|
|
43
44
|
</Container>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { For } from '@askrjs/askr/control';
|
|
1
2
|
import { Link } from '@askrjs/askr/router';
|
|
2
3
|
import { Button } from '@askrjs/ui';
|
|
3
4
|
import {
|
|
@@ -54,17 +55,19 @@ export default function Workflow() {
|
|
|
54
55
|
/>
|
|
55
56
|
|
|
56
57
|
<CardGrid>
|
|
57
|
-
{steps
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
58
|
+
<For each={steps} by={(step) => step.number}>
|
|
59
|
+
{(step) => (
|
|
60
|
+
<Card
|
|
61
|
+
eyebrow={step.number}
|
|
62
|
+
title={step.title}
|
|
63
|
+
description={step.body}
|
|
64
|
+
>
|
|
65
|
+
<p>
|
|
66
|
+
<code>{step.command}</code>
|
|
67
|
+
</p>
|
|
68
|
+
</Card>
|
|
69
|
+
)}
|
|
70
|
+
</For>
|
|
68
71
|
</CardGrid>
|
|
69
72
|
|
|
70
73
|
<Card
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { For } from '@askrjs/askr/control';
|
|
1
2
|
import { Link } from '@askrjs/askr/router';
|
|
2
3
|
import { Button } from '@askrjs/ui';
|
|
3
4
|
import {
|
|
@@ -50,13 +51,15 @@ export default function Content() {
|
|
|
50
51
|
/>
|
|
51
52
|
|
|
52
53
|
<CardGrid>
|
|
53
|
-
{routeMap
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
<For each={[...routeMap]} by={(route) => route.path}>
|
|
55
|
+
{(route) => (
|
|
56
|
+
<Card
|
|
57
|
+
eyebrow={route.path}
|
|
58
|
+
title={route.title}
|
|
59
|
+
description={route.note}
|
|
60
|
+
/>
|
|
61
|
+
)}
|
|
62
|
+
</For>
|
|
60
63
|
</CardGrid>
|
|
61
64
|
</>
|
|
62
65
|
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { For } from '@askrjs/askr/control';
|
|
1
2
|
import { Link } from '@askrjs/askr/router';
|
|
2
3
|
import { Button } from '@askrjs/ui';
|
|
3
4
|
import {
|
|
@@ -42,9 +43,11 @@ export default function Home() {
|
|
|
42
43
|
/>
|
|
43
44
|
|
|
44
45
|
<CardGrid>
|
|
45
|
-
{highlights
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
<For each={highlights} by={(highlight) => highlight.title}>
|
|
47
|
+
{(highlight) => (
|
|
48
|
+
<Card title={highlight.title} description={highlight.body} />
|
|
49
|
+
)}
|
|
50
|
+
</For>
|
|
48
51
|
</CardGrid>
|
|
49
52
|
</>
|
|
50
53
|
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { For } from '@askrjs/askr/control';
|
|
1
2
|
import { Link } from '@askrjs/askr/router';
|
|
2
3
|
import {
|
|
3
4
|
LayoutDashboardIcon,
|
|
@@ -67,27 +68,31 @@ export default function AppSidebar() {
|
|
|
67
68
|
</NavBrand>
|
|
68
69
|
|
|
69
70
|
<NavGroup id="workspace-nav-group" label="Workspace">
|
|
70
|
-
{primaryNav
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
<
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
71
|
+
<For each={primaryNav} by={(item) => item.href}>
|
|
72
|
+
{(item) => {
|
|
73
|
+
const Icon = item.icon;
|
|
74
|
+
return (
|
|
75
|
+
<NavLink href={item.href}>
|
|
76
|
+
<Icon size={16} aria-hidden={true} />
|
|
77
|
+
<span>{item.label}</span>
|
|
78
|
+
</NavLink>
|
|
79
|
+
);
|
|
80
|
+
}}
|
|
81
|
+
</For>
|
|
79
82
|
</NavGroup>
|
|
80
83
|
|
|
81
84
|
<NavGroup id="other-nav-group" label="Other" placement="bottom">
|
|
82
|
-
{secondaryNav
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
<
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
85
|
+
<For each={secondaryNav} by={(item) => item.href}>
|
|
86
|
+
{(item) => {
|
|
87
|
+
const Icon = item.icon;
|
|
88
|
+
return (
|
|
89
|
+
<NavLink href={item.href}>
|
|
90
|
+
<Icon size={16} aria-hidden={true} />
|
|
91
|
+
<span>{item.label}</span>
|
|
92
|
+
</NavLink>
|
|
93
|
+
);
|
|
94
|
+
}}
|
|
95
|
+
</For>
|
|
91
96
|
</NavGroup>
|
|
92
97
|
</Navbar>
|
|
93
98
|
</aside>
|