feat: add initial base pages and mobile-first framework

This commit is contained in:
2026-08-12 12:09:47 +02:00
commit 73d8ee5a8f
8 changed files with 489 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
This project aims to create a playful online-tool to plan a date.
In the end, there will be multiple pages that act like a choose-your-own-adventure story, where users can select different options to plan their ideal date
A first, i need you to create a simple, mobile-first oriented style framework
Most users will access the tool from their mobile devices, so the design should prioritize ease of use and readability on smaller screens
the base color is some love-rose shade, with complementary colors that evoke warmth and romance. The typography should be clean and legible, with a focus on larger font sizes for headings and body text to enhance readability on mobile devices.
I want you to create a few first pages:
- a page where the user is asked if he/she wants to go on a date with me: with a yes and a no option. when the no-option is selected, the no-button shrinks to 66% of its original size. and the yes-button grows by 33% of its original size. That behaviour happens everytime the no-button is clicked. The page should have a playful and inviting design, with a heart-shaped background.
- next page selects an activity for the date: options. for now its
- Indisch essen gehen
- Kinofilm
- Film zu Hause + Essen bestellen
- Walk in the forrest
- Museum für gegenwartskunst
- Picknick auf der Wiese
I want the selection to display in a grid structure, each activity has a central icon / simple image
please create everything in german, but english code/classes/functions
stay at plain html/css/javascript for now. that will be later extended by a simple solution to save it somehow to a database / storage/ textfile
+74
View File
@@ -0,0 +1,74 @@
/* ==========================================================================
Page: Aktivitäts-Auswahl (activity.html)
========================================================================== */
.page-activity .intro {
text-align: center;
margin-bottom: 1.5em;
}
.page-activity .intro p {
color: var(--color-text-light);
}
.activity-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
@media (min-width: 600px) {
.activity-grid {
grid-template-columns: repeat(3, 1fr);
}
}
.activity-card {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 10px;
min-height: 140px;
padding: 16px 10px;
background: var(--color-white);
border: 2px solid transparent;
border-radius: var(--radius-md);
box-shadow: var(--shadow-soft);
cursor: pointer;
touch-action: manipulation;
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}
.activity-card:active {
transform: scale(0.97);
}
.activity-card .icon {
font-size: 2.6rem;
line-height: 1;
}
.activity-card .label {
font-family: var(--font-heading);
font-weight: 700;
font-size: 0.95rem;
text-align: center;
color: var(--color-text);
}
.activity-card.selected {
border-color: var(--color-rose);
background: linear-gradient(135deg, var(--color-rose-light) 0%, var(--color-white) 100%);
box-shadow: var(--shadow-strong);
}
.activity-card.selected::after {
content: "✓";
position: absolute;
top: 8px;
right: 10px;
color: var(--color-rose-dark);
font-weight: 700;
}
+32
View File
@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<title>Wähle eure Aktivität Date-Planer</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=Nunito:wght@400;600;700&family=Quicksand:wght@600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="activity.css" />
</head>
<body class="page-activity has-continue-bar">
<main class="container">
<a class="back-link" href="index.html"> Zurück</a>
<div class="intro">
<h1>Worauf hast du Lust? 🥰</h1>
<p>Wähle eure gemeinsame Aktivität für das Date aus.</p>
</div>
<div class="activity-grid" id="activityGrid"></div>
</main>
<div class="continue-bar">
<div class="container">
<button id="continueBtn" class="btn btn-primary" type="button" disabled>Weiter</button>
</div>
</div>
<script src="activity.js" defer></script>
</body>
</html>
+52
View File
@@ -0,0 +1,52 @@
// Aktivitäts-Auswahl: lädt Aktivitäten aus appsettings.json, Kartenauswahl + Weiter-Button
(function () {
const activityGrid = document.getElementById("activityGrid");
const continueBtn = document.getElementById("continueBtn");
let selectedActivity = null;
fetch("appsettings.json")
.then((response) => response.json())
.then((settings) => renderActivities(settings.activities || []))
.catch(() => {
activityGrid.textContent = "Aktivitäten konnten nicht geladen werden.";
});
function renderActivities(activities) {
activities.forEach((activity) => {
const card = document.createElement("button");
card.type = "button";
card.className = "activity-card";
card.dataset.activity = activity.name;
const icon = document.createElement("span");
icon.className = "icon";
icon.setAttribute("aria-hidden", "true");
icon.textContent = activity.icon;
const label = document.createElement("span");
label.className = "label";
label.textContent = activity.name;
card.append(icon, label);
card.addEventListener("click", () => {
activityGrid.querySelectorAll(".activity-card").forEach((c) => c.classList.remove("selected"));
card.classList.add("selected");
selectedActivity = activity.name;
continueBtn.disabled = false;
});
activityGrid.appendChild(card);
});
}
continueBtn.addEventListener("click", () => {
if (!selectedActivity) {
return;
}
// Ablage für die spätere Anbindung an Datenbank/Storage
localStorage.setItem("selectedActivity", selectedActivity);
window.location.href = "datetime.html";
});
})();
+47
View File
@@ -0,0 +1,47 @@
/* ==========================================================================
Page: Frage-Seite (index.html)
Heart-shaped decorative background
========================================================================== */
body.page-ask {
display: flex;
min-height: 100vh;
overflow-x: hidden;
}
.page-ask .content {
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
min-height: 100vh;
width: 100%;
max-width: 480px;
margin: 0 auto;
padding: 24px 20px;
}
.page-ask .question {
margin-bottom: 0.3em;
}
.page-ask .subtitle {
color: var(--color-text-light);
font-size: clamp(1rem, 4vw, 1.1rem);
margin-bottom: 2.5em;
}
.page-ask .button-group {
display: flex;
align-items: center;
justify-content: center;
gap: 20px;
flex-wrap: wrap;
}
.page-ask .btn {
transform-origin: center;
}
+27
View File
@@ -0,0 +1,27 @@
// Frage-Seite: Ja/Nein-Interaktion
// Der Nein-Button schrumpft und der Ja-Button wächst bei jedem Klick auf "Nein".
(function () {
const yesBtn = document.getElementById("yesBtn");
const noBtn = document.getElementById("noBtn");
const SHRINK_FACTOR = 0.66;
const GROW_FACTOR = 1.33;
const MIN_NO_SCALE = 0.12; // bleibt minimal antippbar
const MAX_YES_SCALE = 3.2; // wird nicht größer als der Bildschirm
let noScale = 1;
let yesScale = 1;
noBtn.addEventListener("click", () => {
noScale = Math.max(MIN_NO_SCALE, noScale * SHRINK_FACTOR);
yesScale = Math.min(MAX_YES_SCALE, yesScale * GROW_FACTOR);
noBtn.style.transform = `scale(${noScale})`;
yesBtn.style.transform = `scale(${yesScale})`;
});
yesBtn.addEventListener("click", () => {
window.location.href = "activity.html";
});
})();
+30
View File
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<title>Willst du mit mir gehen? Date-Planer</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=Nunito:wght@400;600;700&family=Quicksand:wght@600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="ask.css" />
</head>
<body class="page-ask">
<div class="heart-background" aria-hidden="true">
<div class="heart-shape"></div>
</div>
<main class="content">
<h1 class="question">Hättest du Lust,<br />mit mir auszugehen? 💕</h1>
<p class="subtitle">Eine kleine Frage mit hoffentlich großer Antwort …</p>
<div class="button-group">
<button id="yesBtn" class="btn btn-yes" type="button">Ja!</button>
<button id="noBtn" class="btn btn-no" type="button">Nein</button>
</div>
</main>
<script src="ask.js" defer></script>
</body>
</html>
+204
View File
@@ -0,0 +1,204 @@
/* ==========================================================================
Date-Planer Shared mobile-first stylesheet
Base color: love-rose, complemented by warm peach and gold tones.
========================================================================== */
:root {
--color-rose: #e0577e;
--color-rose-dark: #b83a5e;
--color-rose-light: #ffd1dc;
--color-peach: #ffb4a2;
--color-gold: #ffd166;
--color-bg: #fff5f7;
--color-bg-gradient: linear-gradient(160deg, #fff5f7 0%, #ffe8ec 45%, #ffe3d6 100%);
--color-text: #4a2c3d;
--color-text-light: #7a5568;
--color-white: #fffdfd;
--font-heading: "Quicksand", "Segoe UI", sans-serif;
--font-body: "Nunito", "Segoe UI", sans-serif;
--radius-lg: 24px;
--radius-md: 16px;
--shadow-soft: 0 8px 24px rgba(184, 58, 94, 0.2);
--shadow-strong: 0 12px 32px rgba(184, 58, 94, 0.32);
}
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
}
body {
margin: 0;
min-height: 100vh;
font-family: var(--font-body);
font-size: clamp(1rem, 3.6vw, 1.15rem);
line-height: 1.5;
color: var(--color-text);
background: var(--color-bg-gradient);
-webkit-font-smoothing: antialiased;
}
h1,
h2,
h3 {
font-family: var(--font-heading);
font-weight: 700;
margin: 0 0 0.5em;
color: var(--color-rose-dark);
}
h1 {
font-size: clamp(1.75rem, 7vw, 2.5rem);
}
p {
margin: 0 0 1em;
}
.container {
width: 100%;
max-width: 480px;
margin: 0 auto;
padding: 24px 20px 40px;
}
/* Buttons -------------------------------------------------------------- */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
min-height: 56px;
padding: 14px 28px;
border: none;
border-radius: var(--radius-lg);
font-family: var(--font-heading);
font-size: clamp(1.05rem, 4.5vw, 1.25rem);
font-weight: 700;
cursor: pointer;
touch-action: manipulation;
transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.2s ease, opacity 0.2s ease;
}
.btn:active {
transform: scale(0.96);
}
.btn-yes {
background: linear-gradient(135deg, var(--color-rose) 0%, var(--color-rose-dark) 100%);
color: var(--color-white);
box-shadow: var(--shadow-soft);
}
.btn-no {
background: var(--color-white);
color: var(--color-text-light);
box-shadow: var(--shadow-soft);
}
.btn-primary {
width: 100%;
background: linear-gradient(135deg, var(--color-rose) 0%, var(--color-rose-dark) 100%);
color: var(--color-white);
box-shadow: var(--shadow-soft);
}
.btn-primary:disabled {
background: #e6d3d8;
color: #b39aa4;
box-shadow: none;
cursor: not-allowed;
}
/* Heart-shaped decorative background (reused across pages) -------------- */
.heart-background {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
z-index: 0;
pointer-events: none;
}
.heart-shape {
position: relative;
width: 62vmin;
height: 56vmin;
}
.heart-shape::before,
.heart-shape::after {
content: "";
position: absolute;
top: 0;
width: 31vmin;
height: 50vmin;
background: linear-gradient(135deg, var(--color-rose-light) 0%, var(--color-peach) 100%);
border-radius: 31vmin 31vmin 0 0;
opacity: 0.55;
}
.heart-shape::before {
left: 31vmin;
transform: rotate(45deg);
transform-origin: 0 100%;
}
.heart-shape::after {
left: 0;
transform: rotate(-45deg);
transform-origin: 100% 100%;
}
/* Fixed bottom bar for a primary continue action ------------------------- */
body.has-continue-bar {
padding-bottom: 96px;
}
.continue-bar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 16px 20px calc(16px + env(safe-area-inset-bottom));
background: linear-gradient(0deg, var(--color-bg) 60%, rgba(255, 245, 247, 0));
}
.continue-bar .container {
padding: 0;
max-width: 480px;
}
/* Back link --------------------------------------------------------------- */
.back-link {
display: inline-flex;
align-items: center;
gap: 4px;
margin-bottom: 12px;
color: var(--color-text-light);
font-family: var(--font-heading);
font-weight: 700;
text-decoration: none;
}
/* Utility ---------------------------------------------------------------- */
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
}