@stacksjs/defaults 0.75.93 → 0.75.94
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.
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-dashboard
|
|
3
|
-
description: Use when building or customizing the Stacks admin dashboard, including dashboard pages, model management views, analytics widgets, commerce dashboards, content management, settings panels, deployment monitoring, job/queue management, or the
|
|
3
|
+
description: Use when building or customizing the Stacks admin dashboard, including dashboard pages, model management views, analytics widgets, commerce dashboards, content management, settings panels, deployment monitoring, job/queue management, or the 410 built-in dashboard components. Covers the dashboard system at storage/framework/defaults/.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -8,7 +8,7 @@ allowed-tools: Read Edit Write Bash Grep Glob
|
|
|
8
8
|
|
|
9
9
|
# Stacks Dashboard
|
|
10
10
|
|
|
11
|
-
The Stacks admin dashboard provides a full-featured admin panel with 100+ route views,
|
|
11
|
+
The Stacks admin dashboard provides a full-featured admin panel with 100+ route views, 410 components, and a multi-section layout.
|
|
12
12
|
|
|
13
13
|
## Key Paths
|
|
14
14
|
- Dashboard components: `storage/framework/defaults/resources/components/Dashboard/`
|
package/ide/vscode/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"publisher": "Stacks",
|
|
3
3
|
"name": "vscode-stacks",
|
|
4
4
|
"displayName": "Stacks",
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.94",
|
|
6
6
|
"description": "Stacks, built into VS Code: stx templates, pickier linting and formatting, encrypted env files, the dev server preview and every buddy command. No other extensions required.",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"funding": "https://github.com/sponsors/chrisbbreuer",
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/defaults",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.94",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/stacksjs/stacks.git",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@iconify-json/f7": "^1.2.2",
|
|
57
57
|
"@iconify-json/hugeicons": "^1.2.35",
|
|
58
|
-
"@stacksjs/mobile": "^0.75.
|
|
58
|
+
"@stacksjs/mobile": "^0.75.94",
|
|
59
59
|
"@stacksjs/sanitizer": "^0.2.395",
|
|
60
60
|
"@xterm/addon-fit": "^0.11.0",
|
|
61
61
|
"@xterm/xterm": "^6.0.0",
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
interface NativeAccountButtonProps {
|
|
3
|
+
/** Where the account screen is, such as `/m/me`. */
|
|
4
|
+
href: string
|
|
5
|
+
/** The person's name; the button shows its initials. */
|
|
6
|
+
name?: string
|
|
7
|
+
/** A photo of them, shown instead of the initials. */
|
|
8
|
+
image?: string
|
|
9
|
+
/** A count on the button (unread notifications, say). Zero and empty draw nothing. */
|
|
10
|
+
badge?: string | number
|
|
11
|
+
/** What a screen reader calls the button. */
|
|
12
|
+
label?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { href, label = 'Account' } = defineProps<NativeAccountButtonProps>()
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<script client>
|
|
19
|
+
import { haptics } from '@stacksjs/mobile'
|
|
20
|
+
|
|
21
|
+
// The account at the top right of a tab's screen, as iOS apps put it: the
|
|
22
|
+
// tab bar keeps its tabs for the places the app is used from. Reactive, so it
|
|
23
|
+
// follows the signed-in person and the count as they change.
|
|
24
|
+
const accountName = useReactiveProp<string>('name', '')
|
|
25
|
+
const accountImage = useReactiveProp<string>('image', '')
|
|
26
|
+
const accountBadge = useReactiveProp<string | number>('badge', '')
|
|
27
|
+
|
|
28
|
+
const accountInitials = derived(() => {
|
|
29
|
+
const parts = String(accountName() || '').trim().split(/\s+/).filter(Boolean)
|
|
30
|
+
const first = parts[0]?.[0] ?? ''
|
|
31
|
+
const last = parts.length > 1 ? (parts[parts.length - 1]?.[0] ?? '') : ''
|
|
32
|
+
return (first + last).toUpperCase()
|
|
33
|
+
})
|
|
34
|
+
const accountCount = derived(() => {
|
|
35
|
+
const value = accountBadge()
|
|
36
|
+
return value === '' || value === 0 || value === '0' || value == null ? '' : String(value)
|
|
37
|
+
})
|
|
38
|
+
const accountPhoto = derived(() => (accountImage() ? `background-image: url("${String(accountImage()).replace(/"/g, '%22')}")` : ''))
|
|
39
|
+
|
|
40
|
+
function tapAccount(): void {
|
|
41
|
+
void haptics.selection()
|
|
42
|
+
}
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<a href="{{ href }}" class="native-account-button" draggable="false" data-stx-link data-stx-prefetch="eager" @click="tapAccount()">
|
|
46
|
+
<span class="native-account-label">{{ label }}<span :if="accountCount()">, {{ accountCount() }}</span></span>
|
|
47
|
+
<span aria-hidden="true" class="native-account-face" :style="accountPhoto()">
|
|
48
|
+
<span :if="!accountImage() && accountInitials()">{{ accountInitials() }}</span>
|
|
49
|
+
<i :if="!accountImage() && !accountInitials()" class="i-lucide-circle-user-round native-account-glyph"></i>
|
|
50
|
+
</span>
|
|
51
|
+
<span :if="accountCount()" aria-hidden="true" class="native-account-badge"></span>
|
|
52
|
+
</a>
|
|
53
|
+
|
|
54
|
+
<style>
|
|
55
|
+
.native-account-button {
|
|
56
|
+
position: relative;
|
|
57
|
+
display: inline-flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
justify-content: center;
|
|
60
|
+
min-width: 2.75rem;
|
|
61
|
+
min-height: 2.75rem;
|
|
62
|
+
text-decoration: none;
|
|
63
|
+
-webkit-tap-highlight-color: transparent;
|
|
64
|
+
-webkit-touch-callout: none;
|
|
65
|
+
transition: transform 120ms ease, opacity 120ms ease;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.native-account-button:active { transform: scale(0.94); opacity: 0.85; }
|
|
69
|
+
|
|
70
|
+
.native-account-label {
|
|
71
|
+
position: absolute;
|
|
72
|
+
width: 1px;
|
|
73
|
+
height: 1px;
|
|
74
|
+
overflow: hidden;
|
|
75
|
+
clip: rect(0 0 0 0);
|
|
76
|
+
white-space: nowrap;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.native-account-face {
|
|
80
|
+
display: inline-flex;
|
|
81
|
+
align-items: center;
|
|
82
|
+
justify-content: center;
|
|
83
|
+
width: 2rem;
|
|
84
|
+
height: 2rem;
|
|
85
|
+
overflow: hidden;
|
|
86
|
+
border-radius: 999px;
|
|
87
|
+
color: var(--native-accent, rgb(29 78 216));
|
|
88
|
+
background: rgb(219 234 254) center / cover no-repeat;
|
|
89
|
+
font-size: 0.8125rem;
|
|
90
|
+
font-weight: 600;
|
|
91
|
+
letter-spacing: 0.01em;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.native-account-glyph { width: 1.25rem; height: 1.25rem; }
|
|
95
|
+
|
|
96
|
+
.native-account-badge {
|
|
97
|
+
position: absolute;
|
|
98
|
+
top: 0.375rem;
|
|
99
|
+
right: 0.375rem;
|
|
100
|
+
width: 0.625rem;
|
|
101
|
+
height: 0.625rem;
|
|
102
|
+
border-radius: 999px;
|
|
103
|
+
background: rgb(225 29 72);
|
|
104
|
+
box-shadow: 0 0 0 2px var(--native-safe-area-background, white);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.dark .native-account-face {
|
|
108
|
+
color: var(--native-accent-dark, rgb(147 197 253));
|
|
109
|
+
background-color: rgb(30 58 138 / 0.45);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@media (prefers-reduced-motion: reduce) {
|
|
113
|
+
.native-account-button { transition: none; }
|
|
114
|
+
}
|
|
115
|
+
</style>
|
|
@@ -27,6 +27,17 @@ describe('Native components', () => {
|
|
|
27
27
|
expect(shell).toContain('padding-bottom: calc(var(--craft-tab-bar-height, 6rem) + 0.75rem);')
|
|
28
28
|
})
|
|
29
29
|
|
|
30
|
+
it('puts the account at the top right: initials or a photo, a count, a native press', () => {
|
|
31
|
+
const button = read('NativeAccountButton')
|
|
32
|
+
// Reactive, so it follows the signed-in person and the count.
|
|
33
|
+
expect(button).toContain("useReactiveProp<string>('name', '')")
|
|
34
|
+
expect(button).toContain("useReactiveProp<string | number>('badge', '')")
|
|
35
|
+
expect(button).toContain('data-stx-link data-stx-prefetch="eager"')
|
|
36
|
+
expect(button).toContain('void haptics.selection()')
|
|
37
|
+
// A photo is a background, not an <img>: apps check that every image goes through their delivery.
|
|
38
|
+
expect(button).not.toContain('<img')
|
|
39
|
+
})
|
|
40
|
+
|
|
30
41
|
it('lifts the launch splash once the first screen has painted', () => {
|
|
31
42
|
expect(read('NativeAppShell')).toContain('requestAnimationFrame(() => requestAnimationFrame(() => splash.hide()))')
|
|
32
43
|
})
|