uibee 2.17.4 → 3.0.0
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 +34 -0
- package/dist/icons-lZYQ6Vlr.js +125 -0
- package/dist/src/components/index.d.ts +706 -30
- package/dist/src/components/index.js +3243 -44
- package/dist/src/hooks/index.d.ts +15 -3
- package/dist/src/hooks/index.js +44 -3
- package/dist/src/icons/index.d.ts +420 -0
- package/dist/src/icons/index.js +3 -0
- package/dist/src/styles/index.d.ts +1 -1
- package/dist/src/styles/index.js +2 -1
- package/dist/src/utils/index.d.ts +38 -5
- package/dist/src/utils/index.js +125 -6
- package/dist/{src/globals.css → style.css} +1226 -607
- package/dist/useClickOutside-Cmp-RsP3.js +13 -0
- package/index.d.ts +0 -1
- package/package.json +22 -23
- package/src/components/alert/alert.tsx +20 -18
- package/src/components/buttons/button.tsx +28 -35
- package/src/components/confirm/confirmPopup.tsx +15 -17
- package/src/components/container/accordion.tsx +54 -0
- package/src/components/container/glassCard.tsx +14 -0
- package/src/components/container/iconBubble.tsx +30 -0
- package/src/components/container/leftBarPanel.tsx +15 -0
- package/src/components/container/pulseDot.tsx +31 -0
- package/src/components/container/statCard.tsx +24 -0
- package/src/components/container/tabs.tsx +64 -0
- package/src/components/footer/footer.tsx +124 -0
- package/src/components/footer/loginContent.tsx +70 -0
- package/src/components/index.ts +15 -0
- package/src/components/inputs/checkbox.tsx +4 -4
- package/src/components/inputs/input.tsx +11 -13
- package/src/components/inputs/multiSelect.tsx +144 -0
- package/src/components/inputs/radio.tsx +4 -4
- package/src/components/inputs/range.tsx +6 -5
- package/src/components/inputs/searchInput.tsx +1 -1
- package/src/components/inputs/select.tsx +19 -18
- package/src/components/inputs/shared/colorPickerPopup.tsx +5 -5
- package/src/components/inputs/shared/dateTimePickerPopup.tsx +9 -9
- package/src/components/inputs/shared/inputError.tsx +1 -1
- package/src/components/inputs/switch.tsx +7 -7
- package/src/components/inputs/tagInput.tsx +6 -7
- package/src/components/inputs/textarea.tsx +8 -10
- package/src/components/inputs/toggle.tsx +6 -6
- package/src/components/markdownrender/markdownRender.tsx +4 -2
- package/src/components/table/body.tsx +6 -6
- package/src/components/table/format.ts +1 -1
- package/src/components/table/header.tsx +1 -1
- package/src/components/table/pagination.tsx +17 -31
- package/src/components/table/table.tsx +2 -2
- package/src/components/version/version.tsx +1 -1
- package/src/components/vulnerability/constants.ts +6 -6
- package/src/components/vulnerability/severityPill.tsx +6 -7
- package/src/globals.css +12 -1
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useClickOutside.ts +5 -22
- package/src/icons/icons.tsx +431 -0
- package/src/icons/index.ts +2 -0
- package/src/index.ts +0 -1
- package/src/types/hooks.d.ts +8 -2
- package/src/utils/index.ts +1 -1
- package/src/utils/logoConsoleOutput/logoConsoleOutput.ts +31 -0
- package/tsconfig.json +3 -2
- package/tsdown.config.ts +26 -0
- package/Readme.md +0 -29
- package/bun.lock +0 -662
- package/dist/src/components/alert/alert.d.ts +0 -8
- package/dist/src/components/alert/alert.js +0 -15
- package/dist/src/components/buttons/button.d.ts +0 -13
- package/dist/src/components/buttons/button.js +0 -30
- package/dist/src/components/confirm/confirmPopup.d.ts +0 -12
- package/dist/src/components/confirm/confirmPopup.js +0 -18
- package/dist/src/components/container/highlight.d.ts +0 -4
- package/dist/src/components/container/highlight.js +0 -4
- package/dist/src/components/container/page.d.ts +0 -8
- package/dist/src/components/container/page.js +0 -4
- package/dist/src/components/inputs/checkbox.d.ts +0 -17
- package/dist/src/components/inputs/checkbox.js +0 -37
- package/dist/src/components/inputs/input.d.ts +0 -12
- package/dist/src/components/inputs/input.js +0 -124
- package/dist/src/components/inputs/radio.d.ts +0 -17
- package/dist/src/components/inputs/radio.js +0 -27
- package/dist/src/components/inputs/range.d.ts +0 -11
- package/dist/src/components/inputs/range.js +0 -22
- package/dist/src/components/inputs/searchInput.d.ts +0 -6
- package/dist/src/components/inputs/searchInput.js +0 -42
- package/dist/src/components/inputs/select.d.ts +0 -23
- package/dist/src/components/inputs/select.js +0 -70
- package/dist/src/components/inputs/shared/colorPickerPopup.d.ts +0 -8
- package/dist/src/components/inputs/shared/colorPickerPopup.js +0 -191
- package/dist/src/components/inputs/shared/dateTimePickerPopup.d.ts +0 -9
- package/dist/src/components/inputs/shared/dateTimePickerPopup.js +0 -128
- package/dist/src/components/inputs/shared/fieldWrapper.d.ts +0 -14
- package/dist/src/components/inputs/shared/fieldWrapper.js +0 -8
- package/dist/src/components/inputs/shared/index.d.ts +0 -5
- package/dist/src/components/inputs/shared/index.js +0 -5
- package/dist/src/components/inputs/shared/inputError.d.ts +0 -6
- package/dist/src/components/inputs/shared/inputError.js +0 -6
- package/dist/src/components/inputs/shared/inputInfo.d.ts +0 -5
- package/dist/src/components/inputs/shared/inputInfo.js +0 -5
- package/dist/src/components/inputs/shared/inputLabel.d.ts +0 -9
- package/dist/src/components/inputs/shared/inputLabel.js +0 -4
- package/dist/src/components/inputs/switch.d.ts +0 -11
- package/dist/src/components/inputs/switch.js +0 -14
- package/dist/src/components/inputs/tagInput.d.ts +0 -15
- package/dist/src/components/inputs/tagInput.js +0 -40
- package/dist/src/components/inputs/textarea.d.ts +0 -11
- package/dist/src/components/inputs/textarea.js +0 -36
- package/dist/src/components/inputs/toggle.d.ts +0 -14
- package/dist/src/components/inputs/toggle.js +0 -12
- package/dist/src/components/login/loginPage.d.ts +0 -2
- package/dist/src/components/login/loginPage.js +0 -18
- package/dist/src/components/logo/logo.d.ts +0 -5
- package/dist/src/components/logo/logo.js +0 -6
- package/dist/src/components/logo/logoSmall.d.ts +0 -1
- package/dist/src/components/logo/logoSmall.js +0 -6
- package/dist/src/components/markdownrender/markdownRender.d.ts +0 -6
- package/dist/src/components/markdownrender/markdownRender.js +0 -25
- package/dist/src/components/navbar/bubble.d.ts +0 -14
- package/dist/src/components/navbar/bubble.js +0 -8
- package/dist/src/components/navbar/navbar.d.ts +0 -34
- package/dist/src/components/navbar/navbar.js +0 -36
- package/dist/src/components/navbar/navbarDropdown.d.ts +0 -7
- package/dist/src/components/navbar/navbarDropdown.js +0 -19
- package/dist/src/components/navbar/navbarItem.d.ts +0 -11
- package/dist/src/components/navbar/navbarItem.js +0 -12
- package/dist/src/components/table/body.d.ts +0 -15
- package/dist/src/components/table/body.js +0 -116
- package/dist/src/components/table/format.d.ts +0 -1
- package/dist/src/components/table/format.js +0 -27
- package/dist/src/components/table/header.d.ts +0 -8
- package/dist/src/components/table/header.js +0 -47
- package/dist/src/components/table/menu.d.ts +0 -17
- package/dist/src/components/table/menu.js +0 -30
- package/dist/src/components/table/pagination.d.ts +0 -6
- package/dist/src/components/table/pagination.js +0 -86
- package/dist/src/components/table/table.d.ts +0 -14
- package/dist/src/components/table/table.js +0 -14
- package/dist/src/components/toast/toastItem.d.ts +0 -2
- package/dist/src/components/toast/toastItem.js +0 -38
- package/dist/src/components/toast/toaster.d.ts +0 -9
- package/dist/src/components/toast/toaster.js +0 -86
- package/dist/src/components/toggle/language.d.ts +0 -4
- package/dist/src/components/toggle/language.js +0 -29
- package/dist/src/components/toggle/theme.d.ts +0 -3
- package/dist/src/components/toggle/theme.js +0 -30
- package/dist/src/components/version/version.d.ts +0 -7
- package/dist/src/components/version/version.js +0 -12
- package/dist/src/components/vulnerability/constants.d.ts +0 -4
- package/dist/src/components/vulnerability/constants.js +0 -14
- package/dist/src/components/vulnerability/severityPill.d.ts +0 -8
- package/dist/src/components/vulnerability/severityPill.js +0 -8
- package/dist/src/hooks/useClickOutside.d.ts +0 -2
- package/dist/src/hooks/useClickOutside.js +0 -27
- package/dist/src/hooks/useDarkMode.d.ts +0 -1
- package/dist/src/hooks/useDarkMode.js +0 -17
- package/dist/src/hooks/useVisibility.d.ts +0 -4
- package/dist/src/hooks/useVisibility.js +0 -23
- package/dist/src/index.d.ts +0 -5
- package/dist/src/index.js +0 -5
- package/dist/src/scripts/buildCss.d.ts +0 -1
- package/dist/src/scripts/buildCss.js +0 -22
- package/dist/src/scripts/index.d.ts +0 -1
- package/dist/src/scripts/index.js +0 -1
- package/dist/src/scripts/rewriteAlias.d.ts +0 -1
- package/dist/src/scripts/rewriteAlias.js +0 -31
- package/dist/src/utils/LogoConsoleOutput/LogoConsoleOutput.d.ts +0 -1
- package/dist/src/utils/LogoConsoleOutput/LogoConsoleOutput.js +0 -44
- package/dist/src/utils/auth/callback.d.ts +0 -2
- package/dist/src/utils/auth/callback.js +0 -63
- package/dist/src/utils/auth/getDomain.d.ts +0 -2
- package/dist/src/utils/auth/getDomain.js +0 -6
- package/dist/src/utils/auth/login.d.ts +0 -3
- package/dist/src/utils/auth/login.js +0 -14
- package/dist/src/utils/auth/logout.d.ts +0 -3
- package/dist/src/utils/auth/logout.js +0 -18
- package/dist/src/utils/auth/token.d.ts +0 -3
- package/dist/src/utils/auth/token.js +0 -33
- package/dist/tailwind.config.d.ts +0 -3
- package/dist/tailwind.config.js +0 -7
- package/src/scripts/buildCss.ts +0 -25
- package/src/scripts/index.ts +0 -1
- package/src/scripts/rewriteAlias.ts +0 -39
- package/src/utils/LogoConsoleOutput/LogoConsoleOutput.ts +0 -61
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
import VersionTag from '@components/version/version'
|
|
3
|
+
|
|
4
|
+
export type Lang = 'no' | 'en'
|
|
5
|
+
export type BilingualString = string | { no: string; en: string }
|
|
6
|
+
|
|
7
|
+
export type FooterColumn = {
|
|
8
|
+
heading: BilingualString
|
|
9
|
+
items: { label: BilingualString; href?: string }[]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type FooterSocialLink = {
|
|
13
|
+
title: string
|
|
14
|
+
href: string
|
|
15
|
+
icon: ReactNode
|
|
16
|
+
hoverClass?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type FooterProps = {
|
|
20
|
+
logo: ReactNode
|
|
21
|
+
sponsor?: { node: ReactNode; label?: BilingualString }
|
|
22
|
+
columns?: FooterColumn[]
|
|
23
|
+
socialLinks?: FooterSocialLink[]
|
|
24
|
+
copyright: BilingualString
|
|
25
|
+
version?: { tag: string; href: string }
|
|
26
|
+
lang?: Lang
|
|
27
|
+
className?: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function t(s: BilingualString, lang: Lang): string {
|
|
31
|
+
return typeof s === 'string' ? s : s[lang]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default function Footer({
|
|
35
|
+
logo,
|
|
36
|
+
sponsor,
|
|
37
|
+
columns,
|
|
38
|
+
socialLinks,
|
|
39
|
+
copyright,
|
|
40
|
+
version,
|
|
41
|
+
lang = 'no',
|
|
42
|
+
className,
|
|
43
|
+
}: FooterProps) {
|
|
44
|
+
const year = new Date().getFullYear()
|
|
45
|
+
const hasRight = (columns && columns.length > 0) || (socialLinks && socialLinks.length > 0)
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div className={`mt-24 bg-login-950 md:mt-40 ${className || ''}`}>
|
|
49
|
+
<div className={`
|
|
50
|
+
mx-auto w-full px-4 pt-16 pb-24 md:max-w-304 md:px-12 md:pt-20 md:pb-4
|
|
51
|
+
${hasRight ? 'md:grid md:grid-cols-[18rem_1fr] md:gap-x-12' : ''}
|
|
52
|
+
`}>
|
|
53
|
+
<div className='mx-auto grid w-full max-w-60 gap-16 md:row-span-2 md:max-w-72 md:gap-20'>
|
|
54
|
+
<div className='block w-full'>{logo}</div>
|
|
55
|
+
{sponsor && (
|
|
56
|
+
<div>
|
|
57
|
+
<div className='block w-full'>{sponsor.node}</div>
|
|
58
|
+
{sponsor.label && (
|
|
59
|
+
<p className='pt-8 text-center text-login-100'>{t(sponsor.label, lang)}</p>
|
|
60
|
+
)}
|
|
61
|
+
</div>
|
|
62
|
+
)}
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
{columns && columns.length > 0 && (
|
|
66
|
+
<div className={`
|
|
67
|
+
mt-12 grid w-full max-w-60 gap-8
|
|
68
|
+
sm:max-w-88 sm:justify-items-end sm:justify-self-end
|
|
69
|
+
md:col-start-2 md:row-start-1 md:mt-0 md:max-w-136 md:gap-0 md:justify-self-end
|
|
70
|
+
${columns.length > 1 ? 'sm:grid-cols-2' : ''}
|
|
71
|
+
`}>
|
|
72
|
+
{columns.map((col, i) => (
|
|
73
|
+
<div key={i} className='sm:justify-self-center md:justify-self-end'>
|
|
74
|
+
<h4 className='pb-2 text-sm font-medium tracking-widest text-login-100'>
|
|
75
|
+
{t(col.heading, lang)}
|
|
76
|
+
</h4>
|
|
77
|
+
{col.items.map((item, j) =>
|
|
78
|
+
item.href ? (
|
|
79
|
+
<a key={j} className='link--underscore-hover block' href={item.href}>
|
|
80
|
+
{t(item.label, lang)}
|
|
81
|
+
</a>
|
|
82
|
+
) : (
|
|
83
|
+
<p key={j}>{t(item.label, lang)}</p>
|
|
84
|
+
)
|
|
85
|
+
)}
|
|
86
|
+
</div>
|
|
87
|
+
))}
|
|
88
|
+
</div>
|
|
89
|
+
)}
|
|
90
|
+
|
|
91
|
+
{socialLinks && socialLinks.length > 0 && (
|
|
92
|
+
<div className='md:col-start-2 md:row-start-2 md:justify-self-end'>
|
|
93
|
+
<div className='mx-auto mt-20 mb-12 flex w-fit flex-wrap justify-center gap-6'>
|
|
94
|
+
{socialLinks.map((link, i) => (
|
|
95
|
+
<a
|
|
96
|
+
key={i}
|
|
97
|
+
className={`block size-8 text-login-100 transition-all duration-200 group
|
|
98
|
+
${link.hoverClass ?? 'hover:text-login-50'}`}
|
|
99
|
+
title={link.title}
|
|
100
|
+
href={link.href}
|
|
101
|
+
target='_blank'
|
|
102
|
+
rel='noreferrer'
|
|
103
|
+
>
|
|
104
|
+
{link.icon}
|
|
105
|
+
</a>
|
|
106
|
+
))}
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
)}
|
|
110
|
+
|
|
111
|
+
<div className='mt-16 flex flex-col items-start gap-4 md:col-span-2 md:row-start-3 md:mt-24 md:grid
|
|
112
|
+
md:grid-cols-[auto_min-content] md:items-end md:gap-8'
|
|
113
|
+
>
|
|
114
|
+
<p className='text-xs wrap-break-word text-login-100'>
|
|
115
|
+
Copyright © {year} {t(copyright, lang)}
|
|
116
|
+
</p>
|
|
117
|
+
{version && (
|
|
118
|
+
<VersionTag version={version.tag} url={version.href} />
|
|
119
|
+
)}
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
)
|
|
124
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Discord, Facebook, Linkedin, Github, Wikijs } from '../../icons/icons'
|
|
3
|
+
import type { LogfontIconProps } from '../../icons/icons'
|
|
4
|
+
import type { FooterColumn, FooterSocialLink } from './footer'
|
|
5
|
+
|
|
6
|
+
export type { FooterSocialLink as LoginSocialLinkData }
|
|
7
|
+
|
|
8
|
+
// eslint-disable-next-line @stylistic/max-len
|
|
9
|
+
const INSTAGRAM_PATH = 'M512 960Q408 960 375.0 959.5Q342 959 301 957Q260 955 230.5 949.0Q201 943 177 933Q151 923 129.0 909.0Q107 895 86 874Q65 853 51.0 831.0Q37 809 27 783Q17 759 11.0 729.5Q5 700 3 659Q1 618 0.5 585.0Q0 552 0 448Q0 344 0.5 311.0Q1 278 3 237Q5 196 11.0 166.5Q17 137 27 113Q37 87 51.0 65.0Q65 43 86 22Q107 1 129.0 -13.0Q151 -27 177 -37Q201 -47 230.5 -53.0Q260 -59 301 -61Q342 -63 375.0 -63.5Q408 -64 512 -64Q616 -64 649.0 -63.5Q682 -63 723 -61Q764 -59 793.5 -53.0Q823 -47 847 -37Q873 -27 895.0 -13.0Q917 1 938 22Q959 43 973.0 65.0Q987 87 997 113Q1007 137 1013.0 166.5Q1019 196 1021 237Q1023 278 1023.5 311.0Q1024 344 1024 448Q1024 552 1023.5 585.0Q1023 618 1021 659Q1019 700 1013.0 729.5Q1007 759 997 783Q987 809 973.0 831.0Q959 853 938 874Q917 895 895.0 909.0Q873 923 847 933Q823 943 793.5 949.0Q764 955 723 957Q682 959 649.0 959.5Q616 960 512 960ZM512 868Q614 868 646.0 867.5Q678 867 719 865Q756 863 778.0 857.5Q800 852 814 847Q832 840 845.5 831.0Q859 822 873 809Q886 795 895.0 781.5Q904 768 911 750Q916 736 921.5 714.0Q927 692 929 655Q931 614 931.5 582.5Q932 551 932 448Q932 345 931.0 313.5Q930 282 929 241Q927 204 921.5 182.0Q916 160 911 146Q903 128 894.5 114.5Q886 101 872 87Q859 74 845.0 65.0Q831 56 813 49Q800 44 777.5 38.5Q755 33 718 31Q677 29 645.0 28.5Q613 28 511 28Q408 28 376.0 29.0Q344 30 303 31Q266 33 243.5 38.5Q221 44 208 49Q190 57 176.5 65.5Q163 74 149 88Q136 101 126.5 115.0Q117 129 111 147Q105 160 100.0 182.5Q95 205 93 242Q91 282 90.5 314.0Q90 346 90 449Q90 551 90.5 583.0Q91 615 93 656Q95 693 100.0 715.5Q105 738 111 751Q117 770 126.5 783.5Q136 797 149 810Q163 824 176.5 833.0Q190 842 208 849Q221 854 243.0 859.5Q265 865 303 867Q344 868 375.5 868.5Q407 869 510 869ZM512 711Q458 711 410 690Q362 670 326.0 634.0Q290 598 270 550Q249 502 249 448Q249 394 270 346Q290 298 326.0 262.0Q362 226 410 206Q458 185 512 185Q566 185 614 206Q662 226 698.0 262.0Q734 298 754 346Q775 394 775 448Q775 502 754 550Q734 598 698.0 634.0Q662 670 614 690Q566 711 512 711ZM512 277Q441 277 391.0 327.0Q341 377 341 448Q341 519 391.0 569.0Q441 619 512 619Q583 619 633.0 569.0Q683 519 683 448Q683 377 633.0 327.0Q583 277 512 277ZM847 721Q847 696 829.0 678.0Q811 660 785 660Q760 660 742.0 678.0Q724 696 724 721Q724 747 742.0 765.0Q760 783 785 783Q811 783 829.0 765.0Q847 747 847 721Z'
|
|
10
|
+
|
|
11
|
+
function InstagramIcon({ size = 24 }: LogfontIconProps) {
|
|
12
|
+
return (
|
|
13
|
+
<span className='relative block' style={{ width: size, height: size }}>
|
|
14
|
+
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'
|
|
15
|
+
width={size} height={size} aria-hidden='true'
|
|
16
|
+
className='absolute inset-0 transition-opacity duration-200 opacity-100 group-hover:opacity-0'>
|
|
17
|
+
<g transform='translate(0 960) scale(1 -1)'>
|
|
18
|
+
<path fill='currentColor' d={INSTAGRAM_PATH} />
|
|
19
|
+
</g>
|
|
20
|
+
</svg>
|
|
21
|
+
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'
|
|
22
|
+
width={size} height={size} aria-hidden='true'
|
|
23
|
+
className='absolute inset-0 transition-opacity duration-200 opacity-0 group-hover:opacity-100'>
|
|
24
|
+
<defs>
|
|
25
|
+
<linearGradient id='ig-grad' x1='0%' y1='100%' x2='100%' y2='0%'>
|
|
26
|
+
<stop offset='0%' stopColor='#fff695' />
|
|
27
|
+
<stop offset='45%' stopColor='#ff5445' />
|
|
28
|
+
<stop offset='60%' stopColor='#ff37c0' />
|
|
29
|
+
<stop offset='90%' stopColor='#3d6dff' />
|
|
30
|
+
</linearGradient>
|
|
31
|
+
</defs>
|
|
32
|
+
<g transform='translate(0 960) scale(1 -1)'>
|
|
33
|
+
<path fill='url(#ig-grad)' d={INSTAGRAM_PATH} />
|
|
34
|
+
</g>
|
|
35
|
+
</svg>
|
|
36
|
+
</span>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const loginAddress: FooterColumn = {
|
|
41
|
+
heading: { no: 'Adresse', en: 'Address' },
|
|
42
|
+
items: [
|
|
43
|
+
{ label: 'Teknologivegen 22' },
|
|
44
|
+
{ label: { no: 'Bygg A, rom 155', en: 'Building A, room 155' } },
|
|
45
|
+
{ label: '2815 GJØVIK' },
|
|
46
|
+
],
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const loginEmail = (email: string): FooterColumn => ({
|
|
50
|
+
heading: { no: 'E-post', en: 'Email' },
|
|
51
|
+
items: [{ label: email, href: `mailto:${email}` }],
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
export const loginCopyright = {
|
|
55
|
+
no: 'Login - Linjeforeningen for IT, NO 811 940 372',
|
|
56
|
+
en: 'Login - Association for IT, NO 811 940 372',
|
|
57
|
+
} as const
|
|
58
|
+
|
|
59
|
+
export const loginSponsor = {
|
|
60
|
+
label: { no: 'Hovedsamarbeidspartner', en: 'Main partner' },
|
|
61
|
+
} as const
|
|
62
|
+
|
|
63
|
+
export const loginSocialLinks: FooterSocialLink[] = [
|
|
64
|
+
{ title: 'Discord', href: 'https://discord.gg/login-ntnu', icon: <Discord size={24} />, hoverClass: 'hover:text-[#6571fd]' },
|
|
65
|
+
{ title: 'Instagram', href: 'https://www.instagram.com/login_linjeforening/', icon: <InstagramIcon size={24} />, },
|
|
66
|
+
{ title: 'Facebook', href: 'https://facebook.com/LogNTNU', icon: <Facebook size={24} />, hoverClass: 'hover:text-[#2c87ff]' },
|
|
67
|
+
{ title: 'LinkedIn', href: 'https://www.linkedin.com/company/linjeforeningen-login/about', icon: <Linkedin size={24} />, hoverClass: 'hover:text-[#1a7bdd]' },
|
|
68
|
+
{ title: 'GitHub', href: 'https://github.com/login-linjeforeningen-for-it', icon: <Github size={24} />, hoverClass: 'hover:text-white' },
|
|
69
|
+
{ title: 'Wiki', href: 'https://outline.login.no/s/doc', icon: <Wikijs size={24} />, hoverClass: 'hover:text-login-50' },
|
|
70
|
+
]
|
package/src/components/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client'
|
|
1
2
|
// Input components
|
|
2
3
|
export { default as Input } from './inputs/input'
|
|
3
4
|
export { default as SearchInput } from './inputs/searchInput'
|
|
@@ -5,6 +6,7 @@ export { default as Textarea } from './inputs/textarea'
|
|
|
5
6
|
export { default as Checkbox } from './inputs/checkbox'
|
|
6
7
|
export { default as Select } from './inputs/select'
|
|
7
8
|
export { default as TagInput } from './inputs/tagInput'
|
|
9
|
+
export { default as MultiSelect } from './inputs/multiSelect'
|
|
8
10
|
export { default as Switch } from './inputs/switch'
|
|
9
11
|
export { default as Radio } from './inputs/radio'
|
|
10
12
|
export { default as Range } from './inputs/range'
|
|
@@ -22,9 +24,22 @@ export { default as Navbar } from './navbar/navbar'
|
|
|
22
24
|
export { default as NavItem } from './navbar/navbarItem'
|
|
23
25
|
export { default as NavDropdown } from './navbar/navbarDropdown'
|
|
24
26
|
|
|
27
|
+
// Footer
|
|
28
|
+
export { default as Footer } from './footer/footer'
|
|
29
|
+
export type { FooterColumn, FooterSocialLink, FooterProps, Lang, BilingualString } from './footer/footer'
|
|
30
|
+
export { loginAddress, loginEmail, loginCopyright, loginSponsor, loginSocialLinks } from './footer/loginContent'
|
|
31
|
+
export type { LoginSocialLinkData } from './footer/loginContent'
|
|
32
|
+
|
|
25
33
|
// Containers
|
|
26
34
|
export { default as PageContainer} from './container/page'
|
|
27
35
|
export { default as Highlight } from './container/highlight'
|
|
36
|
+
export { default as LeftBarPanel } from './container/leftBarPanel'
|
|
37
|
+
export { default as GlassCard } from './container/glassCard'
|
|
38
|
+
export { default as IconBubble } from './container/iconBubble'
|
|
39
|
+
export { default as StatCard } from './container/statCard'
|
|
40
|
+
export { Tabs, TabPanel } from './container/tabs'
|
|
41
|
+
export { default as Accordion, AccordionGroup } from './container/accordion'
|
|
42
|
+
export { default as PulseDot } from './container/pulseDot'
|
|
28
43
|
|
|
29
44
|
// Login
|
|
30
45
|
export { default as VersionTag } from './version/version'
|
|
@@ -87,11 +87,11 @@ function CheckboxItem(props: CheckboxItemProps) {
|
|
|
87
87
|
className={`
|
|
88
88
|
peer appearance-none rounded border border-login-500 bg-login-500/50
|
|
89
89
|
checked:bg-login checked:border-login
|
|
90
|
-
focus:outline-none focus:ring-
|
|
91
|
-
disabled:opacity-
|
|
92
|
-
cursor-pointer transition-all duration-
|
|
90
|
+
focus:outline-none focus:ring-1 focus:ring-login/30
|
|
91
|
+
disabled:opacity-40 disabled:cursor-not-allowed
|
|
92
|
+
cursor-pointer transition-all duration-150
|
|
93
93
|
w-5 h-5 absolute inset-0
|
|
94
|
-
${error ? 'border-red-500' : ''}
|
|
94
|
+
${error ? 'border-red-500/70' : ''}
|
|
95
95
|
`}
|
|
96
96
|
/>
|
|
97
97
|
<Check
|
|
@@ -24,7 +24,8 @@ export default function Input(props: InputProps) {
|
|
|
24
24
|
const id = useId()
|
|
25
25
|
const anchorName = `--input-${id.replace(/:/g, '')}`
|
|
26
26
|
|
|
27
|
-
const containerRef =
|
|
27
|
+
const containerRef = useRef<HTMLDivElement>(null)
|
|
28
|
+
useClickOutside(containerRef, () => setIsOpen(false))
|
|
28
29
|
|
|
29
30
|
const isDateType = ['date', 'datetime-local', 'time'].includes(type as string)
|
|
30
31
|
const isColorType = type === 'color'
|
|
@@ -38,11 +39,12 @@ export default function Input(props: InputProps) {
|
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
function pad(n: number) { return n.toString().padStart(2, '0') }
|
|
43
|
+
|
|
41
44
|
function handleDateChange(date: Date) {
|
|
42
45
|
const onChange = inputProps.onChange
|
|
43
46
|
if (!onChange) return
|
|
44
47
|
|
|
45
|
-
const pad = (n: number) => n.toString().padStart(2, '0')
|
|
46
48
|
const yyyy = date.getFullYear()
|
|
47
49
|
const MM = pad(date.getMonth() + 1)
|
|
48
50
|
const dd = pad(date.getDate())
|
|
@@ -110,10 +112,6 @@ export default function Input(props: InputProps) {
|
|
|
110
112
|
const date = getDateValue()
|
|
111
113
|
if (!date) return value as string
|
|
112
114
|
|
|
113
|
-
function pad(n: number) {
|
|
114
|
-
return n.toString().padStart(2, '0')
|
|
115
|
-
}
|
|
116
|
-
|
|
117
115
|
const yyyy = date.getFullYear()
|
|
118
116
|
const MM = pad(date.getMonth() + 1)
|
|
119
117
|
const dd = pad(date.getDate())
|
|
@@ -162,14 +160,14 @@ export default function Input(props: InputProps) {
|
|
|
162
160
|
aria-describedby={error ? `${name}-error` : undefined}
|
|
163
161
|
style={{ anchorName } as any}
|
|
164
162
|
className={`
|
|
165
|
-
w-full rounded-md bg-login-500/50 border border-login-500
|
|
166
|
-
text-login-text placeholder-login-200
|
|
167
|
-
focus:outline-none focus:border-login focus:ring-1 focus:ring-login
|
|
168
|
-
disabled:opacity-
|
|
169
|
-
h-10
|
|
170
|
-
transition-all duration-
|
|
163
|
+
w-full rounded-md bg-login-500/50 border border-login-500
|
|
164
|
+
text-login-text placeholder-login-200 text-sm
|
|
165
|
+
focus:outline-none focus:border-login/60 focus:ring-1 focus:ring-login/30
|
|
166
|
+
disabled:opacity-40 disabled:cursor-not-allowed
|
|
167
|
+
h-10 py-2 ${displayIcon ? 'pl-10 pr-3' : 'px-3'}
|
|
168
|
+
transition-all duration-150
|
|
171
169
|
input-reset
|
|
172
|
-
${error ? 'border-red-500 focus:border-red-500 focus:ring-red-500' : ''}
|
|
170
|
+
${error ? 'border-red-500/70 focus:border-red-500/70 focus:ring-red-500/30' : ''}
|
|
173
171
|
${isClickableType && !inputProps.disabled ? 'cursor-pointer' : ''}
|
|
174
172
|
`}
|
|
175
173
|
/>
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState, useRef } from 'react'
|
|
4
|
+
import { X, ChevronDown, Check } from 'lucide-react'
|
|
5
|
+
import { FieldWrapper } from './shared'
|
|
6
|
+
import useClickOutside from '../../hooks/useClickOutside'
|
|
7
|
+
|
|
8
|
+
type Option = {
|
|
9
|
+
label: string
|
|
10
|
+
value: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type MultiSelectProps = {
|
|
14
|
+
label?: string
|
|
15
|
+
name: string
|
|
16
|
+
options: Option[]
|
|
17
|
+
value?: string[]
|
|
18
|
+
onChange?: (value: string[]) => void
|
|
19
|
+
placeholder?: string
|
|
20
|
+
error?: string
|
|
21
|
+
className?: string
|
|
22
|
+
disabled?: boolean
|
|
23
|
+
required?: boolean
|
|
24
|
+
info?: string
|
|
25
|
+
description?: string
|
|
26
|
+
textSize?: 'sm' | 'md'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default function MultiSelect({
|
|
30
|
+
label,
|
|
31
|
+
name,
|
|
32
|
+
options,
|
|
33
|
+
value = [],
|
|
34
|
+
onChange,
|
|
35
|
+
placeholder = 'Select…',
|
|
36
|
+
error,
|
|
37
|
+
className,
|
|
38
|
+
disabled,
|
|
39
|
+
required,
|
|
40
|
+
info,
|
|
41
|
+
description,
|
|
42
|
+
textSize = 'sm',
|
|
43
|
+
}: MultiSelectProps) {
|
|
44
|
+
const [open, setOpen] = useState(false)
|
|
45
|
+
const containerRef = useRef<HTMLDivElement>(null)
|
|
46
|
+
useClickOutside(containerRef, () => setOpen(false))
|
|
47
|
+
|
|
48
|
+
function toggleOption(optionValue: string) {
|
|
49
|
+
if (!onChange) return
|
|
50
|
+
if (value.includes(optionValue)) {
|
|
51
|
+
onChange(value.filter((v) => v !== optionValue))
|
|
52
|
+
} else {
|
|
53
|
+
onChange([...value, optionValue])
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function removeOption(optionValue: string) {
|
|
58
|
+
if (!onChange) return
|
|
59
|
+
onChange(value.filter((v) => v !== optionValue))
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<FieldWrapper
|
|
65
|
+
label={label}
|
|
66
|
+
name={name}
|
|
67
|
+
required={required}
|
|
68
|
+
info={info}
|
|
69
|
+
description={description}
|
|
70
|
+
error={error}
|
|
71
|
+
className={className}
|
|
72
|
+
textSize={textSize}
|
|
73
|
+
>
|
|
74
|
+
<div ref={containerRef} className='relative w-full'>
|
|
75
|
+
<div
|
|
76
|
+
onClick={() => !disabled && setOpen((o) => !o)}
|
|
77
|
+
className={`
|
|
78
|
+
flex min-h-10 cursor-pointer items-center justify-between gap-2
|
|
79
|
+
rounded-md bg-login-500/50 border border-login-500 px-3 py-1.5
|
|
80
|
+
transition-all duration-150 select-none
|
|
81
|
+
${open ? 'border-login/60 ring-1 ring-login/30' : ''}
|
|
82
|
+
${error ? 'border-red-500/70' : ''}
|
|
83
|
+
${disabled ? 'opacity-40 cursor-not-allowed' : ''}
|
|
84
|
+
`}
|
|
85
|
+
>
|
|
86
|
+
<div className='flex flex-wrap gap-1.5'>
|
|
87
|
+
{value.length === 0 && (
|
|
88
|
+
<span className='text-sm text-login-200'>{placeholder}</span>
|
|
89
|
+
)}
|
|
90
|
+
{value.map((val) => {
|
|
91
|
+
const option = options.find((o) => o.value === val)
|
|
92
|
+
if (!option) return null
|
|
93
|
+
return (
|
|
94
|
+
<span
|
|
95
|
+
key={val}
|
|
96
|
+
className='flex items-center gap-1 px-2 py-0.5 bg-login-600 text-login-100 border border-login-500 rounded text-sm'
|
|
97
|
+
>
|
|
98
|
+
{option.label}
|
|
99
|
+
{!disabled && (
|
|
100
|
+
<button
|
|
101
|
+
type='button'
|
|
102
|
+
onClick={(e) => { e.stopPropagation(); removeOption(val) }}
|
|
103
|
+
className='hover:text-red-300 transition-colors'
|
|
104
|
+
>
|
|
105
|
+
<X size={13} />
|
|
106
|
+
</button>
|
|
107
|
+
)}
|
|
108
|
+
</span>
|
|
109
|
+
)
|
|
110
|
+
})}
|
|
111
|
+
</div>
|
|
112
|
+
<ChevronDown
|
|
113
|
+
size={16}
|
|
114
|
+
className={`shrink-0 text-login-200 transition-transform duration-150 ${open ? 'rotate-180' : ''}`}
|
|
115
|
+
/>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
{open && options.length > 0 && (
|
|
119
|
+
<div className='absolute z-50 mt-1 w-full max-h-60 overflow-auto rounded-md bg-login-800 border border-login-500/50 shadow-lg'>
|
|
120
|
+
{options.map((option) => {
|
|
121
|
+
const selected = value.includes(option.value)
|
|
122
|
+
return (
|
|
123
|
+
<div
|
|
124
|
+
key={option.value}
|
|
125
|
+
onClick={() => toggleOption(option.value)}
|
|
126
|
+
className={`
|
|
127
|
+
flex cursor-pointer items-center justify-between px-3 py-2 text-sm
|
|
128
|
+
hover:bg-login-700 transition-colors select-none
|
|
129
|
+
${selected ? 'text-login-50' : 'text-login-100'}
|
|
130
|
+
`}
|
|
131
|
+
>
|
|
132
|
+
<span>{option.label}</span>
|
|
133
|
+
{selected && <Check size={14} className='text-login shrink-0' />}
|
|
134
|
+
</div>
|
|
135
|
+
)
|
|
136
|
+
})}
|
|
137
|
+
</div>
|
|
138
|
+
)}
|
|
139
|
+
|
|
140
|
+
<input type='hidden' name={name} value={value.join(',')} />
|
|
141
|
+
</div>
|
|
142
|
+
</FieldWrapper>
|
|
143
|
+
)
|
|
144
|
+
}
|
|
@@ -78,11 +78,11 @@ function RadioItem(props: RadioItemProps) {
|
|
|
78
78
|
className={`
|
|
79
79
|
peer appearance-none rounded-full border border-login-500 bg-login-500/50
|
|
80
80
|
checked:bg-login checked:border-login
|
|
81
|
-
focus:outline-none focus:ring-
|
|
82
|
-
disabled:opacity-
|
|
83
|
-
cursor-pointer transition-all duration-
|
|
81
|
+
focus:outline-none focus:ring-1 focus:ring-login/30
|
|
82
|
+
disabled:opacity-40 disabled:cursor-not-allowed
|
|
83
|
+
cursor-pointer transition-all duration-150
|
|
84
84
|
w-5 h-5 absolute inset-0
|
|
85
|
-
${error ? 'border-red-500' : ''}
|
|
85
|
+
${error ? 'border-red-500/70' : ''}
|
|
86
86
|
`}
|
|
87
87
|
/>
|
|
88
88
|
<div className={`
|
|
@@ -13,13 +13,14 @@ export type RangeProps = Omit<React.ComponentProps<'input'>, 'name'> & {
|
|
|
13
13
|
|
|
14
14
|
export default function Range(props: RangeProps) {
|
|
15
15
|
const { name, label, error, className, info, description, showValue = true, textSize = 'sm', ...inputProps } = props
|
|
16
|
-
const { min = 0, max = 100, step = 1, value
|
|
16
|
+
const { min = 0, max = 100, step = 1, value, defaultValue, onChange, ...restInputProps } = inputProps
|
|
17
|
+
const displayValue = value ?? defaultValue ?? 0
|
|
17
18
|
|
|
18
19
|
return (
|
|
19
20
|
<FieldWrapper
|
|
20
21
|
label={label}
|
|
21
22
|
name={name}
|
|
22
|
-
required={
|
|
23
|
+
required={restInputProps.required}
|
|
23
24
|
info={info}
|
|
24
25
|
description={description}
|
|
25
26
|
error={error}
|
|
@@ -28,14 +29,14 @@ export default function Range(props: RangeProps) {
|
|
|
28
29
|
>
|
|
29
30
|
<div className='flex items-center gap-4'>
|
|
30
31
|
<input
|
|
31
|
-
{...
|
|
32
|
+
{...restInputProps}
|
|
32
33
|
id={name}
|
|
33
34
|
name={name}
|
|
34
35
|
type='range'
|
|
35
36
|
min={min}
|
|
36
37
|
max={max}
|
|
37
38
|
step={step}
|
|
38
|
-
value
|
|
39
|
+
{...(onChange ? { value, onChange } : { defaultValue: value ?? defaultValue ?? 0 })}
|
|
39
40
|
title={label}
|
|
40
41
|
aria-invalid={!!error}
|
|
41
42
|
aria-describedby={error ? `${name}-error` : undefined}
|
|
@@ -58,7 +59,7 @@ export default function Range(props: RangeProps) {
|
|
|
58
59
|
/>
|
|
59
60
|
{showValue && (
|
|
60
61
|
<span className='text-login-text text-sm font-medium min-w-10 text-right'>
|
|
61
|
-
{
|
|
62
|
+
{displayValue}
|
|
62
63
|
</span>
|
|
63
64
|
)}
|
|
64
65
|
</div>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { useState, useEffect } from 'react'
|
|
3
|
+
import { useState, useEffect, useRef } from 'react'
|
|
4
4
|
import Image from 'next/image'
|
|
5
|
-
import
|
|
5
|
+
import useClickOutside from '../../hooks/useClickOutside'
|
|
6
6
|
import { ChevronDown, X, Search } from 'lucide-react'
|
|
7
7
|
import { FieldWrapper } from './shared'
|
|
8
8
|
|
|
@@ -63,7 +63,8 @@ export default function Select({
|
|
|
63
63
|
setSelectedOption(options.find(opt => opt.value === value))
|
|
64
64
|
}, [value, options])
|
|
65
65
|
|
|
66
|
-
const containerRef =
|
|
66
|
+
const containerRef = useRef<HTMLDivElement>(null)
|
|
67
|
+
useClickOutside(containerRef, () => setIsOpen(false))
|
|
67
68
|
|
|
68
69
|
function handleSelect(option: Option) {
|
|
69
70
|
if (disabled) return
|
|
@@ -107,14 +108,14 @@ export default function Select({
|
|
|
107
108
|
aria-expanded={isOpen}
|
|
108
109
|
aria-labelledby={label ? undefined : name}
|
|
109
110
|
className={`
|
|
110
|
-
w-full rounded-md bg-login-500/50 border border-login-500
|
|
111
|
-
text-login-text text-left
|
|
112
|
-
focus:outline-none focus:border-login focus:ring-1 focus:ring-login
|
|
113
|
-
disabled:opacity-
|
|
114
|
-
h-10
|
|
115
|
-
transition-all duration-
|
|
111
|
+
w-full rounded-md bg-login-500/50 border border-login-500
|
|
112
|
+
text-login-text text-left text-sm
|
|
113
|
+
focus:outline-none focus:border-login/60 focus:ring-1 focus:ring-login/30
|
|
114
|
+
disabled:opacity-40 disabled:cursor-not-allowed
|
|
115
|
+
h-10 py-2 pl-3 pr-10
|
|
116
|
+
transition-all duration-150
|
|
116
117
|
flex items-center justify-between
|
|
117
|
-
${error ? 'border-red-500 focus:border-red-500 focus:ring-red-500' : ''}
|
|
118
|
+
${error ? 'border-red-500/70 focus:border-red-500/70 focus:ring-red-500/30' : ''}
|
|
118
119
|
${!selectedOption ? 'text-login-200' : ''}
|
|
119
120
|
`}
|
|
120
121
|
title={label}
|
|
@@ -159,11 +160,11 @@ export default function Select({
|
|
|
159
160
|
|
|
160
161
|
{isOpen && (
|
|
161
162
|
<div className={`
|
|
162
|
-
absolute z-50 w-full mt-1 bg-login-
|
|
163
|
-
rounded-md shadow-
|
|
163
|
+
absolute z-50 w-full mt-1 bg-login-700 border border-login-500/50
|
|
164
|
+
rounded-md shadow-xl max-h-60 overflow-hidden flex flex-col
|
|
164
165
|
`}>
|
|
165
166
|
{searchable && (
|
|
166
|
-
<div className='p-2 sticky top-0 bg-login-
|
|
167
|
+
<div className='p-2 sticky top-0 bg-login-700 border-b border-login-500/20 z-10'>
|
|
167
168
|
<div className='relative'>
|
|
168
169
|
<Search className='absolute left-2.5 top-1/2 -translate-y-1/2 w-4 h-4 text-login-200' />
|
|
169
170
|
<input
|
|
@@ -173,9 +174,9 @@ export default function Select({
|
|
|
173
174
|
placeholder='Search...'
|
|
174
175
|
autoFocus
|
|
175
176
|
className={`
|
|
176
|
-
w-full bg-login-
|
|
177
|
-
py-1.5 pl-9 pr-3 text-sm text-login-text
|
|
178
|
-
focus:outline-none focus:border-login focus:ring-1 focus:ring-login
|
|
177
|
+
w-full bg-login-600 border border-login-500/50 rounded-md
|
|
178
|
+
py-1.5 pl-9 pr-3 text-sm text-login-text
|
|
179
|
+
focus:outline-none focus:border-login/60 focus:ring-1 focus:ring-login/30
|
|
179
180
|
`}
|
|
180
181
|
/>
|
|
181
182
|
</div>
|
|
@@ -191,9 +192,9 @@ export default function Select({
|
|
|
191
192
|
onClick={() => handleSelect(option)}
|
|
192
193
|
className={`
|
|
193
194
|
w-full text-left px-3 py-2 text-sm
|
|
194
|
-
hover:bg-login-
|
|
195
|
+
hover:bg-login-600 transition-colors duration-150
|
|
195
196
|
flex items-center gap-2
|
|
196
|
-
${selectedOption?.value === option.value ? 'bg-login
|
|
197
|
+
${selectedOption?.value === option.value ? 'bg-login/15 text-login' : 'text-login-text'}
|
|
197
198
|
`}
|
|
198
199
|
>
|
|
199
200
|
{option.image && (
|
|
@@ -193,7 +193,7 @@ export default function ColorPickerPopup({ value, onChange, onClose, anchorName
|
|
|
193
193
|
|
|
194
194
|
return (
|
|
195
195
|
<div
|
|
196
|
-
className='fixed z-50 bg-login-
|
|
196
|
+
className='fixed z-50 bg-login-700 border border-login-500/50 rounded-md shadow-xl p-3 w-64 select-none anchor-popup'
|
|
197
197
|
style={{
|
|
198
198
|
positionAnchor: anchorName,
|
|
199
199
|
positionArea: 'bottom span-right',
|
|
@@ -212,19 +212,19 @@ export default function ColorPickerPopup({ value, onChange, onClose, anchorName
|
|
|
212
212
|
value={hexInput}
|
|
213
213
|
onChange={manualHexChange}
|
|
214
214
|
className={`
|
|
215
|
-
flex-1 min-w-0 bg-login-
|
|
215
|
+
flex-1 min-w-0 bg-login-600 border border-login-500/50 rounded
|
|
216
216
|
px-2 py-1 text-sm text-login-text focus:outline-none
|
|
217
|
-
focus:border-login focus:ring-1 focus:ring-login
|
|
217
|
+
focus:border-login/60 focus:ring-1 focus:ring-login/30
|
|
218
218
|
`}
|
|
219
219
|
spellCheck={false}
|
|
220
220
|
/>
|
|
221
221
|
<div
|
|
222
|
-
className='w-8 h-8 rounded border border-login-500 shrink-0'
|
|
222
|
+
className='w-8 h-8 rounded border border-login-500/50 shrink-0'
|
|
223
223
|
style={{ backgroundColor: hexInput }}
|
|
224
224
|
/>
|
|
225
225
|
</div>
|
|
226
226
|
|
|
227
|
-
<div className='grid grid-cols-8 gap-1.5 pt-3 border-t border-login-500'>
|
|
227
|
+
<div className='grid grid-cols-8 gap-1.5 pt-3 border-t border-login-500/25'>
|
|
228
228
|
{PRESET_COLORS.map(color => (
|
|
229
229
|
<button
|
|
230
230
|
key={color}
|