Skip to content

Commit ce287c8

Browse files
chore: wip
1 parent 35ab5e9 commit ce287c8

File tree

21 files changed

+2098
-31
lines changed

21 files changed

+2098
-31
lines changed

resources/components/Button.vue

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
<script setup lang="ts">
2+
/**
3+
* Marketing Button Component
4+
*
5+
* A simple button designed for marketing pages with solid/outline variants.
6+
* NOTE: For dashboard/app UIs, use @stacksjs/stx-ui components instead.
7+
*/
8+
import { computed } from 'vue'
9+
210
const props = defineProps<{
311
variant?: 'solid' | 'outline'
4-
color?: 'blue' | 'slate' | 'white'
12+
color?: 'blue' | 'slate' | 'white' | 'black'
513
href?: string
614
className?: string
715
}>()
816
917
const baseStyles = {
1018
solid:
11-
'group inline-flex items-center justify-center rounded-full py-2 px-4 text-sm font-semibold focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2',
12-
outline: 'group inline-flex ring-1 items-center justify-center rounded-full py-2 px-4 text-sm focus:outline-none',
19+
'group inline-flex items-center justify-center rounded-full py-2 px-4 text-sm font-semibold focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 transition-colors',
20+
outline:
21+
'group inline-flex ring-1 items-center justify-center rounded-full py-2 px-4 text-sm focus:outline-none transition-colors',
1322
}
1423
1524
const variantStyles = {
@@ -24,37 +33,36 @@ const variantStyles = {
2433
outline: {
2534
slate:
2635
'ring-slate-200 text-slate-700 hover:text-slate-900 hover:ring-slate-300 active:bg-slate-100 active:text-slate-600 focus-visible:outline-blue-600 focus-visible:ring-slate-300',
36+
blue: 'ring-blue-200 text-blue-700 hover:text-blue-900 hover:ring-blue-300 active:bg-blue-100 active:text-blue-600 focus-visible:outline-blue-600',
2737
white:
2838
'ring-slate-700 text-white hover:ring-slate-500 active:ring-slate-700 active:text-slate-400 focus-visible:outline-white',
39+
black: 'ring-black text-black hover:ring-gray-700 active:bg-gray-100 focus-visible:outline-black',
2940
},
3041
}
3142
3243
const className = computed(() => {
33-
let classes = baseStyles[props.variant ?? 'solid']
44+
const variant = props.variant ?? 'solid'
45+
const color = props.color ?? 'slate'
46+
let classes = baseStyles[variant]
3447
35-
if (props.variant === 'outline')
36-
classes += ` ${variantStyles.outline[props.color ?? 'slate']}`
37-
else if (props.variant === 'solid')
38-
classes += ` ${variantStyles.solid[props.color ?? 'slate']}`
48+
const colorStyles = variantStyles[variant]?.[color]
49+
if (colorStyles) {
50+
classes += ` ${colorStyles}`
51+
}
3952
40-
if (props.className)
53+
if (props.className) {
4154
classes += ` ${props.className}`
55+
}
4256
4357
return classes
4458
})
45-
46-
// easily use any of the lifecycle hooks without needing to import them
47-
onMounted(() => {
48-
// eslint-disable-next-line no-console
49-
console.log('Button component mounted')
50-
})
5159
</script>
5260

5361
<template>
5462
<button v-if="!props.href" :class="className">
5563
<slot />
5664
</button>
57-
<a v-else :class="className">
65+
<a v-else :href="href" :class="className">
5866
<slot />
5967
</a>
6068
</template>

storage/framework/core/router/src/router.ts

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -444,15 +444,16 @@ export class StacksRouter implements RouterInterface {
444444

445445
/**
446446
* Create a route group with shared attributes
447+
* Supports both sync and async callbacks
447448
*/
448-
group(options: string | RouteGroupOptions, callback?: () => void): this {
449+
group(options: string | RouteGroupOptions, callback?: (() => void) | (() => Promise<void>)): this {
449450
// Handle string prefix shorthand
450451
if (typeof options === 'string') {
451452
options = { prefix: options.startsWith('/') ? options.slice(1) : options }
452453
}
453454

454455
// Handle function-only call
455-
let cb: () => void
456+
let cb: (() => void) | (() => Promise<void>)
456457
if (typeof options === 'function') {
457458
cb = options
458459
options = {}
@@ -479,18 +480,33 @@ export class StacksRouter implements RouterInterface {
479480
// Create temporary routes array to track routes in this group
480481
this._stacksRoutes = []
481482

482-
// Execute callback
483-
cb()
483+
// Execute callback (handle both sync and async)
484+
const result = cb()
484485

485-
// Merge group routes back to main routes
486-
for (const route of this._stacksRoutes) {
487-
previousRoutes.push(route)
486+
// If callback returns a promise, track it for later awaiting
487+
if (result instanceof Promise) {
488+
const groupPromise = result.then(() => {
489+
// Merge group routes back to main routes after async completion
490+
for (const route of this._stacksRoutes) {
491+
previousRoutes.push(route)
492+
}
493+
// Restore previous state
494+
this._groupPrefix = previousPrefix
495+
this._groupMiddleware = previousMiddleware
496+
this._stacksRoutes = previousRoutes
497+
})
498+
this._pendingRoutes.push(groupPromise)
499+
}
500+
else {
501+
// Sync callback - merge immediately
502+
for (const route of this._stacksRoutes) {
503+
previousRoutes.push(route)
504+
}
505+
// Restore previous state
506+
this._groupPrefix = previousPrefix
507+
this._groupMiddleware = previousMiddleware
508+
this._stacksRoutes = previousRoutes
488509
}
489-
490-
// Restore previous state
491-
this._groupPrefix = previousPrefix
492-
this._groupMiddleware = previousMiddleware
493-
this._stacksRoutes = previousRoutes
494510

495511
return this
496512
}
@@ -511,10 +527,13 @@ export class StacksRouter implements RouterInterface {
511527

512528
/**
513529
* Set middleware for the last registered route
530+
* Accepts a string name, array of strings, or middleware handlers
514531
*/
515-
middleware(middleware: StacksRoute['middleware']): this {
532+
middleware(middleware: string | string[] | StacksRoute['middleware']): this {
516533
if (this._stacksRoutes.length > 0) {
517-
this._stacksRoutes[this._stacksRoutes.length - 1].middleware = middleware
534+
// Normalize to array if single string
535+
const normalizedMiddleware = typeof middleware === 'string' ? [middleware] : middleware
536+
this._stacksRoutes[this._stacksRoutes.length - 1].middleware = normalizedMiddleware
518537
}
519538
return this
520539
}
@@ -763,6 +782,10 @@ export class StacksRouter implements RouterInterface {
763782
prepareUri(path: string): string {
764783
if (path.startsWith('/')) path = path.slice(1)
765784
path = `/${path}`
785+
786+
// Normalize :param syntax to {param} syntax for bun-router compatibility
787+
path = path.replace(/:(\w+)/g, '{$1}')
788+
766789
return path.endsWith('/') ? path.slice(0, -1) : path
767790
}
768791

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Build script for @stacksjs/stx-ui
3+
*/
4+
import { $ } from 'bun'
5+
6+
async function build() {
7+
console.log('Building @stacksjs/stx-ui...')
8+
9+
// Clean dist
10+
await $`rm -rf dist`
11+
12+
// Build web components
13+
await Bun.build({
14+
entrypoints: ['./src/web-components/index.ts'],
15+
outdir: './dist/web-components',
16+
target: 'browser',
17+
format: 'esm',
18+
minify: false,
19+
})
20+
21+
// Build composables
22+
await Bun.build({
23+
entrypoints: ['./src/composables/index.ts'],
24+
outdir: './dist/composables',
25+
target: 'browser',
26+
format: 'esm',
27+
minify: false,
28+
external: ['vue'],
29+
})
30+
31+
// Build main index
32+
await Bun.build({
33+
entrypoints: ['./src/index.ts'],
34+
outdir: './dist',
35+
target: 'browser',
36+
format: 'esm',
37+
minify: false,
38+
external: ['vue'],
39+
})
40+
41+
// Generate type declarations
42+
await $`bunx tsc --emitDeclarationOnly --declaration --outDir dist`
43+
44+
console.log('Build complete!')
45+
}
46+
47+
build().catch(console.error)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"name": "@stacksjs/stx-ui",
3+
"type": "module",
4+
"version": "0.1.0",
5+
"description": "Framework-agnostic UI primitives for Stacks - web components with Vue wrappers",
6+
"author": "Chris Breuer",
7+
"license": "MIT",
8+
"exports": {
9+
".": {
10+
"types": "./dist/index.d.ts",
11+
"import": "./dist/index.js"
12+
},
13+
"./web-components": {
14+
"types": "./dist/web-components/index.d.ts",
15+
"import": "./dist/web-components/index.js"
16+
},
17+
"./vue": {
18+
"types": "./dist/vue/index.d.ts",
19+
"import": "./dist/vue/index.js"
20+
},
21+
"./composables": {
22+
"types": "./dist/composables/index.d.ts",
23+
"import": "./dist/composables/index.js"
24+
},
25+
"./styles": "./dist/styles/index.css"
26+
},
27+
"main": "dist/index.js",
28+
"types": "dist/index.d.ts",
29+
"files": ["dist", "README.md"],
30+
"scripts": {
31+
"build": "bun build.ts",
32+
"typecheck": "bun tsc --noEmit"
33+
},
34+
"dependencies": {},
35+
"devDependencies": {
36+
"vue": "^3.4.0"
37+
},
38+
"peerDependencies": {
39+
"vue": "^3.4.0"
40+
},
41+
"peerDependenciesMeta": {
42+
"vue": {
43+
"optional": true
44+
}
45+
}
46+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* STX-UI Composables
3+
* Reusable Vue composition functions.
4+
*/
5+
6+
export {
7+
useDarkMode,
8+
type ColorMode,
9+
type UseDarkModeOptions,
10+
type UseDarkModeReturn,
11+
} from './useDarkMode'
12+
13+
export {
14+
useMediaQuery,
15+
useIsMobile,
16+
useIsTablet,
17+
useIsDesktop,
18+
usePrefersReducedMotion,
19+
usePrefersDark,
20+
type UseMediaQueryReturn,
21+
} from './useMediaQuery'
22+
23+
export {
24+
useModal,
25+
type UseModalOptions,
26+
type UseModalReturn,
27+
} from './useModal'
28+
29+
export {
30+
useClipboard,
31+
type UseClipboardOptions,
32+
type UseClipboardReturn,
33+
} from './useClipboard'
34+
35+
export {
36+
useLocalStorage,
37+
useLocalStorageString,
38+
useLocalStorageBoolean,
39+
useLocalStorageNumber,
40+
type UseLocalStorageOptions,
41+
type UseLocalStorageReturn,
42+
} from './useLocalStorage'

0 commit comments

Comments
 (0)