TAShaikhh commited on
Commit
d3b533c
·
verified ·
1 Parent(s): 60ef331

Upload 159 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +33 -0
  2. w-312356-main/.gitignore +24 -0
  3. w-312356-main/README.md +1 -0
  4. w-312356-main/bun.lockb +3 -0
  5. w-312356-main/components.json +20 -0
  6. w-312356-main/eslint.config.js +29 -0
  7. w-312356-main/index.html +72 -0
  8. w-312356-main/package-lock.json +0 -0
  9. w-312356-main/package.json +85 -0
  10. w-312356-main/postcss.config.js +6 -0
  11. w-312356-main/public/Cellmolecules Logo No bg.png +3 -0
  12. w-312356-main/public/cookie-banner/README.txt +88 -0
  13. w-312356-main/public/cookie-banner/silktide-consent-manager.css +565 -0
  14. w-312356-main/public/cookie-banner/silktide-consent-manager.js +850 -0
  15. w-312356-main/public/favicon.ico +0 -0
  16. w-312356-main/public/lovable-uploads/078a129e-0f98-4d91-af61-873687db1a04.png +3 -0
  17. w-312356-main/public/lovable-uploads/11e92b89-ed02-453a-9888-56cd91807f2d.png +3 -0
  18. w-312356-main/public/lovable-uploads/14ea3fe0-19d6-425c-b95b-4117bc41f3ca.png +0 -0
  19. w-312356-main/public/lovable-uploads/1cd5a3da-7a58-4374-abc1-d7b02b0c5fd5.png +3 -0
  20. w-312356-main/public/lovable-uploads/30473baa-85f4-4931-aad9-c722ae7a4918.png +3 -0
  21. w-312356-main/public/lovable-uploads/39605e90-8478-4fee-b1b9-cee41df66f10.png +3 -0
  22. w-312356-main/public/lovable-uploads/39671993-1bb4-4bb6-8819-3ca5c07c0042.png +0 -0
  23. w-312356-main/public/lovable-uploads/3de85ddd-15e1-4216-9697-f91abb9a47ce.png +0 -0
  24. w-312356-main/public/lovable-uploads/4187f423-ba69-4043-be76-c43098488348.png +3 -0
  25. w-312356-main/public/lovable-uploads/48e540e5-6a25-44e4-b3f7-80f3bfc2777a.png +3 -0
  26. w-312356-main/public/lovable-uploads/48ecf6e2-5a98-4a9d-af6f-ae2265cd4098.png +3 -0
  27. w-312356-main/public/lovable-uploads/4bfa0d71-3ed2-4693-90b6-35142468907f.png +3 -0
  28. w-312356-main/public/lovable-uploads/5262afdb-dd24-4d5e-be66-7c6717adbca9.png +3 -0
  29. w-312356-main/public/lovable-uploads/526dc38a-25fa-40d4-b520-425b23ae0464.png +3 -0
  30. w-312356-main/public/lovable-uploads/5463c9c5-0946-4280-a14b-17636ff69a98.png +3 -0
  31. w-312356-main/public/lovable-uploads/5ca619e6-2139-4879-9b3c-94777ab85e2a.png +0 -0
  32. w-312356-main/public/lovable-uploads/6739bd63-bf19-4abd-bb23-0b613bbf7ac8.png +3 -0
  33. w-312356-main/public/lovable-uploads/6b0637e9-4a7b-40d0-b219-c8b7f879f93e.png +3 -0
  34. w-312356-main/public/lovable-uploads/6fdd3d0d-5dca-470a-a845-bd7b07bff599.png +3 -0
  35. w-312356-main/public/lovable-uploads/700e27d7-0513-4bfa-8ac4-f7fd6087594c.png +3 -0
  36. w-312356-main/public/lovable-uploads/7293c494-769c-421b-9028-d8ccb0bdd80a.png +3 -0
  37. w-312356-main/public/lovable-uploads/761e2d9d-3a1c-458b-9848-dd1d7b42d1b9.png +3 -0
  38. w-312356-main/public/lovable-uploads/7d120ee6-3614-4b75-9c35-716d54490d67.png +0 -0
  39. w-312356-main/public/lovable-uploads/843446fe-638e-4efb-b885-ed3cd505325a.png +3 -0
  40. w-312356-main/public/lovable-uploads/927dae7e-6aaf-4b76-add2-1287a1dd9dc0.png +3 -0
  41. w-312356-main/public/lovable-uploads/93ab0638-8190-4ccf-897f-21fda7f4f5ad.png +0 -0
  42. w-312356-main/public/lovable-uploads/a1ef45a0-dde4-4b30-856f-8032dd58247e.png +3 -0
  43. w-312356-main/public/lovable-uploads/a9bb9110-964a-43b0-a5ab-7162140cd133.png +3 -0
  44. w-312356-main/public/lovable-uploads/aa5291bd-2417-4c1e-9a02-0bcc71a92507.png +0 -0
  45. w-312356-main/public/lovable-uploads/af5ee2ce-3942-48bb-a2ad-3b49b419daf9.png +3 -0
  46. w-312356-main/public/lovable-uploads/b0622048-17b4-4c75-a3f0-6c9e17de1d09.png +3 -0
  47. w-312356-main/public/lovable-uploads/b862d5ae-6abb-44da-84f0-00a222f62906.png +3 -0
  48. w-312356-main/public/lovable-uploads/c30e0487-2fa0-41d1-9a0b-699cb2855388.png +3 -0
  49. w-312356-main/public/lovable-uploads/c5f8ee24-9815-4ebe-b65d-6f3d449feb8b.png +3 -0
  50. w-312356-main/public/lovable-uploads/cbd073dd-ecad-4643-bf2b-efc3d5846994.png +0 -0
.gitattributes CHANGED
@@ -33,3 +33,36 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ w-312356-main/bun.lockb filter=lfs diff=lfs merge=lfs -text
37
+ w-312356-main/public/Cellmolecules[[:space:]]Logo[[:space:]]No[[:space:]]bg.png filter=lfs diff=lfs merge=lfs -text
38
+ w-312356-main/public/lovable-uploads/078a129e-0f98-4d91-af61-873687db1a04.png filter=lfs diff=lfs merge=lfs -text
39
+ w-312356-main/public/lovable-uploads/11e92b89-ed02-453a-9888-56cd91807f2d.png filter=lfs diff=lfs merge=lfs -text
40
+ w-312356-main/public/lovable-uploads/1cd5a3da-7a58-4374-abc1-d7b02b0c5fd5.png filter=lfs diff=lfs merge=lfs -text
41
+ w-312356-main/public/lovable-uploads/30473baa-85f4-4931-aad9-c722ae7a4918.png filter=lfs diff=lfs merge=lfs -text
42
+ w-312356-main/public/lovable-uploads/39605e90-8478-4fee-b1b9-cee41df66f10.png filter=lfs diff=lfs merge=lfs -text
43
+ w-312356-main/public/lovable-uploads/4187f423-ba69-4043-be76-c43098488348.png filter=lfs diff=lfs merge=lfs -text
44
+ w-312356-main/public/lovable-uploads/48e540e5-6a25-44e4-b3f7-80f3bfc2777a.png filter=lfs diff=lfs merge=lfs -text
45
+ w-312356-main/public/lovable-uploads/48ecf6e2-5a98-4a9d-af6f-ae2265cd4098.png filter=lfs diff=lfs merge=lfs -text
46
+ w-312356-main/public/lovable-uploads/4bfa0d71-3ed2-4693-90b6-35142468907f.png filter=lfs diff=lfs merge=lfs -text
47
+ w-312356-main/public/lovable-uploads/5262afdb-dd24-4d5e-be66-7c6717adbca9.png filter=lfs diff=lfs merge=lfs -text
48
+ w-312356-main/public/lovable-uploads/526dc38a-25fa-40d4-b520-425b23ae0464.png filter=lfs diff=lfs merge=lfs -text
49
+ w-312356-main/public/lovable-uploads/5463c9c5-0946-4280-a14b-17636ff69a98.png filter=lfs diff=lfs merge=lfs -text
50
+ w-312356-main/public/lovable-uploads/6739bd63-bf19-4abd-bb23-0b613bbf7ac8.png filter=lfs diff=lfs merge=lfs -text
51
+ w-312356-main/public/lovable-uploads/6b0637e9-4a7b-40d0-b219-c8b7f879f93e.png filter=lfs diff=lfs merge=lfs -text
52
+ w-312356-main/public/lovable-uploads/6fdd3d0d-5dca-470a-a845-bd7b07bff599.png filter=lfs diff=lfs merge=lfs -text
53
+ w-312356-main/public/lovable-uploads/700e27d7-0513-4bfa-8ac4-f7fd6087594c.png filter=lfs diff=lfs merge=lfs -text
54
+ w-312356-main/public/lovable-uploads/7293c494-769c-421b-9028-d8ccb0bdd80a.png filter=lfs diff=lfs merge=lfs -text
55
+ w-312356-main/public/lovable-uploads/761e2d9d-3a1c-458b-9848-dd1d7b42d1b9.png filter=lfs diff=lfs merge=lfs -text
56
+ w-312356-main/public/lovable-uploads/843446fe-638e-4efb-b885-ed3cd505325a.png filter=lfs diff=lfs merge=lfs -text
57
+ w-312356-main/public/lovable-uploads/927dae7e-6aaf-4b76-add2-1287a1dd9dc0.png filter=lfs diff=lfs merge=lfs -text
58
+ w-312356-main/public/lovable-uploads/a1ef45a0-dde4-4b30-856f-8032dd58247e.png filter=lfs diff=lfs merge=lfs -text
59
+ w-312356-main/public/lovable-uploads/a9bb9110-964a-43b0-a5ab-7162140cd133.png filter=lfs diff=lfs merge=lfs -text
60
+ w-312356-main/public/lovable-uploads/af5ee2ce-3942-48bb-a2ad-3b49b419daf9.png filter=lfs diff=lfs merge=lfs -text
61
+ w-312356-main/public/lovable-uploads/b0622048-17b4-4c75-a3f0-6c9e17de1d09.png filter=lfs diff=lfs merge=lfs -text
62
+ w-312356-main/public/lovable-uploads/b862d5ae-6abb-44da-84f0-00a222f62906.png filter=lfs diff=lfs merge=lfs -text
63
+ w-312356-main/public/lovable-uploads/c30e0487-2fa0-41d1-9a0b-699cb2855388.png filter=lfs diff=lfs merge=lfs -text
64
+ w-312356-main/public/lovable-uploads/c5f8ee24-9815-4ebe-b65d-6f3d449feb8b.png filter=lfs diff=lfs merge=lfs -text
65
+ w-312356-main/public/lovable-uploads/cf8966e3-de0d-445f-9fbd-ee6c48daa7ff.png filter=lfs diff=lfs merge=lfs -text
66
+ w-312356-main/public/lovable-uploads/d5ce901e-2ce0-4f2a-bce1-f0ca5d6192df.png filter=lfs diff=lfs merge=lfs -text
67
+ w-312356-main/public/lovable-uploads/e2f944f7-0d40-4c33-8ce1-30ef7cd3a4b0.png filter=lfs diff=lfs merge=lfs -text
68
+ w-312356-main/public/lovable-uploads/e502f601-c519-43a8-86f5-5fa89ae50d2f.png filter=lfs diff=lfs merge=lfs -text
w-312356-main/.gitignore ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ pnpm-debug.log*
8
+ lerna-debug.log*
9
+
10
+ node_modules
11
+ dist
12
+ dist-ssr
13
+ *.local
14
+
15
+ # Editor directories and files
16
+ .vscode/*
17
+ !.vscode/extensions.json
18
+ .idea
19
+ .DS_Store
20
+ *.suo
21
+ *.ntvs*
22
+ *.njsproj
23
+ *.sln
24
+ *.sw?
w-312356-main/README.md ADDED
@@ -0,0 +1 @@
 
 
1
+
w-312356-main/bun.lockb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a3c575fd4a99dc9d1d74a4a7a31b979d577c15f379bc5cb0dd7e823586e98c23
3
+ size 198351
w-312356-main/components.json ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "default",
4
+ "rsc": false,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "tailwind.config.ts",
8
+ "css": "src/index.css",
9
+ "baseColor": "slate",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "aliases": {
14
+ "components": "@/components",
15
+ "utils": "@/lib/utils",
16
+ "ui": "@/components/ui",
17
+ "lib": "@/lib",
18
+ "hooks": "@/hooks"
19
+ }
20
+ }
w-312356-main/eslint.config.js ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import js from "@eslint/js";
2
+ import globals from "globals";
3
+ import reactHooks from "eslint-plugin-react-hooks";
4
+ import reactRefresh from "eslint-plugin-react-refresh";
5
+ import tseslint from "typescript-eslint";
6
+
7
+ export default tseslint.config(
8
+ { ignores: ["dist"] },
9
+ {
10
+ extends: [js.configs.recommended, ...tseslint.configs.recommended],
11
+ files: ["**/*.{ts,tsx}"],
12
+ languageOptions: {
13
+ ecmaVersion: 2020,
14
+ globals: globals.browser,
15
+ },
16
+ plugins: {
17
+ "react-hooks": reactHooks,
18
+ "react-refresh": reactRefresh,
19
+ },
20
+ rules: {
21
+ ...reactHooks.configs.recommended.rules,
22
+ "react-refresh/only-export-components": [
23
+ "warn",
24
+ { allowConstantExport: true },
25
+ ],
26
+ "@typescript-eslint/no-unused-vars": "off",
27
+ },
28
+ }
29
+ );
w-312356-main/index.html ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <!DOCTYPE html>
3
+ <html lang="en">
4
+ <head>
5
+ <!-- Consent Management - Silktide -->
6
+ <script>
7
+ // Initialize the dataLayer
8
+ window.dataLayer = window.dataLayer || [];
9
+
10
+ // Create the gtag function that pushes to the dataLayer
11
+ function gtag() {
12
+ dataLayer.push(arguments);
13
+ }
14
+
15
+ // Set consent defaults
16
+ gtag('consent', 'default', {
17
+ analytics_storage: localStorage.getItem('silktideCookieChoice_analytics') === 'true' ? 'granted' : 'denied',
18
+ ad_storage: localStorage.getItem('silktideCookieChoice_marketing') === 'true' ? 'granted' : 'denied',
19
+ ad_user_data: localStorage.getItem('silktideCookieChoice_marketing') === 'true' ? 'granted' : 'denied',
20
+ ad_personalization: localStorage.getItem('silktideCookieChoice_marketing') === 'true' ? 'granted' : 'denied',
21
+ functionality_storage: localStorage.getItem('silktideCookieChoice_necessary') === 'true' ? 'granted' : 'denied',
22
+ security_storage: localStorage.getItem('silktideCookieChoice_necessary') === 'true' ? 'granted' : 'denied'
23
+ });
24
+ </script>
25
+ <!-- Google Tag Manager -->
26
+ <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
27
+ new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
28
+ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
29
+ 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
30
+ })(window,document,'script','dataLayer','GTM-TZ8DHWCH');</script>
31
+ <!-- End Google Tag Manager -->
32
+ <meta charset="UTF-8" />
33
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
34
+ <link rel="icon" href="/favicon.ico" type="image/x-icon" />
35
+ <title>Cellmolecules - Advanced Medical Diagnostics</title>
36
+ <meta name="description" content="Cellmolecules provides cutting-edge medical diagnostic solutions with advanced testing capabilities for healthcare professionals and patients." />
37
+ <meta name="author" content="Cellmolecules" />
38
+ <meta name="keywords" content="medical diagnostics, healthcare testing, laboratory services, diagnostic solutions, medical technology, clinical testing, health screening, diagnostic equipment" />
39
+ <meta property="og:title" content="Cellmolecules - Advanced Medical Diagnostics" />
40
+ <meta property="og:description" content="Leading provider of cutting-edge medical diagnostic solutions and testing services for healthcare professionals." />
41
+ <meta property="og:image" content="/placeholder.svg" />
42
+ <meta property="og:image:width" content="1200" />
43
+ <meta property="og:image:height" content="630" />
44
+ <meta property="og:url" content="" />
45
+ <meta property="og:type" content="website" />
46
+ <meta property="og:site_name" content="Cellmolecules" />
47
+ <meta property="og:locale" content="en_US" />
48
+ <meta name="twitter:card" content="summary_large_image" />
49
+ <meta name="twitter:title" content="Cellmolecules - Advanced Medical Diagnostics" />
50
+ <meta name="twitter:description" content="Leading provider of cutting-edge medical diagnostic solutions and testing services." />
51
+ <meta name="twitter:image" content="/placeholder.svg" />
52
+ <meta name="twitter:site" content="" />
53
+ <!-- LinkedIn specific -->
54
+ <meta property="og:image:secure_url" content="/placeholder.svg" />
55
+ <!-- Pinterest specific -->
56
+ <meta name="pinterest:description" content="Leading provider of cutting-edge medical diagnostic solutions and testing services." />
57
+ <meta name="pinterest:image" content="/placeholder.svg" />
58
+ <link rel="canonical" href="" />
59
+ <!-- Robots directive -->
60
+ <meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1" />
61
+ </head>
62
+
63
+ <body>
64
+ <!-- Google Tag Manager (noscript) -->
65
+ <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-TZ8DHWCH"
66
+ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
67
+ <!-- End Google Tag Manager (noscript) -->
68
+ <div id="root"></div>
69
+ <script src="https://cdn.gpteng.co/gptengineer.js" type="module"></script>
70
+ <script type="module" src="/src/main.tsx"></script>
71
+ </body>
72
+ </html>
w-312356-main/package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
w-312356-main/package.json ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "vite_react_shadcn_ts",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "build:dev": "vite build --mode development",
10
+ "lint": "eslint .",
11
+ "preview": "vite preview"
12
+ },
13
+ "dependencies": {
14
+ "@hookform/resolvers": "^4.1.3",
15
+ "@radix-ui/react-accordion": "^1.2.0",
16
+ "@radix-ui/react-alert-dialog": "^1.1.1",
17
+ "@radix-ui/react-aspect-ratio": "^1.1.0",
18
+ "@radix-ui/react-avatar": "^1.1.0",
19
+ "@radix-ui/react-checkbox": "^1.1.1",
20
+ "@radix-ui/react-collapsible": "^1.1.0",
21
+ "@radix-ui/react-context-menu": "^2.2.1",
22
+ "@radix-ui/react-dialog": "^1.1.2",
23
+ "@radix-ui/react-dropdown-menu": "^2.1.1",
24
+ "@radix-ui/react-hover-card": "^1.1.1",
25
+ "@radix-ui/react-label": "^2.1.0",
26
+ "@radix-ui/react-menubar": "^1.1.1",
27
+ "@radix-ui/react-navigation-menu": "^1.2.0",
28
+ "@radix-ui/react-popover": "^1.1.1",
29
+ "@radix-ui/react-progress": "^1.1.0",
30
+ "@radix-ui/react-radio-group": "^1.2.0",
31
+ "@radix-ui/react-scroll-area": "^1.1.0",
32
+ "@radix-ui/react-select": "^2.1.1",
33
+ "@radix-ui/react-separator": "^1.1.0",
34
+ "@radix-ui/react-slider": "^1.2.0",
35
+ "@radix-ui/react-slot": "^1.1.0",
36
+ "@radix-ui/react-switch": "^1.1.0",
37
+ "@radix-ui/react-tabs": "^1.1.0",
38
+ "@radix-ui/react-toast": "^1.2.1",
39
+ "@radix-ui/react-toggle": "^1.1.0",
40
+ "@radix-ui/react-toggle-group": "^1.1.0",
41
+ "@radix-ui/react-tooltip": "^1.1.4",
42
+ "@tanstack/react-query": "^5.56.2",
43
+ "class-variance-authority": "^0.7.1",
44
+ "clsx": "^2.1.1",
45
+ "cmdk": "^1.0.0",
46
+ "date-fns": "^3.6.0",
47
+ "emailjs-com": "^3.2.0",
48
+ "embla-carousel-react": "^8.5.2",
49
+ "framer-motion": "^12.6.2",
50
+ "input-otp": "^1.2.4",
51
+ "lucide-react": "^0.462.0",
52
+ "next-themes": "^0.3.0",
53
+ "react": "^18.3.1",
54
+ "react-day-picker": "^8.10.1",
55
+ "react-dom": "^18.3.1",
56
+ "react-helmet-async": "^2.0.5",
57
+ "react-hook-form": "^7.53.0",
58
+ "react-resizable-panels": "^2.1.3",
59
+ "react-router-dom": "^6.26.2",
60
+ "recharts": "^2.12.7",
61
+ "sonner": "^1.5.0",
62
+ "tailwind-merge": "^2.5.2",
63
+ "tailwindcss-animate": "^1.0.7",
64
+ "vaul": "^0.9.3",
65
+ "zod": "^3.23.8"
66
+ },
67
+ "devDependencies": {
68
+ "@eslint/js": "^9.9.0",
69
+ "@tailwindcss/typography": "^0.5.15",
70
+ "@types/node": "^22.5.5",
71
+ "@types/react": "^18.3.3",
72
+ "@types/react-dom": "^18.3.0",
73
+ "@vitejs/plugin-react-swc": "^3.5.0",
74
+ "autoprefixer": "^10.4.20",
75
+ "eslint": "^9.9.0",
76
+ "eslint-plugin-react-hooks": "^5.1.0-rc.0",
77
+ "eslint-plugin-react-refresh": "^0.4.9",
78
+ "globals": "^15.9.0",
79
+ "postcss": "^8.4.47",
80
+ "tailwindcss": "^3.4.11",
81
+ "typescript": "^5.5.3",
82
+ "typescript-eslint": "^8.0.1",
83
+ "vite": "^5.4.1"
84
+ }
85
+ }
w-312356-main/postcss.config.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ }
w-312356-main/public/Cellmolecules Logo No bg.png ADDED

Git LFS Details

  • SHA256: 15cbc292c8cd651e618d36a493a4b5045cfd0f9343acb1f4412b8414a9ecf713
  • Pointer size: 131 Bytes
  • Size of remote file: 172 kB
w-312356-main/public/cookie-banner/README.txt ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Consent Manager Installation Instructions
2
+
3
+ 1. Extract the contents of this zip file
4
+ 2. Place the files in your website directory
5
+ 3. Add the following code to your HTML page, inside the <head> tag:
6
+
7
+ <link rel="stylesheet" id="silktide-consent-manager-css" href="path-to-css/silktide-consent-manager.css">
8
+ <script src="path-to-js/silktide-consent-manager.js"></script>
9
+ <script>
10
+ silktideCookieBannerManager.updateCookieBannerConfig({
11
+ background: {
12
+ showBackground: true
13
+ },
14
+ cookieIcon: {
15
+ position: "bottomLeft"
16
+ },
17
+ cookieTypes: [
18
+ {
19
+ id: "necessary",
20
+ name: "Necessary",
21
+ description: "<p>These cookies are necessary for the website to function properly and cannot be switched off. They help with things like logging in and setting your privacy preferences.</p>",
22
+ required: true,
23
+ onAccept: function() {
24
+ console.log('Add logic for the required Necessary here');
25
+ }
26
+ },
27
+ {
28
+ id: "analytical",
29
+ name: "Analytical",
30
+ description: "<p>These cookies help us improve the site by tracking which pages are most popular and how visitors move around the site.</p>",
31
+ required: false,
32
+ onAccept: function() {
33
+ gtag('consent', 'update', {
34
+ analytics_storage: 'granted',
35
+ });
36
+ dataLayer.push({
37
+ 'event': 'consent_accepted_analytical',
38
+ });
39
+ },
40
+ onReject: function() {
41
+ gtag('consent', 'update', {
42
+ analytics_storage: 'denied',
43
+ });
44
+ }
45
+ },
46
+ {
47
+ id: "advertising",
48
+ name: "Advertising",
49
+ description: "<p>These cookies provide extra features and personalization to improve your experience. They may be set by us or by partners whose services we use.</p>",
50
+ required: false,
51
+ onAccept: function() {
52
+ gtag('consent', 'update', {
53
+ ad_storage: 'granted',
54
+ ad_user_data: 'granted',
55
+ ad_personalization: 'granted',
56
+ });
57
+ dataLayer.push({
58
+ 'event': 'consent_accepted_advertising',
59
+ });
60
+ },
61
+ onReject: function() {
62
+ gtag('consent', 'update', {
63
+ ad_storage: 'denied',
64
+ ad_user_data: 'denied',
65
+ ad_personalization: 'denied',
66
+ });
67
+ }
68
+ }
69
+ ],
70
+ text: {
71
+ banner: {
72
+ description: "<p>We use cookies on our site to enhance your user experience, provide personalized content, and analyze our traffic. <a href=\"https://your-website.com/cookie-policy\" target=\"_blank\">Cookie Policy.</a></p>",
73
+ acceptAllButtonText: "Accept all",
74
+ acceptAllButtonAccessibleLabel: "Accept all cookies",
75
+ rejectNonEssentialButtonText: "Reject non-essential",
76
+ rejectNonEssentialButtonAccessibleLabel: "Reject non-essential",
77
+ preferencesButtonText: "Preferences",
78
+ preferencesButtonAccessibleLabel: "Toggle preferences"
79
+ },
80
+ preferences: {
81
+ title: "Customize your cookie preferences",
82
+ description: "<p>We respect your right to privacy. You can choose not to allow some types of cookies. Your cookie preferences will apply across our website.</p>",
83
+ creditLinkText: "Get this banner for free",
84
+ creditLinkAccessibleLabel: "Get this banner for free"
85
+ }
86
+ }
87
+ });
88
+ </script>
w-312356-main/public/cookie-banner/silktide-consent-manager.css ADDED
@@ -0,0 +1,565 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ Silktide Consent Manager - https://silktide.com/consent-manager/
3
+
4
+ Styles are at risked of being overridden by styles coming from the site the consent manager is used on.
5
+ To help prevent this, global wrapper elements are prefixed with "#silktide-"
6
+ */
7
+
8
+ /* --------------------------------
9
+ Global Styles - These elements exist in the main DOM and styling is limited to positioning and animation
10
+ -------------------------------- */
11
+ /* Wrapper (Global) */
12
+ #silktide-wrapper {
13
+ --focus: 0 0 0 2px #ffffff, 0 0 0 4px #000000, 0 0 0 6px #ffffff;
14
+ --boxShadow: -5px 5px 10px 0px #00000012, 0px 0px 50px 0px #0000001a;
15
+ --fontFamily: Helvetica Neue, Segoe UI, Arial, sans-serif;
16
+ --primaryColor: #000000;
17
+ --backgroundColor: #ffffff;
18
+ --textColor: #4b494b;
19
+ --backdropBackgroundColor: #00000033;
20
+ --backdropBackgroundBlur: 0px;
21
+ --cookieIconColor: #000000;
22
+ --cookieIconBackgroundColor: #ffffff;
23
+ position: fixed;
24
+ bottom: 0;
25
+ right: 0;
26
+ width: 100%;
27
+ height: 100%;
28
+ z-index: 99999;
29
+ pointer-events: none;
30
+ border: 0px;
31
+ display: flex;
32
+ justify-content: center;
33
+ align-items: center
34
+ }
35
+
36
+ /* Backdrop (Global) */
37
+ #silktide-backdrop-global {
38
+ position: fixed;
39
+ top: 0;
40
+ left: 0;
41
+ width: 100%;
42
+ height: 100%;
43
+ pointer-events: auto;
44
+ border: 0px;
45
+ display: none;
46
+ }
47
+
48
+ /* --------------------------------
49
+ Links
50
+ -------------------------------- */
51
+ #silktide-wrapper a {
52
+ all: unset;
53
+ display: inline-block;
54
+ color: var(--primaryColor);
55
+ text-decoration: underline;
56
+ }
57
+
58
+ #silktide-wrapper a:hover {
59
+ cursor: pointer;
60
+ color: var(--textColor);
61
+ }
62
+
63
+ /* --------------------------------
64
+ Focus Styles
65
+ -------------------------------- */
66
+ #silktide-wrapper a:focus,
67
+ #silktide-wrapper #silktide-banner button:focus,
68
+ #silktide-wrapper #silktide-modal button:focus,
69
+ #silktide-wrapper #silktide-cookie-icon:focus {
70
+ outline: none;
71
+ box-shadow: var(--focus);
72
+ border-radius: 5px;
73
+ }
74
+
75
+ #silktide-wrapper #silktide-cookie-icon:focus {
76
+ border-radius: 50%;
77
+ }
78
+
79
+ /* --------------------------------
80
+ General Styles
81
+ -------------------------------- */
82
+
83
+ #silktide-wrapper .st-button {
84
+ color: var(--backgroundColor);
85
+ background-color: var(--primaryColor);
86
+ border: 2px solid var(--primaryColor);
87
+ padding: 10px 20px;
88
+ text-decoration: none;
89
+ text-align: center;
90
+ display: inline-block;
91
+ font-size: 16px;
92
+ line-height: 24px;
93
+ cursor: pointer;
94
+ border-radius: 5px;
95
+ }
96
+
97
+ #silktide-wrapper .st-button--primary {
98
+ }
99
+
100
+ #silktide-wrapper .st-button--primary:hover {
101
+ background-color: var(--backgroundColor);
102
+ color: var(--primaryColor);
103
+ }
104
+
105
+ #silktide-wrapper .st-button--secondary {
106
+ background-color: var(--backgroundColor);
107
+ color: var(--primaryColor);
108
+ }
109
+
110
+ #silktide-wrapper .st-button--secondary:hover {
111
+ background-color: var(--primaryColor);
112
+ color: var(--backgroundColor);
113
+ }
114
+
115
+ /* --------------------------------
116
+ Banner
117
+ -------------------------------- */
118
+ #silktide-banner {
119
+ font-family: var(--fontFamily);
120
+ color: var(--textColor);
121
+ background-color: var(--backgroundColor);
122
+ box-sizing: border-box;
123
+ padding: 32px;
124
+ border-radius: 5px;
125
+ pointer-events: auto;
126
+ border: 0px;
127
+ position: fixed;
128
+ bottom: 16px;
129
+ right: 16px;
130
+ width: 600px;
131
+ max-width: calc(100% - 32px);
132
+ transform: translate(0, -20px);
133
+ opacity: 0;
134
+ animation: silktide-slideInDown 350ms ease-out forwards;
135
+ animation-delay: 0.3s;
136
+ box-shadow: -5px 5px 10px 0px #00000012, 0px 0px 50px 0px #0000001a;
137
+ }
138
+
139
+ #silktide-banner:focus {
140
+ border-radius: 50%;
141
+ }
142
+
143
+ #silktide-banner.center {
144
+ top: 50%;
145
+ left: 50%;
146
+ bottom: auto;
147
+ right: auto;
148
+ position: fixed;
149
+ transform: translate(-50%, calc(-50% - 20px));
150
+ animation: silktide-slideInDown-center 350ms ease-out forwards;
151
+ }
152
+
153
+ #silktide-banner.bottomLeft {
154
+ bottom: 16px;
155
+ left: 16px;
156
+ position: fixed;
157
+ }
158
+
159
+ #silktide-banner.bottomCenter {
160
+ bottom: 16px;
161
+ left: 50%;
162
+ position: fixed;
163
+ transform: translate(-50%, -20px);
164
+ animation: silktide-slideInDown-bottomCenter 350ms ease-out forwards;
165
+ }
166
+
167
+ #silktide-banner .preferences {
168
+ display: flex;
169
+ gap: 5px;
170
+ border: none;
171
+ padding: 0px;
172
+ background-color: transparent;
173
+ color: var(--primaryColor);
174
+ cursor: pointer;
175
+ font-size: 16px;
176
+ }
177
+
178
+ #silktide-banner .preferences span {
179
+ display: block;
180
+ white-space: nowrap;
181
+ text-decoration: underline;
182
+ }
183
+
184
+ #silktide-banner .preferences span:hover {
185
+ color: var(--textColor);
186
+ }
187
+
188
+ #silktide-banner .preferences:after {
189
+ display: block;
190
+ content: '>';
191
+ text-decoration: none;
192
+ }
193
+
194
+ #silktide-banner p {
195
+ font-size: 16px;
196
+ line-height: 24px;
197
+ margin: 0px 0px 15px;
198
+ }
199
+
200
+ #silktide-banner a {
201
+ display: inline-block;
202
+ color: var(--primaryColor);
203
+ text-decoration: underline;
204
+ background-color: var(--backgroundColor);
205
+ }
206
+
207
+ #silktide-banner a:hover {
208
+ color: var(--textColor);
209
+ }
210
+
211
+ #silktide-banner a.silktide-logo {
212
+ display: block;
213
+ fill: var(--primaryColor); /* passed down to svg > path */
214
+ margin-left: auto;
215
+ width: 24px;
216
+ height: 24px;
217
+ }
218
+
219
+
220
+ #silktide-banner .actions {
221
+ display: flex;
222
+ gap: 16px;
223
+ flex-direction: column;
224
+ margin-top: 24px;
225
+ }
226
+
227
+ @media (min-width: 600px) {
228
+ #silktide-banner .actions {
229
+ flex-direction: row;
230
+ align-items: center;
231
+ }
232
+ }
233
+
234
+ #silktide-banner .actions-row {
235
+ display: flex;
236
+ gap: 16px;
237
+ flex-direction: row;
238
+ align-items: center;
239
+ justify-content: space-between;
240
+ flex-grow: 1;
241
+ }
242
+
243
+ /* --------------------------------
244
+ Modal
245
+ -------------------------------- */
246
+ #silktide-modal {
247
+ display: none;
248
+ pointer-events: auto;
249
+ width: 800px;
250
+ max-width: 100%;
251
+ max-height: 100%;
252
+ border: 0px;
253
+ transform: translate(0px, -20px);
254
+ opacity: 0;
255
+ animation: silktide-slideInUp-center 350ms ease-out forwards;
256
+ box-shadow: -5px 5px 10px 0px #00000012, 0px 0px 50px 0px #0000001a;
257
+ font-family: var(--fontFamily);
258
+ color: var(--textColor);
259
+ flex-direction: column;
260
+ padding: 30px;
261
+ background-color: var(--backgroundColor);
262
+ border-radius: 5px;
263
+ box-sizing: border-box;
264
+ }
265
+
266
+ /* --------------------------------
267
+ Modal - Header
268
+ -------------------------------- */
269
+ #silktide-modal header {
270
+ display: flex;
271
+ justify-content: space-between;
272
+ align-items: center;
273
+ margin-bottom: 20px;
274
+ gap: 16px;
275
+ }
276
+
277
+ #silktide-modal h1 {
278
+ font-family: var(--fontFamily);
279
+ color: var(--textColor);
280
+ font-size: 24px;
281
+ font-weight: 500;
282
+ margin: 0px;
283
+ }
284
+
285
+ #silktide-modal .modal-close {
286
+ display: inline-flex;
287
+ border: none;
288
+ padding: 10px;
289
+ border: 0px;
290
+ cursor: pointer;
291
+ background: var(--backgroundColor);
292
+ color: var(--primaryColor);
293
+ }
294
+
295
+ #silktide-modal .modal-close svg {
296
+ fill: var(--primaryColor);
297
+ }
298
+
299
+ /* --------------------------------
300
+ Modal - Content
301
+ -------------------------------- */
302
+
303
+ #silktide-modal section {
304
+ flex: 1;
305
+ overflow-y: auto;
306
+ margin-top: 32px;
307
+ padding-right: 7px; /* Prevents scrollbar from appearing over the switches */
308
+ }
309
+
310
+ #silktide-modal section::-webkit-scrollbar {
311
+ display: block; /* Force scrollbars to show */
312
+ width: 5px; /* Width of the scrollbar */
313
+ }
314
+
315
+ #silktide-modal section::-webkit-scrollbar-thumb {
316
+ background-color: var(--textColor); /* Color of the scrollbar thumb */
317
+ border-radius: 10px; /* Rounded corners for the thumb */
318
+ }
319
+
320
+ #silktide-modal p {
321
+ font-size: 16px;
322
+ line-height: 24px;
323
+ color: var(--textColor);
324
+ margin: 0px 0px 15px;
325
+ }
326
+
327
+ #silktide-modal p:last-of-type {
328
+ margin: 0px;
329
+ }
330
+
331
+ #silktide-modal fieldset {
332
+ padding: 0px;
333
+ border: none;
334
+ margin: 0px 0px 32px;
335
+ }
336
+
337
+ #silktide-modal fieldset:last-of-type {
338
+ margin: 0px;
339
+ }
340
+
341
+ #silktide-modal legend {
342
+ padding: 0px;
343
+ margin: 0px 0px 10px;
344
+ font-weight: 700;
345
+ color: var(--textColor);
346
+ font-size: 16px;
347
+ }
348
+
349
+ #silktide-modal .cookie-type-content {
350
+ display: flex;
351
+ justify-content: space-between;
352
+ align-items: flex-start;
353
+ gap: 24px;
354
+ }
355
+
356
+ /* --------------------------------
357
+ Modal - Switches
358
+ -------------------------------- */
359
+ #silktide-modal .switch {
360
+ flex-shrink: 0;
361
+ position: relative;
362
+ display: inline-block;
363
+ height: 34px;
364
+ width: 74px;
365
+ cursor: pointer;
366
+ }
367
+
368
+ #silktide-modal .switch:focus-within {
369
+ outline: none;
370
+ box-shadow: var(--focus);
371
+ border-radius: 25px;
372
+ }
373
+
374
+ #silktide-modal .switch input {
375
+ opacity: 0;
376
+ position: absolute;
377
+ }
378
+
379
+ /* Unchecked Switch Styles */
380
+ #silktide-modal .switch__pill {
381
+ position: relative;
382
+ display: block;
383
+ height: 34px;
384
+ width: 74px;
385
+ background: var(--textColor);
386
+ border-radius: 25px;
387
+ }
388
+
389
+ #silktide-modal .switch__dot {
390
+ position: absolute;
391
+ top: 2px;
392
+ left: 2px;
393
+ display: block;
394
+ height: 30px;
395
+ width: 30px;
396
+ background: var(--backgroundColor);
397
+ border-radius: 50%;
398
+ transition: left 150ms ease-out;
399
+ }
400
+
401
+ #silktide-modal .switch__off,
402
+ #silktide-modal .switch__on {
403
+ text-transform: uppercase;
404
+ font-size: 15px;
405
+ font-weight: 500;
406
+ color: var(--backgroundColor);
407
+ position: absolute;
408
+ top: 7px;
409
+ right: 8px;
410
+ transition: right 150ms ease-out, opacity 150ms ease-out;
411
+ }
412
+
413
+ #silktide-modal .switch__off {
414
+ opacity: 1;
415
+ }
416
+
417
+ #silktide-modal .switch__on {
418
+ opacity: 0;
419
+ }
420
+
421
+ /* Checked Switch Styles */
422
+ #silktide-modal .switch input:checked + .switch__pill {
423
+ background: var(--primaryColor);
424
+ }
425
+
426
+ #silktide-modal .switch input:checked ~ .switch__dot {
427
+ left: calc(100% - 32px);
428
+ }
429
+
430
+ #silktide-modal .switch input:checked ~ .switch__off {
431
+ right: calc(100% - 32px);
432
+ opacity: 0;
433
+ }
434
+
435
+ #silktide-modal .switch input:checked ~ .switch__on {
436
+ right: calc(100% - 34px);
437
+ opacity: 1;
438
+ }
439
+
440
+ /* Disabled Switch Styles */
441
+ #silktide-modal .switch input:disabled + .switch__pill {
442
+ opacity: 0.65;
443
+ cursor: not-allowed;
444
+ }
445
+
446
+ /* --------------------------------
447
+ Modal - Footer
448
+ -------------------------------- */
449
+ #silktide-modal footer {
450
+ display: flex;
451
+ flex-direction: column;
452
+ gap: 16px;
453
+ margin-top: 24px;
454
+ }
455
+
456
+ @media (min-width: 600px) {
457
+ #silktide-modal footer {
458
+ flex-direction: row;
459
+ align-items: center;
460
+ }
461
+ }
462
+
463
+ #silktide-modal footer a {
464
+ margin-left: auto;
465
+ }
466
+
467
+ /* Cookie Icon */
468
+ #silktide-cookie-icon {
469
+ display: none;
470
+ position: fixed;
471
+ bottom: 10px;
472
+ left: 10px;
473
+ justify-content: center;
474
+ align-items: center;
475
+ width: 60px;
476
+ height: 60px;
477
+ border-radius: 50%;
478
+ padding: 0px;
479
+ border: none;
480
+ background-color: var(--cookieIconColor);
481
+ cursor: pointer;
482
+ box-shadow: 0px 0px 6px 0px #0000001a;
483
+ pointer-events: auto;
484
+ animation: silktide-fadeIn 0.3s ease-in-out forwards;
485
+ }
486
+
487
+ #silktide-cookie-icon.bottomRight {
488
+ left: auto;
489
+ right: 10px;
490
+ }
491
+
492
+ #silktide-cookie-icon svg {
493
+ fill: var(--cookieIconBackgroundColor);
494
+ }
495
+
496
+ /* --------------------------------
497
+ Backdrop
498
+ -------------------------------- */
499
+ #silktide-backdrop {
500
+ display: none;
501
+ position: absolute;
502
+ top: 0;
503
+ left: 0;
504
+ width: 100%;
505
+ height: 100%;
506
+ background-color: var(--backdropBackgroundColor);
507
+ backdrop-filter: blur(var(--backdropBackgroundBlur));
508
+ pointer-events: all;
509
+ }
510
+
511
+ /* --------------------------------
512
+ Animations
513
+ -------------------------------- */
514
+ @keyframes silktide-fadeIn {
515
+ from {
516
+ opacity: 0;
517
+ }
518
+ to {
519
+ opacity: 1;
520
+ }
521
+ }
522
+
523
+ @keyframes silktide-slideInDown {
524
+ from {
525
+ opacity: 0;
526
+ transform: translateY(-20px);
527
+ }
528
+ to {
529
+ opacity: 1;
530
+ transform: translateY(0);
531
+ }
532
+ }
533
+
534
+ @keyframes silktide-slideInDown-center {
535
+ from {
536
+ opacity: 0;
537
+ transform: translate(-50%, calc(-50% - 20px));
538
+ }
539
+ to {
540
+ opacity: 1;
541
+ transform: translate(-50%, -50%);
542
+ }
543
+ }
544
+
545
+ @keyframes silktide-slideInDown-bottomCenter {
546
+ from {
547
+ opacity: 0;
548
+ transform: translate(-50%, -20px);
549
+ }
550
+ to {
551
+ opacity: 1;
552
+ transform: translate(-50%, 0);
553
+ }
554
+ }
555
+
556
+ @keyframes silktide-slideInUp-center {
557
+ from {
558
+ opacity: 0;
559
+ transform: translate(0px, 20px);
560
+ }
561
+ to {
562
+ opacity: 1;
563
+ transform: translate(0px, 0px);
564
+ }
565
+ }
w-312356-main/public/cookie-banner/silktide-consent-manager.js ADDED
@@ -0,0 +1,850 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Silktide Consent Manager - https://silktide.com/consent-manager/
2
+
3
+ class SilktideCookieBanner {
4
+ constructor(config) {
5
+ this.config = config; // Save config to the instance
6
+
7
+ this.wrapper = null;
8
+ this.banner = null;
9
+ this.modal = null;
10
+ this.cookieIcon = null;
11
+ this.backdrop = null;
12
+
13
+ this.createWrapper();
14
+
15
+ if (this.shouldShowBackdrop()) {
16
+ this.createBackdrop();
17
+ }
18
+
19
+ this.createCookieIcon();
20
+ this.createModal();
21
+
22
+ if (this.shouldShowBanner()) {
23
+ this.createBanner();
24
+ this.showBackdrop();
25
+ } else {
26
+ this.showCookieIcon();
27
+ }
28
+
29
+ this.setupEventListeners();
30
+
31
+ if (this.hasSetInitialCookieChoices()) {
32
+ this.loadRequiredCookies();
33
+ this.runAcceptedCookieCallbacks();
34
+ }
35
+ }
36
+
37
+ destroyCookieBanner() {
38
+ // Remove all cookie banner elements from the DOM
39
+ if (this.wrapper && this.wrapper.parentNode) {
40
+ this.wrapper.parentNode.removeChild(this.wrapper);
41
+ }
42
+
43
+ // Restore scrolling
44
+ this.allowBodyScroll();
45
+
46
+ // Clear all references
47
+ this.wrapper = null;
48
+ this.banner = null;
49
+ this.modal = null;
50
+ this.cookieIcon = null;
51
+ this.backdrop = null;
52
+ }
53
+
54
+ // ----------------------------------------------------------------
55
+ // Wrapper
56
+ // ----------------------------------------------------------------
57
+ createWrapper() {
58
+ this.wrapper = document.createElement('div');
59
+ this.wrapper.id = 'silktide-wrapper';
60
+ document.body.insertBefore(this.wrapper, document.body.firstChild);
61
+ }
62
+
63
+ // ----------------------------------------------------------------
64
+ // Wrapper Child Generator
65
+ // ----------------------------------------------------------------
66
+ createWrapperChild(htmlContent, id) {
67
+ // Create child element
68
+ const child = document.createElement('div');
69
+ child.id = id;
70
+ child.innerHTML = htmlContent;
71
+
72
+ // Ensure wrapper exists
73
+ if (!this.wrapper || !document.body.contains(this.wrapper)) {
74
+ this.createWrapper();
75
+ }
76
+
77
+ // Append child to wrapper
78
+ this.wrapper.appendChild(child);
79
+ return child;
80
+ }
81
+
82
+ // ----------------------------------------------------------------
83
+ // Backdrop
84
+ // ----------------------------------------------------------------
85
+ createBackdrop() {
86
+ this.backdrop = this.createWrapperChild(null, 'silktide-backdrop');
87
+ }
88
+
89
+ showBackdrop() {
90
+ if (this.backdrop) {
91
+ this.backdrop.style.display = 'block';
92
+ }
93
+ // Trigger optional onBackdropOpen callback
94
+ if (typeof this.config.onBackdropOpen === 'function') {
95
+ this.config.onBackdropOpen();
96
+ }
97
+ }
98
+
99
+ hideBackdrop() {
100
+ if (this.backdrop) {
101
+ this.backdrop.style.display = 'none';
102
+ }
103
+
104
+ // Trigger optional onBackdropClose callback
105
+ if (typeof this.config.onBackdropClose === 'function') {
106
+ this.config.onBackdropClose();
107
+ }
108
+ }
109
+
110
+ shouldShowBackdrop() {
111
+ return this.config?.background?.showBackground || false;
112
+ }
113
+
114
+ // update the checkboxes in the modal with the values from localStorage
115
+ updateCheckboxState(saveToStorage = false) {
116
+ const preferencesSection = this.modal.querySelector('#cookie-preferences');
117
+ const checkboxes = preferencesSection.querySelectorAll('input[type="checkbox"]');
118
+
119
+ checkboxes.forEach((checkbox) => {
120
+ const [, cookieId] = checkbox.id.split('cookies-');
121
+ const cookieType = this.config.cookieTypes.find(type => type.id === cookieId);
122
+
123
+ if (!cookieType) return;
124
+
125
+ if (saveToStorage) {
126
+ // Save the current state to localStorage and run callbacks
127
+ const currentState = checkbox.checked;
128
+
129
+ if (cookieType.required) {
130
+ localStorage.setItem(
131
+ `silktideCookieChoice_${cookieId}${this.getBannerSuffix()}`,
132
+ 'true'
133
+ );
134
+ } else {
135
+ localStorage.setItem(
136
+ `silktideCookieChoice_${cookieId}${this.getBannerSuffix()}`,
137
+ currentState.toString()
138
+ );
139
+
140
+ // Run appropriate callback
141
+ if (currentState && typeof cookieType.onAccept === 'function') {
142
+ cookieType.onAccept();
143
+ } else if (!currentState && typeof cookieType.onReject === 'function') {
144
+ cookieType.onReject();
145
+ }
146
+ }
147
+ } else {
148
+ // When reading values (opening modal)
149
+ if (cookieType.required) {
150
+ checkbox.checked = true;
151
+ checkbox.disabled = true;
152
+ } else {
153
+ const storedValue = localStorage.getItem(
154
+ `silktideCookieChoice_${cookieId}${this.getBannerSuffix()}`
155
+ );
156
+
157
+ if (storedValue !== null) {
158
+ checkbox.checked = storedValue === 'true';
159
+ } else {
160
+ checkbox.checked = !!cookieType.defaultValue;
161
+ }
162
+ }
163
+ }
164
+ });
165
+ }
166
+
167
+ setInitialCookieChoiceMade() {
168
+ window.localStorage.setItem(`silktideCookieBanner_InitialChoice${this.getBannerSuffix()}`, 1);
169
+ }
170
+
171
+ // ----------------------------------------------------------------
172
+ // Consent Handling
173
+ // ----------------------------------------------------------------
174
+ handleCookieChoice(accepted) {
175
+ // We set that an initial choice was made regardless of what it was so we don't show the banner again
176
+ this.setInitialCookieChoiceMade();
177
+
178
+ this.removeBanner();
179
+ this.hideBackdrop();
180
+ this.toggleModal(false);
181
+ this.showCookieIcon();
182
+
183
+ this.config.cookieTypes.forEach((type) => {
184
+ // Set localStorage and run accept/reject callbacks
185
+ if (type.required == true) {
186
+ localStorage.setItem(`silktideCookieChoice_${type.id}${this.getBannerSuffix()}`, 'true');
187
+ if (typeof type.onAccept === 'function') { type.onAccept() }
188
+ } else {
189
+ localStorage.setItem(
190
+ `silktideCookieChoice_${type.id}${this.getBannerSuffix()}`,
191
+ accepted.toString(),
192
+ );
193
+
194
+ if (accepted) {
195
+ if (typeof type.onAccept === 'function') { type.onAccept(); }
196
+ } else {
197
+ if (typeof type.onReject === 'function') { type.onReject(); }
198
+ }
199
+ }
200
+ });
201
+
202
+ // Trigger optional onAcceptAll/onRejectAll callbacks
203
+ if (accepted && typeof this.config.onAcceptAll === 'function') {
204
+ if (typeof this.config.onAcceptAll === 'function') { this.config.onAcceptAll(); }
205
+ } else if (typeof this.config.onRejectAll === 'function') {
206
+ if (typeof this.config.onRejectAll === 'function') { this.config.onRejectAll(); }
207
+ }
208
+
209
+ // finally update the checkboxes in the modal with the values from localStorage
210
+ this.updateCheckboxState();
211
+ }
212
+
213
+ getAcceptedCookies() {
214
+ return (this.config.cookieTypes || []).reduce((acc, cookieType) => {
215
+ acc[cookieType.id] =
216
+ localStorage.getItem(`silktideCookieChoice_${cookieType.id}${this.getBannerSuffix()}`) ===
217
+ 'true';
218
+ return acc;
219
+ }, {});
220
+ }
221
+
222
+ runAcceptedCookieCallbacks() {
223
+ if (!this.config.cookieTypes) return;
224
+
225
+ const acceptedCookies = this.getAcceptedCookies();
226
+ this.config.cookieTypes.forEach((type) => {
227
+ if (type.required) return; // we run required cookies separately in loadRequiredCookies
228
+ if (acceptedCookies[type.id] && typeof type.onAccept === 'function') {
229
+ if (typeof type.onAccept === 'function') { type.onAccept(); }
230
+ }
231
+ });
232
+ }
233
+
234
+ runRejectedCookieCallbacks() {
235
+ if (!this.config.cookieTypes) return;
236
+
237
+ const rejectedCookies = this.getRejectedCookies();
238
+ this.config.cookieTypes.forEach((type) => {
239
+ if (rejectedCookies[type.id] && typeof type.onReject === 'function') {
240
+ if (typeof type.onReject === 'function') { type.onReject(); }
241
+ }
242
+ });
243
+ }
244
+
245
+ /**
246
+ * Run through all of the cookie callbacks based on the current localStorage values
247
+ */
248
+ runStoredCookiePreferenceCallbacks() {
249
+ this.config.cookieTypes.forEach((type) => {
250
+ const accepted =
251
+ localStorage.getItem(`silktideCookieChoice_${type.id}${this.getBannerSuffix()}`) === 'true';
252
+ // Set localStorage and run accept/reject callbacks
253
+ if (accepted) {
254
+ if (typeof type.onAccept === 'function') { type.onAccept(); }
255
+ } else {
256
+ if (typeof type.onReject === 'function') { type.onReject(); }
257
+ }
258
+ });
259
+ }
260
+
261
+ loadRequiredCookies() {
262
+ if (!this.config.cookieTypes) return;
263
+ this.config.cookieTypes.forEach((cookie) => {
264
+ if (cookie.required && typeof cookie.onAccept === 'function') {
265
+ if (typeof cookie.onAccept === 'function') { cookie.onAccept(); }
266
+ }
267
+ });
268
+ }
269
+
270
+ // ----------------------------------------------------------------
271
+ // Banner
272
+ // ----------------------------------------------------------------
273
+ getBannerContent() {
274
+ const bannerDescription =
275
+ this.config.text?.banner?.description ||
276
+ `We use cookies on our site to enhance your user experience, provide personalized content, and analyze our traffic.`;
277
+
278
+ // Accept button
279
+ const acceptAllButtonText = this.config.text?.banner?.acceptAllButtonText || 'Accept all';
280
+ const acceptAllButtonLabel = this.config.text?.banner?.acceptAllButtonAccessibleLabel;
281
+ const acceptAllButton = `<button class="accept-all st-button st-button--primary"${
282
+ acceptAllButtonLabel && acceptAllButtonLabel !== acceptAllButtonText
283
+ ? ` aria-label="${acceptAllButtonLabel}"`
284
+ : ''
285
+ }>${acceptAllButtonText}</button>`;
286
+
287
+ // Reject button
288
+ const rejectNonEssentialButtonText = this.config.text?.banner?.rejectNonEssentialButtonText || 'Reject non-essential';
289
+ const rejectNonEssentialButtonLabel = this.config.text?.banner?.rejectNonEssentialButtonAccessibleLabel;
290
+ const rejectNonEssentialButton = `<button class="reject-all st-button st-button--primary"${
291
+ rejectNonEssentialButtonLabel && rejectNonEssentialButtonLabel !== rejectNonEssentialButtonText
292
+ ? ` aria-label="${rejectNonEssentialButtonLabel}"`
293
+ : ''
294
+ }>${rejectNonEssentialButtonText}</button>`;
295
+
296
+ // Preferences button
297
+ const preferencesButtonText = this.config.text?.banner?.preferencesButtonText || 'Preferences';
298
+ const preferencesButtonLabel = this.config.text?.banner?.preferencesButtonAccessibleLabel;
299
+ const preferencesButton = `<button class="preferences"${
300
+ preferencesButtonLabel && preferencesButtonLabel !== preferencesButtonText
301
+ ? ` aria-label="${preferencesButtonLabel}"`
302
+ : ''
303
+ }><span>${preferencesButtonText}</span></button>`;
304
+
305
+
306
+ // Silktide logo link
307
+ const silktideLogo = `
308
+ <a class="silktide-logo" href="https://silktide.com/consent-manager" aria-label="Visit the Silktide Consent Manager page">
309
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="25" viewBox="0 0 24 25" fill="inherit">
310
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M14.1096 16.7745C13.8895 17.2055 13.3537 17.3805 12.9129 17.1653L8.28443 14.9055L2.73192 17.7651L11.1025 21.9814C11.909 22.3876 12.8725 22.3591 13.6524 21.9058L20.4345 17.9645C21.2845 17.4704 21.7797 16.5522 21.7164 15.5872L21.7088 15.4704C21.6487 14.5561 21.0962 13.7419 20.2579 13.3326L15.6793 11.0972L10.2283 13.9045L13.71 15.6043C14.1507 15.8195 14.3297 16.3434 14.1096 16.7745ZM8.2627 12.9448L13.7136 10.1375L10.2889 8.46543C9.84803 8.25021 9.66911 7.72629 9.88916 7.29524C10.1093 6.86417 10.6451 6.68921 11.0859 6.90442L15.6575 9.13647L21.2171 6.27325L12.8808 2.03496C12.0675 1.62147 11.0928 1.65154 10.3078 2.11432L3.54908 6.09869C2.70732 6.59492 2.21846 7.50845 2.28139 8.46761L2.29003 8.59923C2.35002 9.51362 2.9026 10.3278 3.7409 10.7371L8.2627 12.9448ZM6.31884 13.9458L2.94386 12.2981C1.53727 11.6113 0.610092 10.2451 0.509431 8.71094L0.500795 8.57933C0.3952 6.96993 1.21547 5.4371 2.62787 4.60447L9.38662 0.620092C10.7038 -0.156419 12.3392 -0.206861 13.7039 0.486938L23.3799 5.40639C23.4551 5.44459 23.5224 5.4918 23.5811 5.54596C23.7105 5.62499 23.8209 5.73754 23.897 5.87906C24.1266 6.30534 23.9594 6.83293 23.5234 7.05744L17.6231 10.0961L21.0549 11.7716C22.4615 12.4583 23.3887 13.8245 23.4893 15.3587L23.497 15.4755C23.6033 17.0947 22.7724 18.6354 21.346 19.4644L14.5639 23.4057C13.2554 24.1661 11.6386 24.214 10.2854 23.5324L0.621855 18.6649C0.477299 18.592 0.361696 18.4859 0.279794 18.361C0.210188 18.2968 0.150054 18.2204 0.10296 18.133C-0.126635 17.7067 0.0406445 17.1792 0.47659 16.9546L6.31884 13.9458Z" fill="inherit"/>
311
+ </svg>
312
+ </a>
313
+ `;
314
+
315
+ const bannerContent = `
316
+ ${bannerDescription}
317
+ <div class="actions">
318
+ ${acceptAllButton}
319
+ ${rejectNonEssentialButton}
320
+ <div class="actions-row">
321
+ ${preferencesButton}
322
+ ${silktideLogo}
323
+ </div>
324
+ </div>
325
+ `;
326
+
327
+ return bannerContent;
328
+ }
329
+
330
+ hasSetInitialCookieChoices() {
331
+ return !!localStorage.getItem(`silktideCookieBanner_InitialChoice${this.getBannerSuffix()}`);
332
+ }
333
+
334
+ createBanner() {
335
+ // Create banner element
336
+ this.banner = this.createWrapperChild(this.getBannerContent(), 'silktide-banner');
337
+
338
+ // Add positioning class from config
339
+ if (this.banner && this.config.position?.banner) {
340
+ this.banner.classList.add(this.config.position.banner);
341
+ }
342
+
343
+ // Trigger optional onBannerOpen callback
344
+ if (this.banner && typeof this.config.onBannerOpen === 'function') {
345
+ this.config.onBannerOpen();
346
+ }
347
+ }
348
+
349
+ removeBanner() {
350
+ if (this.banner && this.banner.parentNode) {
351
+ this.banner.parentNode.removeChild(this.banner);
352
+ this.banner = null;
353
+
354
+ // Trigger optional onBannerClose callback
355
+ if (typeof this.config.onBannerClose === 'function') {
356
+ this.config.onBannerClose();
357
+ }
358
+ }
359
+ }
360
+
361
+ shouldShowBanner() {
362
+ if (this.config.showBanner === false) {
363
+ return false;
364
+ }
365
+ return (
366
+ localStorage.getItem(`silktideCookieBanner_InitialChoice${this.getBannerSuffix()}`) === null
367
+ );
368
+ }
369
+
370
+ // ----------------------------------------------------------------
371
+ // Modal
372
+ // ----------------------------------------------------------------
373
+ getModalContent() {
374
+ const preferencesTitle =
375
+ this.config.text?.preferences?.title || 'Customize your cookie preferences';
376
+
377
+ const preferencesDescription =
378
+ this.config.text?.preferences?.description ||
379
+ '<p>We respect your right to privacy. You can choose not to allow some types of cookies. Your cookie preferences will apply across our website.</p>';
380
+
381
+ // Preferences button
382
+ const preferencesButtonLabel = this.config.text?.banner?.preferencesButtonAccessibleLabel;
383
+
384
+ const closeModalButton = `<button class="modal-close"${preferencesButtonLabel ? ` aria-label="${preferencesButtonLabel}"` : ''}>
385
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
386
+ <path d="M19.4081 3.41559C20.189 2.6347 20.189 1.36655 19.4081 0.585663C18.6272 -0.195221 17.3591 -0.195221 16.5782 0.585663L10 7.17008L3.41559 0.59191C2.6347 -0.188974 1.36655 -0.188974 0.585663 0.59191C-0.195221 1.37279 -0.195221 2.64095 0.585663 3.42183L7.17008 10L0.59191 16.5844C-0.188974 17.3653 -0.188974 18.6335 0.59191 19.4143C1.37279 20.1952 2.64095 20.1952 3.42183 19.4143L10 12.8299L16.5844 19.4081C17.3653 20.189 18.6335 20.189 19.4143 19.4081C20.1952 18.6272 20.1952 17.3591 19.4143 16.5782L12.8299 10L19.4081 3.41559Z"/>
387
+ </svg>
388
+ </button>`;
389
+
390
+
391
+ const cookieTypes = this.config.cookieTypes || [];
392
+ const acceptedCookieMap = this.getAcceptedCookies();
393
+
394
+ // Accept button
395
+ const acceptAllButtonText = this.config.text?.banner?.acceptAllButtonText || 'Accept all';
396
+ const acceptAllButtonLabel = this.config.text?.banner?.acceptAllButtonAccessibleLabel;
397
+ const acceptAllButton = `<button class="preferences-accept-all st-button st-button--primary"${
398
+ acceptAllButtonLabel && acceptAllButtonLabel !== acceptAllButtonText
399
+ ? ` aria-label="${acceptAllButtonLabel}"`
400
+ : ''
401
+ }>${acceptAllButtonText}</button>`;
402
+
403
+ // Reject button
404
+ const rejectNonEssentialButtonText = this.config.text?.banner?.rejectNonEssentialButtonText || 'Reject non-essential';
405
+ const rejectNonEssentialButtonLabel = this.config.text?.banner?.rejectNonEssentialButtonAccessibleLabel;
406
+ const rejectNonEssentialButton = `<button class="preferences-reject-all st-button st-button--primary"${
407
+ rejectNonEssentialButtonLabel && rejectNonEssentialButtonLabel !== rejectNonEssentialButtonText
408
+ ? ` aria-label="${rejectNonEssentialButtonLabel}"`
409
+ : ''
410
+ }>${rejectNonEssentialButtonText}</button>`;
411
+
412
+ // Credit link
413
+ const creditLinkText = this.config.text?.preferences?.creditLinkText || 'Get this banner for free';
414
+ const creditLinkAccessibleLabel = this.config.text?.preferences?.creditLinkAccessibleLabel;
415
+ const creditLink = `<a href="https://silktide.com/consent-manager"${
416
+ creditLinkAccessibleLabel && creditLinkAccessibleLabel !== creditLinkText
417
+ ? ` aria-label="${creditLinkAccessibleLabel}"`
418
+ : ''
419
+ }>${creditLinkText}</a>`;
420
+
421
+
422
+
423
+ const modalContent = `
424
+ <header>
425
+ <h1>${preferencesTitle}</h1>
426
+ ${closeModalButton}
427
+ </header>
428
+ ${preferencesDescription}
429
+ <section id="cookie-preferences">
430
+ ${cookieTypes
431
+ .map((type) => {
432
+ const accepted = acceptedCookieMap[type.id];
433
+ let isChecked = false;
434
+
435
+ // if it's accepted then show as checked
436
+ if (accepted) {
437
+ isChecked = true;
438
+ }
439
+
440
+ // if nothing has been accepted / rejected yet, then show as checked if the default value is true
441
+ if (!accepted && !this.hasSetInitialCookieChoices()) {
442
+ isChecked = type.defaultValue;
443
+ }
444
+
445
+ return `
446
+ <fieldset>
447
+ <legend>${type.name}</legend>
448
+ <div class="cookie-type-content">
449
+ <div class="cookie-type-description">${type.description}</div>
450
+ <label class="switch" for="cookies-${type.id}">
451
+ <input type="checkbox" id="cookies-${type.id}" ${
452
+ type.required ? 'checked disabled' : isChecked ? 'checked' : ''
453
+ } />
454
+ <span class="switch__pill" aria-hidden="true"></span>
455
+ <span class="switch__dot" aria-hidden="true"></span>
456
+ <span class="switch__off" aria-hidden="true">Off</span>
457
+ <span class="switch__on" aria-hidden="true">On</span>
458
+ </label>
459
+ </div>
460
+ </fieldset>
461
+ `;
462
+ })
463
+ .join('')}
464
+ </section>
465
+ <footer>
466
+ ${acceptAllButton}
467
+ ${rejectNonEssentialButton}
468
+ ${creditLink}
469
+ </footer>
470
+ `;
471
+
472
+ return modalContent;
473
+ }
474
+
475
+ createModal() {
476
+ // Create banner element
477
+ this.modal = this.createWrapperChild(this.getModalContent(), 'silktide-modal');
478
+ }
479
+
480
+ toggleModal(show) {
481
+ if (!this.modal) return;
482
+
483
+ this.modal.style.display = show ? 'flex' : 'none';
484
+
485
+ if (show) {
486
+ this.showBackdrop();
487
+ this.hideCookieIcon();
488
+ this.removeBanner();
489
+ this.preventBodyScroll();
490
+
491
+ // Focus the close button
492
+ const modalCloseButton = this.modal.querySelector('.modal-close');
493
+ modalCloseButton.focus();
494
+
495
+ // Trigger optional onPreferencesOpen callback
496
+ if (typeof this.config.onPreferencesOpen === 'function') {
497
+ this.config.onPreferencesOpen();
498
+ }
499
+
500
+ this.updateCheckboxState(false); // read from storage when opening
501
+ } else {
502
+ // Set that an initial choice was made when closing the modal
503
+ this.setInitialCookieChoiceMade();
504
+
505
+ // Save current checkbox states to storage
506
+ this.updateCheckboxState(true);
507
+
508
+ this.hideBackdrop();
509
+ this.showCookieIcon();
510
+ this.allowBodyScroll();
511
+
512
+ // Trigger optional onPreferencesClose callback
513
+ if (typeof this.config.onPreferencesClose === 'function') {
514
+ this.config.onPreferencesClose();
515
+ }
516
+ }
517
+ }
518
+
519
+ // ----------------------------------------------------------------
520
+ // Cookie Icon
521
+ // ----------------------------------------------------------------
522
+ getCookieIconContent() {
523
+ return `
524
+ <svg width="38" height="38" viewBox="0 0 38 38" fill="none" xmlns="http://www.w3.org/2000/svg">
525
+ <path d="M19.1172 1.15625C19.0547 0.734374 18.7344 0.390624 18.3125 0.328124C16.5859 0.0859365 14.8281 0.398437 13.2813 1.21875L7.5 4.30469C5.96094 5.125 4.71875 6.41406 3.95313 7.98437L1.08594 13.8906C0.320314 15.4609 0.0703136 17.2422 0.375001 18.9609L1.50781 25.4297C1.8125 27.1562 2.64844 28.7344 3.90625 29.9531L8.61719 34.5156C9.875 35.7344 11.4766 36.5156 13.2031 36.7578L19.6875 37.6719C21.4141 37.9141 23.1719 37.6016 24.7188 36.7812L30.5 33.6953C32.0391 32.875 33.2813 31.5859 34.0469 30.0078L36.9141 24.1094C37.6797 22.5391 37.9297 20.7578 37.625 19.0391C37.5547 18.625 37.2109 18.3125 36.7969 18.25C32.7734 17.6094 29.5469 14.5703 28.6328 10.6406C28.4922 10.0469 28.0078 9.59375 27.4063 9.5C23.1406 8.82031 19.7734 5.4375 19.1094 1.15625H19.1172ZM15.25 10.25C15.913 10.25 16.5489 10.5134 17.0178 10.9822C17.4866 11.4511 17.75 12.087 17.75 12.75C17.75 13.413 17.4866 14.0489 17.0178 14.5178C16.5489 14.9866 15.913 15.25 15.25 15.25C14.587 15.25 13.9511 14.9866 13.4822 14.5178C13.0134 14.0489 12.75 13.413 12.75 12.75C12.75 12.087 13.0134 11.4511 13.4822 10.9822C13.9511 10.5134 14.587 10.25 15.25 10.25ZM10.25 25.25C10.25 24.587 10.5134 23.9511 10.9822 23.4822C11.4511 23.0134 12.087 22.75 12.75 22.75C13.413 22.75 14.0489 23.0134 14.5178 23.4822C14.9866 23.9511 15.25 24.587 15.25 25.25C15.25 25.913 14.9866 26.5489 14.5178 27.0178C14.0489 27.4866 13.413 27.75 12.75 27.75C12.087 27.75 11.4511 27.4866 10.9822 27.0178C10.5134 26.5489 10.25 25.913 10.25 25.25ZM27.75 20.25C28.413 20.25 29.0489 20.5134 29.5178 20.9822C29.9866 21.4511 30.25 22.087 30.25 22.75C30.25 23.413 29.9866 24.0489 29.5178 24.5178C29.0489 24.9866 28.413 25.25 27.75 25.25C27.087 25.25 26.4511 24.9866 25.9822 24.5178C25.5134 24.0489 25.25 23.413 25.25 22.75C25.25 22.087 25.5134 21.4511 25.9822 20.9822C26.4511 20.5134 27.087 20.25 27.75 20.25Z" />
526
+ </svg>
527
+ `;
528
+ }
529
+
530
+ createCookieIcon() {
531
+ this.cookieIcon = document.createElement('button');
532
+ this.cookieIcon.id = 'silktide-cookie-icon';
533
+ this.cookieIcon.innerHTML = this.getCookieIconContent();
534
+
535
+ if (this.config.text?.banner?.preferencesButtonAccessibleLabel) {
536
+ this.cookieIcon.ariaLabel = this.config.text?.banner?.preferencesButtonAccessibleLabel;
537
+ }
538
+
539
+ // Ensure wrapper exists
540
+ if (!this.wrapper || !document.body.contains(this.wrapper)) {
541
+ this.createWrapper();
542
+ }
543
+
544
+ // Append child to wrapper
545
+ this.wrapper.appendChild(this.cookieIcon);
546
+
547
+ // Add positioning class from config
548
+ if (this.cookieIcon && this.config.cookieIcon?.position) {
549
+ this.cookieIcon.classList.add(this.config.cookieIcon.position);
550
+ }
551
+
552
+ // Add color scheme class from config
553
+ if (this.cookieIcon && this.config.cookieIcon?.colorScheme) {
554
+ this.cookieIcon.classList.add(this.config.cookieIcon.colorScheme);
555
+ }
556
+ }
557
+
558
+ showCookieIcon() {
559
+ if (this.cookieIcon) {
560
+ this.cookieIcon.style.display = 'flex';
561
+ }
562
+ }
563
+
564
+ hideCookieIcon() {
565
+ if (this.cookieIcon) {
566
+ this.cookieIcon.style.display = 'none';
567
+ }
568
+ }
569
+
570
+ /**
571
+ * This runs if the user closes the modal without making a choice for the first time
572
+ * We apply the default values and the necessary values as default
573
+ */
574
+ handleClosedWithNoChoice() {
575
+ this.config.cookieTypes.forEach((type) => {
576
+ let accepted = true;
577
+ // Set localStorage and run accept/reject callbacks
578
+ if (type.required == true) {
579
+ localStorage.setItem(
580
+ `silktideCookieChoice_${type.id}${this.getBannerSuffix()}`,
581
+ accepted.toString(),
582
+ );
583
+ } else if (type.defaultValue) {
584
+ localStorage.setItem(
585
+ `silktideCookieChoice_${type.id}${this.getBannerSuffix()}`,
586
+ accepted.toString(),
587
+ );
588
+ } else {
589
+ accepted = false;
590
+ localStorage.setItem(
591
+ `silktideCookieChoice_${type.id}${this.getBannerSuffix()}`,
592
+ accepted.toString(),
593
+ );
594
+ }
595
+
596
+ if (accepted) {
597
+ if (typeof type.onAccept === 'function') { type.onAccept(); }
598
+ } else {
599
+ if (typeof type.onReject === 'function') { type.onReject(); }
600
+ }
601
+ // set the flag to say that the cookie choice has been made
602
+ this.setInitialCookieChoiceMade();
603
+ this.updateCheckboxState();
604
+ });
605
+ }
606
+
607
+ // ----------------------------------------------------------------
608
+ // Focusable Elements
609
+ // ----------------------------------------------------------------
610
+ getFocusableElements(element) {
611
+ return element.querySelectorAll(
612
+ 'button, a[href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
613
+ );
614
+ }
615
+
616
+ // ----------------------------------------------------------------
617
+ // Event Listeners
618
+ // ----------------------------------------------------------------
619
+ setupEventListeners() {
620
+ // Check Banner exists before trying to add event listeners
621
+ if (this.banner) {
622
+ // Get the buttons
623
+ const acceptButton = this.banner.querySelector('.accept-all');
624
+ const rejectButton = this.banner.querySelector('.reject-all');
625
+ const preferencesButton = this.banner.querySelector('.preferences');
626
+
627
+ // Add event listeners to the buttons
628
+ acceptButton?.addEventListener('click', () => this.handleCookieChoice(true));
629
+ rejectButton?.addEventListener('click', () => this.handleCookieChoice(false));
630
+ preferencesButton?.addEventListener('click', () => {
631
+ this.showBackdrop();
632
+ this.toggleModal(true);
633
+ });
634
+
635
+ // Focus Trap
636
+ const focusableElements = this.getFocusableElements(this.banner);
637
+ const firstFocusableEl = focusableElements[0];
638
+ const lastFocusableEl = focusableElements[focusableElements.length - 1];
639
+
640
+ // Add keydown event listener to handle tab navigation
641
+ this.banner.addEventListener('keydown', (e) => {
642
+ if (e.key === 'Tab') {
643
+ if (e.shiftKey) {
644
+ if (document.activeElement === firstFocusableEl) {
645
+ lastFocusableEl.focus();
646
+ e.preventDefault();
647
+ }
648
+ } else {
649
+ if (document.activeElement === lastFocusableEl) {
650
+ firstFocusableEl.focus();
651
+ e.preventDefault();
652
+ }
653
+ }
654
+ }
655
+ });
656
+
657
+ // Set initial focus
658
+ if (this.config.mode !== 'wizard') {
659
+ acceptButton?.focus();
660
+ }
661
+ }
662
+
663
+ // Check Modal exists before trying to add event listeners
664
+ if (this.modal) {
665
+ const closeButton = this.modal.querySelector('.modal-close');
666
+ const acceptAllButton = this.modal.querySelector('.preferences-accept-all');
667
+ const rejectAllButton = this.modal.querySelector('.preferences-reject-all');
668
+
669
+ closeButton?.addEventListener('click', () => {
670
+ this.toggleModal(false);
671
+
672
+ const hasMadeFirstChoice = this.hasSetInitialCookieChoices();
673
+
674
+ if (hasMadeFirstChoice) {
675
+ // run through the callbacks based on the current localStorage state
676
+ this.runStoredCookiePreferenceCallbacks();
677
+ } else {
678
+ // handle the case where the user closes without making a choice for the first time
679
+ this.handleClosedWithNoChoice();
680
+ }
681
+ });
682
+ acceptAllButton?.addEventListener('click', () => this.handleCookieChoice(true));
683
+ rejectAllButton?.addEventListener('click', () => this.handleCookieChoice(false));
684
+
685
+ // Banner Focus Trap
686
+ const focusableElements = this.getFocusableElements(this.modal);
687
+ const firstFocusableEl = focusableElements[0];
688
+ const lastFocusableEl = focusableElements[focusableElements.length - 1];
689
+
690
+ this.modal.addEventListener('keydown', (e) => {
691
+ if (e.key === 'Tab') {
692
+ if (e.shiftKey) {
693
+ if (document.activeElement === firstFocusableEl) {
694
+ lastFocusableEl.focus();
695
+ e.preventDefault();
696
+ }
697
+ } else {
698
+ if (document.activeElement === lastFocusableEl) {
699
+ firstFocusableEl.focus();
700
+ e.preventDefault();
701
+ }
702
+ }
703
+ }
704
+ if (e.key === 'Escape') {
705
+ this.toggleModal(false);
706
+ }
707
+ });
708
+
709
+ closeButton?.focus();
710
+
711
+ // Update the checkbox event listeners
712
+ const preferencesSection = this.modal.querySelector('#cookie-preferences');
713
+ const checkboxes = preferencesSection.querySelectorAll('input[type="checkbox"]');
714
+
715
+ checkboxes.forEach(checkbox => {
716
+ checkbox.addEventListener('change', (event) => {
717
+ const [, cookieId] = event.target.id.split('cookies-');
718
+ const isAccepted = event.target.checked;
719
+ const previousValue = localStorage.getItem(
720
+ `silktideCookieChoice_${cookieId}${this.getBannerSuffix()}`
721
+ ) === 'true';
722
+
723
+ // Only proceed if the value has actually changed
724
+ if (isAccepted !== previousValue) {
725
+ // Find the corresponding cookie type
726
+ const cookieType = this.config.cookieTypes.find(type => type.id === cookieId);
727
+
728
+ if (cookieType) {
729
+ // Update localStorage
730
+ localStorage.setItem(
731
+ `silktideCookieChoice_${cookieId}${this.getBannerSuffix()}`,
732
+ isAccepted.toString()
733
+ );
734
+
735
+ // Run the appropriate callback only if the value changed
736
+ if (isAccepted && typeof cookieType.onAccept === 'function') {
737
+ cookieType.onAccept();
738
+ } else if (!isAccepted && typeof cookieType.onReject === 'function') {
739
+ cookieType.onReject();
740
+ }
741
+ }
742
+ }
743
+ });
744
+ });
745
+ }
746
+
747
+ // Check Cookie Icon exists before trying to add event listeners
748
+ if (this.cookieIcon) {
749
+
750
+ this.cookieIcon.addEventListener('click', () => {
751
+ // If modal is not found, create it
752
+ if (!this.modal) {
753
+ this.createModal();
754
+ this.toggleModal(true);
755
+ this.hideCookieIcon();
756
+ }
757
+ // If modal is hidden, show it
758
+ else if (this.modal.style.display === 'none' || this.modal.style.display === '') {
759
+ this.toggleModal(true);
760
+ this.hideCookieIcon();
761
+ }
762
+ // If modal is visible, hide it
763
+ else {
764
+ this.toggleModal(false);
765
+ }
766
+ });
767
+ }
768
+ }
769
+
770
+ getBannerSuffix() {
771
+ if (this.config.bannerSuffix) {
772
+ return '_' + this.config.bannerSuffix;
773
+ }
774
+ return '';
775
+ }
776
+
777
+ preventBodyScroll() {
778
+ document.body.style.overflow = 'hidden';
779
+ // Prevent iOS Safari scrolling
780
+ document.body.style.position = 'fixed';
781
+ document.body.style.width = '100%';
782
+ }
783
+
784
+ allowBodyScroll() {
785
+ document.body.style.overflow = '';
786
+ document.body.style.position = '';
787
+ document.body.style.width = '';
788
+ }
789
+ }
790
+
791
+ (function () {
792
+ window.silktideCookieBannerManager = {};
793
+
794
+ let config = {};
795
+ let cookieBanner;
796
+
797
+ function updateCookieBannerConfig(userConfig = {}) {
798
+ config = {...config, ...userConfig};
799
+
800
+ // If cookie banner exists, destroy and recreate it with new config
801
+ if (cookieBanner) {
802
+ cookieBanner.destroyCookieBanner(); // We'll need to add this method
803
+ cookieBanner = null;
804
+ }
805
+
806
+ // Only initialize if document.body exists
807
+ if (document.body) {
808
+ initCookieBanner();
809
+ } else {
810
+ // Wait for DOM to be ready
811
+ document.addEventListener('DOMContentLoaded', initCookieBanner, {once: true});
812
+ }
813
+ }
814
+
815
+ function initCookieBanner() {
816
+ if (!cookieBanner) {
817
+ cookieBanner = new SilktideCookieBanner(config); // Pass config to the CookieBanner instance
818
+ }
819
+ }
820
+
821
+ function injectScript(url, loadOption) {
822
+ // Check if script with this URL already exists
823
+ const existingScript = document.querySelector(`script[src="${url}"]`);
824
+ if (existingScript) {
825
+ return; // Script already exists, don't add it again
826
+ }
827
+
828
+ const script = document.createElement('script');
829
+ script.src = url;
830
+
831
+ // Apply the async or defer attribute based on the loadOption parameter
832
+ if (loadOption === 'async') {
833
+ script.async = true;
834
+ } else if (loadOption === 'defer') {
835
+ script.defer = true;
836
+ }
837
+
838
+ document.head.appendChild(script);
839
+ }
840
+
841
+ window.silktideCookieBannerManager.initCookieBanner = initCookieBanner;
842
+ window.silktideCookieBannerManager.updateCookieBannerConfig = updateCookieBannerConfig;
843
+ window.silktideCookieBannerManager.injectScript = injectScript;
844
+
845
+ if (document.readyState === 'loading') {
846
+ document.addEventListener('DOMContentLoaded', initCookieBanner, {once: true});
847
+ } else {
848
+ initCookieBanner();
849
+ }
850
+ })();
w-312356-main/public/favicon.ico ADDED
w-312356-main/public/lovable-uploads/078a129e-0f98-4d91-af61-873687db1a04.png ADDED

Git LFS Details

  • SHA256: 042b0d745de4f09dbe932f7c461dd3cafc1808656c657d8905567f96aec1f928
  • Pointer size: 132 Bytes
  • Size of remote file: 2.34 MB
w-312356-main/public/lovable-uploads/11e92b89-ed02-453a-9888-56cd91807f2d.png ADDED

Git LFS Details

  • SHA256: a7c17c33e083cac1ba7bcf7e56144674860c1f17e48d436fe8c10cfd1be8c3ea
  • Pointer size: 131 Bytes
  • Size of remote file: 251 kB
w-312356-main/public/lovable-uploads/14ea3fe0-19d6-425c-b95b-4117bc41f3ca.png ADDED
w-312356-main/public/lovable-uploads/1cd5a3da-7a58-4374-abc1-d7b02b0c5fd5.png ADDED

Git LFS Details

  • SHA256: 0b2e716c5218725a1e8581bfd41fc6cfa80dabc74a8369efd06e72712bfce88a
  • Pointer size: 132 Bytes
  • Size of remote file: 1.91 MB
w-312356-main/public/lovable-uploads/30473baa-85f4-4931-aad9-c722ae7a4918.png ADDED

Git LFS Details

  • SHA256: 7f4a53cb7db0c097db08ee41a9105d1677fc14aa85b51b82206d907fc978095d
  • Pointer size: 131 Bytes
  • Size of remote file: 288 kB
w-312356-main/public/lovable-uploads/39605e90-8478-4fee-b1b9-cee41df66f10.png ADDED

Git LFS Details

  • SHA256: 1c4e03074f1c72b844d4ef2d4ff910880e870f7b051eb90fe62d029daf1ee499
  • Pointer size: 131 Bytes
  • Size of remote file: 405 kB
w-312356-main/public/lovable-uploads/39671993-1bb4-4bb6-8819-3ca5c07c0042.png ADDED
w-312356-main/public/lovable-uploads/3de85ddd-15e1-4216-9697-f91abb9a47ce.png ADDED
w-312356-main/public/lovable-uploads/4187f423-ba69-4043-be76-c43098488348.png ADDED

Git LFS Details

  • SHA256: 068544924921c43c666850f767a4a9e48da1cacfc8a905d9a2dc23ef31d40375
  • Pointer size: 132 Bytes
  • Size of remote file: 3.11 MB
w-312356-main/public/lovable-uploads/48e540e5-6a25-44e4-b3f7-80f3bfc2777a.png ADDED

Git LFS Details

  • SHA256: 5b48390d1cba16b0c1863824eb2d54fd115923aa11be33fbb7eec6713049a2f3
  • Pointer size: 132 Bytes
  • Size of remote file: 2.11 MB
w-312356-main/public/lovable-uploads/48ecf6e2-5a98-4a9d-af6f-ae2265cd4098.png ADDED

Git LFS Details

  • SHA256: ba6ee20e5a77ba18603757d7260b5fbf9ae997022897df34cd0a812fd8f901e9
  • Pointer size: 132 Bytes
  • Size of remote file: 2.08 MB
w-312356-main/public/lovable-uploads/4bfa0d71-3ed2-4693-90b6-35142468907f.png ADDED

Git LFS Details

  • SHA256: c43f91acd61e050537772a32c5f302e4e0d9a29a7970ad4024533d5e01734464
  • Pointer size: 131 Bytes
  • Size of remote file: 122 kB
w-312356-main/public/lovable-uploads/5262afdb-dd24-4d5e-be66-7c6717adbca9.png ADDED

Git LFS Details

  • SHA256: 922bd70efe61030128e521e4ebf438a742aa89e250701dfc9dde7e22801b0e78
  • Pointer size: 132 Bytes
  • Size of remote file: 1.58 MB
w-312356-main/public/lovable-uploads/526dc38a-25fa-40d4-b520-425b23ae0464.png ADDED

Git LFS Details

  • SHA256: e742a19f9063a24353766ab4b600583afead854563550ff463827579678af8c7
  • Pointer size: 132 Bytes
  • Size of remote file: 1.97 MB
w-312356-main/public/lovable-uploads/5463c9c5-0946-4280-a14b-17636ff69a98.png ADDED

Git LFS Details

  • SHA256: 882ca2907f478966683eb84027c18f420300fb052ea1c47140e76bf127428057
  • Pointer size: 131 Bytes
  • Size of remote file: 265 kB
w-312356-main/public/lovable-uploads/5ca619e6-2139-4879-9b3c-94777ab85e2a.png ADDED
w-312356-main/public/lovable-uploads/6739bd63-bf19-4abd-bb23-0b613bbf7ac8.png ADDED

Git LFS Details

  • SHA256: bac59c64ab05131efb9348bda200bb76b7a0e747509dbe24e0ebcd5b9b40ca80
  • Pointer size: 132 Bytes
  • Size of remote file: 2.67 MB
w-312356-main/public/lovable-uploads/6b0637e9-4a7b-40d0-b219-c8b7f879f93e.png ADDED

Git LFS Details

  • SHA256: 7c22fc7fb181a7007f36bb033aeb697ea37ad027a60e3b788e5bd5134e5dcda7
  • Pointer size: 132 Bytes
  • Size of remote file: 2.18 MB
w-312356-main/public/lovable-uploads/6fdd3d0d-5dca-470a-a845-bd7b07bff599.png ADDED

Git LFS Details

  • SHA256: fc003cc53287309d2eed81b5cc709a5100e7dd37a99701ee57924e22879d967a
  • Pointer size: 132 Bytes
  • Size of remote file: 1.47 MB
w-312356-main/public/lovable-uploads/700e27d7-0513-4bfa-8ac4-f7fd6087594c.png ADDED

Git LFS Details

  • SHA256: 949f17b37d4269ee87fe006395e26eb84f57e1381bdce34fbe742c1b9b5d8124
  • Pointer size: 131 Bytes
  • Size of remote file: 376 kB
w-312356-main/public/lovable-uploads/7293c494-769c-421b-9028-d8ccb0bdd80a.png ADDED

Git LFS Details

  • SHA256: 252e7499f63b179b167d147493862169ceed8566a6adf979e651096a49d9b608
  • Pointer size: 131 Bytes
  • Size of remote file: 275 kB
w-312356-main/public/lovable-uploads/761e2d9d-3a1c-458b-9848-dd1d7b42d1b9.png ADDED

Git LFS Details

  • SHA256: 2b094ea846771e1684963af0e3843aec4a427b3fc6a34284b9375e0e56c2f692
  • Pointer size: 131 Bytes
  • Size of remote file: 329 kB
w-312356-main/public/lovable-uploads/7d120ee6-3614-4b75-9c35-716d54490d67.png ADDED
w-312356-main/public/lovable-uploads/843446fe-638e-4efb-b885-ed3cd505325a.png ADDED

Git LFS Details

  • SHA256: 6a152e4c480e1a308b7a48c44a1a0033a8fa5b341b87b54db2189db6c0efb94b
  • Pointer size: 131 Bytes
  • Size of remote file: 278 kB
w-312356-main/public/lovable-uploads/927dae7e-6aaf-4b76-add2-1287a1dd9dc0.png ADDED

Git LFS Details

  • SHA256: b89a000e3e8d64cd4ff66d68670ee573a2b1fb533fa04ed2c90b63de9a76f9f6
  • Pointer size: 132 Bytes
  • Size of remote file: 1.03 MB
w-312356-main/public/lovable-uploads/93ab0638-8190-4ccf-897f-21fda7f4f5ad.png ADDED
w-312356-main/public/lovable-uploads/a1ef45a0-dde4-4b30-856f-8032dd58247e.png ADDED

Git LFS Details

  • SHA256: ff17b442f6754f6d2ca74248ac56ec5af6e432319e916c76887e39344ca259b6
  • Pointer size: 131 Bytes
  • Size of remote file: 311 kB
w-312356-main/public/lovable-uploads/a9bb9110-964a-43b0-a5ab-7162140cd133.png ADDED

Git LFS Details

  • SHA256: de31f534a7184d021c975635f95afdededd95403bd63188c1cb3d29891e12b46
  • Pointer size: 132 Bytes
  • Size of remote file: 3.04 MB
w-312356-main/public/lovable-uploads/aa5291bd-2417-4c1e-9a02-0bcc71a92507.png ADDED
w-312356-main/public/lovable-uploads/af5ee2ce-3942-48bb-a2ad-3b49b419daf9.png ADDED

Git LFS Details

  • SHA256: 209e58bddc447abe11e27a0edb4f0f5c93f3d691edba0237e84615dda17aacd9
  • Pointer size: 132 Bytes
  • Size of remote file: 3.11 MB
w-312356-main/public/lovable-uploads/b0622048-17b4-4c75-a3f0-6c9e17de1d09.png ADDED

Git LFS Details

  • SHA256: 7d96db25f4f28db697ee2c7df8aa5bab4e458809083587d98007e37157074871
  • Pointer size: 132 Bytes
  • Size of remote file: 2.5 MB
w-312356-main/public/lovable-uploads/b862d5ae-6abb-44da-84f0-00a222f62906.png ADDED

Git LFS Details

  • SHA256: 93c40d9d34d1faa18faa2e066b14fb244c70ef5d65fe21352687525a2433d701
  • Pointer size: 131 Bytes
  • Size of remote file: 174 kB
w-312356-main/public/lovable-uploads/c30e0487-2fa0-41d1-9a0b-699cb2855388.png ADDED

Git LFS Details

  • SHA256: e38f0d75863678cb556b124025451fa2f9c47ff1933f4ea8624163a0a5f78cab
  • Pointer size: 132 Bytes
  • Size of remote file: 2.8 MB
w-312356-main/public/lovable-uploads/c5f8ee24-9815-4ebe-b65d-6f3d449feb8b.png ADDED

Git LFS Details

  • SHA256: 57751c8d1682348ee896dcf20a52e131b886dbc8bc1b4e3c9a59cf5fd0228bfd
  • Pointer size: 131 Bytes
  • Size of remote file: 113 kB
w-312356-main/public/lovable-uploads/cbd073dd-ecad-4643-bf2b-efc3d5846994.png ADDED