@simple-photo-gallery/theme-modern 2.0.15 → 2.0.17

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simple-photo-gallery/theme-modern",
3
- "version": "2.0.15",
3
+ "version": "2.0.17",
4
4
  "description": "Modern theme for Simple Photo Gallery",
5
5
  "license": "MIT",
6
6
  "author": "Vladimir Haltakov, Tomasz Rusin",
@@ -14,7 +14,7 @@
14
14
  .footer {
15
15
  padding: 2rem 1.5rem 1.5rem;
16
16
  text-align: center;
17
- background-color: transparent;
17
+ background-color: var(--section-bg-color-odd, var(--section-bg-color, #ffffff));
18
18
  }
19
19
 
20
20
  .footer__text {
@@ -40,10 +40,20 @@ const validImages = section.images.filter(
40
40
  <style>
41
41
  .gallery-section {
42
42
  padding: 1rem 1rem;
43
+ background-color: var(--section-bg-color-odd, var(--section-bg-color, #ffffff));
43
44
  }
44
45
 
45
46
  .gallery-section:nth-child(even) {
46
- background-color: #f9fafb;
47
+ background-color: var(--section-bg-color-even, var(--section-bg-color, #f9fafb));
48
+ }
49
+
50
+ /* Opt-in embed mode: transparent backgrounds for iframe embedding */
51
+ .gallery-section--transparent {
52
+ background-color: var(--section-bg-color-odd, var(--section-bg-color, transparent));
53
+ }
54
+
55
+ .gallery-section--transparent:nth-child(even) {
56
+ background-color: var(--section-bg-color-even, var(--section-bg-color, transparent));
47
57
  }
48
58
 
49
59
  .gallery-section__container {
@@ -27,13 +27,13 @@ const parsedDescription = section.description ? await renderMarkdown(section.des
27
27
  font-size: clamp(1.5rem, 3vw, 2.5rem);
28
28
  font-weight: 700;
29
29
  margin-bottom: 1.5rem;
30
- color: #111827;
30
+ color: var(--typography-color-title, var(--gallery-section-title-color, #111827));
31
31
  text-align: center;
32
32
  }
33
33
 
34
34
  .gallery-section__header-description {
35
35
  font-size: 1.125rem;
36
- color: #6b7280;
36
+ color: var(--typography-color-description, var(--gallery-section-description-color, #6b7280));
37
37
  max-width: 42rem;
38
38
  margin: 0 auto;
39
39
  line-height: 1.6;
@@ -145,13 +145,13 @@ const headerPhotoPath = getPhotoPath(headerImage || '', mediaBaseUrl);
145
145
  () => {
146
146
  // Final fallback failed, blurhash stays visible
147
147
  },
148
- { once: true }
148
+ { once: true },
149
149
  );
150
150
 
151
151
  // If fallback succeeds, hide blurhash
152
152
  img.addEventListener('load', hideBlurhash, { once: true });
153
153
  },
154
- { once: true }
154
+ { once: true },
155
155
  );
156
156
  })();
157
157
  </script>
@@ -168,7 +168,7 @@ const headerPhotoPath = getPhotoPath(headerImage || '', mediaBaseUrl);
168
168
  .hero {
169
169
  position: relative;
170
170
  min-height: 450px;
171
- height: 100vh;
171
+ height: var(--hero-height, 100vh);
172
172
  display: flex;
173
173
  align-items: center;
174
174
  justify-content: center;
@@ -58,6 +58,10 @@ const headerImageBasename = headerImage ? path.basename(headerImage, path.extnam
58
58
  font-weight: 400;
59
59
  }
60
60
 
61
+ body.embed-transparent {
62
+ background: transparent;
63
+ }
64
+
61
65
  /* Markdown content styles */
62
66
  .markdown-content p {
63
67
  margin-bottom: 1rem;
@@ -38,6 +38,8 @@ const showCtaBanner = ctaBanner === true;
38
38
  <script>
39
39
  import { decode } from 'blurhash';
40
40
 
41
+ import { applyQueryParams } from '@/features/themes/base-theme/utils/queryParams';
42
+
41
43
  const blurHashCanvases = document.querySelectorAll<HTMLCanvasElement>('canvas[data-blur-hash]');
42
44
 
43
45
  for (const canvas of blurHashCanvases) {
@@ -53,6 +55,8 @@ const showCtaBanner = ctaBanner === true;
53
55
  }
54
56
  }
55
57
  }
58
+
59
+ applyQueryParams();
56
60
  </script>
57
61
 
58
62
  <MainLayout
@@ -0,0 +1,159 @@
1
+ const TYPOGRAPHY_MODERN_THEME_PRESETS: Record<string, { title: string; description: string }> = {
2
+ light: { title: 'rgba(255, 255, 255, 0.95)', description: 'rgba(255, 255, 255, 0.75)' },
3
+ white: { title: 'rgba(255, 255, 255, 0.95)', description: 'rgba(255, 255, 255, 0.75)' },
4
+ dark: { title: '#111827', description: '#6b7280' },
5
+ black: { title: '#111827', description: '#6b7280' },
6
+ };
7
+
8
+ /**
9
+ * Normalizes hex color values to 6-digit format (e.g., #abc -> #aabbcc).
10
+ * Returns null if the hex value is invalid.
11
+ */
12
+ const normalizeHex = (hex: string): string | null => {
13
+ hex = hex.replace('#', '');
14
+ if (hex.length === 3) hex = [...hex].map((c) => c + c).join('');
15
+ return hex.length === 6 && /^[0-9A-Fa-f]{6}$/.test(hex) ? `#${hex}` : null;
16
+ };
17
+
18
+ /**
19
+ * Parses and validates a color value from query parameters.
20
+ * Supports CSS color names, hex values, rgb/rgba, and 'transparent'.
21
+ * Returns null if the color is invalid.
22
+ */
23
+ const parseColor = (colorParam: string | null): string | null => {
24
+ if (!colorParam) return null;
25
+ const normalized = colorParam.toLowerCase().trim();
26
+ if (normalized === 'transparent') return 'transparent';
27
+
28
+ const testEl = document.createElement('div');
29
+ testEl.style.color = normalized;
30
+ if (testEl.style.color) return normalized;
31
+
32
+ return normalizeHex(colorParam);
33
+ };
34
+
35
+ /**
36
+ * Sets or removes a CSS custom property (variable) on an element.
37
+ * Removes the property if value is null.
38
+ */
39
+ const setCSSVar = (root: HTMLElement, name: string, value: string | null): void => {
40
+ if (value) {
41
+ root.style.setProperty(name, value);
42
+ } else {
43
+ root.style.removeProperty(name);
44
+ }
45
+ };
46
+
47
+ /**
48
+ * Derives a description color from a title color by adjusting opacity to 0.8.
49
+ * Converts rgb to rgba if needed, otherwise returns the original color.
50
+ */
51
+ const deriveDescriptionColor = (titleColor: string): string => {
52
+ if (titleColor.startsWith('rgba')) {
53
+ return titleColor.replace(/,\s*[\d.]+\)$/, ', 0.8)');
54
+ }
55
+ if (titleColor.startsWith('rgb')) {
56
+ return titleColor.replace('rgb', 'rgba').replace(')', ', 0.8)');
57
+ }
58
+ return titleColor;
59
+ };
60
+
61
+ /**
62
+ * Controls the visibility of the hero/header image based on the 'headerImage' query parameter.
63
+ * Hides the hero section if headerImage is 'false' or '0'.
64
+ */
65
+ const applyHeaderImageVisibility = (params: URLSearchParams): void => {
66
+ const heroSection = document.querySelector<HTMLElement>('.hero');
67
+ if (!heroSection) return;
68
+
69
+ const headerImage = params.get('headerImage');
70
+ heroSection.style.display = headerImage === 'false' || headerImage === '0' ? 'none' : '';
71
+ };
72
+
73
+ /**
74
+ * Applies transparent background styling when 'background=transparent' is in query params.
75
+ * Adds CSS classes and sets background styles on root, body, and gallery sections.
76
+ */
77
+ const applyTransparentBackground = (params: URLSearchParams): void => {
78
+ const root = document.documentElement;
79
+ const body = document.body;
80
+ const isTransparent = params.get('background') === 'transparent';
81
+
82
+ body.classList.toggle('embed-transparent', isTransparent);
83
+ const bgValue = isTransparent ? 'transparent' : '';
84
+ root.style.background = bgValue;
85
+ body.style.background = bgValue;
86
+
87
+ for (const section of document.querySelectorAll('.gallery-section')) {
88
+ section.classList.toggle('gallery-section--transparent', isTransparent);
89
+ }
90
+ };
91
+
92
+ /**
93
+ * Applies typography colors from the 'typographyColor' query parameter.
94
+ * Supports preset values (light, dark, white, black) or custom color values.
95
+ * Automatically derives description color from title color if using custom values.
96
+ */
97
+ const applyTypographyColors = (params: URLSearchParams): void => {
98
+ const root = document.documentElement;
99
+ const typographyParam = params.get('typographyColor');
100
+
101
+ if (!typographyParam) {
102
+ setCSSVar(root, '--typography-color-title', null);
103
+ setCSSVar(root, '--typography-color-description', null);
104
+ return;
105
+ }
106
+
107
+ const normalized = typographyParam.toLowerCase().trim();
108
+ const preset = TYPOGRAPHY_MODERN_THEME_PRESETS[normalized];
109
+
110
+ if (preset) {
111
+ setCSSVar(root, '--typography-color-title', preset.title);
112
+ setCSSVar(root, '--typography-color-description', preset.description);
113
+ return;
114
+ }
115
+
116
+ const color = parseColor(typographyParam);
117
+ if (color) {
118
+ setCSSVar(root, '--typography-color-title', color);
119
+ setCSSVar(root, '--typography-color-description', deriveDescriptionColor(color));
120
+ } else {
121
+ setCSSVar(root, '--typography-color-title', null);
122
+ setCSSVar(root, '--typography-color-description', null);
123
+ }
124
+ };
125
+
126
+ /**
127
+ * Applies section background colors from query parameters.
128
+ * Sets CSS variables for general, even, and odd section background colors.
129
+ */
130
+ const applySectionBackgroundColors = (params: URLSearchParams): void => {
131
+ const root = document.documentElement;
132
+ setCSSVar(root, '--section-bg-color', parseColor(params.get('sectionBgColor')));
133
+ setCSSVar(root, '--section-bg-color-even', parseColor(params.get('sectionBgColorEven')));
134
+ setCSSVar(root, '--section-bg-color-odd', parseColor(params.get('sectionBgColorOdd')));
135
+ };
136
+
137
+ /**
138
+ * Applies hero height from the 'heroHeight' query parameter.
139
+ * Accepts a number (e.g., '100' for 100vh, '50' for 50vh).
140
+ */
141
+ const applyHeroHeight = (params: URLSearchParams): void => {
142
+ const value = params.get('heroHeight')?.trim();
143
+ const height = value && /^\d+(\.\d+)?$/.test(value) ? `${value}vh` : null;
144
+ setCSSVar(document.documentElement, '--hero-height', height);
145
+ };
146
+
147
+ /**
148
+ * Main function that applies all query parameter configurations to the page.
149
+ * Reads URL search params and applies header visibility, background, typography, and section colors.
150
+ */
151
+ export const applyQueryParams = (): void => {
152
+ const params = new URLSearchParams(globalThis.location.search);
153
+
154
+ applyHeaderImageVisibility(params);
155
+ applyTransparentBackground(params);
156
+ applyTypographyColors(params);
157
+ applySectionBackgroundColors(params);
158
+ applyHeroHeight(params);
159
+ };
package/tsconfig.json CHANGED
@@ -5,7 +5,8 @@
5
5
  "compilerOptions": {
6
6
  "baseUrl": ".",
7
7
  "paths": {
8
- "@/*": ["src/*"]
8
+ "@/*": ["src/*"],
9
+ "@simple-photo-gallery/common/src/*": ["../../common/src/*"]
9
10
  }
10
11
  }
11
12
  }