@apex-stack/core 0.4.0 → 0.4.1
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/components/Carousel.alpine +59 -0
- package/components/ChatBubble.alpine +17 -0
- package/components/Combobox.alpine +85 -0
- package/components/Counter.alpine +19 -0
- package/components/FileInput.alpine +7 -0
- package/components/Navbar.alpine +32 -0
- package/components/Pagination.alpine +27 -0
- package/components/Range.alpine +7 -0
- package/components/Rating.alpine +40 -0
- package/components/Sidebar.alpine +82 -0
- package/components/Steps.alpine +35 -0
- package/components/Table.alpine +35 -0
- package/components/Toast.alpine +71 -0
- package/components/registry.json +70 -1
- package/package.json +3 -3
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<!-- Apex component adapted from Penguin UI (MIT). -->
|
|
2
|
+
<template x-data="{
|
|
3
|
+
slides: [
|
|
4
|
+
{ label: 'Slide 1' },
|
|
5
|
+
{ label: 'Slide 2' },
|
|
6
|
+
{ label: 'Slide 3' },
|
|
7
|
+
],
|
|
8
|
+
currentSlideIndex: 1,
|
|
9
|
+
previous() {
|
|
10
|
+
if (this.currentSlideIndex > 1) {
|
|
11
|
+
this.currentSlideIndex = this.currentSlideIndex - 1
|
|
12
|
+
} else {
|
|
13
|
+
// If it's the first slide, go to the last slide
|
|
14
|
+
this.currentSlideIndex = this.slides.length
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
next() {
|
|
18
|
+
if (this.currentSlideIndex < this.slides.length) {
|
|
19
|
+
this.currentSlideIndex = this.currentSlideIndex + 1
|
|
20
|
+
} else {
|
|
21
|
+
// If it's the last slide, go to the first slide
|
|
22
|
+
this.currentSlideIndex = 1
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
}">
|
|
26
|
+
<div class="relative w-full overflow-hidden">
|
|
27
|
+
|
|
28
|
+
<!-- previous button -->
|
|
29
|
+
<button type="button" class="absolute left-5 top-1/2 z-20 flex rounded-full -translate-y-1/2 items-center justify-center bg-surface/40 p-2 text-on-surface transition hover:bg-surface/60 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary active:outline-offset-0 dark:bg-surface-dark/40 dark:text-on-surface-dark dark:hover:bg-surface-dark/60 dark:focus-visible:outline-primary-dark" aria-label="previous slide" x-on:click="previous()">
|
|
30
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="3" class="size-5 md:size-6 pr-0.5" aria-hidden="true">
|
|
31
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5" />
|
|
32
|
+
</svg>
|
|
33
|
+
</button>
|
|
34
|
+
|
|
35
|
+
<!-- next button -->
|
|
36
|
+
<button type="button" class="absolute right-5 top-1/2 z-20 flex rounded-full -translate-y-1/2 items-center justify-center bg-surface/40 p-2 text-on-surface transition hover:bg-surface/60 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary active:outline-offset-0 dark:bg-surface-dark/40 dark:text-on-surface-dark dark:hover:bg-surface-dark/60 dark:focus-visible:outline-primary-dark" aria-label="next slide" x-on:click="next()">
|
|
37
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="3" class="size-5 md:size-6 pl-0.5" aria-hidden="true">
|
|
38
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
|
|
39
|
+
</svg>
|
|
40
|
+
</button>
|
|
41
|
+
|
|
42
|
+
<!-- slides -->
|
|
43
|
+
<!-- Change min-h-[50svh] to your preferred height size -->
|
|
44
|
+
<div class="relative min-h-[50svh] w-full">
|
|
45
|
+
<template x-for="(slide, index) in slides">
|
|
46
|
+
<div x-show="currentSlideIndex == index + 1" class="absolute inset-0" x-transition.opacity.duration.1000ms>
|
|
47
|
+
<div class="absolute inset-0 flex h-full w-full items-center justify-center bg-surface-alt text-on-surface dark:bg-surface-dark-alt dark:text-on-surface-dark" x-text="slide.label"></div>
|
|
48
|
+
</div>
|
|
49
|
+
</template>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<!-- indicators -->
|
|
53
|
+
<div class="absolute rounded-radius bottom-3 md:bottom-5 left-1/2 z-20 flex -translate-x-1/2 gap-4 md:gap-3 bg-surface/75 px-1.5 py-1 md:px-2 dark:bg-surface-dark/75" role="group" aria-label="slides">
|
|
54
|
+
<template x-for="(slide, index) in slides">
|
|
55
|
+
<button class="size-2 rounded-full transition bg-on-surface dark:bg-on-surface-dark" x-on:click="currentSlideIndex = index + 1" x-bind:class="[currentSlideIndex === index + 1 ? 'bg-on-surface dark:bg-on-surface-dark' : 'bg-on-surface/50 dark:bg-on-surface-dark/50']" x-bind:aria-label="'slide ' + (index + 1)"></button>
|
|
56
|
+
</template>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</template>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<!-- Apex component adapted from Penguin UI (MIT). -->
|
|
2
|
+
<template>
|
|
3
|
+
<div class="flex w-full flex-col gap-4">
|
|
4
|
+
<!-- Received -->
|
|
5
|
+
<div class="mr-auto flex max-w-[80%] flex-col gap-2 rounded-r-radius rounded-tl-radius bg-surface-alt p-4 md:max-w-[60%] dark:bg-surface-dark-alt">
|
|
6
|
+
<span class="font-semibold text-on-surface-strong dark:text-on-surface-dark-strong">Penguin UI</span>
|
|
7
|
+
<div class="text-sm text-on-surface dark:text-on-surface-dark">
|
|
8
|
+
<slot></slot>
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<!-- Sent -->
|
|
13
|
+
<div class="ml-auto flex max-w-[80%] flex-col gap-2 rounded-l-radius rounded-tr-radius bg-primary p-4 text-sm text-on-primary md:max-w-[60%] dark:bg-primary-dark dark:text-on-primary-dark">
|
|
14
|
+
<slot></slot>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<!-- Apex component adapted from Penguin UI (MIT). -->
|
|
2
|
+
<template x-data="{
|
|
3
|
+
allOptions: [
|
|
4
|
+
{ label: 'Acura', value: 'Acura' },
|
|
5
|
+
{ label: 'Audi', value: 'Audi' },
|
|
6
|
+
{ label: 'BMW', value: 'BMW' },
|
|
7
|
+
{ label: 'Ford', value: 'Ford' },
|
|
8
|
+
{ label: 'Honda', value: 'Honda' },
|
|
9
|
+
{ label: 'Tesla', value: 'Tesla' },
|
|
10
|
+
{ label: 'Toyota', value: 'Toyota' },
|
|
11
|
+
],
|
|
12
|
+
options: [],
|
|
13
|
+
isOpen: false,
|
|
14
|
+
openedWithKeyboard: false,
|
|
15
|
+
selectedOption: null,
|
|
16
|
+
setSelectedOption(option) {
|
|
17
|
+
this.selectedOption = option
|
|
18
|
+
this.isOpen = false
|
|
19
|
+
this.openedWithKeyboard = false
|
|
20
|
+
this.$refs.hiddenTextField.value = option.value
|
|
21
|
+
},
|
|
22
|
+
getFilteredOptions(query) {
|
|
23
|
+
this.options = this.allOptions.filter((option) =>
|
|
24
|
+
option.label.toLowerCase().includes(query.toLowerCase()),
|
|
25
|
+
)
|
|
26
|
+
if (this.options.length === 0) {
|
|
27
|
+
this.$refs.noResultsMessage.classList.remove('hidden')
|
|
28
|
+
} else {
|
|
29
|
+
this.$refs.noResultsMessage.classList.add('hidden')
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
handleKeydownOnOptions(event) {
|
|
33
|
+
// if the user presses backspace or the alpha-numeric keys, focus on the search field
|
|
34
|
+
if ((event.keyCode >= 65 && event.keyCode <= 90) || (event.keyCode >= 48 && event.keyCode <= 57) || event.keyCode === 8) {
|
|
35
|
+
this.$refs.searchField.focus()
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
}">
|
|
39
|
+
<div class="flex w-full max-w-xs flex-col gap-1" x-on:keydown="handleKeydownOnOptions($event)" x-on:keydown.esc.window="isOpen = false, openedWithKeyboard = false" x-init="options = allOptions">
|
|
40
|
+
<label for="make" class="w-fit pl-0.5 text-sm text-on-surface dark:text-on-surface-dark">Make</label>
|
|
41
|
+
<div class="relative">
|
|
42
|
+
|
|
43
|
+
<!-- trigger button -->
|
|
44
|
+
<button type="button" class="inline-flex w-full items-center justify-between gap-2 border border-outline rounded-radius bg-surface-alt px-4 py-2 text-sm font-medium tracking-wide text-on-surface transition hover:opacity-75 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:border-outline-dark dark:bg-surface-dark-alt/50 dark:text-on-surface-dark dark:focus-visible:outline-primary-dark" role="combobox" aria-controls="makesList" aria-haspopup="listbox" x-on:click="isOpen = ! isOpen" x-on:keydown.down.prevent="openedWithKeyboard = true" x-on:keydown.enter.prevent="openedWithKeyboard = true" x-on:keydown.space.prevent="openedWithKeyboard = true" x-bind:aria-expanded="isOpen || openedWithKeyboard" x-bind:aria-label="selectedOption ? selectedOption.value : 'Please Select'" >
|
|
45
|
+
<span class="text-sm font-normal" x-text="selectedOption ? selectedOption.value : 'Please Select'"></span>
|
|
46
|
+
<!-- Chevron -->
|
|
47
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5" aria-hidden="true">
|
|
48
|
+
<path fill-rule="evenodd" d="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd"/>
|
|
49
|
+
</svg>
|
|
50
|
+
</button>
|
|
51
|
+
|
|
52
|
+
<!-- Hidden Input To Grab The Selected Value -->
|
|
53
|
+
<input id="make" name="make" x-ref="hiddenTextField" hidden=""/>
|
|
54
|
+
<div x-show="isOpen || openedWithKeyboard" id="makesList" class="absolute left-0 top-11 z-10 w-full overflow-hidden rounded-radius border border-outline bg-surface-alt dark:border-outline-dark dark:bg-surface-dark-alt" role="listbox" aria-label="industries list" x-on:click.outside="isOpen = false, openedWithKeyboard = false" x-on:keydown.down.prevent="$focus.wrap().next()" x-on:keydown.up.prevent="$focus.wrap().previous()" x-transition x-trap="openedWithKeyboard">
|
|
55
|
+
|
|
56
|
+
<!-- Search -->
|
|
57
|
+
<div class="relative">
|
|
58
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="1.5" class="absolute left-4 top-1/2 size-5 -translate-y-1/2 text-on-surface/50 dark:text-on-surface-dark/50" aria-hidden="true" >
|
|
59
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"/>
|
|
60
|
+
</svg>
|
|
61
|
+
<input type="text" class="w-full border-b border-outline bg-surface-alt py-2.5 pl-11 pr-4 text-sm text-on-surface focus:outline-hidden focus-visible:border-primary disabled:cursor-not-allowed disabled:opacity-75 dark:border-outline-dark dark:bg-surface-dark-alt dark:text-on-surface-dark dark:focus-visible:border-primary-dark" name="searchField" aria-label="Search" x-on:input="getFilteredOptions($el.value)" x-ref="searchField" placeholder="Search" />
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<!-- Options -->
|
|
65
|
+
<ul class="flex max-h-44 flex-col overflow-y-auto">
|
|
66
|
+
<li class="hidden px-4 py-2 text-sm text-on-surface dark:text-on-surface-dark" x-ref="noResultsMessage">
|
|
67
|
+
<span>No matches found</span>
|
|
68
|
+
</li>
|
|
69
|
+
<template x-for="(item, index) in options" x-bind:key="item.value">
|
|
70
|
+
<li class="combobox-option inline-flex justify-between gap-6 bg-surface-alt px-4 py-2 text-sm text-on-surface hover:bg-surface-dark-alt/5 hover:text-on-surface-strong focus-visible:bg-surface-dark-alt/5 focus-visible:text-on-surface-strong focus-visible:outline-hidden dark:bg-surface-dark-alt dark:text-on-surface-dark dark:hover:bg-surface-alt/5 dark:hover:text-on-surface-dark-strong dark:focus-visible:bg-surface-alt/10 dark:focus-visible:text-on-surface-dark-strong" role="option" x-on:click="setSelectedOption(item)" x-on:keydown.enter="setSelectedOption(item)" x-bind:id="'option-' + index" tabindex="0">
|
|
71
|
+
<!-- Label -->
|
|
72
|
+
<span x-bind:class="selectedOption == item ? 'font-bold' : null" x-text="item.label"></span>
|
|
73
|
+
<!-- Screen reader 'selected' indicator -->
|
|
74
|
+
<span class="sr-only" x-text="selectedOption == item ? 'selected' : null"></span>
|
|
75
|
+
<!-- Checkmark -->
|
|
76
|
+
<svg x-cloak x-show="selectedOption == item" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="2" class="size-4" aria-hidden="true">
|
|
77
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"/>
|
|
78
|
+
</svg>
|
|
79
|
+
</li>
|
|
80
|
+
</template>
|
|
81
|
+
</ul>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</template>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- Apex component adapted from Penguin UI (MIT). -->
|
|
2
|
+
<template x-data="{ currentVal: 1, minVal: 0, maxVal: 10, decimalPoints: 0, incrementAmount: 1 }">
|
|
3
|
+
<div class="flex flex-col gap-1">
|
|
4
|
+
<label for="counterInput" class="pl-1 text-sm text-on-surface dark:text-on-surface-dark">Items(s)</label>
|
|
5
|
+
<div x-on:dblclick.prevent class="flex items-center">
|
|
6
|
+
<button x-on:click="currentVal = Math.max(minVal, currentVal - incrementAmount)" class="flex h-10 items-center justify-center rounded-l-radius border border-outline bg-surface-alt px-4 py-2 text-on-surface hover:opacity-75 focus-visible:z-10 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary active:opacity-100 active:outline-offset-0 dark:border-outline-dark dark:bg-surface-dark-alt dark:text-on-surface-dark dark:focus-visible:outline-primary-dark" aria-label="subtract">
|
|
7
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="2" class="size-4">
|
|
8
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 12h-15"/>
|
|
9
|
+
</svg>
|
|
10
|
+
</button>
|
|
11
|
+
<input x-model="currentVal.toFixed(decimalPoints)" id="counterInput" type="text" class="border-x-none h-10 w-20 rounded-none border-y border-outline bg-surface-alt/50 text-center text-on-surface-strong focus-visible:z-10 focus-visible:outline-2 focus-visible:outline-primary dark:border-outline-dark dark:bg-surface-dark-alt/50 dark:text-on-surface-dark-strong dark:focus-visible:outline-primary-dark" readonly />
|
|
12
|
+
<button x-on:click="currentVal = Math.min(maxVal, currentVal + incrementAmount)" class="flex h-10 items-center justify-center rounded-r-radius border border-outline bg-surface-alt px-4 py-2 text-on-surface hover:opacity-75 focus-visible:z-10 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary active:opacity-100 active:outline-offset-0 dark:border-outline-dark dark:bg-surface-dark-alt dark:text-on-surface-dark dark:focus-visible:outline-primary-dark" aria-label="add">
|
|
13
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="2" class="size-4">
|
|
14
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15"/>
|
|
15
|
+
</svg>
|
|
16
|
+
</button>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<!-- Apex component adapted from Penguin UI (MIT). -->
|
|
2
|
+
<template>
|
|
3
|
+
<div class="relative flex w-full max-w-sm flex-col gap-1">
|
|
4
|
+
<label class="w-fit pl-0.5 text-sm text-on-surface dark:text-on-surface-dark" for="fileInput"><slot>Upload File</slot></label>
|
|
5
|
+
<input id="fileInput" type="file" class="w-full overflow-clip rounded-radius border border-outline bg-surface-alt/50 text-sm text-on-surface file:mr-4 file:border-none file:bg-surface-alt file:px-4 file:py-2 file:font-medium file:text-on-surface-strong focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary disabled:cursor-not-allowed disabled:opacity-75 dark:border-outline-dark dark:bg-surface-dark-alt/50 dark:text-on-surface-dark dark:file:bg-surface-dark-alt dark:file:text-on-surface-dark-strong dark:focus-visible:outline-primary-dark" />
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<!-- Apex component adapted from Penguin UI (MIT). -->
|
|
2
|
+
<template x-data="{ mobileMenuIsOpen: false }">
|
|
3
|
+
<nav x-on:click.away="mobileMenuIsOpen = false" class="flex items-center justify-between border-b border-outline px-6 py-4 dark:border-outline-dark" aria-label="apex ui menu">
|
|
4
|
+
<!-- Brand wordmark -->
|
|
5
|
+
<a href="#" class="text-2xl font-bold text-on-surface-strong dark:text-on-surface-dark-strong">
|
|
6
|
+
<span>Ap<span class="text-primary dark:text-primary-dark">e</span>x</span>
|
|
7
|
+
</a>
|
|
8
|
+
<!-- Desktop Menu -->
|
|
9
|
+
<ul class="hidden items-center gap-4 md:flex">
|
|
10
|
+
<li><a href="#" class="font-bold text-primary underline-offset-2 hover:text-primary focus:outline-hidden focus:underline dark:text-primary-dark dark:hover:text-primary-dark" aria-current="page">Products</a></li>
|
|
11
|
+
<li><a href="#" class="font-medium text-on-surface underline-offset-2 hover:text-primary focus:outline-hidden focus:underline dark:text-on-surface-dark dark:hover:text-primary-dark">Pricing</a></li>
|
|
12
|
+
<li><a href="#" class="font-medium text-on-surface underline-offset-2 hover:text-primary focus:outline-hidden focus:underline dark:text-on-surface-dark dark:hover:text-primary-dark">Blog</a></li>
|
|
13
|
+
<li><a href="#" class="font-medium text-on-surface underline-offset-2 hover:text-primary focus:outline-hidden focus:underline dark:text-on-surface-dark dark:hover:text-primary-dark">Login</a></li>
|
|
14
|
+
</ul>
|
|
15
|
+
<!-- Mobile Menu Button -->
|
|
16
|
+
<button x-on:click="mobileMenuIsOpen = !mobileMenuIsOpen" x-bind:aria-expanded="mobileMenuIsOpen" x-bind:class="mobileMenuIsOpen ? 'fixed top-6 right-6 z-20' : null" type="button" class="flex text-on-surface dark:text-on-surface-dark md:hidden" aria-label="mobile menu" aria-controls="mobileMenu">
|
|
17
|
+
<svg x-cloak x-show="!mobileMenuIsOpen" xmlns="http://www.w3.org/2000/svg" fill="none" aria-hidden="true" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="size-6">
|
|
18
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
|
19
|
+
</svg>
|
|
20
|
+
<svg x-cloak x-show="mobileMenuIsOpen" xmlns="http://www.w3.org/2000/svg" fill="none" aria-hidden="true" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="size-6">
|
|
21
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
|
|
22
|
+
</svg>
|
|
23
|
+
</button>
|
|
24
|
+
<!-- Mobile Menu -->
|
|
25
|
+
<ul x-cloak x-show="mobileMenuIsOpen" x-transition:enter="transition motion-reduce:transition-none ease-out duration-300" x-transition:enter-start="-translate-y-full" x-transition:enter-end="translate-y-0" x-transition:leave="transition motion-reduce:transition-none ease-out duration-300" x-transition:leave-start="translate-y-0" x-transition:leave-end="-translate-y-full" id="mobileMenu" class="fixed max-h-svh overflow-y-auto inset-x-0 top-0 z-10 flex flex-col divide-y divide-outline rounded-b-radius border-b border-outline bg-surface-alt px-6 pb-6 pt-20 dark:divide-outline-dark dark:border-outline-dark dark:bg-surface-dark-alt md:hidden">
|
|
26
|
+
<li class="py-4"><a href="#" class="w-full text-lg font-bold text-primary focus:underline dark:text-primary-dark" aria-current="page">Products</a></li>
|
|
27
|
+
<li class="py-4"><a href="#" class="w-full text-lg font-medium text-on-surface focus:underline dark:text-on-surface-dark">Pricing</a></li>
|
|
28
|
+
<li class="py-4"><a href="#" class="w-full text-lg font-medium text-on-surface focus:underline dark:text-on-surface-dark">Blog</a></li>
|
|
29
|
+
<li class="py-4"><a href="#" class="w-full text-lg font-medium text-on-surface focus:underline dark:text-on-surface-dark">Login</a></li>
|
|
30
|
+
</ul>
|
|
31
|
+
</nav>
|
|
32
|
+
</template>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<!-- Apex component adapted from Penguin UI (MIT). -->
|
|
2
|
+
<template>
|
|
3
|
+
<nav aria-label="pagination">
|
|
4
|
+
<ul class="flex shrink-0 items-center gap-2 text-sm font-medium">
|
|
5
|
+
<li>
|
|
6
|
+
<a href="#" class="flex items-center rounded-radius p-1 text-on-surface hover:text-primary dark:text-on-surface-dark dark:hover:text-primary-dark" aria-label="previous page">
|
|
7
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="size-6">
|
|
8
|
+
<path fill-rule="evenodd" d="M11.78 5.22a.75.75 0 0 1 0 1.06L8.06 10l3.72 3.72a.75.75 0 1 1-1.06 1.06l-4.25-4.25a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0Z" clip-rule="evenodd" />
|
|
9
|
+
</svg>
|
|
10
|
+
Previous
|
|
11
|
+
</a>
|
|
12
|
+
</li>
|
|
13
|
+
<li><a href="#" class="flex size-6 items-center justify-center rounded-radius p-1 text-on-surface hover:text-primary dark:text-on-surface-dark dark:hover:text-primary-dark" aria-label="page 1">1</a></li>
|
|
14
|
+
<li><a href="#" class="flex size-6 items-center justify-center rounded-radius bg-primary p-1 font-bold text-on-primary dark:bg-primary-dark dark:text-on-primary-dark" aria-current="page" aria-label="page 2">2</a></li>
|
|
15
|
+
<li><a href="#" class="flex size-6 items-center justify-center rounded-radius p-1 text-on-surface hover:text-primary dark:text-on-surface-dark dark:hover:text-primary-dark" aria-label="page 3">3</a></li>
|
|
16
|
+
<li><a href="#" class="flex size-6 items-center justify-center rounded-radius p-1 text-on-surface hover:text-primary dark:text-on-surface-dark dark:hover:text-primary-dark" aria-label="page 4">4</a></li>
|
|
17
|
+
<li>
|
|
18
|
+
<a href="#" class="flex items-center rounded-radius p-1 text-on-surface hover:text-primary dark:text-on-surface-dark dark:hover:text-primary-dark" aria-label="next page">
|
|
19
|
+
Next
|
|
20
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="size-6">
|
|
21
|
+
<path fill-rule="evenodd" d="M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
|
|
22
|
+
</svg>
|
|
23
|
+
</a>
|
|
24
|
+
</li>
|
|
25
|
+
</ul>
|
|
26
|
+
</nav>
|
|
27
|
+
</template>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<!-- Apex component adapted from Penguin UI (MIT). -->
|
|
2
|
+
<template>
|
|
3
|
+
<div class="flex w-full flex-col gap-4 text-on-surface dark:text-on-surface-dark">
|
|
4
|
+
<label for="rangeSlider" class="w-fit pl-0.5 text-sm">Mood Meter</label>
|
|
5
|
+
<input id="rangeSlider" type="range" class="h-2 w-full appearance-none bg-on-surface/15 focus:outline-primary dark:bg-on-surface-dark/15 dark:focus:outline-primary-dark [&::-moz-range-thumb]:size-4 [&::-moz-range-thumb]:appearance-none [&::-moz-range-thumb]:border-none [&::-moz-range-thumb]:bg-primary dark:[&::-moz-range-thumb]:bg-primary-dark active:[&::-moz-range-thumb]:scale-110 [&::-webkit-slider-thumb]:size-4 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:border-none [&::-webkit-slider-thumb]:bg-primary active:[&::-webkit-slider-thumb]:scale-110 dark:[&::-webkit-slider-thumb]:bg-primary-dark [&::-moz-range-thumb]:rounded-full [&::-webkit-slider-thumb]:rounded-full rounded-full" value="20" min="0" max="100" step="1" />
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<!-- Apex component adapted from Penguin UI (MIT). -->
|
|
2
|
+
<template x-data="{ currentVal: 3 }">
|
|
3
|
+
<div class="flex items-center gap-1">
|
|
4
|
+
<label for="oneStar" class="transition hover:scale-125 has-focus:scale-125">
|
|
5
|
+
<span class="sr-only">one star</span>
|
|
6
|
+
<input x-model="currentVal" id="oneStar" type="radio" class="sr-only" name="rating" value="1">
|
|
7
|
+
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" viewBox="0 0 24 24" fill="currentColor" class="size-5" x-bind:class="currentVal > 0 ? 'text-amber-500' : 'text-on-surface dark:text-on-surface-dark'">
|
|
8
|
+
<path fill-rule="evenodd" d="M10.788 3.21c.448-1.077 1.976-1.077 2.424 0l2.082 5.006 5.404.434c1.164.093 1.636 1.545.749 2.305l-4.117 3.527 1.257 5.273c.271 1.136-.964 2.033-1.96 1.425L12 18.354 7.373 21.18c-.996.608-2.231-.29-1.96-1.425l1.257-5.273-4.117-3.527c-.887-.76-.415-2.212.749-2.305l5.404-.434 2.082-5.005Z" clip-rule="evenodd">
|
|
9
|
+
</svg>
|
|
10
|
+
</label>
|
|
11
|
+
<label for="twoStars" class="transition hover:scale-125 has-focus:scale-125">
|
|
12
|
+
<span class="sr-only">two stars</span>
|
|
13
|
+
<input x-model="currentVal" id="twoStars" type="radio" class="sr-only" name="rating" value="2">
|
|
14
|
+
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" viewBox="0 0 24 24" fill="currentColor" class="size-5" x-bind:class="currentVal > 1 ? 'text-amber-500' : 'text-on-surface dark:text-on-surface-dark'">
|
|
15
|
+
<path fill-rule="evenodd" d="M10.788 3.21c.448-1.077 1.976-1.077 2.424 0l2.082 5.006 5.404.434c1.164.093 1.636 1.545.749 2.305l-4.117 3.527 1.257 5.273c.271 1.136-.964 2.033-1.96 1.425L12 18.354 7.373 21.18c-.996.608-2.231-.29-1.96-1.425l1.257-5.273-4.117-3.527c-.887-.76-.415-2.212.749-2.305l5.404-.434 2.082-5.005Z" clip-rule="evenodd">
|
|
16
|
+
</svg>
|
|
17
|
+
</label>
|
|
18
|
+
<label for="threeStars" class="transition hover:scale-125 has-focus:scale-125">
|
|
19
|
+
<span class="sr-only">three stars</span>
|
|
20
|
+
<input x-model="currentVal" id="threeStars" type="radio" class="sr-only" name="rating" value="3">
|
|
21
|
+
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" viewBox="0 0 24 24" fill="currentColor" class="size-5" x-bind:class="currentVal > 2 ? 'text-amber-500' : 'text-on-surface dark:text-on-surface-dark'">
|
|
22
|
+
<path fill-rule="evenodd" d="M10.788 3.21c.448-1.077 1.976-1.077 2.424 0l2.082 5.006 5.404.434c1.164.093 1.636 1.545.749 2.305l-4.117 3.527 1.257 5.273c.271 1.136-.964 2.033-1.96 1.425L12 18.354 7.373 21.18c-.996.608-2.231-.29-1.96-1.425l1.257-5.273-4.117-3.527c-.887-.76-.415-2.212.749-2.305l5.404-.434 2.082-5.005Z" clip-rule="evenodd">
|
|
23
|
+
</svg>
|
|
24
|
+
</label>
|
|
25
|
+
<label for="fourStars" class="transition hover:scale-125 has-focus:scale-125">
|
|
26
|
+
<span class="sr-only">four stars</span>
|
|
27
|
+
<input x-model="currentVal" id="fourStars" type="radio" class="sr-only" name="rating" value="4">
|
|
28
|
+
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" viewBox="0 0 24 24" fill="currentColor" class="size-5" x-bind:class="currentVal > 3 ? 'text-amber-500' : 'text-on-surface dark:text-on-surface-dark'">
|
|
29
|
+
<path fill-rule="evenodd" d="M10.788 3.21c.448-1.077 1.976-1.077 2.424 0l2.082 5.006 5.404.434c1.164.093 1.636 1.545.749 2.305l-4.117 3.527 1.257 5.273c.271 1.136-.964 2.033-1.96 1.425L12 18.354 7.373 21.18c-.996.608-2.231-.29-1.96-1.425l1.257-5.273-4.117-3.527c-.887-.76-.415-2.212.749-2.305l5.404-.434 2.082-5.005Z" clip-rule="evenodd">
|
|
30
|
+
</svg>
|
|
31
|
+
</label>
|
|
32
|
+
<label for="fiveStars" class="transition hover:scale-125 has-focus:scale-125">
|
|
33
|
+
<span class="sr-only">five stars</span>
|
|
34
|
+
<input x-model="currentVal" id="fiveStars" type="radio" class="sr-only" name="rating" value="5">
|
|
35
|
+
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" viewBox="0 0 24 24" fill="currentColor" class="size-5" x-bind:class="currentVal > 4 ? 'text-amber-500' : 'text-on-surface dark:text-on-surface-dark'">
|
|
36
|
+
<path fill-rule="evenodd" d="M10.788 3.21c.448-1.077 1.976-1.077 2.424 0l2.082 5.006 5.404.434c1.164.093 1.636 1.545.749 2.305l-4.117 3.527 1.257 5.273c.271 1.136-.964 2.033-1.96 1.425L12 18.354 7.373 21.18c-.996.608-2.231-.29-1.96-1.425l1.257-5.273-4.117-3.527c-.887-.76-.415-2.212.749-2.305l5.404-.434 2.082-5.005Z" clip-rule="evenodd">
|
|
37
|
+
</svg>
|
|
38
|
+
</label>
|
|
39
|
+
</div>
|
|
40
|
+
</template>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<!-- Apex component adapted from Penguin UI (MIT). -->
|
|
2
|
+
<template x-data="{ showSidebar: false }">
|
|
3
|
+
<div class="relative flex w-full flex-col md:flex-row">
|
|
4
|
+
<!-- This allows screen readers to skip the sidebar and go directly to the main content. -->
|
|
5
|
+
<a class="sr-only" href="#main-content">skip to the main content</a>
|
|
6
|
+
|
|
7
|
+
<!-- dark overlay for when the sidebar is open on smaller screens -->
|
|
8
|
+
<div x-cloak x-show="showSidebar" class="fixed inset-0 z-10 bg-surface-dark/10 backdrop-blur-xs md:hidden" aria-hidden="true" x-on:click="showSidebar = false" x-transition.opacity ></div>
|
|
9
|
+
|
|
10
|
+
<nav x-cloak class="fixed left-0 z-20 flex h-svh w-60 shrink-0 flex-col border-r border-outline bg-surface-alt p-4 transition-transform duration-300 md:w-64 md:translate-x-0 md:relative dark:border-outline-dark dark:bg-surface-dark-alt" x-bind:class="showSidebar ? 'translate-x-0' : '-translate-x-60'" aria-label="sidebar navigation">
|
|
11
|
+
<!-- brand wordmark -->
|
|
12
|
+
<a href="#" class="ml-2 w-fit text-2xl font-bold text-on-surface-strong dark:text-on-surface-dark-strong">
|
|
13
|
+
<span class="sr-only">homepage</span>
|
|
14
|
+
<span>Ap<span class="text-primary dark:text-primary-dark">e</span>x</span>
|
|
15
|
+
</a>
|
|
16
|
+
|
|
17
|
+
<!-- search -->
|
|
18
|
+
<div class="relative my-4 flex w-full max-w-xs flex-col gap-1 text-on-surface dark:text-on-surface-dark">
|
|
19
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="2" class="absolute left-2 top-1/2 size-5 -translate-y-1/2 text-on-surface/50 dark:text-on-surface-dark/50" aria-hidden="true">
|
|
20
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"/>
|
|
21
|
+
</svg>
|
|
22
|
+
<input type="search" class="w-full border border-outline rounded-radius bg-surface px-2 py-1.5 pl-9 text-sm focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary disabled:cursor-not-allowed disabled:opacity-75 dark:border-outline-dark dark:bg-surface-dark/50 dark:focus-visible:outline-primary-dark" name="search" aria-label="Search" placeholder="Search"/>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<!-- sidebar links -->
|
|
26
|
+
<div class="flex flex-col gap-2 overflow-y-auto pb-6">
|
|
27
|
+
|
|
28
|
+
<a href="#" class="flex items-center rounded-radius gap-2 px-2 py-1.5 text-sm font-medium text-on-surface underline-offset-2 hover:bg-primary/5 hover:text-on-surface-strong focus-visible:underline focus:outline-hidden dark:text-on-surface-dark dark:hover:bg-primary-dark/5 dark:hover:text-on-surface-dark-strong">
|
|
29
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5 shrink-0" aria-hidden="true">
|
|
30
|
+
<path d="M15.5 2A1.5 1.5 0 0 0 14 3.5v13a1.5 1.5 0 0 0 1.5 1.5h1a1.5 1.5 0 0 0 1.5-1.5v-13A1.5 1.5 0 0 0 16.5 2h-1ZM9.5 6A1.5 1.5 0 0 0 8 7.5v9A1.5 1.5 0 0 0 9.5 18h1a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 10.5 6h-1ZM3.5 10A1.5 1.5 0 0 0 2 11.5v5A1.5 1.5 0 0 0 3.5 18h1A1.5 1.5 0 0 0 6 16.5v-5A1.5 1.5 0 0 0 4.5 10h-1Z"/>
|
|
31
|
+
</svg>
|
|
32
|
+
<span>Dashboard</span>
|
|
33
|
+
</a>
|
|
34
|
+
|
|
35
|
+
<a href="#" class="flex items-center rounded-radius gap-2 bg-primary/10 px-2 py-1.5 text-sm font-medium text-on-surface-strong underline-offset-2 focus-visible:underline focus:outline-hidden dark:bg-primary-dark/10 dark:text-on-surface-dark-strong">
|
|
36
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5 shrink-0" aria-hidden="true">
|
|
37
|
+
<path d="M10 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM3.465 14.493a1.23 1.23 0 0 0 .41 1.412A9.957 9.957 0 0 0 10 18c2.31 0 4.438-.784 6.131-2.1.43-.333.604-.903.408-1.41a7.002 7.002 0 0 0-13.074.003Z"/>
|
|
38
|
+
</svg>
|
|
39
|
+
<span>Profile</span>
|
|
40
|
+
<span class="sr-only">active</span>
|
|
41
|
+
</a>
|
|
42
|
+
|
|
43
|
+
<a href="#" class="flex items-center rounded-radius gap-2 px-2 py-1.5 text-sm font-medium text-on-surface underline-offset-2 hover:bg-primary/5 hover:text-on-surface-strong focus-visible:underline focus:outline-hidden dark:text-on-surface-dark dark:hover:bg-primary-dark/5 dark:hover:text-on-surface-dark-strong">
|
|
44
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5 shrink-0" aria-hidden="true">
|
|
45
|
+
<path fill-rule="evenodd" d="M10 2c-2.236 0-4.43.18-6.57.524C1.993 2.755 1 4.014 1 5.426v5.148c0 1.413.993 2.67 2.43 2.902 1.168.188 2.352.327 3.55.414.28.02.521.18.642.413l1.713 3.293a.75.75 0 0 0 1.33 0l1.713-3.293a.783.783 0 0 1 .642-.413 41.102 41.102 0 0 0 3.55-.414c1.437-.231 2.43-1.49 2.43-2.902V5.426c0-1.413-.993-2.67-2.43-2.902A41.289 41.289 0 0 0 10 2ZM6.75 6a.75.75 0 0 0 0 1.5h6.5a.75.75 0 0 0 0-1.5h-6.5Zm0 2.5a.75.75 0 0 0 0 1.5h3.5a.75.75 0 0 0 0-1.5h-3.5Z" clip-rule="evenodd"/>
|
|
46
|
+
</svg>
|
|
47
|
+
<span>Inbox</span>
|
|
48
|
+
</a>
|
|
49
|
+
|
|
50
|
+
<a href="#" class="flex items-center rounded-radius gap-2 px-2 py-1.5 text-sm font-medium text-on-surface underline-offset-2 hover:bg-primary/5 hover:text-on-surface-strong focus-visible:underline focus:outline-hidden dark:text-on-surface-dark dark:hover:bg-primary-dark/5 dark:hover:text-on-surface-dark-strong">
|
|
51
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5 shrink-0" aria-hidden="true">
|
|
52
|
+
<path fill-rule="evenodd" d="M10 2a6 6 0 0 0-6 6c0 1.887-.454 3.665-1.257 5.234a.75.75 0 0 0 .515 1.076 32.91 32.91 0 0 0 3.256.508 3.5 3.5 0 0 0 6.972 0 32.903 32.903 0 0 0 3.256-.508.75.75 0 0 0 .515-1.076A11.448 11.448 0 0 1 16 8a6 6 0 0 0-6-6ZM8.05 14.943a33.54 33.54 0 0 0 3.9 0 2 2 0 0 1-3.9 0Z" clip-rule="evenodd"/>
|
|
53
|
+
</svg>
|
|
54
|
+
<span>Notifications</span>
|
|
55
|
+
</a>
|
|
56
|
+
|
|
57
|
+
<a href="#" class="flex items-center rounded-radius gap-2 px-2 py-1.5 text-sm font-medium text-on-surface underline-offset-2 hover:bg-primary/5 hover:text-on-surface-strong focus-visible:underline focus:outline-hidden dark:text-on-surface-dark dark:hover:bg-primary-dark/5 dark:hover:text-on-surface-dark-strong">
|
|
58
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5 shrink-0" aria-hidden="true">
|
|
59
|
+
<path d="M7.84 1.804A1 1 0 0 1 8.82 1h2.36a1 1 0 0 1 .98.804l.331 1.652a6.993 6.993 0 0 1 1.929 1.115l1.598-.54a1 1 0 0 1 1.186.447l1.18 2.044a1 1 0 0 1-.205 1.251l-1.267 1.113a7.047 7.047 0 0 1 0 2.228l1.267 1.113a1 1 0 0 1 .206 1.25l-1.18 2.045a1 1 0 0 1-1.187.447l-1.598-.54a6.993 6.993 0 0 1-1.929 1.115l-.33 1.652a1 1 0 0 1-.98.804H8.82a1 1 0 0 1-.98-.804l-.331-1.652a6.993 6.993 0 0 1-1.929-1.115l-1.598.54a1 1 0 0 1-1.186-.447l-1.18-2.044a1 1 0 0 1 .205-1.251l1.267-1.114a7.05 7.05 0 0 1 0-2.227L1.821 7.773a1 1 0 0 1-.206-1.25l1.18-2.045a1 1 0 0 1 1.187-.447l1.598.54A6.992 6.992 0 0 1 7.51 3.456l.33-1.652ZM10 13a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z" clip-rule="evenodd"/>
|
|
60
|
+
</svg>
|
|
61
|
+
<span>Settings</span>
|
|
62
|
+
</a>
|
|
63
|
+
</div>
|
|
64
|
+
</nav>
|
|
65
|
+
|
|
66
|
+
<!-- main content -->
|
|
67
|
+
<div id="main-content" class="h-svh w-full overflow-y-auto p-4 bg-surface dark:bg-surface-dark">
|
|
68
|
+
<!-- Add main content here -->
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<!-- toggle button for small screen -->
|
|
72
|
+
<button class="fixed right-4 top-4 z-20 rounded-full bg-primary p-4 md:hidden text-on-primary dark:bg-primary-dark dark:text-on-primary-dark" x-on:click="showSidebar = ! showSidebar">
|
|
73
|
+
<svg x-show="showSidebar" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-5" aria-hidden="true">
|
|
74
|
+
<path d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z"/>
|
|
75
|
+
</svg>
|
|
76
|
+
<svg x-show="! showSidebar" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-5" aria-hidden="true">
|
|
77
|
+
<path d="M0 3a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm5-1v12h9a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1zM4 2H2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h2z"/>
|
|
78
|
+
</svg>
|
|
79
|
+
<span class="sr-only">sidebar toggle</span>
|
|
80
|
+
</button>
|
|
81
|
+
</div>
|
|
82
|
+
</template>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<!-- Apex component adapted from Penguin UI (MIT). -->
|
|
2
|
+
<template>
|
|
3
|
+
<ol class="flex w-full items-center gap-2" aria-label="registration progress">
|
|
4
|
+
<!-- completed step -->
|
|
5
|
+
<li class="text-sm">
|
|
6
|
+
<div class="flex items-center gap-2" aria-label="create an account">
|
|
7
|
+
<span class="flex size-6 items-center justify-center rounded-full border-primary bg-primary text-on-primary dark:border-primary-dark dark:bg-primary-dark dark:text-on-primary-dark">
|
|
8
|
+
<svg class="size-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" aria-hidden="true">
|
|
9
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"/>
|
|
10
|
+
</svg>
|
|
11
|
+
<span class="sr-only">completed</span>
|
|
12
|
+
</span>
|
|
13
|
+
</div>
|
|
14
|
+
</li>
|
|
15
|
+
<!-- current step -->
|
|
16
|
+
<li class="flex w-full items-center text-sm" aria-current="step" aria-label="choose a plan">
|
|
17
|
+
<span class="h-0.5 w-full bg-primary dark:bg-primary-dark" aria-hidden="true"></span>
|
|
18
|
+
<div class="flex items-center gap-2 pl-2">
|
|
19
|
+
<span class="flex size-6 shrink-0 items-center justify-center rounded-full border-primary bg-primary font-bold text-on-primary outline outline-2 outline-offset-2 outline-primary dark:border-primary-dark dark:bg-primary-dark dark:text-on-primary-dark dark:outline-primary-dark">2</span>
|
|
20
|
+
</div>
|
|
21
|
+
</li>
|
|
22
|
+
<li class="flex w-full items-center text-sm" aria-label="checkout">
|
|
23
|
+
<span class="h-0.5 w-full bg-outline dark:bg-outline-dark" aria-hidden="true"></span>
|
|
24
|
+
<div class="flex items-center gap-2 pl-2">
|
|
25
|
+
<span class="flex size-6 shrink-0 items-center justify-center rounded-full border-outline bg-surface-alt font-medium text-on-surface dark:border-outline-dark dark:bg-surface-dark-alt dark:text-on-surface-dark">3</span>
|
|
26
|
+
</div>
|
|
27
|
+
</li>
|
|
28
|
+
<li aria-label="start trial" class="flex w-full items-center text-sm">
|
|
29
|
+
<span aria-hidden="true" class="h-0.5 w-full bg-outline dark:bg-outline-dark"></span>
|
|
30
|
+
<div class="flex items-center gap-2 pl-2">
|
|
31
|
+
<span class="flex size-6 shrink-0 items-center justify-center rounded-full border-outline bg-surface-alt font-medium text-on-surface dark:border-outline-dark dark:bg-surface-dark-alt dark:text-on-surface-dark">4</span>
|
|
32
|
+
</div>
|
|
33
|
+
</li>
|
|
34
|
+
</ol>
|
|
35
|
+
</template>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<!-- Apex component adapted from Penguin UI (MIT). -->
|
|
2
|
+
<template>
|
|
3
|
+
<div class="overflow-hidden w-full overflow-x-auto rounded-radius border border-outline dark:border-outline-dark">
|
|
4
|
+
<table class="w-full text-left text-sm text-on-surface dark:text-on-surface-dark">
|
|
5
|
+
<thead class="border-b border-outline bg-surface-alt text-sm text-on-surface-strong dark:border-outline-dark dark:bg-surface-dark-alt dark:text-on-surface-dark-strong">
|
|
6
|
+
<tr>
|
|
7
|
+
<th scope="col" class="p-4">CustomerID</th>
|
|
8
|
+
<th scope="col" class="p-4">Name</th>
|
|
9
|
+
<th scope="col" class="p-4">Email</th>
|
|
10
|
+
<th scope="col" class="p-4">Membership</th>
|
|
11
|
+
</tr>
|
|
12
|
+
</thead>
|
|
13
|
+
<tbody class="divide-y divide-outline dark:divide-outline-dark">
|
|
14
|
+
<tr>
|
|
15
|
+
<td class="p-4">2335</td>
|
|
16
|
+
<td class="p-4">Alice Brown</td>
|
|
17
|
+
<td class="p-4">alice.brown@gmail.com</td>
|
|
18
|
+
<td class="p-4">Silver</td>
|
|
19
|
+
</tr>
|
|
20
|
+
<tr>
|
|
21
|
+
<td class="p-4">2338</td>
|
|
22
|
+
<td class="p-4">Bob Johnson</td>
|
|
23
|
+
<td class="p-4">johnson.bob@outlook.com</td>
|
|
24
|
+
<td class="p-4">Gold</td>
|
|
25
|
+
</tr>
|
|
26
|
+
<tr>
|
|
27
|
+
<td class="p-4">2342</td>
|
|
28
|
+
<td class="p-4">Sarah Adams</td>
|
|
29
|
+
<td class="p-4">s.adams@gmail.com</td>
|
|
30
|
+
<td class="p-4">Gold</td>
|
|
31
|
+
</tr>
|
|
32
|
+
</tbody>
|
|
33
|
+
</table>
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<!-- Apex component adapted from Penguin UI (MIT). -->
|
|
2
|
+
<template x-data="{
|
|
3
|
+
notifications: [],
|
|
4
|
+
displayDuration: 8000,
|
|
5
|
+
|
|
6
|
+
addNotification({ variant = 'info', title = null, message = null }) {
|
|
7
|
+
const id = Date.now()
|
|
8
|
+
const notification = { id, variant, title, message }
|
|
9
|
+
|
|
10
|
+
// Keep only the most recent 20 notifications
|
|
11
|
+
if (this.notifications.length >= 20) {
|
|
12
|
+
this.notifications.splice(0, this.notifications.length - 19)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Add the new notification to the notifications stack
|
|
16
|
+
this.notifications.push(notification)
|
|
17
|
+
},
|
|
18
|
+
removeNotification(id) {
|
|
19
|
+
setTimeout(() => {
|
|
20
|
+
this.notifications = this.notifications.filter(
|
|
21
|
+
(notification) => notification.id !== id,
|
|
22
|
+
)
|
|
23
|
+
}, 400);
|
|
24
|
+
},
|
|
25
|
+
}">
|
|
26
|
+
<div x-on:notify.window="addNotification({
|
|
27
|
+
variant: $event.detail.variant,
|
|
28
|
+
title: $event.detail.title,
|
|
29
|
+
message: $event.detail.message,
|
|
30
|
+
})">
|
|
31
|
+
|
|
32
|
+
<!-- Trigger -->
|
|
33
|
+
<button x-on:click="$dispatch('notify', { variant: 'info', title: 'Update Available', message: 'A new version of the app is ready for you. Update now to enjoy the latest features!' })" type="button" class="whitespace-nowrap rounded-radius bg-info px-4 py-2 text-center text-sm font-medium tracking-wide text-on-info transition hover:opacity-75 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-info active:opacity-100 active:outline-offset-0 disabled:cursor-not-allowed disabled:opacity-75">Info</button>
|
|
34
|
+
|
|
35
|
+
<!-- Notifications -->
|
|
36
|
+
<div x-on:mouseenter="$dispatch('pause-auto-dismiss')" x-on:mouseleave="$dispatch('resume-auto-dismiss')" class="group pointer-events-none fixed inset-x-8 top-0 z-99 flex max-w-full flex-col gap-2 bg-transparent px-6 py-6 md:bottom-0 md:left-[unset] md:right-0 md:top-[unset] md:max-w-sm">
|
|
37
|
+
<template x-for="(notification, index) in notifications" x-bind:key="notification.id">
|
|
38
|
+
<!-- root div holds all of the notifications -->
|
|
39
|
+
<div>
|
|
40
|
+
<!-- Info Notification -->
|
|
41
|
+
<template x-if="notification.variant === 'info'">
|
|
42
|
+
<div x-data="{ isVisible: false, timeout: null }" x-cloak x-show="isVisible" class="pointer-events-auto relative rounded-radius border border-info bg-surface text-on-surface dark:bg-surface-dark dark:text-on-surface-dark" role="alert" x-on:pause-auto-dismiss.window="clearTimeout(timeout)" x-on:resume-auto-dismiss.window=" timeout = setTimeout(() => {(isVisible = false), removeNotification(notification.id) }, displayDuration)" x-init="$nextTick(() => { isVisible = true }), (timeout = setTimeout(() => { isVisible = false, removeNotification(notification.id)}, displayDuration))" x-transition:enter="transition duration-300 ease-out" x-transition:enter-end="translate-y-0" x-transition:enter-start="translate-y-8" x-transition:leave="transition duration-300 ease-in" x-transition:leave-end="-translate-x-24 opacity-0 md:translate-x-24" x-transition:leave-start="translate-x-0 opacity-100">
|
|
43
|
+
<div class="flex w-full items-center gap-2.5 bg-info/10 rounded-radius p-4 transition-all duration-300">
|
|
44
|
+
|
|
45
|
+
<!-- Icon -->
|
|
46
|
+
<div class="rounded-full bg-info/15 p-0.5 text-info" aria-hidden="true">
|
|
47
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5" aria-hidden="true">
|
|
48
|
+
<path fill-rule="evenodd" d="M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0Zm-7-4a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM9 9a.75.75 0 0 0 0 1.5h.253a.25.25 0 0 1 .244.304l-.459 2.066A1.75 1.75 0 0 0 10.747 15H11a.75.75 0 0 0 0-1.5h-.253a.25.25 0 0 1-.244-.304l.459-2.066A1.75 1.75 0 0 0 9.253 9H9Z" clip-rule="evenodd" />
|
|
49
|
+
</svg>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<!-- Title & Message -->
|
|
53
|
+
<div class="flex flex-col gap-2">
|
|
54
|
+
<h3 x-cloak x-show="notification.title" class="text-sm font-semibold text-info" x-text="notification.title"></h3>
|
|
55
|
+
<p x-cloak x-show="notification.message" class="text-pretty text-sm" x-text="notification.message"></p>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<!--Dismiss Button -->
|
|
59
|
+
<button type="button" class="ml-auto" aria-label="dismiss notification" x-on:click="(isVisible = false), removeNotification(notification.id)">
|
|
60
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="2" class="size-5 shrink-0" aria-hidden="true">
|
|
61
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
|
|
62
|
+
</svg>
|
|
63
|
+
</button>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</template>
|
|
67
|
+
</div>
|
|
68
|
+
</template>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</template>
|
package/components/registry.json
CHANGED
|
@@ -9,7 +9,11 @@
|
|
|
9
9
|
"file": "Card.alpine",
|
|
10
10
|
"description": "A surface container that inherits the theme."
|
|
11
11
|
},
|
|
12
|
-
"badge": {
|
|
12
|
+
"badge": {
|
|
13
|
+
"name": "Badge",
|
|
14
|
+
"file": "Badge.alpine",
|
|
15
|
+
"description": "A small status/label pill."
|
|
16
|
+
},
|
|
13
17
|
"alert": {
|
|
14
18
|
"name": "Alert",
|
|
15
19
|
"file": "Alert.alpine",
|
|
@@ -109,5 +113,70 @@
|
|
|
109
113
|
"name": "Dropdown",
|
|
110
114
|
"file": "Dropdown.alpine",
|
|
111
115
|
"description": "Menu with keyboard nav + click-outside close."
|
|
116
|
+
},
|
|
117
|
+
"carousel": {
|
|
118
|
+
"name": "Carousel",
|
|
119
|
+
"file": "Carousel.alpine",
|
|
120
|
+
"description": "Slide carousel with prev/next + dot indicators."
|
|
121
|
+
},
|
|
122
|
+
"chat-bubble": {
|
|
123
|
+
"name": "ChatBubble",
|
|
124
|
+
"file": "ChatBubble.alpine",
|
|
125
|
+
"description": "Received/sent chat message bubbles; text via slot."
|
|
126
|
+
},
|
|
127
|
+
"counter": {
|
|
128
|
+
"name": "Counter",
|
|
129
|
+
"file": "Counter.alpine",
|
|
130
|
+
"description": "Numeric stepper with min/max clamping."
|
|
131
|
+
},
|
|
132
|
+
"range": {
|
|
133
|
+
"name": "Range",
|
|
134
|
+
"file": "Range.alpine",
|
|
135
|
+
"description": "Styled range slider with themed thumb."
|
|
136
|
+
},
|
|
137
|
+
"file-input": {
|
|
138
|
+
"name": "FileInput",
|
|
139
|
+
"file": "FileInput.alpine",
|
|
140
|
+
"description": "Native file upload with styled button + label."
|
|
141
|
+
},
|
|
142
|
+
"rating": {
|
|
143
|
+
"name": "Rating",
|
|
144
|
+
"file": "Rating.alpine",
|
|
145
|
+
"description": "Interactive 5-star radio rating."
|
|
146
|
+
},
|
|
147
|
+
"pagination": {
|
|
148
|
+
"name": "Pagination",
|
|
149
|
+
"file": "Pagination.alpine",
|
|
150
|
+
"description": "Numbered pagination with prev/next."
|
|
151
|
+
},
|
|
152
|
+
"steps": {
|
|
153
|
+
"name": "Steps",
|
|
154
|
+
"file": "Steps.alpine",
|
|
155
|
+
"description": "Horizontal step progress indicator."
|
|
156
|
+
},
|
|
157
|
+
"navbar": {
|
|
158
|
+
"name": "Navbar",
|
|
159
|
+
"file": "Navbar.alpine",
|
|
160
|
+
"description": "Responsive top nav with mobile hamburger menu."
|
|
161
|
+
},
|
|
162
|
+
"sidebar": {
|
|
163
|
+
"name": "Sidebar",
|
|
164
|
+
"file": "Sidebar.alpine",
|
|
165
|
+
"description": "Responsive off-canvas sidebar with nav links."
|
|
166
|
+
},
|
|
167
|
+
"table": {
|
|
168
|
+
"name": "Table",
|
|
169
|
+
"file": "Table.alpine",
|
|
170
|
+
"description": "Bordered data table with header + rows."
|
|
171
|
+
},
|
|
172
|
+
"combobox": {
|
|
173
|
+
"name": "Combobox",
|
|
174
|
+
"file": "Combobox.alpine",
|
|
175
|
+
"description": "Searchable single-select with keyboard nav."
|
|
176
|
+
},
|
|
177
|
+
"toast": {
|
|
178
|
+
"name": "Toast",
|
|
179
|
+
"file": "Toast.alpine",
|
|
180
|
+
"description": "Stacking toast notifications with auto-dismiss."
|
|
112
181
|
}
|
|
113
182
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apex-stack/core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "The full-stack meta-framework for Alpine.js — CLI and runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"vite": "^6.0.7",
|
|
49
49
|
"zod": "^4.4.3",
|
|
50
50
|
"@apex-stack/kit": "0.2.0",
|
|
51
|
-
"@apex-stack/
|
|
52
|
-
"@apex-stack/
|
|
51
|
+
"@apex-stack/theme": "0.3.0",
|
|
52
|
+
"@apex-stack/vite": "0.1.6"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"alpinejs": "^3.14.0"
|