New feauter, change font family and font size

This commit is contained in:
2026-06-19 13:42:57 +02:00
parent 5417176dd4
commit a90d10368e
10 changed files with 264 additions and 11 deletions
+1
View File
@@ -4,3 +4,4 @@
CLAUDE.md
LEARNINGS.md
PLAN.md
/memory
+3
View File
@@ -7,6 +7,9 @@
<link rel="alternate icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RSS-Reader</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&family=Lora:ital,wght@0,400;0,700;1,400&family=Merriweather:ital,wght@0,400;0,700;1,400&family=Playfair+Display:wght@400;700&family=Raleway:wght@400;700&family=Source+Serif+4:ital,opsz,wght@0,8..60,400;0,8..60,700;1,8..60,400&display=swap" rel="stylesheet">
</head>
<body>
+4
View File
@@ -1,8 +1,12 @@
<script setup>
import { onMounted } from 'vue'
import { RouterView, useRoute } from 'vue-router'
import AppNav from './components/AppNav.vue'
import { useSettings } from './composables/useSettings.js'
const route = useRoute()
const { applySettings } = useSettings()
onMounted(applySettings)
</script>
<template>
+5
View File
@@ -23,6 +23,11 @@
/* semantic color variables for this project */
:root {
--headline-font-family: Glook, 'Courier New';
--content-font-family: Merriweather, Georgia, 'Times New Roman', Times, serif;
--headline-font-size-scale: 1;
--content-font-size-scale: 1;
--color-background: var(--vt-c-white);
--color-background-soft: var(--vt-c-white-soft);
--color-background-mute: var(--vt-c-white-mute);
+5 -5
View File
@@ -69,8 +69,8 @@ a,
.feed-title {
cursor: pointer;
font-family: Glook, 'Courier New';
font-size: clamp(1.4rem, 5vw, 2rem);
font-family: var(--headline-font-family);
font-size: calc(clamp(1.4rem, 5vw, 2rem) * var(--headline-font-size-scale));
font-weight: bold;
color: var(--color-accent-2);
border-bottom: 1px solid #ccc;
@@ -84,8 +84,8 @@ a,
}
.feed-content {
font-family: Merriweather, Georgia, 'Times New Roman', Times, serif;
font-size: clamp(1rem, 3.5vw, 1.25rem);
font-family: var(--content-font-family);
font-size: calc(clamp(1rem, 3.5vw, 1.25rem) * var(--content-font-size-scale));
padding: 0 1em 1em;
overflow-wrap: break-word;
}
@@ -101,7 +101,7 @@ a,
.feed-content h3 {
padding: 0.5em 0;
font-size: clamp(1rem, 3vw, 1.3rem);
font-size: calc(clamp(1rem, 3vw, 1.3rem) * var(--headline-font-size-scale));
font-weight: bold;
}
+158
View File
@@ -0,0 +1,158 @@
<script setup>
import { useSettings } from '../composables/useSettings.js'
const {
headlineSizeScale,
contentSizeScale,
headlineFontKey,
contentFontKey,
SIZE_STEPS,
SIZE_LABELS,
HEADLINE_FONT_OPTIONS,
CONTENT_FONT_OPTIONS,
setHeadlineSize,
setContentSize,
setHeadlineFont,
setContentFont,
} = useSettings()
</script>
<template>
<div class="settings">
<h1 class="settings__heading">Typography</h1>
<section class="settings__section">
<h2 class="settings__section-title">Headline Size</h2>
<div class="settings__strip">
<button
v-for="(step, i) in SIZE_STEPS"
:key="step"
class="settings__btn"
:class="{ 'settings__btn--active': headlineSizeScale === step }"
type="button"
@click="setHeadlineSize(step)"
>{{ SIZE_LABELS[i] }}</button>
</div>
</section>
<section class="settings__section">
<h2 class="settings__section-title">Article Text Size</h2>
<div class="settings__strip">
<button
v-for="(step, i) in SIZE_STEPS"
:key="step"
class="settings__btn"
:class="{ 'settings__btn--active': contentSizeScale === step }"
type="button"
@click="setContentSize(step)"
>{{ SIZE_LABELS[i] }}</button>
</div>
</section>
<section class="settings__section">
<h2 class="settings__section-title">Headline Font</h2>
<select
class="settings__select"
:value="headlineFontKey"
@change="setHeadlineFont($event.target.value)"
>
<option
v-for="opt in HEADLINE_FONT_OPTIONS"
:key="opt.key"
:value="opt.key"
>{{ opt.label }}</option>
</select>
</section>
<section class="settings__section">
<h2 class="settings__section-title">Article Text Font</h2>
<select
class="settings__select"
:value="contentFontKey"
@change="setContentFont($event.target.value)"
>
<option
v-for="opt in CONTENT_FONT_OPTIONS"
:key="opt.key"
:value="opt.key"
>{{ opt.label }}</option>
</select>
</section>
</div>
</template>
<style scoped>
.settings {
padding: 1.5rem 1rem 0.5rem;
max-width: 720px;
margin: 0 auto;
}
.settings__heading {
font-size: 1.25rem;
font-weight: bold;
margin-bottom: 1.25rem;
}
.settings__section {
margin-bottom: 1.25rem;
padding: 0.75rem 1rem;
border: 1px solid var(--color-border);
border-radius: 6px;
background: var(--color-background-soft);
}
.settings__section-title {
font-size: 0.8rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
opacity: 0.6;
margin-bottom: 0.6rem;
}
.settings__strip {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.settings__btn {
min-height: 36px;
padding: 0.3rem 0.9rem;
border: 1px solid var(--color-border);
border-radius: 4px;
background: transparent;
color: var(--color-text);
font: inherit;
cursor: pointer;
transition: border-color 0.15s, background 0.15s;
}
.settings__btn:hover {
border-color: var(--color-border-hover);
}
.settings__btn--active {
border-color: var(--color-accent);
background: var(--color-accent-hover);
color: var(--color-text);
}
.settings__select {
width: 100%;
min-height: 36px;
padding: 0.3rem 0.6rem;
border: 1px solid var(--color-border);
border-radius: 4px;
background: var(--color-background);
color: var(--color-text);
font: inherit;
cursor: pointer;
appearance: auto;
}
.settings__select:hover {
border-color: var(--color-border-hover);
}
</style>
+6 -6
View File
@@ -324,8 +324,8 @@ onMounted(async () => {
cursor: pointer;
margin: 0;
padding: 0 1rem;
font-family: 'Courier New';
font-size: clamp(1.4rem, 5vw, 2rem);
font-family: var(--headline-font-family);
font-size: calc(clamp(1.4rem, 5vw, 2rem) * var(--headline-font-size-scale));
font-weight: bold;
line-height: 1.15;
color: var(--color-accent-2);
@@ -352,8 +352,8 @@ onMounted(async () => {
.article-feature__content {
padding: 0 1rem;
font-family: Georgia, 'Times New Roman', Times, serif;
font-size: clamp(1rem, 3.5vw, 1.25rem);
font-family: var(--content-font-family);
font-size: calc(clamp(1rem, 3.5vw, 1.25rem) * var(--content-font-size-scale));
line-height: 1.75;
overflow-wrap: break-word;
}
@@ -364,7 +364,7 @@ onMounted(async () => {
.article-feature__content :deep(h3) {
padding: 0.5em 0;
font-size: clamp(1rem, 3vw, 1.3rem);
font-size: calc(clamp(1rem, 3vw, 1.3rem) * var(--headline-font-size-scale));
font-weight: bold;
}
@@ -421,7 +421,7 @@ onMounted(async () => {
padding: 1em 0;
border-top: 1px solid var(--color-border);
border-bottom: 1px solid var(--color-border);
font-family: Georgia, 'Times New Roman', Times, serif;
font-family: var(--content-font-family);
font-size: 1.25em;
font-style: italic;
text-align: center;
+79
View File
@@ -0,0 +1,79 @@
import { ref } from 'vue'
const HEADLINE_FONT_OPTIONS = [
{ key: 'default', label: 'Default (Glook)', value: "Glook, 'Courier New'" },
{ key: 'playfair', label: 'Playfair Display', value: "'Playfair Display', Georgia, serif" },
{ key: 'lora', label: 'Lora', value: "Lora, Georgia, serif" },
{ key: 'raleway', label: 'Raleway', value: "Raleway, -apple-system, sans-serif" },
{ key: 'inter', label: 'Inter', value: "Inter, -apple-system, sans-serif" },
]
const CONTENT_FONT_OPTIONS = [
{ key: 'default', label: 'Default (Merriweather)', value: "Merriweather, Georgia, 'Times New Roman', Times, serif" },
{ key: 'lora', label: 'Lora', value: "Lora, Georgia, serif" },
{ key: 'source-serif', label: 'Source Serif 4', value: "'Source Serif 4', Georgia, serif" },
{ key: 'inter', label: 'Inter', value: "Inter, -apple-system, sans-serif" },
{ key: 'playfair', label: 'Playfair Display', value: "'Playfair Display', Georgia, serif" },
]
const SIZE_STEPS = [0.85, 1, 1.2, 1.45]
const SIZE_LABELS = ['S', 'M', 'L', 'XL']
const headlineSizeScale = ref(parseFloat(localStorage.getItem('s-headline-size') ?? '1'))
const contentSizeScale = ref(parseFloat(localStorage.getItem('s-content-size') ?? '1'))
const headlineFontKey = ref(localStorage.getItem('s-headline-font') ?? 'default')
const contentFontKey = ref(localStorage.getItem('s-content-font') ?? 'default')
function fontValue(options, key) {
return (options.find(o => o.key === key) ?? options[0]).value
}
function applySettings() {
const s = document.documentElement.style
s.setProperty('--headline-font-size-scale', headlineSizeScale.value)
s.setProperty('--content-font-size-scale', contentSizeScale.value)
s.setProperty('--headline-font-family', fontValue(HEADLINE_FONT_OPTIONS, headlineFontKey.value))
s.setProperty('--content-font-family', fontValue(CONTENT_FONT_OPTIONS, contentFontKey.value))
}
function setHeadlineSize(scale) {
headlineSizeScale.value = scale
localStorage.setItem('s-headline-size', scale)
applySettings()
}
function setContentSize(scale) {
contentSizeScale.value = scale
localStorage.setItem('s-content-size', scale)
applySettings()
}
function setHeadlineFont(key) {
headlineFontKey.value = key
localStorage.setItem('s-headline-font', key)
applySettings()
}
function setContentFont(key) {
contentFontKey.value = key
localStorage.setItem('s-content-font', key)
applySettings()
}
export function useSettings() {
return {
headlineSizeScale,
contentSizeScale,
headlineFontKey,
contentFontKey,
SIZE_STEPS,
SIZE_LABELS,
HEADLINE_FONT_OPTIONS,
CONTENT_FONT_OPTIONS,
applySettings,
setHeadlineSize,
setContentSize,
setHeadlineFont,
setContentFont,
}
}
+1
View File
@@ -2,6 +2,7 @@ import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
scrollBehavior: () => ({ top: 0, behavior: 'instant' }),
routes: [
{
path: '/',
+2
View File
@@ -1,9 +1,11 @@
<script setup>
import AdminFeeds from '../components/AdminFeeds.vue'
import AdminSettings from '../components/AdminSettings.vue'
</script>
<template>
<main>
<AdminSettings />
<AdminFeeds />
</main>
</template>