KiCad PCB EDA Suite
Loading...
Searching...
No Matches
template_default_html.h
Go to the documentation of this file.
1/*
2 * KiCad Project Template HTML defaults
3 * Extracted from dialog_template_selector.cpp to allow reuse and to provide
4 * a styled fallback page when a template does not supply an info.html.
5 */
6
7#ifndef KICAD_TEMPLATE_DEFAULT_HTML_H
8#define KICAD_TEMPLATE_DEFAULT_HTML_H
9
10#include <wx/string.h>
11
12// Uses _() translation macro which is defined globally in KiCad builds.
13
14namespace
15{
16
17// Common CSS variables and base styles shared across all template HTML pages.
18// Uses CSS custom properties for light/dark theme switching via the kicad-dark class.
19inline wxString GetCommonStyles()
20{
21 return wxString(
22 ":root {"
23 "--bg-primary: #FFFFFF;"
24 "--bg-secondary: #F3F3F3;"
25 "--bg-elevated: #FFFFFF;"
26 "--text-primary: #545454;"
27 "--text-secondary: #848484;"
28 "--accent: #1A81C4;"
29 "--accent-subtle: rgba(26, 129, 196, 0.08);"
30 "--border: #E0E0E0;"
31 "--shadow: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);"
32 "}"
33 "body.kicad-dark {"
34 "--bg-primary: #1E1E1E;"
35 "--bg-secondary: #2D2D2D;"
36 "--bg-elevated: #333333;"
37 "--text-primary: #DED3DD;"
38 "--text-secondary: #848484;"
39 "--accent: #42B8EB;"
40 "--accent-subtle: rgba(66, 184, 235, 0.1);"
41 "--border: #404040;"
42 "--shadow: 0 1px 3px rgba(0,0,0,0.2), 0 1px 2px rgba(0,0,0,0.15);"
43 "}"
44 "* { box-sizing: border-box; }"
45 "body {"
46 "font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;"
47 "margin: 0;"
48 "padding: 24px;"
49 "background: var(--bg-primary);"
50 "color: var(--text-primary);"
51 "line-height: 1.5;"
52 "}"
53 );
54}
55
56// SVG icon for template/document
57inline wxString GetTemplateIcon()
58{
59 return wxString(
60 "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" "
61 "stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">"
62 "<path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/>"
63 "<polyline points=\"14 2 14 8 20 8\"/>"
64 "<line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"/>"
65 "<line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"/>"
66 "<polyline points=\"10 9 9 9 8 9\"/>"
67 "</svg>"
68 );
69}
70
71// SVG icon for settings/gear
72inline wxString GetSettingsIcon()
73{
74 return wxString(
75 "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" "
76 "stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">"
77 "<circle cx=\"12\" cy=\"12\" r=\"3\"/>"
78 "<path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06"
79 "a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09"
80 "A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83"
81 "l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09"
82 "A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0"
83 "l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09"
84 "a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83"
85 "l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09"
86 "a1.65 1.65 0 0 0-1.51 1z\"/>"
87 "</svg>"
88 );
89}
90
91// SVG icon for layers/stack
92inline wxString GetLayersIcon()
93{
94 return wxString(
95 "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" "
96 "stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">"
97 "<polygon points=\"12 2 2 7 12 12 22 7 12 2\"/>"
98 "<polyline points=\"2 17 12 22 22 17\"/>"
99 "<polyline points=\"2 12 12 17 22 12\"/>"
100 "</svg>"
101 );
102}
103
104// SVG icon for folder
105inline wxString GetFolderIcon()
106{
107 return wxString(
108 "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" "
109 "stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">"
110 "<path d=\"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z\"/>"
111 "</svg>"
112 );
113}
114
115// SVG icon for info/lightbulb
116inline wxString GetInfoIcon()
117{
118 return wxString(
119 "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" "
120 "stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">"
121 "<circle cx=\"12\" cy=\"12\" r=\"10\"/>"
122 "<line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"/>"
123 "<line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"/>"
124 "</svg>"
125 );
126}
127
128} // anonymous namespace
129
130
131// Welcome page shown when no template is selected.
132inline wxString GetWelcomeHtml( bool aDarkMode )
133{
134 wxString bodyClass = aDarkMode ? wxS( "kicad-dark" ) : wxS( "" );
135
136 return wxString(
137 "<!DOCTYPE html>"
138 "<html lang=\"en\">"
139 "<head>"
140 "<meta charset=\"UTF-8\">"
141 "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
142 "<title>KiCad Project Template Selector</title>"
143 "<style>" )
144 + GetCommonStyles() +
145 wxString(
146 ".card {"
147 "max-width: 600px;"
148 "margin: 0 auto;"
149 "background: var(--bg-elevated);"
150 "border-radius: 8px;"
151 "padding: 32px;"
152 "box-shadow: var(--shadow);"
153 "border: 1px solid var(--border);"
154 "}"
155 ".header {"
156 "text-align: center;"
157 "margin-bottom: 28px;"
158 "}"
159 ".title {"
160 "font-size: 1.5rem;"
161 "font-weight: 600;"
162 "color: var(--text-primary);"
163 "margin: 0 0 8px 0;"
164 "}"
165 ".subtitle {"
166 "font-size: 0.95rem;"
167 "color: var(--text-secondary);"
168 "margin: 0;"
169 "}"
170 ".features {"
171 "display: flex;"
172 "flex-direction: column;"
173 "gap: 16px;"
174 "margin-bottom: 28px;"
175 "}"
176 ".feature {"
177 "display: flex;"
178 "align-items: flex-start;"
179 "gap: 14px;"
180 "padding: 14px;"
181 "background: var(--bg-secondary);"
182 "border-radius: 6px;"
183 "}"
184 ".feature-icon {"
185 "flex-shrink: 0;"
186 "width: 40px;"
187 "height: 40px;"
188 "display: flex;"
189 "align-items: center;"
190 "justify-content: center;"
191 "background: var(--accent-subtle);"
192 "border-radius: 8px;"
193 "color: var(--accent);"
194 "}"
195 ".feature-content h3 {"
196 "margin: 0 0 4px 0;"
197 "font-size: 0.95rem;"
198 "font-weight: 600;"
199 "color: var(--text-primary);"
200 "}"
201 ".feature-content p {"
202 "margin: 0;"
203 "font-size: 0.875rem;"
204 "color: var(--text-secondary);"
205 "}"
206 ".tip {"
207 "display: flex;"
208 "align-items: flex-start;"
209 "gap: 10px;"
210 "padding: 12px 14px;"
211 "background: var(--accent-subtle);"
212 "border-radius: 6px;"
213 "border-left: 3px solid var(--accent);"
214 "}"
215 ".tip-icon {"
216 "flex-shrink: 0;"
217 "color: var(--accent);"
218 "}"
219 ".tip-text {"
220 "font-size: 0.875rem;"
221 "color: var(--text-secondary);"
222 "margin: 0;"
223 "}"
224 "</style>"
225 "</head>"
226 "<body class=\"" ) + bodyClass + wxString( "\">"
227 "<div class=\"card\">"
228 "<div class=\"header\">"
229 "<h1 class=\"title\">" ) + _( "Select a Template" ) + wxString( "</h1>"
230 "<p class=\"subtitle\">" )
231 + _( "Templates provide pre-configured project structures to jumpstart your design." )
232 + wxString( "</p>"
233 "</div>"
234 "<div class=\"features\">"
235 "<div class=\"feature\">"
236 "<div class=\"feature-icon\">" ) + GetTemplateIcon() + wxString( "</div>"
237 "<div class=\"feature-content\">"
238 "<h3>" ) + _( "Pre-configured Libraries" ) + wxString( "</h3>"
239 "<p>" ) + _( "Common symbols and footprints already linked and ready to use." ) + wxString( "</p>"
240 "</div>"
241 "</div>"
242 "<div class=\"feature\">"
243 "<div class=\"feature-icon\">" ) + GetSettingsIcon() + wxString( "</div>"
244 "<div class=\"feature-content\">"
245 "<h3>" ) + _( "Design Rules" ) + wxString( "</h3>"
246 "<p>" ) + _( "Electrical and mechanical constraints configured for the intended application." ) + wxString( "</p>"
247 "</div>"
248 "</div>"
249 "<div class=\"feature\">"
250 "<div class=\"feature-icon\">" ) + GetLayersIcon() + wxString( "</div>"
251 "<div class=\"feature-content\">"
252 "<h3>" ) + _( "Board Stackups" ) + wxString( "</h3>"
253 "<p>" ) + _( "Layer configurations optimized for common manufacturing processes." ) + wxString( "</p>"
254 "</div>"
255 "</div>"
256 "</div>"
257 "<div class=\"tip\">"
258 "<div class=\"tip-icon\">" ) + GetInfoIcon() + wxString( "</div>"
259 "<p class=\"tip-text\">" )
260 + _( "Recently used templates appear at the top. Use the folder icon to browse custom template directories." )
261 + wxString( "</p>"
262 "</div>"
263 "</div>"
264 "</body>"
265 "</html>"
266 );
267}
268
269
270// Fallback when a specific template has no meta/info.html.
271inline wxString GetTemplateInfoHtml( const wxString& aTemplateName, bool aDarkMode )
272{
273 wxString bodyClass = aDarkMode ? wxS( "kicad-dark" ) : wxS( "" );
274
275 return wxString(
276 "<!DOCTYPE html>"
277 "<html lang=\"en\">"
278 "<head>"
279 "<meta charset=\"UTF-8\">"
280 "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
281 "<title>" ) + aTemplateName + wxString( " - KiCad Template</title>"
282 "<style>" )
283 + GetCommonStyles() +
284 wxString(
285 ".card {"
286 "max-width: 600px;"
287 "margin: 0 auto;"
288 "background: var(--bg-elevated);"
289 "border-radius: 8px;"
290 "padding: 28px;"
291 "box-shadow: var(--shadow);"
292 "border: 1px solid var(--border);"
293 "}"
294 ".header {"
295 "display: flex;"
296 "align-items: center;"
297 "gap: 12px;"
298 "margin-bottom: 20px;"
299 "}"
300 ".badge {"
301 "background: var(--accent);"
302 "color: #FFFFFF;"
303 "padding: 4px 10px;"
304 "border-radius: 4px;"
305 "font-size: 0.75rem;"
306 "font-weight: 600;"
307 "letter-spacing: 0.03em;"
308 "text-transform: uppercase;"
309 "}"
310 ".template-name {"
311 "font-size: 1.25rem;"
312 "font-weight: 600;"
313 "color: var(--text-primary);"
314 "margin: 0;"
315 "}"
316 ".description {"
317 "color: var(--text-secondary);"
318 "margin-bottom: 24px;"
319 "}"
320 ".steps {"
321 "background: var(--bg-secondary);"
322 "border-radius: 6px;"
323 "padding: 20px;"
324 "margin-bottom: 20px;"
325 "}"
326 ".steps-title {"
327 "font-size: 0.875rem;"
328 "font-weight: 600;"
329 "color: var(--text-primary);"
330 "margin: 0 0 16px 0;"
331 "}"
332 ".step {"
333 "display: flex;"
334 "gap: 12px;"
335 "margin-bottom: 14px;"
336 "}"
337 ".step:last-child {"
338 "margin-bottom: 0;"
339 "}"
340 ".step-number {"
341 "flex-shrink: 0;"
342 "width: 24px;"
343 "height: 24px;"
344 "display: flex;"
345 "align-items: center;"
346 "justify-content: center;"
347 "background: var(--accent);"
348 "color: #FFFFFF;"
349 "border-radius: 50%;"
350 "font-size: 0.75rem;"
351 "font-weight: 600;"
352 "}"
353 ".step-content h4 {"
354 "margin: 0 0 2px 0;"
355 "font-size: 0.875rem;"
356 "font-weight: 600;"
357 "color: var(--text-primary);"
358 "}"
359 ".step-content p {"
360 "margin: 0;"
361 "font-size: 0.8125rem;"
362 "color: var(--text-secondary);"
363 "}"
364 ".hint {"
365 "display: flex;"
366 "align-items: flex-start;"
367 "gap: 10px;"
368 "padding: 12px 14px;"
369 "background: var(--accent-subtle);"
370 "border-radius: 6px;"
371 "border-left: 3px solid var(--accent);"
372 "}"
373 ".hint-icon {"
374 "flex-shrink: 0;"
375 "color: var(--accent);"
376 "}"
377 ".hint-text {"
378 "font-size: 0.8125rem;"
379 "color: var(--text-secondary);"
380 "margin: 0;"
381 "}"
382 "code {"
383 "background: var(--bg-secondary);"
384 "padding: 2px 6px;"
385 "border-radius: 3px;"
386 "font-size: 0.8125rem;"
387 "font-family: 'SF Mono', Monaco, Consolas, monospace;"
388 "}"
389 "</style>"
390 "</head>"
391 "<body class=\"" ) + bodyClass + wxString( "\">"
392 "<div class=\"card\">"
393 "<div class=\"header\">"
394 "<span class=\"badge\">" ) + _( "Template" ) + wxString( "</span>"
395 "<h1 class=\"template-name\">" ) + aTemplateName + wxString( "</h1>"
396 "</div>"
397 "<p class=\"description\">" )
398 + _( "This template does not include a description. You can still use it to create a new project." )
399 + wxString( "</p>"
400 "<div class=\"steps\">"
401 "<h3 class=\"steps-title\">" ) + _( "To use this template" ) + wxString( "</h3>"
402 "<div class=\"step\">"
403 "<span class=\"step-number\">1</span>"
404 "<div class=\"step-content\">"
405 "<h4>" ) + _( "Create the project" ) + wxString( "</h4>"
406 "<p>" ) + _( "Click OK to create a new project folder with this template's contents." ) + wxString( "</p>"
407 "</div>"
408 "</div>"
409 "<div class=\"step\">"
410 "<span class=\"step-number\">2</span>"
411 "<div class=\"step-content\">"
412 "<h4>" ) + _( "Open schematic and PCB" ) + wxString( "</h4>"
413 "<p>" ) + _( "Use the Project Manager to launch the Schematic and PCB editors." ) + wxString( "</p>"
414 "</div>"
415 "</div>"
416 "<div class=\"step\">"
417 "<span class=\"step-number\">3</span>"
418 "<div class=\"step-content\">"
419 "<h4>" ) + _( "Review settings" ) + wxString( "</h4>"
420 "<p>" ) + _( "Verify libraries, design rules, and board stackup match your needs." ) + wxString( "</p>"
421 "</div>"
422 "</div>"
423 "</div>"
424 "<div class=\"hint\">"
425 "<div class=\"hint-icon\">" ) + GetInfoIcon() + wxString( "</div>"
426 "<p class=\"hint-text\">" )
427 + _( "Add a description by creating" ) + wxString( " <code>meta/info.html</code> " )
428 + _( "inside this template's directory." )
429 + wxString( "</p>"
430 "</div>"
431 "</div>"
432 "</body>"
433 "</html>"
434 );
435}
436
437
438// Page shown when a template directory has no templates.
439inline wxString GetNoTemplatesHtml( bool aDarkMode )
440{
441 wxString bodyClass = aDarkMode ? wxS( "kicad-dark" ) : wxS( "" );
442
443 return wxString(
444 "<!DOCTYPE html>"
445 "<html lang=\"en\">"
446 "<head>"
447 "<meta charset=\"UTF-8\">"
448 "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
449 "<title>No Templates - KiCad</title>"
450 "<style>" )
451 + GetCommonStyles() +
452 wxString(
453 ".card {"
454 "max-width: 500px;"
455 "margin: 0 auto;"
456 "background: var(--bg-elevated);"
457 "border-radius: 8px;"
458 "padding: 32px;"
459 "box-shadow: var(--shadow);"
460 "border: 1px solid var(--border);"
461 "text-align: center;"
462 "}"
463 ".icon {"
464 "width: 56px;"
465 "height: 56px;"
466 "margin: 0 auto 20px auto;"
467 "display: flex;"
468 "align-items: center;"
469 "justify-content: center;"
470 "background: var(--bg-secondary);"
471 "border-radius: 50%;"
472 "color: var(--text-secondary);"
473 "}"
474 ".icon svg {"
475 "width: 28px;"
476 "height: 28px;"
477 "}"
478 ".title {"
479 "font-size: 1.25rem;"
480 "font-weight: 600;"
481 "color: var(--text-primary);"
482 "margin: 0 0 8px 0;"
483 "}"
484 ".message {"
485 "color: var(--text-secondary);"
486 "margin: 0 0 24px 0;"
487 "}"
488 ".suggestions {"
489 "text-align: left;"
490 "background: var(--bg-secondary);"
491 "border-radius: 6px;"
492 "padding: 16px 20px;"
493 "margin-bottom: 20px;"
494 "}"
495 ".suggestions-title {"
496 "font-size: 0.875rem;"
497 "font-weight: 600;"
498 "color: var(--text-primary);"
499 "margin: 0 0 12px 0;"
500 "}"
501 ".suggestions ul {"
502 "margin: 0;"
503 "padding-left: 20px;"
504 "color: var(--text-secondary);"
505 "font-size: 0.875rem;"
506 "}"
507 ".suggestions li {"
508 "margin-bottom: 8px;"
509 "}"
510 ".suggestions li:last-child {"
511 "margin-bottom: 0;"
512 "}"
513 ".tip {"
514 "display: flex;"
515 "align-items: flex-start;"
516 "gap: 10px;"
517 "padding: 12px 14px;"
518 "background: var(--accent-subtle);"
519 "border-radius: 6px;"
520 "text-align: left;"
521 "}"
522 ".tip-icon {"
523 "flex-shrink: 0;"
524 "color: var(--accent);"
525 "}"
526 ".tip-text {"
527 "font-size: 0.8125rem;"
528 "color: var(--text-secondary);"
529 "margin: 0;"
530 "}"
531 "</style>"
532 "</head>"
533 "<body class=\"" ) + bodyClass + wxString( "\">"
534 "<div class=\"card\">"
535 "<div class=\"icon\">" ) + GetFolderIcon() + wxString( "</div>"
536 "<h1 class=\"title\">" ) + _( "No Templates Found" ) + wxString( "</h1>"
537 "<p class=\"message\">" )
538 + _( "The selected directory does not contain any project templates." )
539 + wxString( "</p>"
540 "<div class=\"suggestions\">"
541 "<h3 class=\"suggestions-title\">" ) + _( "Suggestions" ) + wxString( "</h3>"
542 "<ul>"
543 "<li>" ) + _( "Browse to a different directory using the folder icon" ) + wxString( "</li>"
544 "<li>" ) + _( "Use the refresh icon to reload the current directory" ) + wxString( "</li>"
545 "<li>" ) + _( "Switch to a system templates tab" ) + wxString( "</li>"
546 "</ul>"
547 "</div>"
548 "<div class=\"tip\">"
549 "<div class=\"tip-icon\">" ) + GetInfoIcon() + wxString( "</div>"
550 "<p class=\"tip-text\">" )
551 + _( "Each template needs a 'meta' folder containing configuration files." )
552 + wxString( "</p>"
553 "</div>"
554 "</div>"
555 "</body>"
556 "</html>"
557 );
558}
559
560#endif // KICAD_TEMPLATE_DEFAULT_HTML_H
#define _(s)
wxString GetWelcomeHtml(bool aDarkMode)
wxString GetTemplateInfoHtml(const wxString &aTemplateName, bool aDarkMode)
wxString GetNoTemplatesHtml(bool aDarkMode)