desy-html 16.0.2 → 16.0.4

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/AGENTS.md CHANGED
@@ -155,8 +155,9 @@ desy-html/
155
155
 
156
156
  To customize for different organizations:
157
157
  1. Edit `branding/branding.config.js` or create `branding/branding.config.{name}.js`
158
- 2. Replace logos in `branding/logos/`
159
- 3. Run `BRANDING_CONFIG={name} npm run build`
158
+ 2. Add favicon files to `branding/logos/` (favicon.svg, favicon.ico, apple-touch-icon.png). The plugin automatically copies them to `/dist/images/` during build.
159
+ 3. Replace logos in `branding/logos/`
160
+ 4. Run `BRANDING_CONFIG={name} npm run build`
160
161
 
161
162
  ## Common Patterns
162
163
 
@@ -175,6 +176,32 @@ To customize for different organizations:
175
176
  2. Export function that accepts `aria` namespace
176
177
  3. Register in `src/js/desy-html.js`
177
178
 
179
+ ## Post-Implementation Documentation Review
180
+
181
+ After making code changes, review if documentation needs updates:
182
+
183
+ ### Checklist
184
+
185
+ - [ ] **AGENTS.md** - If adding new commands, patterns, or workflows
186
+ - [ ] **README.md** - If changing project setup or usage
187
+ - [ ] **TESTING_PLAN.md** - If adding new test scenarios
188
+ - [ ] **branding/BRANDING.md** - If changing branding configuration
189
+ - [ ] **Other .md files** - Check for relevant changes
190
+
191
+ ### When to Update
192
+
193
+ | Change Type | Files to Review |
194
+ | ----------- | --------------- |
195
+ | New feature | AGENTS.md, README.md, possibly TESTING_PLAN.md |
196
+ | Config change | BRANDING.md, AGENTS.md |
197
+ | Bug fix | TESTING_PLAN.md if adding test scenarios |
198
+ | Documentation only | Only the .md files being changed |
199
+
200
+ **Tip**: After any technical change, run a quick grep to find relevant .md files:
201
+ ```bash
202
+ grep -r "keyword" --include="*.md"
203
+ ```
204
+
178
205
  ## License
179
206
 
180
207
  This project uses EUPL-1.2 license. See EUPL-1.2.txt for details.
package/TESTING_PLAN.md CHANGED
@@ -27,6 +27,10 @@ This document defines the complete testing plan to execute before publishing the
27
27
  - [ ] Verify background images exist:
28
28
  - `branding/images/header-background.svg`
29
29
  - `branding/images/header-background-lg.svg`
30
+ - [ ] Verify favicon files exist:
31
+ - `branding/logos/favicon.svg`
32
+ - `branding/logos/favicon.ico`
33
+ - `branding/logos/apple-touch-icon.png`
30
34
 
31
35
  ### 1.2. package.json Exports Review
32
36
 
@@ -53,6 +57,10 @@ This document defines the complete testing plan to execute before publishing the
53
57
  - Organization logos (aragon-*.svg)
54
58
  - EU logos (*.svg in subfolder or root)
55
59
  - Background images (header-background*.svg)
60
+ - [ ] Verify favicon files are copied to dist/images/:
61
+ - `dist/images/favicon.svg`
62
+ - `dist/images/favicon.ico`
63
+ - `dist/images/apple-touch-icon.png`
56
64
 
57
65
  ### 2.3. Production Paths Verification
58
66
 
@@ -75,6 +83,7 @@ Using the browser agent, test the following pages:
75
83
  - [ ] Verify organization logo displays (not broken, no 404)
76
84
  - [ ] Verify primary colors are Aragón's (#00607a)
77
85
  - [ ] Verify typography is correct (Open Sans)
86
+ - [ ] Verify favicon displays in browser tab (all 3: svg, ico, apple-touch-icon in /images/)
78
87
 
79
88
  #### Header
80
89
 
@@ -351,6 +360,7 @@ The project is ready for npm publishing when:
351
360
  - [ ] Organization logos display correctly
352
361
  - [ ] EU logos display correctly
353
362
  - [ ] Header background images display correctly
363
+ - [ ] Favicon files are generated and load correctly
354
364
  - [ ] All interactive components work correctly
355
365
  - [ ] No 404 errors in console
356
366
  - [ ] No JavaScript errors in console
@@ -29,6 +29,11 @@ export default {
29
29
  plurifondo: '/branding/logos/eu/logo-plurifondo.svg',
30
30
  },
31
31
  },
32
+ favicon: {
33
+ svg: '/branding/logos/favicon.svg',
34
+ ico: '/branding/logos/favicon.ico',
35
+ appleTouch: '/branding/logos/apple-touch-icon.png'
36
+ },
32
37
  };
33
38
  ```
34
39
 
@@ -133,6 +138,21 @@ Additional images.
133
138
  | `headerBackground` | string | No | Header background image |
134
139
  | `headerBackgroundLg` | string | No | Large header background image |
135
140
 
141
+ ### favicon
142
+
143
+ Favicon configuration for browser tabs and mobile devices.
144
+
145
+ | Field | Type | Required | Size | Description |
146
+ | ------------------ | ------ | -------- | --------- | ---------------------------------------------------------- |
147
+ | `favicon.svg` | string | Yes | 32×32 | Main favicon in SVG format (modern browsers) |
148
+ | `favicon.ico` | string | Yes | 32×32 | Legacy favicon in ICO format (fallback for older browsers) |
149
+ | `favicon.appleTouch` | string | Yes | 180×180 | Apple Touch Icon for iOS home screen |
150
+
151
+ > **Note:** For optimal compatibility, use the following sizes: 32×32 for browser tabs (both SVG and ICO), and 180×180 for Apple Touch Icon. The vite-branding-plugin automatically copies favicon files to `/dist/images/` during build and rewrites the HTML paths:
152
+ > - `favicon.svg` → `/dist/images/favicon.svg`
153
+ > - `favicon.ico` → `/dist/images/favicon.ico`
154
+ > - `apple-touch-icon.png` → `/dist/images/apple-touch-icon.png`
155
+
136
156
  ## CSS Variables
137
157
 
138
158
  The following CSS variables are available for runtime customization:
@@ -197,6 +217,9 @@ You only need:
197
217
  - `logos.organization.expanded`
198
218
  - `logos.organization.mini`
199
219
  - `logos.organization.alt`
220
+ - `favicon.svg`
221
+ - `favicon.ico`
222
+ - `favicon.appleTouch`
200
223
 
201
224
  See `branding/branding.config.yourorganization.js` for a minimal example.
202
225
 
@@ -339,6 +362,12 @@ export default {
339
362
  headerBackground: '/branding/images/header-background.svg',
340
363
  headerBackgroundLg: '/branding/images/header-background-lg.svg',
341
364
  },
365
+
366
+ favicon: {
367
+ svg: '/branding/logos/favicon.svg',
368
+ ico: '/branding/logos/favicon.ico',
369
+ appleTouch: '/branding/logos/apple-touch-icon.png',
370
+ },
342
371
  };
343
372
  ```
344
373
 
@@ -66,4 +66,11 @@ export default {
66
66
  headerBackground: '/branding/images/header-background.svg',
67
67
  headerBackgroundLg: '/branding/images/header-background-lg.svg',
68
68
  },
69
+
70
+ // Favicon Configuration
71
+ favicon: {
72
+ svg: '/branding/logos/favicon.svg',
73
+ ico: '/branding/logos/favicon.ico',
74
+ appleTouch: '/branding/logos/apple-touch-icon.png'
75
+ },
69
76
  };
@@ -62,4 +62,11 @@ export default {
62
62
  headerBackground: '/branding/images/header-background.svg',
63
63
  headerBackgroundLg: '/branding/images/header-background-lg.svg',
64
64
  },
65
+
66
+ // Favicon Configuration
67
+ favicon: {
68
+ svg: '/branding/logos/yourorganization-favicon.svg',
69
+ ico: '/branding/logos/yourorganization-favicon.ico',
70
+ appleTouch: '/branding/logos/yourorganization-apple-touch-icon.png'
71
+ },
65
72
  };
Binary file
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" aria-label="Ir a la página de inicio de la aplicación" role="img"><defs><clipPath id="b-logo-mini"><path fill="rgb(252, 228, 0)" d="M0 0h32v32.001H0z"/></clipPath><clipPath id="a-logo-mini"><path d="M0 0h32v32H0z"/></clipPath></defs><g clip-path="url(#a-logo-mini)"><path fill="rgb(252, 228, 0)" d="M0 .305h32v32.001H0z"/><g clip-path="url(#b-logo-mini)" transform="translate(0 .305)"><g fill="#dd171b" fill-rule="evenodd"><path d="m31.997 6.145-7.686 1.539a14.764 14.764 0 0 1-8.028-1.042 15.267 15.267 0 0 0-5.073-1.846 12.725 12.725 0 0 0-3.59-.011l-5.13.918a94.41 94.41 0 0 1-2.491.442V.324a7.213 7.213 0 0 1 3.952-.09 10.087 10.087 0 0 1 2.118.951 17.859 17.859 0 0 0 4.36 1.993 14.13 14.13 0 0 0 6.7-.034l4.8-.872 5.016-.906 5.048-1.04ZM6.705 24.619a14.812 14.812 0 0 1 9.7 1.03 12.363 12.363 0 0 0 8.437 1.529l7.154-1.291v5.8a8.37 8.37 0 0 1-3.055.26 6.509 6.509 0 0 1-1.619-.464l-3.714-1.948a12.4 12.4 0 0 0-7.2-.838l-15.366 2.82L0 31.686v-5.8l1.28-.26 3.363-.623c.679-.125 1.393-.249 2.061-.385ZM-.003 15.32v-4.462l13.23-2.417a15.734 15.734 0 0 1 9.252 1.665 12.723 12.723 0 0 0 8.606.94l.914-.192v4.462L29.08 13.65a12.472 12.472 0 0 0-6.941-1.031l-8.131 1.483c-.974.182-2.921.532-2.921.532l-7.406 1.371a5.23 5.23 0 0 1-3.684-.685ZM31.997 16.851v4.393l-13.11 2.413a15.735 15.735 0 0 1-9.252-1.665 12.721 12.721 0 0 0-8.606-.94l-1.03.193v-4.394l3.035 1.6a12.476 12.476 0 0 0 6.941 1.03l8.13-1.483c.974-.182 2.922-.532 2.922-.532l7.406-1.371a5.219 5.219 0 0 1 3.564.756Z"/></g></g></g></svg>
@@ -0,0 +1,13 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" aria-label="YourLogo" role="img">
2
+ <defs>
3
+ <clipPath id="clip-hex">
4
+ <path d="M16 1.5L29 9V23L16 30.5L3 23V9L16 1.5Z"/>
5
+ </clipPath>
6
+ </defs>
7
+ <!-- Hexagono exterior -->
8
+ <path d="M16 1.5L29 9V23L16 30.5L3 23V9L16 1.5Z" fill="#00607a" stroke="#00475c" stroke-width="1"/>
9
+ <!-- Cuadrado interior -->
10
+ <rect x="10" y="10" width="12" height="12" rx="1" fill="#ffffff"/>
11
+ <!-- Círculo centro -->
12
+ <circle cx="16" cy="16" r="3" fill="#00607a"/>
13
+ </svg>
@@ -121,6 +121,99 @@ export function brandingPlugin(config) {
121
121
  }
122
122
 
123
123
  return hasChanges ? { code: transformed, map: null } : null;
124
+ },
125
+
126
+ closeBundle() {
127
+ const distDir = path.resolve(process.cwd(), 'dist');
128
+ const imagesDir = path.resolve(process.cwd(), 'dist/images');
129
+ const favicon = config?.favicon;
130
+
131
+ // Early exit if no favicon configuration
132
+ if (!favicon) return;
133
+
134
+ // Helper function to recursively find HTML files
135
+ const findHtmlFiles = (dir, files = []) => {
136
+ if (!fs.existsSync(dir)) return files;
137
+ const items = fs.readdirSync(dir, { withFileTypes: true });
138
+ for (const item of items) {
139
+ const fullPath = path.join(dir, item.name);
140
+ if (item.isDirectory()) {
141
+ findHtmlFiles(fullPath, files);
142
+ } else if (item.name.endsWith('.html')) {
143
+ files.push(fullPath);
144
+ }
145
+ }
146
+ return files;
147
+ };
148
+
149
+ const faviconFiles = [
150
+ { key: 'svg', fileName: 'favicon.svg' },
151
+ { key: 'ico', fileName: 'favicon.ico' },
152
+ { key: 'appleTouch', fileName: 'apple-touch-icon.png' }
153
+ ];
154
+
155
+ // All go to imagesDir
156
+ const destDir = imagesDir;
157
+
158
+ for (const { key, fileName } of faviconFiles) {
159
+ const faviconPath = favicon[key];
160
+ if (!faviconPath) continue;
161
+
162
+ // Extraer el nombre del archivo de la ruta configurada
163
+ const fileNameFromPath = path.basename(faviconPath);
164
+ const src = path.resolve(process.cwd(), faviconPath.slice(1)); // Quitar el / inicial
165
+
166
+ if (fs.existsSync(src)) {
167
+ try {
168
+ // Ensure destination directory exists
169
+ if (!fs.existsSync(destDir)) {
170
+ fs.mkdirSync(destDir, { recursive: true });
171
+ }
172
+ fs.copyFileSync(src, path.join(destDir, fileNameFromPath));
173
+ console.log(`✓ Favicon ${fileNameFromPath}: branding/logos/${fileNameFromPath} → dist/images/`);
174
+ } catch (err) {
175
+ console.warn(`Warning: Could not copy ${fileNameFromPath}:`, err.message);
176
+ }
177
+ }
178
+ }
179
+
180
+ // Rewrite HTML files to update favicon href paths
181
+ // Note: This is now handled in vite.config.js after HTML generation (rewriteFaviconPaths)
182
+ // Kept here for reference but not executed (HTML files don't exist yet at this point)
183
+ try {
184
+ const htmlFiles = findHtmlFiles(distDir);
185
+
186
+ for (const htmlFile of htmlFiles) {
187
+ let content = fs.readFileSync(htmlFile, 'utf8');
188
+ let modified = content;
189
+
190
+ // Rewrite favicon hrefs from /branding/logos/ to ./images/
191
+ // Only rewrite if the file was actually copied (exists in imagesDir)
192
+ for (const { key } of faviconFiles) {
193
+ const faviconPath = favicon[key];
194
+ if (!faviconPath) continue;
195
+
196
+ const fileNameFromPath = path.basename(faviconPath);
197
+ const sourcePath = faviconPath; // e.g., "/branding/logos/favicon.svg"
198
+ const destPath = `./images/${fileNameFromPath}`;
199
+
200
+ // Only rewrite if the destination file exists
201
+ const destFilePath = path.join(destDir, fileNameFromPath);
202
+ if (fs.existsSync(destFilePath)) {
203
+ // Simple string replacement - sourcePath is like "/branding/logos/favicon.svg"
204
+ const oldHref = `href="${sourcePath}"`;
205
+ const newHref = `href="${destPath}"`;
206
+ modified = modified.replaceAll(oldHref, newHref);
207
+ }
208
+ }
209
+
210
+ if (modified !== content) {
211
+ fs.writeFileSync(htmlFile, modified);
212
+ }
213
+ }
214
+ } catch (err) {
215
+ // Silently ignore - favicon rewriting is handled in vite.config.js
216
+ }
124
217
  }
125
218
  };
126
219
  }
@@ -5,7 +5,6 @@
5
5
  <meta name="viewport" content="width=1=device-width, initial-scale=1.0">
6
6
  <title>{{ title if title else "desy-html docs" }}</title>
7
7
  {% if description %}<meta name="description" content="{{ description }}">{% endif %}
8
- <link rel="icon" type="image/x-icon" href="https://aplicaciones.aragon.es/favicon.ico">
9
8
  {% if branding and branding.typography and branding.typography.fontUrl %}
10
9
  {% if 'fonts.googleapis.com' in branding.typography.fontUrl %}
11
10
  <link rel="preconnect" href="https://fonts.googleapis.com">
@@ -18,6 +17,13 @@
18
17
  <link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,400;0,600;0,700;1,400;1,600;1,700&display=swap" rel="stylesheet">
19
18
  {% endif %}
20
19
  <link rel="stylesheet" href="css/styles.css">
20
+ {% if branding and branding.favicon %}
21
+ <link rel="icon" href="{{ branding.favicon.svg }}" type="image/svg+xml">
22
+ <link rel="icon" href="{{ branding.favicon.ico }}" sizes="32x32">
23
+ <link rel="apple-touch-icon" href="{{ branding.favicon.appleTouch }}">
24
+ {% else %}
25
+ <link rel="icon" type="image/x-icon" href="https://aplicaciones.aragon.es/favicon.ico">
26
+ {% endif %}
21
27
  <style>
22
28
  pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
23
29
  Theme: StackOverflow Light
package/docs/index.html CHANGED
@@ -147,6 +147,17 @@ cd desy-html</code></pre>
147
147
 
148
148
  <h2>Changelog (English)</h2>
149
149
  <p>What's new in the latest version of desy-html</p>
150
+ <h3>v.16.0.4</h3>
151
+ <ul class="text-sm">
152
+ <li>Fixed env vars in Windows to allow branding configuration.</li>
153
+ <li>Minor fixes.</li>
154
+ </ul>
155
+ <h3>v.16.0.3</h3>
156
+ <ul class="text-sm">
157
+ <li>Added favicon to branding configuration and vite plugin.</li>
158
+ <li>Fixed breakpoints variants in text classes.</li>
159
+ <li>Added missing params in header components.</li>
160
+ </ul>
150
161
  <h3>v.16.0.2</h3>
151
162
  <ul class="text-sm">
152
163
  <li>Fixed a bug in footer logos urls.</li>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "desy-html",
3
- "version": "16.0.2",
3
+ "version": "16.0.4",
4
4
  "description": "desy-html contains the code you need to start building a user interface for Gobierno de Aragón government webapps.",
5
5
  "type": "module",
6
6
  "author": {
@@ -30,27 +30,30 @@
30
30
  },
31
31
  "scripts": {
32
32
  "dev": "vite",
33
- "dev:yourorganization": "BRANDING_CONFIG=yourorganization vite",
33
+ "dev:yourorganization": "cross-env BRANDING_CONFIG=yourorganization npm run dev",
34
34
  "build": "vite build",
35
- "preview": "vite preview"
35
+ "build:yourorganization": "cross-env BRANDING_CONFIG=yourorganization npm run build",
36
+ "preview": "vite preview",
37
+ "preview:yourorganization": "cross-env BRANDING_CONFIG=yourorganization npm run preview"
36
38
  },
37
39
  "dependencies": {
38
40
  "@floating-ui/dom": "^1.6.13",
41
+ "@tailwindcss/forms": "^0.5.10",
42
+ "@tailwindcss/typography": "^0.5.18",
39
43
  "@tailwindcss/vite": "^4.1.17",
40
44
  "autoprefixer": "^10.4.21",
41
45
  "cally": "^0.8.0",
42
46
  "chokidar": "^3.6.0",
43
47
  "hex-rgb": "^5.0.0",
44
48
  "js-yaml": "^4.1.0",
45
- "tailwindcss": "^4.1.17",
46
- "@tailwindcss/forms": "^0.5.10",
47
- "@tailwindcss/typography": "^0.5.18"
49
+ "tailwindcss": "^4.1.17"
48
50
  },
49
51
  "devDependencies": {
52
+ "cross-env": "^10.1.0",
50
53
  "glob": "^11.0.1",
51
54
  "highlight.js": "^11.11.1",
52
- "nunjucks": "^3.2.4",
53
55
  "js-beautify": "^1.14.11",
56
+ "nunjucks": "^3.2.4",
54
57
  "outdent": "^0.8.0",
55
58
  "sharp": "^0.34.3",
56
59
  "vite": "^7.1.6"
@@ -0,0 +1,9 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" aria-label="Demo Icon" role="img">
2
+ <!-- Face circle -->
3
+ <circle cx="16" cy="16" r="14" fill="none" stroke="currentColor" stroke-width="2"/>
4
+ <!-- Eyes -->
5
+ <circle cx="10" cy="12" r="2" fill="currentColor"/>
6
+ <circle cx="22" cy="12" r="2" fill="currentColor"/>
7
+ <!-- Smile -->
8
+ <path d="M10 20 Q16 26 22 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
9
+ </svg>
@@ -2,169 +2,167 @@
2
2
  text.css
3
3
  ========================================================================== */
4
4
 
5
- @layer components {
6
- .c-h0 {
7
- @apply mb-8;
8
- font-size: 2.5rem;
9
- font-family: var(--font-heading);
10
- @apply font-bold;
11
- @apply leading-tight;
12
- }
5
+ @utility c-h0 {
6
+ @apply mb-8;
7
+ font-size: 2.5rem;
8
+ font-family: var(--font-heading);
9
+ @apply font-bold;
10
+ @apply leading-tight;
11
+ }
13
12
 
14
- .c-h1 {
15
- @apply mb-lg;
16
- @apply text-3xl;
17
- font-family: var(--font-heading);
18
- @apply font-bold;
19
- @apply leading-tight;
20
- }
13
+ @utility c-h1 {
14
+ @apply mb-lg;
15
+ @apply text-3xl;
16
+ font-family: var(--font-heading);
17
+ @apply font-bold;
18
+ @apply leading-tight;
19
+ }
21
20
 
22
- .c-h2 {
23
- @apply mb-base;
24
- @apply text-2xl;
25
- font-family: var(--font-heading);
26
- @apply font-bold;
27
- @apply leading-tight;
28
- }
21
+ @utility c-h2 {
22
+ @apply mb-base;
23
+ @apply text-2xl;
24
+ font-family: var(--font-heading);
25
+ @apply font-bold;
26
+ @apply leading-tight;
27
+ }
29
28
 
30
- .c-h3 {
31
- @apply mb-sm;
32
- @apply text-lg;
33
- font-family: var(--font-heading);
34
- @apply font-bold;
35
- @apply leading-tight;
36
- }
29
+ @utility c-h3 {
30
+ @apply mb-sm;
31
+ @apply text-lg;
32
+ font-family: var(--font-heading);
33
+ @apply font-bold;
34
+ @apply leading-tight;
35
+ }
37
36
 
38
- .c-h4 {
39
- @apply mb-sm;
40
- @apply text-base;
41
- font-family: var(--font-heading);
42
- @apply font-bold;
43
- @apply leading-tight;
44
- }
37
+ @utility c-h4 {
38
+ @apply mb-sm;
39
+ @apply text-base;
40
+ font-family: var(--font-heading);
41
+ @apply font-bold;
42
+ @apply leading-tight;
43
+ }
45
44
 
46
- .c-link {
47
- @apply text-primary-base;
48
- @apply underline;
45
+ @utility c-link {
46
+ @apply text-primary-base;
47
+ @apply underline;
49
48
 
50
- &:hover {
51
- @apply text-primary-dark;
52
- }
49
+ &:hover {
50
+ @apply text-primary-dark;
51
+ }
53
52
 
54
- &:focus {
55
- @apply bg-warning-base;
56
- @apply shadow-outline-focus;
57
- @apply outline-hidden;
58
- @apply text-black;
59
- }
53
+ &:focus {
54
+ @apply bg-warning-base;
55
+ @apply shadow-outline-focus;
56
+ @apply outline-hidden;
57
+ @apply text-black;
60
58
  }
59
+ }
61
60
 
62
- .c-link--alert {
63
- @apply text-alert-base;
64
- @apply underline;
65
- @apply font-semibold;
61
+ @utility c-link--alert {
62
+ @apply text-alert-base;
63
+ @apply underline;
64
+ @apply font-semibold;
66
65
 
67
- &:hover {
68
- @apply text-alert-dark;
69
- }
66
+ &:hover {
67
+ @apply text-alert-dark;
70
68
  }
69
+ }
71
70
 
72
- .c-link--neutral {
73
- @apply text-neutral-dark;
74
- @apply underline;
71
+ @utility c-link--neutral {
72
+ @apply text-neutral-dark;
73
+ @apply underline;
75
74
 
76
- &:hover {
77
- @apply text-black;
78
- }
75
+ &:hover {
76
+ @apply text-black;
79
77
  }
78
+ }
80
79
 
81
- .c-link--full {
82
- &::after {
83
- content: '';
84
- @apply absolute;
85
- @apply inset-0;
86
- }
80
+ @utility c-link--full {
81
+ &::after {
82
+ content: "";
83
+ @apply absolute;
84
+ @apply inset-0;
87
85
  }
86
+ }
88
87
 
89
- .c-link--no-underline {
90
- @apply no-underline;
88
+ @utility c-link--no-underline {
89
+ @apply no-underline;
91
90
 
92
- &:hover {
93
- @apply underline;
94
- }
91
+ &:hover {
92
+ @apply underline;
95
93
  }
94
+ }
96
95
 
97
- .c-paragraph-lg {
98
- @apply mb-lg;
99
- @apply text-lg;
100
- }
96
+ @utility c-paragraph-lg {
97
+ @apply mb-lg;
98
+ @apply text-lg;
99
+ }
101
100
 
102
- .c-paragraph-base {
103
- @apply mb-base;
104
- @apply text-base;
105
- }
101
+ @utility c-paragraph-base {
102
+ @apply mb-base;
103
+ @apply text-base;
104
+ }
106
105
 
107
- .c-paragraph-sm {
108
- @apply mb-sm;
109
- @apply text-sm;
110
- }
106
+ @utility c-paragraph-sm {
107
+ @apply mb-sm;
108
+ @apply text-sm;
109
+ }
110
+
111
+ @utility c-ul {
112
+ @apply mb-base;
113
+ @apply list-none;
111
114
 
112
- .c-ul {
115
+ li {
116
+ @apply relative;
113
117
  @apply mb-base;
114
- @apply list-none;
115
-
116
- li {
117
- @apply relative;
118
- @apply mb-base;
119
- @apply pl-8;
120
-
121
- &::before {
122
- content: '';
123
- @apply absolute;
124
- top: 0.625rem;
125
- left: 0.25rem;
126
- @apply w-1.5;
127
- @apply h-1.5;
128
- @apply bg-black;
129
- @apply rounded-full;
130
- }
131
-
132
- &:last-of-type {
133
- @apply mb-0;
134
- }
118
+ @apply pl-8;
119
+
120
+ &::before {
121
+ content: "";
122
+ @apply absolute;
123
+ top: 0.625rem;
124
+ left: 0.25rem;
125
+ @apply w-1.5;
126
+ @apply h-1.5;
127
+ @apply bg-black;
128
+ @apply rounded-full;
129
+ }
130
+
131
+ &:last-of-type {
132
+ @apply mb-0;
135
133
  }
136
134
  }
135
+ }
137
136
 
138
- .c-ul--no-bullets {
139
- li {
140
- @apply pl-0;
137
+ @utility c-ul--no-bullets {
138
+ li {
139
+ @apply pl-0;
141
140
 
142
- &::before {
143
- @apply hidden;
144
- }
141
+ &::before {
142
+ @apply hidden;
145
143
  }
146
144
  }
145
+ }
147
146
 
148
- .c-ol {
147
+ @utility c-ol {
148
+ @apply mb-base;
149
+ counter-reset: list-counter;
150
+
151
+ li {
152
+ @apply relative;
149
153
  @apply mb-base;
150
- counter-reset: list-counter;
151
-
152
- li {
153
- @apply relative;
154
- @apply mb-base;
155
- @apply pl-8;
156
-
157
- &::before {
158
- counter-increment: list-counter;
159
- content: counter(list-counter) '.';
160
- @apply absolute;
161
- left: 0.25rem;
162
- @apply text-black;
163
- }
164
-
165
- &:last-of-type {
166
- @apply mb-0;
167
- }
154
+ @apply pl-8;
155
+
156
+ &::before {
157
+ counter-increment: list-counter;
158
+ content: counter(list-counter) ".";
159
+ @apply absolute;
160
+ left: 0.25rem;
161
+ @apply text-black;
162
+ }
163
+
164
+ &:last-of-type {
165
+ @apply mb-0;
168
166
  }
169
167
  }
170
168
  }
@@ -4,8 +4,6 @@
4
4
  @import "tailwindcss";
5
5
  /* Custom base */
6
6
  @import './base.css';
7
- /* Branding variables for runtime customization */
8
- @import './branding-variables.css';
9
7
 
10
8
  /* Custom components */
11
9
  @import './component.text.css';
@@ -3,6 +3,21 @@ params:
3
3
  type: component
4
4
  required: false
5
5
  description: The skipLink component parameters
6
+ - name: logoExpanded
7
+ type: string
8
+ required: false
9
+ default: branding.logos.organization.expanded
10
+ description: URL del logo expandido (con texto). Por defecto usa branding.logos.organization.expanded
11
+ - name: logoCompact
12
+ type: string
13
+ required: false
14
+ default: branding.logos.organization.compact
15
+ description: URL del logo compacto (solo icono). Por defecto usa branding.logos.organization.compact
16
+ - name: logoAlt
17
+ type: string
18
+ required: false
19
+ default: branding.logos.organization.alt
20
+ description: Texto alternativo del logo. Por defecto usa branding.logos.organization.alt
6
21
  - name: homepageUrl
7
22
  type: string
8
23
  required: false
@@ -43,7 +58,7 @@ params:
43
58
  type: object
44
59
  required: false
45
60
  description: Options for the subnav at right.
46
- params:
61
+ params:
47
62
  - name: text
48
63
  type: string
49
64
  required: true
@@ -74,7 +89,7 @@ params:
74
89
  description: HTML attributes (for example data attributes) to add to the dropdown element.
75
90
  - name: contentHtml
76
91
  type: string
77
- required: true
92
+ required: false
78
93
  description: Html content inside the subnav once opened.
79
94
  - name: items
80
95
  type: array
@@ -125,7 +140,7 @@ params:
125
140
  type: object
126
141
  required: false
127
142
  description: Options for the dropdown at right.
128
- params:
143
+ params:
129
144
  - name: text
130
145
  type: string
131
146
  required: true
@@ -156,7 +171,7 @@ params:
156
171
  description: HTML attributes (for example data attributes) to add to the dropdown element.
157
172
  - name: contentHtml
158
173
  type: string
159
- required: true
174
+ required: false
160
175
  description: Html content inside the dropdown once opened.
161
176
  - name: items
162
177
  type: array
@@ -207,7 +222,7 @@ params:
207
222
  type: object
208
223
  required: false
209
224
  description: Options for the navigation main menu.
210
- params:
225
+ params:
211
226
  - name: classes
212
227
  type: string
213
228
  required: false
@@ -249,7 +264,7 @@ params:
249
264
  type: object
250
265
  required: false
251
266
  description: Options for the offcanvas menu.
252
- params:
267
+ params:
253
268
  - name: text
254
269
  type: string
255
270
  required: true
@@ -11,10 +11,12 @@ params:
11
11
  type: object
12
12
  required: false
13
13
  description: This is an area over the title
14
+ params:
14
15
  - name: logo
15
16
  type: object
16
17
  required: false
17
18
  description: options for the logo element
19
+ params:
18
20
  - name: url
19
21
  type: string
20
22
  required: true
@@ -143,7 +145,7 @@ params:
143
145
  type: object
144
146
  required: false
145
147
  description: Options for the dropdown at right.
146
- params:
148
+ params:
147
149
  - name: text
148
150
  type: string
149
151
  required: true
@@ -174,7 +176,7 @@ params:
174
176
  description: HTML attributes (for example data attributes) to add to the dropdown element.
175
177
  - name: contentHtml
176
178
  type: string
177
- required: true
179
+ required: false
178
180
  description: Html content inside the dropdown once opened.
179
181
  - name: items
180
182
  type: array
@@ -225,7 +227,7 @@ params:
225
227
  type: object
226
228
  required: false
227
229
  description: Options for the navigation main menu.
228
- params:
230
+ params:
229
231
  - name: classes
230
232
  type: string
231
233
  required: false
@@ -266,7 +268,7 @@ params:
266
268
  - name: sub
267
269
  type: object
268
270
  required: false
269
- description: This is an area over the title
271
+ description: This is an area under the title
270
272
  - name: logo
271
273
  type: object
272
274
  required: false
@@ -294,7 +296,7 @@ params:
294
296
  - name: backgroundFullColor
295
297
  type: string
296
298
  required: true
297
- description: The css color used in the background image that fills all the super area.
299
+ description: The css color used in the background image that fills all the sub area.
298
300
  - name: backgroundFullUrl
299
301
  type: string
300
302
  required: false
@@ -315,7 +317,11 @@ params:
315
317
  type: object
316
318
  required: false
317
319
  description: Options for the offcanvas menu.
318
- params:
320
+ params:
321
+ - name: labelledId
322
+ type: string
323
+ required: false
324
+ description: ID para conectar con aria-labelledby del offcanvas. Útil para accesibilidad.
319
325
  - name: text
320
326
  type: string
321
327
  required: true
@@ -1,4 +1,14 @@
1
1
  params:
2
+ - name: logoSrc
3
+ type: string
4
+ required: false
5
+ default: branding.logos.organization.mini
6
+ description: URL del logo de la organización. Por defecto usa el valor de branding.logos.organization.mini
7
+ - name: logoAlt
8
+ type: string
9
+ required: false
10
+ default: branding.logos.organization.alt
11
+ description: Texto alternativo del logo. Por defecto usa el valor de branding.logos.organization.alt
2
12
  - name: homepageUrl
3
13
  type: string
4
14
  required: false
@@ -5,7 +5,13 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>{{ title if title else "Project title" }}</title>
7
7
  <link rel="stylesheet" href="/src/css/styles.css">
8
- <link rel="icon" type="image/x-icon" href="https://aplicaciones.aragon.es/favicon.ico">
8
+ {% if branding and branding.favicon %}
9
+ <link rel="icon" href="{{ branding.favicon.svg }}" type="image/svg+xml">
10
+ <link rel="icon" href="{{ branding.favicon.ico }}" sizes="32x32">
11
+ <link rel="apple-touch-icon" href="{{ branding.favicon.appleTouch }}">
12
+ {% else %}
13
+ <link rel="icon" type="image/x-icon" href="https://aplicaciones.aragon.es/favicon.ico">
14
+ {% endif %}
9
15
  {% if branding and branding.typography and branding.typography.fontUrl %}
10
16
  {% if 'fonts.googleapis.com' in branding.typography.fontUrl %}
11
17
  <link rel="preconnect" href="https://fonts.googleapis.com">
package/vite.config.js CHANGED
@@ -18,6 +18,28 @@ const brandingConfig = await loadBrandingConfig(
18
18
  'branding'
19
19
  );
20
20
 
21
+ // Helper para servir archivos con el MIME type correcto
22
+ function serveFileWithMimeType(filePath, res) {
23
+ if (!fs.existsSync(filePath)) return false;
24
+
25
+ const ext = path.extname(filePath).toLowerCase();
26
+ const mimeTypes = {
27
+ '.svg': 'image/svg+xml',
28
+ '.png': 'image/png',
29
+ '.jpg': 'image/jpeg',
30
+ '.jpeg': 'image/jpeg',
31
+ '.webp': 'image/webp',
32
+ '.ico': 'image/x-icon',
33
+ '.js': 'application/javascript',
34
+ '.css': 'text/css',
35
+ '.html': 'text/html'
36
+ };
37
+
38
+ res.setHeader('Content-Type', mimeTypes[ext] || 'application/octet-stream');
39
+ res.end(fs.readFileSync(filePath));
40
+ return true;
41
+ }
42
+
21
43
  // Helper functions
22
44
  function kebabCaseToPascalCase(value) {
23
45
  return value
@@ -588,32 +610,76 @@ async function rewriteHtmlImagePaths() {
588
610
 
589
611
  const htmlFiles = await glob('**/*.html', { cwd: distDir, nodir: true });
590
612
 
613
+ // Configuración centralizada de rewrites
614
+ const rewriteRules = [
615
+ // Imágenes en /images/
616
+ { pattern: /src="(\/images\/)/g, replacement: 'src="./images/' },
617
+ { pattern: /srcset="(\/images\/)/g, replacement: 'srcset="./images/' },
618
+ // Imágenes en /branding/logos/
619
+ { pattern: /src="(\/branding\/logos\/)/g, replacement: 'src="./images/' },
620
+ { pattern: /srcset="(\/branding\/logos\/)/g, replacement: 'srcset="./images/' },
621
+ // Imágenes en /branding/images/
622
+ { pattern: /src="(\/branding\/images\/)/g, replacement: 'src="./images/' },
623
+ { pattern: /srcset="(\/branding\/images\/)/g, replacement: 'srcset="./images/' },
624
+ ];
625
+
591
626
  for (const htmlFile of htmlFiles) {
592
627
  const filePath = path.join(distDir, htmlFile);
593
628
  let content = await fs.promises.readFile(filePath, 'utf8');
594
629
 
595
- // Replace src="/images/ with src="./images/
596
- let modified = content.replace(/src="(\/images\/)/g, 'src="./images/');
597
-
598
- // Replace srcset="/images/ with srcset="./images/
599
- modified = modified.replace(/srcset="(\/images\/)/g, 'srcset="./images/');
630
+ // Aplicar todas las reglas
631
+ let modified = content;
632
+ for (const rule of rewriteRules) {
633
+ modified = modified.replace(rule.pattern, rule.replacement);
634
+ }
600
635
 
601
- // Replace src="/branding/logos/ with src="./images/
602
- modified = modified.replace(/src="(\/branding\/logos\/)/g, 'src="./images/');
636
+ if (modified !== content) {
637
+ await fs.promises.writeFile(filePath, modified);
638
+ }
639
+ }
640
+ }
603
641
 
604
- // Replace srcset="/branding/logos/ with srcset="./images/
605
- modified = modified.replace(/srcset="(\/branding\/logos\/)/g, 'srcset="./images/');
642
+ // Rewrite favicon hrefs from /branding/logos/ to ./images/ (after HTML files are generated)
643
+ async function rewriteFaviconPaths() {
644
+ const distDir = path.resolve(process.cwd(), 'dist');
645
+ const imagesDir = path.resolve(process.cwd(), 'dist/images');
646
+ if (!fs.existsSync(distDir)) return;
606
647
 
607
- // Replace src="/branding/images/ with src="./images/
608
- modified = modified.replace(/src="(\/branding\/images\/)/g, 'src="./images/');
648
+ const htmlFiles = await glob('**/*.html', { cwd: distDir, nodir: true });
649
+
650
+ // Favicon files to rewrite
651
+ const faviconFiles = [
652
+ 'favicon.svg',
653
+ 'favicon.ico',
654
+ 'apple-touch-icon.png'
655
+ ];
609
656
 
610
- // Replace srcset="/branding/images/ with srcset="./images/
611
- modified = modified.replace(/srcset="(\/branding\/images\/)/g, 'srcset="./images/');
657
+ for (const htmlFile of htmlFiles) {
658
+ const filePath = path.join(distDir, htmlFile);
659
+ let content = await fs.promises.readFile(filePath, 'utf8');
660
+ let modified = content;
661
+
662
+ for (const faviconFile of faviconFiles) {
663
+ const sourcePath = `/branding/logos/${faviconFile}`;
664
+ const destPath = `./images/${faviconFile}`;
665
+
666
+ // Only rewrite if the destination file exists in imagesDir
667
+ const destFilePath = path.join(imagesDir, faviconFile);
668
+ if (fs.existsSync(destFilePath)) {
669
+ const oldHref = `href="${sourcePath}"`;
670
+ const newHref = `href="${destPath}"`;
671
+ modified = modified.replaceAll(oldHref, newHref);
672
+ }
673
+ }
612
674
 
613
675
  if (modified !== content) {
614
676
  await fs.promises.writeFile(filePath, modified);
615
677
  }
616
678
  }
679
+
680
+ if (htmlFiles.length > 0) {
681
+ console.log(`✓ Rewrote favicon paths in ${htmlFiles.length} HTML file(s)`);
682
+ }
617
683
  }
618
684
 
619
685
  // Custom Nunjucks plugin
@@ -643,18 +709,7 @@ function customNunjucksPlugin() {
643
709
  middlewares.use(async (req, res, next) => {
644
710
  if (req.url.startsWith('/branding/')) {
645
711
  const filePath = path.join(process.cwd(), req.url);
646
- if (fs.existsSync(filePath)) {
647
- const ext = path.extname(filePath).toLowerCase();
648
- const mimeTypes = {
649
- '.svg': 'image/svg+xml',
650
- '.png': 'image/png',
651
- '.jpg': 'image/jpeg',
652
- '.jpeg': 'image/jpeg',
653
- '.webp': 'image/webp'
654
- };
655
- res.setHeader('Content-Type', mimeTypes[ext] || 'application/octet-stream');
656
- return res.end(fs.readFileSync(filePath));
657
- }
712
+ if (serveFileWithMimeType(filePath, res)) return;
658
713
  }
659
714
  next();
660
715
  });
@@ -700,16 +755,7 @@ function customNunjucksPlugin() {
700
755
  }
701
756
 
702
757
  if (fs.existsSync(filePath)) {
703
- const ext = path.extname(filePath).toLowerCase();
704
- const mimeTypes = {
705
- '.svg': 'image/svg+xml',
706
- '.png': 'image/png',
707
- '.jpg': 'image/jpeg',
708
- '.jpeg': 'image/jpeg',
709
- '.webp': 'image/webp'
710
- };
711
- res.setHeader('Content-Type', mimeTypes[ext] || 'application/octet-stream');
712
- return res.end(fs.readFileSync(filePath));
758
+ if (serveFileWithMimeType(filePath, res)) return;
713
759
  }
714
760
  }
715
761
  next();
@@ -722,18 +768,7 @@ function customNunjucksPlugin() {
722
768
  const brandingLogosPath = path.join(process.cwd(), 'branding/logos');
723
769
  const filePath = findFileRecursive(brandingLogosPath, fileName);
724
770
 
725
- if (filePath && fs.existsSync(filePath)) {
726
- const ext = path.extname(filePath).toLowerCase();
727
- const mimeTypes = {
728
- '.svg': 'image/svg+xml',
729
- '.png': 'image/png',
730
- '.jpg': 'image/jpeg',
731
- '.jpeg': 'image/jpeg',
732
- '.webp': 'image/webp'
733
- };
734
- res.setHeader('Content-Type', mimeTypes[ext] || 'application/octet-stream');
735
- return res.end(fs.readFileSync(filePath));
736
- }
771
+ if (serveFileWithMimeType(filePath, res)) return;
737
772
  }
738
773
  next();
739
774
  });
@@ -745,18 +780,7 @@ function customNunjucksPlugin() {
745
780
  const brandingImagesPath = path.join(process.cwd(), 'branding/images');
746
781
  const filePath = findFileRecursive(brandingImagesPath, fileName);
747
782
 
748
- if (filePath && fs.existsSync(filePath)) {
749
- const ext = path.extname(filePath).toLowerCase();
750
- const mimeTypes = {
751
- '.svg': 'image/svg+xml',
752
- '.png': 'image/png',
753
- '.jpg': 'image/jpeg',
754
- '.jpeg': 'image/jpeg',
755
- '.webp': 'image/webp'
756
- };
757
- res.setHeader('Content-Type', mimeTypes[ext] || 'application/octet-stream');
758
- return res.end(fs.readFileSync(filePath));
759
- }
783
+ if (serveFileWithMimeType(filePath, res)) return;
760
784
  }
761
785
  next();
762
786
  });
@@ -878,6 +902,9 @@ function customNunjucksPlugin() {
878
902
  // Step 4b: Correct HTML image paths for production (after HTML files are generated)
879
903
  await rewriteHtmlImagePaths();
880
904
 
905
+ // Step 4c: Rewrite favicon paths from /branding/logos/ to ./images/
906
+ await rewriteFaviconPaths();
907
+
881
908
  // Step 5: Final validation to find and fix common errors
882
909
  await validateBuild();
883
910
 
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="169" height="30.7" viewBox="0 0 169 30.7"><g fill="#ffffff" fill-rule="evenodd"><path d="M13.3 23.8a18.279 18.279 0 0 1-5.1.9 7.762 7.762 0 0 1-5.9-2.4A8.869 8.869 0 0 1 0 16a9.324 9.324 0 0 1 2-6.1 6.45 6.45 0 0 1 5.2-2.4 5.477 5.477 0 0 1 4.6 2.1c1.1 1.4 1.6 3.4 1.6 6v.9H3c.4 3.9 2.3 5.9 5.7 5.9a13.2 13.2 0 0 0 4.6-1ZM3.2 14.3h7.3c0-3.1-1.1-4.6-3.4-4.6-2.4 0-3.7 1.6-3.9 4.6Z"/><path data-name="Trazado 1" d="M28 24.3v-3.1a5.863 5.863 0 0 1-5.5 3.5 5.605 5.605 0 0 1-4.7-2.2 9.008 9.008 0 0 1-1.7-5.9A10.548 10.548 0 0 1 18 10a6.076 6.076 0 0 1 5.1-2.5 5.925 5.925 0 0 1 4.8 2.2V.4h3v23.9Zm0-12.5a6.482 6.482 0 0 0-4.4-2c-2.9 0-4.3 2.2-4.3 6.6 0 3.8 1.3 5.8 3.8 5.8 1.7 0 3.3-.9 4.9-2.7v-7.7Z"/><path d="M46.1 24.3v-3.1c-1.6 2.3-3.5 3.5-5.8 3.5a4.441 4.441 0 0 1-3.4-1.4 5.353 5.353 0 0 1-1.3-3.7V7.9h3v10.8a5.385 5.385 0 0 0 .5 2.6 2.067 2.067 0 0 0 1.8.8q2.7 0 5.1-3.6V7.9h3v16.4Z"/><path data-name="Trazado 2" d="M60.4 24.7a6.828 6.828 0 0 1-5.5-2.5 8.723 8.723 0 0 1-2.2-6.2 8.494 8.494 0 0 1 2.2-6.3 7.781 7.781 0 0 1 6-2.2 23.692 23.692 0 0 1 4.3.5v2.5a15.149 15.149 0 0 0-4.1-.7 4.8 4.8 0 0 0-3.7 1.7 7.209 7.209 0 0 0-1.4 4.6 7.314 7.314 0 0 0 1.4 4.5 4.655 4.655 0 0 0 3.7 1.7 9.245 9.245 0 0 0 4.2-1v2.6a19.135 19.135 0 0 1-4.9.8Z"/><path data-name="Trazado 3" d="M76.7 22.5a7.087 7.087 0 0 1-4.8 2.2 4.6 4.6 0 0 1-3.5-1.3 4.665 4.665 0 0 1-1.4-3.5 4.617 4.617 0 0 1 2.2-4.2 12.192 12.192 0 0 1 6.3-1.5h1.2v-1.5c0-1.7-1-2.6-3-2.6a10.966 10.966 0 0 0-5.3 1.5V8.5a16.05 16.05 0 0 1 6-1.2c4.3 0 6.5 1.7 6.5 5.2v7.4c0 1.3.4 2 1.3 2a1.486 1.486 0 0 0 .6-.1l.1 2.5a8.082 8.082 0 0 1-2.5.4c-1.8 0-3-.7-3.5-2.2h-.2Zm0-2.4v-3.4h-1.1c-2.9 0-4.3.9-4.3 2.7a2.452 2.452 0 0 0 .6 1.6 1.8 1.8 0 0 0 1.6.6 4.932 4.932 0 0 0 3.2-1.5Z"/><path data-name="Trazado 4" d="M85.7 24.3V7.7h4.5v3.1c1.2-2.3 2.9-3.5 5.3-3.5a1.949 1.949 0 0 1 .8.1v4a5.663 5.663 0 0 0-1.8-.3 5.137 5.137 0 0 0-4.4 2.7v10.5Z"/><path data-name="Trazado 5" d="M106.9 22.5a7.087 7.087 0 0 1-4.8 2.2 4.6 4.6 0 0 1-3.5-1.3 4.665 4.665 0 0 1-1.4-3.5 4.617 4.617 0 0 1 2.2-4.2 12.192 12.192 0 0 1 6.3-1.5h1.2v-1.5c0-1.7-1-2.6-3-2.6a10.966 10.966 0 0 0-5.3 1.5V8.5a16.05 16.05 0 0 1 6-1.2c4.3 0 6.5 1.7 6.5 5.2v7.4c0 1.3.4 2 1.3 2a1.486 1.486 0 0 0 .6-.1l.1 2.5a8.082 8.082 0 0 1-2.5.4c-1.8 0-3-.7-3.5-2.2h-.2Zm0-2.4v-3.4h-1.1c-2.9 0-4.3.9-4.3 2.7a2.452 2.452 0 0 0 .6 1.6 1.8 1.8 0 0 0 1.6.6 4.932 4.932 0 0 0 3.2-1.5Z"/><path data-name="Trazado 6" d="m116 29.5.4-3.3a13.3 13.3 0 0 0 5.3 1.3 4.99 4.99 0 0 0 3.6-1.1 4.78 4.78 0 0 0 1.1-3.4v-2.3a5.962 5.962 0 0 1-10.1 1.4 9.3 9.3 0 0 1-1.7-6 9.8 9.8 0 0 1 2-6.4 6.316 6.316 0 0 1 5.2-2.4 6.559 6.559 0 0 1 4.7 2.1l.5-1.7h4v12.7a23.154 23.154 0 0 1-.5 5.5 5.938 5.938 0 0 1-1.8 2.9 9.3 9.3 0 0 1-6.3 1.9 26.488 26.488 0 0 1-6.4-1.2Zm10.4-11.4V12a4.628 4.628 0 0 0-3.4-1.8 3.174 3.174 0 0 0-2.7 1.5 7.121 7.121 0 0 0-1 4.1c0 3.2 1 4.9 3.1 4.9 1.4 0 2.8-.9 4-2.6Z"/><path data-name="Trazado 7" d="M142.3 24.7a8.135 8.135 0 0 1-6.2-2.4 8.869 8.869 0 0 1-2.3-6.3 8.951 8.951 0 0 1 2.3-6.4c1.5-1.6 3.6-2.3 6.3-2.3a8.541 8.541 0 0 1 6.3 2.3 8.7 8.7 0 0 1 2.3 6.3 8.787 8.787 0 0 1-2.3 6.4 8.6 8.6 0 0 1-6.4 2.4Zm0-2.8c2.6 0 3.9-2 3.9-5.9a7.83 7.83 0 0 0-1-4.3 3.25 3.25 0 0 0-5.6 0 7.83 7.83 0 0 0-1 4.3 7.83 7.83 0 0 0 1 4.3 3.152 3.152 0 0 0 2.7 1.6Z"/><path data-name="Trazado 8" d="m139.5 4.9 3.6-4.9h4.1l-4.8 4.9Z"/><path data-name="Trazado 9" d="M154 24.3V7.7h4.5v3.1c1.5-2.3 3.4-3.5 5.7-3.5a4.513 4.513 0 0 1 3.5 1.4 5.167 5.167 0 0 1 1.3 3.8v11.8h-4.5V13.7c0-1.9-.6-2.8-1.9-2.8-1.4 0-2.8 1-4.1 3v10.4Z"/></g></svg>
@@ -1,37 +0,0 @@
1
- /**
2
- * Branding Variables
3
- *
4
- * CSS custom properties for runtime branding customization.
5
- * These variables can be overridden at runtime via JavaScript
6
- * to customize the appearance without rebuilding.
7
- *
8
- * Los colores se configuran en src/css/styles.css
9
- * Edita las variables: --color-primary-base, --color-primary-light, --color-primary-dark
10
- *
11
- * LOGO SYSTEM
12
- * ===========
13
- * The system uses three logo variants for different contexts:
14
- *
15
- * --branding-logo-expanded: Full logo with text. Shown in the main header
16
- * on desktop when there is enough space.
17
- * Used by: header component (desktop version)
18
- *
19
- * --branding-logo-mini: Standard size logo.
20
- * Shown in header-mini and header-advanced.
21
- * Used by: header-mini, header-advanced components
22
- *
23
- * --branding-logo-compact: Compact logo, typically just the symbol/coat of arms.
24
- * Shown in reduced spaces or on mobile.
25
- * Used by: header component (mobile/responsive version)
26
- */
27
-
28
- :root {
29
- /* Expanded logo - Main header on desktop (full logo with text) */
30
- --branding-logo-expanded: url('/images/aragon-expanded.svg');
31
-
32
- /* Mini logo - Header-mini and header-advanced (standard size) */
33
- --branding-logo-mini: url('/images/aragon-mini.svg');
34
-
35
- /* Compact logo - Main header on mobile (symbol/coat of arms only) */
36
- --branding-logo-compact: url('/images/aragon-compact.svg');
37
- }