@sumaq/site-kit 0.2.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/README.md +93 -0
- package/package.json +57 -0
- package/src/astro-modules.d.ts +11 -0
- package/src/blocks/About.astro +94 -0
- package/src/blocks/Audience.astro +66 -0
- package/src/blocks/BlockRenderer.astro +105 -0
- package/src/blocks/Contact.astro +58 -0
- package/src/blocks/ContactDetails.astro +91 -0
- package/src/blocks/CtaBand.astro +53 -0
- package/src/blocks/EmergencyGrid.astro +47 -0
- package/src/blocks/EmergencyHelplines.astro +109 -0
- package/src/blocks/EmergencyPrimary.astro +51 -0
- package/src/blocks/Faq.astro +56 -0
- package/src/blocks/FeatureList.astro +73 -0
- package/src/blocks/Gallery.astro +95 -0
- package/src/blocks/Generic.astro +30 -0
- package/src/blocks/Hero.astro +82 -0
- package/src/blocks/IntroCta.astro +41 -0
- package/src/blocks/LegalDocument.astro +83 -0
- package/src/blocks/LocationsOverview.astro +161 -0
- package/src/blocks/NotFound.astro +33 -0
- package/src/blocks/Notice.astro +49 -0
- package/src/blocks/PageBanner.astro +57 -0
- package/src/blocks/Pricing.astro +97 -0
- package/src/blocks/ProfileDetail.astro +202 -0
- package/src/blocks/Projects.astro +91 -0
- package/src/blocks/Quote.astro +53 -0
- package/src/blocks/Services.astro +46 -0
- package/src/blocks/Skills.astro +65 -0
- package/src/blocks/Stats.astro +54 -0
- package/src/blocks/Steps.astro +76 -0
- package/src/blocks/TeamDirectory.astro +164 -0
- package/src/blocks/TeamTeaser.astro +84 -0
- package/src/blocks/Testimonials.astro +75 -0
- package/src/blocks/Timeline.astro +65 -0
- package/src/components/Actions.astro +67 -0
- package/src/components/Card.astro +104 -0
- package/src/components/Logo.astro +57 -0
- package/src/components/Media.astro +83 -0
- package/src/components/Prose.astro +29 -0
- package/src/components/ScrollToTop.astro +49 -0
- package/src/components/Section.astro +75 -0
- package/src/components/SectionHeader.astro +58 -0
- package/src/components/SectionHeading.astro +76 -0
- package/src/components/Seo.astro +55 -0
- package/src/components/SiteFooter.astro +90 -0
- package/src/components/SiteHeader.astro +97 -0
- package/src/config.ts +59 -0
- package/src/index.ts +75 -0
- package/src/layouts/Base.astro +57 -0
- package/src/lib/collections.ts +101 -0
- package/src/lib/content.ts +51 -0
- package/src/lib/format.ts +17 -0
- package/src/lib/markdown.ts +5 -0
- package/src/profiles/clinic.yaml +35 -0
- package/src/profiles/portfolio.yaml +27 -0
- package/src/profiles/therapist.yaml +31 -0
- package/src/scripts/enhancements.js +459 -0
- package/src/tokens/class-inventory.json +284 -0
- package/src/tokens/index.css +83 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* A single pull quote band. Present in every therapist site — the `quote`
|
|
4
|
+
* field of `Psychotherapy.astro` (www-utehofer-at), the two blockquotes of
|
|
5
|
+
* `Method.astro` / `Process.astro` (www-bettinageidl-at), the `quote` section
|
|
6
|
+
* of `AboutSection.astro` (www-juliaschaffer-at).
|
|
7
|
+
*
|
|
8
|
+
* The quotation marks belong to the design, not to the content: style them
|
|
9
|
+
* with `.sq-quote__text::before` instead of typing them into the CMS.
|
|
10
|
+
*/
|
|
11
|
+
import Section from "../components/Section.astro";
|
|
12
|
+
import Media from "../components/Media.astro";
|
|
13
|
+
import { cmsKey, hasImage, hasText } from "../lib/content";
|
|
14
|
+
|
|
15
|
+
const {
|
|
16
|
+
text,
|
|
17
|
+
author,
|
|
18
|
+
authorRole,
|
|
19
|
+
image,
|
|
20
|
+
section = "quote",
|
|
21
|
+
variant = "muted",
|
|
22
|
+
id,
|
|
23
|
+
} = Astro.props;
|
|
24
|
+
|
|
25
|
+
const cms = section;
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
{
|
|
29
|
+
hasText(text) && (
|
|
30
|
+
<Section name="quote" variant={variant} id={id} container="narrow" cms={cms}>
|
|
31
|
+
{hasImage(image) && (
|
|
32
|
+
<div class="sq-quote__media" aria-hidden="true">
|
|
33
|
+
<Media src={image} alt="" cms={cmsKey(cms, "image", "src")} />
|
|
34
|
+
</div>
|
|
35
|
+
)}
|
|
36
|
+
<blockquote class="sq-quote__body">
|
|
37
|
+
<p class="sq-quote__text" data-cms={cmsKey(cms, "text")}>
|
|
38
|
+
{text}
|
|
39
|
+
</p>
|
|
40
|
+
{hasText(author) && (
|
|
41
|
+
<footer class="sq-quote__author">
|
|
42
|
+
<cite data-cms={cmsKey(cms, "author")}>{author}</cite>
|
|
43
|
+
{hasText(authorRole) && (
|
|
44
|
+
<span class="sq-quote__author-role" data-cms={cmsKey(cms, "authorRole")}>
|
|
45
|
+
{authorRole}
|
|
46
|
+
</span>
|
|
47
|
+
)}
|
|
48
|
+
</footer>
|
|
49
|
+
)}
|
|
50
|
+
</blockquote>
|
|
51
|
+
</Section>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Section from "../components/Section.astro";
|
|
3
|
+
import SectionHeader from "../components/SectionHeader.astro";
|
|
4
|
+
import { cmsKey, hasText, list } from "../lib/content";
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
sectionLabel,
|
|
8
|
+
sectionTitle,
|
|
9
|
+
sectionTitleAccent,
|
|
10
|
+
sectionSubtitle,
|
|
11
|
+
items = [],
|
|
12
|
+
section = "services",
|
|
13
|
+
variant = "muted",
|
|
14
|
+
id = "services",
|
|
15
|
+
} = Astro.props;
|
|
16
|
+
|
|
17
|
+
const cms = section;
|
|
18
|
+
const cards = list<any>(items).filter((item) => hasText(item.title) || hasText(item.body));
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
<Section name="services" variant={variant} id={id} cms={cms}>
|
|
22
|
+
<SectionHeader
|
|
23
|
+
label={sectionLabel}
|
|
24
|
+
title={sectionTitle}
|
|
25
|
+
titleAccent={sectionTitleAccent}
|
|
26
|
+
lede={sectionSubtitle}
|
|
27
|
+
cms={cms}
|
|
28
|
+
/>
|
|
29
|
+
{
|
|
30
|
+
cards.length > 0 && (
|
|
31
|
+
<div class="sq-services__grid">
|
|
32
|
+
{cards.map((item: any, i: number) => (
|
|
33
|
+
<article class="sq-services__card">
|
|
34
|
+
{hasText(item.icon) && (
|
|
35
|
+
<div class={`sq-services__icon sq-services__icon--${item.icon}`} aria-hidden="true">
|
|
36
|
+
✦
|
|
37
|
+
</div>
|
|
38
|
+
)}
|
|
39
|
+
{hasText(item.title) && <h3 data-cms={cmsKey(cms, "items", i, "title")}>{item.title}</h3>}
|
|
40
|
+
{hasText(item.body) && <p data-cms={cmsKey(cms, "items", i, "body")}>{item.body}</p>}
|
|
41
|
+
</article>
|
|
42
|
+
))}
|
|
43
|
+
</div>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
</Section>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Labelled groups of tags. Extracted from `Skills.astro` (www-elingan-dev);
|
|
4
|
+
* the same shape covers the `focusAreas` / `methods` / `activityAreas` tag
|
|
5
|
+
* groups that www-therapieraum-graz-at inlines in its profile pages.
|
|
6
|
+
*/
|
|
7
|
+
import Section from "../components/Section.astro";
|
|
8
|
+
import SectionHeader from "../components/SectionHeader.astro";
|
|
9
|
+
import { cmsKey, hasText, list } from "../lib/content";
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
sectionLabel,
|
|
13
|
+
sectionTitle,
|
|
14
|
+
sectionTitleAccent,
|
|
15
|
+
sectionSubtitle,
|
|
16
|
+
groups = [],
|
|
17
|
+
section = "skills",
|
|
18
|
+
variant = "muted",
|
|
19
|
+
id = "skills",
|
|
20
|
+
} = Astro.props;
|
|
21
|
+
|
|
22
|
+
const cms = section;
|
|
23
|
+
const blocks = list<any>(groups)
|
|
24
|
+
.map((group) => ({
|
|
25
|
+
...group,
|
|
26
|
+
entries: list<any>(group.items)
|
|
27
|
+
.map((item) => (typeof item === "string" ? item : item.name))
|
|
28
|
+
.filter(hasText),
|
|
29
|
+
}))
|
|
30
|
+
.filter((group) => group.entries.length > 0 || hasText(group.label));
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
<Section name="skills" variant={variant} id={id} cms={cms}>
|
|
34
|
+
<SectionHeader
|
|
35
|
+
label={sectionLabel}
|
|
36
|
+
title={sectionTitle}
|
|
37
|
+
titleAccent={sectionTitleAccent}
|
|
38
|
+
lede={sectionSubtitle}
|
|
39
|
+
cms={cms}
|
|
40
|
+
/>
|
|
41
|
+
{
|
|
42
|
+
blocks.length > 0 && (
|
|
43
|
+
<div class="sq-skills__body">
|
|
44
|
+
{blocks.map((group: any, i: number) => (
|
|
45
|
+
<article class="sq-skills__group">
|
|
46
|
+
{hasText(group.label) && (
|
|
47
|
+
<h3 class="sq-skills__label" data-cms={cmsKey(cms, "groups", i, "label")}>
|
|
48
|
+
{group.label}
|
|
49
|
+
</h3>
|
|
50
|
+
)}
|
|
51
|
+
{group.entries.length > 0 && (
|
|
52
|
+
<ul class="sq-skills__tags" role="list">
|
|
53
|
+
{group.entries.map((entry: string, ei: number) => (
|
|
54
|
+
<li class="sq-tag" data-cms={cmsKey(cms, "groups", i, "items", ei, "name")}>
|
|
55
|
+
{entry}
|
|
56
|
+
</li>
|
|
57
|
+
))}
|
|
58
|
+
</ul>
|
|
59
|
+
)}
|
|
60
|
+
</article>
|
|
61
|
+
))}
|
|
62
|
+
</div>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
</Section>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* A row of figures — the `stats` list that `Hero` renders inline and the
|
|
4
|
+
* `meta` list of `Hero.astro` in www-elingan-dev, as a standalone band so a
|
|
5
|
+
* page can place it anywhere.
|
|
6
|
+
*/
|
|
7
|
+
import Section from "../components/Section.astro";
|
|
8
|
+
import SectionHeader from "../components/SectionHeader.astro";
|
|
9
|
+
import { cmsKey, hasText, list } from "../lib/content";
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
sectionLabel,
|
|
13
|
+
sectionTitle,
|
|
14
|
+
sectionTitleAccent,
|
|
15
|
+
sectionSubtitle,
|
|
16
|
+
items = [],
|
|
17
|
+
section = "stats",
|
|
18
|
+
variant = "muted",
|
|
19
|
+
id,
|
|
20
|
+
} = Astro.props;
|
|
21
|
+
|
|
22
|
+
const cms = section;
|
|
23
|
+
const figures = list<any>(items).filter((item) => hasText(item.value) || hasText(item.label));
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
<Section name="stats" variant={variant} id={id} cms={cms}>
|
|
27
|
+
<SectionHeader
|
|
28
|
+
label={sectionLabel}
|
|
29
|
+
title={sectionTitle}
|
|
30
|
+
titleAccent={sectionTitleAccent}
|
|
31
|
+
lede={sectionSubtitle}
|
|
32
|
+
cms={cms}
|
|
33
|
+
/>
|
|
34
|
+
{
|
|
35
|
+
figures.length > 0 && (
|
|
36
|
+
<dl class="sq-stats__body">
|
|
37
|
+
{figures.map((item: any, i: number) => (
|
|
38
|
+
<div class="sq-stats__item">
|
|
39
|
+
{hasText(item.value) && (
|
|
40
|
+
<dt class="sq-stats__value" data-cms={cmsKey(cms, "items", i, "value")}>
|
|
41
|
+
{item.value}
|
|
42
|
+
</dt>
|
|
43
|
+
)}
|
|
44
|
+
{hasText(item.label) && (
|
|
45
|
+
<dd class="sq-stats__label" data-cms={cmsKey(cms, "items", i, "label")}>
|
|
46
|
+
{item.label}
|
|
47
|
+
</dd>
|
|
48
|
+
)}
|
|
49
|
+
</div>
|
|
50
|
+
))}
|
|
51
|
+
</dl>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
</Section>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Numbered process. Extracted from `Process.astro` + `ItemStep.astro`
|
|
4
|
+
* (www-utehofer-at) and `Process.astro` (www-bettinageidl-at).
|
|
5
|
+
*
|
|
6
|
+
* The number is markup, not content: it comes from the item's position, so
|
|
7
|
+
* reordering steps in the CMS renumbers them.
|
|
8
|
+
*/
|
|
9
|
+
import Section from "../components/Section.astro";
|
|
10
|
+
import SectionHeader from "../components/SectionHeader.astro";
|
|
11
|
+
import Media from "../components/Media.astro";
|
|
12
|
+
import { cmsKey, hasAny, hasImage, hasText, list } from "../lib/content";
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
sectionLabel,
|
|
16
|
+
sectionTitle,
|
|
17
|
+
sectionTitleAccent,
|
|
18
|
+
sectionSubtitle,
|
|
19
|
+
items = [],
|
|
20
|
+
note,
|
|
21
|
+
section = "steps",
|
|
22
|
+
variant = "muted",
|
|
23
|
+
id = "steps",
|
|
24
|
+
} = Astro.props;
|
|
25
|
+
|
|
26
|
+
const cms = section;
|
|
27
|
+
const steps = list<any>(items).filter((item) => hasText(item.title) || hasText(item.body));
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
<Section name="steps" variant={variant} id={id} cms={cms}>
|
|
31
|
+
<SectionHeader
|
|
32
|
+
label={sectionLabel}
|
|
33
|
+
title={sectionTitle}
|
|
34
|
+
titleAccent={sectionTitleAccent}
|
|
35
|
+
lede={sectionSubtitle}
|
|
36
|
+
cms={cms}
|
|
37
|
+
/>
|
|
38
|
+
{
|
|
39
|
+
steps.length > 0 && (
|
|
40
|
+
<ol class="sq-steps__body">
|
|
41
|
+
{steps.map((item: any, i: number) => (
|
|
42
|
+
<li class="sq-steps__item">
|
|
43
|
+
<span class="sq-steps__num" aria-hidden="true">
|
|
44
|
+
{String(i + 1).padStart(2, "0")}
|
|
45
|
+
</span>
|
|
46
|
+
{hasImage(item.icon) && (
|
|
47
|
+
<span class="sq-steps__icon" aria-hidden="true">
|
|
48
|
+
<Media src={item.icon} alt="" cms={cmsKey(cms, "items", i, "icon")} />
|
|
49
|
+
</span>
|
|
50
|
+
)}
|
|
51
|
+
{hasText(item.title) && (
|
|
52
|
+
<h3 class="sq-steps__title" data-cms={cmsKey(cms, "items", i, "title")}>
|
|
53
|
+
{item.title}
|
|
54
|
+
</h3>
|
|
55
|
+
)}
|
|
56
|
+
{hasText(item.body) && (
|
|
57
|
+
<p class="sq-steps__text" data-cms={cmsKey(cms, "items", i, "body")}>
|
|
58
|
+
{item.body}
|
|
59
|
+
</p>
|
|
60
|
+
)}
|
|
61
|
+
</li>
|
|
62
|
+
))}
|
|
63
|
+
</ol>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
{
|
|
67
|
+
hasAny(note?.title, note?.body) && (
|
|
68
|
+
<div class="sq-steps__note">
|
|
69
|
+
{hasText(note.title) && (
|
|
70
|
+
<h3 data-cms={cmsKey(cms, "note", "title")}>{note.title}</h3>
|
|
71
|
+
)}
|
|
72
|
+
{hasText(note.body) && <p data-cms={cmsKey(cms, "note", "body")}>{note.body}</p>}
|
|
73
|
+
</div>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
</Section>
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Section from "../components/Section.astro";
|
|
3
|
+
import SectionHeader from "../components/SectionHeader.astro";
|
|
4
|
+
import Media from "../components/Media.astro";
|
|
5
|
+
import { cmsKey, hasText, list } from "../lib/content";
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
sectionLabel,
|
|
9
|
+
sectionTitle,
|
|
10
|
+
sectionTitleAccent,
|
|
11
|
+
sectionSubtitle,
|
|
12
|
+
searchPlaceholder,
|
|
13
|
+
searchLabel = "Team-Mitglieder durchsuchen",
|
|
14
|
+
filtersLabel = "Fachgebiete filtern",
|
|
15
|
+
/** `{count}` is replaced at runtime by `scripts/enhancements.js`. */
|
|
16
|
+
counterAllTemplate = "Zeigt alle {count} Fachpersonen",
|
|
17
|
+
counterResultsTemplate = "Suchergebnisse: {count} Treffer",
|
|
18
|
+
filters = [],
|
|
19
|
+
emptyTitle,
|
|
20
|
+
emptyText,
|
|
21
|
+
members = [],
|
|
22
|
+
basePath = "/team",
|
|
23
|
+
section = "teamDirectory",
|
|
24
|
+
variant = "light",
|
|
25
|
+
id,
|
|
26
|
+
} = Astro.props;
|
|
27
|
+
|
|
28
|
+
const cms = section;
|
|
29
|
+
const people = list<any>(members).filter((member) => hasText(member.name));
|
|
30
|
+
const chips = list<any>(filters).filter((filter) => hasText(filter.label) && hasText(filter.value));
|
|
31
|
+
const showSearch = hasText(searchPlaceholder) && people.length > 0;
|
|
32
|
+
const [counterBefore, counterAfter = ""] = String(counterAllTemplate).split("{count}");
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
<Section name="teamDirectory" variant={variant} id={id} cms={cms}>
|
|
36
|
+
<SectionHeader
|
|
37
|
+
label={sectionLabel}
|
|
38
|
+
title={sectionTitle}
|
|
39
|
+
titleAccent={sectionTitleAccent}
|
|
40
|
+
lede={sectionSubtitle}
|
|
41
|
+
cms={cms}
|
|
42
|
+
/>
|
|
43
|
+
|
|
44
|
+
{
|
|
45
|
+
(showSearch || chips.length > 0) && (
|
|
46
|
+
<div class="sq-team__search">
|
|
47
|
+
{showSearch && (
|
|
48
|
+
<div class="sq-team__search-wrap">
|
|
49
|
+
<span class="sq-team__search-icon" aria-hidden="true">
|
|
50
|
+
<svg
|
|
51
|
+
width="20"
|
|
52
|
+
height="20"
|
|
53
|
+
viewBox="0 0 24 24"
|
|
54
|
+
fill="none"
|
|
55
|
+
stroke="currentColor"
|
|
56
|
+
stroke-width="2"
|
|
57
|
+
stroke-linecap="round"
|
|
58
|
+
stroke-linejoin="round"
|
|
59
|
+
>
|
|
60
|
+
<circle cx="11" cy="11" r="8" />
|
|
61
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65" />
|
|
62
|
+
</svg>
|
|
63
|
+
</span>
|
|
64
|
+
<input
|
|
65
|
+
type="search"
|
|
66
|
+
id="team-search"
|
|
67
|
+
class="sq-team__search-input"
|
|
68
|
+
placeholder={searchPlaceholder}
|
|
69
|
+
aria-label={searchLabel}
|
|
70
|
+
data-cms={cmsKey(cms, "searchPlaceholder")}
|
|
71
|
+
/>
|
|
72
|
+
</div>
|
|
73
|
+
)}
|
|
74
|
+
|
|
75
|
+
{chips.length > 0 && (
|
|
76
|
+
<div class="sq-team__filters" role="group" aria-label={filtersLabel}>
|
|
77
|
+
{chips.map((filter: any, i: number) => (
|
|
78
|
+
<button
|
|
79
|
+
type="button"
|
|
80
|
+
class:list={["sq-team__filter", i === 0 && "is-active"]}
|
|
81
|
+
data-filter={filter.value}
|
|
82
|
+
aria-pressed={i === 0 ? "true" : "false"}
|
|
83
|
+
data-cms={cmsKey(cms, "filters", i, "label")}
|
|
84
|
+
>
|
|
85
|
+
{filter.label}
|
|
86
|
+
</button>
|
|
87
|
+
))}
|
|
88
|
+
</div>
|
|
89
|
+
)}
|
|
90
|
+
|
|
91
|
+
{people.length > 0 && (
|
|
92
|
+
<p
|
|
93
|
+
class="sq-team__counter"
|
|
94
|
+
id="search-counter"
|
|
95
|
+
data-counter-all={counterAllTemplate}
|
|
96
|
+
data-counter-results={counterResultsTemplate}
|
|
97
|
+
>
|
|
98
|
+
{counterBefore}
|
|
99
|
+
<span id="member-count">{people.length}</span>
|
|
100
|
+
{counterAfter}
|
|
101
|
+
</p>
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
{
|
|
108
|
+
people.length > 0 && (
|
|
109
|
+
<div class="sq-team__grid" id="team-grid">
|
|
110
|
+
{people.map((member: any, i: number) => (
|
|
111
|
+
<a
|
|
112
|
+
class="sq-team__card"
|
|
113
|
+
href={member.href || `${basePath}/${member.slug}`}
|
|
114
|
+
data-search={member.searchKeywords}
|
|
115
|
+
data-categories={member.categories}
|
|
116
|
+
>
|
|
117
|
+
<div class="sq-team__photo">
|
|
118
|
+
<Media
|
|
119
|
+
src={member.photo}
|
|
120
|
+
alt={member.photo?.alt || member.name}
|
|
121
|
+
width={640}
|
|
122
|
+
height={640}
|
|
123
|
+
transition:name={`profile-photo-${member.slug}`}
|
|
124
|
+
cms={cmsKey(cms, "members", i, "photo", "src")}
|
|
125
|
+
/>
|
|
126
|
+
</div>
|
|
127
|
+
<div class="sq-team__body">
|
|
128
|
+
{hasText(member.titleSuffix) && (
|
|
129
|
+
<span class="sq-team__role" data-cms={cmsKey(cms, "members", i, "titleSuffix")}>
|
|
130
|
+
{member.titleSuffix}
|
|
131
|
+
</span>
|
|
132
|
+
)}
|
|
133
|
+
<h3 class="sq-team__name" data-cms={cmsKey(cms, "members", i, "name")}>
|
|
134
|
+
{member.name}
|
|
135
|
+
</h3>
|
|
136
|
+
{hasText(member.description || member.role) && (
|
|
137
|
+
<p
|
|
138
|
+
class="sq-team__desc"
|
|
139
|
+
data-cms={cmsKey(
|
|
140
|
+
cms,
|
|
141
|
+
"members",
|
|
142
|
+
i,
|
|
143
|
+
hasText(member.description) ? "description" : "role",
|
|
144
|
+
)}
|
|
145
|
+
>
|
|
146
|
+
{member.description || member.role}
|
|
147
|
+
</p>
|
|
148
|
+
)}
|
|
149
|
+
</div>
|
|
150
|
+
</a>
|
|
151
|
+
))}
|
|
152
|
+
</div>
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
{
|
|
157
|
+
people.length > 0 && hasText(emptyTitle || emptyText) && (
|
|
158
|
+
<div class="sq-team__empty" id="no-results" hidden>
|
|
159
|
+
{hasText(emptyTitle) && <h3 data-cms={cmsKey(cms, "emptyTitle")}>{emptyTitle}</h3>}
|
|
160
|
+
{hasText(emptyText) && <p data-cms={cmsKey(cms, "emptyText")}>{emptyText}</p>}
|
|
161
|
+
</div>
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
</Section>
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Section from "../components/Section.astro";
|
|
3
|
+
import SectionHeading from "../components/SectionHeading.astro";
|
|
4
|
+
import Media from "../components/Media.astro";
|
|
5
|
+
import { cmsKey, hasAny, hasImage, hasText, list } from "../lib/content";
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
sectionLabel,
|
|
9
|
+
sectionTitle,
|
|
10
|
+
sectionTitleAccent,
|
|
11
|
+
sectionSubtitle,
|
|
12
|
+
image,
|
|
13
|
+
badgeNum,
|
|
14
|
+
badgeLabel,
|
|
15
|
+
ctas = [],
|
|
16
|
+
section = "teamTeaser",
|
|
17
|
+
variant = "light",
|
|
18
|
+
id = "team",
|
|
19
|
+
} = Astro.props;
|
|
20
|
+
|
|
21
|
+
const cms = section;
|
|
22
|
+
const hasTitle = hasText(sectionTitle) || hasText(sectionTitleAccent);
|
|
23
|
+
const hasBadge = hasAny(badgeNum, badgeLabel);
|
|
24
|
+
/** The teaser shows a single CTA, straight in the copy column — no actions row. */
|
|
25
|
+
const cta = list<any>(ctas).find((item) => hasText(item.label) && hasText(item.href));
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
<Section
|
|
29
|
+
name="teamTeaser"
|
|
30
|
+
variant={variant}
|
|
31
|
+
id={id}
|
|
32
|
+
labelledby={hasTitle ? "team-title" : undefined}
|
|
33
|
+
containerClass="sq-split"
|
|
34
|
+
cms={cms}
|
|
35
|
+
>
|
|
36
|
+
<div class="sq-split__copy">
|
|
37
|
+
<SectionHeading
|
|
38
|
+
label={sectionLabel}
|
|
39
|
+
title={sectionTitle}
|
|
40
|
+
titleAccent={sectionTitleAccent}
|
|
41
|
+
lede={sectionSubtitle}
|
|
42
|
+
titleId="team-title"
|
|
43
|
+
cms={cms}
|
|
44
|
+
/>
|
|
45
|
+
{
|
|
46
|
+
cta && (
|
|
47
|
+
<a
|
|
48
|
+
class="sq-btn sq-btn--primary"
|
|
49
|
+
href={cta.href}
|
|
50
|
+
target={cta.external ? "_blank" : undefined}
|
|
51
|
+
rel={cta.external ? "noopener" : undefined}
|
|
52
|
+
data-cms={cmsKey(cms, "ctas", 0, "label")}
|
|
53
|
+
>
|
|
54
|
+
{cta.label}
|
|
55
|
+
</a>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
</div>
|
|
59
|
+
{
|
|
60
|
+
(hasImage(image) || hasBadge) && (
|
|
61
|
+
<div class="sq-split__visual">
|
|
62
|
+
{hasImage(image) && (
|
|
63
|
+
<figure class="sq-team-teaser__frame">
|
|
64
|
+
<Media src={image} alt={image?.alt} cms={cmsKey(cms, "image", "src")} />
|
|
65
|
+
</figure>
|
|
66
|
+
)}
|
|
67
|
+
{hasBadge && (
|
|
68
|
+
<div class="sq-team-teaser__badge" aria-hidden="true">
|
|
69
|
+
{hasText(badgeNum) && (
|
|
70
|
+
<span class="sq-team-teaser__badge-num" data-cms={cmsKey(cms, "badgeNum")}>
|
|
71
|
+
{badgeNum}
|
|
72
|
+
</span>
|
|
73
|
+
)}
|
|
74
|
+
{hasText(badgeLabel) && (
|
|
75
|
+
<span class="sq-team-teaser__badge-label" data-cms={cmsKey(cms, "badgeLabel")}>
|
|
76
|
+
{badgeLabel}
|
|
77
|
+
</span>
|
|
78
|
+
)}
|
|
79
|
+
</div>
|
|
80
|
+
)}
|
|
81
|
+
</div>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
</Section>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Several quotes as cards.
|
|
4
|
+
*
|
|
5
|
+
* Not extracted from an existing site — none of the five had one — but a
|
|
6
|
+
* standard slot every service site eventually needs, so it ships as part of
|
|
7
|
+
* the catalogue instead of being improvised per client. Same field names as
|
|
8
|
+
* `Quote`, in a list.
|
|
9
|
+
*/
|
|
10
|
+
import Section from "../components/Section.astro";
|
|
11
|
+
import SectionHeader from "../components/SectionHeader.astro";
|
|
12
|
+
import Media from "../components/Media.astro";
|
|
13
|
+
import { cmsKey, hasImage, hasText, list } from "../lib/content";
|
|
14
|
+
|
|
15
|
+
const {
|
|
16
|
+
sectionLabel,
|
|
17
|
+
sectionTitle,
|
|
18
|
+
sectionTitleAccent,
|
|
19
|
+
sectionSubtitle,
|
|
20
|
+
items = [],
|
|
21
|
+
section = "testimonials",
|
|
22
|
+
variant = "muted",
|
|
23
|
+
id = "testimonials",
|
|
24
|
+
} = Astro.props;
|
|
25
|
+
|
|
26
|
+
const cms = section;
|
|
27
|
+
const entries = list<any>(items).filter((item) => hasText(item.text));
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
<Section name="testimonials" variant={variant} id={id} cms={cms}>
|
|
31
|
+
<SectionHeader
|
|
32
|
+
label={sectionLabel}
|
|
33
|
+
title={sectionTitle}
|
|
34
|
+
titleAccent={sectionTitleAccent}
|
|
35
|
+
lede={sectionSubtitle}
|
|
36
|
+
cms={cms}
|
|
37
|
+
/>
|
|
38
|
+
{
|
|
39
|
+
entries.length > 0 && (
|
|
40
|
+
<div class="sq-testimonials__body">
|
|
41
|
+
{entries.map((item: any, i: number) => (
|
|
42
|
+
<figure class="sq-testimonials__card">
|
|
43
|
+
{hasImage(item.image) && (
|
|
44
|
+
<div class="sq-testimonials__photo">
|
|
45
|
+
<Media
|
|
46
|
+
src={item.image}
|
|
47
|
+
alt={item.image?.alt || item.author || ""}
|
|
48
|
+
width={128}
|
|
49
|
+
height={128}
|
|
50
|
+
cms={cmsKey(cms, "items", i, "image", "src")}
|
|
51
|
+
/>
|
|
52
|
+
</div>
|
|
53
|
+
)}
|
|
54
|
+
<blockquote class="sq-testimonials__text" data-cms={cmsKey(cms, "items", i, "text")}>
|
|
55
|
+
{item.text}
|
|
56
|
+
</blockquote>
|
|
57
|
+
{hasText(item.author) && (
|
|
58
|
+
<figcaption class="sq-testimonials__author">
|
|
59
|
+
<cite data-cms={cmsKey(cms, "items", i, "author")}>{item.author}</cite>
|
|
60
|
+
{hasText(item.authorRole) && (
|
|
61
|
+
<span
|
|
62
|
+
class="sq-testimonials__author-role"
|
|
63
|
+
data-cms={cmsKey(cms, "items", i, "authorRole")}
|
|
64
|
+
>
|
|
65
|
+
{item.authorRole}
|
|
66
|
+
</span>
|
|
67
|
+
)}
|
|
68
|
+
</figcaption>
|
|
69
|
+
)}
|
|
70
|
+
</figure>
|
|
71
|
+
))}
|
|
72
|
+
</div>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
</Section>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Chronological list — training, career, certificates.
|
|
4
|
+
*
|
|
5
|
+
* Extracted from the `timeline` list in `AboutSection.astro`
|
|
6
|
+
* (www-juliaschaffer-at), the `education` lists of www-utehofer-at and
|
|
7
|
+
* www-bettinageidl-at, and the `sq-profile__timeline` markup that
|
|
8
|
+
* www-therapieraum-graz-at inlines in `team/[slug].astro`.
|
|
9
|
+
*/
|
|
10
|
+
import Section from "../components/Section.astro";
|
|
11
|
+
import SectionHeader from "../components/SectionHeader.astro";
|
|
12
|
+
import { cmsKey, hasText, list } from "../lib/content";
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
sectionLabel,
|
|
16
|
+
sectionTitle,
|
|
17
|
+
sectionTitleAccent,
|
|
18
|
+
sectionSubtitle,
|
|
19
|
+
items = [],
|
|
20
|
+
section = "timeline",
|
|
21
|
+
variant = "light",
|
|
22
|
+
id,
|
|
23
|
+
} = Astro.props;
|
|
24
|
+
|
|
25
|
+
const cms = section;
|
|
26
|
+
const entries = list<any>(items)
|
|
27
|
+
.map((item) => (typeof item === "string" ? { text: item } : item))
|
|
28
|
+
.filter((item) => hasText(item.text) || hasText(item.title));
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
<Section name="timeline" variant={variant} id={id} cms={cms}>
|
|
32
|
+
<SectionHeader
|
|
33
|
+
label={sectionLabel}
|
|
34
|
+
title={sectionTitle}
|
|
35
|
+
titleAccent={sectionTitleAccent}
|
|
36
|
+
lede={sectionSubtitle}
|
|
37
|
+
cms={cms}
|
|
38
|
+
/>
|
|
39
|
+
{
|
|
40
|
+
entries.length > 0 && (
|
|
41
|
+
<ol class="sq-timeline__body">
|
|
42
|
+
{entries.map((item: any, i: number) => (
|
|
43
|
+
<li class="sq-timeline__item">
|
|
44
|
+
<span class="sq-timeline__dot" aria-hidden="true" />
|
|
45
|
+
{hasText(item.period) && (
|
|
46
|
+
<p class="sq-timeline__period" data-cms={cmsKey(cms, "items", i, "period")}>
|
|
47
|
+
{item.period}
|
|
48
|
+
</p>
|
|
49
|
+
)}
|
|
50
|
+
{hasText(item.title) && (
|
|
51
|
+
<h3 class="sq-timeline__title" data-cms={cmsKey(cms, "items", i, "title")}>
|
|
52
|
+
{item.title}
|
|
53
|
+
</h3>
|
|
54
|
+
)}
|
|
55
|
+
{hasText(item.text) && (
|
|
56
|
+
<p class="sq-timeline__text" data-cms={cmsKey(cms, "items", i, "text")}>
|
|
57
|
+
{item.text}
|
|
58
|
+
</p>
|
|
59
|
+
)}
|
|
60
|
+
</li>
|
|
61
|
+
))}
|
|
62
|
+
</ol>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
</Section>
|