refactor: ♻️ use more of the webc feature set proper

This commit is contained in:
Sebin Nyshkim 2025-04-25 00:15:50 +02:00
parent c0b42b82d0
commit aa410f916a
21 changed files with 678 additions and 723 deletions

View file

@ -1,4 +1,4 @@
<figure class="ability" webc:for="ability of abilities">
<figure webc:for="ability of abilities" webc:root="override">
<eleventy-image
webc:if="img"
class="image"
@ -8,14 +8,14 @@
sizes="(min-width: 64em) 500px, 250px"
></eleventy-image
><span class="no-image" webc:else>Here you would see an illustration… If I had one…</span>
<figcaption class="caption">
<p class="title" @text="ability.name"></p>
<p class="description" @text="ability.description"></p>
<figcaption>
<p @text="ability.name"></p>
<p @text="ability.description"></p>
</figcaption>
</figure>
<style>
.ability {
<style webc:scoped="ability">
:host {
display: grid;
grid-template:
'image' 15em
@ -29,42 +29,43 @@
@media (min-width: 45em) {
grid-template: 'image caption' 1fr / 15em 1fr;
}
}
& .image,
& .no-image {
grid-area: image;
display: grid;
place-items: center;
width: 15em;
height: 15em;
}
:host :where(.image, .no-image) {
grid-area: image;
display: grid;
place-items: center;
width: 15em;
height: 15em;
}
& .image {
width: 100%;
height: 100%;
object-fit: contain;
}
:host .image {
width: 100%;
height: 100%;
object-fit: contain;
}
& .no-image {
text-align: center;
:host .no-image {
text-align: center;
border: 0.125em dashed var(--clr-box-border);
padding: 1em;
}
border: 0.125em dashed var(--clr-box-border);
padding: 1em;
}
& .caption {
grid-area: caption;
}
:host figcaption {
grid-area: caption;
& .title {
font-family: var(--font-family-headings);
font-size: 1.5em;
font-weight: bold;
margin-block: 0;
display: grid;
gap: 0.5em;
}
& + .description {
margin-block: 0.5em 0;
}
}
:host figcaption p {
margin: 0;
}
:host figcaption p:first-child {
font-family: var(--font-family-headings);
font-size: 1.5em;
font-weight: bold;
}
</style>

View file

@ -1,4 +1,4 @@
<a class="character-card" :href="href" :class="char">
<a :href="href" :class="char" webc:root="override">
<div class="image">
<slot name="image"></slot>
</div>
@ -8,8 +8,8 @@
</div>
</a>
<style>
.character-card {
<style webc:scoped="character-card">
:host {
display: grid;
align-content: start;
@ -23,61 +23,59 @@
border-radius: 1em;
overflow: hidden;
}
&:hover {
img {
scale: 1.1;
}
}
:host:hover img {
scale: 1.1;
}
& .image {
overflow: hidden;
aspect-ratio: 3/2;
}
:host .image {
overflow: hidden;
aspect-ratio: 3/2;
}
& img {
width: 100%;
height: 100%;
object-fit: cover;
scale: 1;
transition: scale 0.2s ease-in-out;
}
:host img {
width: 100%;
height: 100%;
object-fit: cover;
scale: 1;
transition: scale 0.2s ease-in-out;
}
& .text {
--card-spacing: 1.5rem;
padding-block: var(--card-spacing);
padding-inline: var(--card-spacing);
}
:host .text {
--card-spacing: 1.5rem;
padding-block: var(--card-spacing);
padding-inline: var(--card-spacing);
}
& h2 {
position: relative;
font-size: 1.375rem;
margin-block: 0 0.5em;
padding-block: 0 0.5em;
:host h2 {
position: relative;
font-size: 1.375rem;
margin-block: 0 0.5em;
padding-block: 0 0.5em;
}
&::after {
content: '';
position: absolute;
display: block;
left: 0;
bottom: 0;
height: 0.125em;
width: 2em;
border-radius: 1em;
background: linear-gradient(
to right,
oklch(from var(--clr-heading-underline) calc(l + 0.1) c h),
oklch(from var(--clr-heading-underline) calc(l - 0.2) c h)
);
}
}
:host h2::after {
content: '';
position: absolute;
display: block;
left: 0;
bottom: 0;
height: 0.125em;
width: 2em;
border-radius: 1em;
background: linear-gradient(
to right,
oklch(from var(--clr-heading-underline) calc(l + 0.1) c h),
oklch(from var(--clr-heading-underline) calc(l - 0.2) c h)
);
}
& p {
margin-block: 0;
:host p {
margin-block: 0;
}
& + p {
margin-block: 1em 0;
}
}
:host p ~ p {
margin-block: 1em 0;
}
</style>

View file

@ -1,4 +1,4 @@
<ul class="character-colors">
<ul webc:root="override">
<li class="color" webc:for="color of colors">
<div class="color-box" @attributes="({ style: `background-color: ${color.value}`})"></div>
<p class="heading" @text="color.name"></p>
@ -6,8 +6,8 @@
</li>
</ul>
<style>
.character-colors {
<style webc:scoped="character-colors">
:host {
--columns: repeat(auto-fit, minmax(15em, 1fr));
--clearance: 0.25rem;
--color-box-size: calc(var(--clearance) * 14);
@ -23,63 +23,62 @@
--color-box-size: 5em;
--columns: repeat(auto-fit, minmax(8em, 1fr));
}
}
& .color {
--areas: 'color heading' 'color value';
--rows: repeat(2, 1fr);
--columns: var(--color-box-size) 1fr;
:host .color {
--areas: 'color heading' 'color value';
--rows: repeat(2, 1fr);
--columns: var(--color-box-size) 1fr;
display: grid;
grid-template-areas: var(--areas);
grid-template-rows: var(--rows);
grid-template-columns: var(--columns);
display: grid;
grid-template-areas: var(--areas);
grid-template-rows: var(--rows);
grid-template-columns: var(--columns);
background-color: var(--clr-color-box-background);
background-color: var(--clr-color-box-background);
border: var(--border-thin) solid var(--clr-box-border);
border-radius: 0.5em;
border: var(--border-thin) solid var(--clr-box-border);
border-radius: 0.5em;
overflow: clip;
overflow: clip;
@media (min-width: 35em) {
--areas: 'color' 'heading' 'value';
--rows: var(--color-box-size) 1fr auto;
--columns: 1fr;
}
}
& .color-box {
grid-area: color;
width: 100%;
height: 100%;
}
& .heading,
& .value {
text-align: left;
margin: 0;
padding-block: calc(var(--clearance) * 2);
padding-inline: calc(var(--clearance) * 2);
}
& .heading {
grid-area: heading;
align-self: start;
font-size: 0.625em;
line-height: 1.2;
color: var(--clr-heading-data);
text-transform: uppercase;
}
& .value {
grid-area: value;
align-self: end;
font-size: 0.75em;
padding-block: 0 calc(var(--clearance) * 2);
@media (min-width: 35em) {
--areas: 'color' 'heading' 'value';
--rows: var(--color-box-size) 1fr auto;
--columns: 1fr;
}
}
:host .color-box {
grid-area: color;
width: 100%;
height: 100%;
}
:host :where(.heading, .value) {
text-align: left;
margin: 0;
padding-block: calc(var(--clearance) * 2);
padding-inline: calc(var(--clearance) * 2);
}
:host .heading {
grid-area: heading;
align-self: start;
font-size: 0.625em;
line-height: 1.2;
text-align: start;
color: var(--clr-heading-data);
text-transform: uppercase;
}
:host .value {
grid-area: value;
align-self: end;
font-size: 0.75em;
padding-block: 0 calc(var(--clearance) * 2);
}
</style>

View file

@ -1,28 +1,28 @@
<nav class="character-nav" :aria-label="label">
<nav :aria-label="label" webc:root="override">
<label for="nav-toggle">
<icon icon="bars" webc:nokeep></icon>
<icon icon="bars"></icon>
</label>
<input type="checkbox" id="nav-toggle" />
<template
webc:nokeep
@html="eleventyNavigationToHtml(eleventyNavigation($data.collections[collection]), {
listClass: 'list',
listItemClass: 'item',
listItemHasChildrenClass: 'hasChildren',
activeListItemClass: 'item-active',
listClass: 'list',
listItemClass: 'item',
listItemHasChildrenClass: 'hasChildren',
activeListItemClass: 'item-active',
anchorClass: 'link',
activeAnchorClass: 'link-active',
anchorClass: 'link',
activeAnchorClass: 'link-active',
activeKey: $data.eleventyNavigation.key,
activeKey: $data.eleventyNavigation.key,
showExcerpt: false
})"
showExcerpt: false
})"
></template>
</nav>
<style>
.character-nav {
<style webc:scoped="character-nav">
:host {
--nav-spacing: 1em;
--nav-background-color: var(--clr-nav-background);
--nav-border: var(--border-thin) solid var(--clr-box-border);
@ -48,99 +48,97 @@
@media (min-width: 64em) {
--nav-spacing: 2em;
}
}
&:has(#nav-toggle:checked) {
& .list {
opacity: 1;
}
:host:has(#nav-toggle:checked) .list {
opacity: 1;
}
& .item {
height: 100%;
}
}
:host:has(#nav-toggle:checked) .item {
height: 100%;
}
& label[for='nav-toggle'] {
width: 1.5em;
height: 1.5em;
margin-block: 0.75em;
margin-inline: 1em;
:host label[for='nav-toggle'] {
width: 1.5em;
height: 1.5em;
margin-block: 0.75em;
margin-inline: 1em;
&:hover {
cursor: pointer;
}
@media (min-width: 35em) {
display: none;
}
}
& #nav-toggle {
@media (min-width: 35em) {
display: none;
}
}
& .list {
--nav-items-position: absolute;
--nav-items-orientation: column nowrap;
:host label[for='nav-toggle']:hover {
cursor: pointer;
}
position: var(--nav-items-position);
top: 3em;
:host #nav-toggle {
display: none;
}
display: flex;
flex-flow: var(--nav-items-orientation);
:host .list {
--nav-items-position: absolute;
--nav-items-orientation: column nowrap;
text-align: end;
list-style: none;
position: var(--nav-items-position);
top: 3em;
background-color: var(--clr-nav-background);
display: flex;
flex-flow: var(--nav-items-orientation);
margin: 0;
border: var(--border-thin) solid var(--clr-nav-border);
border-block-start: none;
border-inline-end: none;
border-end-start-radius: 0.75em;
padding-inline: var(--nav-spacing);
text-align: end;
list-style: none;
z-index: 3;
opacity: 0;
transition: opacity 0.4s ease-in-out;
background-color: var(--clr-nav-background);
@media (min-width: 35em) {
--nav-items-position: static;
--nav-items-orientation: row nowrap;
align-items: start;
gap: 1em;
opacity: 1;
}
}
margin: 0;
border: var(--border-thin) solid var(--clr-nav-border);
border-block-start: none;
border-inline-end: none;
border-end-start-radius: 0.75em;
padding-inline: var(--nav-spacing);
& .item {
overflow: hidden;
height: 0;
transition: height 0.4s ease-in-out;
z-index: 3;
opacity: 0;
transition: opacity 0.4s ease-in-out;
@media (min-width: 35em) {
height: 100%;
}
}
& .link {
display: block;
font-weight: 500;
text-decoration: none;
color: var(--clr-nav-link, inherit);
padding-block: calc(var(--nav-spacing) / 2);
transition: color 0.4s ease;
&:hover {
color: var(--clr-nav-link-hover);
}
}
& .link-active {
color: var(--clr-nav-link-active);
@media (min-width: 35em) {
--nav-items-position: static;
--nav-items-orientation: row nowrap;
align-items: start;
gap: 1em;
opacity: 1;
}
}
:host .item {
overflow: hidden;
height: 0;
transition: height 0.4s ease-in-out;
@media (min-width: 35em) {
height: 100%;
}
}
:host .link {
display: block;
font-weight: 500;
text-decoration: none;
color: var(--clr-nav-link, inherit);
padding-block: calc(var(--nav-spacing) / 2);
transition: color 0.4s ease;
}
:host .link:hover {
color: var(--clr-nav-link-hover);
}
:host .link-active {
color: var(--clr-nav-link-active);
}
</style>

View file

@ -1,11 +1,11 @@
<section class="page-content">
<navigation label="Character" page :collection="char" webc:nokeep></navigation>
<section webc:root="override">
<navigation label="Character" :collection="char"></navigation>
<slot></slot>
</section>
<style>
.page-content {
<style webc:scoped="page-content">
:host {
width: 100%;
background-color: var(--clr-box-background);
@ -13,55 +13,55 @@
border-radius: var(--border-radius);
overflow: clip;
}
& :where(h1, h2, h3, h4, h5, h6) {
--heading-spacing: 0.25em;
position: relative;
font-weight: bold;
margin-block: 0 var(--heading-spacing);
padding-block: 0 var(--heading-spacing);
:host :where(h1, h2, h3, h4, h5, h6) {
--heading-spacing: 0.25em;
position: relative;
font-weight: bold;
margin-block: 0 var(--heading-spacing);
padding-block: 0 var(--heading-spacing);
}
&::after {
content: '';
position: absolute;
display: block;
left: 0;
bottom: 0;
height: 0.125em;
width: 2em;
border-radius: 1em;
background: linear-gradient(
to right,
oklch(from var(--clr-heading-underline) calc(l + 0.1) c h),
oklch(from var(--clr-heading-underline) calc(l - 0.2) c h)
);
}
}
:host :where(h1, h2, h3, h4, h5, h6)::after {
content: '';
position: absolute;
display: block;
left: 0;
bottom: 0;
height: 0.125em;
width: 2em;
border-radius: 1em;
background: linear-gradient(
to right,
oklch(from var(--clr-heading-underline) calc(l + 0.1) c h),
oklch(from var(--clr-heading-underline) calc(l - 0.2) c h)
);
}
& h1 {
font-size: 3em;
}
:host h1 {
font-size: 3em;
}
& h2 {
font-size: 2em;
}
:host h2 {
font-size: 2em;
}
& p {
text-align: justify;
}
:host p {
text-align: justify;
}
& article a {
color: inherit;
text-decoration: underline;
text-underline-offset: 0.1875em;
text-decoration-thickness: 0.125em;
text-decoration-skip-ink: all;
text-decoration-color: var(--clr-link-underline);
transition: color 0.2s ease;
:host article a {
color: inherit;
text-decoration: underline;
text-underline-offset: 0.1875em;
text-decoration-thickness: 0.125em;
text-decoration-skip-ink: all;
text-decoration-color: var(--clr-link-underline);
transition: color 0.2s ease;
}
&:hover {
color: var(--clr-link);
}
}
:host article a:hover {
color: var(--clr-link);
}
</style>

View file

@ -1,4 +1,4 @@
<aside class="profile">
<aside webc:root="override">
<div class="avatar">
<slot name="avatar"></slot>
</div>
@ -11,8 +11,8 @@
<slot></slot>
</aside>
<style>
.profile {
<style webc:scoped="profile">
:host {
--sidebar-position: static;
--sidebar-padding: 1rem;
--sidebar-grid-columns: auto 1fr;
@ -45,45 +45,44 @@
--sidebar-top-text-align: center;
--sidebar-avatar-size: 10em;
}
}
& .avatar {
grid-area: avatar;
justify-self: center;
:host .avatar {
grid-area: avatar;
justify-self: center;
& img {
width: var(--sidebar-avatar-size);
height: var(--sidebar-avatar-size);
aspect-ratio: 1/1;
border-radius: 1em;
object-fit: cover;
}
}
& .name,
& .species {
font-family: var(--font-family-headings);
text-align: var(--sidebar-top-text-align);
}
& .name {
grid-area: name;
align-self: end;
font-size: 1.375em;
font-weight: bold;
margin: 0;
}
& .species {
grid-area: species;
align-self: start;
font-size: 0.75em;
margin: 0;
}
& > :last-child {
grid-area: traits;
border-block-start: var(--border-thin) solid var(--clr-box-border);
padding-block: 0.75em 0;
& img {
width: var(--sidebar-avatar-size);
height: var(--sidebar-avatar-size);
aspect-ratio: 1/1;
border-radius: 1em;
object-fit: cover;
}
}
:host :where(.name, .species) {
font-family: var(--font-family-headings);
text-align: var(--sidebar-top-text-align);
}
:host .name {
grid-area: name;
align-self: end;
font-size: 1.375em;
font-weight: bold;
margin: 0;
}
:host .species {
grid-area: species;
align-self: start;
font-size: 0.75em;
margin: 0;
}
:host > :last-child {
grid-area: traits;
border-block-start: var(--border-thin) solid var(--clr-box-border);
padding-block: 0.75em 0;
}
</style>

View file

@ -1,10 +1,10 @@
<div class="quick-info">
<div webc:root="override">
<h3 class="title">Key Facts</h3>
<slot></slot>
</div>
<style>
.quick-info {
<style webc:scoped="quick-info">
:host {
position: relative;
background: linear-gradient(
to bottom right,
@ -19,26 +19,26 @@
padding: 1em;
z-index: 1;
}
&::before {
content: '';
position: absolute;
inset: var(--border-thin);
background: linear-gradient(
to bottom right,
var(--clr-quick-info-bg-start) 0%,
var(--clr-quick-info-bg-end) 50%
);
border-radius: inherit;
z-index: -1;
}
:host::before {
content: '';
position: absolute;
inset: var(--border-thin);
background: linear-gradient(
to bottom right,
var(--clr-quick-info-bg-start) 0%,
var(--clr-quick-info-bg-end) 50%
);
border-radius: inherit;
z-index: -1;
}
& .title {
margin-block: 0 1em;
}
:host .title {
margin-block: 0 1em;
}
& > :last-child {
grid-template-columns: repeat(auto-fit, minmax(10em, 1fr));
}
:host > :last-child {
grid-template-columns: repeat(auto-fit, minmax(10em, 1fr));
}
</style>

View file

@ -102,12 +102,12 @@
document.addEventListener('DOMContentLoaded', () => initializeGallery());
</script>
<section class="gallery" aria-label="Image gallery">
<section aria-label="Image gallery" webc:root="override">
<button class="prev" aria-label="Previous Image">
<icon icon="chevron-left" webc:nokeep></icon>
<icon icon="chevron-left"></icon>
</button>
<button class="next" aria-label="Next Image">
<icon icon="chevron-right" webc:nokeep></icon>
<icon icon="chevron-right"></icon>
</button>
<div class="track">
@ -117,8 +117,8 @@
<nav class="gallery-nav" aria-label="Gallery"></nav>
</section>
<style>
.gallery {
<style webc:scoped="gallery">
:host {
display: grid;
grid-auto-columns: auto 1fr auto;
grid-template-areas:
@ -126,152 +126,147 @@
'. progress .';
align-items: center;
gap: 1em;
}
& .prev,
& .next,
& .indicator-btn {
position: relative;
:host :where(.prev, .next, .indicator-btn) {
position: relative;
font-size: 1.25em;
color: var(--clr-text);
cursor: pointer;
font-size: 1.25em;
color: var(--clr-text);
cursor: pointer;
background: linear-gradient(
to bottom right,
var(--clr-box-gradient-start) 0%,
var(--clr-box-gradient-end) 50%
);
background: linear-gradient(
to bottom right,
var(--clr-box-gradient-start) 0%,
var(--clr-box-gradient-end) 50%
);
box-shadow: 0.125em 0.125em 0.5em var(--clr-box-shadow);
box-shadow: 0.125em 0.125em 0.5em var(--clr-box-shadow);
border: none;
border-radius: 100%;
padding: 0.875em;
border: none;
border-radius: 100%;
padding: 0.875em;
z-index: 1;
z-index: 1;
}
&:active::after {
background: linear-gradient(
to top left,
var(--clr-quick-info-bg-start) 0%,
var(--clr-quick-info-bg-end) 50%
);
}
:host :where(.prev, .next, .indicator-btn):active::after {
background: linear-gradient(
to top left,
var(--clr-quick-info-bg-start) 0%,
var(--clr-quick-info-bg-end) 50%
);
}
&::after {
content: '';
position: absolute;
inset: var(--border-thin);
background: linear-gradient(
to bottom right,
var(--clr-quick-info-bg-start) 0%,
var(--clr-quick-info-bg-end) 50%
);
border-radius: inherit;
z-index: -1;
}
}
:host :where(.prev, .next, .indicator-btn)::after {
content: '';
position: absolute;
inset: var(--border-thin);
background: linear-gradient(
to bottom right,
var(--clr-quick-info-bg-start) 0%,
var(--clr-quick-info-bg-end) 50%
);
border-radius: inherit;
z-index: -1;
}
& .prev,
& .next {
grid-row: track;
:host :where(.prev, .next) {
grid-row: track;
}
&:disabled {
cursor: not-allowed;
opacity: 0.5;
}
:host :where(.prev, .next):disabled {
cursor: not-allowed;
opacity: 0.5;
}
& svg {
position: absolute;
inset: 0;
padding: 0.375em;
}
}
:host :where(.prev, .next) svg {
position: absolute;
inset: 0;
padding: 0.375em;
}
& .prev {
grid-column: prev;
left: 0.5em;
}
:host .prev {
grid-column: prev;
left: 0.5em;
}
& .next {
grid-column: next;
right: 0.5em;
}
:host .next {
grid-column: next;
right: 0.5em;
}
& .track {
grid-row: track;
grid-column: prev / next;
display: grid;
grid-auto-flow: column;
grid-auto-columns: 100%;
gap: 2em;
:host .track {
grid-row: track;
grid-column: prev / next;
display: grid;
grid-auto-flow: column;
grid-auto-columns: 100%;
gap: 2em;
border-radius: 1em;
border-radius: 1em;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
scrollbar-width: none;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
scrollbar-width: none;
}
& > * {
scroll-snap-align: center;
}
:host .track > * {
scroll-snap-align: center;
}
&::-webkit-scrollbar {
display: none;
}
}
:host .track::-webkit-scrollbar {
display: none;
}
& .ref-image {
& :first-child {
grid-row: image / caption;
}
:host .ref-image :first-child {
grid-row: image / caption;
}
& img {
width: 100%;
height: 80vw;
object-fit: cover;
}
:host .ref-image img {
width: 100%;
height: 80vw;
object-fit: cover;
}
& .caption {
font-size: 0.875em;
text-wrap: balance;
:host .ref-image .caption {
font-size: 0.875em;
text-wrap: balance;
background: oklch(from var(--clr-box-background) l c h / 0.75);
background: oklch(from var(--clr-box-background) l c h / 0.75);
padding-block: 0.5em;
padding-inline: 1em;
}
}
padding-block: 0.5em;
padding-inline: 1em;
}
& .gallery-nav {
--indicator-size: 2.5em;
:host .gallery-nav {
--indicator-size: 2.5em;
grid-row: progress;
grid-column: prev / next;
grid-row: progress;
grid-column: prev / next;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(1em, 100%), var(--indicator-size)));
gap: 0.5em;
place-content: center;
place-items: center;
font-size: 0.875em;
}
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(1em, 100%), var(--indicator-size)));
gap: 0.5em;
place-content: center;
place-items: center;
font-size: 0.875em;
}
& .indicator-btn {
font-size: 1em;
width: var(--indicator-size);
height: var(--indicator-size);
padding: 0;
aspect-ratio: 1 / 1;
}
:host .indicator-btn {
font-size: 1em;
width: var(--indicator-size);
height: var(--indicator-size);
padding: 0;
aspect-ratio: 1 / 1;
}
& .indicator-btn[aria-current='true']::after {
background: linear-gradient(
to top left,
var(--clr-quick-info-bg-start) 0%,
var(--clr-quick-info-bg-end) 50%
);
}
:host .indicator-btn[aria-current='true']::after {
background: linear-gradient(
to top left,
var(--clr-quick-info-bg-start) 0%,
var(--clr-quick-info-bg-end) 50%
);
}
</style>

View file

@ -1,4 +1,4 @@
<figure class="ref-image">
<figure webc:root="override">
<eleventy-image
class="image"
:class="(dropshadow ? 'dropshadow' : '')"
@ -14,8 +14,8 @@
</figcaption>
</figure>
<style>
.ref-image {
<style webc:scoped="ref-image">
:host {
display: grid;
grid-template-rows: [image-start] 1fr [image-end caption-start] auto [caption-end];
place-content: center;
@ -24,26 +24,27 @@
margin-block: 0;
margin-inline: auto;
& :first-child {
grid-area: image;
}
}
& img {
display: block;
width: 100%;
height: 100%;
max-height: 35rem;
object-fit: contain;
border-radius: 1em;
}
:host :first-child {
grid-area: image;
}
& .dropshadow {
filter: drop-shadow(0.5em 0.25em 0.375em oklch(0 0 0 / 0.5));
}
:host img {
display: block;
width: 100%;
height: 100%;
max-height: 35rem;
object-fit: contain;
border-radius: 1em;
}
& .caption {
grid-area: caption;
text-align: center;
}
:host .dropshadow {
filter: drop-shadow(0.5em 0.25em 0.375em oklch(0 0 0 / 0.5));
}
:host .caption {
grid-area: caption;
text-align: center;
}
</style>

View file

@ -1,4 +1,4 @@
<ul class="timeline">
<ul webc:root="override">
<li class="job" webc:for="job of jobs">
<icon class="icon" :icon="job.icon"></icon>
<p class="title" @text="job.title"></p>
@ -6,8 +6,8 @@
</li>
</ul>
<style>
.timeline {
<style webc:scoped="timeline">
:host {
--timeline-circle-size: 3rem;
--timeline-circle-background: var(--clr-box-background);
--timeline-stroke-color: var(--clr-timeline-stroke);
@ -20,70 +20,72 @@
--timeline-circle-size: 4rem;
}
& .job {
display: grid;
grid-template-areas:
'icon title'
'line text';
column-gap: 1em;
}
&::before {
content: '';
:host .job {
display: grid;
grid-template-areas:
'icon title'
'line text';
column-gap: 1em;
grid-row: icon / line;
grid-column: line;
justify-self: center;
}
width: var(--timeline-stroke-thickness);
height: 100%;
:host .job::before {
content: '';
background-color: var(--timeline-stroke-color);
}
grid-row: icon / line;
grid-column: line;
justify-self: center;
&:first-child::before {
align-self: end;
height: calc(100% - var(--timeline-circle-size));
}
width: var(--timeline-stroke-thickness);
height: 100%;
&:last-child::before {
grid-row: icon;
align-self: start;
height: 50%;
}
}
background-color: var(--timeline-stroke-color);
}
& .icon {
grid-area: icon;
align-self: center;
:host .job:first-child::before {
align-self: end;
height: calc(100% - var(--timeline-circle-size));
}
width: var(--timeline-circle-size);
height: var(--timeline-circle-size);
:host .job:last-child::before {
grid-row: icon;
align-self: start;
height: 50%;
}
background-color: var(--timeline-circle-background);
:host .icon {
grid-area: icon;
align-self: center;
border: var(--timeline-stroke-thickness) solid var(--timeline-stroke-color);
border-radius: 100%;
padding: calc(var(--timeline-circle-size) * 0.2);
}
width: var(--timeline-circle-size);
height: var(--timeline-circle-size);
& .title {
grid-area: title;
align-self: center;
background-color: var(--timeline-circle-background);
font-family: var(--font-family-headings);
font-size: calc(var(--timeline-circle-size) / 2);
font-weight: bold;
text-align: start;
margin-block: calc(var(--timeline-circle-size) / 4);
}
border: var(--timeline-stroke-thickness) solid var(--timeline-stroke-color);
border-radius: 100%;
padding: calc(var(--timeline-circle-size) * 0.2);
}
& .text {
grid-area: text;
:host .title {
grid-area: title;
align-self: center;
margin-inline: 0;
margin-block: 0;
line-height: 1.5;
text-align: justify;
}
font-family: var(--font-family-headings);
font-size: calc(var(--timeline-circle-size) / 2);
font-weight: bold;
text-align: start;
margin-block: calc(var(--timeline-circle-size) / 4);
}
:host .text {
grid-area: text;
margin-inline: 0;
margin-block: 0;
line-height: 1.5;
text-align: justify;
}
</style>

View file

@ -1,13 +1,13 @@
<ul class="trait-list">
<ul webc:root="override">
<li class="trait" webc:for="trait of traits">
<div class="icon-box"><icon :icon="trait.icon" webc:nokeep></icon></div>
<div class="icon-box"><icon :@icon="trait.icon"></icon></div>
<p class="type" @text="trait.type"></p>
<p class="text" @text="trait.text"></p>
</li>
</ul>
<style>
.trait-list {
<style webc:scoped="trait-list">
:host {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(12em, 1fr));
gap: 0.75em;
@ -16,7 +16,7 @@
padding: 0;
}
.trait {
:host .trait {
display: grid;
grid-template-areas:
'icon type'
@ -25,57 +25,59 @@
column-gap: 0.75em;
justify-items: start;
& .icon-box {
position: relative;
grid-area: icon;
}
width: 2em;
height: 2em;
:host .icon-box {
position: relative;
grid-area: icon;
background: linear-gradient(
to bottom right,
var(--clr-box-gradient-start) 0%,
var(--clr-box-gradient-end) 50%
);
width: 2em;
height: 2em;
box-shadow: 0.125em 0.125em 0.5em var(--clr-box-shadow);
border-radius: 0.5em;
overflow: hidden;
z-index: 1;
background: linear-gradient(
to bottom right,
var(--clr-box-gradient-start) 0%,
var(--clr-box-gradient-end) 50%
);
&::before {
content: '';
position: absolute;
inset: var(--border-thin);
background-color: var(--clr-box-background);
border-radius: inherit;
z-index: -1;
}
}
box-shadow: 0.125em 0.125em 0.5em var(--clr-box-shadow);
border-radius: 0.5em;
overflow: hidden;
z-index: 1;
& svg {
padding: 0.5em;
}
}
& p {
margin-block: 0;
}
:host .icon-box::before {
content: '';
position: absolute;
inset: var(--border-thin);
background-color: var(--clr-box-background);
border-radius: inherit;
z-index: -1;
}
& .type {
font-size: 0.625em;
color: var(--clr-heading-data);
text-align: left;
text-transform: uppercase;
grid-area: type;
}
:host svg {
padding: 0.5em;
}
& .text {
font-size: 0.75em;
text-align: left;
margin-block: 0;
margin-inline: 0;
color: var(--clr-text);
grid-area: data;
}
:host p {
margin-block: 0;
}
:host .type {
font-size: 0.625em;
color: var(--clr-heading-data);
text-align: left;
text-transform: uppercase;
grid-area: type;
}
:host .text {
font-size: 0.75em;
text-align: left;
margin-block: 0;
margin-inline: 0;
color: var(--clr-text);
grid-area: data;
}
</style>

View file

@ -14,7 +14,7 @@
</header>
<div class="characters">
<card webc:for="char of characters" :href="`/${char}/`" webc:nokeep>
<card webc:for="char of characters" :href="`/${char}/`">
<eleventy-image
slot="image"
:src="getAvatar(char)"

View file

@ -6,4 +6,4 @@ eleventyNavigation:
Jarek's color palette:
<colors :colors="getColors()" webc:nokeep></colors>
<colors :@colors="$data.getColors()"></colors>

View file

@ -3,7 +3,7 @@ layout: base.webc
---
<main :class="firstName.toLowerCase()">
<profile webc:nokeep>
<profile>
<eleventy-image
slot="avatar"
:src="`src/img/${firstName.toLowerCase()}/avatar.png`"
@ -12,10 +12,10 @@ layout: base.webc
></eleventy-image>
<template webc:nokeep slot="name" @text="getFullName()"></template>
<template webc:nokeep slot="species" @text="species"></template>
<traits :traits="getTraits()" webc:nokeep></traits>
<traits :@traits="$data.getTraits()"></traits>
</profile>
<page-content :char="firstName.toLowerCase()" webc:nokeep>
<page-content :@char="$data.firstName.toLowerCase()">
<h1 @text="$data.eleventyNavigation.key"></h1>
<article @raw="content"></article>
</page-content>

View file

@ -8,4 +8,8 @@ Since Sebin is a fire dragon there's a myriad of abilities he has at his disposa
## Attacks
<abilities :abilities="attacks" :img="true" :char="firstName.toLowerCase()" webc:nokeep></abilities>
<abilities
:@abilities="attacks"
:@img="true"
:@char="$data.firstName.toLowerCase()"
></abilities>

View file

@ -2,27 +2,6 @@
eleventyNavigation:
key: Anatomy
order: 2
refs:
sebinFront:
src: ref-front.png
alt: Sebin Ref
artist: draftgon
href: https://bsky.app/profile/draftgon.bsky.social
sebinBack:
src: ref-back.png
alt: Sebin Ref
artist: draftgon
href: https://bsky.app/profile/draftgon.bsky.social
sebinExpressions:
src: ref-expressions.png
alt: Sebin's expressions
artist: draftgon
href: https://bsky.app/profile/draftgon.bsky.social
sebinUpperBody:
src: ref-upper-body.png
alt: Sebin's upper body closeup
artist: Nidhogg
href: https://bsky.app/profile/nidthedragon.bsky.social
gallery: [
{
alt: Sebin looking aloof (but chill),
@ -73,20 +52,19 @@ gallery: [
---
<ref-img
:char="firstName.toLowerCase()"
:src="refs.sebinFront.src"
:alt="refs.sebinFront.alt"
:width="[1000]"
:artist="refs.sebinFront.artist"
:href="refs.sebinFront.href"
:dropshadow="true"
webc:nokeep
src="ref-front.png"
alt="Sebin Ref"
artist="draftgon"
href="https://bsky.app/profile/draftgon.bsky.social"
:width="[1000]"
:@char="$data.firstName.toLowerCase()"
:@dropshadow="true"
></ref-img>
<colors :colors="getColors()" webc:nokeep></colors>
<colors :@colors="$data.getColors()"></colors>
<quick-info webc:nokeep>
<traits :traits="getTraits('general')" webc:nokeep></traits>
<quick-info>
<traits :@traits="$data.getTraits('general')"></traits>
</quick-info>
Sebin is the offspring of a human and a dragon. Like a human, he is a bipedal plantigrade. Most of his body is covered with red scales. Yellow scales run from the underside of his jaw over his chest and legs to the underside of the tip of his tail. These scales are particularly hard and function like plate armor to better protect vital organs.
@ -100,18 +78,17 @@ Sebin has a muscular build that he keeps in shape with regular exercise.
## Wings
<ref-img
:char="firstName.toLowerCase()"
:src="refs.sebinBack.src"
:alt="refs.sebinBack.alt"
:width="[1000]"
:artist="refs.sebinBack.artist"
:href="refs.sebinBack.href"
:dropshadow="true"
webc:nokeep
src="ref-back.png"
alt="Sebin Ref"
artist="draftgon"
href="https://bsky.app/profile/draftgon.bsky.social"
:width="[1000]"
:@char="$data.firstName.toLowerCase()"
:@dropshadow="true"
></ref-img>
<quick-info webc:nokeep>
<traits :traits="getTraits('wings')" webc:nokeep></traits>
<quick-info>
<traits :@traits="$data.getTraits('wings')"></traits>
</quick-info>
Sebin's wings have a span of about 4.17 meters (13'8"). They function very much like a second pair of arms: two interconnected limbs that form a bendable arm, at the end of which sits a hand-like structure, adorned with a talon in exchange for a thumb, with a sturdy membrane stretched between its long fingers. On solid ground, he keeps his wings closed so as not to accidentally bump into anything with them. Sebin also pays a lot of attention to his wings when working out, so that they can keep carrying him reliably through the air. Though, he only travels short to medium distances through the air before he has to take a rest - as long as the airspace in the area has been declared open for wing bearers.
@ -119,18 +96,17 @@ Sebin's wings have a span of about 4.17 meters (13'8"). They function very much
## Head
<ref-img
:char="firstName.toLowerCase()"
:src="refs.sebinExpressions.src"
:alt="refs.sebinExpressions.alt"
:width="[1000]"
:artist="refs.sebinExpressions.artist"
:href="refs.sebinExpressions.href"
:dropshadow="true"
webc:nokeep
src="ref-expressions.png"
alt="Sebin's expressions"
artist="draftgon"
href="https://bsky.app/profile/draftgon.bsky.social"
:width="[1000]"
:@char="$data.firstName.toLowerCase()"
:@dropshadow="true"
></ref-img>
<quick-info webc:nokeep>
<traits :traits="getTraits('head')" webc:nokeep></traits>
<quick-info>
<traits :@traits="$data.getTraits('head')"></traits>
</quick-info>
Despite what one might expect with reptilians, Sebin's pupils are rounded instead of slit-shaped. Yellow spikes running above his eyelids serve as eyebrows. These spikes are also found along his jaw bone. Two pointed, slightly curved, black horns protrude from his head. He usually wears his medium-length, blue hair loose. His long, pointed ears are very flexible, allowing him to hear sounds around him without having to turn his head. They are also used for non-verbal communication, to express emotions through body language. His hearing perceives a wider range of frequencies, making it superior to that of a human. His jaws are equipped with razor-sharp teeth that effortlessly sink into anything he manages to bite, be it nourishment or adversaries. Embedded between them lies his tongue, which is typically pointed for reptilians. Glands in his throat produce a mixture which he uses to spit fire, which can reach up to around 100 °C (212 °F).
@ -138,18 +114,17 @@ Despite what one might expect with reptilians, Sebin's pupils are rounded instea
## Upper body
<ref-img
:char="firstName.toLowerCase()"
:src="refs.sebinUpperBody.src"
:alt="refs.sebinUpperBody.alt"
:width="[1000]"
:artist="refs.sebinUpperBody.artist"
:href="refs.sebinUpperBody.href"
:dropshadow="true"
webc:nokeep
src="ref-upper-body.png"
alt="Sebin's upper body closeup"
artist="Nidhogg"
href="https://bsky.app/profile/nidthedragon.bsky.social"
:width="[1000]"
:@char="$data.firstName.toLowerCase()"
:@dropshadow="true"
></ref-img>
<quick-info webc:nokeep>
<traits :traits="getTraits('muscle')" webc:nokeep></traits>
<quick-info>
<traits :@traits="$data.getTraits('muscle')"></traits>
</quick-info>
At the age of 17, Sebin gradually began to keep his body in shape on a regular basis. His favorite exercises include weightlifting (with both dumbbells and barbells), lat pulldown, leg press and cable curls. He works out three days a week with one day off between training days, rotating the body regions he trains each day.
@ -160,34 +135,32 @@ Sebin is very concerned with an even distribution of muscle mass, but pays parti
An assortment of additional references how Sebin can be drawn.
<ref-gallery webc:nokeep>
<ref-gallery>
<ref-img webc:for="ref of [...Array(9).keys()]"
:char="firstName.toLowerCase()"
:src="`ref-muscle-${ref + 1}.png`"
:alt="gallery[ref].alt"
:artist="gallery[ref].artist"
:href="gallery[ref].href"
:alt="$data.gallery[ref].alt"
:width="[500, 1000]"
:dropshadow="false"
webc:nokeep
:href="$data.gallery[ref].href"
:@artist="$data.gallery[ref].artist"
:@char="$data.firstName.toLowerCase()"
:@dropshadow="false"
></ref-img>
</ref-gallery>
## Penis
<ref-img
:char="firstName.toLowerCase()"
src="ref-penis.png"
alt="Sebin's manly parts"
artist="draftgon"
href="https://bsky.app/profile/draftgon.bsky.social"
:width="[500, 1000]"
:dropshadow="true"
webc:nokeep
src="ref-penis.png"
alt="Sebin's manly parts"
artist="draftgon"
href="https://bsky.app/profile/draftgon.bsky.social"
:width="[500, 1000]"
:@char="$data.firstName.toLowerCase()"
:@dropshadow="true"
></ref-img>
<quick-info webc:nokeep>
<traits :traits="getTraits('naughty')" webc:nokeep></traits>
<quick-info>
<traits :@traits="$data.getTraits('naughty')"></traits>
</quick-info>
Despite his reptilian appearance, Sebin has nipples, a feature of the human side of his family. Furthermore, his external testicles represent another humanized feature. Where relatives of his ilk possess a slit in which the penis lies protectively, Sebin possesses a pouch-like sheath from which the tip of the penis protrudes slightly. The shape of his shaft is predominantly humanoid, but it is surrounded by ridges and has no equivalent of a foreskin. When aroused, the coal-black shaft swells and pushes out of the sheath until fully erect, the sheath wrapping around the root of the shaft like a ring. However, he can also push it out in a flaccid state, e.g. when needing to pass water.

View file

@ -28,15 +28,14 @@ gallery: [
Sebin knows how to dress!
<ref-gallery webc:nokeep>
<ref-gallery>
<ref-img webc:for="ref of Array(4).keys()"
:char="firstName.toLowerCase()"
:src="`ref-clothes-${ref + 1}.png`"
:alt="gallery[ref].alt"
:artist="gallery[ref].artist"
:href="gallery[ref].href"
:alt="$data.gallery[ref].alt"
:href="$data.gallery[ref].href"
:width="[500, 1000]"
:dropshadow="false"
webc:nokeep
:@char="$data.firstName.toLowerCase()"
:@artist="$data.gallery[ref].artist"
:@dropshadow="false"
></ref-img>
</ref-gallery>

View file

@ -2,23 +2,16 @@
eleventyNavigation:
key: Overdrive
order: 4
refs:
overdrive:
src: ref-overdrive.jpg
alt: Sebin Overdrive Ref
artist: CVictorrosso
href: https://bsky.app/profile/cvictorrosso.bsky.social
---
<ref-img
:char="firstName.toLowerCase()"
:src="refs.overdrive.src"
:alt="refs.overdrive.alt"
:width="[1000]"
:artist="refs.overdrive.artist"
:href="refs.overdrive.href"
:dropshadow="false"
webc:nokeep
src="ref-overdrive.jpg"
alt="Sebin Overdrive Ref"
artist="CVictorrosso"
href="https://bsky.app/profile/cvictorrosso.bsky.social"
:width="[1000]"
:@char="$data.firstName.toLowerCase()"
:@dropshadow="false"
></ref-img>
Sebin can enter an Overdrive Form which greatly increases his strength and abilities but it comes at a cost.
@ -31,4 +24,8 @@ Direct body contact with Sebin during overdrive causes 3rd degree burns as he em
## Attacks
<abilities :abilities="overdriveAttacks" :img="false" :char="firstName.toLowerCase()" webc:nokeep></abilities>
<abilities
:@abilities="overdriveAttacks"
:@img="false"
:@char="$data.firstName.toLowerCase()"
></abilities>

View file

@ -2,30 +2,18 @@
eleventyNavigation:
key: Anatomy
order: 2
refs:
viktorRef:
src: ref-SFW.png
alt: Viktor Ref
artist: sabertoofs
href: https://bsky.app/profile/sabertoofs.bsky.social
viktorPinup:
src: pinup-SFW.png
alt: Viktor Ref
artist: sabertoofs
href: https://bsky.app/profile/sabertoofs.bsky.social
---
<ref-img
:char="firstName.toLowerCase()"
:src="refs.viktorRef.src"
:alt="refs.viktorRef.alt"
:artist="refs.viktorRef.artist"
:href="refs.viktorRef.href"
:dropshadow="true"
webc:nokeep
src="ref-SFW.png"
alt="Viktor Ref"
artist="sabertoofs"
href="https://bsky.app/profile/sabertoofs.bsky.social"
:@char="$data.firstName.toLowerCase()"
:@dropshadow="true"
></ref-img>
<colors :colors="getColors()" webc:nokeep></colors>
<colors :@colors="$data.getColors()"></colors>
Viktor is a bipedal plantigrade Ankylosaurus. His skin is mostly bicolored, with several shades of brown.
@ -34,13 +22,12 @@ His forehead, nose, chest, belly and crotch are of light desert sand colors that
His cheeks, shoulders, back and thighs, in contrast, stand out with a rich walnut brown, which is also found on the sides of his tail. From the back of his head, down his spine and across the top of his tail is a continuous strip of deep dark cedar brown. Arms and legs are distinguished by a light earthy brown.
<ref-img
:char="firstName.toLowerCase()"
:src="refs.viktorPinup.src"
:alt="refs.viktorPinup.alt"
:artist="refs.viktorPinup.artist"
:href="refs.viktorPinup.href"
:dropshadow="true"
webc:nokeep
src="pinup-SFW.png"
alt="Viktor Ref"
artist="sabertoofs"
href="https://bsky.app/profile/sabertoofs.bsky.social"
:@char="$data.firstName.toLowerCase()"
:@dropshadow="true"
></ref-img>
His entire body is speckled with scattered aquamarine spots, which come in pairs of one large and one small spot. The only exceptions are the spots on his cheeks and behind his lower cheek horns, which come in threes and his the top side of his snout, which sports a big single spot. Mouth, tongue, nostrils and any other tissue of his body also feature this color.

View file

@ -7,4 +7,4 @@ eleventyNavigation:
Viktor's had many different jobs in the past, some of which where very formative, other's just
paid the bills.
<timeline :@jobs="jobs" webc:nokeep></timeline>
<timeline :@jobs="jobs"></timeline>

View file

@ -14,8 +14,8 @@ Viktor prefers to keep it simple. He's not particularly fond of the dependence o
## Sexuality
<quick-info webc:nokeep>
<traits :traits="getTraits('naughty')" webc:nokeep></traits>
<quick-info>
<traits :@traits="$data.getTraits('naughty')"></traits>
</quick-info>
As a teenager, Viktor noticed that he felt a bit differently about the boys in his class. Especially in gym class, his eyes tended to linger longer on his classmates as they rough-housed in the locker room, as pubescent boys do. However, he could never quite come to terms with the idea that he might be a little different from his friends, who were all beginning to take an interest in girls, unlike him, who was more interested in his buddies.