@owlmeans/create-app 0.1.18-rc.7 → 0.1.18-rc.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/create-app",
3
- "version": "0.1.18-rc.7",
3
+ "version": "0.1.18-rc.8",
4
4
  "license": "MIT",
5
5
  "description": "Scaffold a minimal fullstack OwlMeans Common app — common + api + web workspaces, shadcn UI navigation/layout, no auth, and a session-scoped in-memory resource. Deploys agent skills via @owlmeans/agent-skills by default.",
6
6
  "type": "module",
@@ -29,7 +29,7 @@
29
29
  "template"
30
30
  ],
31
31
  "dependencies": {
32
- "@owlmeans/agent-skills": "^0.1.18-rc.6"
32
+ "@owlmeans/agent-skills": "^0.1.18-rc.7"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@owlmeans/dep-config": "workspace:*",
@@ -18,4 +18,5 @@ export const session = {
18
18
  /** Frontend (web) entrypoint identifiers. */
19
19
  export const web = {
20
20
  session: '__APP_SLUG__:web:session',
21
+ about: '__APP_SLUG__:web:about',
21
22
  }
@@ -22,6 +22,7 @@
22
22
  "@owlmeans/web-client": "^0.1.18-rc.0",
23
23
  "@owlmeans/web-panel": "^0.1.18-rc.0",
24
24
  "@radix-ui/react-label": "^2.1.0",
25
+ "@radix-ui/react-navigation-menu": "^1.2.14",
25
26
  "@radix-ui/react-progress": "^1.1.0",
26
27
  "@radix-ui/react-slot": "^1.1.0",
27
28
  "__APP_SLUG__-common": "workspace:^",
@@ -0,0 +1,169 @@
1
+ // shadcn navigation-menu — sourced from shadcn/ui (new-york) 2026-08-24
2
+ import * as React from "react"
3
+ import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
4
+ import { cva } from "class-variance-authority"
5
+ import { ChevronDownIcon } from "lucide-react"
6
+
7
+ import { cn } from "@/lib/utils"
8
+
9
+ function NavigationMenu({
10
+ className,
11
+ children,
12
+ viewport = true,
13
+ ...props
14
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {
15
+ viewport?: boolean
16
+ }) {
17
+ return (
18
+ <NavigationMenuPrimitive.Root
19
+ data-slot="navigation-menu"
20
+ data-viewport={viewport}
21
+ className={cn(
22
+ "group/navigation-menu relative flex max-w-max flex-1 items-center justify-center",
23
+ className
24
+ )}
25
+ {...props}
26
+ >
27
+ {children}
28
+ {viewport && <NavigationMenuViewport />}
29
+ </NavigationMenuPrimitive.Root>
30
+ )
31
+ }
32
+
33
+ function NavigationMenuList({
34
+ className,
35
+ ...props
36
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {
37
+ return (
38
+ <NavigationMenuPrimitive.List
39
+ data-slot="navigation-menu-list"
40
+ className={cn(
41
+ "group flex flex-1 list-none items-center justify-center gap-1",
42
+ className
43
+ )}
44
+ {...props}
45
+ />
46
+ )
47
+ }
48
+
49
+ function NavigationMenuItem({
50
+ className,
51
+ ...props
52
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {
53
+ return (
54
+ <NavigationMenuPrimitive.Item
55
+ data-slot="navigation-menu-item"
56
+ className={cn("relative", className)}
57
+ {...props}
58
+ />
59
+ )
60
+ }
61
+
62
+ const navigationMenuTriggerStyle = cva(
63
+ "group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1"
64
+ )
65
+
66
+ function NavigationMenuTrigger({
67
+ className,
68
+ children,
69
+ ...props
70
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {
71
+ return (
72
+ <NavigationMenuPrimitive.Trigger
73
+ data-slot="navigation-menu-trigger"
74
+ className={cn(navigationMenuTriggerStyle(), "group", className)}
75
+ {...props}
76
+ >
77
+ {children}{" "}
78
+ <ChevronDownIcon
79
+ className="relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180"
80
+ aria-hidden="true"
81
+ />
82
+ </NavigationMenuPrimitive.Trigger>
83
+ )
84
+ }
85
+
86
+ function NavigationMenuContent({
87
+ className,
88
+ ...props
89
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {
90
+ return (
91
+ <NavigationMenuPrimitive.Content
92
+ data-slot="navigation-menu-content"
93
+ className={cn(
94
+ "data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 top-0 left-0 w-full p-2 pr-2.5 md:absolute md:w-auto",
95
+ "group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none",
96
+ className
97
+ )}
98
+ {...props}
99
+ />
100
+ )
101
+ }
102
+
103
+ function NavigationMenuViewport({
104
+ className,
105
+ ...props
106
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {
107
+ return (
108
+ <div
109
+ className={cn(
110
+ "absolute top-full left-0 isolate z-50 flex justify-center"
111
+ )}
112
+ >
113
+ <NavigationMenuPrimitive.Viewport
114
+ data-slot="navigation-menu-viewport"
115
+ className={cn(
116
+ "origin-top-center bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border shadow md:w-[var(--radix-navigation-menu-viewport-width)]",
117
+ className
118
+ )}
119
+ {...props}
120
+ />
121
+ </div>
122
+ )
123
+ }
124
+
125
+ function NavigationMenuLink({
126
+ className,
127
+ ...props
128
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {
129
+ return (
130
+ <NavigationMenuPrimitive.Link
131
+ data-slot="navigation-menu-link"
132
+ className={cn(
133
+ "data-[active=true]:focus:bg-accent data-[active=true]:hover:bg-accent data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:ring-ring/50 [&_svg:not([class*='text-'])]:text-muted-foreground flex flex-col gap-1 rounded-sm p-2 text-sm transition-all outline-none focus-visible:ring-[3px] focus-visible:outline-1 [&_svg:not([class*='size-'])]:size-4",
134
+ className
135
+ )}
136
+ {...props}
137
+ />
138
+ )
139
+ }
140
+
141
+ function NavigationMenuIndicator({
142
+ className,
143
+ ...props
144
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {
145
+ return (
146
+ <NavigationMenuPrimitive.Indicator
147
+ data-slot="navigation-menu-indicator"
148
+ className={cn(
149
+ "data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden",
150
+ className
151
+ )}
152
+ {...props}
153
+ >
154
+ <div className="bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md" />
155
+ </NavigationMenuPrimitive.Indicator>
156
+ )
157
+ }
158
+
159
+ export {
160
+ NavigationMenu,
161
+ NavigationMenuList,
162
+ NavigationMenuItem,
163
+ NavigationMenuContent,
164
+ NavigationMenuTrigger,
165
+ NavigationMenuLink,
166
+ NavigationMenuIndicator,
167
+ NavigationMenuViewport,
168
+ navigationMenuTriggerStyle,
169
+ }
@@ -1,5 +1,12 @@
1
1
  @import "tailwindcss";
2
2
 
3
+ /*
4
+ * Tailwind scans this app's sources for class names, and node_modules is excluded from that
5
+ * scan by default — so the classes that exist ONLY inside @owlmeans/web-panel components
6
+ * (the navigation shell, the footer) would never reach the stylesheet. This line adds them.
7
+ */
8
+ @source "../../../node_modules/@owlmeans/web-panel/build";
9
+
3
10
  /*
4
11
  * shadcn / Tailwind v4 design tokens (new-york, neutral). The app owns these — they
5
12
  * replace what @owlmeans/owl-theme would otherwise provide. The shadcn primitives in
@@ -1,21 +1,14 @@
1
1
  import type { FC, PropsWithChildren } from 'react'
2
- import { HOME, useNavigate } from '@owlmeans/web-panel'
3
- import { MainNavigation } from '@/components/nav/main'
2
+ import { NavLayout } from '@owlmeans/web-panel'
3
+ import { footerLinks, navConfig } from '@/nav'
4
4
 
5
- export const MainLayout: FC<PropsWithChildren> = ({ children }) => {
6
- const nav = useNavigate()
7
-
8
- return (
9
- <div className="min-h-screen bg-background text-foreground">
10
- <header className="border-b">
11
- <div className="mx-auto flex h-16 max-w-4xl items-center justify-between px-4">
12
- <a onClick={nav.press(HOME)} className="cursor-pointer text-lg font-semibold">
13
- __APP_NAME__
14
- </a>
15
- <MainNavigation />
16
- </div>
17
- </header>
18
- <main className="mx-auto max-w-4xl px-4 py-8">{children}</main>
19
- </div>
20
- )
21
- }
5
+ /**
6
+ * The application shell. `NavLayout` renders the header with the section menu, the side menu
7
+ * of the active section (hidden when that section has a single screen), the content, and the
8
+ * footer — the screen arrives as `children`.
9
+ */
10
+ export const MainLayout: FC<PropsWithChildren> = ({ children }) => (
11
+ <NavLayout nav={navConfig} title="__APP_NAME__" footer={footerLinks} contentClassName="mx-auto w-full max-w-4xl">
12
+ {children}
13
+ </NavLayout>
14
+ )
@@ -1,6 +1,7 @@
1
1
  import { BASE, elevate, entrypoint, frontend, handler, HOME, modules as baseModules, route } from '@owlmeans/web-panel'
2
2
  import { session, sessionModules, web } from '__APP_SLUG__-common'
3
3
  import { MainLayout } from './layout/main.js'
4
+ import { AboutScreen } from './screens/about.js'
4
5
  import { HomeScreen } from './screens/home.js'
5
6
  import { SessionScreen } from './screens/session.js'
6
7
 
@@ -16,5 +17,6 @@ elevate(modules, session.remove)
16
17
  modules.push(entrypoint(route(BASE, '/', frontend()), handler(MainLayout)))
17
18
  modules.push(entrypoint(route(HOME, '/', frontend({ default: true, parent: BASE })), handler(HomeScreen)))
18
19
  modules.push(entrypoint(route(web.session, '/session', frontend({ parent: BASE })), handler(SessionScreen)))
20
+ modules.push(entrypoint(route(web.about, '/about', frontend({ parent: BASE })), handler(AboutScreen)))
19
21
 
20
22
  export const appModules = modules
@@ -0,0 +1,28 @@
1
+ import { HOME } from '@owlmeans/web-panel'
2
+ import type { PanelNavConfig, PanelNavLink } from '@owlmeans/web-panel'
3
+ import { web } from '__APP_SLUG__-common'
4
+
5
+ /**
6
+ * The application's navigation, as data.
7
+ *
8
+ * Sections are the top menu; their items are the side menu of whichever section is active.
9
+ * A section holding ONE item renders no side menu at all — `home` below shows that, `demo`
10
+ * shows the two-level case. Labels here are literal; drop them to fall back on the panel
11
+ * i18n keys (`nav.<section>` / `modules.<alias>`) instead.
12
+ */
13
+ export const navConfig: PanelNavConfig = {
14
+ sections: [
15
+ { name: 'home', label: 'Home', items: [{ alias: HOME, label: 'Overview' }] },
16
+ {
17
+ name: 'demo', label: 'Demo', items: [
18
+ { alias: web.session, label: 'Session' },
19
+ { alias: web.about, label: 'About' },
20
+ ]
21
+ },
22
+ ],
23
+ }
24
+
25
+ export const footerLinks: PanelNavLink[] = [
26
+ { alias: HOME, label: '__APP_NAME__' },
27
+ { href: 'https://owlmeans.com', label: 'OwlMeans', open: true },
28
+ ]
@@ -0,0 +1,19 @@
1
+ import type { FC } from 'react'
2
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
3
+
4
+ export const AboutScreen: FC = () => (
5
+ <Card>
6
+ <CardHeader>
7
+ <CardTitle>About __APP_NAME__</CardTitle>
8
+ <CardDescription>
9
+ The second screen of the Demo section — which is why that section shows a side menu
10
+ and the single-screen Home section does not.
11
+ </CardDescription>
12
+ </CardHeader>
13
+ <CardContent>
14
+ <p className="text-sm text-muted-foreground">
15
+ Built with OwlMeans Common. Navigation lives in <code>src/nav.ts</code>.
16
+ </p>
17
+ </CardContent>
18
+ </Card>
19
+ )
@@ -1,15 +0,0 @@
1
- import type { FC } from 'react'
2
- import { HOME, useNavigate } from '@owlmeans/web-panel'
3
- import { web } from '__APP_SLUG__-common'
4
- import { Button } from '@/components/ui/button'
5
-
6
- export const MainNavigation: FC = () => {
7
- const nav = useNavigate()
8
-
9
- return (
10
- <nav className="flex items-center gap-1">
11
- <Button variant="ghost" size="sm" onClick={nav.press(HOME)}>Home</Button>
12
- <Button variant="ghost" size="sm" onClick={nav.press(web.session)}>Session</Button>
13
- </nav>
14
- )
15
- }