uibee 1.4.1 → 1.4.2

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 CHANGED
@@ -1,4 +1,38 @@
1
- # Login - Linjeforeningen for IT
2
- ## Shared Code
1
+
2
+ # Uibee
3
3
 
4
4
  This package includes shared components, functions and hooks for reuse across Login projects.
5
+
6
+ ## Installation
7
+
8
+ ```bash
9
+ # Clone the repository
10
+ git clone git@github.com:Login-Linjeforening-for-IT/uibee.git
11
+ cd uibee
12
+
13
+ # Install dependencies
14
+ npm install
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```bash
20
+ # Start the development server
21
+ npm run build
22
+ ```
23
+
24
+ ## Folder Structure
25
+ ```
26
+ .
27
+ ├── src/
28
+ │ ├── components/ # Reusable NextJS components
29
+ │ ├── hooks/ # Custom React hooks
30
+ │ ├── scripts/ # Build and utility scripts
31
+ │ ├── types/ # TypeScript type definitions
32
+ │ ├── utils/ # Utility functions
33
+ │ └── globals.css # Global styles
34
+ ├── images/ # Project images and SVGs
35
+ ├── package.json # Project metadata and scripts
36
+ ├── tailwind.config.ts # Tailwind CSS configuration
37
+ ├── tsconfig.json # TypeScript configuration
38
+ ```
package/dist/globals.css CHANGED
@@ -7,6 +7,10 @@
7
7
  "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
8
8
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
9
9
  "Courier New", monospace;
10
+ --color-red-300: oklch(80.8% 0.114 19.571);
11
+ --color-yellow-300: oklch(90.5% 0.182 98.111);
12
+ --color-green-300: oklch(87.1% 0.15 154.449);
13
+ --color-blue-300: oklch(80.9% 0.105 251.813);
10
14
  --spacing: 0.25rem;
11
15
  --container-xs: 20rem;
12
16
  --container-sm: 24rem;
@@ -185,9 +189,6 @@
185
189
  }
186
190
  }
187
191
  @layer utilities {
188
- .absolute {
189
- position: absolute;
190
- }
191
192
  .fixed {
192
193
  position: fixed;
193
194
  }
@@ -209,6 +210,12 @@
209
210
  .mb-2 {
210
211
  margin-bottom: calc(var(--spacing) * 2);
211
212
  }
213
+ .line-clamp-3 {
214
+ overflow: hidden;
215
+ display: -webkit-box;
216
+ -webkit-box-orient: vertical;
217
+ -webkit-line-clamp: 3;
218
+ }
212
219
  .flex {
213
220
  display: flex;
214
221
  }
@@ -326,6 +333,12 @@
326
333
  .py-12 {
327
334
  padding-block: calc(var(--spacing) * 12);
328
335
  }
336
+ .pr-1 {
337
+ padding-right: calc(var(--spacing) * 1);
338
+ }
339
+ .pb-1 {
340
+ padding-bottom: calc(var(--spacing) * 1);
341
+ }
329
342
  .text-center {
330
343
  text-align: center;
331
344
  }
@@ -357,6 +370,18 @@
357
370
  --tw-tracking: var(--tracking-tight);
358
371
  letter-spacing: var(--tracking-tight);
359
372
  }
373
+ .text-blue-300\/70 {
374
+ color: color-mix(in srgb, oklch(80.9% 0.105 251.813) 70%, transparent);
375
+ @supports (color: color-mix(in lab, red, red)) {
376
+ color: color-mix(in oklab, var(--color-blue-300) 70%, transparent);
377
+ }
378
+ }
379
+ .text-green-300\/70 {
380
+ color: color-mix(in srgb, oklch(87.1% 0.15 154.449) 70%, transparent);
381
+ @supports (color: color-mix(in lab, red, red)) {
382
+ color: color-mix(in oklab, var(--color-green-300) 70%, transparent);
383
+ }
384
+ }
360
385
  .text-login {
361
386
  color: var(--color-login);
362
387
  }
@@ -366,6 +391,18 @@
366
391
  .text-login-100 {
367
392
  color: var(--color-login-100);
368
393
  }
394
+ .text-red-300\/70 {
395
+ color: color-mix(in srgb, oklch(80.8% 0.114 19.571) 70%, transparent);
396
+ @supports (color: color-mix(in lab, red, red)) {
397
+ color: color-mix(in oklab, var(--color-red-300) 70%, transparent);
398
+ }
399
+ }
400
+ .text-yellow-300\/70 {
401
+ color: color-mix(in srgb, oklch(90.5% 0.182 98.111) 70%, transparent);
402
+ @supports (color: color-mix(in lab, red, red)) {
403
+ color: color-mix(in oklab, var(--color-yellow-300) 70%, transparent);
404
+ }
405
+ }
369
406
  .transition-all {
370
407
  transition-property: all;
371
408
  transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
@@ -1,3 +1,3 @@
1
- import { ToastProps } from 'uibee/components';
2
- export declare function addToast(message: string, type?: ToastProps['type']): void;
1
+ import { ToastType } from 'uibee/components';
2
+ export declare function addToast(type: ToastType, title: string, description?: string): void;
3
3
  export default function Toaster(): import("react/jsx-runtime").JSX.Element;
@@ -3,19 +3,21 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { CircleAlert, CircleCheck, CircleX, Info } from 'lucide-react';
4
4
  import { useEffect, useState, useRef } from 'react';
5
5
  const observers = [];
6
- export function addToast(message, type) {
7
- observers.forEach((observer) => observer({ message, type }));
6
+ export function addToast(type, title, description = '') {
7
+ observers.forEach((observer) => observer({ title, description, type }));
8
8
  }
9
9
  export default function Toaster() {
10
10
  const [toasts, setToasts] = useState([]);
11
11
  const timers = useRef({});
12
12
  const [isHovered, setIsHovered] = useState(false);
13
13
  const pauseTimes = useRef({});
14
+ const mainToastRef = useRef(null);
15
+ const [mainToastPosition, setMainToastPosition] = useState(null);
14
16
  useEffect(() => {
15
- const listener = ({ message, type }) => {
17
+ const listener = ({ type, title, description }) => {
16
18
  const id = Date.now();
17
19
  setToasts(prev => {
18
- const newToasts = prev.concat({ id, message, type, remaining: 3000, created: Date.now() }).slice(-3);
20
+ const newToasts = prev.concat({ id, type, title, description, remaining: 3000, created: Date.now() }).slice(-3);
19
21
  return newToasts;
20
22
  });
21
23
  };
@@ -51,25 +53,37 @@ export default function Toaster() {
51
53
  });
52
54
  }
53
55
  }, [isHovered, toasts]);
56
+ // Track main toast position for stacking
57
+ useEffect(() => {
58
+ if (mainToastRef.current && toasts.length > 0) {
59
+ const rect = mainToastRef.current.getBoundingClientRect();
60
+ setMainToastPosition({
61
+ top: rect.top,
62
+ right: window.innerWidth - rect.right
63
+ });
64
+ }
65
+ }, [toasts, isHovered]);
54
66
  const bgClasses = ['bg-login-600', 'bg-login-700', 'bg-login-800'];
55
- return (_jsx("div", { className: `fixed bottom-4 right-4 z-50 flex ${isHovered ? 'flex-col-reverse items-end gap-2' : 'flex-col items-end'}`, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: toasts.slice().reverse().map((toast, idx) => (_jsxs("div", { className: 'p-2 rounded-lg text-login-50 animate-fade-in-down transition-all w-sm flex items-center gap-2 ' +
56
- (bgClasses[idx] || bgClasses[2]), style: isHovered ? {} : {
57
- position: 'absolute',
58
- right: 0,
67
+ return (_jsx("div", { className: `fixed bottom-4 right-4 z-50 flex ${isHovered ? 'flex-col-reverse items-end gap-2' : 'flex-col items-end'}`, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: toasts.slice().reverse().map((toast, idx) => (_jsxs("div", { ref: idx === 0 ? mainToastRef : null, className: 'p-2 rounded-lg text-login-50 animate-fade-in-down transition-all w-sm flex items-center gap-2 ' +
68
+ (bgClasses[idx] || bgClasses[2]), style: isHovered ? {} : idx === 0 ? {
69
+ zIndex: 100,
70
+ } : {
71
+ position: 'fixed',
72
+ top: mainToastPosition ? `${mainToastPosition.top - idx * 8}px` : 'auto',
59
73
  zIndex: 100 - idx,
60
- bottom: `${idx * 8}px`,
61
74
  transform: `scale(${1 - idx * 0.05})`,
62
- }, children: [_jsx("span", { className: 'flex-shrink-0 w-10 h-10 flex items-center justify-center', children: _jsx(ToastIcon, { type: toast.type }) }), _jsx("span", { children: toast.message })] }, toast.id))) }));
75
+ }, children: [_jsx("span", { className: 'flex-shrink-0 w-10 h-10 flex items-center justify-center', children: _jsx(ToastIcon, { type: toast.type }) }), _jsxs("div", { className: 'pr-1 pb-1', children: [_jsx("span", { className: 'font-bold', children: toast.title }), (idx === 0 || isHovered) &&
76
+ _jsx("span", { className: 'text-sm line-clamp-3', children: toast.description })] })] }, `${toast.id}-${idx}`))) }));
63
77
  }
64
78
  function ToastIcon({ type }) {
65
79
  switch (type) {
66
80
  case 'success':
67
- return _jsx(CircleCheck, {});
81
+ return _jsx(CircleCheck, { className: 'text-green-300/70' });
68
82
  case 'warning':
69
- return _jsx(CircleAlert, {});
83
+ return _jsx(CircleAlert, { className: 'text-yellow-300/70' });
70
84
  case 'error':
71
- return _jsx(CircleX, {});
85
+ return _jsx(CircleX, { className: 'text-red-300/70' });
72
86
  case 'info':
73
- return _jsx(Info, {});
87
+ return _jsx(Info, { className: 'text-blue-300/70' });
74
88
  }
75
89
  }
@@ -0,0 +1 @@
1
+ export declare function LogoConsoleOutput(): void;
@@ -0,0 +1,44 @@
1
+ export function LogoConsoleOutput() {
2
+ const chromeStr = '%c███████╗ ███████╗\n' +
3
+ '██╔════╝ ╚════██║\n' +
4
+ '██║%c ██╗ ██████╗ ██████╗ ██╗███╗ ██╗ %c██║\n' +
5
+ '╚═╝%c ██║ ██╔═══██╗██╔════╝ ██║████╗ ██║ %c╚═╝%c\n' +
6
+ ' ██║ ██║ ██║██║ ███╗██║██╔██╗ ██║\n' +
7
+ ' ██║ ██║ ██║██║ ██║██║██║╚██╗██║\n' +
8
+ '%c██╗%c ██████╗╚██████╔╝╚██████╔╝██║██║ ╚████║ %c██╗\n' +
9
+ '██║%c ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝ %c██║\n' +
10
+ '███████╗%c %c███████║\n' +
11
+ '╚══════╝ ╚══════╝%c\n\n' +
12
+ ' - Laget av TekKom med 🍕 og ❤️';
13
+ const safariStr = '\n' +
14
+ '%c███████╗\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ███████╗\n' +
15
+ '██╔═════╝\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t╚════██║\n' +
16
+ '██║%c ██╗\t\t\t\t ██████╗\t \t ╔██████╗\t ██╗ \t ███╗ \t\t ██╗%c\t ██║\n' +
17
+ ' ╚═╝%c \t██║\t\t\t ██╔════██╗\t ██╔════╝\t ██║ \t ████╗\t ██║%c\t ╚═╝%c\n' +
18
+ ' \t\t██║\t\t\t ██║\t\t\t ██║\t ██║\t ███╗ ██║\t\t ██╔██╗ ██║\n' +
19
+ ' \t\t██║\t\t\t ██║\t\t\t ██║\t ██║\t\t ██║ ██║\t\t ██║╚██╗ ██║\n' +
20
+ '%c██╗%c ██████╗\t╚██████╝\t\t ╚██████╝\t ██║ ██║\t\t ╚███║ \t %c██╗\n' +
21
+ '██║%c\t ╚═════╝\t\t ╚════╝\t\t\t\t╚═════╝\t\t ╚═╝\t\t ╚═╝\t\t ╚═══╝\t\t %c██║\n' +
22
+ '███████╗%c\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t %c███████║\n' +
23
+ ' ╚══════╝\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t╚══════╝%c\n\n' +
24
+ '\t\t\t\t\t\t\t\t\t\t\t\t\t- Laget av TekKom med 🍕 og ❤️';
25
+ let str = '';
26
+ if (navigator.userAgent.indexOf('Chrome') != -1) {
27
+ str = chromeStr;
28
+ }
29
+ else if (navigator.userAgent.indexOf('Firefox') != -1) {
30
+ str = chromeStr;
31
+ }
32
+ else if (navigator.userAgent.indexOf('Safari') != -1) {
33
+ str = safariStr;
34
+ }
35
+ else {
36
+ return (console.log('Login - Linjeforeningen for IT'));
37
+ }
38
+ // each string is the CSS to apply for each consecutive %c
39
+ console.log(str,
40
+ // applies orange color
41
+ 'color: #fd8738',
42
+ // clears the style for every non orange part
43
+ '', 'color: #fd8738', '', 'color: #fd8738', '', 'color: #fd8738', '', 'color: #fd8738', '', 'color: #fd8738', '', 'color: #fd8738', '');
44
+ }
@@ -0,0 +1,4 @@
1
+ export declare function getCookie(name: string): string | null;
2
+ export declare function setCookie(name: string, value: string, days?: number): void;
3
+ export declare function removeCookies(...cookies: string[]): void;
4
+ export declare function removeCookie(name: string): void;
@@ -0,0 +1,28 @@
1
+ export function getCookie(name) {
2
+ const matches = document.cookie.match(new RegExp('(?:^|; )' + name.replace(/([.$?*|{}()[\]/\\+^])/g, '\\$1') + '=([^;]*)'));
3
+ return matches ? decodeURIComponent(matches[1]) : null;
4
+ }
5
+ export function setCookie(name, value, days) {
6
+ let expires = '';
7
+ if (!value) {
8
+ return;
9
+ }
10
+ if (days) {
11
+ const date = new Date();
12
+ date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
13
+ expires = `expires=${date.toUTCString()};`;
14
+ }
15
+ document.cookie =
16
+ `${name}=${encodeURIComponent(value)}; ` +
17
+ `${expires} path=/; SameSite=Lax`;
18
+ }
19
+ export function removeCookies(...cookies) {
20
+ for (const cookie of cookies) {
21
+ removeCookie(cookie);
22
+ }
23
+ }
24
+ export function removeCookie(name) {
25
+ document.cookie =
26
+ `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; ` +
27
+ 'path=/; SameSite=Lax';
28
+ }
@@ -1,2 +1,4 @@
1
1
  export { default as alertSlowQuery } from './sql/alertSlowQuery';
2
2
  export { default as discordAlert } from './discord/discordAlert';
3
+ export { getCookie, setCookie, removeCookie } from './cookies/cookies';
4
+ export { LogoConsoleOutput } from './LogoConsoleOutput/LogoConsoleOutput';
@@ -1,2 +1,4 @@
1
1
  export { default as alertSlowQuery } from './sql/alertSlowQuery';
2
2
  export { default as discordAlert } from './discord/discordAlert';
3
+ export { getCookie, setCookie, removeCookie } from './cookies/cookies';
4
+ export { LogoConsoleOutput } from './LogoConsoleOutput/LogoConsoleOutput';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uibee",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "description": "Shared components, functions and hooks for reuse across Login projects",
5
5
  "homepage": "https://github.com/Login-Linjeforening-for-IT/uibee#readme",
6
6
  "bugs": {
@@ -2,26 +2,28 @@
2
2
 
3
3
  import { CircleAlert, CircleCheck, CircleX, Info } from 'lucide-react'
4
4
  import { useEffect, useState, useRef } from 'react'
5
- import { ToastProps, ToastObserverProps } from 'uibee/components'
5
+ import { ToastProps, ToastType, ToastObserverProps } from 'uibee/components'
6
6
 
7
7
 
8
8
  const observers: ToastObserverProps[] = []
9
9
 
10
- export function addToast(message: string, type?: ToastProps['type']) {
11
- observers.forEach((observer) => observer({ message, type }))
10
+ export function addToast(type: ToastType, title: string, description: string = '') {
11
+ observers.forEach((observer) => observer({ title, description, type }))
12
12
  }
13
13
 
14
14
  export default function Toaster() {
15
- const [toasts, setToasts] = useState<Array<ToastProps & { id: number; remaining: number; created: number }>>([])
15
+ const [toasts, setToasts] = useState<Array<ToastProps & { remaining: number; created: number }>>([])
16
16
  const timers = useRef<{ [id: number]: NodeJS.Timeout }>({})
17
17
  const [isHovered, setIsHovered] = useState(false)
18
18
  const pauseTimes = useRef<{ [id: number]: number }>({})
19
+ const mainToastRef = useRef<HTMLDivElement>(null)
20
+ const [mainToastPosition, setMainToastPosition] = useState<{ top: number; right: number } | null>(null)
19
21
 
20
22
  useEffect(() => {
21
- const listener: ToastObserverProps = ({ message, type }) => {
23
+ const listener: ToastObserverProps = ({ type, title, description }) => {
22
24
  const id = Date.now()
23
25
  setToasts(prev => {
24
- const newToasts = prev.concat({ id, message, type, remaining: 3000, created: Date.now() }).slice(-3)
26
+ const newToasts = prev.concat({ id, type, title, description, remaining: 3000, created: Date.now() }).slice(-3)
25
27
  return newToasts
26
28
  })
27
29
  }
@@ -57,6 +59,17 @@ export default function Toaster() {
57
59
  }
58
60
  }, [isHovered, toasts])
59
61
 
62
+ // Track main toast position for stacking
63
+ useEffect(() => {
64
+ if (mainToastRef.current && toasts.length > 0) {
65
+ const rect = mainToastRef.current.getBoundingClientRect()
66
+ setMainToastPosition({
67
+ top: rect.top,
68
+ right: window.innerWidth - rect.right
69
+ })
70
+ }
71
+ }, [toasts, isHovered])
72
+
60
73
  const bgClasses = ['bg-login-600', 'bg-login-700', 'bg-login-800']
61
74
  return (
62
75
  <div
@@ -66,38 +79,45 @@ export default function Toaster() {
66
79
  >
67
80
  {toasts.slice().reverse().map((toast, idx) => (
68
81
  <div
69
- key={toast.id}
82
+ key={`${toast.id}-${idx}`}
83
+ ref={idx === 0 ? mainToastRef : null}
70
84
  className={
71
85
  'p-2 rounded-lg text-login-50 animate-fade-in-down transition-all w-sm flex items-center gap-2 ' +
72
86
  (bgClasses[idx] || bgClasses[2])
73
87
  }
74
- style={isHovered ? {} : {
75
- position: 'absolute',
76
- right: 0,
88
+ style={isHovered ? {} : idx === 0 ? {
89
+ zIndex: 100,
90
+ } : {
91
+ position: 'fixed',
92
+ top: mainToastPosition ? `${mainToastPosition.top - idx * 8}px` : 'auto',
77
93
  zIndex: 100 - idx,
78
- bottom: `${idx * 8}px`,
79
94
  transform: `scale(${1 - idx * 0.05})`,
80
95
  }}
81
96
  >
82
97
  <span className='flex-shrink-0 w-10 h-10 flex items-center justify-center'>
83
98
  <ToastIcon type={toast.type} />
84
99
  </span>
85
- <span>{toast.message}</span>
100
+ <div className='pr-1 pb-1'>
101
+ <span className='font-bold'>{toast.title}</span>
102
+ {(idx === 0 || isHovered) &&
103
+ <span className='text-sm line-clamp-3'>{toast.description}</span>
104
+ }
105
+ </div>
86
106
  </div>
87
107
  ))}
88
108
  </div>
89
109
  )
90
110
  }
91
111
 
92
- function ToastIcon({ type }: { type?: ToastProps['type'] }) {
112
+ function ToastIcon({ type }: { type?: ToastType }) {
93
113
  switch (type) {
94
114
  case 'success':
95
- return <CircleCheck />
115
+ return <CircleCheck className='text-green-300/70' />
96
116
  case 'warning':
97
- return <CircleAlert />
117
+ return <CircleAlert className='text-yellow-300/70' />
98
118
  case 'error':
99
- return <CircleX />
119
+ return <CircleX className='text-red-300/70' />
100
120
  case 'info':
101
- return <Info />
121
+ return <Info className='text-blue-300/70' />
102
122
  }
103
123
  }
@@ -9,15 +9,18 @@ declare module 'uibee/components' {
9
9
  handleSubmit?: (formData: FormData) => void
10
10
  }
11
11
 
12
+ export type ToastType = 'success' | 'error' | 'info' | 'warning'
12
13
  export interface ToastProps {
13
14
  id: number
14
- message: string
15
- type?: 'success' | 'error' | 'info' | 'warning'
15
+ type: ToastType
16
+ title: string
17
+ description?: string
16
18
  }
17
19
 
18
20
  export interface ToastEventProps {
19
- message: string
20
- type?: ToastProps['type']
21
+ type: ToastType
22
+ title: string
23
+ description?: string
21
24
  }
22
25
 
23
26
  export interface ToastObserverProps {
@@ -0,0 +1,61 @@
1
+ export function LogoConsoleOutput() {
2
+
3
+ const chromeStr =
4
+ '%c███████╗ ███████╗\n' +
5
+ '██╔════╝ ╚════██║\n' +
6
+ '██║%c ██╗ ██████╗ ██████╗ ██╗███╗ ██╗ %c██║\n' +
7
+ '╚═╝%c ██║ ██╔═══██╗██╔════╝ ██║████╗ ██║ %c╚═╝%c\n' +
8
+ ' ██║ ██║ ██║██║ ███╗██║██╔██╗ ██║\n' +
9
+ ' ██║ ██║ ██║██║ ██║██║██║╚██╗██║\n' +
10
+ '%c██╗%c ██████╗╚██████╔╝╚██████╔╝██║██║ ╚████║ %c██╗\n' +
11
+ '██║%c ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝ %c██║\n' +
12
+ '███████╗%c %c███████║\n' +
13
+ '╚══════╝ ╚══════╝%c\n\n' +
14
+ ' - Laget av TekKom med 🍕 og ❤️'
15
+
16
+ const safariStr =
17
+ '\n' +
18
+ '%c███████╗\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ███████╗\n' +
19
+ '██╔═════╝\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t╚════██║\n' +
20
+ '██║%c ██╗\t\t\t\t ██████╗\t \t ╔██████╗\t ██╗ \t ███╗ \t\t ██╗%c\t ██║\n' +
21
+ ' ╚═╝%c \t██║\t\t\t ██╔════██╗\t ██╔════╝\t ██║ \t ████╗\t ██║%c\t ╚═╝%c\n' +
22
+ ' \t\t██║\t\t\t ██║\t\t\t ██║\t ██║\t ███╗ ██║\t\t ██╔██╗ ██║\n' +
23
+ ' \t\t██║\t\t\t ██║\t\t\t ██║\t ██║\t\t ██║ ██║\t\t ██║╚██╗ ██║\n' +
24
+ '%c██╗%c ██████╗\t╚██████╝\t\t ╚██████╝\t ██║ ██║\t\t ╚███║ \t %c██╗\n' +
25
+ '██║%c\t ╚═════╝\t\t ╚════╝\t\t\t\t╚═════╝\t\t ╚═╝\t\t ╚═╝\t\t ╚═══╝\t\t %c██║\n' +
26
+ '███████╗%c\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t %c███████║\n' +
27
+ ' ╚══════╝\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t╚══════╝%c\n\n' +
28
+ '\t\t\t\t\t\t\t\t\t\t\t\t\t- Laget av TekKom med 🍕 og ❤️'
29
+
30
+ let str = ''
31
+
32
+ if(navigator.userAgent.indexOf('Chrome') != -1) {
33
+ str = chromeStr
34
+ } else if (navigator.userAgent.indexOf('Firefox') != -1) {
35
+ str = chromeStr
36
+ } else if (navigator.userAgent.indexOf('Safari') != -1) {
37
+ str = safariStr
38
+ } else {
39
+ return (console.log('Login - Linjeforeningen for IT'))
40
+ }
41
+
42
+ // each string is the CSS to apply for each consecutive %c
43
+ console.log(str,
44
+ // applies orange color
45
+ 'color: #fd8738',
46
+ // clears the style for every non orange part
47
+ '',
48
+ 'color: #fd8738',
49
+ '',
50
+ 'color: #fd8738',
51
+ '',
52
+ 'color: #fd8738',
53
+ '',
54
+ 'color: #fd8738',
55
+ '',
56
+ 'color: #fd8738',
57
+ '',
58
+ 'color: #fd8738',
59
+ ''
60
+ )
61
+ }
@@ -0,0 +1,38 @@
1
+ export function getCookie(name: string): string | null {
2
+ const matches = document.cookie.match(
3
+ new RegExp(
4
+ '(?:^|; )' + name.replace(/([.$?*|{}()[\]/\\+^])/g, '\\$1') + '=([^;]*)'
5
+ )
6
+ )
7
+ return matches ? decodeURIComponent(matches[1]) : null
8
+ }
9
+
10
+ export function setCookie(name: string, value: string, days?: number) {
11
+ let expires = ''
12
+
13
+ if (!value) {
14
+ return
15
+ }
16
+
17
+ if (days) {
18
+ const date = new Date()
19
+ date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000)
20
+ expires = `expires=${date.toUTCString()};`
21
+ }
22
+
23
+ document.cookie =
24
+ `${name}=${encodeURIComponent(value)}; ` +
25
+ `${expires} path=/; SameSite=Lax`
26
+ }
27
+
28
+ export function removeCookies(...cookies: string[]) {
29
+ for (const cookie of cookies) {
30
+ removeCookie(cookie)
31
+ }
32
+ }
33
+
34
+ export function removeCookie(name: string) {
35
+ document.cookie =
36
+ `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; ` +
37
+ 'path=/; SameSite=Lax'
38
+ }
@@ -1,2 +1,4 @@
1
1
  export { default as alertSlowQuery } from './sql/alertSlowQuery'
2
2
  export { default as discordAlert } from './discord/discordAlert'
3
+ export { getCookie, setCookie, removeCookie } from './cookies/cookies'
4
+ export { LogoConsoleOutput } from './LogoConsoleOutput/LogoConsoleOutput'