nitro-web 0.0.36 → 0.0.37
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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { twMerge } from 'tailwind-merge'
|
|
2
|
-
import {
|
|
2
|
+
import { ChevronDown, ChevronUp } from 'lucide-react'
|
|
3
3
|
|
|
4
4
|
type Button = React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
5
5
|
color?: 'primary'|'secondary'|'black'|'white'
|
|
@@ -51,8 +51,8 @@ export function Button({
|
|
|
51
51
|
const loading = isLoading ? '[&>*]:opacity-0 text-opacity-0' : ''
|
|
52
52
|
|
|
53
53
|
function getIcon(Icon: React.ReactNode | 'v') {
|
|
54
|
-
if (Icon == 'v' || Icon == 'down') return <
|
|
55
|
-
if (Icon == '^' || Icon == 'up') return <
|
|
54
|
+
if (Icon == 'v' || Icon == 'down') return <ChevronDown size={16.5} className="mt-[-1.4rem] mb-[-1.5rem] -mx-0.5" />
|
|
55
|
+
if (Icon == '^' || Icon == 'up') return <ChevronUp size={16.5} className="mt-[-1.4rem] mb-[-1.5rem] -mx-0.5" />
|
|
56
56
|
else return Icon
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// Todo: show correct message type, e.g. error, warning, info, success `${store.message.type || 'success'}`
|
|
2
2
|
import { isObject, isString, queryObject } from 'nitro-web/util'
|
|
3
|
-
import {
|
|
4
|
-
import { CheckCircleIcon } from '@heroicons/react/24/outline'
|
|
5
|
-
import { XMarkIcon } from '@heroicons/react/20/solid'
|
|
3
|
+
import { X, CircleCheck } from 'lucide-react'
|
|
6
4
|
import { MessageObject } from 'nitro-web/types'
|
|
7
5
|
|
|
8
6
|
/**
|
|
@@ -64,7 +62,7 @@ export function Message() {
|
|
|
64
62
|
// Show message and hide it again after some time. Send back cleanup if store.message changes
|
|
65
63
|
} else if (messageObject && now - 500 < messageObject.date) {
|
|
66
64
|
const timeout1 = setTimeout(() => setVisible(true), 50)
|
|
67
|
-
if (messageObject.timeout !== 0 && !devDontHide) var timeout2 = setTimeout(hide, messageObject.timeout ||
|
|
65
|
+
if (messageObject.timeout !== 0 && !devDontHide) var timeout2 = setTimeout(hide, messageObject.timeout || 500000)
|
|
68
66
|
return () => {
|
|
69
67
|
clearTimeout(timeout1)
|
|
70
68
|
clearTimeout(timeout2)
|
|
@@ -85,16 +83,15 @@ export function Message() {
|
|
|
85
83
|
className="pointer-events-none fixed inset-0 flex items-end px-4 py-6 sm:items-start sm:p-6 z-20 nitro-message"
|
|
86
84
|
>
|
|
87
85
|
<div className="flex w-full flex-col items-center space-y-4 sm:items-end">
|
|
88
|
-
{
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
<div className="p-4">
|
|
86
|
+
{isObject(store.message) && (
|
|
87
|
+
<div className={
|
|
88
|
+
'overflow-hidden pointer-events-auto max-w-[350px] rounded-md bg-white shadow-lg ring-1 ring-black/5 transition ' +
|
|
89
|
+
(visible ? 'translate-x-0 opacity-100' : 'translate-x-1 opacity-0')
|
|
90
|
+
}>
|
|
91
|
+
<div className="p-3">
|
|
95
92
|
<div className="flex items-start">
|
|
96
93
|
<div className="shrink-0">
|
|
97
|
-
<
|
|
94
|
+
<CircleCheck aria-hidden="true" size={21} className="text-green-400 mt-0.5" />
|
|
98
95
|
</div>
|
|
99
96
|
<div className="ml-3 flex-1 pt-0.5">
|
|
100
97
|
<p className="text-sm font-medium text-gray-900">{typeof store.message === 'object' && store.message?.text}
|
|
@@ -105,17 +102,17 @@ export function Message() {
|
|
|
105
102
|
<button
|
|
106
103
|
type="button"
|
|
107
104
|
onClick={hide}
|
|
108
|
-
className="inline-flex
|
|
105
|
+
className="inline-flex rounded-md bg-white text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2
|
|
109
106
|
focus:ring-indigo-500 focus:ring-offset-2"
|
|
110
107
|
>
|
|
111
108
|
<span className="sr-only">Close</span>
|
|
112
|
-
<
|
|
109
|
+
<X aria-hidden="true" size={19} className="mt-0.5" />
|
|
113
110
|
</button>
|
|
114
111
|
</div>
|
|
115
112
|
</div>
|
|
116
113
|
</div>
|
|
117
114
|
</div>
|
|
118
|
-
|
|
115
|
+
)}
|
|
119
116
|
</div>
|
|
120
117
|
</div>
|
|
121
118
|
</>
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
// Component: https://tailwindui.com/components/application-ui/application-shells/sidebar#component-a69d85b6237ea2ad506c00ef1cd39a38
|
|
2
|
+
import { css } from 'twin.macro'
|
|
2
3
|
import avatarImg from 'nitro-web/client/imgs/avatar.jpg'
|
|
3
4
|
import { injectedConfig } from 'nitro-web'
|
|
4
5
|
import {
|
|
6
|
+
Bars3Icon,
|
|
5
7
|
HomeIcon,
|
|
6
8
|
UsersIcon,
|
|
9
|
+
XMarkIcon,
|
|
7
10
|
ArrowLeftCircleIcon,
|
|
8
11
|
PaintBrushIcon,
|
|
9
12
|
} from '@heroicons/react/24/outline'
|
|
10
13
|
|
|
11
|
-
const sidebarWidth = 'w-
|
|
14
|
+
const sidebarWidth = 'w-80'
|
|
12
15
|
|
|
13
16
|
export type SidebarProps = {
|
|
14
17
|
Logo?: React.FC<{ width?: string, height?: string }>;
|
|
@@ -24,10 +27,52 @@ export function Sidebar({ Logo, menu, links }: SidebarProps) {
|
|
|
24
27
|
const [sidebarOpen, setSidebarOpen] = useState(false)
|
|
25
28
|
return (
|
|
26
29
|
<>
|
|
27
|
-
{/*
|
|
28
|
-
<div
|
|
30
|
+
{/* desktop sidebar */}
|
|
31
|
+
<div css={style} className={
|
|
32
|
+
'fixed inset-y-0 z-50 flex flex-col ease-in-out lg:left-0 lg:translate-x-0 lg:!delay-0 lg:!duration-0 ' +
|
|
33
|
+
(
|
|
34
|
+
sidebarOpen
|
|
35
|
+
? 'left-0 translate-x-[0px] sidebar-transition '
|
|
36
|
+
: 'left-[-100%] translate-x-[-100%] sidebar-transition-delay '
|
|
37
|
+
) +
|
|
38
|
+
sidebarWidth
|
|
39
|
+
}>
|
|
40
|
+
<div className={
|
|
41
|
+
'absolute left-full top-0 flex w-16 justify-center pt-5 lg:hidden duration-300 ease ' +
|
|
42
|
+
(sidebarOpen ? 'opacity-100' : 'opacity-0')
|
|
43
|
+
}>
|
|
44
|
+
<button type="button" onClick={() => setSidebarOpen(false)} className="-m-2.5 p-2.5">
|
|
45
|
+
<XMarkIcon aria-hidden="true" className="size-6 text-white" />
|
|
46
|
+
</button>
|
|
47
|
+
</div>
|
|
29
48
|
<SidebarContents Logo={Logo} menu={menu} links={links} />
|
|
30
49
|
</div>
|
|
50
|
+
|
|
51
|
+
{/* mobile backdrop */}
|
|
52
|
+
<div
|
|
53
|
+
css={style}
|
|
54
|
+
onClick={() => setSidebarOpen(false)}
|
|
55
|
+
className={'fixed w-full z-[49] inset-0 bg-gray-900/70 ease-linear lg:hidden ' +
|
|
56
|
+
(
|
|
57
|
+
sidebarOpen
|
|
58
|
+
? 'left-0 opacity-100 sidebar-transition '
|
|
59
|
+
: 'left-[-100%] opacity-0 sidebar-transition-delay '
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
/>
|
|
63
|
+
|
|
64
|
+
{/* mobile sidebar topbar */}
|
|
65
|
+
<div className="sticky top-0 z-40 flex items-center gap-x-6 bg-white px-4 py-4 shadow-sm sm:px-6 lg:hidden">
|
|
66
|
+
<button type="button" onClick={() => setSidebarOpen(true)} className="-m-2.5 p-2.5 text-gray-700 lg:hidden">
|
|
67
|
+
<Bars3Icon aria-hidden="true" className="size-6" />
|
|
68
|
+
</button>
|
|
69
|
+
<div className="flex-1 text-sm/6 font-semibold text-gray-900">Dashboard</div>
|
|
70
|
+
<Link to="#">
|
|
71
|
+
<img alt="" src={avatarImg} className="size-8 rounded-full bg-gray-50" />
|
|
72
|
+
</Link>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<div class={`${sidebarWidth}`} />
|
|
31
76
|
</>
|
|
32
77
|
)
|
|
33
78
|
}
|
|
@@ -56,13 +101,13 @@ function SidebarContents ({ Logo, menu, links }: SidebarProps) {
|
|
|
56
101
|
|
|
57
102
|
// Sidebar component, swap this element with another sidebar if you like
|
|
58
103
|
return (
|
|
59
|
-
<div className="flex grow flex-col gap-y-8 overflow-y-auto py-5 px-10 border-r
|
|
104
|
+
<div className="flex grow flex-col gap-y-8 overflow-y-auto bg-white py-5 px-10 lg:border-r lg:border-gray-200">
|
|
60
105
|
{Logo && (
|
|
61
106
|
<div className="flex h-16 shrink-0 items-center gap-2 justify-bedtween">
|
|
62
107
|
<Link to="/">
|
|
63
108
|
<Logo width="70" height={undefined} />
|
|
64
109
|
</Link>
|
|
65
|
-
<span className="text-[9px] text-gray-
|
|
110
|
+
<span className="text-[9px] text-gray-900 font-semibold mt-4">{injectedConfig.version}</span>
|
|
66
111
|
</div>
|
|
67
112
|
)}
|
|
68
113
|
<nav className="flex flex-1 flex-col">
|
|
@@ -125,7 +170,7 @@ function SidebarContents ({ Logo, menu, links }: SidebarProps) {
|
|
|
125
170
|
</ul>
|
|
126
171
|
</li>
|
|
127
172
|
|
|
128
|
-
<li className="-mx-6 mt-auto block">
|
|
173
|
+
<li className="-mx-6 mt-auto hidden lg:block">
|
|
129
174
|
<Link
|
|
130
175
|
to="#"
|
|
131
176
|
className="flex items-center gap-x-4 px-6 py-3 text-sm/6 font-semibold text-gray-900 hover:bg-gray-50"
|
|
@@ -138,4 +183,13 @@ function SidebarContents ({ Logo, menu, links }: SidebarProps) {
|
|
|
138
183
|
</nav>
|
|
139
184
|
</div>
|
|
140
185
|
)
|
|
141
|
-
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const style = css`
|
|
189
|
+
&.sidebar-transition-delay {
|
|
190
|
+
transition: transform 300ms, opacity 300ms, left 0ms 300ms;
|
|
191
|
+
}
|
|
192
|
+
&.sidebar-transition {
|
|
193
|
+
transition: transform 300ms, opacity 300ms, left 0ms 0ms;
|
|
194
|
+
}
|
|
195
|
+
`
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
EyeIcon,
|
|
11
11
|
EyeSlashIcon,
|
|
12
12
|
} from '@heroicons/react/20/solid'
|
|
13
|
+
// Maybe use fill-current tw class for lucide icons (https://github.com/lucide-icons/lucide/discussions/458)
|
|
13
14
|
|
|
14
15
|
type InputProps = React.InputHTMLAttributes<HTMLInputElement>
|
|
15
16
|
type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Drop, Dropdown, Field, Select, Button, Checkbox, GithubLink, Modal, Calendar, injectedConfig } from 'nitro-web'
|
|
2
2
|
import { getCountryOptions, getCurrencyOptions, ucFirst } from 'nitro-web/util'
|
|
3
|
-
import {
|
|
3
|
+
import { Check } from 'lucide-react'
|
|
4
4
|
|
|
5
5
|
export function Styleguide() {
|
|
6
6
|
const [customerSearch, setCustomerSearch] = useState('')
|
|
@@ -106,9 +106,11 @@ export function Styleguide() {
|
|
|
106
106
|
<div><Button color="primary" size="sm">*-sm button</Button></div>
|
|
107
107
|
<div><Button color="primary">*-md (default)</Button></div>
|
|
108
108
|
<div><Button color="primary" size="lg">*-lg button</Button></div>
|
|
109
|
-
<div><Button IconLeft={<
|
|
110
|
-
<div><Button IconLeft={<
|
|
111
|
-
|
|
109
|
+
<div><Button IconLeft={<Check size={19} className="-my-5 -mx-0.5" />}>IconLeft</Button></div>
|
|
110
|
+
<div><Button IconLeft={<Check size={19} className="-my-5 -mx-0.5" />}
|
|
111
|
+
className="w-[160px]">IconLeft 160px</Button></div>
|
|
112
|
+
<div><Button IconLeftEnd={<Check size={19} className="-my-5 -mx-0.5" />}
|
|
113
|
+
className="w-[190px]">IconLeftEnd 190px</Button></div>
|
|
112
114
|
<div><Button IconRight="v">IconRight</Button></div>
|
|
113
115
|
<div><Button IconRightEnd="v" className="w-[190px]">IconRightEnd 190px</Button></div>
|
|
114
116
|
<div><Button color="primary" IconRight="v" isLoading>primary isLoading</Button></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nitro-web",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.37",
|
|
4
4
|
"repository": "github:boycce/nitro-web",
|
|
5
5
|
"homepage": "https://boycce.github.io/nitro-web/",
|
|
6
6
|
"description": "Nitro is a battle-tested, modular base project to turbocharge your projects, styled using Tailwind 🚀",
|