Compare commits
125 Commits
64f48f82c0
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 8391c02b51 | |||
| be883e0b59 | |||
| c276108078 | |||
| e9dfc46b0f | |||
| 144ba84954 | |||
| b30e621c7c | |||
| b696c36de5 | |||
| e15aafc3aa | |||
| 84f9761a35 | |||
| 393b78a0e8 | |||
| 9d1b6dee52 | |||
| 93625b0419 | |||
| 9533f003dc | |||
| dc7a78621c | |||
| db47dbadec | |||
| 6f2d6b643d | |||
| 0b01773cec | |||
| d7961af07a | |||
| 3caa9a3cf2 | |||
| c6c07a1dd8 | |||
| 3e7052a217 | |||
| 93f070ff33 | |||
| 1d43de19a8 | |||
| 0b42a7f0da | |||
| 021a3ea2a2 | |||
| 64c02b39dc | |||
| 94b9134f8e | |||
| df38d7d9ef | |||
| f431b97559 | |||
| d1889f69f0 | |||
| 7f6dde7069 | |||
| 1d5d9c0904 | |||
| fce691fa9c | |||
| 3d27079885 | |||
| c872fa67e6 | |||
| 40cfb685b8 | |||
| 32bf98e146 | |||
| 31a3591ba5 | |||
| 4d2e5de954 | |||
| 78c805bbf9 | |||
| 90c8d56e3c | |||
| 9275601f07 | |||
| 2ad54e184c | |||
| cfa9db823e | |||
| a9165ac371 | |||
| 6e43ebe5be | |||
| f1774fde6b | |||
| c0a280bca8 | |||
| cd97f53632 | |||
| 3a80e71c21 | |||
| c4cad08700 | |||
| 27e4bcdd02 | |||
| e5f26f6d30 | |||
| 997fffa367 | |||
| d33dcd7fb9 | |||
| 78dc8cbd08 | |||
| b0e1dad5ea | |||
| 5db7ad8e6b | |||
| d7702d6697 | |||
| 0d05bb254d | |||
| 881b357167 | |||
| 0c477ca428 | |||
| b12bcfd5ea | |||
| f4b03c9221 | |||
| 9f4a46bc88 | |||
| 7467ae2d37 | |||
| a7f1c83e83 | |||
| ad8b7777f2 | |||
| 041f46f551 | |||
| df0a3cd24e | |||
| 047a190b9d | |||
| 5220230e67 | |||
| 056c68dbc0 | |||
| fa7c5bb487 | |||
| ecdf5dd2cc | |||
| f5a430b39c | |||
| ab1d471fd5 | |||
| be581d7733 | |||
| c6f0ddfa14 | |||
| 332f4197a3 | |||
| 0bfeb87a49 | |||
| c2100248f2 | |||
| 5aa58cbd4a | |||
| de0c566c04 | |||
| 25848c9ea5 | |||
| 1b5ac9bf07 | |||
| a80b914a17 | |||
| 9f5ff9d56b | |||
| e63ae9a9c7 | |||
| 63454468a7 | |||
| f7fe14298a | |||
| 9691b7164b | |||
| 839fcb7314 | |||
| 395f9a0e9f | |||
| 5acced48ad | |||
| 755a0e5057 | |||
| b00f0559f0 | |||
| ce531399f9 | |||
| 265cee9b97 | |||
| 5203e616d0 | |||
| f7b43da97b | |||
| aab02f23c0 | |||
| 2937173a81 | |||
| c2af21ae42 | |||
| b1346cbe90 | |||
| 2e224930b5 | |||
| c398905f9b | |||
| 883dc2122d | |||
| 38de9b916a | |||
| bac70d7823 | |||
| 99bae87b0d | |||
| 1a1dc48afe | |||
| c8f731a353 | |||
| dd9bad935e | |||
| af4cc2ae48 | |||
| 64a3c1d583 | |||
| 3129f982df | |||
| 19b91eb9e4 | |||
| 2197c4408d | |||
| 920c0a1d49 | |||
| 78fe818877 | |||
| f5b46c7a2c | |||
| 99ddd47649 | |||
| 9a3b35b428 | |||
| b0286ee5fe |
@@ -16,9 +16,11 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'pnpm'
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Create Ghost Config
|
||||
run: |
|
||||
echo "window.GhostConfig = { ghostApiKey: '${{ secrets.GHOST_CONTENT_API_KEY }}', ghostApiUrl: '${{ secrets.GHOST_ADMIN_API_URL }}' };" > assets/js/ghost-config.js
|
||||
- name: Build theme
|
||||
run: pnpm build
|
||||
- name: Deploy Ghost Theme
|
||||
|
||||
51
README.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Palina Theme: A Digital Shrine to Artistic Brilliance (and Palina)
|
||||
|
||||
Welcome, digital wanderer, to the "Palina" theme – where every pixel is inspired by the radiant charisma of the one and only Palina Rojinski! ✨ This isn't just a Ghost CMS theme; it's a meticulously crafted digital gallery designed to showcase your most stunning AI-generated images with the elegance and flair that Palina herself embodies.
|
||||
|
||||
## Why "Palina," you ask?
|
||||
|
||||
Because ordinary themes are, well, *ordinary*. This theme captures the vibrant, sophisticated, and utterly captivating essence of Palina Rojinski, translating it into a clean, minimalistic, yet undeniably stylish aesthetic. Think modern art gallery meets exclusive digital showcase, all wrapped up in a package as delightful as Palina's latest dance move.
|
||||
|
||||
## Features that Dazzle (Like Palina's Smile):
|
||||
|
||||
* **Adaptive Brilliance:** Seamlessly switch between a chic **Dark Mode** and a vibrant **Light Mode** to match your mood (or Palina's outfit of the day). Your preference is remembered, naturally!
|
||||
* **Mobile Grace:** A sleek, responsive design ensures your images look phenomenal on any device. Plus, a **hamburger menu** for mobile makes navigation as smooth as Palina's transitions on the dance floor.
|
||||
* **Captivating Animations:** Subtle **CSS animations** bring your content to life, while a convenient **image lightbox** allows admirers to zoom into every exquisite detail.
|
||||
* **Artistic Typography:** Featuring the elegant **Playfair Display** for headlines and the modern **Montserrat** for body text, ensuring your words are as captivating as your visuals.
|
||||
* **Ghost CMS Power:** Full support for all Ghost features, because even artistic masterpieces need solid foundations.
|
||||
|
||||
## Getting Started (It's Easier Than Learning Palina's Choreography):
|
||||
|
||||
1. **Clone this repository.**
|
||||
2. **Install dependencies:** Ensure you have `pnpm` installed, then run:
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
3. **Build the theme:**
|
||||
* For development with live reloading:
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
* For a production-ready, minified build:
|
||||
```bash
|
||||
pnpm build
|
||||
```
|
||||
|
||||
## Deployment (Let Gitea Do the Heavy Lifting):
|
||||
|
||||
This theme comes with a built-in Gitea Actions workflow (`.gitea/workflows/deploy.yml`) to automate deployment to your live Ghost site.
|
||||
|
||||
**Before you push:**
|
||||
|
||||
1. Go to your Gitea repository settings.
|
||||
2. Add the following secrets:
|
||||
* `GHOST_ADMIN_API_URL`: Your Ghost site's URL (e.g., `https://your-domain.com`).
|
||||
* `GHOST_ADMIN_API_KEY`: Your Admin API Key from Ghost (find it under **Settings > Integrations > Custom Integrations**).
|
||||
|
||||
Once configured, simply push your changes to the `main` branch, and watch the magic unfold! ✨
|
||||
|
||||
---
|
||||
|
||||
**A Note on the Images:** The AI-generated images of Palina Rojinski are purely for demonstrative and artistic purposes within the context of this theme. No actual endorsement or affiliation is implied, just immense admiration!
|
||||
|
||||
May your blog be as awesome, outstanding, and beautiful as its namesake!
|
||||
@@ -1,53 +1,243 @@
|
||||
@import "tailwindcss";
|
||||
@plugin "@tailwindcss/typography";
|
||||
|
||||
@custom-variant hover (&:hover);
|
||||
|
||||
@theme {
|
||||
/* Default Custom Properties (Dark Theme) */
|
||||
--bg-primary: var(--color-gray-900);
|
||||
--bg-secondary: var(--color-gray-800);
|
||||
--bg-tertiary: var(--color-gray-700);
|
||||
--text-primary: var(--color-gray-100);
|
||||
--text-secondary: var(--color-gray-400);
|
||||
--text-tertiary: var(--color-gray-300);
|
||||
--brand-primary: var(--color-indigo-600);
|
||||
--brand-secondary: var(--color-indigo-700);
|
||||
|
||||
--color-gray-900: #1a1a1a;
|
||||
--color-gray-800: #2b2b2b;
|
||||
--color-gray-700: #3c3c3c;
|
||||
--color-gray-500: #808080;
|
||||
--color-gray-400: #a0a0a0;
|
||||
--color-gray-200: #e0e0e0;
|
||||
--color-gray-100: #f5f5f5;
|
||||
--color-indigo-600: #4f46e5;
|
||||
--color-indigo-700: #4338ca;
|
||||
/* Brand Palette: Palina Gold (#DDC288) */
|
||||
--color-brand-50: #faf8f0;
|
||||
--color-brand-100: #f4edd1;
|
||||
--color-brand-200: #e9dba4;
|
||||
--color-brand-300: #ddc277;
|
||||
--color-brand-400: #ddc288;
|
||||
--color-brand-500: #c9a765;
|
||||
--color-brand-600: #b58d46;
|
||||
--color-brand-700: #9c763a;
|
||||
--color-brand-800: #7d5e31;
|
||||
--color-brand-900: #624a29;
|
||||
--color-brand-950: #4c3a23;
|
||||
|
||||
/* Font Families */
|
||||
--font-family-body: "Montserrat", sans-serif;
|
||||
--font-family-heading: "Playfair Display", serif;
|
||||
--font-serif: "Fraunces", serif;
|
||||
--font-heading: "Fraunces", serif;
|
||||
--font-sans: "Montserrat", sans-serif;
|
||||
}
|
||||
|
||||
/* Light Theme Overrides (outside @theme block) */
|
||||
html[data-theme='light'] {
|
||||
--bg-primary: var(--color-gray-100);
|
||||
--bg-secondary: var(--color-gray-200);
|
||||
--bg-tertiary: var(--color-gray-300);
|
||||
--text-primary: var(--color-gray-900);
|
||||
--text-secondary: var(--color-gray-600);
|
||||
--text-tertiary: var(--color-gray-700);
|
||||
/*
|
||||
Theme Variable Definitions
|
||||
Using :root for default (Dark) and [data-theme='light'] for overrides.
|
||||
*/
|
||||
:root {
|
||||
--bg-primary: #121212;
|
||||
--bg-secondary: #1e1e1e;
|
||||
--bg-tertiary: #2a2a2a;
|
||||
--text-primary: #f2f2f2;
|
||||
--text-secondary: #a3a3a3;
|
||||
--text-tertiary: #737373;
|
||||
--brand-primary: #ddc288;
|
||||
--brand-secondary: #c9a765;
|
||||
}
|
||||
|
||||
[data-theme='light'] {
|
||||
--bg-primary: #fdfcf9;
|
||||
--bg-secondary: #f4f1e8;
|
||||
--bg-tertiary: #e9e4d5;
|
||||
--text-primary: #2d2114;
|
||||
--text-secondary: #624a29;
|
||||
--text-tertiary: #7d5e31;
|
||||
--brand-primary: #9c763a;
|
||||
--brand-secondary: #7d5e31;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
[x-cloak] { display: none !important; }
|
||||
|
||||
body {
|
||||
background-color: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
font-family: var(--font-family-body); /* Apply default body font */
|
||||
font-family: var(--font-sans);
|
||||
transition: background-color 0.3s ease, color 0.3s ease;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: var(--font-family-heading); /* Apply heading font */
|
||||
font-family: var(--font-heading);
|
||||
color: var(--brand-primary);
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Typography (Prose) Customization
|
||||
Using @utility prose to override internal Typography plugin variables
|
||||
as recommended for Tailwind CSS v4. Must be at the top level.
|
||||
*/
|
||||
@utility prose {
|
||||
--tw-prose-body: var(--text-primary);
|
||||
--tw-prose-headings: var(--brand-primary);
|
||||
--tw-prose-links: var(--brand-primary);
|
||||
--tw-prose-bold: var(--text-primary);
|
||||
--tw-prose-counters: var(--text-secondary);
|
||||
--tw-prose-bullets: var(--brand-primary);
|
||||
--tw-prose-hr: var(--bg-tertiary);
|
||||
--tw-prose-quotes: var(--text-primary);
|
||||
--tw-prose-quote-borders: var(--brand-primary);
|
||||
--tw-prose-captions: var(--text-secondary);
|
||||
--tw-prose-code: var(--text-primary);
|
||||
--tw-prose-pre-code: var(--text-primary);
|
||||
--tw-prose-pre-bg: var(--bg-secondary);
|
||||
--tw-prose-th-borders: var(--bg-tertiary);
|
||||
--tw-prose-td-borders: var(--bg-secondary);
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@layer components {
|
||||
/* Main navigation styling */
|
||||
header nav ul.nav {
|
||||
@apply flex items-center space-x-6;
|
||||
}
|
||||
|
||||
/* Mobile navigation styling */
|
||||
#mobile-menu nav ul.nav {
|
||||
@apply flex flex-col items-center space-y-10 text-4xl;
|
||||
}
|
||||
|
||||
/* Footer navigation styling */
|
||||
footer nav ul.nav {
|
||||
@apply flex items-center space-x-4 text-sm tracking-wide;
|
||||
}
|
||||
|
||||
footer nav ul.nav li {
|
||||
@apply flex items-center;
|
||||
}
|
||||
|
||||
footer nav ul.nav li:not(:last-child)::after {
|
||||
content: "|";
|
||||
@apply ml-4 opacity-20 text-[var(--text-secondary)];
|
||||
}
|
||||
|
||||
/* Navigation Links */
|
||||
.nav-link {
|
||||
@apply relative py-2 px-1 transition-all duration-300 opacity-80 hover:opacity-100 hover:text-[var(--brand-primary)];
|
||||
}
|
||||
|
||||
.nav-link::after {
|
||||
content: "";
|
||||
@apply absolute bottom-0 left-0 w-full h-0.5 bg-[var(--brand-primary)] transform scale-x-0 transition-transform duration-300 ease-out origin-left;
|
||||
}
|
||||
|
||||
.nav-link:hover::after,
|
||||
.nav-current .nav-link::after {
|
||||
@apply scale-x-100;
|
||||
}
|
||||
|
||||
.nav-current .nav-link {
|
||||
@apply text-[var(--brand-primary)] opacity-100 font-semibold;
|
||||
}
|
||||
|
||||
/* Button & Link Components */
|
||||
.btn-primary {
|
||||
@apply inline-flex items-center px-8 py-3 border border-transparent text-base font-semibold rounded-lg shadow-md
|
||||
bg-[var(--brand-primary)] text-[var(--bg-primary)]
|
||||
hover:shadow-lg hover:-translate-y-0.5 active:translate-y-0
|
||||
transition-all duration-300 cursor-pointer relative overflow-hidden;
|
||||
}
|
||||
|
||||
.btn-primary::after {
|
||||
content: "";
|
||||
@apply absolute inset-0 bg-white opacity-0 transition-opacity duration-300;
|
||||
}
|
||||
|
||||
.btn-primary:hover::after {
|
||||
@apply opacity-10;
|
||||
}
|
||||
|
||||
.fancy-link {
|
||||
@apply font-medium transition-all duration-300 relative inline-block;
|
||||
color: var(--brand-primary) !important;
|
||||
text-decoration: none !important;
|
||||
background-image: linear-gradient(var(--brand-primary), var(--brand-primary));
|
||||
background-position: 0 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 0 1px;
|
||||
}
|
||||
|
||||
.fancy-link:hover {
|
||||
@apply text-[var(--text-primary)];
|
||||
background-size: 100% 1px;
|
||||
}
|
||||
|
||||
/* Specific prose element overrides for fonts and effects */
|
||||
.prose :where(h1, h2, h3, h4, h5, h6) {
|
||||
color: var(--brand-primary) !important;
|
||||
font-family: var(--font-heading);
|
||||
@apply font-bold tracking-tight transition-colors duration-300;
|
||||
}
|
||||
|
||||
.prose a {
|
||||
color: var(--brand-primary) !important;
|
||||
text-decoration: none !important;
|
||||
@apply font-medium transition-all duration-300;
|
||||
background-image: linear-gradient(var(--brand-primary), var(--brand-primary));
|
||||
background-position: 0 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 0 1px;
|
||||
}
|
||||
|
||||
.prose a:hover {
|
||||
background-size: 100% 1px;
|
||||
}
|
||||
|
||||
/* Initial Letter (Drop Cap) Effect - Only on Posts */
|
||||
.is-post .post-content > p:first-of-type::first-letter {
|
||||
-webkit-initial-letter: 3 2;
|
||||
initial-letter: 3 2;
|
||||
color: var(--brand-primary);
|
||||
@apply font-serif font-bold mr-4 float-left transition-colors duration-300;
|
||||
/* Fallback for browsers that don't support initial-letter */
|
||||
@supports not (initial-letter: 3) {
|
||||
@apply text-7xl leading-[0.8] mt-2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Koenig Editor (Ghost) required classes */
|
||||
.kg-width-wide {
|
||||
position: relative;
|
||||
width: 85vw;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
max-width: 1200px;
|
||||
}
|
||||
|
||||
.kg-width-full {
|
||||
position: relative;
|
||||
width: 100vw;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.kg-card {
|
||||
@apply mb-8;
|
||||
}
|
||||
|
||||
.kg-card-caption {
|
||||
@apply text-center text-sm text-[var(--text-secondary)] mt-2;
|
||||
}
|
||||
}
|
||||
|
||||
.site-logo {
|
||||
@apply transition-all duration-300;
|
||||
color: var(--brand-primary);
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.post-grid-item {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.post-grid-item.animated {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
@@ -59,20 +249,6 @@ html[data-theme='light'] {
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.animate-fadeInUp {
|
||||
animation: fadeInUp 0.5s ease-out forwards;
|
||||
animation: fadeInUp 0.5s ease-out both;
|
||||
}
|
||||
|
||||
#lightbox.show {
|
||||
animation: fadeIn 0.3s ease-out forwards;
|
||||
}
|
||||
|
||||
|
||||
332
assets/images/palina.svg
Normal file
|
After Width: | Height: | Size: 81 KiB |
@@ -1,93 +1,45 @@
|
||||
// Main JavaScript file for Palina theme
|
||||
// Using HTMX and Alpine.js for enhanced functionality
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
console.log('Palina theme loaded!');
|
||||
|
||||
const htmlElement = document.documentElement;
|
||||
// Remove 'hidden' class from html to prevent FOUC
|
||||
htmlElement.classList.remove('hidden');
|
||||
let lastUrl = window.location.pathname;
|
||||
|
||||
// Staggered fade-in animation for post grid
|
||||
const gridItems = document.querySelectorAll('.post-grid-item');
|
||||
const animateGridItems = (container = document) => {
|
||||
const gridItems = container.querySelectorAll('.post-grid-item:not(.animated)');
|
||||
gridItems.forEach((item, index) => {
|
||||
item.style.animationDelay = `${index * 100}ms`;
|
||||
item.classList.add('animate-fadeInUp');
|
||||
item.classList.add('animated');
|
||||
});
|
||||
};
|
||||
|
||||
// Lightbox for post images
|
||||
const lightbox = document.getElementById('lightbox');
|
||||
if (lightbox) {
|
||||
const lightboxImage = document.getElementById('lightbox-image');
|
||||
const lightboxClose = document.getElementById('lightbox-close');
|
||||
// Initial animation
|
||||
animateGridItems();
|
||||
|
||||
const images = document.querySelectorAll('.kg-image-card img, .post-content img');
|
||||
// Re-run animation and other setup when HTMX settles new content
|
||||
// Use document instead of document.body to persist across boosted navigation
|
||||
document.addEventListener('htmx:afterSettle', (event) => {
|
||||
const currentUrl = window.location.pathname;
|
||||
|
||||
images.forEach(image => {
|
||||
image.style.cursor = 'pointer';
|
||||
image.addEventListener('click', () => {
|
||||
lightbox.classList.remove('hidden');
|
||||
lightbox.classList.add('show');
|
||||
lightboxImage.src = image.src;
|
||||
});
|
||||
});
|
||||
|
||||
lightboxClose.addEventListener('click', () => {
|
||||
lightbox.classList.add('hidden');
|
||||
lightbox.classList.remove('show');
|
||||
lightboxImage.src = '';
|
||||
});
|
||||
|
||||
lightbox.addEventListener('click', (e) => {
|
||||
if (e.target.id !== 'lightbox-image') {
|
||||
lightbox.classList.add('hidden');
|
||||
lightbox.classList.remove('show');
|
||||
lightboxImage.src = '';
|
||||
// Global page fade-in animation - only on full boosted navigations if the URL changed
|
||||
if (event.detail.boosted && currentUrl !== lastUrl) {
|
||||
const mainContent = document.getElementById('main-content');
|
||||
if (mainContent) {
|
||||
mainContent.classList.remove('animate-fadeInUp');
|
||||
void mainContent.offsetWidth; // Force reflow to restart animation
|
||||
mainContent.classList.add('animate-fadeInUp');
|
||||
}
|
||||
});
|
||||
animateGridItems();
|
||||
lastUrl = currentUrl;
|
||||
}
|
||||
|
||||
// Theme Switcher
|
||||
const themeToggle = document.getElementById('theme-toggle');
|
||||
// const htmlElement = document.documentElement; // Already defined above
|
||||
|
||||
const currentTheme = localStorage.getItem('theme');
|
||||
if (currentTheme) {
|
||||
htmlElement.setAttribute('data-theme', currentTheme);
|
||||
} else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) {
|
||||
// Default to light theme if system preference is light
|
||||
htmlElement.setAttribute('data-theme', 'light');
|
||||
// If the settled element is the posts-container or contains grid items
|
||||
const target = event.detail.target;
|
||||
if (target.id === 'posts-container' || target.querySelector('.post-grid-item')) {
|
||||
animateGridItems(target);
|
||||
}
|
||||
|
||||
if (themeToggle) {
|
||||
themeToggle.addEventListener('click', () => {
|
||||
let newTheme = htmlElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
|
||||
htmlElement.setAttribute('data-theme', newTheme);
|
||||
localStorage.setItem('theme', newTheme);
|
||||
});
|
||||
}
|
||||
|
||||
// Mobile Menu
|
||||
const mobileMenuToggle = document.getElementById('mobile-menu-toggle');
|
||||
const mobileMenuClose = document.getElementById('mobile-menu-close');
|
||||
const mobileMenu = document.getElementById('mobile-menu');
|
||||
|
||||
if (mobileMenuToggle && mobileMenu && mobileMenuClose) {
|
||||
mobileMenuToggle.addEventListener('click', () => {
|
||||
mobileMenu.classList.remove('-translate-x-full');
|
||||
mobileMenu.classList.add('translate-x-0');
|
||||
});
|
||||
|
||||
mobileMenuClose.addEventListener('click', () => {
|
||||
mobileMenu.classList.remove('translate-x-0');
|
||||
mobileMenu.classList.add('-translate-x-full');
|
||||
});
|
||||
|
||||
// Close menu if a link is clicked
|
||||
const mobileNavLinks = mobileMenu.querySelectorAll('a');
|
||||
mobileNavLinks.forEach(link => {
|
||||
link.addEventListener('click', () => {
|
||||
mobileMenu.classList.remove('translate-x-0');
|
||||
mobileMenu.classList.add('-translate-x-full');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
69
author.hbs
Normal file
@@ -0,0 +1,69 @@
|
||||
{{!< default}}
|
||||
|
||||
{{#author}}
|
||||
<header class="author-header relative w-full mb-12">
|
||||
{{#if cover_image}}
|
||||
<div class="w-full h-64 md:h-96 relative overflow-hidden">
|
||||
<img class="w-full h-full object-cover opacity-40 grayscale hover:grayscale-0 transition-all duration-700" src="{{img_url cover_image size="xl"}}" alt="{{name}}'s cover image">
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-transparent to-[var(--bg-primary)]"></div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="container mx-auto px-4 relative {{#if cover_image}}-mt-20 md:-mt-32{{else}}pt-12{{/if}} flex flex-col items-center">
|
||||
{{#if profile_image}}
|
||||
<div class="relative inline-block p-1 rounded-full bg-gradient-to-tr from-[var(--brand-primary)] to-[var(--bg-secondary)] mb-6 shadow-2xl">
|
||||
<img class="w-32 h-32 md:w-36 md:h-36 rounded-full object-cover border-4 border-[var(--bg-primary)] shadow-inner" src="{{img_url profile_image size="s"}}" alt="{{name}}'s avatar">
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<h1 class="text-5xl md:text-7xl font-bold tracking-tighter text-[var(--text-primary)] mb-4">{{name}}</h1>
|
||||
|
||||
<div class="flex flex-wrap items-center justify-center gap-4 mb-6 text-[var(--text-secondary)] font-medium">
|
||||
{{#if location}}
|
||||
<span class="flex items-center">
|
||||
{{> "icons/location" class="w-4 h-4 mr-1 text-[var(--brand-primary)]"}}
|
||||
{{location}}
|
||||
</span>
|
||||
{{/if}}
|
||||
{{#if website}}
|
||||
<a href="{{website}}" target="_blank" rel="noopener" class="fancy-link flex items-center">
|
||||
{{> "icons/link" class="w-4 h-4 mr-1"}}
|
||||
Website
|
||||
</a>
|
||||
{{/if}}
|
||||
{{#if twitter}}
|
||||
<a href="{{twitter_url}}" target="_blank" rel="noopener" class="fancy-link flex items-center">
|
||||
{{> "icons/twitter" class="w-4 h-4 mr-1"}}
|
||||
Twitter
|
||||
</a>
|
||||
{{/if}}
|
||||
{{#if facebook}}
|
||||
<a href="{{facebook_url}}" target="_blank" rel="noopener" class="fancy-link flex items-center">
|
||||
{{> "icons/facebook" class="w-4 h-4 mr-1"}}
|
||||
Facebook
|
||||
</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if bio}}
|
||||
<p class="text-xl md:text-2xl text-[var(--text-secondary)] text-center max-w-2xl font-serif italic italic leading-relaxed opacity-90 mb-8">
|
||||
{{bio}}
|
||||
</p>
|
||||
{{/if}}
|
||||
|
||||
<div class="flex items-center text-sm font-medium uppercase tracking-[0.2em] text-[var(--text-tertiary)]">
|
||||
<span class="inline-block w-8 h-px bg-[var(--bg-tertiary)] mr-4"></span>
|
||||
{{plural ../pagination.total empty='No posts' singular='% post' plural='% posts'}}
|
||||
<span class="inline-block w-8 h-px bg-[var(--bg-tertiary)] ml-4"></span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
{{/author}}
|
||||
|
||||
<div class="container mx-auto px-4 pb-20">
|
||||
{{#if posts}}
|
||||
{{> "post-feed"}}
|
||||
{{else}}
|
||||
<p class="text-center text-[var(--text-secondary)] text-2xl py-20">No posts found.</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
69
default.hbs
@@ -1,33 +1,72 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{@site.lang}}" data-theme="dark" class="hidden">
|
||||
<html lang="{{@site.locale}}"
|
||||
x-data="{
|
||||
theme: localStorage.getItem('theme') || (window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark'),
|
||||
mobileMenuOpen: false,
|
||||
currentPath: window.location.pathname,
|
||||
showScrollTop: false,
|
||||
isSticky: false,
|
||||
init() {
|
||||
$watch('theme', val => {
|
||||
localStorage.setItem('theme', val);
|
||||
document.documentElement.setAttribute('data-theme', val);
|
||||
});
|
||||
document.documentElement.setAttribute('data-theme', this.theme);
|
||||
document.documentElement.classList.remove('hidden');
|
||||
|
||||
// Handle scroll for sticky header and scroll-to-top button
|
||||
window.addEventListener('scroll', () => {
|
||||
this.showScrollTop = window.scrollY > 400;
|
||||
this.isSticky = window.scrollY > 50;
|
||||
});
|
||||
|
||||
// Update currentPath on navigation to keep menu highlights in sync
|
||||
document.addEventListener('htmx:afterSettle', () => {
|
||||
this.currentPath = window.location.pathname;
|
||||
this.mobileMenuOpen = false;
|
||||
});
|
||||
}
|
||||
}"
|
||||
:data-theme="theme"
|
||||
class="hidden">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{meta_title}}</title>
|
||||
<title>{{#is "index"}}{{@site.title}}{{else}}{{meta_title}} — {{@site.title}}{{/is}}</title>
|
||||
<link rel="stylesheet" href="{{asset "built/screen.css"}}">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&family=Playfair+Display:wght@700&display=swap" rel="stylesheet">
|
||||
<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=Montserrat:ital,wght@0,100..900;1,100..900&family=Fraunces:ital,opsz,wght@0,9..144,100..900;1,9..144,100..900&display=swap" rel="stylesheet">
|
||||
|
||||
<script defer src="https://unpkg.com/alpinejs@3.14.8/dist/cdn.min.js"></script>
|
||||
<script src="https://unpkg.com/htmx.org@2.0.0"></script>
|
||||
|
||||
{{ghost_head}}
|
||||
</head>
|
||||
<body class="{{body_class}} font-sans antialiased">
|
||||
|
||||
<div class="min-h-screen flex flex-col">
|
||||
<body
|
||||
class="{{body_class}} font-sans antialiased min-h-screen flex flex-col"
|
||||
hx-boost="true"
|
||||
hx-target="#main-content"
|
||||
hx-select="#main-content"
|
||||
hx-swap="innerHTML show:window:top"
|
||||
>
|
||||
{{!--
|
||||
PERSISTENT SHELL:
|
||||
These elements are OUTSIDE #main-content, so they never swap.
|
||||
This keeps Alpine state (mobileMenuOpen) perfectly stable.
|
||||
--}}
|
||||
{{> mobile-menu}}
|
||||
{{> header}}
|
||||
{{> scroll-top}}
|
||||
|
||||
<main class="flex-grow">
|
||||
<main id="main-content" class="flex-grow animate-fadeInUp">
|
||||
{{{body}}}
|
||||
</main>
|
||||
|
||||
{{> footer}}
|
||||
</div>
|
||||
|
||||
{{> mobile-menu}}
|
||||
|
||||
<div id="lightbox" class="hidden fixed inset-0 bg-black bg-opacity-80 z-50 flex items-center justify-center">
|
||||
<button id="lightbox-close" class="absolute top-4 right-4 text-white text-3xl">×</button>
|
||||
<img id="lightbox-image" src="" alt="Lightbox image" class="max-w-full max-h-full">
|
||||
</div>
|
||||
|
||||
{{ghost_foot}}
|
||||
<script src="{{asset "js/ghost-config.js"}}"></script>
|
||||
<script src="{{asset "js/main.js"}}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
23
error-404.hbs
Normal file
@@ -0,0 +1,23 @@
|
||||
{{!< default}}
|
||||
|
||||
<section class="container mx-auto px-4 py-20 md:py-32 flex flex-col items-center justify-center text-center">
|
||||
<h1 class="text-9xl font-bold tracking-tighter text-[var(--brand-primary)] opacity-20 mb-4">404</h1>
|
||||
<h2 class="text-4xl md:text-6xl font-bold mb-12">Page Not Found</h2>
|
||||
|
||||
<a href="{{@site.url}}" class="btn-primary">
|
||||
<span class="mr-2">{{> "icons/arrow-left" class="w-4 h-4"}}</span> Back to Home
|
||||
</a>
|
||||
|
||||
{{#get "posts" limit="3" include="tags,authors"}}
|
||||
{{#if posts}}
|
||||
<div class="mt-24 w-full">
|
||||
<h3 class="text-3xl font-bold mb-10 text-[var(--brand-primary)]">Perhaps read something else?</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-10">
|
||||
{{#foreach posts}}
|
||||
{{> "post-card"}}
|
||||
{{/foreach}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/get}}
|
||||
</section>
|
||||
37
index.hbs
@@ -1,40 +1,13 @@
|
||||
{{!< default}}
|
||||
|
||||
<header class="container mx-auto px-4 py-8 text-center">
|
||||
<h1 class="text-5xl font-bold tracking-tight text-[var(--text-primary)]">Palina Photo Blog</h1>
|
||||
<p class="mt-2 text-xl text-[var(--text-secondary)]">{{@site.description}}</p>
|
||||
<header class="container mx-auto px-4 py-16 md:py-24 text-center">
|
||||
<h1 class="text-6xl md:text-8xl font-bold tracking-tighter text-[var(--brand-primary)] mb-4">{{@site.title}}</h1>
|
||||
<p class="mt-4 text-xl md:text-2xl text-[var(--text-secondary)] max-w-2xl mx-auto font-serif italic italic opacity-90">{{@site.description}}</p>
|
||||
</header>
|
||||
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="container mx-auto px-4 pb-20">
|
||||
{{#if posts}}
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
|
||||
{{#foreach posts}}
|
||||
<article class="post-grid-item opacity-0 relative bg-[var(--bg-secondary)] rounded-lg shadow-lg overflow-hidden group">
|
||||
<a href="{{url}}" class="block">
|
||||
{{#if feature_image}}
|
||||
<img
|
||||
class="w-full h-72 object-cover transition-transform duration-300 ease-in-out group-hover:scale-105"
|
||||
src="{{img_url feature_image size="m"}}"
|
||||
srcset="{{img_url feature_image size="s"}} 400w,
|
||||
{{img_url feature_image size="m"}} 600w,
|
||||
{{img_url feature_image size="l"}} 1000w,
|
||||
{{img_url feature_image size="xl"}} 2000w"
|
||||
sizes="(max-width: 800px) 400px, (max-width: 1200px) 600px, 1000px"
|
||||
alt="{{title}}"
|
||||
loading="lazy"
|
||||
>
|
||||
{{else}}
|
||||
<div class="w-full h-72 flex items-center justify-center bg-[var(--bg-tertiary)] text-[var(--text-tertiary)] text-2xl">No Image</div>
|
||||
{{/if}}
|
||||
<div class="absolute inset-0 bg-black bg-opacity-50 flex items-end p-4 opacity-0 group-hover:opacity-100 transition-opacity duration-300 ease-in-out">
|
||||
<h2 class="text-[var(--text-primary)] text-xl font-semibold leading-tight">{{title}}</h2>
|
||||
</div>
|
||||
</a>
|
||||
</article>
|
||||
{{/foreach}}
|
||||
</div>
|
||||
|
||||
{{pagination}}
|
||||
{{> "post-feed"}}
|
||||
{{else}}
|
||||
<p class="text-center text-[var(--text-secondary)] text-2xl py-20">No posts found.</p>
|
||||
{{/if}}
|
||||
|
||||
@@ -7,20 +7,21 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
"name": "Gemini"
|
||||
"name": "Sebastian Krüger",
|
||||
"email": "valknar@pivoine.art"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "postcss ./assets/css/tailwind.css -o ./assets/built/screen.css --watch",
|
||||
"build": "NODE_ENV=production postcss ./assets/css/tailwind.css -o ./assets/built/screen.css"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/nesting": "0.0.0-insiders.565cd3e",
|
||||
"@tailwindcss/postcss": "^4.0.0-alpha.13",
|
||||
"@tailwindcss/postcss": "^4.2.0",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"cssnano": "^6.0.5",
|
||||
"postcss": "^8.4.35",
|
||||
"postcss-cli": "^11.0.0",
|
||||
"tailwindcss": "^4.0.0-alpha.13"
|
||||
"tailwindcss": "^4.2.0"
|
||||
},
|
||||
"config": {
|
||||
"posts_per_page": 12
|
||||
|
||||
17
page.hbs
Normal file
@@ -0,0 +1,17 @@
|
||||
{{!< default}}
|
||||
|
||||
{{#post}}
|
||||
<article class="container mx-auto px-4 py-12">
|
||||
<header class="text-center mb-8 max-w-3xl mx-auto">
|
||||
<h1 class="text-6xl font-bold tracking-tight text-[var(--text-primary)] mb-4">{{title}}</h1>
|
||||
</header>
|
||||
|
||||
{{#if feature_image}}
|
||||
{{> "feature-image"}}
|
||||
{{/if}}
|
||||
|
||||
<section class="post-content max-w-3xl mx-auto text-[var(--text-primary)] leading-relaxed text-lg prose">
|
||||
{{content}}
|
||||
</section>
|
||||
</article>
|
||||
{{/post}}
|
||||
10
partials/feature-image.hbs
Normal file
@@ -0,0 +1,10 @@
|
||||
<figure class="mb-12 rounded-lg overflow-hidden shadow-xl">
|
||||
<img
|
||||
class="w-full h-auto object-cover"
|
||||
src="{{img_url feature_image size="xl"}}"
|
||||
srcset="{{img_url feature_image size="l"}} 1000w,
|
||||
{{img_url feature_image size="xl"}} 2000w"
|
||||
sizes="(max-width: 1000px) 1000px, 2000px"
|
||||
alt="{{title fallback="No Title"}}"
|
||||
>
|
||||
</figure>
|
||||
@@ -1,24 +1,32 @@
|
||||
<footer class="text-[var(--text-secondary)] bg-[var(--bg-primary)] body-font">
|
||||
<div class="container px-5 py-8 mx-auto flex items-center sm:flex-row flex-col">
|
||||
<a href="{{@site.url}}" class="flex title-font font-medium items-center md:justify-start justify-center text-[var(--text-primary)]">
|
||||
<span class="ml-3 text-xl">{{@site.title}}</span>
|
||||
{{#if @site.logo}}
|
||||
<img src="{{@site.logo}}" alt="{{@site.title}}" class="h-8 w-auto site-logo">
|
||||
{{else}}
|
||||
{{> "icons/logo" class="h-8 w-auto site-logo"}}
|
||||
{{/if}}
|
||||
</a>
|
||||
<p class="text-sm text-[var(--text-secondary)] sm:ml-4 sm:pl-4 sm:border-l-2 sm:border-[var(--bg-secondary)] sm:py-2 sm:mt-0 mt-4">
|
||||
© {{date format="YYYY"}} {{@site.title}} — Powered by Ghost
|
||||
© {{date format="YYYY"}} {{@site.title}} —
|
||||
{{#get "authors" limit="1" order="count.posts desc"}}
|
||||
{{#foreach authors}}
|
||||
Created by <a href="{{url}}" class="fancy-link">{{name}}</a>
|
||||
{{/foreach}}
|
||||
{{/get}}
|
||||
</p>
|
||||
<span class="inline-flex sm:ml-auto sm:mt-0 mt-4 justify-center sm:justify-start">
|
||||
<nav class="sm:ml-auto sm:mt-0 mt-4">
|
||||
{{navigation type="secondary"}}
|
||||
</nav>
|
||||
<span class="inline-flex sm:ml-6 sm:mt-0 mt-4 justify-center sm:justify-start">
|
||||
{{#if @site.facebook}}
|
||||
<a href="{{@site.facebook_url}}" class="text-[var(--text-secondary)] hover:text-[var(--text-primary)] transition duration-200">
|
||||
<svg fill="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-5 h-5" viewBox="0 0 24 24">
|
||||
<path d="M18 2h-3a5 5 0 00-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 011-1h3z"></path>
|
||||
</svg>
|
||||
<a href="{{@site.facebook_url}}" class="text-[var(--text-secondary)] hover:text-[var(--primary-hover)] transition duration-200">
|
||||
{{> "icons/facebook" class="w-5 h-5"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
{{#if @site.twitter}}
|
||||
<a href="{{@site.twitter_url}}" class="ml-3 text-[var(--text-secondary)] hover:text-[var(--text-primary)] transition duration-200">
|
||||
<svg fill="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-5 h-5" viewBox="0 0 24 24">
|
||||
<path d="M23 3a10.9 10.9 0 01-3.14 1.53 4.48 4.48 0 00-7.86 3v1A10.66 10.66 0 013 4s-4 9 5 13a11.64 11.64 0 01-7 2c9 5 20 0 20-11.5a4.5 4.5 0 00-.08-.83A7.72 7.72 0 0023 3z"></path>
|
||||
</svg>
|
||||
<a href="{{@site.twitter_url}}" class="ml-3 text-[var(--text-secondary)] hover:text-[var(--primary-hover)] transition duration-200">
|
||||
{{> "icons/twitter" class="w-5 h-5"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
</span>
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
<header class="text-[var(--text-primary)] body-font shadow-lg bg-[var(--bg-primary)]">
|
||||
<div class="container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center justify-between">
|
||||
<a href="{{@site.url}}" class="flex title-font font-medium items-center text-[var(--text-primary)] mb-4 md:mb-0">
|
||||
<span class="ml-3 text-xl">{{@site.title}}</span>
|
||||
<header
|
||||
class="sticky top-0 z-40 w-full transition-all duration-500 ease-in-out border-b py-5"
|
||||
:class="isSticky ? 'bg-[var(--bg-primary)]/80 backdrop-blur-md shadow-lg border-[var(--bg-tertiary)]' : 'bg-[var(--bg-primary)] border-[var(--bg-tertiary)]/30 shadow-none'">
|
||||
<div class="container mx-auto flex items-center justify-between px-5">
|
||||
<a href="{{@site.url}}" class="flex title-font font-medium items-center text-[var(--text-primary)]" @click.stop>
|
||||
{{#if @site.logo}}
|
||||
<img src="{{@site.logo}}" alt="{{@site.title}}" class="h-10 w-auto site-logo">
|
||||
{{else}}
|
||||
{{> "icons/logo" class="h-10 w-auto site-logo"}}
|
||||
{{/if}}
|
||||
</a>
|
||||
|
||||
<div class="flex items-center">
|
||||
<nav class="hidden md:flex flex-wrap items-center text-base justify-center">
|
||||
<div class="flex items-center space-x-4">
|
||||
<nav class="hidden md:flex items-center space-x-4">
|
||||
{{navigation type="primary"}}
|
||||
<button id="theme-toggle" class="ml-4 p-2 rounded-full bg-[var(--bg-secondary)] text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)] transition-colors duration-200">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-5 h-5">
|
||||
<path fill-rule="evenodd" d="M9.528 1.718a.75.75 0 01.178 1.043l-4.243 4.243a.75.75 0 01-1.061 0L.952 2.761a.75.75 0 011.06-1.06l3.52 3.52 3.712-3.712a.75.75 0 011.042-.178zM16.292 7.625a.75.75 0 01.132 1.056l-3.903 4.171c.466 1.102.615 2.373.13 3.673-.393 1.077-.665 2.164-.707 2.296-.135.347-.216.593-.216.593H12.75a.75.75 0 010-1.5h.084c.007-.022.036-.094.09-.253.307-.872.502-1.78.544-2.701.328-1.55-.145-2.915-.756-3.83A6.064 6.064 0 0015.6 9a.75.75 0 01.692-.375zM12.75 22.5c-2.935 0-5.696-1.07-7.795-2.997a.75.75 0 011.061-1.061 9 9 0 0013.868 0 .75.75 0 011.06-1.061C18.446 21.43 15.685 22.5 12.75 22.5z" clip-rule="evenodd" />
|
||||
<path fill-rule="evenodd" d="M15.6 13.5a3.6 3.6 0 11-7.2 0 3.6 3.6 0 017.2 0z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<button id="mobile-menu-toggle" class="md:hidden p-2 rounded-full bg-[var(--bg-secondary)] text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)] transition-colors duration-200">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
||||
</svg>
|
||||
{{!-- Theme Toggle - Visible on both mobile and desktop --}}
|
||||
<button @click="theme = (theme === 'dark' ? 'light' : 'dark')" class="p-2 rounded-full text-[var(--text-secondary)] hover:text-[var(--brand-primary)] transition-colors duration-200">
|
||||
<div x-show="theme === 'dark'">
|
||||
{{> "icons/sun" class="w-6 h-6"}}
|
||||
</div>
|
||||
<div x-show="theme === 'light'" x-cloak>
|
||||
{{> "icons/moon" class="w-6 h-6"}}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button @click.stop="mobileMenuOpen = true" class="md:hidden p-2 rounded-full text-[var(--text-secondary)] hover:text-[var(--brand-primary)] transition-colors duration-200">
|
||||
{{> "icons/menu" class="w-6 h-6"}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
3
partials/icons/arrow-left.hbs
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg class="{{class}}" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 234 B |
3
partials/icons/arrow-right.hbs
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg class="{{class}}" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 231 B |
3
partials/icons/arrow-up.hbs
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor" class="{{class}}">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 10.5 12 3m0 0 7.5 7.5M12 3v18" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 236 B |
3
partials/icons/close.hbs
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="{{class}}">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 222 B |
3
partials/icons/facebook.hbs
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg fill="currentColor" class="{{class}}" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18 2h-3a5 5 0 00-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 011-1h3z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 191 B |
3
partials/icons/link.hbs
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg class="{{class}}" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 331 B |
3
partials/icons/location.hbs
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg class="{{class}}" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 391 B |
330
partials/icons/logo.hbs
Normal file
|
After Width: | Height: | Size: 81 KiB |
3
partials/icons/menu.hbs
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="{{class}}">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 246 B |
3
partials/icons/moon.hbs
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="{{class}}">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 382 B |
3
partials/icons/sun.hbs
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="{{class}}">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 3v2.25m6.364.386-1.591 1.591M21 12h-2.25m-.386 6.364-1.591-1.591M12 18.75V21m-4.773-4.227-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 395 B |
3
partials/icons/twitter.hbs
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg fill="currentColor" class="{{class}}" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18.901 1.153h3.68l-8.04 4.596 9.457 12.517h-7.405l-5.799-7.67-6.635 7.67h-3.68l8.598-9.825L0 1.153h7.594l5.243 6.932L18.901 1.153zM17.61 16.06h2.039L6.486 3.24H4.298L17.61 16.06z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 308 B |
@@ -1,12 +1,46 @@
|
||||
<div id="mobile-menu" class="fixed inset-0 z-40 bg-[var(--bg-primary)] transform -translate-x-full transition-transform duration-300 ease-in-out md:hidden">
|
||||
<div class="flex justify-end p-5">
|
||||
<button id="mobile-menu-close" class="p-2 rounded-full bg-[var(--bg-secondary)] text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)] transition-colors duration-200">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
<div id="mobile-menu"
|
||||
x-show="mobileMenuOpen"
|
||||
x-transition:enter="transition ease-out duration-300"
|
||||
x-transition:enter-start="-translate-x-full"
|
||||
x-transition:enter-end="translate-x-0"
|
||||
x-transition:leave="transition ease-in duration-300"
|
||||
x-transition:leave-start="translate-x-0"
|
||||
x-transition:leave-end="-translate-x-full"
|
||||
class="fixed inset-0 z-50 bg-[var(--bg-primary)] flex flex-col md:hidden"
|
||||
@click.away="mobileMenuOpen = false"
|
||||
x-cloak>
|
||||
|
||||
<!-- Mobile Menu Header -->
|
||||
<div class="flex justify-between items-center p-5 flex-none">
|
||||
<a href="{{@site.url}}" class="flex items-center text-[var(--text-primary)]" @click.stop="mobileMenuOpen = false">
|
||||
{{#if @site.logo}}
|
||||
<img src="{{@site.logo}}" alt="{{@site.title}}" class="h-10 w-auto site-logo">
|
||||
{{else}}
|
||||
{{> "icons/logo" class="h-10 w-auto site-logo"}}
|
||||
{{/if}}
|
||||
</a>
|
||||
|
||||
<div class="flex items-center space-x-2">
|
||||
{{!-- Theme Toggle in Mobile Menu --}}
|
||||
<button @click="theme = (theme === 'dark' ? 'light' : 'dark')" class="p-2 rounded-full text-[var(--text-secondary)] hover:text-[var(--brand-primary)] transition-colors duration-200">
|
||||
<div x-show="theme === 'dark'">
|
||||
{{> "icons/sun" class="w-6 h-6"}}
|
||||
</div>
|
||||
<div x-show="theme === 'light'" x-cloak>
|
||||
{{> "icons/moon" class="w-6 h-6"}}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button @click.stop="mobileMenuOpen = false" class="p-2 rounded-full text-[var(--text-secondary)] hover:text-[var(--brand-primary)] transition-colors duration-200">
|
||||
{{> "icons/close" class="w-6 h-6"}}
|
||||
</button>
|
||||
</div>
|
||||
<nav class="flex flex-col items-center justify-center h-full space-y-8 text-2xl">
|
||||
</div>
|
||||
|
||||
<!-- Mobile Menu Navigation -->
|
||||
<nav class="flex-grow flex flex-col items-center justify-center p-10 overflow-y-auto" @click="mobileMenuOpen = false">
|
||||
<div class="w-full text-center">
|
||||
{{navigation type="primary"}}
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
13
partials/navigation.hbs
Normal file
@@ -0,0 +1,13 @@
|
||||
<ul class="nav">
|
||||
{{#foreach navigation}}
|
||||
{{!--
|
||||
We use Alpine to dynamically apply the nav-current class based on currentPath.
|
||||
This works even when the navigation itself is not swapped by HTMX.
|
||||
--}}
|
||||
<li class="nav-{{slug}}" :class="currentPath === '{{url}}' ? 'nav-current' : ''">
|
||||
<a href="{{url absolute="true"}}" class="nav-link">
|
||||
{{label}}
|
||||
</a>
|
||||
</li>
|
||||
{{/foreach}}
|
||||
</ul>
|
||||
39
partials/post-card.hbs
Normal file
@@ -0,0 +1,39 @@
|
||||
<article class="post-grid-item h-80">
|
||||
<a href="{{url}}" class="group block h-full relative bg-[var(--bg-secondary)] rounded-xl shadow-lg overflow-hidden transition-all duration-500 hover:shadow-2xl hover:-translate-y-2">
|
||||
{{#if feature_image}}
|
||||
<img
|
||||
class="absolute inset-0 w-full h-full object-cover transition-transform duration-700 ease-out group-hover:scale-110"
|
||||
src="{{img_url feature_image size="m"}}"
|
||||
srcset="{{img_url feature_image size="s"}} 400w,
|
||||
{{img_url feature_image size="m"}} 600w,
|
||||
{{img_url feature_image size="l"}} 1000w,
|
||||
{{img_url feature_image size="xl"}} 2000w"
|
||||
sizes="(max-width: 800px) 400px, (max-width: 1200px) 600px, 1000px"
|
||||
alt="{{title}}"
|
||||
loading="lazy"
|
||||
>
|
||||
{{else}}
|
||||
<div class="absolute inset-0 w-full h-full flex items-center justify-center bg-[var(--bg-tertiary)] text-[var(--text-tertiary)] text-2xl transition-colors duration-500 group-hover:bg-[var(--bg-secondary)]">No Image</div>
|
||||
{{/if}}
|
||||
|
||||
{{!-- Gradient Overlay --}}
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-black/90 via-black/40 to-transparent opacity-70 group-hover:opacity-80 transition-opacity duration-500"></div>
|
||||
|
||||
{{!-- Content Overlay --}}
|
||||
<div class="absolute inset-0 p-8 flex flex-col justify-end">
|
||||
<div class="overflow-hidden">
|
||||
{{#if primary_tag}}
|
||||
<span class="text-[var(--brand-primary)] text-xs uppercase tracking-[0.2em] font-bold mb-3 block transform transition-transform duration-500 translate-y-4 group-hover:translate-y-0">
|
||||
{{primary_tag.name}}
|
||||
</span>
|
||||
{{/if}}
|
||||
<h2 class="text-white text-xl md:text-2xl font-bold leading-tight line-clamp-2 transform transition-transform duration-500 delay-75 translate-y-2 group-hover:translate-y-0">
|
||||
{{title}}
|
||||
</h2>
|
||||
|
||||
{{!-- Decorative line that expands on hover --}}
|
||||
<div class="w-0 h-1 bg-[var(--brand-primary)] mt-4 transition-all duration-500 ease-out group-hover:w-16"></div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</article>
|
||||
22
partials/post-feed.hbs
Normal file
@@ -0,0 +1,22 @@
|
||||
<div id="posts-container" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-10">
|
||||
{{#foreach posts}}
|
||||
{{> "post-card"}}
|
||||
{{/foreach}}
|
||||
|
||||
{{#if pagination.next}}
|
||||
<div id="pagination-trigger"
|
||||
hx-get="{{page_url pagination.next}}"
|
||||
hx-trigger="revealed"
|
||||
hx-select="#posts-container > *"
|
||||
hx-target="this"
|
||||
hx-swap="outerHTML"
|
||||
hx-indicator="#loading-spinner"
|
||||
class="col-span-full h-1">
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div id="loading-spinner" class="htmx-indicator text-center py-12">
|
||||
<div class="inline-block animate-spin rounded-full h-10 w-10 border-4 border-[var(--brand-primary)] border-t-transparent"></div>
|
||||
<p class="text-[var(--text-secondary)] mt-4 font-medium tracking-wide">Loading more posts...</p>
|
||||
</div>
|
||||
25
partials/post-navigation.hbs
Normal file
@@ -0,0 +1,25 @@
|
||||
<nav class="hidden has-[a]:grid mt-16 max-w-3xl mx-auto grid-cols-1 md:grid-cols-2 gap-4 pt-12">
|
||||
{{#prev_post}}
|
||||
<div class="prev-post-nav">
|
||||
<a href="{{url}}" class="group block p-6 bg-[var(--bg-secondary)] rounded-lg hover:bg-[var(--bg-tertiary)] transition-all duration-300">
|
||||
<span class="text-xs uppercase tracking-widest text-[var(--text-tertiary)] mb-2 block flex items-center">
|
||||
<span class="mr-2">{{> "icons/arrow-left" class="w-4 h-4"}}</span>
|
||||
Previous Post
|
||||
</span>
|
||||
<h4 class="text-xl font-bold group-hover:text-[var(--brand-primary)] transition-colors duration-300">{{title}}</h4>
|
||||
</a>
|
||||
</div>
|
||||
{{/prev_post}}
|
||||
|
||||
{{#next_post}}
|
||||
<div class="next-post-nav text-right md:col-start-2">
|
||||
<a href="{{url}}" class="group block p-6 bg-[var(--bg-secondary)] rounded-lg hover:bg-[var(--bg-tertiary)] transition-all duration-300">
|
||||
<span class="text-xs uppercase tracking-widest text-[var(--text-tertiary)] mb-2 block flex items-center justify-end">
|
||||
Next Post
|
||||
<span class="ml-2">{{> "icons/arrow-right" class="w-4 h-4"}}</span>
|
||||
</span>
|
||||
<h4 class="text-xl font-bold group-hover:text-[var(--brand-primary)] transition-colors duration-300">{{title}}</h4>
|
||||
</a>
|
||||
</div>
|
||||
{{/next_post}}
|
||||
</nav>
|
||||
12
partials/related-posts.hbs
Normal file
@@ -0,0 +1,12 @@
|
||||
{{#get "posts" filter="tags:{{primary_tag.slug}}+id:-{{id}}" limit="3" include="tags" as |related_posts|}}
|
||||
{{#if related_posts}}
|
||||
<section class="mt-16 pt-12 border-t border-[var(--bg-tertiary)]">
|
||||
<h3 class="text-3xl font-bold mb-8 text-center">You might like</h3>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{{#foreach related_posts}}
|
||||
{{> "post-card"}}
|
||||
{{/foreach}}
|
||||
</div>
|
||||
</section>
|
||||
{{/if}}
|
||||
{{/get}}
|
||||
14
partials/scroll-top.hbs
Normal file
@@ -0,0 +1,14 @@
|
||||
<button
|
||||
x-show="showScrollTop"
|
||||
x-transition:enter="transition ease-out duration-300"
|
||||
x-transition:enter-start="opacity-0 translate-y-10"
|
||||
x-transition:enter-end="opacity-100 translate-y-0"
|
||||
x-transition:leave="transition ease-in duration-300"
|
||||
x-transition:leave-start="opacity-100 translate-y-0"
|
||||
x-transition:leave-end="opacity-0 translate-y-10"
|
||||
@click="window.scrollTo({ top: 0, behavior: 'smooth' })"
|
||||
class="fixed bottom-8 right-8 z-40 p-3 rounded-lg shadow-xl bg-[var(--brand-primary)] text-[var(--bg-primary)] hover:bg-[var(--brand-secondary)] hover:scale-110 active:scale-95 transition-all duration-300 group"
|
||||
aria-label="Scroll to top"
|
||||
x-cloak>
|
||||
{{> "icons/arrow-up" class="w-6 h-6 transform group-hover:-translate-y-1 transition-transform duration-300"}}
|
||||
</button>
|
||||
302
pnpm-lock.yaml
generated
@@ -8,12 +8,12 @@ importers:
|
||||
|
||||
.:
|
||||
devDependencies:
|
||||
'@tailwindcss/nesting':
|
||||
specifier: 0.0.0-insiders.565cd3e
|
||||
version: 0.0.0-insiders.565cd3e(postcss@8.5.6)
|
||||
'@tailwindcss/postcss':
|
||||
specifier: ^4.0.0-alpha.13
|
||||
version: 4.1.18
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0
|
||||
'@tailwindcss/typography':
|
||||
specifier: ^0.5.19
|
||||
version: 0.5.19(tailwindcss@4.2.0)
|
||||
autoprefixer:
|
||||
specifier: ^10.4.17
|
||||
version: 10.4.24(postcss@8.5.6)
|
||||
@@ -27,8 +27,8 @@ importers:
|
||||
specifier: ^11.0.0
|
||||
version: 11.0.1(jiti@2.6.1)(postcss@8.5.6)
|
||||
tailwindcss:
|
||||
specifier: ^4.0.0-alpha.13
|
||||
version: 4.1.18
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0
|
||||
|
||||
packages:
|
||||
|
||||
@@ -52,70 +52,65 @@ packages:
|
||||
'@jridgewell/trace-mapping@0.3.31':
|
||||
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
||||
|
||||
'@tailwindcss/nesting@0.0.0-insiders.565cd3e':
|
||||
resolution: {integrity: sha512-WhHoFBx19TnH/c+xLwT/sxei6+4RpdfiyG3MYXfmLaMsADmVqBkF7B6lDalgZD9YdM459MF7DtxVbWkOrV7IaQ==}
|
||||
peerDependencies:
|
||||
postcss: ^8.2.15
|
||||
'@tailwindcss/node@4.2.0':
|
||||
resolution: {integrity: sha512-Yv+fn/o2OmL5fh/Ir62VXItdShnUxfpkMA4Y7jdeC8O81WPB8Kf6TT6GSHvnqgSwDzlB5iT7kDpeXxLsUS0T6Q==}
|
||||
|
||||
'@tailwindcss/node@4.1.18':
|
||||
resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==}
|
||||
|
||||
'@tailwindcss/oxide-android-arm64@4.1.18':
|
||||
resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==}
|
||||
engines: {node: '>= 10'}
|
||||
'@tailwindcss/oxide-android-arm64@4.2.0':
|
||||
resolution: {integrity: sha512-F0QkHAVaW/JNBWl4CEKWdZ9PMb0khw5DCELAOnu+RtjAfx5Zgw+gqCHFvqg3AirU1IAd181fwOtJQ5I8Yx5wtw==}
|
||||
engines: {node: '>= 20'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@tailwindcss/oxide-darwin-arm64@4.1.18':
|
||||
resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==}
|
||||
engines: {node: '>= 10'}
|
||||
'@tailwindcss/oxide-darwin-arm64@4.2.0':
|
||||
resolution: {integrity: sha512-I0QylkXsBsJMZ4nkUNSR04p6+UptjcwhcVo3Zu828ikiEqHjVmQL9RuQ6uT/cVIiKpvtVA25msu/eRV97JeNSA==}
|
||||
engines: {node: '>= 20'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@tailwindcss/oxide-darwin-x64@4.1.18':
|
||||
resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==}
|
||||
engines: {node: '>= 10'}
|
||||
'@tailwindcss/oxide-darwin-x64@4.2.0':
|
||||
resolution: {integrity: sha512-6TmQIn4p09PBrmnkvbYQ0wbZhLtbaksCDx7Y7R3FYYx0yxNA7xg5KP7dowmQ3d2JVdabIHvs3Hx4K3d5uCf8xg==}
|
||||
engines: {node: '>= 20'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@tailwindcss/oxide-freebsd-x64@4.1.18':
|
||||
resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==}
|
||||
engines: {node: '>= 10'}
|
||||
'@tailwindcss/oxide-freebsd-x64@4.2.0':
|
||||
resolution: {integrity: sha512-qBudxDvAa2QwGlq9y7VIzhTvp2mLJ6nD/G8/tI70DCDoneaUeLWBJaPcbfzqRIWraj+o969aDQKvKW9dvkUizw==}
|
||||
engines: {node: '>= 20'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18':
|
||||
resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==}
|
||||
engines: {node: '>= 10'}
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf@4.2.0':
|
||||
resolution: {integrity: sha512-7XKkitpy5NIjFZNUQPeUyNJNJn1CJeV7rmMR+exHfTuOsg8rxIO9eNV5TSEnqRcaOK77zQpsyUkBWmPy8FgdSg==}
|
||||
engines: {node: '>= 20'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-gnu@4.1.18':
|
||||
resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==}
|
||||
engines: {node: '>= 10'}
|
||||
'@tailwindcss/oxide-linux-arm64-gnu@4.2.0':
|
||||
resolution: {integrity: sha512-Mff5a5Q3WoQR01pGU1gr29hHM1N93xYrKkGXfPw/aRtK4bOc331Ho4Tgfsm5WDGvpevqMpdlkCojT3qlCQbCpA==}
|
||||
engines: {node: '>= 20'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.1.18':
|
||||
resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==}
|
||||
engines: {node: '>= 10'}
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.2.0':
|
||||
resolution: {integrity: sha512-XKcSStleEVnbH6W/9DHzZv1YhjE4eSS6zOu2eRtYAIh7aV4o3vIBs+t/B15xlqoxt6ef/0uiqJVB6hkHjWD/0A==}
|
||||
engines: {node: '>= 20'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.1.18':
|
||||
resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==}
|
||||
engines: {node: '>= 10'}
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.2.0':
|
||||
resolution: {integrity: sha512-/hlXCBqn9K6fi7eAM0RsobHwJYa5V/xzWspVTzxnX+Ft9v6n+30Pz8+RxCn7sQL/vRHHLS30iQPrHQunu6/vJA==}
|
||||
engines: {node: '>= 20'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.1.18':
|
||||
resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==}
|
||||
engines: {node: '>= 10'}
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.2.0':
|
||||
resolution: {integrity: sha512-lKUaygq4G7sWkhQbfdRRBkaq4LY39IriqBQ+Gk6l5nKq6Ay2M2ZZb1tlIyRNgZKS8cbErTwuYSor0IIULC0SHw==}
|
||||
engines: {node: '>= 20'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-wasm32-wasi@4.1.18':
|
||||
resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==}
|
||||
'@tailwindcss/oxide-wasm32-wasi@4.2.0':
|
||||
resolution: {integrity: sha512-xuDjhAsFdUuFP5W9Ze4k/o4AskUtI8bcAGU4puTYprr89QaYFmhYOPfP+d1pH+k9ets6RoE23BXZM1X1jJqoyw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
cpu: [wasm32]
|
||||
bundledDependencies:
|
||||
@@ -126,24 +121,29 @@ packages:
|
||||
- '@emnapi/wasi-threads'
|
||||
- tslib
|
||||
|
||||
'@tailwindcss/oxide-win32-arm64-msvc@4.1.18':
|
||||
resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==}
|
||||
engines: {node: '>= 10'}
|
||||
'@tailwindcss/oxide-win32-arm64-msvc@4.2.0':
|
||||
resolution: {integrity: sha512-2UU/15y1sWDEDNJXxEIrfWKC2Yb4YgIW5Xz2fKFqGzFWfoMHWFlfa1EJlGO2Xzjkq/tvSarh9ZTjvbxqWvLLXA==}
|
||||
engines: {node: '>= 20'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@tailwindcss/oxide-win32-x64-msvc@4.1.18':
|
||||
resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==}
|
||||
engines: {node: '>= 10'}
|
||||
'@tailwindcss/oxide-win32-x64-msvc@4.2.0':
|
||||
resolution: {integrity: sha512-CrFadmFoc+z76EV6LPG1jx6XceDsaCG3lFhyLNo/bV9ByPrE+FnBPckXQVP4XRkN76h3Fjt/a+5Er/oA/nCBvQ==}
|
||||
engines: {node: '>= 20'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@tailwindcss/oxide@4.1.18':
|
||||
resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==}
|
||||
engines: {node: '>= 10'}
|
||||
'@tailwindcss/oxide@4.2.0':
|
||||
resolution: {integrity: sha512-AZqQzADaj742oqn2xjl5JbIOzZB/DGCYF/7bpvhA8KvjUj9HJkag6bBuwZvH1ps6dfgxNHyuJVlzSr2VpMgdTQ==}
|
||||
engines: {node: '>= 20'}
|
||||
|
||||
'@tailwindcss/postcss@4.1.18':
|
||||
resolution: {integrity: sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==}
|
||||
'@tailwindcss/postcss@4.2.0':
|
||||
resolution: {integrity: sha512-u6YBacGpOm/ixPfKqfgrJEjMfrYmPD7gEFRoygS/hnQaRtV0VCBdpkx5Ouw9pnaLRwwlgGCuJw8xLpaR0hOrQg==}
|
||||
|
||||
'@tailwindcss/typography@0.5.19':
|
||||
resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==}
|
||||
peerDependencies:
|
||||
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
|
||||
|
||||
'@trysound/sax@0.2.0':
|
||||
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
|
||||
@@ -366,74 +366,74 @@ packages:
|
||||
jsonfile@6.2.0:
|
||||
resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==}
|
||||
|
||||
lightningcss-android-arm64@1.30.2:
|
||||
resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==}
|
||||
lightningcss-android-arm64@1.31.1:
|
||||
resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
lightningcss-darwin-arm64@1.30.2:
|
||||
resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==}
|
||||
lightningcss-darwin-arm64@1.31.1:
|
||||
resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
lightningcss-darwin-x64@1.30.2:
|
||||
resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==}
|
||||
lightningcss-darwin-x64@1.31.1:
|
||||
resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
lightningcss-freebsd-x64@1.30.2:
|
||||
resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==}
|
||||
lightningcss-freebsd-x64@1.31.1:
|
||||
resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
lightningcss-linux-arm-gnueabihf@1.30.2:
|
||||
resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==}
|
||||
lightningcss-linux-arm-gnueabihf@1.31.1:
|
||||
resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-arm64-gnu@1.30.2:
|
||||
resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==}
|
||||
lightningcss-linux-arm64-gnu@1.31.1:
|
||||
resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.30.2:
|
||||
resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
|
||||
lightningcss-linux-arm64-musl@1.31.1:
|
||||
resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.30.2:
|
||||
resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
|
||||
lightningcss-linux-x64-gnu@1.31.1:
|
||||
resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-x64-musl@1.30.2:
|
||||
resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
|
||||
lightningcss-linux-x64-musl@1.31.1:
|
||||
resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.30.2:
|
||||
resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
|
||||
lightningcss-win32-arm64-msvc@1.31.1:
|
||||
resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
lightningcss-win32-x64-msvc@1.30.2:
|
||||
resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==}
|
||||
lightningcss-win32-x64-msvc@1.31.1:
|
||||
resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
lightningcss@1.30.2:
|
||||
resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==}
|
||||
lightningcss@1.31.1:
|
||||
resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
||||
lilconfig@3.1.3:
|
||||
@@ -585,12 +585,6 @@ packages:
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
|
||||
postcss-nested@5.0.6:
|
||||
resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==}
|
||||
engines: {node: '>=12.0'}
|
||||
peerDependencies:
|
||||
postcss: ^8.2.14
|
||||
|
||||
postcss-normalize-charset@6.0.2:
|
||||
resolution: {integrity: sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
@@ -669,6 +663,10 @@ packages:
|
||||
peerDependencies:
|
||||
postcss: ^8.1.0
|
||||
|
||||
postcss-selector-parser@6.0.10:
|
||||
resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
postcss-selector-parser@6.1.2:
|
||||
resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -734,8 +732,8 @@ packages:
|
||||
engines: {node: '>=14.0.0'}
|
||||
hasBin: true
|
||||
|
||||
tailwindcss@4.1.18:
|
||||
resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==}
|
||||
tailwindcss@4.2.0:
|
||||
resolution: {integrity: sha512-yYzTZ4++b7fNYxFfpnberEEKu43w44aqDMNM9MHMmcKuCH7lL8jJ4yJ7LGHv7rSwiqM0nkiobF9I6cLlpS2P7Q==}
|
||||
|
||||
tapable@2.3.0:
|
||||
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
|
||||
@@ -809,79 +807,79 @@ snapshots:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
|
||||
'@tailwindcss/nesting@0.0.0-insiders.565cd3e(postcss@8.5.6)':
|
||||
dependencies:
|
||||
postcss: 8.5.6
|
||||
postcss-nested: 5.0.6(postcss@8.5.6)
|
||||
|
||||
'@tailwindcss/node@4.1.18':
|
||||
'@tailwindcss/node@4.2.0':
|
||||
dependencies:
|
||||
'@jridgewell/remapping': 2.3.5
|
||||
enhanced-resolve: 5.19.0
|
||||
jiti: 2.6.1
|
||||
lightningcss: 1.30.2
|
||||
lightningcss: 1.31.1
|
||||
magic-string: 0.30.21
|
||||
source-map-js: 1.2.1
|
||||
tailwindcss: 4.1.18
|
||||
tailwindcss: 4.2.0
|
||||
|
||||
'@tailwindcss/oxide-android-arm64@4.1.18':
|
||||
'@tailwindcss/oxide-android-arm64@4.2.0':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-darwin-arm64@4.1.18':
|
||||
'@tailwindcss/oxide-darwin-arm64@4.2.0':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-darwin-x64@4.1.18':
|
||||
'@tailwindcss/oxide-darwin-x64@4.2.0':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-freebsd-x64@4.1.18':
|
||||
'@tailwindcss/oxide-freebsd-x64@4.2.0':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18':
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf@4.2.0':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-gnu@4.1.18':
|
||||
'@tailwindcss/oxide-linux-arm64-gnu@4.2.0':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.1.18':
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.2.0':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.1.18':
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.2.0':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.1.18':
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.2.0':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-wasm32-wasi@4.1.18':
|
||||
'@tailwindcss/oxide-wasm32-wasi@4.2.0':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-win32-arm64-msvc@4.1.18':
|
||||
'@tailwindcss/oxide-win32-arm64-msvc@4.2.0':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-win32-x64-msvc@4.1.18':
|
||||
'@tailwindcss/oxide-win32-x64-msvc@4.2.0':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide@4.1.18':
|
||||
'@tailwindcss/oxide@4.2.0':
|
||||
optionalDependencies:
|
||||
'@tailwindcss/oxide-android-arm64': 4.1.18
|
||||
'@tailwindcss/oxide-darwin-arm64': 4.1.18
|
||||
'@tailwindcss/oxide-darwin-x64': 4.1.18
|
||||
'@tailwindcss/oxide-freebsd-x64': 4.1.18
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18
|
||||
'@tailwindcss/oxide-linux-arm64-gnu': 4.1.18
|
||||
'@tailwindcss/oxide-linux-arm64-musl': 4.1.18
|
||||
'@tailwindcss/oxide-linux-x64-gnu': 4.1.18
|
||||
'@tailwindcss/oxide-linux-x64-musl': 4.1.18
|
||||
'@tailwindcss/oxide-wasm32-wasi': 4.1.18
|
||||
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.18
|
||||
'@tailwindcss/oxide-win32-x64-msvc': 4.1.18
|
||||
'@tailwindcss/oxide-android-arm64': 4.2.0
|
||||
'@tailwindcss/oxide-darwin-arm64': 4.2.0
|
||||
'@tailwindcss/oxide-darwin-x64': 4.2.0
|
||||
'@tailwindcss/oxide-freebsd-x64': 4.2.0
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.0
|
||||
'@tailwindcss/oxide-linux-arm64-gnu': 4.2.0
|
||||
'@tailwindcss/oxide-linux-arm64-musl': 4.2.0
|
||||
'@tailwindcss/oxide-linux-x64-gnu': 4.2.0
|
||||
'@tailwindcss/oxide-linux-x64-musl': 4.2.0
|
||||
'@tailwindcss/oxide-wasm32-wasi': 4.2.0
|
||||
'@tailwindcss/oxide-win32-arm64-msvc': 4.2.0
|
||||
'@tailwindcss/oxide-win32-x64-msvc': 4.2.0
|
||||
|
||||
'@tailwindcss/postcss@4.1.18':
|
||||
'@tailwindcss/postcss@4.2.0':
|
||||
dependencies:
|
||||
'@alloc/quick-lru': 5.2.0
|
||||
'@tailwindcss/node': 4.1.18
|
||||
'@tailwindcss/oxide': 4.1.18
|
||||
'@tailwindcss/node': 4.2.0
|
||||
'@tailwindcss/oxide': 4.2.0
|
||||
postcss: 8.5.6
|
||||
tailwindcss: 4.1.18
|
||||
tailwindcss: 4.2.0
|
||||
|
||||
'@tailwindcss/typography@0.5.19(tailwindcss@4.2.0)':
|
||||
dependencies:
|
||||
postcss-selector-parser: 6.0.10
|
||||
tailwindcss: 4.2.0
|
||||
|
||||
'@trysound/sax@0.2.0': {}
|
||||
|
||||
@@ -1118,54 +1116,54 @@ snapshots:
|
||||
optionalDependencies:
|
||||
graceful-fs: 4.2.11
|
||||
|
||||
lightningcss-android-arm64@1.30.2:
|
||||
lightningcss-android-arm64@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-darwin-arm64@1.30.2:
|
||||
lightningcss-darwin-arm64@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-darwin-x64@1.30.2:
|
||||
lightningcss-darwin-x64@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-freebsd-x64@1.30.2:
|
||||
lightningcss-freebsd-x64@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-arm-gnueabihf@1.30.2:
|
||||
lightningcss-linux-arm-gnueabihf@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-arm64-gnu@1.30.2:
|
||||
lightningcss-linux-arm64-gnu@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-arm64-musl@1.30.2:
|
||||
lightningcss-linux-arm64-musl@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-x64-gnu@1.30.2:
|
||||
lightningcss-linux-x64-gnu@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-x64-musl@1.30.2:
|
||||
lightningcss-linux-x64-musl@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.30.2:
|
||||
lightningcss-win32-arm64-msvc@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-win32-x64-msvc@1.30.2:
|
||||
lightningcss-win32-x64-msvc@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss@1.30.2:
|
||||
lightningcss@1.31.1:
|
||||
dependencies:
|
||||
detect-libc: 2.1.2
|
||||
optionalDependencies:
|
||||
lightningcss-android-arm64: 1.30.2
|
||||
lightningcss-darwin-arm64: 1.30.2
|
||||
lightningcss-darwin-x64: 1.30.2
|
||||
lightningcss-freebsd-x64: 1.30.2
|
||||
lightningcss-linux-arm-gnueabihf: 1.30.2
|
||||
lightningcss-linux-arm64-gnu: 1.30.2
|
||||
lightningcss-linux-arm64-musl: 1.30.2
|
||||
lightningcss-linux-x64-gnu: 1.30.2
|
||||
lightningcss-linux-x64-musl: 1.30.2
|
||||
lightningcss-win32-arm64-msvc: 1.30.2
|
||||
lightningcss-win32-x64-msvc: 1.30.2
|
||||
lightningcss-android-arm64: 1.31.1
|
||||
lightningcss-darwin-arm64: 1.31.1
|
||||
lightningcss-darwin-x64: 1.31.1
|
||||
lightningcss-freebsd-x64: 1.31.1
|
||||
lightningcss-linux-arm-gnueabihf: 1.31.1
|
||||
lightningcss-linux-arm64-gnu: 1.31.1
|
||||
lightningcss-linux-arm64-musl: 1.31.1
|
||||
lightningcss-linux-x64-gnu: 1.31.1
|
||||
lightningcss-linux-x64-musl: 1.31.1
|
||||
lightningcss-win32-arm64-msvc: 1.31.1
|
||||
lightningcss-win32-x64-msvc: 1.31.1
|
||||
|
||||
lilconfig@3.1.3: {}
|
||||
|
||||
@@ -1299,11 +1297,6 @@ snapshots:
|
||||
postcss: 8.5.6
|
||||
postcss-selector-parser: 6.1.2
|
||||
|
||||
postcss-nested@5.0.6(postcss@8.5.6):
|
||||
dependencies:
|
||||
postcss: 8.5.6
|
||||
postcss-selector-parser: 6.1.2
|
||||
|
||||
postcss-normalize-charset@6.0.2(postcss@8.5.6):
|
||||
dependencies:
|
||||
postcss: 8.5.6
|
||||
@@ -1372,6 +1365,11 @@ snapshots:
|
||||
postcss: 8.5.6
|
||||
thenby: 1.3.4
|
||||
|
||||
postcss-selector-parser@6.0.10:
|
||||
dependencies:
|
||||
cssesc: 3.0.0
|
||||
util-deprecate: 1.0.2
|
||||
|
||||
postcss-selector-parser@6.1.2:
|
||||
dependencies:
|
||||
cssesc: 3.0.0
|
||||
@@ -1438,7 +1436,7 @@ snapshots:
|
||||
csso: 5.0.5
|
||||
picocolors: 1.1.1
|
||||
|
||||
tailwindcss@4.1.18: {}
|
||||
tailwindcss@4.2.0: {}
|
||||
|
||||
tapable@2.3.0: {}
|
||||
|
||||
|
||||
37
post.hbs
@@ -1,8 +1,9 @@
|
||||
{{!< default}}
|
||||
|
||||
<article class="container mx-auto px-4 py-12">
|
||||
<header class="text-center mb-8">
|
||||
<h1 class="text-6xl font-bold tracking-tight text-[var(--text-primary)] mb-4">{{title}}</h1>
|
||||
{{#post}}
|
||||
<article class="is-post container mx-auto px-4 py-12">
|
||||
<header class="text-center mb-8 max-w-3xl mx-auto">
|
||||
<h1 class="text-6xl font-bold tracking-tight text-[var(--text-primary)] mb-4">{{title fallback="No Title Provided"}}</h1>
|
||||
<section class="post-meta text-[var(--text-secondary)] text-lg">
|
||||
<time datetime="{{date format="YYYY-MM-DD"}}">{{date format="MMMM DD, YYYY"}}</time>
|
||||
{{#if primary_tag}}
|
||||
@@ -13,29 +14,17 @@
|
||||
</header>
|
||||
|
||||
{{#if feature_image}}
|
||||
<figure class="mb-12 rounded-lg overflow-hidden shadow-xl">
|
||||
<img
|
||||
class="w-full h-auto object-cover"
|
||||
src="{{img_url feature_image size="xl"}}"
|
||||
srcset="{{img_url feature_image size="l"}} 1000w,
|
||||
{{img_url feature_image size="xl"}} 2000w"
|
||||
sizes="(max-width: 1000px) 1000px, 2000px"
|
||||
alt="{{title}}"
|
||||
>
|
||||
</figure>
|
||||
{{else}}
|
||||
<div class="mb-12 rounded-lg overflow-hidden shadow-xl w-full h-96 flex items-center justify-center bg-[var(--bg-tertiary)] text-[var(--text-tertiary)] text-3xl">
|
||||
No Feature Image
|
||||
</div>
|
||||
{{> "feature-image"}}
|
||||
{{/if}}
|
||||
|
||||
<section class="post-content max-w-3xl mx-auto text-[var(--text-primary)] leading-relaxed text-lg prose prose-invert">
|
||||
{{content}}
|
||||
<section class="post-content max-w-3xl mx-auto text-[var(--text-primary)] leading-relaxed text-lg prose">
|
||||
{{content fallback="<p>No content provided for this post.</p>"}}
|
||||
</section>
|
||||
|
||||
<footer class="mt-12 pt-8 border-t border-[var(--bg-tertiary)] text-center">
|
||||
<a href="/" class="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md shadow-sm text-[var(--text-primary)] bg-[var(--brand-primary)] hover:bg-[var(--brand-secondary)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--brand-primary)] transition duration-200">
|
||||
← Back to Home
|
||||
</a>
|
||||
</footer>
|
||||
{{> "post-navigation"}}
|
||||
|
||||
{{#if primary_tag}}
|
||||
{{> "related-posts"}}
|
||||
{{/if}}
|
||||
</article>
|
||||
{{/post}}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'@tailwindcss/nesting': {},
|
||||
'@tailwindcss/postcss': {},
|
||||
'autoprefixer': {},
|
||||
...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {})
|
||||
|
||||
25
tag.hbs
Normal file
@@ -0,0 +1,25 @@
|
||||
{{!< default}}
|
||||
|
||||
{{#tag}}
|
||||
<header class="container mx-auto px-4 py-16 md:py-24 text-center">
|
||||
<span class="text-xs uppercase tracking-[0.3em] text-[var(--text-tertiary)] mb-4 block">Tag</span>
|
||||
<h1 class="text-6xl md:text-8xl font-bold tracking-tighter text-[var(--brand-primary)] mb-4">{{name}}</h1>
|
||||
{{#if description}}
|
||||
<p class="mt-4 text-xl md:text-2xl text-[var(--text-secondary)] max-w-2xl mx-auto font-serif italic italic leading-relaxed opacity-90 mb-8">{{description}}</p>
|
||||
{{/if}}
|
||||
|
||||
<div class="flex items-center justify-center text-sm font-medium uppercase tracking-[0.2em] text-[var(--text-tertiary)]">
|
||||
<span class="inline-block w-8 h-px bg-[var(--bg-tertiary)] mr-4"></span>
|
||||
{{plural ../pagination.total empty='No posts' singular='% post' plural='% posts'}}
|
||||
<span class="inline-block w-8 h-px bg-[var(--bg-tertiary)] ml-4"></span>
|
||||
</div>
|
||||
</header>
|
||||
{{/tag}}
|
||||
|
||||
<div class="container mx-auto px-4 pb-20">
|
||||
{{#if posts}}
|
||||
{{> "post-feed"}}
|
||||
{{else}}
|
||||
<p class="text-center text-[var(--text-secondary)] text-2xl py-20">No posts found.</p>
|
||||
{{/if}}
|
||||
</div>
|
||||