@stacksjs/defaults 0.75.135 → 0.75.137

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.
@@ -20,6 +20,7 @@ allowed-tools: Read Edit Write Bash Grep Glob
20
20
  ```
21
21
  cms/src/
22
22
  ├── index.ts # CmsNamespace - top-level API
23
+ ├── blog.ts # Markdown posts in content/blog: loadPosts, loadPost, renderPostBody, bylines
23
24
  ├── posts/
24
25
  │ ├── fetch.ts # fetchById, fetchAll, fetchByStatus, fetchByCategory, fetchByAuthor
25
26
  │ ├── store.ts # store, attach, detach, sync (pivot tables)
@@ -198,6 +199,27 @@ email. Moderate without a dashboard with `buddy comments:list [--status] [--type
198
199
 
199
200
  The site-wide `/sitemap.xml` merges the published posts in, so crawlers find them from the root sitemap too (see `stacks-server`, "Sitemap and robots.txt").
200
201
 
202
+ ## Markdown Blog (content/blog, `@stacksjs/cms/blog`)
203
+
204
+ The simplest blog has no tables: each post is `content/blog/<slug>.md`, shipped with the commit that adds it. Add `resources/views/blog.stx` (index) and `resources/views/blog/[slug].stx` (post); once `blog.stx` exists the views server serves only `/blog/feed.xml` and `/blog/sitemap.xml` itself and leaves the pages to stx, and `/sitemap.xml` lists the posts. Pages, feed and sitemap all read posts through `@stacksjs/cms/blog`, so they agree on what is published.
205
+
206
+ ```ts
207
+ import { articleHead } from '@stacksjs/cms/article'
208
+ import { bylineOf, createAuthorResolver, formatPostDate, loadPost, loadPosts, renderPostBody } from '@stacksjs/cms/blog'
209
+
210
+ const posts = loadPosts() // published, featured first then newest; no bodies
211
+ const post = loadPost(useRoute().params?.slug) // null for a draft, unknown or path-like slug -> notFound()
212
+ const html = renderPostBody(post.body) // Bun markdown + renderPostHtml; {!! html !!} plus {!! articleHead() !!}
213
+
214
+ // Bylines: create once at module scope (it caches lookups for ten minutes).
215
+ export const resolveAuthors = createAuthorResolver({
216
+ lookup: async username => /* the app's profile */ ({ name, avatar, bio, url: `/${username}` }),
217
+ })
218
+ const byline = bylineOf(await resolveAuthors(post)) // [{ name, initials, avatar, bio, url, joiner, avatarStyle }]
219
+ ```
220
+
221
+ Frontmatter is one `key: value` per line: `title` and `date` (YYYY-MM-DD) are required, `draft: true` hides a post everywhere, `featured: true` lists it first, `description` is the excerpt and the feed text, `author` is the feed's plain-text byline, `image`/`imageAlt` the preview picture. Several authors: `authors: ada, grace` plus flat fallbacks `author.ada.name`, `author.ada.avatar`, `author.ada.bio` (a frontmatter bio wins over the profile's). One author may use `authorUsername`/`authorAvatar`/`authorBio`. Every key is also on `post.frontmatter`. Also exported: `parseFrontmatter`, `isPublished`, `authorsOf`, `readingMinutes` (`post.minutes`), `formatPostDate`, `joinNames`, `initialsOf`, `sortPosts`, `isPostSlug`, `blogContentDir`.
222
+
201
223
  ## Post Bodies: Images, Grids, Zoom and Embeds
202
224
 
203
225
  Blog post HTML goes through `renderPostHtml` from `@stacksjs/cms/article`, built on ts-medium-editor's article renderer. The BunPress blog (`core/actions/src/blog.ts`) does this already; an stx-native blog calls it from its post view:
@@ -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 413 built-in dashboard components. Covers the dashboard system at storage/framework/defaults/.
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 414 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, 413 components, and a multi-section layout.
11
+ The Stacks admin dashboard provides a full-featured admin panel with 100+ route views, 414 components, and a multi-section layout.
12
12
 
13
13
  ## Key Paths
14
14
  - Dashboard components: `storage/framework/defaults/resources/components/Dashboard/`
@@ -39,7 +39,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
39
39
  | `@stacksjs/datetime` | [`stacks-datetime`](../stacks-datetime/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/index.ts) | 12 |
40
40
  | `@stacksjs/defaults` | [`stacks-build`](../stacks-build/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/defaults/package.json) | 1 |
41
41
  | `@stacksjs/deploy` | [`stacks-deploy`](../stacks-deploy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/deploy/package.json) | 1 |
42
- | `@stacksjs/desktop-build` | [`stacks-desktop`](../stacks-desktop/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/index.ts) | 11 |
42
+ | `@stacksjs/desktop-build` | [`stacks-desktop`](../stacks-desktop/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/index.ts) | 12 |
43
43
  | `@stacksjs/development` | [`stacks-development`](../stacks-development/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/development/package.json) | 1 |
44
44
  | `@stacksjs/dns` | [`stacks-dns`](../stacks-dns/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/dns/src/index.ts) | 3 |
45
45
  | `@stacksjs/docs` | [`stacks-docs`](../stacks-docs/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/docs/src/index.ts) | 2 |
@@ -65,9 +65,9 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
65
65
  | `@stacksjs/newsletter` | [`stacks-newsletter`](../stacks-newsletter/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/src/index.ts) | 7 |
66
66
  | `@stacksjs/notifications` | [`stacks-notifications`](../stacks-notifications/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/index.ts) | 11 |
67
67
  | `@stacksjs/objects` | [`stacks-objects`](../stacks-objects/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/objects/src/index.ts) | 4 |
68
- | `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) | 61 |
68
+ | `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) | 60 |
69
69
  | `@stacksjs/pagination` | [`stacks-pagination`](../stacks-pagination/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/pagination/src/index.ts) | 0 |
70
- | `@stacksjs/path` | [`stacks-path`](../stacks-path/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/path/src/index.ts) | 9 |
70
+ | `@stacksjs/path` | [`stacks-path`](../stacks-path/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/path/src/index.ts) | 10 |
71
71
  | `@stacksjs/payments` | [`stacks-payments`](../stacks-payments/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/index.ts) | 20 |
72
72
  | `@stacksjs/push` | [`stacks-push`](../stacks-push/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/push/src/index.ts) | 6 |
73
73
  | `@stacksjs/query-builder` | [`stacks-query-builder`](../stacks-query-builder/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/query-builder/src/index.ts) | 6 |
@@ -75,11 +75,11 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
75
75
  | `@stacksjs/realtime` | [`stacks-realtime`](../stacks-realtime/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/realtime/src/index.ts) | 11 |
76
76
  | `@stacksjs/registry` | [`stacks-registry`](../stacks-registry/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/registry/src/index.ts) | 1 |
77
77
  | `@stacksjs/repl` | [`stacks-repl`](../stacks-repl/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/repl/src/index.ts) | 2 |
78
- | `@stacksjs/router` | [`stacks-router`](../stacks-router/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/index.ts) | 86 |
78
+ | `@stacksjs/router` | [`stacks-router`](../stacks-router/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/index.ts) | 87 |
79
79
  | `@stacksjs/scheduler` | [`stacks-scheduler`](../stacks-scheduler/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/scheduler/src/index.ts) | 13 |
80
80
  | `@stacksjs/search-engine` | [`stacks-search-engine`](../stacks-search-engine/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/search-engine/src/index.ts) | 10 |
81
81
  | `@stacksjs/security` | [`stacks-security`](../stacks-security/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/index.ts) | 5 |
82
- | `@stacksjs/server` | [`stacks-server`](../stacks-server/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/index.ts) | 20 |
82
+ | `@stacksjs/server` | [`stacks-server`](../stacks-server/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/index.ts) | 21 |
83
83
  | `@stacksjs/shell` | [`stacks-shell`](../stacks-shell/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/shell/src/index.ts) | 1 |
84
84
  | `@stacksjs/sites` | [`stacks-sites`](../stacks-sites/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/sites/src/index.ts) | 3 |
85
85
  | `@stacksjs/skills` | [`stacks-skills`](../stacks-skills/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/skills/src/index.ts) | 1 |
@@ -383,11 +383,11 @@ Evidence directory: [1 retained tests](https://github.com/stacksjs/stacks/blob/m
383
383
 
384
384
  Guidance: [`stacks-desktop`](../stacks-desktop/SKILL.md). Source: [storage/framework/core/desktop/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/index.ts).
385
385
 
386
- Declared runtime exports: `BUN_EXECUTABLE_MARKER`, `RESERVED_PLIST_KEYS`, `USERLAND_LAUNCHER`, `bundleDirectoryFor`, `codesignArgs`, `craftDevCommand`, `createUpdateManifestUrl`, `describeRuntimeDuplication`, `desktopLauncherCompileArgs`, `dmgVolumeName`, `hasUserlandDesktopLauncher`, `isMachO`, `looksLikeBunExecutable`, `openDevWindow`, `plistValue`, `renderUserlandPlistEntries`, `resolveCraftBinary`, `resolveCraftExecutable`, `resolveDesktopLauncher`, `resolveDevWindowUrl`, `xmlEscape`.
386
+ Declared runtime exports: `BUN_EXECUTABLE_MARKER`, `RESERVED_PLIST_KEYS`, `USERLAND_LAUNCHER`, `bundleDirectoryFor`, `codesignArgs`, `craftDevCommand`, `createUpdateManifestUrl`, `describeRuntimeDuplication`, `desktopAppVersion`, `desktopLauncherCompileArgs`, `dmgVolumeName`, `hasUserlandDesktopLauncher`, `isMachO`, `looksLikeBunExecutable`, `openDevWindow`, `plistValue`, `renderInfoPlist`, `renderUserlandPlistEntries`, `resolveCraftBinary`, `resolveCraftExecutable`, `resolveDesktopLauncher`, `resolveDevWindowUrl`, `resolveDmgPackaging`, `xmlEscape`.
387
387
 
388
388
  Local source modules: [src/invites.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/invites.ts), [src/support.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/support.ts), [src/updater.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/updater.ts).
389
389
 
390
- Evidence directory: [11 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
390
+ Evidence directory: [12 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
391
391
 
392
392
  ### @stacksjs/development
393
393
 
@@ -629,9 +629,9 @@ Guidance: [`stacks-orm`](../stacks-orm/SKILL.md). Source: [storage/framework/cor
629
629
 
630
630
  Declared runtime exports: `Activity`, `AnalyticsEvent`, `Auction`, `AuctionItem`, `Author`, `Automation`, `AutomationRun`, `BILLABLE_INSTANCE_METHODS`, `Bid`, `Board`, `BoardColumn`, `Campaign`, `CampaignSend`, `CampaignVariant`, `Card`, `CardAttachment`, `CardComment`, `Cart`, `CartItem`, `Categorizable`, `Category`, `Comment`, `CommunicationSuppression`, `ConsentEvent`, `Coupon`, `Courier`, `CourierPing`, `Customer`, `DeliveryRoute`, `DeliveryStop`, `Deployment`, `DigitalDelivery`, `EmailIdempotency`, `EmailList`, `EmailListSubscriber`, `EmailSuppression`, `EmailWebhookEvent`, `ErrorModel`, `FailedJob`, `FeedbackToken`, `Form`, `FormField`, `FormSubmission`, `GdprRequest`, `GiftCard`, `Job`, `Label`, `LicenseKey`, `Log`, `LoyaltyPoint`, `LoyaltyReward`, `MagicLinkToken`, `MailPreference`, `Manufacturer`, `Menu`, `MenuItem`, `Notification`, `NotificationDelivery`, `Order`, `OrderIdempotency`, `OrderItem`, `Page`, `PageRevision`, `Payment`, `PaymentMethod`, `PaymentProduct`, `PaymentTransaction`, `PaymentWebhookEvent`, `PersonalAccessToken`, `Pledge`, `Post`, `PrintDevice`, `Product`, `ProductUnit`, `ProductVariant`, `QueryLog`, `Receipt`, `Redirect`, `Referral`, `ReferralCode`, `Release`, `Request`, `Review`, `SenderDomain`, `ShippingMethod`, `ShippingRate`, `ShippingZone`, `Site`, `SiteDomain`, `SmsOptOut`, `SocialAccount`, `SocialPost`, `StorageItem`, `StorageItemTask`, `Subscriber`, `SubscriberEmail`, `Subscription`, `SubscriptionNotOwnedError`, `Tag`, `TaxRate`, `Team`, `TeamInvitation`, `TeamMember`, `Transaction`, `UsageEvent`, `User`, `WaitlistProduct`, `WaitlistRestaurant`, `Websocket`, `buildDatabaseSchema`, `collectEncryptedAttributes`, `createAuditMethods`, `createCategorizableMethods`, `createCommentableMethods`, `createLikeableMethods`, `createTaggableMethods`, `customerOwnership`, `decryptValue`, `encryptValue`, `enrichPaginatorUrls`, `filterFillable`, `getWritableFields`, `isBillable`, `isCursorPaginator`, `isEncrypted`, `isPaginator`, `isSimplePaginator`, `isUniqueViolation`, `mapWriteError`, `modelGlobalNames`, `ormReady`, `parentOwnership`, `parseCursor`, `renderDatabaseTypeFile`, `resolveCursorArgs`, `resolvePageArgs`, `selfOwnership`, `setAuditUser`, `siteOwnership`, `teamMembershipOwnership`, `toCursorPaginator`, `toPaginator`, `toSimplePaginator`, `toSnakeCaseKeys`.
631
631
 
632
- Local source modules: [src/auto-crud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/auto-crud.ts), [src/batch-loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/batch-loader.ts), [src/db.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/db.ts), [src/define-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/define-model.ts), [src/extend-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/extend-model.ts), [src/gdpr/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/gdpr/index.ts), [src/generate-database-schema.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/generate-database-schema.ts), [src/locked-row.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/locked-row.ts), [src/messaging.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/messaging.ts), [src/model-types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/model-types.ts), [src/ownership.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/ownership.ts), [src/paginator-request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/paginator-request.ts), [src/row-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/row-token.ts), [src/subquery.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/subquery.ts), [src/traits/audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/audit.ts), [src/traits/billable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/billable.ts), [src/traits/categorizable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/categorizable.ts), [src/traits/commentable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/commentable.ts), [src/traits/likeable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/likeable.ts), [src/traits/taggable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/taggable.ts), [src/transaction.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/transaction.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/types.ts), [src/utils/compiled-binary.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/compiled-binary.ts), [src/utils/encrypted.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/encrypted.ts), [src/utils/prunable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/prunable.ts).
632
+ Local source modules: [src/auto-crud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/auto-crud.ts), [src/batch-loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/batch-loader.ts), [src/db.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/db.ts), [src/define-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/define-model.ts), [src/extend-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/extend-model.ts), [src/gdpr/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/gdpr/index.ts), [src/generate-database-schema.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/generate-database-schema.ts), [src/locked-row.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/locked-row.ts), [src/messaging.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/messaging.ts), [src/model-types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/model-types.ts), [src/ownership.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/ownership.ts), [src/paginator-request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/paginator-request.ts), [src/row-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/row-token.ts), [src/subquery.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/subquery.ts), [src/traits/audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/audit.ts), [src/traits/billable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/billable.ts), [src/traits/categorizable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/categorizable.ts), [src/traits/commentable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/commentable.ts), [src/traits/likeable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/likeable.ts), [src/traits/taggable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/taggable.ts), [src/transaction.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/transaction.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/types.ts), [src/utils/encrypted.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/encrypted.ts), [src/utils/prunable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/prunable.ts).
633
633
 
634
- Evidence directory: [61 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
634
+ Evidence directory: [60 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
635
635
 
636
636
  ### @stacksjs/pagination
637
637
 
@@ -643,11 +643,11 @@ Declared runtime exports: `isCursorPaginator`, `isPaginator`, `isSimplePaginator
643
643
 
644
644
  Guidance: [`stacks-path`](../stacks-path/SKILL.md). Source: [storage/framework/core/path/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/path/src/index.ts).
645
645
 
646
- Declared runtime exports: `DEFAULTS_SYNC_MARKER`, `actionRunnerPath`, `actionsPath`, `aiPath`, `aliasPath`, `analyticsPath`, `appPath`, `applyRuntimeDirectoryEnv`, `arraysPath`, `assetsPath`, `authPath`, `basename`, `browserPath`, `buddyPath`, `buildEnginePath`, `buildPath`, `builtUserActionsPath`, `cachePath`, `chartsPath`, `chatPath`, `cliPath`, `cloudPath`, `cloudStatePath`, `collectionsPath`, `commandsPath`, `componentsPath`, `configPath`, `coreApiPath`, `coreEnvPath`, `corePath`, `coreStoragePath`, `customElementsDataPath`, `databasePath`, `datetimePath`, `defaultsAppPath`, `defaultsPackagePath`, `defaultsResourcesPath`, `delimiter`, `desktopPath`, `developmentPath`, `dirname`, `dnsPath`, `docsPath`, `emailPath`, `ensureRuntimeDirectories`, `enumsPath`, `errorHandlingPath`, `eslintPluginPath`, `eventsPath`, `examplesPath`, `extname`, `fakerPath`, `featureFlagsPath`, `featuresPath`, `findProjectPath`, `frameworkCloudPath`, `frameworkPath`, `frameworkRuntimePath`, `functionsPath`, `gitPath`, `healthPath`, `homeDir`, `inspectDefaultsProvenance`, `installedDefaultsVersion`, `isAbsolute`, `jobsPath`, `join`, `langPath`, `layoutsPath`, `libraryPackagePath`, `libsEntriesPath`, `libsPath`, `lintPath`, `listenersPath`, `loggingPath`, `logsPath`, `mergeDirectoryInto`, `modelMetaPath`, `modelsPath`, `modulesPath`, `newsletterPath`, `normalize`, `notificationsPath`, `objectsPath`, `onboardingPath`, `ormPath`, `paginationPath`, `path`, `pathPath`, `paymentsPath`, `projectConfigPath`, `projectPath`, `publicPath`, `pushPath`, `queryBuilderPath`, `queuePath`, `realtimePath`, `relative`, `relativeActionsPath`, `replPath`, `resolve`, `resolveUserLibBase`, `resourcesPath`, `routerPath`, `routesPath`, `runtimeDirectoryEnv`, `runtimePath`, `schedulerPath`, `scriptsPath`, `searchEnginePath`, `securityPath`, `sep`, `serverPath`, `serverlessPath`, `settingsPath`, `shellPath`, `siteConfigPath`, `skillsPath`, `slugPath`, `smsPath`, `socialsPath`, `stacksBackupPath`, `stacksLockPath`, `stacksPath`, `storagePath`, `storesPath`, `stringsPath`, `stxPath`, `testingPath`, `testsPath`, `tinkerPath`, `toNamespacedPath`, `typesPath`, `uiPath`, `userActionsPath`, `userComponentsPath`, `userControllersPath`, `userDatabasePath`, `userEmailsPath`, `userEventsPath`, `userFunctionsPath`, `userJobsPath`, `userLibsPath`, `userListenersPath`, `userMailPath`, `userMiddlewarePath`, `userMigrationsPath`, `userModelsPath`, `userNotificationsPath`, `userServerPath`, `userViewsPath`, `utilsPath`, `validationPath`, `viewsPath`.
646
+ Declared runtime exports: `DEFAULTS_SYNC_MARKER`, `actionRunnerPath`, `actionsPath`, `aiPath`, `aliasPath`, `analyticsPath`, `appPath`, `applyRuntimeDirectoryEnv`, `arraysPath`, `assetsPath`, `authPath`, `basename`, `browserPath`, `buddyPath`, `buildEnginePath`, `buildPath`, `builtUserActionsPath`, `cachePath`, `chartsPath`, `chatPath`, `cliPath`, `cloudPath`, `cloudStatePath`, `collectionsPath`, `commandsPath`, `componentsPath`, `configPath`, `coreApiPath`, `coreEnvPath`, `corePath`, `coreStoragePath`, `customElementsDataPath`, `databasePath`, `datetimePath`, `defaultsAppPath`, `defaultsPackagePath`, `defaultsResourcesPath`, `delimiter`, `desktopPath`, `developmentPath`, `dirname`, `dnsPath`, `docsPath`, `emailPath`, `ensureRuntimeDirectories`, `enumsPath`, `errorHandlingPath`, `eslintPluginPath`, `eventsPath`, `examplesPath`, `extname`, `fakerPath`, `featureFlagsPath`, `featuresPath`, `findProjectPath`, `frameworkCloudPath`, `frameworkPath`, `frameworkRuntimePath`, `functionsPath`, `gitPath`, `healthPath`, `homeDir`, `inspectDefaultsProvenance`, `installedDefaultsVersion`, `isAbsolute`, `isCompiledBinary`, `jobsPath`, `join`, `langPath`, `layoutsPath`, `libraryPackagePath`, `libsEntriesPath`, `libsPath`, `lintPath`, `listenersPath`, `loggingPath`, `logsPath`, `mergeDirectoryInto`, `modelMetaPath`, `modelsPath`, `modulesPath`, `newsletterPath`, `normalize`, `notificationsPath`, `objectsPath`, `onboardingPath`, `ormPath`, `paginationPath`, `path`, `pathPath`, `paymentsPath`, `projectConfigPath`, `projectPath`, `publicPath`, `pushPath`, `queryBuilderPath`, `queuePath`, `realtimePath`, `relative`, `relativeActionsPath`, `replPath`, `resolve`, `resolveUserLibBase`, `resourcesPath`, `routerPath`, `routesPath`, `runtimeDirectoryEnv`, `runtimePath`, `schedulerPath`, `scriptsPath`, `searchEnginePath`, `securityPath`, `sep`, `serverPath`, `serverlessPath`, `settingsPath`, `shellPath`, `siteConfigPath`, `skillsPath`, `slugPath`, `smsPath`, `socialsPath`, `stacksBackupPath`, `stacksLockPath`, `stacksPath`, `storagePath`, `storesPath`, `stringsPath`, `stxPath`, `testingPath`, `testsPath`, `tinkerPath`, `toNamespacedPath`, `typesPath`, `uiPath`, `userActionsPath`, `userComponentsPath`, `userControllersPath`, `userDatabasePath`, `userEmailsPath`, `userEventsPath`, `userFunctionsPath`, `userJobsPath`, `userLibsPath`, `userListenersPath`, `userMailPath`, `userMiddlewarePath`, `userMigrationsPath`, `userModelsPath`, `userNotificationsPath`, `userServerPath`, `userViewsPath`, `utilsPath`, `validationPath`, `viewsPath`.
647
647
 
648
648
  Local source modules: [src/project.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/path/src/project.ts).
649
649
 
650
- Evidence directory: [9 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/path/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
650
+ Evidence directory: [10 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/path/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
651
651
 
652
652
  ### @stacksjs/payments
653
653
 
@@ -721,7 +721,7 @@ Declared runtime exports: `DASHBOARD_ROUTE_GROUPS`, `DEFAULT_ROUTE_BUNDLE_FEATUR
721
721
 
722
722
  Local source modules: [src/api-shape.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/api-shape.ts), [src/dashboard-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/dashboard-access.ts), [src/encrypted-session-store.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/encrypted-session-store.ts), [src/error-handler.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/error-handler.ts), [src/health.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/health.ts), [src/middleware.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/middleware.ts), [src/path-sanitize.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/path-sanitize.ts), [src/rate-limit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/rate-limit.ts), [src/request-augmentation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/request-augmentation.ts), [src/request-context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/request-context.ts), [src/route-loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/route-loader.ts), [src/route-model-binding.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/route-model-binding.ts), [src/session-factory.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/session-factory.ts), [src/signed-url.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/signed-url.ts), [src/stacks-router.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/stacks-router.ts), [src/typed-router.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/typed-router.ts).
723
723
 
724
- Evidence directory: [86 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
724
+ Evidence directory: [87 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
725
725
 
726
726
  ### @stacksjs/scheduler
727
727
 
@@ -761,7 +761,7 @@ Declared runtime exports: `server`.
761
761
 
762
762
  Local source modules: [src/config.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/config.ts), [src/controllers/base.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/controllers/base.ts), [src/imports.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/imports.ts), [src/maintenance.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/maintenance.ts), [src/proxy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/proxy.ts), [src/redirects.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/redirects.ts), [src/rewrites.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/rewrites.ts), [src/security-headers.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/security-headers.ts).
763
763
 
764
- Evidence directory: [20 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
764
+ Evidence directory: [21 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
765
765
 
766
766
  ### @stacksjs/shell
767
767
 
@@ -2,7 +2,7 @@
2
2
  "publisher": "Stacks",
3
3
  "name": "vscode-stacks",
4
4
  "displayName": "Stacks",
5
- "version": "0.75.135",
5
+ "version": "0.75.137",
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.135",
5
+ "version": "0.75.137",
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.135",
58
+ "@stacksjs/mobile": "0.75.137",
59
59
  "@stacksjs/sanitizer": "^0.2.422",
60
60
  "@xterm/addon-fit": "^0.11.0",
61
61
  "@xterm/xterm": "^6.0.0",
@@ -0,0 +1,169 @@
1
+ <script server>
2
+ interface NativeBarButtonProps {
3
+ /** Where the button goes, such as `/m/messages`. */
4
+ href: string
5
+ /** What a screen reader calls the button. */
6
+ label: string
7
+ /** The SF Symbol the native bar draws for it (`bubble.left`), drawn here with its Iconify stand-in. */
8
+ symbol?: string
9
+ /** An Iconify class for a symbol the stand-ins below don't cover. */
10
+ icon?: string
11
+ /** A picture (the account's own photo), drawn round inside the button. */
12
+ image?: string
13
+ /** A short title instead of the symbol: an account's initials. */
14
+ title?: string
15
+ /** A count on the button. Zero and empty draw nothing. */
16
+ badge?: string | number
17
+ /** `count` draws the number, `dot` a red dot (unread notifications). */
18
+ badgeStyle?: 'count' | 'dot'
19
+ /** `accent` sits a shade stronger in dark mode (chat); `account` is the default. */
20
+ variant?: 'accent' | 'account'
21
+ }
22
+
23
+ const { symbol = '', icon = '' } = defineProps<NativeBarButtonProps>()
24
+
25
+ // The same names the native bar takes (mobileHeaderOptions-style rightButtons),
26
+ // so one list of buttons describes both. Written out so the stylesheet
27
+ // generator sees every class.
28
+ const standIns: Record<string, string> = {
29
+ 'bubble.left': 'i-lucide-message-square',
30
+ 'bubble.left.and.bubble.right': 'i-lucide-messages-square',
31
+ 'person.crop.circle': 'i-lucide-circle-user-round',
32
+ 'bell': 'i-lucide-bell',
33
+ 'gearshape': 'i-lucide-settings',
34
+ 'plus': 'i-lucide-plus',
35
+ 'magnifyingglass': 'i-lucide-search',
36
+ 'square.and.arrow.up': 'i-lucide-share',
37
+ }
38
+
39
+ export const glyphClass = `${icon || standIns[symbol] || 'i-lucide-circle-user-round'} native-bar-glyph`
40
+ </script>
41
+
42
+ <script client>
43
+ import { haptics } from '@stacksjs/mobile'
44
+
45
+ // A round button at the top right of a phone screen, drawn exactly as the
46
+ // app's native bar draws its buttons (Craft's accountNavigationButton in
47
+ // CraftNativeScreen.swift): a 44pt circle tinted with the accent, a 20pt
48
+ // glyph, a 36pt photo inset in the circle, a count badge or a red dot at its
49
+ // top right. The native screens (Today, Calendar) and the web screens of the
50
+ // same app then show one set of buttons, not two that almost match.
51
+ //
52
+ // Every prop through useReactiveProp, under names of its own: read as plain
53
+ // {{ label }}, a host's client signal of the same name would be shown instead.
54
+ // What shows (picture, title or glyph) is written in the template itself: a
55
+ // derived only the template reads is dropped by the bundler's tree-shake.
56
+ const barHref = useReactiveProp<string>('href', '')
57
+ const barLabel = useReactiveProp<string>('label', '')
58
+ const barImage = useReactiveProp<string>('image', '')
59
+ const barTitle = useReactiveProp<string>('title', '')
60
+ const barBadge = useReactiveProp<string | number>('badge', '')
61
+ const barBadgeStyle = useReactiveProp<string>('badgeStyle', 'count')
62
+ const barVariant = useReactiveProp<string>('variant', 'account')
63
+
64
+ const barCount = derived(() => {
65
+ const value = barBadge()
66
+ return value === '' || value === 0 || value === '0' || value == null ? '' : Number(value) > 99 ? '99+' : String(value)
67
+ })
68
+ const barDot = derived(() => barBadgeStyle() === 'dot')
69
+ const barPhoto = derived(() => (barImage() ? `background-image: url("${String(barImage()).replace(/"/g, '%22')}")` : ''))
70
+
71
+ function tapBarButton(): void {
72
+ void haptics.selection()
73
+ }
74
+ </script>
75
+
76
+ <a :href="barHref()" class="native-bar-button" :class="barVariant() === 'accent' ? 'native-bar-accent' : ''" draggable="false" data-stx-link data-stx-prefetch="eager" @click="tapBarButton()">
77
+ <span class="native-bar-label">{{ barLabel() }}<span :if="barCount()">, {{ barCount() }} unread</span></span>
78
+ <span :if="barImage()" aria-hidden="true" class="native-bar-photo" :style="barPhoto()"></span>
79
+ <span :if="!barImage() && barTitle()" aria-hidden="true" class="native-bar-title">{{ barTitle() }}</span>
80
+ <!-- :show, not :if: an :if branch is re-rendered in the browser, where the
81
+ server's glyphClass doesn't exist, and the glyph silently never drew. -->
82
+ <i :show="!barImage() && !barTitle()" aria-hidden="true" class="{{ glyphClass }}"></i>
83
+ <span :if="barCount() && !barDot()" aria-hidden="true" class="native-bar-count">{{ barCount() }}</span>
84
+ <span :if="barCount() && barDot()" aria-hidden="true" class="native-bar-dot"></span>
85
+ </a>
86
+
87
+ <style>
88
+ /* The values are Craft's (CraftNativeScreen.swift, accountNavigationButton):
89
+ keep them in step, or the web and native screens drift apart again. */
90
+ .native-bar-button {
91
+ position: relative;
92
+ display: inline-flex;
93
+ flex: none;
94
+ align-items: center;
95
+ justify-content: center;
96
+ width: 2.75rem;
97
+ height: 2.75rem;
98
+ border-radius: 999px;
99
+ color: rgb(28 77 217);
100
+ background: rgb(38 99 235 / 0.08);
101
+ text-decoration: none;
102
+ -webkit-tap-highlight-color: transparent;
103
+ -webkit-touch-callout: none;
104
+ transition: transform 120ms ease, opacity 120ms ease;
105
+ }
106
+
107
+ .native-bar-button:active { transform: scale(0.94); opacity: 0.85; }
108
+
109
+ .native-bar-label {
110
+ position: absolute;
111
+ width: 1px;
112
+ height: 1px;
113
+ overflow: hidden;
114
+ clip: rect(0 0 0 0);
115
+ white-space: nowrap;
116
+ }
117
+
118
+ .native-bar-glyph { width: 1.25rem; height: 1.25rem; }
119
+
120
+ .native-bar-title {
121
+ font-size: 0.8125rem;
122
+ font-weight: 600;
123
+ letter-spacing: 0.01em;
124
+ }
125
+
126
+ .native-bar-photo {
127
+ width: 2.25rem;
128
+ height: 2.25rem;
129
+ border-radius: 999px;
130
+ background: center / cover no-repeat;
131
+ }
132
+
133
+ .native-bar-count {
134
+ position: absolute;
135
+ top: 0;
136
+ right: 0;
137
+ min-width: 1.125rem;
138
+ height: 1.125rem;
139
+ padding: 0 0.25rem;
140
+ border-radius: 999px;
141
+ color: white;
142
+ background: rgb(0 122 255);
143
+ font-size: 0.625rem;
144
+ font-weight: 700;
145
+ line-height: 1.125rem;
146
+ text-align: center;
147
+ }
148
+
149
+ .native-bar-dot {
150
+ position: absolute;
151
+ top: 0;
152
+ right: 0;
153
+ width: 0.5625rem;
154
+ height: 0.5625rem;
155
+ border-radius: 999px;
156
+ background: rgb(255 59 48);
157
+ }
158
+
159
+ .dark .native-bar-button {
160
+ color: rgb(148 196 252);
161
+ background: rgb(38 99 235 / 0.12);
162
+ }
163
+
164
+ .dark .native-bar-accent { background: rgb(38 99 235 / 0.24); }
165
+
166
+ @media (prefers-reduced-motion: reduce) {
167
+ .native-bar-button { transition: none; }
168
+ }
169
+ </style>
@@ -39,6 +39,19 @@ describe('Native components', () => {
39
39
  expect(button).not.toContain('<img')
40
40
  })
41
41
 
42
+ it('draws bar buttons as the native bar does, from the same SF Symbol names', () => {
43
+ const button = read('NativeBarButton')
44
+ // Craft's accountNavigationButton: a 44pt tinted circle, a 36pt photo inset.
45
+ expect(button).toContain('width: 2.75rem;')
46
+ expect(button).toContain('background: rgb(38 99 235 / 0.08);')
47
+ expect(button).toContain('width: 2.25rem;')
48
+ expect(button).toContain("'bubble.left': 'i-lucide-message-square'")
49
+ expect(button).toContain("useReactiveProp<string | number>('badge', '')")
50
+ expect(button).toContain('data-stx-link data-stx-prefetch="eager"')
51
+ // A photo is a background, not an <img>: apps check that every image goes through their delivery.
52
+ expect(button).not.toContain('<img')
53
+ })
54
+
42
55
  it('lifts the launch splash once the first screen has painted', () => {
43
56
  expect(read('NativeAppShell')).toContain('requestAnimationFrame(() => requestAnimationFrame(() => splash.hide()))')
44
57
  })