@koehler8/cms 1.0.0-beta.5

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.
Files changed (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +202 -0
  3. package/bin/cms-generate-public-assets.js +27 -0
  4. package/bin/cms-validate-extensions.js +18 -0
  5. package/bin/cms-validate-themes.js +7 -0
  6. package/extensions/manifest.schema.json +125 -0
  7. package/package.json +84 -0
  8. package/public/img/preloaders/preloader-black.svg +1 -0
  9. package/public/img/preloaders/preloader-white.svg +1 -0
  10. package/public/robots.txt +5 -0
  11. package/scripts/check-overflow.mjs +33 -0
  12. package/scripts/generate-public-assets.js +401 -0
  13. package/scripts/patch-lru-cache-tla.js +164 -0
  14. package/scripts/validate-extensions.mjs +392 -0
  15. package/scripts/validate-themes.mjs +64 -0
  16. package/src/App.vue +3 -0
  17. package/src/components/About.vue +481 -0
  18. package/src/components/AboutValue.vue +361 -0
  19. package/src/components/BackToTop.vue +42 -0
  20. package/src/components/ComingSoon.vue +411 -0
  21. package/src/components/ComingSoonModal.vue +230 -0
  22. package/src/components/Contact.vue +518 -0
  23. package/src/components/Footer.vue +65 -0
  24. package/src/components/FooterMinimal.vue +153 -0
  25. package/src/components/Header.vue +583 -0
  26. package/src/components/Hero.vue +327 -0
  27. package/src/components/Home.vue +144 -0
  28. package/src/components/Intro.vue +130 -0
  29. package/src/components/IntroGate.vue +444 -0
  30. package/src/components/Plan.vue +116 -0
  31. package/src/components/Portfolio.vue +459 -0
  32. package/src/components/Preloader.vue +20 -0
  33. package/src/components/Principles.vue +67 -0
  34. package/src/components/Spacer15.vue +9 -0
  35. package/src/components/Spacer30.vue +9 -0
  36. package/src/components/Spacer40.vue +9 -0
  37. package/src/components/Spacer60.vue +9 -0
  38. package/src/components/StickyCTA.vue +263 -0
  39. package/src/components/Team.vue +432 -0
  40. package/src/components/icons/IconLinkedIn.vue +22 -0
  41. package/src/components/icons/IconX.vue +22 -0
  42. package/src/components/ui/SbCard.vue +52 -0
  43. package/src/components/ui/SkeletonPulse.vue +117 -0
  44. package/src/components/ui/UnitChip.vue +69 -0
  45. package/src/composables/useComingSoonConfig.js +120 -0
  46. package/src/composables/useComingSoonInterstitial.js +27 -0
  47. package/src/composables/useComponentResolver.js +196 -0
  48. package/src/composables/useEngagementTracking.js +187 -0
  49. package/src/composables/useIntroGate.js +46 -0
  50. package/src/composables/useLazyImage.js +77 -0
  51. package/src/composables/usePageConfig.js +184 -0
  52. package/src/composables/usePageMeta.js +76 -0
  53. package/src/composables/usePromoBackgroundStyles.js +67 -0
  54. package/src/constants/locales.js +20 -0
  55. package/src/extensions/extensionLoader.js +512 -0
  56. package/src/main.js +175 -0
  57. package/src/router/index.js +112 -0
  58. package/src/styles/base.css +896 -0
  59. package/src/styles/layout.css +342 -0
  60. package/src/styles/theme-base.css +84 -0
  61. package/src/themes/themeLoader.js +124 -0
  62. package/src/themes/themeManager.js +257 -0
  63. package/src/themes/themeValidator.js +380 -0
  64. package/src/utils/analytics.js +100 -0
  65. package/src/utils/appInfo.js +9 -0
  66. package/src/utils/assetResolver.js +162 -0
  67. package/src/utils/componentRegistry.js +46 -0
  68. package/src/utils/contentRequirements.js +67 -0
  69. package/src/utils/cookieConsent.js +281 -0
  70. package/src/utils/ctaCopy.js +58 -0
  71. package/src/utils/formatNumber.js +115 -0
  72. package/src/utils/imageSources.js +179 -0
  73. package/src/utils/inflateFlatConfig.js +30 -0
  74. package/src/utils/loadConfig.js +271 -0
  75. package/src/utils/semver.js +49 -0
  76. package/src/utils/siteStyles.js +40 -0
  77. package/src/utils/themeColors.js +65 -0
  78. package/src/utils/trackingContext.js +142 -0
  79. package/src/utils/unwrapDefault.js +14 -0
  80. package/src/utils/useScrollReveal.js +48 -0
  81. package/templates/index.html +36 -0
  82. package/themes/base/README.md +23 -0
  83. package/themes/base/theme.config.js +214 -0
  84. package/vite-plugin.js +637 -0
@@ -0,0 +1,153 @@
1
+ <template>
2
+ <footer class="brand-footer" data-analytics-section="footer">
3
+ <div class="container" role="presentation">
4
+ <div class="footer-grid">
5
+ <a class="footer-logo" href="/">
6
+ <img :src="logoSrc" :alt="siteName" class="img-fluid" />
7
+ </a>
8
+ <p class="footer-text">{{ footerText }}</p>
9
+ <p v-if="footerDisclaimer" class="footer-disclaimer">
10
+ {{ footerDisclaimer }}
11
+ </p>
12
+ <nav v-if="footerLinks.length" class="footer-links" aria-label="Legal links">
13
+ <a
14
+ v-for="(link, idx) in footerLinks"
15
+ :key="idx"
16
+ class="footer-link"
17
+ :href="link.href"
18
+ :target="link.target"
19
+ :rel="link.rel"
20
+ >
21
+ {{ link.text }}
22
+ </a>
23
+ </nav>
24
+ </div>
25
+ </div>
26
+ </footer>
27
+ </template>
28
+
29
+ <script setup>
30
+ import { computed, inject, ref } from 'vue';
31
+ import { resolveAsset } from '../utils/assetResolver.js';
32
+
33
+ const injectedSiteData = inject('siteData', ref({}));
34
+ const pageContent = inject('pageContent', ref({}));
35
+
36
+ const logoSrc = computed(() => resolveAsset('img/logo.png'));
37
+ const siteName = computed(() => injectedSiteData.value?.site?.title || '');
38
+
39
+ const sharedFooter = computed(() => injectedSiteData.value?.shared?.content?.footer || {});
40
+ const pageFooter = computed(() => pageContent.value?.footer || {});
41
+
42
+ const footerContent = computed(() => {
43
+ const pageValue = pageFooter.value;
44
+ if (pageValue && Object.keys(pageValue).length > 0) return pageValue;
45
+ return sharedFooter.value || {};
46
+ });
47
+
48
+ const footerText = computed(() => footerContent.value?.text || '');
49
+ const footerLinks = computed(() => {
50
+ const links = Array.isArray(footerContent.value?.links) ? footerContent.value.links : [];
51
+ return links
52
+ .filter((link) => link && typeof link === 'object')
53
+ .map((link) => {
54
+
55
+ const href = typeof link.href === 'string' ? link.href.trim() : '';
56
+ const explicitExternal = link.external === true;
57
+ const explicitInternal = link.external === false;
58
+ const implicitExternal = !explicitInternal && /^https?:\/\//i.test(href);
59
+ const isExternal = explicitExternal || implicitExternal;
60
+
61
+ const target = isExternal ? '_blank' : link.target || null;
62
+ const rel = isExternal ? 'noopener noreferrer' : link.rel || null;
63
+
64
+ return {
65
+ ...link,
66
+ href,
67
+ target,
68
+ rel,
69
+ };
70
+ });
71
+ });
72
+ const footerDisclaimer = computed(() => footerContent.value?.disclaimer || '');
73
+ </script>
74
+
75
+ <style scoped>
76
+ .brand-footer {
77
+ background: var(
78
+ --footer-bg,
79
+ color-mix(in srgb, var(--brand-bg-900, #070410) 88%, var(--brand-bg-800, #120b1f) 12%)
80
+ );
81
+ color: var(--footer-text, var(--ui-text-primary, var(--brand-card-text, #f0eaf3)));
82
+ padding: 48px 0 28px;
83
+ }
84
+
85
+ .footer-grid {
86
+ display: grid;
87
+ gap: 20px;
88
+ text-align: center;
89
+ justify-items: center;
90
+ }
91
+
92
+ .footer-logo img {
93
+ max-width: 160px;
94
+ }
95
+
96
+ .footer-text {
97
+ max-width: 520px;
98
+ margin: 0;
99
+ color: var(--footer-text, var(--ui-text-primary, var(--brand-card-text, #f0eaf3)));
100
+ font-size: 0.9rem;
101
+ line-height: 1.55;
102
+ }
103
+
104
+ .footer-disclaimer {
105
+ margin: 0 auto;
106
+ max-width: min(100%, 760px);
107
+ font-size: 0.75rem;
108
+ font-style: italic;
109
+ line-height: 1.6;
110
+ color: var(
111
+ --footer-disclaimer,
112
+ color-mix(in srgb, var(--ui-text-muted, var(--brand-card-text, #f0eaf3)) 70%, transparent)
113
+ );
114
+ }
115
+
116
+ .footer-links {
117
+ display: flex;
118
+ gap: 18px;
119
+ justify-content: center;
120
+ flex-wrap: wrap;
121
+ font-size: 0.85rem;
122
+ letter-spacing: 0.08em;
123
+ text-transform: uppercase;
124
+ }
125
+
126
+ .footer-link {
127
+ color: var(
128
+ --footer-link-color,
129
+ color-mix(in srgb, var(--ui-text-primary, var(--brand-card-text, #f0eaf3)) 75%, transparent)
130
+ );
131
+ text-decoration: none;
132
+ transition: color 0.2s ease, text-decoration 0.2s ease;
133
+ }
134
+
135
+ .footer-link:hover,
136
+ .footer-link:focus-visible {
137
+ color: var(--footer-link-hover, var(--brand-accent-electric, #27f3ff));
138
+ text-decoration: underline;
139
+ }
140
+
141
+ @media (prefers-reduced-motion: reduce) {
142
+ .footer-link {
143
+ transition: none;
144
+ }
145
+ }
146
+
147
+ @media (min-width: 992px) {
148
+ .footer-text,
149
+ .footer-disclaimer {
150
+ max-width: 760px;
151
+ }
152
+ }
153
+ </style>