Updated to Astro 5. Cruft removed.

This commit is contained in:
Christoph Haas 2025-01-21 20:10:04 +01:00
parent 510ecc2094
commit 97c36c6a42
11 changed files with 819 additions and 1344 deletions

View file

@ -1,6 +1,6 @@
---
import { getImage } from "astro:assets";
import HoustonGrad from "~/assets/houston_grad.png";
// import { getImage } from "astro:assets";
// import HoustonGrad from "~/assets/houston_grad.png";
export interface Props {
icon?: "puzzle-piece" | "question-mark" | "check-list";

View file

@ -1,108 +0,0 @@
<div class="checklist"><slot /></div>
{
Astro.slots.has('alternative') && (
<>
<p class="or">
foo
</p>
<div class="checklist alternative">
<slot name="alternative" />
</div>
</>
)
}
<style>
check-list > * + * {
margin-top: 1rem;
}
.checklist > :global(ul) {
list-style: none;
padding-inline-start: 0;
}
check-list :global(label) {
display: block;
position: relative;
margin: 0 -1rem !important;
border-radius: 0.5rem;
padding-block: 0.5rem;
padding-inline: 3.5rem 0.5rem;
cursor: pointer;
font-size: var(--sl-text-lg);
color: var(--sl-color-green-high);
}
check-list :global(label span) {
display: inline-block;
}
check-list :global(input[type='checkbox']) {
-webkit-appearance: none;
appearance: none;
}
check-list :global(input[type='checkbox']:focus) {
outline: none;
}
check-list :global(input[type='checkbox']::after) {
content: '';
position: absolute;
inset-inline-start: 1rem;
top: 50%;
transform: translateY(-50%);
transform-origin: center;
text-align: center;
line-height: 1.25;
width: 1.25em;
height: 1.25em;
font-size: 1.25em;
border: 1px solid var(--sl-color-green-high);
border-radius: 0.25rem;
color: var(--sl-color-green);
cursor: pointer;
}
check-list :global(input[type='checkbox']:focus::after) {
outline: 3px solid var(--sl-color-green);
outline-offset: 0.5rem;
}
check-list :global(input[type='checkbox']:not(:focus-visible)::after) {
outline: none;
}
check-list :global(label:has(> input[type='checkbox']:checked)) {
color: var(--sl-color-white);
}
check-list :global(input[type='checkbox']:checked::after) {
content: url("data:image/svg+xml,%3Csvg width='28' height='28' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='24' height='24' rx='4' fill='white'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M20.0946 6.02558C20.6992 6.592 20.7301 7.54124 20.1636 8.14578L10.3868 18.5806C9.55548 19.468 8.14726 19.468 7.3159 18.5806L4.02558 15.0689C3.45917 14.4643 3.49008 13.5151 4.09461 12.9487C4.69915 12.3822 5.6484 12.4132 6.21481 13.0177L8.85137 15.8317L17.9744 6.09461C18.5408 5.49007 19.4901 5.45917 20.0946 6.02558Z' fill='%232F4D22'/%3E%3C/svg%3E%0A");
border: none;
/* color: var(--sl-color-green-low); */
/* background-color: var(--sl-color-gray-1); */
}
.or {
display: grid;
grid-template-columns: 1fr auto 1fr;
gap: 1em;
text-transform: uppercase;
font-weight: bold;
color: var(--theme-text-lighter);
}
.or::before,
.or::after {
--divider-width: 4px;
content: '';
background-image: linear-gradient(
to bottom,
transparent calc(50% - var(--divider-width) / 2),
var(--theme-divider) calc(50% - var(--divider-width) / 2) calc(50% + var(--divider-width) / 2),
transparent calc(50% + var(--divider-width) / 2) 100%
);
}
</style>

View file

@ -8,7 +8,7 @@ import Default from "@astrojs/starlight/components/Footer.astro";
{
Astro.url.pathname !== "/" && (
<script defer src="https://comentario.workaround.org/comentario.js"></script>
<script defer is:inline src="https://comentario.workaround.org/comentario.js"></script>
<comentario-comments no-fonts="true" id="comments"></comentario-comments>
)
}

View file

@ -1,167 +0,0 @@
<multiple-choice data-correct-label={"Correct"} data-incorrect-label={"Wrong"}>
<form onsubmit="event.preventDefault()">
<ol class="opt-list not-content"><slot /></ol>
<div class="footer">
<button class="submit" type="submit" disabled>
{"Submit"}
</button>
<div class="answer sr-only" role="alert"></div>
</div>
</form>
</multiple-choice>
<style>
multiple-choice {
display: block;
padding-bottom: 1rem;
color: var(--sl-color-text-accent);
}
form > * + * {
margin-top: 1rem;
}
.opt-list {
list-style: none;
padding-inline-start: 0;
}
/* .footer {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
} */
.submit,
.answer {
padding: 0.8rem;
line-height: 1.4;
max-width: 15em;
border: 2px solid var(--sl-color-gray-4);
}
.submit {
cursor: pointer;
color: var(--sl-color-accent);
background-color: white;
}
.submit:focus {
background-color: hsl(224, 20%, 94%);
}
.submit:not(:focus-visible) {
outline: none;
}
.submit:hover {
background: var(--sl-color-text-accent);
color: var(--sl-color-black);
/* border-color: transparent; */
}
.submit:disabled,
.submit:active {
/* transform: translateY(0.25rem); */
}
.submit:disabled {
background-color: hsl(224, 20%, 94%);
color: hsl(224, 7%, 36%);
opacity: 0.65;
cursor: not-allowed;
}
.answer {
text-align: center;
border-color: transparent;
}
.correct {
color: var(--sl-color-green-low);
background-color: var(--sl-color-green);
}
.wrong {
color: var(--sl-color-red-low);
background-color: var(--sl-color-red);
}
</style>
<script>
class MultipleChoice extends HTMLElement {
#defaultCorrectLabel: string;
#defaultIncorrectLabel: string;
#key: string;
#submitEl: HTMLButtonElement;
#answerEl: HTMLParagraphElement;
constructor() {
super();
this.#defaultCorrectLabel = this.dataset.correctLabel!;
this.#defaultIncorrectLabel = this.dataset.incorrectLabel!;
this.#key = Math.random().toString();
this.#submitEl = this.querySelector(".submit")!;
this.#answerEl = this.querySelector(".answer")!;
this.querySelectorAll(".opt-list > li").forEach((li) => this.#upgradeListItem(li));
}
#upgradeListItem(li: Element) {
const option = li.querySelector('input[type="radio"]') as HTMLInputElement | null;
if (!option) return;
option.removeAttribute("disabled");
option.setAttribute("name", this.#key);
option.addEventListener("change", () => {
this.#clearAnswer();
this.#enableSubmit();
});
if (option.checked) this.#enableSubmit();
}
/** Clear the answer text and hide its container visually. */
#clearAnswer() {
this.#answerEl.innerText = "";
this.#answerEl.classList.remove("wrong", "correct");
this.#answerEl.classList.add("sr-only");
}
/** Show the answer result to the user. */
#setAnswer(isCorrect: boolean) {
const answerTemplate = this.querySelector("input:checked ~ template") as HTMLTemplateElement | null;
if (answerTemplate) {
this.#answerEl.replaceChildren(answerTemplate.content.cloneNode(true));
} else {
this.#answerEl.innerText = isCorrect ? this.#defaultCorrectLabel : this.#defaultIncorrectLabel;
}
this.#answerEl.classList.remove("sr-only", "wrong", "correct");
this.#answerEl.classList.add(isCorrect ? "correct" : "wrong");
}
/** Activate the submit button, preparing it to evaluate the form when clicked. */
#enableSubmit() {
this.#submitEl.removeAttribute("disabled");
this.#submitEl.classList.remove("sr-only");
this.#submitEl.onclick = () => this.#submitAnswer();
}
/** Disable the submit button and hide it visually. */
#disableSubmit() {
this.#submitEl.setAttribute("disabled", "");
this.#submitEl.classList.add("sr-only");
this.#submitEl.onclick = null;
}
/** Check if the selected option is correct and display the result. */
#submitAnswer() {
const selection = this.querySelector("input:checked") as HTMLInputElement | null;
if (!selection) return;
this.#disableSubmit();
const isCorrect = selection.dataset.isCorrect !== undefined && ["", "true"].includes(selection.dataset.isCorrect);
this.#setAnswer(isCorrect);
}
}
customElements.define("multiple-choice", MultipleChoice);
</script>

View file

@ -1,87 +0,0 @@
---
export interface Props {
isCorrect?: boolean;
}
const { isCorrect } = Astro.props as Props;
---
<li>
<label>
<input type="radio" disabled data-is-correct={isCorrect} /><span><slot /></span>
{
Astro.slots.has('feedback') && (
<template>
<slot name="feedback" />
</template>
)
}
</label>
</li>
<style>
label {
display: grid;
grid-template-columns: auto 1fr;
gap: 1rem;
align-items: center;
border-radius: 1rem;
margin-inline: -0.5rem;
padding: 0.5rem;
cursor: pointer;
}
label:hover {
background-color: var(--sl-color-accent-low);
}
input[type='radio'] {
appearance: none;
cursor: pointer;
}
input[type='radio'] ~ * {
color: var(--sl-color-text-accent);
}
input[type='radio']:checked ~ * {
color: var(--sl-color-white);
}
input[type='radio']:focus::after {
outline: 3px solid var(--sl-color-text-accent);
outline-offset: 0.5rem;
}
input[type='radio']:focus,
input[type='radio']:not(:focus-visible)::after {
outline: none;
}
input[type='radio']::after {
display: block;
content: '';
text-align: center;
line-height: 1.5;
width: 1em;
height: 1em;
font-size: 1em;
font-weight: 900;
border: 2px solid var(--sl-color-accent-high);
border-radius: 100%;
color: var(--sl-color-white);
box-shadow: -3px 3px var(--theme-shade-subtle);
}
input[type='radio']:checked::after {
color: hsl(var(--color-base-white), 100%);
background-image: radial-gradient(var(--sl-color-white) 50%, transparent 0%, transparent);
border-color: var(--sl-color-white);
}
@media (forced-colors: active) {
input[type='radio']:checked::after {
background-color: Highlight;
}
}
</style>

View file

@ -1,10 +0,0 @@
---
import type { UIDictionaryKeys } from '../i18n/translation-checkers';
import { useTranslations } from '../i18n/util';
export interface Props {
key: UIDictionaryKeys;
}
---
{useTranslations(Astro)(Astro.props.key)}