so-web-components 0.1.0
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/LICENSE +21 -0
- package/README.md +217 -0
- package/dist/components/so-breadcrumb.d.ts +12 -0
- package/dist/components/so-breadcrumb.js +157 -0
- package/dist/components/so-header.d.ts +16 -0
- package/dist/components/so-header.js +437 -0
- package/dist/demo/index.html +50 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +12 -0
- package/dist/styles/fonts.css +67 -0
- package/dist/styles/reset.css +7 -0
- package/dist/styles/tokens.css +54 -0
- package/package.json +45 -0
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
const DEFAULT_TOP_NAV = [
|
|
2
|
+
{ label: "Regierung", href: "#" },
|
|
3
|
+
{ label: "Gerichte", href: "#" },
|
|
4
|
+
{ label: "Parlament", href: "#" },
|
|
5
|
+
{ label: "Karriere", href: "#" },
|
|
6
|
+
{ label: "my.so.ch", href: "#" }
|
|
7
|
+
];
|
|
8
|
+
const DEFAULT_SECTION_NAV = [
|
|
9
|
+
{ label: "Services", href: "#" },
|
|
10
|
+
{ label: "Verwaltung", href: "#" }
|
|
11
|
+
];
|
|
12
|
+
function safeParseNav(json, fallback) {
|
|
13
|
+
if (!json)
|
|
14
|
+
return fallback;
|
|
15
|
+
try {
|
|
16
|
+
const v = JSON.parse(json);
|
|
17
|
+
if (!Array.isArray(v))
|
|
18
|
+
return fallback;
|
|
19
|
+
const items = [];
|
|
20
|
+
for (const it of v) {
|
|
21
|
+
if (!it || typeof it !== "object")
|
|
22
|
+
continue;
|
|
23
|
+
const label = it["label"];
|
|
24
|
+
const href = it["href"];
|
|
25
|
+
if (typeof label === "string" && typeof href === "string") {
|
|
26
|
+
items.push({ label, href });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return items.length ? items : fallback;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return fallback;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function el(tag, cls) {
|
|
36
|
+
const n = document.createElement(tag);
|
|
37
|
+
if (cls)
|
|
38
|
+
n.className = cls;
|
|
39
|
+
return n;
|
|
40
|
+
}
|
|
41
|
+
function buildNavList(items, options = {}) {
|
|
42
|
+
const ul = el("ul", options.className);
|
|
43
|
+
for (const item of items) {
|
|
44
|
+
const li = el("li");
|
|
45
|
+
const a = el("a");
|
|
46
|
+
a.href = item.href;
|
|
47
|
+
const handled = options.setLinkContent?.(a, item);
|
|
48
|
+
if (!handled) {
|
|
49
|
+
a.textContent = item.label;
|
|
50
|
+
}
|
|
51
|
+
options.setLinkAttributes?.(a, item);
|
|
52
|
+
li.appendChild(a);
|
|
53
|
+
ul.appendChild(li);
|
|
54
|
+
}
|
|
55
|
+
return ul;
|
|
56
|
+
}
|
|
57
|
+
const LOGO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" id="logo" viewBox="0 0 171.086 15.742" aria-hidden="true" focusable="false">
|
|
58
|
+
<g>
|
|
59
|
+
<path d="m20.424.104h.877l-.595,2.634.016.017L23.658.104h1.156l-3.296,2.951,2.43,3.036h-1.105l-2.242-2.864-.613,2.864h-.887L20.424.104Z" fill="#1d1d1b"></path>
|
|
60
|
+
<path d="m31.676,3.878h-2.428l1.852-2.848.576,2.848Zm-4.827,2.213h.972l.981-1.509h3.006l.324,1.509h.904L31.685.104h-.867s-3.969,5.987-3.969,5.987Z" fill="#1d1d1b"></path>
|
|
61
|
+
<path d="m37.714.104h1.157l1.726,5.017h.018L41.701.104h.833l-1.332,5.987h-1.131l-1.726-4.975h-.016l-1.042,4.975h-.843L37.714.104Z" fill="#1d1d1b"></path>
|
|
62
|
+
<path d="m50.965.858h-1.903l-1.147,5.233h-.886l1.149-5.233h-1.902l.167-.754h4.687s-.165.754-.165.754Z" fill="#1d1d1b"></path>
|
|
63
|
+
<path d="m54.55,3.681c0-1.527.998-2.925,2.496-2.925,1.052,0,1.577.644,1.577,1.793,0,1.305-.891,2.892-2.401,2.892-1.105,0-1.671-.695-1.671-1.76h0Zm-.93-.025c0,1.654.884,2.538,2.567,2.538,2.218,0,3.367-1.87,3.367-3.765,0-1.527-.92-2.429-2.481-2.429-2.242,0-3.453,1.956-3.453,3.656Z" fill="#1d1d1b"></path>
|
|
64
|
+
<path d="m64.057.104h1.157l1.726,5.017h.018l1.087-5.017h.832l-1.332,5.987h-1.13l-1.726-4.975h-.018l-1.043,4.975h-.842s1.271-5.987,1.271-5.987Z" fill="#1d1d1b"></path>
|
|
65
|
+
<path d="m69.661,12.986c.847.367,1.765.551,2.684.551.532,0,1.855-.054,1.855-.846,0-1.359-3.952-.661-3.952-3.824,0-2.242,2.611-3.142,4.834-3.142.828,0,1.987.182,3.181.57l-.699,2.168c-.846-.348-1.654-.533-2.648-.533-.734,0-1.543.166-1.543.827,0,1.065,4.136.993,4.136,3.4,0,2.372-2.005,3.548-4.485,3.584-1.453.019-2.997-.201-4.027-.495l.663-2.261h0Z" fill="#1d1d1b"></path>
|
|
66
|
+
<path d="m87.97,9.971c0,2.17-.974,3.457-2.519,3.457-1.12.018-1.8-.847-1.8-2.133,0-1.526.992-3.254,2.592-3.254,1.288,0,1.728.939,1.728,1.93h0Zm3.419.037c0-2.408-1.728-4.282-4.982-4.282-3.75,0-6.176,2.278-6.176,5.642,0,2.407,1.434,4.374,4.982,4.374,3.583,0,6.176-1.745,6.176-5.735h0Z" fill="#1d1d1b"></path>
|
|
67
|
+
<path d="m95.708,1.737h3.346l-2.868,13.786h-3.345l2.868-13.786h0Z" fill="#1d1d1b"></path>
|
|
68
|
+
<path d="m107.455,9.971c0,2.17-.976,3.457-2.519,3.457-1.12.018-1.802-.847-1.802-2.133,0-1.526.994-3.254,2.593-3.254,1.286,0,1.728.939,1.728,1.93Zm3.418.037c0-2.408-1.728-4.282-4.98-4.282-3.751,0-6.178,2.278-6.178,5.642,0,2.407,1.434,4.374,4.983,4.374,3.583,0,6.174-1.745,6.174-5.735h.001Z" fill="#1d1d1b"></path>
|
|
69
|
+
<path d="m113.372,5.946h1.894l.458-2.059,3.495-.938-.663,2.997h2.28l-.405,2.317h-2.408l-.571,2.665c-.146.716-.273,1.194-.273,1.653,0,.644.421,1.066,1.083,1.066.349,0,.717-.147,1.066-.276l-.366,2.187c-.699.111-1.398.183-2.059.183-1.691,0-3.034-.827-3.034-2.83,0-.478.072-.956.294-1.966l.57-2.684h-1.765l.404-2.317v.002Z" fill="#1d1d1b"></path>
|
|
70
|
+
<path d="m125.247,1.737h3.346l-1.177,5.606h.037c.68-.899,1.783-1.617,3.328-1.617,1.929,0,2.975,1.434,2.975,3.308,0,.643-.053,1.01-.255,2.022l-.882,4.467h-3.419l.918-4.485c.093-.479.222-.955.222-1.453,0-.57-.366-1.14-1.286-1.103-1.397,0-2.225,1.215-2.464,2.628l-.936,4.412h-3.31l2.905-13.786h-.002Z" fill="#1d1d1b"></path>
|
|
71
|
+
<path d="m146.496,13.023c-.165.828-.312,1.636-.405,2.5h-3.069l.258-1.563h-.037c-.956,1.066-1.948,1.782-3.696,1.782-1.929,0-2.975-1.433-2.975-3.308,0-.644.053-1.011.257-2.021l.882-4.468h3.418l-.918,4.485c-.093.478-.222.955-.222,1.452,0,.571.368,1.14,1.286,1.104,1.398,0,2.226-1.213,2.464-2.628l.937-4.412h3.308l-1.489,7.077h.001Z" fill="#1d1d1b"></path>
|
|
72
|
+
<path d="m154.952,5.946l-.368,1.967h.037c.534-1.121,1.599-2.186,2.959-2.186.44,0,.956.054,1.397.238l-.754,2.923c-.423-.333-.9-.405-1.525-.405-1.397,0-2.223,1.215-2.463,2.628l-.937,4.412h-3.31l1.489-7.078c.167-.827.315-1.635.405-2.499h3.07,0Z" fill="#1d1d1b"></path>
|
|
73
|
+
<path d="m161.161,8.445c.166-.827.312-1.635.405-2.499h3.069l-.257,1.563h.035c.956-1.065,1.95-1.782,3.696-1.782,1.93,0,2.977,1.434,2.977,3.308,0,.643-.055,1.01-.257,2.022l-.882,4.467h-3.418l.918-4.485c.094-.479.222-.955.222-1.453,0-.57-.368-1.14-1.288-1.103-1.397,0-2.225,1.215-2.463,2.628l-.939,4.412h-3.307s1.489-7.078,1.489-7.078Z" fill="#1d1d1b"></path>
|
|
74
|
+
</g>
|
|
75
|
+
<g>
|
|
76
|
+
<path d="m2.364.109h13.713s-1.474,6.483-2.234,9.833c-.771,3.393-4.621,5.774-8.159,5.774-3.496,0-6.321-2.402-5.559-5.752C.886,6.613,2.364.109,2.364.109Z" fill="#fff"></path>
|
|
77
|
+
<path d="m4.602,15.073l-.88.375c.613.174,1.274.268,1.961.268,3.017,0,6.261-1.732,7.629-4.347l-.858.362c-1.473,2.159-4.339,3.436-6.771,3.436-.37,0-.73-.036-1.081-.093h0Z" fill="#1d1d1b"></path>
|
|
78
|
+
<path d="m2.364.109s-.682,2.998-1.357,5.972h13.713c.676-2.972,1.357-5.972,1.357-5.972,0,0-13.713,0-13.713,0Z" fill="#e01f26"></path>
|
|
79
|
+
</g>
|
|
80
|
+
</svg>`;
|
|
81
|
+
export class SoHeader extends HTMLElement {
|
|
82
|
+
constructor() {
|
|
83
|
+
super();
|
|
84
|
+
this.topNav = DEFAULT_TOP_NAV;
|
|
85
|
+
this.sectionNav = DEFAULT_SECTION_NAV;
|
|
86
|
+
this.activeSection = "Services";
|
|
87
|
+
this.logoHref = "/";
|
|
88
|
+
this.siteName = "Kanton Solothurn";
|
|
89
|
+
this.root = this.attachShadow({ mode: "open" });
|
|
90
|
+
this.updateFromAttributes();
|
|
91
|
+
this.render();
|
|
92
|
+
this.bindEvents();
|
|
93
|
+
}
|
|
94
|
+
attributeChangedCallback() {
|
|
95
|
+
this.updateFromAttributes();
|
|
96
|
+
this.render();
|
|
97
|
+
}
|
|
98
|
+
updateFromAttributes() {
|
|
99
|
+
this.topNav = safeParseNav(this.getAttribute("top-nav"), DEFAULT_TOP_NAV);
|
|
100
|
+
this.sectionNav = safeParseNav(this.getAttribute("section-nav"), DEFAULT_SECTION_NAV);
|
|
101
|
+
this.activeSection = this.getAttribute("active-section") ?? this.activeSection;
|
|
102
|
+
this.logoHref = this.getAttribute("logo-href") ?? this.logoHref;
|
|
103
|
+
this.siteName = this.getAttribute("site-name") ?? this.siteName;
|
|
104
|
+
}
|
|
105
|
+
bindEvents() {
|
|
106
|
+
this.root.addEventListener("click", (e) => {
|
|
107
|
+
const t = e.target;
|
|
108
|
+
const btn = t?.closest("button[data-action]");
|
|
109
|
+
if (btn?.dataset.action === "toggle-menu") {
|
|
110
|
+
this.toggleMobileMenu();
|
|
111
|
+
}
|
|
112
|
+
const a = t?.closest("a[data-section]");
|
|
113
|
+
if (a) {
|
|
114
|
+
const label = a.dataset.section ?? "";
|
|
115
|
+
this.dispatchEvent(new CustomEvent("so-section-select", {
|
|
116
|
+
detail: { label, href: a.getAttribute("href") ?? "" },
|
|
117
|
+
bubbles: true,
|
|
118
|
+
composed: true
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
toggleMobileMenu() {
|
|
124
|
+
const panel = this.root.querySelector(".mobile-panel-inner");
|
|
125
|
+
const btn = this.root.querySelector('button[data-action="toggle-menu"]');
|
|
126
|
+
if (!panel || !btn)
|
|
127
|
+
return;
|
|
128
|
+
const open = panel.getAttribute("data-open") === "true";
|
|
129
|
+
const nextOpen = !open;
|
|
130
|
+
panel.setAttribute("data-open", nextOpen ? "true" : "false");
|
|
131
|
+
btn.setAttribute("aria-expanded", nextOpen ? "true" : "false");
|
|
132
|
+
btn.setAttribute("data-open", nextOpen ? "true" : "false");
|
|
133
|
+
btn.innerHTML = nextOpen ? closeIcon() : burgerIcon();
|
|
134
|
+
}
|
|
135
|
+
render() {
|
|
136
|
+
this.root.innerHTML = "";
|
|
137
|
+
const styleEl = document.createElement("style");
|
|
138
|
+
styleEl.textContent = this.styles();
|
|
139
|
+
this.root.appendChild(styleEl);
|
|
140
|
+
const header = el("header", "so-header");
|
|
141
|
+
header.setAttribute("role", "banner");
|
|
142
|
+
// Row 1: full-width, internal container for gutters
|
|
143
|
+
const top = el("div", "topbar");
|
|
144
|
+
const topInner = el("div", "topbar-inner so-header-container");
|
|
145
|
+
//topInner.style.setProperty("--so-container-size", "var(--so-container-size-full)");
|
|
146
|
+
const left = el("div", "left");
|
|
147
|
+
const logoLink = el("a", "logo");
|
|
148
|
+
logoLink.href = this.logoHref;
|
|
149
|
+
logoLink.setAttribute("aria-label", this.siteName);
|
|
150
|
+
logoLink.title = this.siteName;
|
|
151
|
+
logoLink.innerHTML = LOGO_SVG;
|
|
152
|
+
left.appendChild(logoLink);
|
|
153
|
+
const right = el("div", "right");
|
|
154
|
+
const nav = el("nav", "topnav");
|
|
155
|
+
nav.setAttribute("aria-label", "Hauptnavigation");
|
|
156
|
+
const ul = buildNavList(this.topNav, {
|
|
157
|
+
setLinkContent: (a, item) => {
|
|
158
|
+
if (item.label === "my.so.ch") {
|
|
159
|
+
const label = el("span");
|
|
160
|
+
label.textContent = item.label;
|
|
161
|
+
a.append(label);
|
|
162
|
+
a.insertAdjacentHTML("beforeend", ` <svg class="icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><title>my.so.ch</title><path d="M20.39 18.71c1.48-1.84 2.36-4.17 2.36-6.71 0-5.93-4.82-10.75-10.75-10.75S1.25 6.07 1.25 12 6.07 22.75 12 22.75c3.39 0 6.41-1.58 8.38-4.04ZM12 2.75c5.1 0 9.25 4.15 9.25 9.25 0 1.93-.6 3.72-1.61 5.21-1.08-.92-3.49-2.46-7.64-2.46s-6.56 1.54-7.64 2.46A9.156 9.156 0 0 1 2.75 12c0-5.1 4.15-9.25 9.25-9.25Zm0 18.5c-2.63 0-5.01-1.11-6.69-2.88.84-.74 2.93-2.12 6.69-2.12s5.85 1.38 6.69 2.12C17 20.14 14.63 21.25 12 21.25Z"/><path d="M12 12.75c2.07 0 3.75-1.68 3.75-3.75S14.07 5.25 12 5.25 8.25 6.93 8.25 9s1.68 3.75 3.75 3.75Zm0-6c1.24 0 2.25 1.01 2.25 2.25s-1.01 2.25-2.25 2.25S9.75 10.24 9.75 9 10.76 6.75 12 6.75Z"/></svg>`);
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
nav.appendChild(ul);
|
|
169
|
+
const actions = el("div", "actions");
|
|
170
|
+
const btnMenu = el("button", "iconbtn menubtn");
|
|
171
|
+
btnMenu.type = "button";
|
|
172
|
+
btnMenu.dataset.action = "toggle-menu";
|
|
173
|
+
btnMenu.setAttribute("aria-label", "Menü");
|
|
174
|
+
btnMenu.setAttribute("aria-expanded", "false");
|
|
175
|
+
btnMenu.setAttribute("data-open", "false");
|
|
176
|
+
btnMenu.innerHTML = burgerIcon();
|
|
177
|
+
actions.append(btnMenu);
|
|
178
|
+
right.append(nav, actions);
|
|
179
|
+
topInner.append(left, right);
|
|
180
|
+
top.appendChild(topInner);
|
|
181
|
+
// Row 2: section nav
|
|
182
|
+
const second = el("div", "secondbar");
|
|
183
|
+
const secondInner = el("div", "secondbar-inner so-header-container");
|
|
184
|
+
//secondInner.style.setProperty("--so-container-size", "var(--so-container-size-full)");
|
|
185
|
+
const sectionNav = el("nav", "sectionnav");
|
|
186
|
+
sectionNav.setAttribute("aria-label", "Bereiche");
|
|
187
|
+
const sul = buildNavList(this.sectionNav, {
|
|
188
|
+
setLinkAttributes: (a, item) => {
|
|
189
|
+
a.dataset.section = item.label;
|
|
190
|
+
if (item.label === this.activeSection)
|
|
191
|
+
a.setAttribute("aria-current", "page");
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
sectionNav.appendChild(sul);
|
|
195
|
+
secondInner.appendChild(sectionNav);
|
|
196
|
+
second.appendChild(secondInner);
|
|
197
|
+
// Mobile panel (drawer-ish)
|
|
198
|
+
const mobilePanelWrap = el("div", "mobile-panel");
|
|
199
|
+
const mobilePanel = el("div", "mobile-panel-inner so-container");
|
|
200
|
+
//mobilePanel.style.setProperty("--so-container-size", "var(--so-container-size-full)");
|
|
201
|
+
mobilePanel.setAttribute("data-open", "false");
|
|
202
|
+
const mpTop = el("div", "mobile-group");
|
|
203
|
+
mpTop.appendChild(el("div", "mobile-title")).textContent = "Navigation";
|
|
204
|
+
const mpUl = buildNavList(this.topNav, { className: "mobile-list" });
|
|
205
|
+
mpTop.appendChild(mpUl);
|
|
206
|
+
const mpSections = el("div", "mobile-group");
|
|
207
|
+
mpSections.appendChild(el("div", "mobile-title")).textContent = "Bereiche";
|
|
208
|
+
const msUl = buildNavList(this.sectionNav, { className: "mobile-list" });
|
|
209
|
+
mpSections.appendChild(msUl);
|
|
210
|
+
mobilePanel.append(mpTop, mpSections);
|
|
211
|
+
mobilePanelWrap.appendChild(mobilePanel);
|
|
212
|
+
header.append(top, second, mobilePanelWrap);
|
|
213
|
+
this.root.appendChild(header);
|
|
214
|
+
}
|
|
215
|
+
styles() {
|
|
216
|
+
return (`
|
|
217
|
+
:host{
|
|
218
|
+
display: block;
|
|
219
|
+
background: var(--so-bg, #fff);
|
|
220
|
+
color: var(--so-fg, rgb(47, 72, 88));
|
|
221
|
+
font-family: var(--so-font-family, Frutiger, sans-serif);
|
|
222
|
+
font-size: var(--so-font-size, 16px);
|
|
223
|
+
line-height: var(--so-line-height, 1.5);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.so-header{
|
|
227
|
+
background: var(--so-bg, #fff);
|
|
228
|
+
color: var(--so-fg, rgb(47, 72, 88));
|
|
229
|
+
border-bottom: 1px solid var(--so-border-color);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.so-container{
|
|
233
|
+
width: 100%;
|
|
234
|
+
max-width: var(--so-container-size, var(--so-container-size-full, 120rem));
|
|
235
|
+
margin-inline: auto;
|
|
236
|
+
padding-inline: var(--so-container-padding, var(--so-space-6, 1.5rem));
|
|
237
|
+
box-sizing: border-box;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.so-header-container{
|
|
241
|
+
width: 100%;
|
|
242
|
+
margin-inline: auto;
|
|
243
|
+
padding-top: var(--so-container-padding, var(--so-space-6, 1.5rem));
|
|
244
|
+
padding-inline: var(--so-container-padding, var(--so-space-6, 1.5rem));
|
|
245
|
+
box-sizing: border-box;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.topbar-inner{
|
|
249
|
+
display: flex;
|
|
250
|
+
justify-content: space-between;
|
|
251
|
+
align-items: center;
|
|
252
|
+
gap: 1.25rem;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.logo{
|
|
256
|
+
display: inline-flex;
|
|
257
|
+
align-items: center;
|
|
258
|
+
text-decoration: none;
|
|
259
|
+
}
|
|
260
|
+
.logo svg#logo{
|
|
261
|
+
width: 10.125rem;
|
|
262
|
+
height: 1rem;
|
|
263
|
+
/*width: 10.7rem;*/ /* close to screenshot */
|
|
264
|
+
height: auto;
|
|
265
|
+
display: block;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/* Top links */
|
|
269
|
+
.right{ display: flex; align-items: center; gap: 1rem; }
|
|
270
|
+
.topnav ul{
|
|
271
|
+
list-style: none;
|
|
272
|
+
display: flex;
|
|
273
|
+
gap: 2.5rem;
|
|
274
|
+
margin: 0;
|
|
275
|
+
padding: 0;
|
|
276
|
+
align-items: center;
|
|
277
|
+
white-space: nowrap;
|
|
278
|
+
}
|
|
279
|
+
.topnav a{
|
|
280
|
+
text-decoration: none;
|
|
281
|
+
font-weight: 900;
|
|
282
|
+
color: var(--so-fg, rgb(47, 72, 88));
|
|
283
|
+
display: inline-flex;
|
|
284
|
+
align-items: center;
|
|
285
|
+
gap: 0.4rem;
|
|
286
|
+
line-height: 1;
|
|
287
|
+
}
|
|
288
|
+
.topnav a span{
|
|
289
|
+
line-height: 1;
|
|
290
|
+
}
|
|
291
|
+
.topnav .icon{
|
|
292
|
+
width: 1.5rem;
|
|
293
|
+
height: 1.5rem;
|
|
294
|
+
fill: currentColor;
|
|
295
|
+
display: block;
|
|
296
|
+
align-self: center;
|
|
297
|
+
transform: translateY(-2px);
|
|
298
|
+
}
|
|
299
|
+
.topnav a:hover{ color: rgb(204, 0, 0); }
|
|
300
|
+
|
|
301
|
+
.actions{ display: flex; align-items: center; }
|
|
302
|
+
.iconbtn{
|
|
303
|
+
border: 1px solid var(--so-border-color);
|
|
304
|
+
background: transparent;
|
|
305
|
+
border-radius: 9999px;
|
|
306
|
+
width: 2.75rem;
|
|
307
|
+
height: 2.75rem;
|
|
308
|
+
display: inline-flex;
|
|
309
|
+
align-items: center;
|
|
310
|
+
justify-content: center;
|
|
311
|
+
cursor: pointer;
|
|
312
|
+
color: rgba(0,0,0,0.8);
|
|
313
|
+
}
|
|
314
|
+
.iconbtn:hover{ background: rgba(0,0,0,0.04); }
|
|
315
|
+
.menubtn{
|
|
316
|
+
display: none;
|
|
317
|
+
color: rgb(204, 0, 0);
|
|
318
|
+
}
|
|
319
|
+
.menubtn[data-open="true"]{
|
|
320
|
+
background: rgb(204, 0, 0);
|
|
321
|
+
border-color: rgb(204, 0, 0);
|
|
322
|
+
color: #fff;
|
|
323
|
+
}
|
|
324
|
+
.menubtn[data-open="true"]:hover{
|
|
325
|
+
background: rgb(204, 0, 0);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/* Second row */
|
|
329
|
+
.secondbar{
|
|
330
|
+
width: 100%;
|
|
331
|
+
/*margin-block: 0.4rem;*/
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.sectionnav ul{
|
|
335
|
+
list-style: none;
|
|
336
|
+
display: flex;
|
|
337
|
+
gap: 1.5rem;
|
|
338
|
+
margin: 0;
|
|
339
|
+
padding: 0;
|
|
340
|
+
padding-top: var(--so-space-2, 0.5rem);
|
|
341
|
+
align-items: baseline;
|
|
342
|
+
/*border-bottom: 1px solid rgba(0,0,0,0.08);*/
|
|
343
|
+
}
|
|
344
|
+
.sectionnav a{
|
|
345
|
+
text-decoration: none;
|
|
346
|
+
font-weight: 900;
|
|
347
|
+
font-size: 1.5rem;
|
|
348
|
+
letter-spacing: -0.01em;
|
|
349
|
+
color: var(--so-fg, rgb(47, 72, 88));
|
|
350
|
+
padding-bottom: 0.45rem;
|
|
351
|
+
border-bottom: 1px solid transparent;
|
|
352
|
+
margin-bottom: -1px;
|
|
353
|
+
display: inline-block;
|
|
354
|
+
}
|
|
355
|
+
.sectionnav a:hover{
|
|
356
|
+
color: rgb(204, 0, 0);
|
|
357
|
+
}
|
|
358
|
+
.sectionnav a[aria-current="page"]{
|
|
359
|
+
color: rgb(204, 0, 0);
|
|
360
|
+
border-bottom: 1px solid rgb(204, 0, 0);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/* Responsive: hide links + show menu */
|
|
364
|
+
@media (max-width: 992px){
|
|
365
|
+
.topnav ul{ gap: 2rem; }
|
|
366
|
+
}
|
|
367
|
+
@media (max-width: 768px){
|
|
368
|
+
.topnav{ display: none; }
|
|
369
|
+
.sectionnav a{ font-size: 1.35rem; }
|
|
370
|
+
.menubtn{ display: inline-flex; }
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/* Mobile panel */
|
|
374
|
+
.mobile-panel{ display: none; border-top: 1px solid var(--so-border-color); }
|
|
375
|
+
.mobile-panel-inner{ padding-block: 0.75rem 1.25rem; }
|
|
376
|
+
@media (max-width: 768px){
|
|
377
|
+
.mobile-panel{
|
|
378
|
+
display: block;
|
|
379
|
+
border: 0;
|
|
380
|
+
}
|
|
381
|
+
.mobile-panel-inner[data-open="false"]{ display: none; }
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.mobile-group{ margin-top: 0.75rem; }
|
|
385
|
+
.mobile-title{ font-weight: 900; margin-bottom: 0.5rem; }
|
|
386
|
+
|
|
387
|
+
.mobile-list{
|
|
388
|
+
list-style: none;
|
|
389
|
+
margin: 0;
|
|
390
|
+
padding: 0;
|
|
391
|
+
display: grid;
|
|
392
|
+
gap: 0;
|
|
393
|
+
|
|
394
|
+
border-top: 1px solid var(--so-border-color);
|
|
395
|
+
border-bottom: 1px solid var(--so-border-color);
|
|
396
|
+
/*border-radius: 0.6rem;*/
|
|
397
|
+
overflow: hidden; /* clips inner items to rounded corners */
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.mobile-list a{
|
|
401
|
+
display: block;
|
|
402
|
+
padding: 0.65rem 0.75rem;
|
|
403
|
+
text-decoration: none;
|
|
404
|
+
font-size: 1rem;
|
|
405
|
+
|
|
406
|
+
border: 0; /* remove per-item border */
|
|
407
|
+
border-radius: 0; /* only the container rounds */
|
|
408
|
+
background: rgba(255,255,255,0.75);
|
|
409
|
+
color: var(--so-fg, rgb(47, 72, 88));
|
|
410
|
+
font-weight: 400;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/* add separators (1px) between items */
|
|
414
|
+
.mobile-list li + li a{
|
|
415
|
+
border-top: 1px solid var(--so-border-color);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.mobile-list a:hover{
|
|
419
|
+
color: rgb(204, 0, 0);
|
|
420
|
+
background: rgba(255,255,255,0.95);
|
|
421
|
+
}
|
|
422
|
+
`).replace(/^[\t ]+/gm, "").trim() + "\n";
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
SoHeader.observedAttributes = ["top-nav", "section-nav", "active-section", "logo-href", "site-name"];
|
|
426
|
+
function burgerIcon() {
|
|
427
|
+
return `
|
|
428
|
+
<svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
|
429
|
+
<path fill="currentColor" d="M4 7h16v2H4V7zm0 6h16v2H4v-2zm0 6h16v2H4v-2z"/>
|
|
430
|
+
</svg>`;
|
|
431
|
+
}
|
|
432
|
+
function closeIcon() {
|
|
433
|
+
return `
|
|
434
|
+
<svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
|
435
|
+
<path fill="currentColor" d="M18.3 5.71 12 12l6.3 6.29-1.41 1.42L10.59 13.4l-6.3 6.31-1.41-1.42L9.17 12 2.88 5.71l1.41-1.42 6.3 6.31 6.3-6.31 1.41 1.42Z"/>
|
|
436
|
+
</svg>`;
|
|
437
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="de">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
6
|
+
<title>so-header demo</title>
|
|
7
|
+
<link rel="stylesheet" href="../styles/reset.css">
|
|
8
|
+
<link rel="stylesheet" href="../styles/fonts.css">
|
|
9
|
+
<link rel="stylesheet" href="../styles/tokens.css">
|
|
10
|
+
<script type="module" src="../index.js"></script>
|
|
11
|
+
<style>
|
|
12
|
+
body{ background: var(--so-bg); color: var(--so-fg); font-family: var(--so-font-family); }
|
|
13
|
+
main{ padding: 2rem 0; }
|
|
14
|
+
.so-container{ max-width: var(--so-container-size-full); margin-inline:auto; padding-inline: var(--so-container-padding); }
|
|
15
|
+
.hero{
|
|
16
|
+
height: 260px;
|
|
17
|
+
border-radius: 12px;
|
|
18
|
+
background: linear-gradient(135deg, rgba(0,0,0,0.08), rgba(0,0,0,0.02));
|
|
19
|
+
border: 1px solid rgba(0,0,0,0.08);
|
|
20
|
+
display:flex;
|
|
21
|
+
align-items:flex-end;
|
|
22
|
+
padding: 1.25rem;
|
|
23
|
+
font-size: clamp(1.5rem, 3.5vw, 3rem);
|
|
24
|
+
font-weight: 900;
|
|
25
|
+
}
|
|
26
|
+
</style>
|
|
27
|
+
</head>
|
|
28
|
+
<body>
|
|
29
|
+
<so-header></so-header>
|
|
30
|
+
<so-breadcrumb>
|
|
31
|
+
<so-breadcrumb-item href="https://so.ch">so.ch</so-breadcrumb-item>
|
|
32
|
+
<so-breadcrumb-item href="https://so.ch/verwaltung/">Verwaltung</so-breadcrumb-item>
|
|
33
|
+
<so-breadcrumb-item href="https://so.ch/verwaltung/bau-und-justizdepartement/">Bau- und Justizdepartement</so-breadcrumb-item>
|
|
34
|
+
<so-breadcrumb-item href="https://so.ch/verwaltung/bau-und-justizdepartement/amt-fuer-geoinformation/" isCurrentPage>
|
|
35
|
+
Amt für Geoinformation
|
|
36
|
+
</so-breadcrumb-item>
|
|
37
|
+
</so-breadcrumb>
|
|
38
|
+
|
|
39
|
+
<main>
|
|
40
|
+
<div class="so-container">
|
|
41
|
+
<div class="hero">Willkommen beim Kanton Solothurn</div>
|
|
42
|
+
</div>
|
|
43
|
+
</main>
|
|
44
|
+
|
|
45
|
+
<script type="module">
|
|
46
|
+
const header = document.querySelector("so-header");
|
|
47
|
+
header?.addEventListener("so-section-select", (e) => console.log("section select", e.detail));
|
|
48
|
+
</script>
|
|
49
|
+
</body>
|
|
50
|
+
</html>
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SoBreadcrumb, SoBreadcrumbItem } from "./components/so-breadcrumb.js";
|
|
2
|
+
import { SoHeader } from "./components/so-header.js";
|
|
3
|
+
if (!customElements.get("so-header")) {
|
|
4
|
+
customElements.define("so-header", SoHeader);
|
|
5
|
+
}
|
|
6
|
+
if (!customElements.get("so-breadcrumb")) {
|
|
7
|
+
customElements.define("so-breadcrumb", SoBreadcrumb);
|
|
8
|
+
}
|
|
9
|
+
if (!customElements.get("so-breadcrumb-item")) {
|
|
10
|
+
customElements.define("so-breadcrumb-item", SoBreadcrumbItem);
|
|
11
|
+
}
|
|
12
|
+
export { SoBreadcrumb, SoBreadcrumbItem, SoHeader };
|