Files
code-crispies/src/index.html

516 lines
23 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="./favicon.ico" type="image/x-icon" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- Primary Meta Tags -->
<title>Code Crispies - Learn HTML & CSS Interactively | Free Coding Practice</title>
<meta
name="description"
content="Master HTML, CSS, and Tailwind through hands-on coding exercises. Free, open-source learning platform with instant feedback. No account required."
/>
<meta name="keywords" content="learn CSS, HTML tutorial, Tailwind CSS, web development, coding practice, free" />
<meta name="robots" content="index, follow" />
<meta name="theme-color" content="#6366f1" />
<link rel="canonical" href="https://codecrispi.es/" />
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website" />
<meta property="og:url" content="https://codecrispi.es/" />
<meta property="og:title" content="Code Crispies - Learn HTML & CSS Interactively" />
<meta property="og:description" content="Master HTML, CSS, and Tailwind through hands-on coding exercises. Free and open source." />
<meta property="og:image" content="https://codecrispi.es/og-image.png" />
<meta property="og:site_name" content="Code Crispies" />
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Code Crispies - Learn HTML & CSS Interactively" />
<meta name="twitter:description" content="Master HTML, CSS, and Tailwind through hands-on coding exercises." />
<meta name="twitter:image" content="https://codecrispi.es/og-image.png" />
<!-- Structured Data -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebApplication",
"name": "Code Crispies",
"description": "Interactive platform for learning HTML, CSS, and Tailwind through hands-on coding exercises",
"url": "https://codecrispi.es/",
"applicationCategory": "EducationalApplication",
"operatingSystem": "Web Browser",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
},
"author": {
"@type": "Organization",
"name": "LibreTECH",
"url": "https://librete.ch"
}
}
</script>
<link rel="stylesheet" href="main.css" />
<script defer src="https://librete.ch/u/script.js" data-website-id="2189049f-80c1-4ca0-b0ff-b5cc49276b5f"></script>
</head>
<body>
<a href="#main-content" class="skip-link" data-i18n="skipLink">Skip to main content</a>
<div class="app-container">
<header class="header">
<div class="header-left">
<button id="menu-btn" class="menu-toggle" data-i18n-aria-label="menuOpen" aria-label="Open menu">
<span class="hamburger-icon"></span>
</button>
<a href="#" class="header-level-pill" id="header-level-pill"></a>
</div>
<a href="#" id="logo-link" class="logo">
<img src="./bowl.png" width="40" alt="CODE CRISPIES Logo" />
<h1><span class="code-text">CODE</span><span class="crispies-text">CRISPIES</span></h1>
</a>
<div class="header-actions">
<nav class="main-nav" id="main-nav" aria-label="Main sections">
<a href="#css" class="nav-link" data-section="css">CSS</a>
<a href="#html" class="nav-link" data-section="html">HTML</a>
<a href="#tailwind" class="nav-link" data-section="tailwind">Tailwind</a>
<a href="#reference/css" class="nav-link nav-link-ref" data-section="reference">Reference</a>
</nav>
<button id="help-btn" class="help-toggle" data-i18n-aria-label="help" aria-label="Help">?</button>
</div>
</header>
<!-- Landing Page (Home) -->
<div class="landing-page hidden" id="landing-page">
<div class="landing-content">
<section class="hero">
<img src="./bowl.png" width="120" alt="" class="hero-logo" />
<h1>
<span data-i18n="landingHeroTitle">Learn Web Development</span><br /><span
class="hero-highlight"
data-i18n="landingHeroHighlight"
>By Writing Real Code</span
>
</h1>
<p class="hero-subtitle" data-i18n="landingHeroSubtitle">
Master HTML, CSS, and Tailwind through hands-on exercises with instant feedback. Free and open source.
</p>
<a href="#welcome/0" class="cta-button cta-primary" data-i18n="landingCtaStart">Start Learning NOW</a>
</section>
<section class="why-it-works">
<h2 data-i18n="landingWhyTitle">Why Code Crispies Works</h2>
<div class="benefits-grid">
<article class="benefit-card">
<svg class="benefit-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="16 18 22 12 16 6"></polyline>
<polyline points="8 6 2 12 8 18"></polyline>
</svg>
<h3 data-i18n="landingBenefit1Title">Learn by Doing</h3>
<p data-i18n="landingBenefit1Text">
Write real code from lesson one. No videos to watch—just you, an editor, and instant feedback on every keystroke.
</p>
</article>
<article class="benefit-card">
<svg class="benefit-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 20V10M18 20V4M6 20v-4"></path>
</svg>
<h3 data-i18n="landingBenefit2Title">Practice at Your Pace</h3>
<p data-i18n="landingBenefit2Text">
Start with basics, fill gaps in your understanding, then accelerate. Pick up where you left off anytime.
</p>
</article>
<article class="benefit-card">
<svg class="benefit-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path
d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"
></path>
</svg>
<h3 data-i18n="landingBenefit3Title">Master Real Skills</h3>
<p data-i18n="landingBenefit3Text">
Learn CSS, HTML, and Tailwind the way professionals use them—through hands-on exercises and reference guides.
</p>
</article>
</div>
</section>
<section class="learning-paths">
<h2 data-i18n="landingPathsTitle">Explore Learning Paths</h2>
<div class="section-cards" id="section-cards">
<a href="#css" class="section-card" data-section="css">
<div class="section-card-icon" style="background: #7c4dff">CSS</div>
<h3>CSS</h3>
<p data-i18n="landingCssDesc">Styling, layout, and animations</p>
<span class="section-card-progress" id="css-progress"></span>
</a>
<a href="#html" class="section-card" data-section="html">
<div class="section-card-icon" style="background: #e91e63">HTML</div>
<h3>HTML</h3>
<p data-i18n="landingHtmlDesc">Semantic markup and native elements</p>
<span class="section-card-progress" id="html-progress"></span>
</a>
<a href="#tailwind" class="section-card" data-section="tailwind">
<div class="section-card-icon" style="background: #00bcd4">TW</div>
<h3>Tailwind CSS</h3>
<p data-i18n="landingTailwindDesc">Utility-first CSS framework</p>
<span class="section-card-progress" id="tailwind-progress"></span>
</a>
</div>
</section>
<section class="landing-cta">
<h2 data-i18n="landingCtaTitle">Start Learning Today</h2>
<a href="#welcome/0" class="cta-button" data-i18n="landingCtaButton">Begin Your Journey</a>
<p class="cta-sub" data-i18n="landingCtaSub">Free and open source. No account required. Progress saved locally.</p>
</section>
<footer class="landing-footer">
<div class="footer-grid">
<section class="footer-section footer-modules">
<div id="footer-lesson-links" class="footer-links"></div>
</section>
<section class="footer-section">
<h4 data-i18n="footerResources">Resources</h4>
<ul class="footer-links">
<li><a href="#reference/css">CSS Reference</a></li>
<li><a href="#reference/html">HTML Reference</a></li>
<li><a href="#playground/0" data-i18n="footerPlayground">Playground</a></li>
</ul>
</section>
<section class="footer-section">
<h4 data-i18n="footerAbout">About</h4>
<ul class="footer-links">
<li><a href="https://librete.ch" target="_blank">LibreTECH</a></li>
<li><a href="https://git.librete.ch/public/code-crispies" target="_blank">Source Code</a></li>
<li><a href="https://github.com/nextlevelshit/code-crispies" target="_blank">GitHub</a></li>
</ul>
</section>
<section class="footer-section footer-support">
<h4 data-i18n="footerSupport">Support</h4>
<p data-i18n="footerSupportText">Help keep Code Crispies free and open source.</p>
<script src="https://liberapay.com/libretech/widgets/button.js"></script>
<noscript><a href="https://liberapay.com/libretech/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a></noscript>
</section>
</div>
<div class="footer-bottom">
<p>&copy; 2025 <a href="https://librete.ch">LibreTECH</a>. <span data-i18n="footerLicense">Open source under MIT License.</span></p>
</div>
</footer>
</div>
</div>
<!-- Section Landing Page -->
<div class="section-page hidden" id="section-page">
<article class="section-content">
<header class="section-hero">
<h1 id="section-title">CSS</h1>
<p id="section-description">Styling, layout, and animations</p>
<div class="section-progress-bar">
<div class="progress-bar">
<div class="progress-fill" id="section-progress-fill"></div>
</div>
<span class="progress-text" id="section-progress-text">0 of 0 lessons complete</span>
</div>
</header>
<!-- Educational content with integrated module links -->
<div class="section-intro" id="section-intro"></div>
</article>
</div>
<!-- Reference/Cheatsheet Pages -->
<div class="reference-page hidden" id="reference-page">
<article class="reference-content">
<nav class="reference-nav" id="reference-nav">
<a href="#reference/css" class="ref-nav-link" data-ref="css">CSS Properties</a>
<a href="#reference/selectors" class="ref-nav-link" data-ref="selectors">Selectors</a>
<a href="#reference/flexbox" class="ref-nav-link" data-ref="flexbox">Flexbox</a>
<a href="#reference/grid" class="ref-nav-link" data-ref="grid">Grid</a>
<a href="#reference/html" class="ref-nav-link" data-ref="html">HTML Elements</a>
</nav>
<div class="reference-body" id="reference-body">
<!-- Reference content injected by JS -->
</div>
</article>
</div>
<main class="game-layout" id="main-content">
<!-- Left Panel: Instructions + Editor -->
<div class="left-panel">
<section class="instructions">
<div class="lesson-title-row">
<h2 id="lesson-title"></h2>
<button id="share-btn" class="share-btn" data-i18n-title="shareTitle" title="Share lesson" aria-label="Share lesson">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
</svg>
</button>
</div>
<div class="task-instruction" id="task-instruction"></div>
<div class="lesson-description" id="lesson-description"></div>
</section>
<section class="editor-section">
<div class="code-editor">
<div class="editor-header">
<label for="code-input" class="editor-label" data-i18n="editorLabel">CSS Editor</label>
<div class="editor-actions">
<div class="editor-tools">
<button id="undo-btn" class="btn btn-icon" data-i18n-title="undoTitle" title="Undo (Ctrl+Z)"></button>
<button id="redo-btn" class="btn btn-icon" data-i18n-title="redoTitle" title="Redo (Ctrl+Shift+Z)"></button>
<button
id="reset-code-btn"
class="btn btn-icon"
data-i18n-title="resetCodeTitle"
title="Reset to initial code"
>
</button>
<button id="random-template-btn" class="btn btn-icon hidden" title="Load random template"><img src="./dice.svg" alt="" /></button>
</div>
<button id="run-btn" class="btn btn-run"><img src="./gear.svg" alt="" /><span data-i18n="run">Run</span></button>
</div>
</div>
<div class="editor-content">
<textarea id="code-input" class="code-input" spellcheck="false" autocomplete="off" style="display: none"></textarea>
</div>
</div>
<div class="hint-area" id="hint-area"></div>
</section>
</div>
<!-- Right Panel: Preview + Navigation -->
<div class="right-panel">
<div class="game-controls">
<button id="prev-btn" class="btn" data-i18n="previous">Previous</button>
<span class="module-pill" id="module-pill">
<span class="module-name"></span>
<span class="level-indicator" id="level-indicator"></span>
</span>
<button id="next-btn" class="btn btn-primary" data-i18n="next">Next</button>
</div>
<div class="preview-section">
<div class="preview-wrapper">
<div class="preview-frame" id="preview-area"></div>
<div class="expected-overlay" id="expected-overlay">
<div class="expected-frame" id="preview-expected"></div>
</div>
</div>
<div class="preview-header">
<span class="preview-label" data-i18n="yourOutput">Your Output</span>
<button id="show-expected-btn" class="btn btn-small" data-i18n="showExpected">Show Expected</button>
</div>
</div>
</div>
</main>
<!-- Sidebar Backdrop -->
<div class="sidebar-backdrop" id="sidebar-backdrop"></div>
<!-- Slide-out Sidebar -->
<aside class="sidebar-drawer" id="sidebar-drawer" data-i18n-aria-label="menu" aria-label="Menu">
<div class="sidebar-header">
<h3 data-i18n="menu">Menu</h3>
<button id="close-sidebar" class="close-btn" data-i18n-aria-label="closeMenu" aria-label="Close menu">&times;</button>
</div>
<div class="sidebar-section">
<h4 data-i18n="progress">Progress</h4>
<div class="progress-display" id="progress-display">
<div class="progress-bar">
<div class="progress-fill" id="progress-fill"></div>
</div>
<span class="progress-text" id="progress-text">0% Complete</span>
</div>
</div>
<nav class="sidebar-section" aria-label="Lesson navigation">
<h4 id="lessons-heading" data-i18n="lessons">Lessons</h4>
<div class="module-list" id="module-list" role="tree" aria-labelledby="lessons-heading"></div>
</nav>
<div class="sidebar-section">
<h4 data-i18n="settings">Settings</h4>
<label class="setting-row">
<span class="setting-label" data-i18n="language">Language</span>
<select id="lang-select" class="lang-select">
<option value="en">English</option>
<option value="de">Deutsch</option>
<option value="pl">Polski</option>
<option value="es">Español</option>
<option value="ar">العربية</option>
<option value="uk">Українська</option>
</select>
</label>
<label class="toggle-switch">
<input type="checkbox" id="disable-feedback-toggle" checked />
<span class="toggle-slider"></span>
<span class="toggle-label" data-i18n="showHints">Show Hints</span>
</label>
<button id="reset-btn" class="btn btn-text" data-i18n="resetAllProgress">Reset All Progress</button>
</div>
<footer class="app-footer">
<span data-i18n="openSource">Open Source:</span>
<a href="https://git.librete.ch/public/code-crispies" target="_blank">Gitea</a>
<span data-i18n="by">by</span> <a href="https://librete.ch" title="LibreTECH">LibreTECH</a>
</footer>
</aside>
<!-- Help Dialog -->
<dialog id="help-dialog" class="dialog">
<div class="dialog-header">
<h3 data-i18n="helpTitle">Help</h3>
<button id="help-dialog-close" class="dialog-close" aria-label="Close">&times;</button>
</div>
<div class="dialog-content">
<h4 data-i18n="aboutTitle">About Code Crispies</h4>
<p data-i18n="aboutText">
Code Crispies is a free, open-source platform for learning web development through hands-on exercises. No account required -
just start coding!
</p>
<h4 data-i18n="learningModesTitle">Learning Modes</h4>
<ul>
<li data-i18n-html="modeCss"><strong>CSS</strong> - Write CSS rules to style elements</li>
<li data-i18n-html="modeTailwind"><strong>Tailwind</strong> - Apply utility classes directly in HTML</li>
<li data-i18n-html="modeHtml"><strong>HTML</strong> - Practice semantic markup and native elements</li>
</ul>
<p class="help-nav-links">
Jump to: <a href="#css">CSS</a> | <a href="#html">HTML</a> |
<a href="#reference/css">Reference</a>
</p>
<h4 data-i18n="gettingStartedTitle">Getting Started</h4>
<p data-i18n="gettingStartedText">
Open the menu (☰) to browse lesson modules. Each module covers a specific topic with progressive exercises.
</p>
<h4 data-i18n="completingLessonsTitle">Completing Lessons</h4>
<ol>
<li data-i18n="completingStep1">Read the task instructions on the left</li>
<li data-i18n="completingStep2">Write your code in the editor</li>
<li data-i18n="completingStep3">Watch the live preview update as you type</li>
<li data-i18n="completingStep4">Follow hints to fix any issues</li>
<li data-i18n-html="completingStep5">Click <strong>Next</strong> when complete</li>
</ol>
<h4 data-i18n="editorToolsTitle">Editor Tools</h4>
<ul>
<li data-i18n-html="editorToolUndo"><strong>↶ Undo</strong> / <strong>↷ Redo</strong> - Navigate edit history</li>
<li data-i18n-html="editorToolReset"><strong>⟲ Reset</strong> - Restore initial code for current lesson</li>
<li data-i18n-html="editorToolExpected"><strong>Show Expected</strong> - Toggle the target result overlay</li>
</ul>
<h4 data-i18n="keyboardShortcutsTitle">Keyboard Shortcuts</h4>
<ul>
<li data-i18n-html="shortcutUndo"><kbd>Ctrl+Z</kbd> - Undo</li>
<li data-i18n-html="shortcutRedo"><kbd>Ctrl+Shift+Z</kbd> - Redo</li>
</ul>
<h4 data-i18n="emmetTitle">Emmet Shortcuts (HTML mode)</h4>
<p data-i18n-html="emmetText">Type abbreviations and press <kbd>Tab</kbd> to expand:</p>
<ul>
<li data-i18n-html="emmetClass"><kbd>div.box</kbd> → div with class</li>
<li data-i18n-html="emmetChildren"><kbd>ul>li*3</kbd> → ul with 3 li children</li>
<li data-i18n-html="emmetNested"><kbd>form>input+button</kbd> → nested structure</li>
<li data-i18n-html="emmetContent"><kbd>p{Hello}</kbd> → p with text content</li>
</ul>
<h4 data-i18n="moreProjectsTitle">More Projects</h4>
<div class="project-cards">
<a href="https://nextlevelshit.github.io/html-over-js/" target="_blank" class="project-card">
<strong>HTML over JS</strong>
<span data-i18n="htmlOverJsDesc"> - Learn to leverage native HTML elements instead of custom JavaScript solutions</span>
</a>
<a href="https://nextlevelshit.github.io/web-engineering-mandala/" target="_blank" class="project-card">
<strong>Web Engineering Mandala</strong>
<span data-i18n="mandalaDesc"> - Interactive visualization of JavaScript technologies organized by complexity</span>
</a>
</div>
<h4 data-i18n="contactTitle">Contact & Links</h4>
<p data-i18n-html="contactText">Code Crispies is developed by <a href="https://librete.ch" target="_blank">LibreTECH</a></p>
<ul>
<li><a href="https://git.librete.ch/public/code-crispies" target="_blank">Gitea</a> Self-hosted source repository</li>
<li><a href="https://github.com/nextlevelshit/code-crispies" target="_blank">GitHub</a> Public mirror</li>
<li><a href="https://www.linkedin.com/in/michael-werner-czechowski" target="_blank">LinkedIn</a> Michael Czechowski</li>
</ul>
<h4 data-i18n="supportTitle">Support the Project</h4>
<p data-i18n="supportText">Help keep Code Crispies free and open source.</p>
<div class="help-support" onclick="typeof umami !== 'undefined' && umami.track('support_click', {location: 'help'})">
<script src="https://liberapay.com/libretech/widgets/button.js"></script>
<noscript><a href="https://liberapay.com/libretech/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a></noscript>
</div>
</div>
</dialog>
<!-- Reset Code Confirmation Dialog -->
<dialog id="reset-code-dialog" class="dialog">
<div class="dialog-header">
<h3 data-i18n="resetCodeDialogTitle">Reset Code</h3>
<button id="reset-code-dialog-close" class="dialog-close" aria-label="Close">&times;</button>
</div>
<div class="dialog-content">
<p data-i18n="resetCodeDialogText">Reset your code to the initial state for this lesson?</p>
<label class="toggle-switch" style="margin: 1rem 0">
<input type="checkbox" id="reset-code-dont-show" />
<span class="toggle-slider"></span>
<span class="toggle-label" data-i18n="dontShowAgain">Don't show this again</span>
</label>
<div class="dialog-actions">
<button id="cancel-reset-code" class="btn" data-i18n="cancel">Cancel</button>
<button id="confirm-reset-code" class="btn btn-ghost" data-i18n="reset">Reset</button>
</div>
</div>
</dialog>
<!-- Reset Confirmation Dialog -->
<dialog id="reset-dialog" class="dialog">
<div class="dialog-header">
<h3 data-i18n="resetDialogTitle">Reset Progress</h3>
<button id="reset-dialog-close" class="dialog-close" aria-label="Close">&times;</button>
</div>
<div class="dialog-content">
<p data-i18n="resetDialogText">Are you sure you want to reset all your progress? This cannot be undone.</p>
<div class="dialog-actions">
<button id="cancel-reset" class="btn" data-i18n="cancel">Cancel</button>
<button id="confirm-reset" class="btn btn-ghost" data-i18n="resetAll">Reset All</button>
</div>
</div>
</dialog>
<!-- Share Dialog -->
<dialog id="share-dialog" class="dialog">
<div class="dialog-header">
<h3 data-i18n="shareDialogTitle">Share Lesson</h3>
<button id="share-dialog-close" class="dialog-close" aria-label="Close">&times;</button>
</div>
<div class="dialog-content">
<p data-i18n="shareDialogText">Copy this URL to share the current lesson:</p>
<div class="share-url-container">
<input type="text" id="share-url-input" class="share-url-input" readonly />
<button id="copy-url-btn" class="btn btn-primary" data-i18n="copyUrl">Copy</button>
</div>
<p id="copy-feedback" class="copy-feedback" data-i18n="urlCopied" hidden>URL copied to clipboard!</p>
</div>
</dialog>
</div>
<script type="module" src="app.js"></script>
</body>
</html>