Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -485,3 +485,28 @@ Om utvecklingsservern får en annan port än 8080 används adressen den skriver
## Hemligt rymdspel

Kontroller, multiplayer, arkitektur och tester finns i [spelets README](docs/space-egg/README.md).

### Designpilot: Verkstadsmagasinet

Startsidan och `/systemutveckling/` provar en redaktionell form med serifrubriker,
panoramabilder och återkommande bildutsnitt. Det är en avgränsad designpilot;
övriga sidfamiljer behåller sin befintliga form. Den gemensamma mobilfootern
är kompaktare på samtliga sidor, med två kolumner och minst 44 px höga länkar. CSS ligger i
`_includes/styles/magazine.scss` med brytpunkter sist i `responsive.scss`.
Georgia används från besökarens system; inga externa fonter eller nya paket laddas.

Startsidan får formen via `magazine-page` i `home.html`. På en Markdown-sida med
`layout: sections` väljs den med `presentation: magazine` i front matter.
Innehållet ligger fortsatt i Markdown och befintlig startsidesdata.

En ensam Markdown-bild inne i en hero, `![](/assets/img/...)`, blir en dekorativ
panoramabild mellan ingress och sammanfattning. Kontaktlänkarna ligger efter
sammanfattningen. Utan bild behåller hero-sektionen sin tidigare struktur.
Startsidan anger bilden via `intro.image` i `_data/home/content.json` och
respektive tjänsteutsnitt via `services.items[].image`. Bilderna återanvänds
från bildförslaget i PR #59; inga av dess font- eller komponentändringar ingår.
Mobilen beskär panoramat åt höger och visar tjänsterna som en lista med små
bildutsnitt. Bildrörelse vid hovring stängs av vid minskad rörelse.

Startsidan lyfter den befintliga ingressen till huvudrubrik och använder den
befintliga huvudrubriken som ingress. Det här är ett medvetet designförslag.
15 changes: 10 additions & 5 deletions _data/home/content.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"intro": {
"heading": "Vi är experter på den senaste mjukvarutekniken",
"emphasis": "och erbjuder den till våra kunder.",
"lead": "Nyfikna på att utforska nytt, med erfarenhet av vad som håller."
"lead": "Nyfikna på att utforska nytt, med erfarenhet av vad som håller.",
"image": "/assets/img/home-hero.webp"
},
"about": {
"eyebrow": "Athega i korthet",
Expand All @@ -14,22 +15,26 @@
{
"title": "Systemutveckling",
"description": "Seniora utvecklingskonsulter som hjälper er att utveckla, modernisera och förvalta system oavsett teknik, plattform eller var i livscykeln ni befinner er.",
"href": "/systemutveckling/"
"href": "/systemutveckling/",
"image": "/assets/img/systemutveckling/hero.webp"
},
{
"title": "AI & maskininlärning",
"description": "Vi tar AI från idé till fungerande lösning, med erfarenhet av allt från analys och automation till generativa modeller.",
"href": "/ai-labbet/"
"href": "/ai-labbet/",
"image": "/assets/img/ai-labbet/hero.webp"
},
{
"title": "AI för industri",
"description": "Hårdvara, mjukvara och stöd i en helhet för produktionsnära AI, optimering, kvalitet och prediktivt underhåll.",
"href": "/ai-labbet/industri/"
"href": "/ai-labbet/industri/",
"image": "/assets/img/home-hero.webp"
},
{
"title": "Teknikgranskning",
"description": "En djup teknisk genomlysning som ger köpare, investerare och bolag ett tydligt beslutsunderlag.",
"href": "/teknikgranskning/"
"href": "/teknikgranskning/",
"image": "/assets/img/teknikgranskning/hero.webp"
}
]
},
Expand Down
5 changes: 5 additions & 0 deletions _includes/components/magazine-picture.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% if image %}
<div class="magazine-picture" aria-hidden="true">
<img src="{{ image | escape }}" alt="" fetchpriority="high">
</div>
{% endif %}
4 changes: 4 additions & 0 deletions _includes/components/service-card.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
<a class="service-card" href="{{ service.href | escape }}">
{% if service.image %}
<div class="service-card-picture"><img src="{{ service.image | escape }}" alt="" loading="lazy"></div>
<span class="service-card-number" aria-hidden="true">{% if number < 10 %}0{% endif %}{{ number }}</span>
{% endif %}
<div class="service-card-heading">
<h2>{{ service.title | escape }}</h2>
</div>
Expand Down
2 changes: 1 addition & 1 deletion _includes/home.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<main id="main" class="section-page">
<main id="main" class="section-page magazine-page">
{% include "home/intro.html" %}

<section class="section focus-section" id="tjanster">
Expand Down
5 changes: 3 additions & 2 deletions _includes/home/intro.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<section class="page-hero home-page-hero">
<div class="shell">
<h1>{{ home.content.intro.heading | escape }} <span>{{ home.content.intro.emphasis | escape }}</span></h1>
<p class="page-lead">{{ home.content.intro.lead | escape }}</p>
<h1>{{ home.content.intro.lead | escape }}</h1>
<p class="page-lead">{{ home.content.intro.heading | escape }} {{ home.content.intro.emphasis | escape }}</p>
{% include "components/magazine-picture.html", image: home.content.intro.image %}
</div>
</section>
2 changes: 1 addition & 1 deletion _includes/home/services.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<p class="eyebrow focus-label">{{ home.content.services.heading | escape }}</p>
<div class="service-grid home-service-grid">
{% for service in home.content.services.items %}
{% include "components/service-card.html", service: service %}
{% include "components/service-card.html", service: service, number: forloop.index %}
{% endfor %}
</div>
3 changes: 2 additions & 1 deletion _includes/sections/hero.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
<div class="shell">
{{ eyebrow }}
{{ heading }}
{{ lead }}
{{ lead }}{% if image %}
{% include "components/magazine-picture.html", image: image %}{% endif %}
{% if summary != empty %}
{% if variant == 'ai' %}<div class="hero-summary">{{ summary }}</div>{% else %}{{ summary }}{% endif %}
{% endif %}
Expand Down
178 changes: 178 additions & 0 deletions _includes/styles/magazine.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/* Verkstadsmagasinet: scoped to the homepage and opted-in section pages.
Existing content, navigation and other page families keep their own styles. */
.magazine-page {
--magazine-serif: Georgia, "Times New Roman", serif;
--magazine-gap: 28px;
font-weight: 400;

:is(h1, h2, h3):not(.eyebrow) {
font-family: var(--magazine-serif);
font-weight: 700;
letter-spacing: -.035em;
text-wrap: pretty;
}

> .page-hero {
padding-top: 56px;
padding-bottom: 0;
}

> .page-hero > .shell {
display: block;
}

.page-hero h1 {
max-width: 1150px;
font-size: clamp(44px, 5.5vw, 76px);
line-height: 1.08;
letter-spacing: -.045em;
}

.page-hero h1 span { color: inherit; }

.page-hero .page-lead {
max-width: 930px;
padding-left: 0;
border: 0;
color: var(--ink);
font-size: clamp(20px, 2.1vw, 28px);
line-height: 1.4;
}

> .page-hero > .shell > .magazine-picture {
margin-top: 32px;
}

> .page-hero > .shell > .hero-summary {
max-width: 820px;
margin-top: 28px;
}

> .page-hero > .shell > .hero-actions {
margin-top: 24px;
margin-bottom: 24px;
}

.home-service-grid {
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: var(--magazine-gap);
border: 0;
}

.home-service-grid .service-card {
display: flex;
flex-direction: column;
align-items: stretch;
gap: 0;
padding: 0 0 24px;
border: 0;
border-bottom: 1px solid var(--line);
}

.service-card-picture {
overflow: hidden;
margin-bottom: 22px;
background: var(--neutral);
}

.service-card-picture img {
width: 100%;
aspect-ratio: 1 / 1;
object-fit: cover;
object-position: 55% center;
transition: transform .35s ease;
}

.service-card:is(:hover, :focus-visible) img { transform: scale(1.035); }

.service-card-number {
display: flex;
align-items: center;
gap: 14px;
margin-bottom: 12px;
color: var(--muted);
font-size: var(--text-sm);
font-variant-numeric: tabular-nums;
}

.service-card-number::after {
content: "";
width: 28px;
height: 2px;
background: var(--orange);
}

.service-card h2 { font-size: clamp(23px, 2vw, 28px); line-height: 1.15; }
.service-card p { margin-top: 16px; font-size: var(--text-base); }

.focus-section > .shell > .section-heading {
display: grid;
grid-template-columns: 220px minmax(0, 1fr);
gap: 40px;
margin: 0 0 44px;
padding-top: 4px;
}

.focus-section .focus-intro { font-size: var(--text-base); }
.focus-label { margin-bottom: 24px; }

.home-latest { margin-top: 56px; }
.home-latest-grid { gap: var(--magazine-gap); }
.home-latest-card {
grid-template-columns: 110px minmax(0, 1fr);
gap: 18px;
min-height: 0;
border: 0;
border-radius: 0;
overflow: visible;
transition: none;
}
.home-latest-card:hover { transform: none; }
.home-latest-card img { height: 150px; min-height: 0; }
.home-latest-card > div { padding: 0; }
.home-latest-card h3 { font-size: 21px; line-height: 1.2; hyphens: none; overflow-wrap: anywhere; }
.home-latest-card:is(:hover, :focus-visible) h3 {
text-decoration: underline;
text-decoration-color: var(--orange);
text-underline-offset: .2em;
}
.home-latest-card p { font-size: var(--text-sm); line-height: 1.5; }

.section-heading h2 { font-size: clamp(30px, 3.4vw, 44px); }
.join-grid h2 { font-size: clamp(28px, 3vw, 38px); }

.focus-grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 32px var(--magazine-gap);
border: 0;
}
.focus-grid article {
min-height: 0;
padding: 24px 0 0;
border: 0;
border-top: 1px solid var(--line);
}
.focus-grid h3, .step-grid h3 { font-size: 26px; }
.focus-grid p { font-size: var(--text-base); }
.step-grid { gap: var(--magazine-gap); }
.step-grid article {
border-radius: 0;
padding: 24px 0 0;
border-top: 2px solid var(--orange);
background: transparent;
}
.soft-section, .join-section { background: #f5f4f1; }
}

.magazine-picture {
width: 100%;
padding-bottom: 16px;
border-bottom: 1px solid var(--orange);
}
.magazine-picture img {
width: 100%;
height: auto;
aspect-ratio: 1916 / 700;
object-fit: cover;
object-position: center 60%;
}
60 changes: 58 additions & 2 deletions _includes/styles/responsive.scss
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,62 @@
.article-shell { padding-top: 45px; }
.back-link { margin-bottom: 45px; }
.article-body iframe { min-height: 260px; }
.footer-top { grid-template-columns: 1fr; }
.footer-bottom { gap: 20px; }
.site-footer { padding: 32px 0 20px; }
.footer-top { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px 20px; }
.footer-top > div:first-child { grid-column: 1 / -1; }
.footer-top img { width: 120px; margin-bottom: 0; }
.footer-links { min-width: 0; gap: 0; }
.footer-links > span { margin-bottom: 8px; }
.footer-links a { display: flex; align-items: center; min-height: 44px; overflow-wrap: anywhere; }
.footer-links p { margin: 8px 0 0; }
.footer-social { grid-column: 1 / -1; width: auto; flex-direction: row; flex-wrap: wrap; gap: 0 24px; }
.footer-social > span { flex-basis: 100%; }
.footer-social a { justify-content: flex-start; }
.footer-bottom { flex-wrap: wrap; gap: 8px 20px; margin-top: 24px; padding-top: 16px; }
}

/* Editorial pilot: keep image crops and text readable before four columns fit. */
@media (max-width: 1100px) {
.magazine-page .home-service-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.magazine-page .service-card-picture img { aspect-ratio: 3 / 2; }
.magazine-page .home-latest-grid { grid-template-columns: 1fr; }
.magazine-page .home-latest-card { grid-template-columns: 150px minmax(0, 1fr); }
.magazine-page .focus-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 640px) {
.magazine-page { --magazine-gap: 24px; }
.magazine-page > .page-hero { padding-top: 36px; }
.magazine-page .page-hero h1 { font-size: clamp(36px, 9.7vw, 52px); }
.magazine-page .page-hero .page-lead { font-size: 20px; }
.magazine-page > .page-hero > .shell > .magazine-picture { margin-top: 24px; }
.magazine-picture img { aspect-ratio: 3 / 2; object-position: 70% center; }
.magazine-page .focus-section > .shell > .section-heading { grid-template-columns: 1fr; gap: 0; margin-bottom: 32px; }
.magazine-page .home-service-grid { grid-template-columns: 1fr; }
.magazine-page .home-service-grid .service-card {
display: grid;
grid-template-columns: 112px minmax(0, 1fr);
column-gap: 18px;
align-items: start;
}
.magazine-page .service-card-picture { grid-column: 1; grid-row: 1 / 4; margin-bottom: 0; }
.magazine-page .service-card-picture img { aspect-ratio: 1 / 1; }
.magazine-page .service-card-number, .magazine-page .service-card-heading, .magazine-page .service-card p { grid-column: 2; }
.magazine-page .service-card h2 { font-size: 23px; overflow-wrap: anywhere; }
.magazine-page .service-card p { font-size: var(--text-sm); margin-top: 12px; }
.magazine-page .home-latest { margin-top: 40px; }
.magazine-page .home-latest-card { grid-template-columns: 100px minmax(0, 1fr); gap: 16px; }
.magazine-page .home-latest-card img { height: 132px; }
.magazine-page .home-latest-card h3 { font-size: 21px; }
.magazine-page .focus-grid { grid-template-columns: 1fr; }
.magazine-page .focus-grid h3, .magazine-page .step-grid h3 { font-size: 25px; }
}

@media (prefers-reduced-motion: reduce) {
.magazine-page .service-card img { transition: none; }
.magazine-page .service-card:is(:hover, :focus-visible) img { transform: none; }
}

@media print {
.magazine-picture, .magazine-page .service-card-picture { display: none; }
}
2 changes: 1 addition & 1 deletion _layouts/sections.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
layout: default
---
<main id="main" class="section-page">
<main id="main" class="section-page{% if presentation == 'magazine' %} magazine-page{% endif %}">
{{ content }}
</main>
Binary file added assets/img/ai-labbet/hero.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/home-hero.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/systemutveckling/hero.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/teknikgranskning/hero.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/site.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@
@use "styles/prism";
@use "styles/footer";
@use "styles/section-spacing";
@use "styles/magazine";
@use "styles/responsive";
7 changes: 7 additions & 0 deletions scripts/markdown-sections.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ export function createSectionRenderer(md, renderTemplate) {
template = 'hero';
Object.assign(data, header(blocks, 'h1'));
if (!data.heading) throw new Error('A hero needs a # heading.');
const imageIndex = blocks.findIndex(block => {
const tokens = inlineTokens(block);
return block[0].type === 'paragraph_open' && tokens.length === 1 && tokens[0].type === 'image';
});
if (imageIndex !== -1) {
data.image = inlineTokens(blocks.splice(imageIndex, 1)[0])[0].attrGet('src');
}
data.links = links(blocks);
data.lead = paragraph(blocks.shift(), 'page-lead');
data.summary = variant === 'ai' ? render(blocks) : blocks.map(block => paragraph(block, 'hero-summary')).join('');
Expand Down
Loading
Loading