@owlmeans/create-app 0.1.18-rc.26 → 0.1.18-rc.27
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 +3 -3
- package/build/args.js +1 -1
- package/build/run.js +2 -2
- package/package.json +2 -2
- package/template/AGENTS.md +1 -1
- package/template/README.bare.md +1 -1
- package/template/_agents/skills/getting-started/SKILL.md +6 -6
- package/template/_agents/skills/reuse-code/SKILL.md +2 -2
- package/template/sources/api/package.json +2 -2
- package/template/sources/api/src/entrypoints.bare.ts +1 -1
- package/template/sources/api/src/entrypoints.ts +6 -6
- package/template/sources/api/src/index.ts +2 -2
- package/template/sources/common/package.json +5 -5
- package/template/sources/common/src/entrypoints.bare.ts +1 -1
- package/template/sources/common/src/entrypoints.ts +4 -4
- package/template/sources/web/package.json +10 -10
- package/template/sources/web/src/components/ui/dropdown-menu.tsx +257 -0
- package/template/sources/web/src/entrypoints.bare.ts +5 -5
- package/template/sources/web/src/entrypoints.ts +7 -7
- package/template/sources/web/src/index.tsx +2 -2
- package/template/sources/web/src/nav.ts +2 -2
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ bun create @owlmeans/app my-app
|
|
|
9
9
|
# or
|
|
10
10
|
yarn create @owlmeans/app my-app
|
|
11
11
|
# or
|
|
12
|
-
npx @owlmeans/create-app@^0.1.18-rc.
|
|
12
|
+
npx @owlmeans/create-app@^0.1.18-rc.27 my-app
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## What it generates
|
|
@@ -23,7 +23,7 @@ my-app/
|
|
|
23
23
|
├── .agents/skills/<name>/SKILL.md # deployed agent skills
|
|
24
24
|
├── .agents/memory/MEMORY.md # shared agent memory index
|
|
25
25
|
├── sources/
|
|
26
|
-
│ ├── common/ # shared
|
|
26
|
+
│ ├── common/ # shared protocol declarations (routes), schemas and types
|
|
27
27
|
│ ├── api/ # @owlmeans/server-app backend; session data in an in-memory static resource
|
|
28
28
|
│ └── web/ # @owlmeans/web-panel + shadcn UI: navigation, layout and screens
|
|
29
29
|
```
|
|
@@ -65,7 +65,7 @@ is present even with `--no-install`.
|
|
|
65
65
|
`--bare` keeps the three workspaces, the config/context/entrypoint wiring, the layout, the nav
|
|
66
66
|
skeleton and one Home screen, and drops every piece of example code — the `SessionItem` types and
|
|
67
67
|
schemas, the api's `app/session/**` handlers and its static resource, the About and Session screens.
|
|
68
|
-
`sources/common/src/entrypoints.ts` exports an immutable `
|
|
68
|
+
`sources/common/src/entrypoints.ts` exports an immutable `appProtocols` tree with an empty `api`
|
|
69
69
|
branch and the web routes. The API and web bind those branches locally, so the first feature adds a
|
|
70
70
|
declaration to the tree, then a handler and a screen binding.
|
|
71
71
|
|
package/build/args.js
CHANGED
|
@@ -5,7 +5,7 @@ Usage:
|
|
|
5
5
|
npm create @owlmeans/app@latest <dir> [options]
|
|
6
6
|
bun create @owlmeans/app <dir> [options]
|
|
7
7
|
yarn create @owlmeans/app <dir> [options]
|
|
8
|
-
npx @owlmeans/create-app@^0.1.18-rc.
|
|
8
|
+
npx @owlmeans/create-app@^0.1.18-rc.27 <dir> [options]
|
|
9
9
|
|
|
10
10
|
Generates three workspaces (common + api + web) with shadcn UI navigation and
|
|
11
11
|
layout, no authentication, and a session-scoped in-memory resource on the
|
package/build/run.js
CHANGED
|
@@ -50,7 +50,7 @@ export const run = async (args) => {
|
|
|
50
50
|
log(args.install
|
|
51
51
|
? '\nDeploying agent skills via @owlmeans/agent-skills…'
|
|
52
52
|
: '\nDeploying harness guidance via @owlmeans/agent-skills (general skills only — re-run'
|
|
53
|
-
+ '\n`npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
53
|
+
+ '\n`npx @owlmeans/agent-skills@^0.1.18-rc.21` after installing to add the package-specific ones)…');
|
|
54
54
|
try {
|
|
55
55
|
const result = await installSkills({
|
|
56
56
|
dir: dest,
|
|
@@ -62,7 +62,7 @@ export const run = async (args) => {
|
|
|
62
62
|
help: false,
|
|
63
63
|
});
|
|
64
64
|
if (result.code !== 0) {
|
|
65
|
-
process.stderr.write(` agent-skills exited with code ${result.code} — you can re-run \`npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
65
|
+
process.stderr.write(` agent-skills exited with code ${result.code} — you can re-run \`npx @owlmeans/agent-skills@^0.1.18-rc.21\` later.\n`);
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
catch (err) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/create-app",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.27",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Scaffold a fullstack OwlMeans Common app — common + api + web workspaces, shadcn UI navigation/layout, no auth, and a session-scoped in-memory resource, or --bare for the demo-free shell. Also usable programmatically via scaffold(). Deploys agent skills via @owlmeans/agent-skills by default.",
|
|
6
6
|
"type": "module",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"template"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@owlmeans/agent-skills": "^0.1.18-rc.
|
|
33
|
+
"@owlmeans/agent-skills": "^0.1.18-rc.21"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@owlmeans/dep-config": "workspace:*",
|
package/template/AGENTS.md
CHANGED
|
@@ -94,7 +94,7 @@ from the installed `@owlmeans/*` packages. Agents load a skill by topic, or you
|
|
|
94
94
|
explicitly. Copilot and Codex read `.agents/skills/` directly; Claude Code reads the generated
|
|
95
95
|
symlinks in `.claude/skills/` (see `CLAUDE.md`).
|
|
96
96
|
|
|
97
|
-
- After adding or updating any `@owlmeans/*` dependency, run `npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
97
|
+
- After adding or updating any `@owlmeans/*` dependency, run `npx @owlmeans/agent-skills@^0.1.18-rc.21` to refresh
|
|
98
98
|
the deployed skills.
|
|
99
99
|
- Deployed files carry an `AUTO-GENERATED` banner and are refreshed in place — never hand-edit them.
|
|
100
100
|
- To capture your own guidance, see the `skill-authoring` skill; to turn repeatedly-used memory into
|
package/template/README.bare.md
CHANGED
|
@@ -13,7 +13,7 @@ runtime. The declaration is never modified by a server or browser.
|
|
|
13
13
|
|
|
14
14
|
```ts
|
|
15
15
|
// common/src/entrypoints.ts
|
|
16
|
-
export const
|
|
16
|
+
export const sessionProtocols = {
|
|
17
17
|
list: protocol(
|
|
18
18
|
route(session.list, '/session', backend()),
|
|
19
19
|
contract.request({ query: typed<SessionQuery>(SessionQuerySchema) }, typed<Session[]>())
|
|
@@ -24,20 +24,20 @@ export const sessionEntrypoints = {
|
|
|
24
24
|
```ts
|
|
25
25
|
// api/src/entrypoints.ts
|
|
26
26
|
const api = handlers<Context>()
|
|
27
|
-
export const
|
|
27
|
+
export const serverBindings = [
|
|
28
28
|
...frameworkEntrypoints,
|
|
29
|
-
bind(
|
|
29
|
+
bind(sessionProtocols.list, api.request(sessionProtocols.list, listSessions)),
|
|
30
30
|
]
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
```ts
|
|
34
34
|
// web/src/entrypoints.ts
|
|
35
|
-
export const
|
|
35
|
+
export const clientBindings = [
|
|
36
36
|
...frameworkEntrypoints,
|
|
37
|
-
...bindAll(
|
|
37
|
+
...bindAll(sessionProtocols),
|
|
38
38
|
]
|
|
39
39
|
|
|
40
|
-
const sessions = await context.entrypoint(
|
|
40
|
+
const sessions = await context.entrypoint(sessionProtocols.list).call({ query: { sid } })
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
Use `schema<T>(...)` or `typed<T>(...)` at the contract boundary. Bind all route parents with their
|
|
@@ -47,7 +47,7 @@ How you research the repo depends on whether `@owlmeans/*` is linked locally:
|
|
|
47
47
|
**https://github.com/owlmeans/common** — `tree.md` and package READMEs — to find the right package.
|
|
48
48
|
|
|
49
49
|
This is the same dev-linked detection `@owlmeans/agent-skills` uses (see its `detectLinked`). After
|
|
50
|
-
adding an `@owlmeans/*` dependency, run `npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
50
|
+
adding an `@owlmeans/*` dependency, run `npx @owlmeans/agent-skills@^0.1.18-rc.21` to deploy its
|
|
51
51
|
skill. Prefer an `@owlmeans/*` package over a third-party library or bespoke code whenever one fits.
|
|
52
52
|
|
|
53
53
|
### Never add an OwlMeans dependency without an explicit range
|
|
@@ -57,7 +57,7 @@ other `@owlmeans/*` packages:
|
|
|
57
57
|
|
|
58
58
|
```json
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@owlmeans/queue": "^0.1.18-rc.
|
|
60
|
+
"@owlmeans/queue": "^0.1.18-rc.18"
|
|
61
61
|
}
|
|
62
62
|
```
|
|
63
63
|
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"typecheck": "tsc -b"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@owlmeans/server-app": "^0.1.18-rc.
|
|
15
|
-
"@owlmeans/static-resource": "^0.1.18-rc.
|
|
14
|
+
"@owlmeans/server-app": "^0.1.18-rc.28",
|
|
15
|
+
"@owlmeans/static-resource": "^0.1.18-rc.18",
|
|
16
16
|
"__APP_SLUG__-common": "workspace:^"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { entrypoints } from '@owlmeans/server-app'
|
|
2
2
|
import { bind } from '@owlmeans/server-entrypoint'
|
|
3
|
-
import {
|
|
3
|
+
import { appProtocols } from '__APP_SLUG__-common'
|
|
4
4
|
import * as handlers from './app/session/index.js'
|
|
5
5
|
|
|
6
6
|
/** Local server bindings for the shared session protocol tree. */
|
|
7
|
-
export const
|
|
7
|
+
export const appBindings = [
|
|
8
8
|
...entrypoints,
|
|
9
|
-
bind(
|
|
10
|
-
bind(
|
|
11
|
-
bind(
|
|
12
|
-
bind(
|
|
9
|
+
bind(appProtocols.api.session.base),
|
|
10
|
+
bind(appProtocols.api.session.list, handlers.list),
|
|
11
|
+
bind(appProtocols.api.session.add, handlers.add),
|
|
12
|
+
bind(appProtocols.api.session.remove, handlers.remove),
|
|
13
13
|
]
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { main } from '@owlmeans/server-app'
|
|
2
2
|
import config from './config.js'
|
|
3
3
|
import { makeContext } from './context.js'
|
|
4
|
-
import {
|
|
4
|
+
import { appBindings } from './entrypoints.js'
|
|
5
5
|
import type { Config, Context } from './types.js'
|
|
6
6
|
|
|
7
7
|
const context = makeContext<Config, Context>(config)
|
|
8
8
|
|
|
9
|
-
main<{}, Config, Context>(context,
|
|
9
|
+
main<{}, Config, Context>(context, appBindings)
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
"typecheck": "tsc -b"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@owlmeans/config": "^0.1.18-rc.
|
|
23
|
-
"@owlmeans/entrypoint": "^0.1.18-rc.
|
|
24
|
-
"@owlmeans/error": "^0.1.18-rc.
|
|
25
|
-
"@owlmeans/resource": "^0.1.18-rc.
|
|
26
|
-
"@owlmeans/route": "^0.1.18-rc.
|
|
22
|
+
"@owlmeans/config": "^0.1.18-rc.21",
|
|
23
|
+
"@owlmeans/entrypoint": "^0.1.18-rc.20",
|
|
24
|
+
"@owlmeans/error": "^0.1.18-rc.17",
|
|
25
|
+
"@owlmeans/resource": "^0.1.18-rc.18",
|
|
26
|
+
"@owlmeans/route": "^0.1.18-rc.18",
|
|
27
27
|
"ajv": "^8.17.1"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
@@ -5,7 +5,7 @@ import { frontend, route } from '@owlmeans/route'
|
|
|
5
5
|
const webBase = openProtocol(route(BASE, '/', frontend()))
|
|
6
6
|
|
|
7
7
|
/** The shared immutable protocol tree. Add API declarations below `api` as the shell grows. */
|
|
8
|
-
export const
|
|
8
|
+
export const appProtocols = {
|
|
9
9
|
api: {},
|
|
10
10
|
web: {
|
|
11
11
|
base: webBase,
|
|
@@ -54,7 +54,7 @@ export const web = {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/** The shared immutable protocol tree. Runtime packages bind their own local handlers and screens. */
|
|
57
|
-
export const
|
|
58
|
-
api: { session },
|
|
59
|
-
web,
|
|
60
|
-
}
|
|
57
|
+
export const appProtocols = Object.freeze({
|
|
58
|
+
api: Object.freeze({ session }),
|
|
59
|
+
web: Object.freeze(web),
|
|
60
|
+
})
|
|
@@ -11,16 +11,16 @@
|
|
|
11
11
|
"preview": "vite preview"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@owlmeans/client": "^0.1.18-rc.
|
|
15
|
-
"@owlmeans/client-config": "^0.1.18-rc.
|
|
16
|
-
"@owlmeans/client-context": "^0.1.18-rc.
|
|
17
|
-
"@owlmeans/client-entrypoint": "^0.1.18-rc.
|
|
18
|
-
"@owlmeans/client-i18n": "^0.1.18-rc.
|
|
19
|
-
"@owlmeans/entrypoint": "^0.1.18-rc.
|
|
20
|
-
"@owlmeans/route": "^0.1.18-rc.
|
|
21
|
-
"@owlmeans/state": "^0.1.18-rc.
|
|
22
|
-
"@owlmeans/web-client": "^0.1.18-rc.
|
|
23
|
-
"@owlmeans/web-panel": "^0.1.18-rc.
|
|
14
|
+
"@owlmeans/client": "^0.1.18-rc.25",
|
|
15
|
+
"@owlmeans/client-config": "^0.1.18-rc.21",
|
|
16
|
+
"@owlmeans/client-context": "^0.1.18-rc.22",
|
|
17
|
+
"@owlmeans/client-entrypoint": "^0.1.18-rc.22",
|
|
18
|
+
"@owlmeans/client-i18n": "^0.1.18-rc.24",
|
|
19
|
+
"@owlmeans/entrypoint": "^0.1.18-rc.20",
|
|
20
|
+
"@owlmeans/route": "^0.1.18-rc.18",
|
|
21
|
+
"@owlmeans/state": "^0.1.18-rc.19",
|
|
22
|
+
"@owlmeans/web-client": "^0.1.18-rc.34",
|
|
23
|
+
"@owlmeans/web-panel": "^0.1.18-rc.42",
|
|
24
24
|
"@radix-ui/react-label": "^2.1.0",
|
|
25
25
|
"@radix-ui/react-navigation-menu": "^1.2.14",
|
|
26
26
|
"@radix-ui/react-progress": "^1.1.0",
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
|
5
|
+
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
|
|
6
|
+
|
|
7
|
+
import { cn } from "@/lib/utils"
|
|
8
|
+
|
|
9
|
+
function DropdownMenu({
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
|
12
|
+
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function DropdownMenuPortal({
|
|
16
|
+
...props
|
|
17
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
|
18
|
+
return (
|
|
19
|
+
<DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function DropdownMenuTrigger({
|
|
24
|
+
...props
|
|
25
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
|
26
|
+
return (
|
|
27
|
+
<DropdownMenuPrimitive.Trigger
|
|
28
|
+
data-slot="dropdown-menu-trigger"
|
|
29
|
+
{...props}
|
|
30
|
+
/>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function DropdownMenuContent({
|
|
35
|
+
className,
|
|
36
|
+
sideOffset = 4,
|
|
37
|
+
...props
|
|
38
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
|
39
|
+
return (
|
|
40
|
+
<DropdownMenuPrimitive.Portal>
|
|
41
|
+
<DropdownMenuPrimitive.Content
|
|
42
|
+
data-slot="dropdown-menu-content"
|
|
43
|
+
sideOffset={sideOffset}
|
|
44
|
+
className={cn(
|
|
45
|
+
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
|
|
46
|
+
className
|
|
47
|
+
)}
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
</DropdownMenuPrimitive.Portal>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function DropdownMenuGroup({
|
|
55
|
+
...props
|
|
56
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
|
57
|
+
return (
|
|
58
|
+
<DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function DropdownMenuItem({
|
|
63
|
+
className,
|
|
64
|
+
inset,
|
|
65
|
+
variant = "default",
|
|
66
|
+
...props
|
|
67
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
|
68
|
+
inset?: boolean
|
|
69
|
+
variant?: "default" | "destructive"
|
|
70
|
+
}) {
|
|
71
|
+
return (
|
|
72
|
+
<DropdownMenuPrimitive.Item
|
|
73
|
+
data-slot="dropdown-menu-item"
|
|
74
|
+
data-inset={inset}
|
|
75
|
+
data-variant={variant}
|
|
76
|
+
className={cn(
|
|
77
|
+
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
78
|
+
className
|
|
79
|
+
)}
|
|
80
|
+
{...props}
|
|
81
|
+
/>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function DropdownMenuCheckboxItem({
|
|
86
|
+
className,
|
|
87
|
+
children,
|
|
88
|
+
checked,
|
|
89
|
+
...props
|
|
90
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
|
|
91
|
+
return (
|
|
92
|
+
<DropdownMenuPrimitive.CheckboxItem
|
|
93
|
+
data-slot="dropdown-menu-checkbox-item"
|
|
94
|
+
className={cn(
|
|
95
|
+
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
96
|
+
className
|
|
97
|
+
)}
|
|
98
|
+
checked={checked}
|
|
99
|
+
{...props}
|
|
100
|
+
>
|
|
101
|
+
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
102
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
103
|
+
<CheckIcon className="size-4" />
|
|
104
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
105
|
+
</span>
|
|
106
|
+
{children}
|
|
107
|
+
</DropdownMenuPrimitive.CheckboxItem>
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function DropdownMenuRadioGroup({
|
|
112
|
+
...props
|
|
113
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
|
114
|
+
return (
|
|
115
|
+
<DropdownMenuPrimitive.RadioGroup
|
|
116
|
+
data-slot="dropdown-menu-radio-group"
|
|
117
|
+
{...props}
|
|
118
|
+
/>
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function DropdownMenuRadioItem({
|
|
123
|
+
className,
|
|
124
|
+
children,
|
|
125
|
+
...props
|
|
126
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
|
|
127
|
+
return (
|
|
128
|
+
<DropdownMenuPrimitive.RadioItem
|
|
129
|
+
data-slot="dropdown-menu-radio-item"
|
|
130
|
+
className={cn(
|
|
131
|
+
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
132
|
+
className
|
|
133
|
+
)}
|
|
134
|
+
{...props}
|
|
135
|
+
>
|
|
136
|
+
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
137
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
138
|
+
<CircleIcon className="size-2 fill-current" />
|
|
139
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
140
|
+
</span>
|
|
141
|
+
{children}
|
|
142
|
+
</DropdownMenuPrimitive.RadioItem>
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function DropdownMenuLabel({
|
|
147
|
+
className,
|
|
148
|
+
inset,
|
|
149
|
+
...props
|
|
150
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
|
151
|
+
inset?: boolean
|
|
152
|
+
}) {
|
|
153
|
+
return (
|
|
154
|
+
<DropdownMenuPrimitive.Label
|
|
155
|
+
data-slot="dropdown-menu-label"
|
|
156
|
+
data-inset={inset}
|
|
157
|
+
className={cn(
|
|
158
|
+
"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
|
|
159
|
+
className
|
|
160
|
+
)}
|
|
161
|
+
{...props}
|
|
162
|
+
/>
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function DropdownMenuSeparator({
|
|
167
|
+
className,
|
|
168
|
+
...props
|
|
169
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
|
170
|
+
return (
|
|
171
|
+
<DropdownMenuPrimitive.Separator
|
|
172
|
+
data-slot="dropdown-menu-separator"
|
|
173
|
+
className={cn("bg-border -mx-1 my-1 h-px", className)}
|
|
174
|
+
{...props}
|
|
175
|
+
/>
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function DropdownMenuShortcut({
|
|
180
|
+
className,
|
|
181
|
+
...props
|
|
182
|
+
}: React.ComponentProps<"span">) {
|
|
183
|
+
return (
|
|
184
|
+
<span
|
|
185
|
+
data-slot="dropdown-menu-shortcut"
|
|
186
|
+
className={cn(
|
|
187
|
+
"text-muted-foreground ml-auto text-xs tracking-widest",
|
|
188
|
+
className
|
|
189
|
+
)}
|
|
190
|
+
{...props}
|
|
191
|
+
/>
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function DropdownMenuSub({
|
|
196
|
+
...props
|
|
197
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
|
198
|
+
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function DropdownMenuSubTrigger({
|
|
202
|
+
className,
|
|
203
|
+
inset,
|
|
204
|
+
children,
|
|
205
|
+
...props
|
|
206
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
|
207
|
+
inset?: boolean
|
|
208
|
+
}) {
|
|
209
|
+
return (
|
|
210
|
+
<DropdownMenuPrimitive.SubTrigger
|
|
211
|
+
data-slot="dropdown-menu-sub-trigger"
|
|
212
|
+
data-inset={inset}
|
|
213
|
+
className={cn(
|
|
214
|
+
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8",
|
|
215
|
+
className
|
|
216
|
+
)}
|
|
217
|
+
{...props}
|
|
218
|
+
>
|
|
219
|
+
{children}
|
|
220
|
+
<ChevronRightIcon className="ml-auto size-4" />
|
|
221
|
+
</DropdownMenuPrimitive.SubTrigger>
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function DropdownMenuSubContent({
|
|
226
|
+
className,
|
|
227
|
+
...props
|
|
228
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
|
229
|
+
return (
|
|
230
|
+
<DropdownMenuPrimitive.SubContent
|
|
231
|
+
data-slot="dropdown-menu-sub-content"
|
|
232
|
+
className={cn(
|
|
233
|
+
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
|
|
234
|
+
className
|
|
235
|
+
)}
|
|
236
|
+
{...props}
|
|
237
|
+
/>
|
|
238
|
+
)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export {
|
|
242
|
+
DropdownMenu,
|
|
243
|
+
DropdownMenuPortal,
|
|
244
|
+
DropdownMenuTrigger,
|
|
245
|
+
DropdownMenuContent,
|
|
246
|
+
DropdownMenuGroup,
|
|
247
|
+
DropdownMenuLabel,
|
|
248
|
+
DropdownMenuItem,
|
|
249
|
+
DropdownMenuCheckboxItem,
|
|
250
|
+
DropdownMenuRadioGroup,
|
|
251
|
+
DropdownMenuRadioItem,
|
|
252
|
+
DropdownMenuSeparator,
|
|
253
|
+
DropdownMenuShortcut,
|
|
254
|
+
DropdownMenuSub,
|
|
255
|
+
DropdownMenuSubTrigger,
|
|
256
|
+
DropdownMenuSubContent,
|
|
257
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { bindAll, bindScreen, entrypoints as baseEntrypoints, handler } from '@owlmeans/web-panel'
|
|
2
|
-
import {
|
|
2
|
+
import { appProtocols } from '__APP_SLUG__-common'
|
|
3
3
|
import { MainLayout } from './layout/main.js'
|
|
4
4
|
import { HomeScreen } from './screens/home.js'
|
|
5
5
|
|
|
6
6
|
/** Local browser bindings for shared API and screen protocols. */
|
|
7
|
-
export const
|
|
7
|
+
export const appBindings = [
|
|
8
8
|
...baseEntrypoints,
|
|
9
|
-
...bindAll(
|
|
9
|
+
...bindAll(appProtocols.api),
|
|
10
10
|
// BASE renders the shared layout; HOME is its default child.
|
|
11
|
-
bindScreen(
|
|
12
|
-
bindScreen(
|
|
11
|
+
bindScreen(appProtocols.web.base, handler(MainLayout)),
|
|
12
|
+
bindScreen(appProtocols.web.home, handler(HomeScreen)),
|
|
13
13
|
]
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { bindAll, bindScreen, entrypoints as baseEntrypoints, handler } from '@owlmeans/web-panel'
|
|
2
|
-
import {
|
|
2
|
+
import { appProtocols } from '__APP_SLUG__-common'
|
|
3
3
|
import { MainLayout } from './layout/main.js'
|
|
4
4
|
import { AboutScreen } from './screens/about.js'
|
|
5
5
|
import { HomeScreen } from './screens/home.js'
|
|
6
6
|
import { SessionScreen } from './screens/session.js'
|
|
7
7
|
|
|
8
8
|
/** Local browser bindings for shared API and screen protocols. */
|
|
9
|
-
export const
|
|
9
|
+
export const appBindings = [
|
|
10
10
|
...baseEntrypoints,
|
|
11
|
-
...bindAll(
|
|
12
|
-
bindScreen(
|
|
13
|
-
bindScreen(
|
|
14
|
-
bindScreen(
|
|
15
|
-
bindScreen(
|
|
11
|
+
...bindAll(appProtocols.api),
|
|
12
|
+
bindScreen(appProtocols.web.base, handler(MainLayout)),
|
|
13
|
+
bindScreen(appProtocols.web.home, handler(HomeScreen)),
|
|
14
|
+
bindScreen(appProtocols.web.session, handler(SessionScreen)),
|
|
15
|
+
bindScreen(appProtocols.web.about, handler(AboutScreen)),
|
|
16
16
|
]
|
|
@@ -2,12 +2,12 @@ import './index.css'
|
|
|
2
2
|
import { APP_API, APP_WEB } from '__APP_SLUG__-common'
|
|
3
3
|
import config from './config.js'
|
|
4
4
|
import { makeContext } from './context.js'
|
|
5
|
-
import {
|
|
5
|
+
import { appBindings } from './entrypoints.js'
|
|
6
6
|
import { render } from './render.js'
|
|
7
7
|
import type { Config, Context } from './types.js'
|
|
8
8
|
|
|
9
9
|
const context = makeContext<Config, Context>(config)
|
|
10
|
-
context.registerEntrypoints(
|
|
10
|
+
context.registerEntrypoints(appBindings)
|
|
11
11
|
|
|
12
12
|
context.serviceRoute(APP_WEB, true)
|
|
13
13
|
context.serviceRoute(APP_API, true)
|
|
@@ -15,8 +15,8 @@ export const navConfig: PanelNavConfig = {
|
|
|
15
15
|
{ name: 'home', label: 'Home', items: [{ alias: HOME, label: 'Overview' }] },
|
|
16
16
|
{
|
|
17
17
|
name: 'demo', label: 'Demo', items: [
|
|
18
|
-
{ alias: web.session, label: 'Session' },
|
|
19
|
-
{ alias: web.about, label: 'About' },
|
|
18
|
+
{ alias: web.session.alias, label: 'Session' },
|
|
19
|
+
{ alias: web.about.alias, label: 'About' },
|
|
20
20
|
]
|
|
21
21
|
},
|
|
22
22
|
],
|