Downloaded theme
33
themes/minimal-black/.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Hugo
|
||||||
|
public/
|
||||||
|
resources/
|
||||||
|
.hugo_build.lock
|
||||||
|
hugo_stats.json
|
||||||
|
|
||||||
|
# Node.js
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
|
# IDE & Editor
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Build artifacts
|
||||||
|
*.log
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
|
||||||
|
# Backup files
|
||||||
|
*.backup
|
||||||
|
*.bak
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
Thumbs.db
|
||||||
|
Desktop.ini
|
||||||
111
themes/minimal-black/CHANGELOG.md
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to the Minimal Black theme will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Initial theme release
|
||||||
|
- Dark and light mode with automatic switching
|
||||||
|
- True black dark mode with purple accents
|
||||||
|
- Responsive design for mobile, tablet, and desktop
|
||||||
|
- Built-in search functionality with keyboard shortcuts (Ctrl/Cmd+K)
|
||||||
|
- Table of contents for blog posts with active section tracking
|
||||||
|
- Syntax highlighting with copy button and language labels
|
||||||
|
- Multiple page layouts: home, blog, projects, about, about-alternative
|
||||||
|
- Mermaid diagram support
|
||||||
|
- Gallery shortcode with lightbox
|
||||||
|
- GitHub-style alerts (note, tip, warning, danger, important)
|
||||||
|
- Analytics support (Google Analytics, Plausible, Umami, Fathom)
|
||||||
|
- Font Awesome and Devicon icon support
|
||||||
|
- Technology stack marquee on home page
|
||||||
|
- Project portfolio with featured projects
|
||||||
|
- Blog with tags and categories
|
||||||
|
- SEO optimized meta tags
|
||||||
|
- RSS feed generation
|
||||||
|
- JSON output for search indexing
|
||||||
|
- Modular CSS architecture
|
||||||
|
- Configurable stats and skills for about-alternative page
|
||||||
|
- Favicon and touch icon support
|
||||||
|
- Social links configuration
|
||||||
|
- Hero section with customizable badge, title, and CTAs
|
||||||
|
- "Now" section for quick facts
|
||||||
|
- Floating action dock
|
||||||
|
- Mobile-friendly navigation
|
||||||
|
- Theme toggle button
|
||||||
|
- Custom 404 page
|
||||||
|
- Markdown enhancements:
|
||||||
|
- Enhanced blockquotes with gradient backgrounds
|
||||||
|
- Improved list styling with hover effects
|
||||||
|
- Task list support with checkboxes
|
||||||
|
- Definition lists
|
||||||
|
- Footnotes
|
||||||
|
- Table styling with responsive wrapper
|
||||||
|
- Image captions (optional)
|
||||||
|
- External link indicators
|
||||||
|
- Heading anchor links
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- N/A (initial release)
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
- N/A (initial release)
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- N/A (initial release)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- N/A (initial release)
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- N/A (initial release)
|
||||||
|
|
||||||
|
## Release Notes
|
||||||
|
|
||||||
|
### Version 1.0.0 (Unreleased)
|
||||||
|
|
||||||
|
Initial release of Minimal Black theme for Hugo. A minimal, dark-mode first theme designed for developers, designers, and writers who value simplicity and performance.
|
||||||
|
|
||||||
|
**Key Features:**
|
||||||
|
- ⚡ Fast and lightweight
|
||||||
|
- 🎨 Beautiful dark mode with true black backgrounds
|
||||||
|
- 📱 Fully responsive design
|
||||||
|
- 🔍 Built-in search
|
||||||
|
- 💻 Excellent code highlighting
|
||||||
|
- 📚 Comprehensive documentation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Version History Format
|
||||||
|
|
||||||
|
Each version entry should follow this structure:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## [X.Y.Z] - YYYY-MM-DD
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- New features
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Changes in existing functionality
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
- Soon-to-be removed features
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Removed features
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Bug fixes
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Security patches
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[Unreleased]: https://gitlab.com/jimchr12/hugo-minimal-black/-/compare/v1.0.0...main
|
||||||
|
[1.0.0]: https://gitlab.com/jimchr12/hugo-minimal-black/-/releases/v1.0.0
|
||||||
249
themes/minimal-black/CONTRIBUTING.md
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
# Contributing to Minimal Black
|
||||||
|
|
||||||
|
Thank you for your interest in contributing to Minimal Black! This document provides guidelines and instructions for contributing to the theme.
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
|
||||||
|
By participating in this project, you agree to maintain a respectful and collaborative environment. Be kind, be professional, and be constructive in your feedback.
|
||||||
|
|
||||||
|
## How Can I Contribute?
|
||||||
|
|
||||||
|
### Reporting Bugs
|
||||||
|
|
||||||
|
Before creating a bug report, please check the [existing issues](https://gitlab.com/jimchr12/hugo-minimal-black/-/issues) to avoid duplicates.
|
||||||
|
|
||||||
|
When creating a bug report, include:
|
||||||
|
|
||||||
|
- **Clear title** — Descriptive and specific
|
||||||
|
- **Steps to reproduce** — Minimal steps needed to reproduce the issue
|
||||||
|
- **Expected behavior** — What you expected to happen
|
||||||
|
- **Actual behavior** — What actually happened
|
||||||
|
- **Screenshots** — If applicable
|
||||||
|
- **Environment:**
|
||||||
|
- Hugo version (`hugo version`)
|
||||||
|
- Operating system
|
||||||
|
- Browser (if frontend issue)
|
||||||
|
- Node.js version (`node --version`)
|
||||||
|
|
||||||
|
### Suggesting Enhancements
|
||||||
|
|
||||||
|
Enhancement suggestions are welcome! Please:
|
||||||
|
|
||||||
|
1. **Check existing issues** — Your idea might already be proposed
|
||||||
|
2. **Provide clear use case** — Explain why this would be useful
|
||||||
|
3. **Consider alternatives** — Mention any alternative solutions you've considered
|
||||||
|
4. **Keep it minimal** — The theme prioritizes simplicity
|
||||||
|
|
||||||
|
### Pull Requests
|
||||||
|
|
||||||
|
1. **Fork the repository** and create your branch from `main`
|
||||||
|
2. **Make your changes** following the code style guidelines below
|
||||||
|
3. **Test your changes** thoroughly
|
||||||
|
4. **Update documentation** if you're changing functionality
|
||||||
|
5. **Commit with clear messages** following the commit conventions
|
||||||
|
6. **Submit a pull request** with a comprehensive description
|
||||||
|
|
||||||
|
## Development Setup
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- Hugo Extended v0.120.0+
|
||||||
|
- Node.js 18+
|
||||||
|
- npm or yarn
|
||||||
|
|
||||||
|
### Local Development
|
||||||
|
|
||||||
|
1. **Clone your fork:**
|
||||||
|
```bash
|
||||||
|
git clone https://gitlab.com/YOUR-USERNAME/hugo-minimal-black.git
|
||||||
|
cd hugo-minimal-black
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Install dependencies:**
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Run the example site:**
|
||||||
|
```bash
|
||||||
|
cd exampleSite
|
||||||
|
hugo server -D --themesDir ../..
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Build CSS** (if modifying styles):
|
||||||
|
```bash
|
||||||
|
npx tailwindcss -i ./assets/css/main.css -o ./static/css/main.css
|
||||||
|
```
|
||||||
|
|
||||||
|
### Making Changes
|
||||||
|
|
||||||
|
#### CSS/Styling
|
||||||
|
|
||||||
|
- CSS files are in `assets/css/`
|
||||||
|
- The theme uses Tailwind CSS with a modular structure
|
||||||
|
- See [CSS-STRUCTURE.md](CSS-STRUCTURE.md) for architecture details
|
||||||
|
- Follow the existing pattern: one component per file
|
||||||
|
- Use CSS custom properties for theme colors
|
||||||
|
- Ensure changes work in both light and dark modes
|
||||||
|
|
||||||
|
#### HTML/Templates
|
||||||
|
|
||||||
|
- Templates are in `layouts/`
|
||||||
|
- Follow Hugo's template best practices
|
||||||
|
- Use semantic HTML5 elements
|
||||||
|
- Test responsiveness on mobile, tablet, and desktop
|
||||||
|
|
||||||
|
#### JavaScript
|
||||||
|
|
||||||
|
- Keep JavaScript minimal
|
||||||
|
- Use vanilla JavaScript (no frameworks)
|
||||||
|
- Ensure compatibility with all modern browsers
|
||||||
|
- Add comments for complex logic
|
||||||
|
- Test with JavaScript disabled for core functionality
|
||||||
|
|
||||||
|
### HTML/Templates
|
||||||
|
|
||||||
|
- **2 spaces** for indentation
|
||||||
|
- **Semantic HTML** — Use appropriate elements
|
||||||
|
- **Accessibility** — Include ARIA labels where needed
|
||||||
|
- **Hugo conventions** — Follow Hugo's best practices
|
||||||
|
|
||||||
|
```html
|
||||||
|
{{ define "main" }}
|
||||||
|
<section class="layout-page">
|
||||||
|
<article class="about-page">
|
||||||
|
<h1>{{ .Title }}</h1>
|
||||||
|
{{ .Content }}
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
{{ end }}
|
||||||
|
```
|
||||||
|
|
||||||
|
### CSS
|
||||||
|
|
||||||
|
- **2 spaces** for indentation
|
||||||
|
- **BEM-inspired** naming for custom classes
|
||||||
|
- **Mobile-first** responsive design
|
||||||
|
- **CSS custom properties** for theme values
|
||||||
|
- **Comments** for complex styles
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* Component name */
|
||||||
|
.component-name {
|
||||||
|
property: value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Component variant */
|
||||||
|
.component-name--variant {
|
||||||
|
property: value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Component element */
|
||||||
|
.component-name__element {
|
||||||
|
property: value;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### JavaScript
|
||||||
|
|
||||||
|
- **2 spaces** for indentation
|
||||||
|
- **camelCase** for variables and functions
|
||||||
|
- **Descriptive names** — Avoid abbreviations
|
||||||
|
- **Comments** for non-obvious code
|
||||||
|
- **Modern syntax** — Use ES6+ features
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function handleSearchInput(event) {
|
||||||
|
const query = event.target.value;
|
||||||
|
const results = filterPages(query);
|
||||||
|
renderResults(results);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Commit Messages
|
||||||
|
|
||||||
|
Follow the [Conventional Commits](https://www.conventionalcommits.org/) specification:
|
||||||
|
|
||||||
|
```
|
||||||
|
type(scope): subject
|
||||||
|
|
||||||
|
body (optional)
|
||||||
|
|
||||||
|
footer (optional)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Types
|
||||||
|
|
||||||
|
- `feat`: New feature
|
||||||
|
- `fix`: Bug fix
|
||||||
|
- `docs`: Documentation changes
|
||||||
|
- `style`: Code style changes (formatting, etc.)
|
||||||
|
- `refactor`: Code refactoring
|
||||||
|
- `perf`: Performance improvements
|
||||||
|
- `test`: Adding or updating tests
|
||||||
|
- `chore`: Maintenance tasks
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
feat(search): add keyboard navigation to search results
|
||||||
|
|
||||||
|
fix(toc): correct active link highlighting on scroll
|
||||||
|
|
||||||
|
docs(readme): update installation instructions
|
||||||
|
|
||||||
|
style(css): reorganize markdown styles into modules
|
||||||
|
|
||||||
|
refactor(cards): simplify project card component
|
||||||
|
|
||||||
|
perf(images): optimize image loading with lazy loading
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing Checklist
|
||||||
|
|
||||||
|
Before submitting a pull request, ensure:
|
||||||
|
|
||||||
|
- [ ] Hugo builds without errors (`hugo`)
|
||||||
|
- [ ] No console errors in browser
|
||||||
|
- [ ] Works in latest Chrome, Firefox, Safari
|
||||||
|
- [ ] Responsive on mobile, tablet, desktop
|
||||||
|
- [ ] Dark and light modes both work
|
||||||
|
- [ ] Accessibility: Keyboard navigation works
|
||||||
|
- [ ] Performance: Lighthouse score >90
|
||||||
|
- [ ] Documentation updated (if applicable)
|
||||||
|
- [ ] No breaking changes (or clearly documented)
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
minimal-black/
|
||||||
|
├── archetypes/ # Content templates
|
||||||
|
├── assets/
|
||||||
|
│ └── css/ # Modular CSS files
|
||||||
|
├── layouts/
|
||||||
|
│ ├── _default/ # Default layouts
|
||||||
|
│ ├── partials/ # Reusable components
|
||||||
|
│ └── shortcodes/ # Custom shortcodes
|
||||||
|
├── static/
|
||||||
|
│ └── js/ # JavaScript files
|
||||||
|
├── exampleSite/ # Example site for testing
|
||||||
|
├── images/ # Theme screenshots
|
||||||
|
├── CSS-STRUCTURE.md # CSS architecture docs
|
||||||
|
├── CONTRIBUTING.md # This file
|
||||||
|
├── LICENSE # MIT License
|
||||||
|
├── README.md # Main documentation
|
||||||
|
└── theme.toml # Theme metadata
|
||||||
|
```
|
||||||
|
|
||||||
|
## Questions?
|
||||||
|
|
||||||
|
- **Issues:** [GitLab Issues](https://gitlab.com/jimchr12/hugo-minimal-black/-/issues)
|
||||||
|
- **Discussions:** [GitLab Discussions](https://gitlab.com/jimchr12/hugo-minimal-black/-/issues)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
By contributing, you agree that your contributions will be licensed under the MIT License.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Thank you for contributing to Minimal Black! 🎉
|
||||||
106
themes/minimal-black/CSS-STRUCTURE.md
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
# CSS Architecture
|
||||||
|
|
||||||
|
The Minimal Black theme uses a modular CSS architecture for better maintainability and organization.
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
assets/css/
|
||||||
|
├── main.css # Entry point (imports all modules)
|
||||||
|
├── base.css # Tailwind imports & theme variables
|
||||||
|
├── utilities.css # Utility classes & animations
|
||||||
|
├── responsive.css # Global responsive styles
|
||||||
|
├── components/
|
||||||
|
│ ├── dock.css # Floating action dock
|
||||||
|
│ ├── cards.css # Card variants (home, project, post, CTA)
|
||||||
|
│ ├── navigation.css # Header, footer, nav links
|
||||||
|
│ ├── search.css # Search overlay & results
|
||||||
|
│ └── tech-marquee.css # Technology carousel
|
||||||
|
├── content/
|
||||||
|
│ ├── markdown.css # Typography, blockquotes, lists, code
|
||||||
|
│ └── toc.css # Table of contents sidebar
|
||||||
|
└── pages/
|
||||||
|
├── about.css # About page with timeline
|
||||||
|
└── about-alternative.css # Alternative about page layout
|
||||||
|
```
|
||||||
|
|
||||||
|
## Module Descriptions
|
||||||
|
|
||||||
|
### Base Layer
|
||||||
|
- **base.css**: Tailwind directives, CSS custom properties for theming (light/dark mode), and base body styles
|
||||||
|
|
||||||
|
### Utilities
|
||||||
|
- **utilities.css**: Color utilities, animation classes, and helper classes used throughout the theme
|
||||||
|
|
||||||
|
### Components
|
||||||
|
Reusable UI components that appear across multiple pages:
|
||||||
|
- **dock.css**: Floating action button dock with expandable panel
|
||||||
|
- **cards.css**: All card variants including home cards, project/post cards, CTA cards, and badges
|
||||||
|
- **navigation.css**: Page layouts, header, footer, navigation links, and theme toggle
|
||||||
|
- **search.css**: Search modal overlay, search results, empty states, and keyboard hints
|
||||||
|
- **tech-marquee.css**: Animated technology/skills carousel component
|
||||||
|
|
||||||
|
### Content
|
||||||
|
Styles specific to content rendering:
|
||||||
|
- **markdown.css**: Complete markdown styling including typography, blockquotes, lists, code blocks, tables, GitHub-style alerts, and syntax highlighting
|
||||||
|
- **toc.css**: Table of contents sidebar with sticky positioning and active link tracking
|
||||||
|
|
||||||
|
### Pages
|
||||||
|
Page-specific styles:
|
||||||
|
- **about.css**: Standard about page with timeline visualization
|
||||||
|
- **about-alternative.css**: Alternative about layout with sidebar profile card and stats
|
||||||
|
|
||||||
|
### Responsive
|
||||||
|
- **responsive.css**: All media queries and mobile optimizations for global components
|
||||||
|
|
||||||
|
## Import Order
|
||||||
|
|
||||||
|
The import order in `main.css` is important:
|
||||||
|
1. Base styles (Tailwind + variables)
|
||||||
|
2. Utilities (available to all components)
|
||||||
|
3. Components (dock → cards → navigation → search → tech)
|
||||||
|
4. Content styles (markdown → TOC)
|
||||||
|
5. Page-specific styles
|
||||||
|
6. Responsive overrides
|
||||||
|
|
||||||
|
## Development Guidelines
|
||||||
|
|
||||||
|
### Adding New Styles
|
||||||
|
- Component styles → `components/`
|
||||||
|
- Content/typography → `content/`
|
||||||
|
- Page-specific → `pages/`
|
||||||
|
- Utilities → `utilities.css`
|
||||||
|
- Theme variables → `base.css`
|
||||||
|
|
||||||
|
### Modifying Existing Styles
|
||||||
|
Each file is focused on a specific concern. Find the relevant module and edit it directly. Hugo will automatically rebuild the combined CSS.
|
||||||
|
|
||||||
|
### Theme Colors
|
||||||
|
All theme colors are defined as CSS custom properties in `base.css`:
|
||||||
|
```css
|
||||||
|
--color-bg /* Background */
|
||||||
|
--color-surface /* Card/surface backgrounds */
|
||||||
|
--color-text /* Primary text */
|
||||||
|
--color-text-muted /* Secondary text */
|
||||||
|
--color-border /* Borders */
|
||||||
|
--color-accent /* Primary accent color */
|
||||||
|
```
|
||||||
|
|
||||||
|
These variables automatically switch between light and dark themes.
|
||||||
|
|
||||||
|
### Responsive Breakpoints
|
||||||
|
- Mobile: `max-width: 640px`
|
||||||
|
- Tablet: `641px - 1023px`
|
||||||
|
- Desktop: `min-width: 1024px`
|
||||||
|
- Large Desktop: `min-width: 1536px`
|
||||||
|
- XL Desktop: `min-width: 1920px`
|
||||||
|
|
||||||
|
## Build Process
|
||||||
|
|
||||||
|
Hugo processes `main.css` through:
|
||||||
|
1. Resolves `@import` statements
|
||||||
|
2. Processes Tailwind directives (@tailwind, @apply)
|
||||||
|
3. Minifies for production
|
||||||
|
4. Outputs to `public/css/main.css`
|
||||||
|
|
||||||
|
The modular structure is development-only; users receive a single optimized CSS file.
|
||||||
21
themes/minimal-black/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 Jim Christopoulos
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
457
themes/minimal-black/README.md
Normal file
@@ -0,0 +1,457 @@
|
|||||||
|
# Minimal Black
|
||||||
|
|
||||||
|
A minimal, dark-mode first Hugo theme with true black backgrounds, purple accents, and comprehensive content styling. Perfect for developers, writers and everyone in general who want a clean, fast, and beautiful personal site.
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- ✨ **Dark & Light Mode** — Auto-switching themes with manual toggle
|
||||||
|
- 🎨 **True Black Dark Mode** — OLED-friendly with purple (`#a855f7`) accents
|
||||||
|
- 📱 **Fully Responsive** — Mobile-first design that works on all devices
|
||||||
|
- 🔍 **Built-in Search** — Fast client-side search with keyboard shortcuts (Ctrl/Cmd+K)
|
||||||
|
- 📑 **Table of Contents** — Auto-generated TOC for blog posts with active section tracking
|
||||||
|
- 💻 **Beautiful Code Blocks** — Syntax highlighting with copy button and language labels
|
||||||
|
- 🎯 **Multiple Layouts** — Home, blog, projects, and two about page variants
|
||||||
|
- 📊 **Mermaid Diagrams** — Native support for flowcharts and diagrams
|
||||||
|
- 🖼️ **Image Gallery** — Gallery shortcode with lightbox functionality
|
||||||
|
- 🏷️ **GitHub-Style Alerts** — Support for note, tip, warning, danger, and important callouts
|
||||||
|
- 📈 **Analytics Ready** — Built-in support for Google Analytics, Plausible, Umami, and Fathom
|
||||||
|
- ⚡ **Performance Optimized** — Minimal JavaScript, CSS, and fast load times
|
||||||
|
- 🎭 **Icon Support** — Font Awesome and Devicon integration
|
||||||
|
|
||||||
|
## Demo
|
||||||
|
|
||||||
|
**Live Demo:** [minimal-black-demo.netlify.app](https://minimal-black-demo.netlify.app)
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- Hugo Extended v0.120.0 or higher
|
||||||
|
- Node.js and npm (for Tailwind CSS compilation)
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
1. **Create a new Hugo site** (or use existing):
|
||||||
|
```bash
|
||||||
|
hugo new site my-site
|
||||||
|
cd my-site
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Install the theme** using Git submodule:
|
||||||
|
```bash
|
||||||
|
git init
|
||||||
|
git submodule add https://gitlab.com/jimchr12/hugo-minimal-black.git themes/minimal-black
|
||||||
|
```
|
||||||
|
|
||||||
|
Or clone it directly:
|
||||||
|
```bash
|
||||||
|
git clone https://gitlab.com/jimchr12/hugo-minimal-black.git themes/minimal-black
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Install Node dependencies** (for Tailwind CSS):
|
||||||
|
```bash
|
||||||
|
cd themes/minimal-black
|
||||||
|
npm install
|
||||||
|
cd ../..
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Configure your site** — Copy the example configuration:
|
||||||
|
```bash
|
||||||
|
cp themes/minimal-black/exampleSite/hugo.toml ./hugo.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Start Hugo server**:
|
||||||
|
```bash
|
||||||
|
hugo server -D
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Visit** `http://localhost:1313` in your browser.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Basic Configuration
|
||||||
|
|
||||||
|
Edit your `hugo.toml` file:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
baseURL = 'https://yoursite.com/'
|
||||||
|
languageCode = 'en-us'
|
||||||
|
title = 'Your Name'
|
||||||
|
theme = 'minimal-black'
|
||||||
|
|
||||||
|
[params]
|
||||||
|
brand = "Your Name"
|
||||||
|
|
||||||
|
# Favicon (place files in /static/)
|
||||||
|
favicon = "favicon.svg"
|
||||||
|
appleTouchIcon = "apple-touch-icon.png"
|
||||||
|
|
||||||
|
# Theme Configuration
|
||||||
|
[params.theme]
|
||||||
|
defaultTheme = "dark" # "light", "dark", or "system"
|
||||||
|
|
||||||
|
# Hero Section
|
||||||
|
[params.hero]
|
||||||
|
badge = "Software Engineer"
|
||||||
|
title = "Hi, I'm Your Name."
|
||||||
|
role = "Building minimal, fast web experiences."
|
||||||
|
summary = "Brief description of what you do."
|
||||||
|
avatar = "images/avatar.jpg" # Optional
|
||||||
|
location = "City, Country"
|
||||||
|
|
||||||
|
[params.hero.primary]
|
||||||
|
label = "View projects"
|
||||||
|
href = "/projects/"
|
||||||
|
|
||||||
|
[params.hero.secondary]
|
||||||
|
label = "Read the blog"
|
||||||
|
href = "/blog/"
|
||||||
|
|
||||||
|
# Social Links
|
||||||
|
[[params.social]]
|
||||||
|
label = "GitHub"
|
||||||
|
url = "https://github.com/yourusername"
|
||||||
|
icon = "fa-brands fa-github"
|
||||||
|
|
||||||
|
[[params.social]]
|
||||||
|
label = "LinkedIn"
|
||||||
|
url = "https://linkedin.com/in/yourusername"
|
||||||
|
icon = "fa-brands fa-linkedin-in"
|
||||||
|
|
||||||
|
[menu]
|
||||||
|
[[menu.main]]
|
||||||
|
name = "Home"
|
||||||
|
url = "/"
|
||||||
|
weight = 1
|
||||||
|
|
||||||
|
[[menu.main]]
|
||||||
|
name = "About"
|
||||||
|
url = "/about/"
|
||||||
|
weight = 2
|
||||||
|
|
||||||
|
[[menu.main]]
|
||||||
|
name = "Projects"
|
||||||
|
url = "/projects/"
|
||||||
|
weight = 3
|
||||||
|
|
||||||
|
[[menu.main]]
|
||||||
|
name = "Blog"
|
||||||
|
url = "/blog/"
|
||||||
|
weight = 4
|
||||||
|
|
||||||
|
[markup]
|
||||||
|
[markup.tableOfContents]
|
||||||
|
startLevel = 2
|
||||||
|
endLevel = 4
|
||||||
|
|
||||||
|
[markup.goldmark.renderer]
|
||||||
|
unsafe = true
|
||||||
|
|
||||||
|
[markup.highlight]
|
||||||
|
codeFences = true
|
||||||
|
guessSyntax = true
|
||||||
|
style = "monokai"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Advanced Configuration
|
||||||
|
|
||||||
|
#### Analytics
|
||||||
|
|
||||||
|
Google Analytics (GA4):
|
||||||
|
```toml
|
||||||
|
[params.analytics]
|
||||||
|
googleAnalytics = "G-XXXXXXXXXX"
|
||||||
|
```
|
||||||
|
|
||||||
|
Plausible Analytics:
|
||||||
|
```toml
|
||||||
|
[params.analytics.plausible]
|
||||||
|
enabled = true
|
||||||
|
domain = "yourdomain.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
Umami Analytics:
|
||||||
|
```toml
|
||||||
|
[params.analytics.umami]
|
||||||
|
enabled = true
|
||||||
|
scriptUrl = "https://analytics.yourdomain.com/script.js"
|
||||||
|
websiteId = "your-website-id"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Technology Stack Display
|
||||||
|
|
||||||
|
Show your tech stack on the home page:
|
||||||
|
```toml
|
||||||
|
[params.home]
|
||||||
|
[[params.home.tech]]
|
||||||
|
label = "Python"
|
||||||
|
icon = "devicon-python-plain"
|
||||||
|
|
||||||
|
[[params.home.tech]]
|
||||||
|
label = "Docker"
|
||||||
|
icon = "devicon-docker-plain"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### About Page Customization
|
||||||
|
|
||||||
|
For the alternative about page layout:
|
||||||
|
```toml
|
||||||
|
[params.about.alt]
|
||||||
|
# Stats in profile card
|
||||||
|
[[params.about.alt.stats]]
|
||||||
|
value = "5+"
|
||||||
|
label = "Years Coding"
|
||||||
|
|
||||||
|
[[params.about.alt.stats]]
|
||||||
|
value = "20+"
|
||||||
|
label = "Projects"
|
||||||
|
|
||||||
|
# Skills with icons
|
||||||
|
[[params.about.alt.skills]]
|
||||||
|
label = "JavaScript"
|
||||||
|
icon = "devicon-javascript-plain"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Content Organization
|
||||||
|
|
||||||
|
### Creating Content
|
||||||
|
|
||||||
|
**Blog Post:**
|
||||||
|
```bash
|
||||||
|
hugo new blog/my-first-post.md
|
||||||
|
```
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
+++
|
||||||
|
title = "My First Post"
|
||||||
|
date = "2025-01-01"
|
||||||
|
author = "Your Name"
|
||||||
|
tags = ["hugo", "web development"]
|
||||||
|
categories = ["tutorials"]
|
||||||
|
draft = false
|
||||||
|
+++
|
||||||
|
|
||||||
|
Your content here...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Project:**
|
||||||
|
```bash
|
||||||
|
hugo new projects/my-project.md
|
||||||
|
```
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
+++
|
||||||
|
title = "My Project"
|
||||||
|
date = "2025-01-01"
|
||||||
|
description = "Brief project description"
|
||||||
|
github = "https://github.com/username/project"
|
||||||
|
demo = "https://project-demo.com"
|
||||||
|
tags = ["react", "typescript"]
|
||||||
|
featured = true
|
||||||
|
+++
|
||||||
|
|
||||||
|
Project details...
|
||||||
|
```
|
||||||
|
|
||||||
|
### About Page
|
||||||
|
|
||||||
|
Create `content/about.md`:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
+++
|
||||||
|
title = "About Me"
|
||||||
|
subtitle = "Software Engineer | Open Source Contributor"
|
||||||
|
layout = "about" # or "about-alternative"
|
||||||
|
+++
|
||||||
|
|
||||||
|
Your introduction here.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Job Title** — [Company](https://company.com)
|
||||||
|
*Dates • Location*
|
||||||
|
|
||||||
|
Description of role...
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Another Role** — Company
|
||||||
|
*Dates • Location*
|
||||||
|
|
||||||
|
Description...
|
||||||
|
```
|
||||||
|
|
||||||
|
The `---` separators create timeline entries in the standard about layout, or experience cards in the alternative layout.
|
||||||
|
|
||||||
|
## Shortcodes
|
||||||
|
|
||||||
|
### Gallery
|
||||||
|
|
||||||
|
Create image galleries with lightbox:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
{{< gallery >}}
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
{{< /gallery >}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Alert
|
||||||
|
|
||||||
|
Create GitHub-style callouts:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
{{< alert type="note" >}}
|
||||||
|
This is a note alert.
|
||||||
|
{{< /alert >}}
|
||||||
|
|
||||||
|
{{< alert type="warning" >}}
|
||||||
|
This is a warning alert.
|
||||||
|
{{< /alert >}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Available types: `note`, `tip`, `important`, `warning`, `danger`
|
||||||
|
|
||||||
|
### Mermaid Diagrams
|
||||||
|
|
||||||
|
````markdown
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[Start] --> B[Process]
|
||||||
|
B --> C[End]
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
|
## Customization
|
||||||
|
|
||||||
|
### Colors
|
||||||
|
|
||||||
|
Theme colors are defined in `assets/css/base.css`:
|
||||||
|
|
||||||
|
```css
|
||||||
|
:root {
|
||||||
|
--color-bg: #f9fafb; /* Light background */
|
||||||
|
--color-accent: #a855f7; /* Purple accent */
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme="dark"] {
|
||||||
|
--color-bg: #000000; /* True black */
|
||||||
|
--color-accent: #c084fc; /* Lighter purple */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### CSS Architecture
|
||||||
|
|
||||||
|
The theme uses a modular CSS structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
assets/css/
|
||||||
|
├── main.css # Imports all modules
|
||||||
|
├── base.css # Tailwind & variables
|
||||||
|
├── utilities.css # Utility classes
|
||||||
|
├── components/ # Reusable components
|
||||||
|
├── content/ # Content styling
|
||||||
|
├── pages/ # Page-specific styles
|
||||||
|
└── responsive.css # Media queries
|
||||||
|
```
|
||||||
|
|
||||||
|
See [CSS-STRUCTURE.md](CSS-STRUCTURE.md) for details.
|
||||||
|
|
||||||
|
### Adding Custom CSS
|
||||||
|
|
||||||
|
Create `assets/css/custom.css` in your site root and import it in your config:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[params]
|
||||||
|
customCSS = ["css/custom.css"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
### Netlify
|
||||||
|
|
||||||
|
1. Push your site to GitHub
|
||||||
|
2. Connect to Netlify
|
||||||
|
3. Build command: `hugo --minify`
|
||||||
|
4. Publish directory: `public`
|
||||||
|
5. Environment variables:
|
||||||
|
```
|
||||||
|
HUGO_VERSION = 0.120.0
|
||||||
|
NODE_VERSION = 18
|
||||||
|
```
|
||||||
|
|
||||||
|
## Browser Support
|
||||||
|
|
||||||
|
- Chrome/Edge (last 2 versions)
|
||||||
|
- Firefox (last 2 versions)
|
||||||
|
- Safari (last 2 versions)
|
||||||
|
- Mobile browsers (iOS Safari, Chrome Mobile)
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### CSS not loading
|
||||||
|
|
||||||
|
Ensure Tailwind dependencies are installed:
|
||||||
|
```bash
|
||||||
|
cd themes/minimal-black
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
Also ensure css is compiled:
|
||||||
|
```bash
|
||||||
|
npx tailwindcss -i ./assets/css/main.css -o ./static/css/main.css
|
||||||
|
```
|
||||||
|
|
||||||
|
### Search not working
|
||||||
|
|
||||||
|
Check that `[outputs]` includes JSON in `hugo.toml`:
|
||||||
|
```toml
|
||||||
|
[outputs]
|
||||||
|
home = ["HTML", "RSS", "JSON"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Icons not showing
|
||||||
|
|
||||||
|
Verify icon library is enabled:
|
||||||
|
```toml
|
||||||
|
[params.icons]
|
||||||
|
useFontAwesome = true
|
||||||
|
useDevicon = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
||||||
|
|
||||||
|
1. Fork the repository
|
||||||
|
2. Create a feature branch
|
||||||
|
3. Make your changes
|
||||||
|
4. Submit a pull request
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This theme is released under the MIT License. See [LICENSE](LICENSE) for details.
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
- Built with [Hugo](https://gohugo.io/)
|
||||||
|
- Styled with [Tailwind CSS](https://tailwindcss.com/)
|
||||||
|
- Icons from [Font Awesome](https://fontawesome.com/) and [Devicon](https://devicon.dev/)
|
||||||
|
- Typography plugin by [@tailwindcss/typography](https://github.com/tailwindlabs/tailwindcss-typography)
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
See [CHANGELOG.md](CHANGELOG.md) for version history and updates.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Made with ❤️ by [Jim Christopoulos](https://jimchristopoulos.com/)**
|
||||||
|
|
||||||
|
If you find this theme useful, consider giving it a ⭐ and/or supporting its development!
|
||||||
|
|
||||||
|
[](https://ko-fi.com/jimchr)
|
||||||
35
themes/minimal-black/assets/css/base.css
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/* ==========================================================================
|
||||||
|
BASE STYLES
|
||||||
|
Tailwind imports, CSS variables, theme colors, and base styles
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
/* Theme Variables */
|
||||||
|
:root {
|
||||||
|
/* LIGHT THEME */
|
||||||
|
--color-bg: #f9fafb;
|
||||||
|
--color-surface: #ffffff;
|
||||||
|
--color-text: #111827;
|
||||||
|
--color-text-muted: #6b7280;
|
||||||
|
--color-border: #e5e7eb;
|
||||||
|
--color-accent: #a855f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme="dark"] {
|
||||||
|
/* DARK THEME */
|
||||||
|
--color-bg: #000000; /* TRUE BLACK */
|
||||||
|
--color-surface: #0a0a0a;
|
||||||
|
--color-text: #f9fafb;
|
||||||
|
--color-text-muted: #9ca3af;
|
||||||
|
--color-border: #27272a;
|
||||||
|
--color-accent: #c084fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Base Styles */
|
||||||
|
body {
|
||||||
|
background: var(--color-bg);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
271
themes/minimal-black/assets/css/components/cards.css
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
/* ==========================================================================
|
||||||
|
CARD COMPONENTS
|
||||||
|
Home cards, project cards, post cards, CTA cards, badges
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.card-home {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 0.5rem;
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface) 96%, transparent);
|
||||||
|
box-shadow: 0 18px 40px rgba(0, 0, 0, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-home--project {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
transition:
|
||||||
|
transform 0.18s ease-out,
|
||||||
|
box-shadow 0.18s ease-out,
|
||||||
|
border-color 0.18s ease-out,
|
||||||
|
background-color 0.18s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-home--project::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: -40%;
|
||||||
|
background: radial-gradient(
|
||||||
|
circle at 120% 50%,
|
||||||
|
color-mix(in srgb, var(--color-accent) 70%, transparent),
|
||||||
|
transparent 60%
|
||||||
|
);
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-8px);
|
||||||
|
transition:
|
||||||
|
opacity 0.22s ease-out,
|
||||||
|
transform 0.22s ease-out;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-home--project:hover {
|
||||||
|
transform: translateY(-4px) translateX(3px);
|
||||||
|
border-color: color-mix(in srgb, var(--color-accent) 40%, var(--color-border));
|
||||||
|
box-shadow:
|
||||||
|
0 18px 40px rgba(0, 0, 0, 0.7),
|
||||||
|
16px 0 38px rgba(124, 58, 237, 0.45); /* purple-ish accent on right */
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface) 99%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-home--project:hover::after {
|
||||||
|
opacity: 0.22;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-home-body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-home--post {
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface) 94%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-home-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-home-icon {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 2.1rem;
|
||||||
|
height: 2.1rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
background-color: color-mix(in srgb, var(--color-bg) 92%, transparent);
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-badge {
|
||||||
|
margin-left: 0.25rem;
|
||||||
|
padding: 0.05rem 0.35rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
background-color: color-mix(in srgb, var(--color-accent) 22%, transparent);
|
||||||
|
color: var(--color-accent);
|
||||||
|
font-size: 0.6rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-home-footer {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-home-footer--buttons {
|
||||||
|
padding-top: 0.4rem;
|
||||||
|
border-top: 1px solid color-mix(in srgb, var(--color-border) 80%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-tag-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-tag-pill {
|
||||||
|
padding: 0.1rem 0.45rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 80%, transparent);
|
||||||
|
background-color: color-mix(in srgb, var(--color-bg) 92%, transparent);
|
||||||
|
font-size: 0.65rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-cta {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.35rem;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 0.25rem 0.6rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
transition:
|
||||||
|
color 0.15s ease-out,
|
||||||
|
border-color 0.15s ease-out,
|
||||||
|
background-color 0.15s ease-out,
|
||||||
|
transform 0.15s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-cta-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.35rem;
|
||||||
|
padding: 0.25rem 0.6rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.68rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
background-color: color-mix(in srgb, var(--color-bg) 92%, transparent);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 80%, transparent);
|
||||||
|
text-decoration: none;
|
||||||
|
transition:
|
||||||
|
color 0.15s ease-out,
|
||||||
|
background-color 0.15s ease-out,
|
||||||
|
border-color 0.15s ease-out,
|
||||||
|
transform 0.15s ease-out,
|
||||||
|
box-shadow 0.15s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-cta-btn:hover {
|
||||||
|
color: var(--color-accent);
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface) 96%, transparent);
|
||||||
|
border-color: color-mix(in srgb, var(--color-accent) 50%, transparent);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-cta-repo {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.4rem;
|
||||||
|
padding: 0.25rem 0.7rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 85%, transparent);
|
||||||
|
background-color: color-mix(in srgb, var(--color-bg) 94%, transparent);
|
||||||
|
font-size: 0.7rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
text-decoration: none;
|
||||||
|
transition:
|
||||||
|
color 0.15s ease-out,
|
||||||
|
border-color 0.15s ease-out,
|
||||||
|
background-color 0.15s ease-out,
|
||||||
|
transform 0.15s ease-out,
|
||||||
|
box-shadow 0.15s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-cta-repo:hover {
|
||||||
|
color: var(--color-accent);
|
||||||
|
border-color: color-mix(in srgb, var(--color-accent) 55%, transparent);
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface) 96%, transparent);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.card-cta:hover {
|
||||||
|
color: var(--color-accent);
|
||||||
|
border-color: color-mix(in srgb, var(--color-accent) 40%, transparent);
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface) 94%, transparent);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-home--post {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface) 94%, transparent);
|
||||||
|
border-left-width: 2px;
|
||||||
|
border-left-color: color-mix(in srgb, var(--color-border) 80%, transparent);
|
||||||
|
transition:
|
||||||
|
transform 0.18s ease-out,
|
||||||
|
box-shadow 0.18s ease-out,
|
||||||
|
border-color 0.18s ease-out,
|
||||||
|
background-color 0.18s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-home--post::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: -4px;
|
||||||
|
top: -20%;
|
||||||
|
bottom: -20%;
|
||||||
|
width: 10px;
|
||||||
|
background: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
transparent,
|
||||||
|
color-mix(in srgb, var(--color-accent) 70%, transparent),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-6px);
|
||||||
|
transition:
|
||||||
|
opacity 0.22s ease-out,
|
||||||
|
transform 0.22s ease-out;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-home--post:hover {
|
||||||
|
transform: translateY(-3px);
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface) 98%, transparent);
|
||||||
|
border-left-color: color-mix(in srgb, var(--color-accent) 55%, var(--color-border));
|
||||||
|
box-shadow: 0 16px 34px rgba(0, 0, 0, 0.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-home--post:hover::before {
|
||||||
|
opacity: 0.55;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-home-icon--post {
|
||||||
|
background-color: color-mix(in srgb, var(--color-bg) 94%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-badge--soft {
|
||||||
|
background-color: color-mix(in srgb, var(--color-accent) 16%, transparent);
|
||||||
|
color: color-mix(in srgb, var(--color-accent) 85%, white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
transition: all 0.2s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-pad {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
|
||||||
|
border-color: color-mix(in srgb, var(--color-accent) 40%, transparent);
|
||||||
|
}
|
||||||
134
themes/minimal-black/assets/css/components/dock.css
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
/* ==========================================================================
|
||||||
|
DOCK COMPONENT
|
||||||
|
Floating action dock with toggle and panel
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.dock {
|
||||||
|
position: fixed;
|
||||||
|
right: 1.5rem;
|
||||||
|
bottom: 1.6rem;
|
||||||
|
z-index: 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dock-inner {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.45rem;
|
||||||
|
padding: 0.3rem 0.5rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
/* border: 1px solid var(--color-border);
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface) 92%, transparent);
|
||||||
|
box-shadow: 0 14px 40px rgba(0, 0, 0, 0.55); */
|
||||||
|
backdrop-filter: blur(16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dock-panel {
|
||||||
|
@apply p-1;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.35rem;
|
||||||
|
max-width: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(6px);
|
||||||
|
overflow: hidden;
|
||||||
|
transition: max-width 0.18s ease-out, opacity 0.18s ease-out,
|
||||||
|
transform 0.18s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dock--open .dock-panel {
|
||||||
|
max-width: 10rem;
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dock-divider {
|
||||||
|
width: 1px;
|
||||||
|
height: 1.4rem;
|
||||||
|
background: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
transparent,
|
||||||
|
color-mix(in srgb, var(--color-border) 80%, transparent),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dock-action {
|
||||||
|
@apply flex items-center justify-center;
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
background-color: color-mix(in srgb, var(--color-bg) 75%, transparent);
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.16s ease-out, border-color 0.16s ease-out,
|
||||||
|
color 0.16s ease-out, transform 0.16s ease-out, box-shadow 0.16s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dock-action:hover {
|
||||||
|
border-color: var(--color-accent);
|
||||||
|
color: var(--color-accent);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
/* box-shadow: 0 8px 26px rgba(0, 0, 0, 0.55); */
|
||||||
|
}
|
||||||
|
|
||||||
|
.dock-toggle {
|
||||||
|
@apply flex items-center justify-center;
|
||||||
|
width: 2.1rem;
|
||||||
|
height: 2.1rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
background-color: color-mix(in srgb, var(--color-bg) 85%, transparent);
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.16s ease-out, border-color 0.16s ease-out,
|
||||||
|
transform 0.16s ease-out, box-shadow 0.16s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dock-toggle:hover {
|
||||||
|
border-color: var(--color-accent);
|
||||||
|
color: var(--color-accent);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dock-toggle-dots {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 0.8rem;
|
||||||
|
height: 0.16rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
background-color: var(--color-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dock-toggle-dots::before,
|
||||||
|
.dock-toggle-dots::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset-y: 0;
|
||||||
|
width: 0.16rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
background-color: var(--color-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dock-toggle-dots::before {
|
||||||
|
left: -0.18rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dock-toggle-dots::after {
|
||||||
|
right: -0.18rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dock--open .dock-toggle-dots,
|
||||||
|
.dock--open .dock-toggle-dots::before,
|
||||||
|
.dock--open .dock-toggle-dots::after {
|
||||||
|
background-color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary-sm {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
padding: 0.35rem 0.9rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
}
|
||||||
203
themes/minimal-black/assets/css/components/navigation.css
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
/* ==========================================================================
|
||||||
|
LAYOUT & NAVIGATION
|
||||||
|
Page layouts, headers, footers, navigation links
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.layout-page {
|
||||||
|
@apply mx-auto max-w-7xl px-4 py-6 sm:px-6 lg:py-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-page-tight {
|
||||||
|
@apply mx-auto max-w-6xl px-4 py-4 sm:px-6 lg:py-10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-stack {
|
||||||
|
@apply space-y-10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-stack--home > * + * {
|
||||||
|
margin-top: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-stack > div + div.posts-section {
|
||||||
|
border-top: 1px solid color-mix(in srgb, var(--color-border) 60%, transparent);
|
||||||
|
padding-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Headings */
|
||||||
|
.heading-page {
|
||||||
|
@apply text-3xl font-semibold tracking-tight sm:text-4xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading-section {
|
||||||
|
@apply text-sm font-semibold tracking-tight;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eyebrow {
|
||||||
|
@apply text-[0.65rem] uppercase tracking-[0.22em];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cards */
|
||||||
|
.card {
|
||||||
|
@apply border border-border bg-surface rounded-xl shadow-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-pad {
|
||||||
|
@apply p-4 sm:p-5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-hover {
|
||||||
|
@apply transition-transform transition-shadow duration-150 ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-hover:hover {
|
||||||
|
@apply shadow-lg;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
border-color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Buttons */
|
||||||
|
.btn-primary {
|
||||||
|
@apply inline-flex items-center rounded-full bg-accent px-4 py-2 text-xs font-medium text-white shadow-sm transition-transform duration-150 ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-ghost {
|
||||||
|
@apply inline-flex items-center text-xs font-medium text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-shell {
|
||||||
|
@apply rounded-full border border-border shadow-md backdrop-blur p-3;
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface) 82%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-shell::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset-inline: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
height: 1px;
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
transparent,
|
||||||
|
color-mix(in srgb, var(--color-accent) 80%, transparent),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
opacity: 0.8;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-inner {
|
||||||
|
@apply flex items-center justify-between px-4 py-2 sm:px-5 sm:py-2.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Brand logo badge (fallback) */
|
||||||
|
.logo-badge {
|
||||||
|
@apply flex h-8 w-8 items-center justify-center rounded-full bg-accent text-[0.65rem] font-semibold text-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nav links */
|
||||||
|
.nav-link {
|
||||||
|
@apply text-[0.78rem] font-medium text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link:hover {
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Theme toggle */
|
||||||
|
.theme-toggle {
|
||||||
|
@apply inline-flex h-8 w-8 items-center justify-center rounded-full border border-border bg-bg text-muted shadow-sm text-[0.7rem];
|
||||||
|
transition: background-color 0.15s ease-out, color 0.15s ease-out,
|
||||||
|
transform 0.15s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-toggle:hover {
|
||||||
|
@apply text-accent;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme="dark"] .theme-toggle {
|
||||||
|
background-color: var(--color-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fancy underline link */
|
||||||
|
.link-underline {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-underline::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: -0.15rem;
|
||||||
|
width: 0;
|
||||||
|
height: 1px;
|
||||||
|
background-color: var(--color-accent);
|
||||||
|
transition: width 0.16s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-underline:hover::after {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer shell */
|
||||||
|
.footer-shell {
|
||||||
|
@apply rounded-2xl border border-border shadow-md backdrop-blur;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface) 86%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-shell::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset-inline: 0;
|
||||||
|
top: 0;
|
||||||
|
height: 1px;
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
transparent,
|
||||||
|
color-mix(in srgb, var(--color-accent) 80%, transparent),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
opacity: 0.8;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-inner {
|
||||||
|
@apply flex flex-col gap-3 px-4 py-3 text-[0.72rem] sm:flex-row sm:items-center sm:justify-between sm:px-5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-links {
|
||||||
|
@apply flex flex-wrap items-center gap-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-link {
|
||||||
|
@apply inline-flex items-center gap-1 text-[0.75rem] font-medium text-muted transition-all duration-150 ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-link:hover {
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-small {
|
||||||
|
@apply text-[0.72rem] text-muted leading-relaxed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-float:hover {
|
||||||
|
color: var(--color-accent);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-float:hover i {
|
||||||
|
filter: drop-shadow(
|
||||||
|
0 0 2px color-mix(in srgb, var(--color-accent) 60%, transparent)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
289
themes/minimal-black/assets/css/components/search.css
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
/* ==========================================================================
|
||||||
|
SEARCH OVERLAY
|
||||||
|
Search modal, search results, empty states
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.search-overlay {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 40;
|
||||||
|
display: none;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity 0.18s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-overlay--open {
|
||||||
|
opacity: 1;
|
||||||
|
display: block;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-overlay-backdrop {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: radial-gradient(
|
||||||
|
circle at top,
|
||||||
|
rgba(0, 0, 0, 0.4),
|
||||||
|
transparent 55%
|
||||||
|
),
|
||||||
|
rgba(0, 0, 0, 0.7);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-panel {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
max-width: 36rem;
|
||||||
|
margin-inline: 1.5rem;
|
||||||
|
|
||||||
|
border-radius: 1.1rem;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
background-color: color-mix(in srgb, var(--color-bg) 96%, transparent);
|
||||||
|
box-shadow: 0 26px 70px rgba(0, 0, 0, 0.85);
|
||||||
|
padding: 0.8rem 0.9rem 0.6rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-overlay--open .search-panel {
|
||||||
|
animation: search-panel-in 0.18s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-overlay-backdrop {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: radial-gradient(
|
||||||
|
circle at top,
|
||||||
|
rgba(0, 0, 0, 0.4),
|
||||||
|
transparent 55%
|
||||||
|
),
|
||||||
|
rgba(0, 0, 0, 0.7);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-overlay .search-overlay--open .search-overlay-backdrop {
|
||||||
|
animation: search-backdrop-in 0.18s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-overlay--closing .search-panel {
|
||||||
|
animation: search-panel-out 0.18s ease-in forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-overlay--closing .search-overlay-backdrop {
|
||||||
|
animation: search-backdrop-out 0.18s ease-in forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-panel-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input-wrap {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 0.45rem 0.8rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface) 96%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
flex: 1;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input::placeholder {
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-close {
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
background-color: color-mix(in srgb, var(--color-bg) 90%, transparent);
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.16s ease-out, border-color 0.16s ease-out,
|
||||||
|
color 0.16s ease-out, transform 0.16s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-close:hover {
|
||||||
|
border-color: var(--color-accent);
|
||||||
|
color: var(--color-accent);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-panel-body {
|
||||||
|
border-radius: 0.9rem;
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent);
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface) 96%, transparent);
|
||||||
|
padding: 0.5rem 0.4rem 0.4rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results {
|
||||||
|
max-height: 18rem;
|
||||||
|
padding: 0.25rem 0.15rem 0.4rem;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-empty-state {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 1.2rem 0.5rem 1.4rem;
|
||||||
|
gap: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-empty-icon {
|
||||||
|
width: 2.3rem;
|
||||||
|
height: 2.3rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
background-color: color-mix(in srgb, var(--color-bg) 92%, transparent);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-empty-title {
|
||||||
|
font-size: 0.86rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-empty-subtitle {
|
||||||
|
font-size: 0.76rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-footer-hints {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.45rem;
|
||||||
|
border-top: 1px solid
|
||||||
|
color-mix(in srgb, var(--color-border) 75%, transparent);
|
||||||
|
padding: 0.4rem 0.5rem 0.1rem;
|
||||||
|
margin-top: 0.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-hint-key {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
font-size: 0.68rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-hint-key span:first-child,
|
||||||
|
.search-hint-key span:nth-child(2) {
|
||||||
|
padding: 0.1rem 0.3rem;
|
||||||
|
border-radius: 0.3rem;
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 80%, transparent);
|
||||||
|
background-color: color-mix(in srgb, var(--color-bg) 96%, transparent);
|
||||||
|
font-size: 0.65rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-hint-key.search-hint-right {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-item {
|
||||||
|
display: block;
|
||||||
|
padding: 0.42rem 0.55rem;
|
||||||
|
border-radius: 0.6rem;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background-color 0.12s ease-out, transform 0.12s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-item:hover {
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface) 92%, transparent);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-title {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-meta {
|
||||||
|
margin-top: 0.15rem;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
}
|
||||||
|
.search-footer-hints {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.45rem;
|
||||||
|
border-top: 1px solid
|
||||||
|
color-mix(in srgb, var(--color-border) 75%, transparent);
|
||||||
|
padding: 0.4rem 0.5rem 0.1rem;
|
||||||
|
margin-top: 0.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-hint-key {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
font-size: 0.68rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-hint-key span:first-child,
|
||||||
|
.search-hint-key span:nth-child(2) {
|
||||||
|
padding: 0.1rem 0.3rem;
|
||||||
|
border-radius: 0.3rem;
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 80%, transparent);
|
||||||
|
background-color: color-mix(in srgb, var(--color-bg) 96%, transparent);
|
||||||
|
font-size: 0.65rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-hint-key.search-hint-right {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-item {
|
||||||
|
display: block;
|
||||||
|
padding: 0.42rem 0.55rem;
|
||||||
|
border-radius: 0.6rem;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background-color 0.12s ease-out, transform 0.12s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-item:hover {
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface) 92%, transparent);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-title {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-meta {
|
||||||
|
margin-top: 0.15rem;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
}
|
||||||
111
themes/minimal-black/assets/css/components/tech-marquee.css
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/* ==========================================================================
|
||||||
|
TECH MARQUEE
|
||||||
|
Technology carousel/strip component
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.tech-carousel {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 0.3rem 0.1rem 0.1rem;
|
||||||
|
overflow-x: auto;
|
||||||
|
scroll-snap-type: x mandatory;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-carousel::-webkit-scrollbar {
|
||||||
|
height: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-carousel::-webkit-scrollbar-thumb {
|
||||||
|
border-radius: 999px;
|
||||||
|
background-color: rgba(255, 255, 255, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-pill {
|
||||||
|
scroll-snap-align: start;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.4rem;
|
||||||
|
padding: 0.35rem 0.7rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
background-color: color-mix(in srgb, var(--color-surface) 92%, transparent);
|
||||||
|
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.28);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-available {
|
||||||
|
@apply inline-flex items-center gap-1.5;
|
||||||
|
padding: 0.25rem 0.7rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
background-color: var(--color-accent);
|
||||||
|
color: white;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
font-weight: 600;
|
||||||
|
box-shadow: 0 0 0.4rem rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Tech marquee --- */
|
||||||
|
.tech-icon {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-strip {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
padding-block: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-strip-track {
|
||||||
|
@apply py-2;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
animation-name: tech-marquee;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
animation-play-state: running;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-strip-track {
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-strip--wide .tech-strip-track--primary {
|
||||||
|
animation-duration: 40s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-strip--wide .tech-strip-track--secondary {
|
||||||
|
animation-duration: 40s;
|
||||||
|
animation-direction: reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-strip--compact .tech-strip-track--primary {
|
||||||
|
animation-duration: 40s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-strip--compact .tech-strip-track--secondary {
|
||||||
|
animation-duration: 48s;
|
||||||
|
animation-direction: reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-strip--compact .tech-strip-track {
|
||||||
|
gap: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pause both rows on hover */
|
||||||
|
.tech-strip:hover .tech-strip-track {
|
||||||
|
animation-play-state: paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-strip-item {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.4rem;
|
||||||
|
opacity: 0.88;
|
||||||
|
transition: opacity 0.15s ease-out, transform 0.15s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-strip-item:hover {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
1372
themes/minimal-black/assets/css/content/markdown.css
Normal file
211
themes/minimal-black/assets/css/content/toc.css
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
/* ==========================================================================
|
||||||
|
TABLE OF CONTENTS
|
||||||
|
TOC sidebar, active link tracking, responsive behavior
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.article-layout {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 2rem;
|
||||||
|
position: relative;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.article-layout {
|
||||||
|
grid-template-columns: 260px 1fr;
|
||||||
|
gap: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-toc {
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-main {
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-main {
|
||||||
|
min-width: 0;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-toc {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-wrapper {
|
||||||
|
position: sticky;
|
||||||
|
top: 2rem;
|
||||||
|
background: color-mix(in srgb, var(--color-surface) 50%, transparent);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 0.85rem;
|
||||||
|
padding: 1rem;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
transition: all 0.2s ease-out;
|
||||||
|
max-height: calc(100vh - 24rem);
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-wrapper:hover {
|
||||||
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
|
||||||
|
border-color: color-mix(in srgb, var(--color-accent) 40%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
padding-bottom: 0.75rem;
|
||||||
|
border-bottom: 1px solid color-mix(in srgb, var(--color-border) 60%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 650;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-title i {
|
||||||
|
color: var(--color-accent);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-toggle {
|
||||||
|
display: flex;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
width: 1.75rem;
|
||||||
|
height: 1.75rem;
|
||||||
|
border-radius: 0.4rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease-out;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-toggle:hover {
|
||||||
|
color: var(--color-accent);
|
||||||
|
border-color: var(--color-accent);
|
||||||
|
background: color-mix(in srgb, var(--color-accent) 10%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-toggle i {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
transition: transform 0.2s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-wrapper.collapsed .toc-toggle i {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-wrapper.collapsed .toc-nav {
|
||||||
|
max-height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1023px) {
|
||||||
|
.toc-wrapper {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-nav {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
transition: all 0.3s ease-out;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom scrollbar for TOC */
|
||||||
|
.toc-nav::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-nav::-webkit-scrollbar-track {
|
||||||
|
background: color-mix(in srgb, var(--color-bg) 30%, transparent);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-nav::-webkit-scrollbar-thumb {
|
||||||
|
background: color-mix(in srgb, var(--color-border) 70%, transparent);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-nav::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-nav > ul {
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-nav ul {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-nav ul ul {
|
||||||
|
padding-left: 1rem;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
border-left: 1px solid color-mix(in srgb, var(--color-border) 50%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-nav li {
|
||||||
|
margin: 0.35rem 0;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-nav li:hover {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-nav a {
|
||||||
|
display: block;
|
||||||
|
padding: 0.35rem 0.5rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
text-decoration: none;
|
||||||
|
border-left: 2px solid transparent;
|
||||||
|
border-radius: 0.35rem;
|
||||||
|
transition: all 0.15s ease-out;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-nav a:hover {
|
||||||
|
color: var(--color-text);
|
||||||
|
background: color-mix(in srgb, var(--color-surface) 40%, transparent);
|
||||||
|
border-left-color: var(--color-accent);
|
||||||
|
transform: translateX(3px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-nav a.active {
|
||||||
|
color: var(--color-accent);
|
||||||
|
background: color-mix(in srgb, var(--color-accent) 12%, transparent);
|
||||||
|
border-left-color: var(--color-accent);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile: TOC appears at top */
|
||||||
|
@media (max-width: 1023px) {
|
||||||
|
.article-toc {
|
||||||
|
order: -1;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
28
themes/minimal-black/assets/css/main.css
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/* ==========================================================================
|
||||||
|
MINIMAL BLACK THEME - MAIN STYLESHEET
|
||||||
|
A minimal, dark-mode first Hugo theme
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/* Base Styles & Tailwind */
|
||||||
|
@import "base.css";
|
||||||
|
|
||||||
|
/* Utility Classes */
|
||||||
|
@import "utilities.css";
|
||||||
|
|
||||||
|
/* Components */
|
||||||
|
@import "components/dock.css";
|
||||||
|
@import "components/cards.css";
|
||||||
|
@import "components/navigation.css";
|
||||||
|
@import "components/search.css";
|
||||||
|
@import "components/tech-marquee.css";
|
||||||
|
|
||||||
|
/* Content */
|
||||||
|
@import "content/markdown.css";
|
||||||
|
@import "content/toc.css";
|
||||||
|
|
||||||
|
/* Pages */
|
||||||
|
@import "pages/about.css";
|
||||||
|
@import "pages/about-alternative.css";
|
||||||
|
|
||||||
|
/* Responsive Styles */
|
||||||
|
@import "responsive.css";
|
||||||
363
themes/minimal-black/assets/css/pages/about-alternative.css
Normal file
@@ -0,0 +1,363 @@
|
|||||||
|
/* ==========================================================================
|
||||||
|
ABOUT ALTERNATIVE PAGE STYLES
|
||||||
|
Alternative about page with sidebar profile card
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.page-int, .about-alt-page {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-layout {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 2rem;
|
||||||
|
padding: 2rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.about-alt-layout {
|
||||||
|
grid-template-columns: 320px 1fr;
|
||||||
|
gap: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Profile Card - Left Sidebar */
|
||||||
|
.about-alt-sidebar {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-profile-card {
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
color-mix(in srgb, var(--color-surface) 70%, transparent),
|
||||||
|
color-mix(in srgb, var(--color-surface) 50%, transparent)
|
||||||
|
);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 60%, transparent);
|
||||||
|
border-radius: 1.5rem;
|
||||||
|
padding: 2rem;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
|
||||||
|
position: sticky;
|
||||||
|
top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-avatar,
|
||||||
|
.about-alt-avatar-placeholder {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin: 0 auto 1.5rem;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 4px solid var(--color-accent);
|
||||||
|
box-shadow: 0 0 0 8px color-mix(in srgb, var(--color-accent) 15%, transparent);
|
||||||
|
transition: all 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-avatar:hover,
|
||||||
|
.about-alt-avatar-placeholder:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 0 0 12px color-mix(in srgb, var(--color-accent) 20%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-avatar img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-avatar-placeholder {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
color-mix(in srgb, var(--color-accent) 30%, transparent),
|
||||||
|
color-mix(in srgb, var(--color-accent) 15%, transparent)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-avatar-placeholder i {
|
||||||
|
font-size: 3rem;
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-name {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-role {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
line-height: 1.5;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-meta i {
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stats Grid */
|
||||||
|
.about-alt-stats {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 1rem;
|
||||||
|
margin: 2rem 0;
|
||||||
|
padding: 1.5rem 0;
|
||||||
|
border-top: 1px solid color-mix(in srgb, var(--color-border) 50%, transparent);
|
||||||
|
border-bottom: 1px solid color-mix(in srgb, var(--color-border) 50%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-stat {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-stat-value {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--color-accent);
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-stat-label {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Social Icons */
|
||||||
|
.about-alt-social {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-social-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 2.5rem;
|
||||||
|
height: 2.5rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: color-mix(in srgb, var(--color-bg) 50%, transparent);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 60%, transparent);
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
transition: all 0.2s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-social-icon:hover {
|
||||||
|
background: var(--color-accent);
|
||||||
|
border-color: var(--color-accent);
|
||||||
|
color: white;
|
||||||
|
transform: translateY(-3px);
|
||||||
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-social-icon i {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Content Area */
|
||||||
|
.about-alt-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-section {
|
||||||
|
background: color-mix(in srgb, var(--color-surface) 40%, transparent);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 60%, transparent);
|
||||||
|
border-radius: 1.25rem;
|
||||||
|
padding: 2rem;
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-section-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
border-bottom: 2px solid color-mix(in srgb, var(--color-accent) 20%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-section-title i {
|
||||||
|
color: var(--color-accent);
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Experience Cards Grid */
|
||||||
|
.about-alt-experience-grid {
|
||||||
|
display: grid;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-experience-card {
|
||||||
|
background: color-mix(in srgb, var(--color-bg) 40%, transparent);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 50%, transparent);
|
||||||
|
border-left: 4px solid var(--color-accent);
|
||||||
|
border-radius: 0.85rem;
|
||||||
|
padding: 1.5rem;
|
||||||
|
transition: all 0.3s ease-out;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-experience-card::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
background: radial-gradient(
|
||||||
|
circle at center,
|
||||||
|
color-mix(in srgb, var(--color-accent) 10%, transparent),
|
||||||
|
transparent 70%
|
||||||
|
);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-experience-card:hover {
|
||||||
|
border-left-width: 6px;
|
||||||
|
transform: translateX(6px);
|
||||||
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-experience-card:hover::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-experience-card p:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-experience-card p:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-experience-card strong {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: var(--color-text);
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-experience-card em {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
font-style: normal;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skills Badge Cloud */
|
||||||
|
.about-alt-skills {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-skill {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
background: color-mix(in srgb, var(--color-bg) 50%, transparent);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 60%, transparent);
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text);
|
||||||
|
transition: all 0.2s ease-out;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-skill i {
|
||||||
|
font-size: 1.1em;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-skill:hover {
|
||||||
|
background: var(--color-accent);
|
||||||
|
border-color: var(--color-accent);
|
||||||
|
color: white;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-skill:hover i {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 1023px) {
|
||||||
|
.about-alt-profile-card {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-layout {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.about-alt-profile-card {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-avatar,
|
||||||
|
.about-alt-avatar-placeholder {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-name {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-stats {
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-stat-value {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-section {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-section-title {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-alt-experience-card {
|
||||||
|
padding: 1.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================== */
|
||||||
|
/* TABLE OF CONTENTS */
|
||||||
|
/* ==================== */
|
||||||
|
|
||||||
380
themes/minimal-black/assets/css/pages/about.css
Normal file
@@ -0,0 +1,380 @@
|
|||||||
|
/* ==========================================================================
|
||||||
|
ABOUT PAGE STYLES
|
||||||
|
Standard about page with timeline
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.about-page {
|
||||||
|
max-width: 900px;
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-hero {
|
||||||
|
text-align: center;
|
||||||
|
padding: 3rem 0 4rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-hero::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 60px;
|
||||||
|
height: 3px;
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
transparent,
|
||||||
|
var(--color-accent),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-hero-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-avatar,
|
||||||
|
.about-avatar-placeholder {
|
||||||
|
width: 140px;
|
||||||
|
height: 140px;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 3px solid var(--color-accent);
|
||||||
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2),
|
||||||
|
0 0 0 8px color-mix(in srgb, var(--color-accent) 15%, transparent);
|
||||||
|
transition: all 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-avatar:hover,
|
||||||
|
.about-avatar-placeholder:hover {
|
||||||
|
transform: translateY(-4px) scale(1.02);
|
||||||
|
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.3),
|
||||||
|
0 0 0 12px color-mix(in srgb, var(--color-accent) 20%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-avatar img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-avatar-placeholder {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
color-mix(in srgb, var(--color-accent) 20%, transparent),
|
||||||
|
color-mix(in srgb, var(--color-accent) 10%, transparent)
|
||||||
|
);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-avatar-placeholder i {
|
||||||
|
font-size: 4rem;
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-title {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-subtitle {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
max-width: 600px;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-content {
|
||||||
|
margin-bottom: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-content .card {
|
||||||
|
background: color-mix(in srgb, var(--color-surface) 60%, transparent);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent);
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-content .markdown-body h3 {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin-top: 2.5rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
border-bottom: 2px solid color-mix(in srgb, var(--color-accent) 30%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-content .markdown-body h3::before {
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
width: 4px;
|
||||||
|
height: 1.5rem;
|
||||||
|
background: var(--color-accent);
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Timeline */
|
||||||
|
.timeline {
|
||||||
|
position: relative;
|
||||||
|
padding: 2rem 0 1rem 0;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 20px;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 2px;
|
||||||
|
background: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
transparent,
|
||||||
|
var(--color-accent) 10%,
|
||||||
|
var(--color-accent) 90%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-item {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 60px;
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-item:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-marker {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 8px;
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-marker::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
background: var(--color-accent);
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid var(--color-bg);
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 4px color-mix(in srgb, var(--color-accent) 20%, transparent),
|
||||||
|
0 4px 12px rgba(0, 0, 0, 0.3);
|
||||||
|
transition: all 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-item:hover .timeline-marker::before {
|
||||||
|
transform: scale(1.3);
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 6px color-mix(in srgb, var(--color-accent) 30%, transparent),
|
||||||
|
0 6px 16px rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-content {
|
||||||
|
background: color-mix(in srgb, var(--color-surface) 30%, transparent);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 50%, transparent);
|
||||||
|
border-radius: 0.85rem;
|
||||||
|
padding: 1.5rem;
|
||||||
|
transition: all 0.3s ease-out;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-content::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 4px;
|
||||||
|
background: var(--color-accent);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-item:hover .timeline-content {
|
||||||
|
background: color-mix(in srgb, var(--color-surface) 50%, transparent);
|
||||||
|
border-color: color-mix(in srgb, var(--color-accent) 40%, transparent);
|
||||||
|
transform: translateX(4px);
|
||||||
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-item:hover .timeline-content::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-content > p:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-content > p:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-content strong {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: var(--color-text);
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-content em {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
font-style: normal;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-content a {
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove hr from timeline */
|
||||||
|
.timeline hr {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-social {
|
||||||
|
text-align: center;
|
||||||
|
padding: 3rem 2rem;
|
||||||
|
background: color-mix(in srgb, var(--color-surface) 40%, transparent);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 60%, transparent);
|
||||||
|
border-radius: 1.25rem;
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-social-title {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 650;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-social-links {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-social-link {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: color-mix(in srgb, var(--color-bg) 60%, transparent);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent);
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all 0.2s ease-out;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-social-link:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
background: color-mix(in srgb, var(--color-surface) 80%, transparent);
|
||||||
|
border-color: var(--color-accent);
|
||||||
|
color: var(--color-accent);
|
||||||
|
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-social-link i {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive about page */
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.about-hero {
|
||||||
|
padding: 2rem 0 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-avatar,
|
||||||
|
.about-avatar-placeholder {
|
||||||
|
width: 110px;
|
||||||
|
height: 110px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-avatar-placeholder i {
|
||||||
|
font-size: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-title {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-subtitle {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-social {
|
||||||
|
padding: 2rem 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-social-links {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-social-link {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Timeline responsive */
|
||||||
|
.timeline::before {
|
||||||
|
left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-item {
|
||||||
|
padding-left: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-marker {
|
||||||
|
left: -5px;
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-marker::before {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-content {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-content strong {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-content em {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
277
themes/minimal-black/assets/css/responsive.css
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
/* ==========================================================================
|
||||||
|
RESPONSIVE STYLES
|
||||||
|
Global responsive breakpoints and mobile optimizations
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/* Mobile - Small screens (up to 640px) */
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.card-pad {
|
||||||
|
padding: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-page {
|
||||||
|
padding-inline: 1rem;
|
||||||
|
padding-block: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-page-tight {
|
||||||
|
padding-inline: 1rem;
|
||||||
|
padding-block: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Markdown body */
|
||||||
|
.markdown-body {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Headings - scale down for mobile */
|
||||||
|
.markdown-body h1 {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h2 {
|
||||||
|
font-size: 1.35rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h3 {
|
||||||
|
font-size: 1.15rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h4 {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h5,
|
||||||
|
.markdown-body h6 {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Heading anchors - adjust for smaller screens */
|
||||||
|
.markdown-body .md-heading-anchor::before {
|
||||||
|
left: -1rem;
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Blockquotes */
|
||||||
|
.markdown-body blockquote,
|
||||||
|
.markdown-body .md-blockquote {
|
||||||
|
margin: 1.25rem 0;
|
||||||
|
padding: 1rem;
|
||||||
|
border-left-width: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body blockquote::before,
|
||||||
|
.markdown-body .md-blockquote::before {
|
||||||
|
font-size: 2rem;
|
||||||
|
left: 0.5rem;
|
||||||
|
top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alerts */
|
||||||
|
.markdown-body .md-alert {
|
||||||
|
padding: 0.85rem 1rem 0.85rem 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .md-alert::before {
|
||||||
|
left: 0.75rem;
|
||||||
|
top: 0.95rem;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lists */
|
||||||
|
.markdown-body ul,
|
||||||
|
.markdown-body ol {
|
||||||
|
padding-left: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Code blocks */
|
||||||
|
.markdown-body pre {
|
||||||
|
margin: 1rem -1rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre code {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-codeblock {
|
||||||
|
margin: 1.25rem -1rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-codeblock-content pre {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-codeblock-content pre code {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inline code */
|
||||||
|
.markdown-body :not(pre) > code {
|
||||||
|
font-size: 0.85em;
|
||||||
|
padding: 0.1rem 0.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tables - full bleed on mobile */
|
||||||
|
.markdown-body table {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body th,
|
||||||
|
.markdown-body td {
|
||||||
|
padding: 0.5rem 0.65rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .table-wrap {
|
||||||
|
margin: 1.25rem -1rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Images */
|
||||||
|
.markdown-body img,
|
||||||
|
.markdown-body .md-image {
|
||||||
|
margin: 1.25rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .md-image a {
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .md-image a::after {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .md-image figcaption {
|
||||||
|
font-size: 0.82rem;
|
||||||
|
padding: 0.4rem 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Page heading */
|
||||||
|
.heading-page {
|
||||||
|
font-size: 1.75rem !important;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Article header */
|
||||||
|
.article-main header {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TOC on mobile */
|
||||||
|
.toc-wrapper {
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
padding: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-nav {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tablet - Medium screens (641px to 1023px) */
|
||||||
|
@media (min-width: 641px) and (max-width: 1023px) {
|
||||||
|
.article-layout {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-main {
|
||||||
|
max-width: -webkit-fill-available;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-page {
|
||||||
|
padding-inline: 1.5rem;
|
||||||
|
padding-block: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body {
|
||||||
|
font-size: 0.93rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1 {
|
||||||
|
font-size: 1.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h2 {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h3 {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Larger screens - Adjust max-widths */
|
||||||
|
@media (min-width: 1536px) {
|
||||||
|
.article-layout {
|
||||||
|
padding-inline: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ultra-wide screens */
|
||||||
|
@media (min-width: 1920px) {
|
||||||
|
.markdown-body {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Touch device improvements */
|
||||||
|
@media (hover: none) and (pointer: coarse) {
|
||||||
|
/* Increase tap targets for touch */
|
||||||
|
.toc-nav a {
|
||||||
|
padding: 0.5rem 0.65rem;
|
||||||
|
margin: 0.15rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-toggle {
|
||||||
|
width: 2.5rem;
|
||||||
|
height: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-action-btn {
|
||||||
|
padding: 0.5rem 0.85rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove hover effects on touch devices */
|
||||||
|
.markdown-body li:hover {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-hover:hover {
|
||||||
|
transform: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Landscape mobile */
|
||||||
|
@media (max-height: 500px) and (orientation: landscape) {
|
||||||
|
.toc-wrapper {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-page {
|
||||||
|
padding-block: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
.prose {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose a {
|
||||||
|
color: var(--color-accent);
|
||||||
|
text-decoration-color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose strong {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
}
|
||||||
95
themes/minimal-black/assets/css/utilities.css
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/* ==========================================================================
|
||||||
|
UTILITY CLASSES
|
||||||
|
Color utilities, animations, helper classes
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.bg-bg {
|
||||||
|
background-color: var(--color-bg);
|
||||||
|
}
|
||||||
|
.bg-surface {
|
||||||
|
background-color: var(--color-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-text {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
.text-muted {
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
}
|
||||||
|
.text-accent {
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-border {
|
||||||
|
border-color: var(--color-border);
|
||||||
|
}
|
||||||
|
.border-accent {
|
||||||
|
border-color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-accent {
|
||||||
|
background-color: var(--color-accent);
|
||||||
|
}
|
||||||
|
.underline-accent {
|
||||||
|
text-decoration-color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simple fade-up animation */
|
||||||
|
@keyframes fade-up {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(8px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fade-up {
|
||||||
|
animation: fade-up 0.45s ease-out both;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes search-panel-in {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(-50%, -48%) scale(0.97);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate(-50%, -50%) scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes search-backdrop-in {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes search-panel-out {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate(-50%, -50%) scale(1);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(-50%, -48%) scale(0.97);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes search-backdrop-out {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@layer components { }
|
||||||
|
/* Layout helpers */
|
||||||
0
themes/minimal-black/exampleSite/content/_index.md
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
+++
|
||||||
|
title = "About Me"
|
||||||
|
subtitle = "Software Engineer | Full Stack Developer | Open Source Enthusiast"
|
||||||
|
layout = "about-alternative"
|
||||||
|
+++
|
||||||
|
|
||||||
|
I'm a software engineer passionate about building elegant solutions to complex problems. Currently working on modern web applications and exploring the intersection of design, performance, and developer experience.
|
||||||
|
|
||||||
|
## What I Do
|
||||||
|
|
||||||
|
I work across the full stack with expertise in:
|
||||||
|
|
||||||
|
- **Backend Development** — Scalable APIs, microservices, database design
|
||||||
|
- **Frontend Engineering** — React, Vue, modern JavaScript frameworks
|
||||||
|
- **Cloud & DevOps** — AWS, Docker, Kubernetes, CI/CD pipelines
|
||||||
|
- **Open Source** — Contributing to projects and building developer tools
|
||||||
|
|
||||||
|
## Current Projects
|
||||||
|
|
||||||
|
Right now I'm focused on:
|
||||||
|
|
||||||
|
- Building minimal Hugo themes for personal sites
|
||||||
|
- Exploring dark-mode design patterns and accessibility
|
||||||
|
- Writing about web performance and developer experience
|
||||||
|
- Contributing to open-source projects in the web ecosystem
|
||||||
|
|
||||||
|
## About This Layout
|
||||||
|
|
||||||
|
> This page demonstrates the **alternative about layout** with a sidebar profile card.
|
||||||
|
|
||||||
|
### Key Features
|
||||||
|
|
||||||
|
This layout includes:
|
||||||
|
|
||||||
|
1. **Left Sidebar Profile Card** with:
|
||||||
|
- Avatar/profile image (or placeholder icon)
|
||||||
|
- Name and role
|
||||||
|
- Location indicator
|
||||||
|
- Customizable stats (configured in `hugo.toml`)
|
||||||
|
- Social media links
|
||||||
|
|
||||||
|
2. **Main Content Area** with:
|
||||||
|
- Introduction section
|
||||||
|
- Experience cards (from `---` separators)
|
||||||
|
- Tech stack badges (configured in `hugo.toml`)
|
||||||
|
|
||||||
|
### How to Configure
|
||||||
|
|
||||||
|
**Stats and Skills** are parametrized in your `hugo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[params.about.alt]
|
||||||
|
# Custom stats
|
||||||
|
[[params.about.alt.stats]]
|
||||||
|
value = "5+"
|
||||||
|
label = "Years Coding"
|
||||||
|
|
||||||
|
# Tech stack with icons
|
||||||
|
[[params.about.alt.skills]]
|
||||||
|
label = "JavaScript"
|
||||||
|
icon = "devicon-javascript-plain"
|
||||||
|
```
|
||||||
|
|
||||||
|
This makes it easy to update your stats and skills without editing this page!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Lead Developer** — [Modern Tech Co](https://example.com)
|
||||||
|
*2022 – Present • Remote*
|
||||||
|
|
||||||
|
Leading development of cloud-native applications and mentoring engineering teams. Focus on scalable architecture, clean code practices, and continuous delivery.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Senior Engineer** — Startup Ventures
|
||||||
|
*2020 – 2022 • San Francisco*
|
||||||
|
|
||||||
|
Built full-stack applications from scratch. Worked with React, Node.js, PostgreSQL, and AWS to deliver features serving hundreds of thousands of users.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Software Engineer** — Digital Solutions
|
||||||
|
*2018 – 2020 • New York*
|
||||||
|
|
||||||
|
Developed enterprise applications using Java, Spring Boot, and modern frontend frameworks. Collaborated with cross-functional teams to ship quality software.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Junior Developer** — Tech Academy
|
||||||
|
*2016 – 2018 • Boston*
|
||||||
|
|
||||||
|
Started my career building web applications and learning industry best practices. Contributed to client projects and internal tooling.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Layout Comparison
|
||||||
|
|
||||||
|
| Feature | Standard About | Alternative About |
|
||||||
|
|---------|---------------|-------------------|
|
||||||
|
| Layout | Centered, single column | Sidebar + content |
|
||||||
|
| Profile Info | Top hero section | Left sidebar card |
|
||||||
|
| Stats | Not included | Configurable stats grid |
|
||||||
|
| Tech Stack | Not included | Icon badges |
|
||||||
|
| Timeline | Vertical with markers | Card-based grid |
|
||||||
|
| Best For | Traditional resumes | Modern portfolios |
|
||||||
|
|
||||||
|
Try both layouts to see which fits your style! Switch by changing `layout = "about"` or `layout = "about-alternative"` in the frontmatter.
|
||||||
|
|
||||||
|
### Responsive Design
|
||||||
|
|
||||||
|
Both layouts are fully responsive:
|
||||||
|
- **Desktop:** Sidebar + content (alternative) or centered (standard)
|
||||||
|
- **Tablet:** Stacked layout with adjusted spacing
|
||||||
|
- **Mobile:** Single column, optimized for small screens
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Get Started
|
||||||
|
|
||||||
|
To use this layout on your site:
|
||||||
|
|
||||||
|
1. Copy this content file structure
|
||||||
|
2. Set `layout = "about-alternative"` in frontmatter
|
||||||
|
3. Configure stats and skills in `hugo.toml`
|
||||||
|
4. Add your own content and experience
|
||||||
|
5. Optionally add an avatar image to `static/images/`
|
||||||
|
|
||||||
|
That's it! The theme handles all the styling and responsive behavior automatically.
|
||||||
111
themes/minimal-black/exampleSite/content/about/_index.md
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
+++
|
||||||
|
title = "About Me"
|
||||||
|
subtitle = "Software Engineer | Full Stack Developer | Open Source Enthusiast"
|
||||||
|
layout = "about"
|
||||||
|
+++
|
||||||
|
|
||||||
|
I'm a passionate software engineer with expertise in building scalable web applications and developer tools. With a focus on clean code, performance optimization, and user experience, I help teams ship products that users love.
|
||||||
|
|
||||||
|
## What I Do
|
||||||
|
|
||||||
|
I specialize in full-stack development with a keen interest in:
|
||||||
|
|
||||||
|
- **Backend Engineering** — Building robust APIs and microservices with modern frameworks
|
||||||
|
- **Frontend Development** — Creating responsive, accessible user interfaces
|
||||||
|
- **DevOps & Infrastructure** — Container orchestration, CI/CD, and cloud platforms
|
||||||
|
- **Open Source** — Contributing to and maintaining open-source projects
|
||||||
|
|
||||||
|
## Timeline Demonstration
|
||||||
|
|
||||||
|
> This page demonstrates the **standard about layout** with a timeline feature. Use horizontal rules (`---`) to separate timeline entries. Each section becomes a card in the timeline visualization.
|
||||||
|
|
||||||
|
### Current Focus
|
||||||
|
|
||||||
|
Right now, I'm exploring minimal design patterns, modern web frameworks, and building tools that make developers' lives easier. I believe in writing code that is simple, maintainable, and well-documented.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Senior Software Engineer** — [Tech Company](https://example.com)
|
||||||
|
*January 2022 – Present • Remote*
|
||||||
|
|
||||||
|
Leading the development of cloud-native applications using modern frameworks and best practices. Mentoring junior developers and driving technical decisions for large-scale projects.
|
||||||
|
|
||||||
|
Key achievements:
|
||||||
|
- Architected microservices platform serving 1M+ users
|
||||||
|
- Reduced deployment time by 60% through CI/CD improvements
|
||||||
|
- Led migration from monolith to distributed architecture
|
||||||
|
|
||||||
|
**Technologies:** React, Node.js, PostgreSQL, Docker, Kubernetes, AWS
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Full Stack Developer** — Startup Inc.
|
||||||
|
*March 2020 – December 2021 • San Francisco, CA*
|
||||||
|
|
||||||
|
Developed and maintained multiple web applications from concept to production. Collaborated with cross-functional teams to deliver features that increased user engagement by 40%.
|
||||||
|
|
||||||
|
- Built RESTful APIs serving 500K+ daily requests
|
||||||
|
- Implemented real-time features using WebSockets
|
||||||
|
- Optimized database queries reducing response time by 50%
|
||||||
|
|
||||||
|
**Technologies:** Python, Django, Vue.js, Redis, MySQL, GCP
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Software Engineer** — Digital Solutions Corp.
|
||||||
|
*June 2018 – February 2020 • New York, NY*
|
||||||
|
|
||||||
|
Worked on enterprise solutions for Fortune 500 clients. Focused on backend development, database design, and system integration.
|
||||||
|
|
||||||
|
- Developed internal tools that saved 200+ hours monthly
|
||||||
|
- Integrated third-party APIs for payment processing
|
||||||
|
- Maintained legacy systems while modernizing architecture
|
||||||
|
|
||||||
|
**Technologies:** Java, Spring Boot, Oracle DB, Angular, Jenkins
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Junior Developer** — Code Academy
|
||||||
|
*January 2017 – May 2018 • Boston, MA*
|
||||||
|
|
||||||
|
Started my professional journey building web applications and learning industry best practices. Contributed to various client projects and internal tooling.
|
||||||
|
|
||||||
|
- Developed responsive web interfaces
|
||||||
|
- Wrote automated tests achieving 90%+ coverage
|
||||||
|
- Participated in code reviews and agile ceremonies
|
||||||
|
|
||||||
|
**Technologies:** JavaScript, PHP, Laravel, MySQL, Git
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Education & Certifications
|
||||||
|
|
||||||
|
**Bachelor of Science in Computer Science**
|
||||||
|
University of Technology • 2013-2017
|
||||||
|
|
||||||
|
**Certifications:**
|
||||||
|
- AWS Certified Solutions Architect
|
||||||
|
- Google Cloud Professional Developer
|
||||||
|
- Certified Kubernetes Administrator (CKA)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How This Layout Works
|
||||||
|
|
||||||
|
This about page uses the **timeline layout**. Here's how to customize it:
|
||||||
|
|
||||||
|
1. Set `layout = "about"` in the frontmatter
|
||||||
|
2. Write your introduction before the first `---` separator
|
||||||
|
3. Each section after `---` becomes a timeline card
|
||||||
|
4. Use markdown formatting: **bold** for job titles, *italic* for dates
|
||||||
|
5. Add links using `[text](url)` syntax
|
||||||
|
6. Timeline items appear in chronological order (newest first)
|
||||||
|
|
||||||
|
### Features Demonstrated
|
||||||
|
|
||||||
|
- ✅ Hero section with avatar and subtitle
|
||||||
|
- ✅ Timeline visualization with markers and cards
|
||||||
|
- ✅ Markdown content with formatting
|
||||||
|
- ✅ Links and emphasis
|
||||||
|
- ✅ Responsive design
|
||||||
|
- ✅ Social links in footer
|
||||||
592
themes/minimal-black/exampleSite/content/blog/theme-guide.md
Normal file
@@ -0,0 +1,592 @@
|
|||||||
|
+++
|
||||||
|
title = "Complete Guide to Minimal Black Theme"
|
||||||
|
date = "2025-01-15"
|
||||||
|
author = "Jim Christopoulos"
|
||||||
|
tags = ["hugo", "tutorial", "guide", "theme"]
|
||||||
|
categories = ["documentation"]
|
||||||
|
description = "A comprehensive guide to all features and capabilities of the Minimal Black Hugo theme"
|
||||||
|
draft = false
|
||||||
|
+++
|
||||||
|
|
||||||
|
Welcome to the complete guide for the Minimal Black Hugo theme!
|
||||||
|
|
||||||
|
This post demonstrates all the features, components, and customization options available in the theme.
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
Minimal Black is designed for developers, designers, and everybody who want a clean, fast, and beautiful personal website.
|
||||||
|
|
||||||
|
This guide will walk you through every feature with examples you can use in your own content.
|
||||||
|
|
||||||
|
## Typography & Text Formatting
|
||||||
|
|
||||||
|
### Headings
|
||||||
|
|
||||||
|
The theme supports all six heading levels with proper hierarchy and spacing:
|
||||||
|
|
||||||
|
# Heading 1
|
||||||
|
## Heading 2
|
||||||
|
### Heading 3
|
||||||
|
#### Heading 4
|
||||||
|
##### Heading 5
|
||||||
|
###### Heading 6
|
||||||
|
|
||||||
|
Each heading automatically gets an anchor link (hover to see the # symbol) for easy linking.
|
||||||
|
|
||||||
|
### Text Emphasis
|
||||||
|
|
||||||
|
Use standard Markdown for text formatting:
|
||||||
|
|
||||||
|
- **Bold text** for emphasis
|
||||||
|
- *Italic text* for subtle emphasis
|
||||||
|
- ***Bold and italic*** for strong emphasis
|
||||||
|
- ~~Strikethrough~~ for deleted content
|
||||||
|
- `Inline code` for code references
|
||||||
|
|
||||||
|
You can also ==highlight text== using the mark syntax (if enabled in your config).
|
||||||
|
|
||||||
|
### Links
|
||||||
|
|
||||||
|
Links are styled with subtle hover effects:
|
||||||
|
|
||||||
|
- [External link](https://example.com)
|
||||||
|
|
||||||
|
## Lists
|
||||||
|
|
||||||
|
### Unordered Lists
|
||||||
|
|
||||||
|
Simple bullet lists:
|
||||||
|
|
||||||
|
- First item
|
||||||
|
- Second item
|
||||||
|
- Nested item 1
|
||||||
|
- Nested item 2
|
||||||
|
- Deeply nested item
|
||||||
|
- Third item
|
||||||
|
|
||||||
|
### Ordered Lists
|
||||||
|
|
||||||
|
Numbered lists:
|
||||||
|
|
||||||
|
1. First step
|
||||||
|
2. Second step
|
||||||
|
1. Sub-step A
|
||||||
|
2. Sub-step B
|
||||||
|
3. Third step
|
||||||
|
|
||||||
|
### Task Lists
|
||||||
|
|
||||||
|
Interactive checkboxes:
|
||||||
|
|
||||||
|
- [x] Completed task
|
||||||
|
- [x] Another completed item
|
||||||
|
- [ ] Pending task
|
||||||
|
- [ ] Another pending item
|
||||||
|
- [x] Nested completed
|
||||||
|
- [ ] Nested pending
|
||||||
|
|
||||||
|
Task lists are great for project planning, feature tracking, or tutorial steps.
|
||||||
|
|
||||||
|
### Definition Lists
|
||||||
|
|
||||||
|
For glossary-style content:
|
||||||
|
|
||||||
|
Hugo
|
||||||
|
: A fast static site generator written in Go
|
||||||
|
|
||||||
|
Markdown
|
||||||
|
: A lightweight markup language for formatting text
|
||||||
|
|
||||||
|
Tailwind CSS
|
||||||
|
: A utility-first CSS framework
|
||||||
|
|
||||||
|
## Blockquotes
|
||||||
|
|
||||||
|
### Standard Blockquotes
|
||||||
|
|
||||||
|
Simple quotes with gradient background:
|
||||||
|
|
||||||
|
> This is a standard blockquote. It has a subtle gradient background and a colored left border for visual distinction.
|
||||||
|
|
||||||
|
> Multi-paragraph blockquotes work too.
|
||||||
|
>
|
||||||
|
> They maintain proper spacing between paragraphs while keeping the unified look.
|
||||||
|
|
||||||
|
### Nested Blockquotes
|
||||||
|
|
||||||
|
You can nest quotes:
|
||||||
|
|
||||||
|
> This is the outer quote.
|
||||||
|
>
|
||||||
|
> > This is a nested quote inside.
|
||||||
|
> >
|
||||||
|
> > > You can nest multiple levels.
|
||||||
|
|
||||||
|
### GitHub-Style Alerts
|
||||||
|
|
||||||
|
The theme supports GitHub-flavored alert callouts:
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> This is a note callout. Use it for informational content that readers should be aware of.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> This is a tip callout. Perfect for helpful suggestions and best practices.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> This is an important callout. Use it for critical information that must not be missed.
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> This is a warning callout. Great for cautionary information and potential pitfalls.
|
||||||
|
|
||||||
|
> [!CAUTION]
|
||||||
|
> This is a caution callout. Use for dangerous actions or critical warnings.
|
||||||
|
|
||||||
|
## Code Blocks
|
||||||
|
|
||||||
|
### Inline Code
|
||||||
|
|
||||||
|
Reference code inline with `backticks`.
|
||||||
|
|
||||||
|
Great for mentioning `variables`, `functions()`, or `file-names.txt`.
|
||||||
|
|
||||||
|
### Basic Code Blocks
|
||||||
|
|
||||||
|
Simple code blocks without syntax highlighting:
|
||||||
|
|
||||||
|
```
|
||||||
|
This is a plain code block.
|
||||||
|
No syntax highlighting.
|
||||||
|
Perfect for plain text or output.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Syntax Highlighted Code
|
||||||
|
|
||||||
|
The theme supports syntax highlighting for dozens of languages:
|
||||||
|
|
||||||
|
**JavaScript:**
|
||||||
|
```javascript
|
||||||
|
|
||||||
|
const greet = (name) => {
|
||||||
|
console.log(`Hello, ${name}!`);
|
||||||
|
return `Welcome to the Minimal Black theme`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Async/await example
|
||||||
|
async function fetchData(url) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(url);
|
||||||
|
const data = await response.json();
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching data:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Python:**
|
||||||
|
```python
|
||||||
|
def fibonacci(n):
|
||||||
|
"""Calculate fibonacci number recursively."""
|
||||||
|
if n <= 1:
|
||||||
|
return n
|
||||||
|
return fibonacci(n-1) + fibonacci(n-2)
|
||||||
|
|
||||||
|
# List comprehension example
|
||||||
|
squares = [x**2 for x in range(10)]
|
||||||
|
print(squares)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Go:**
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Simple HTTP server
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintf(w, "Hello, World!")
|
||||||
|
})
|
||||||
|
|
||||||
|
http.ListenAndServe(":8080", nil)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Bash:**
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Deploy script
|
||||||
|
hugo --minify
|
||||||
|
rsync -avz public/ user@server:/var/www/
|
||||||
|
echo "Deployment complete!"
|
||||||
|
```
|
||||||
|
|
||||||
|
**CSS:**
|
||||||
|
```css
|
||||||
|
/* Dark theme variables */
|
||||||
|
:root {
|
||||||
|
--color-bg: #000000;
|
||||||
|
--color-accent: #c084fc;
|
||||||
|
--transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
background: var(--color-accent);
|
||||||
|
transition: var(--transition);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**HTML:**
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Minimal Black</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Welcome!</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code Block Features
|
||||||
|
|
||||||
|
All code blocks include:
|
||||||
|
|
||||||
|
- **Language Label** — Shows the language in top-right corner
|
||||||
|
- **Copy Button** — Click to copy code to clipboard
|
||||||
|
- **Line Numbers** — Optional (configure in hugo.toml)
|
||||||
|
- **Syntax Highlighting** — Powered by Hugo's Chroma
|
||||||
|
|
||||||
|
## Tables
|
||||||
|
|
||||||
|
### Basic Tables
|
||||||
|
|
||||||
|
| Feature | Supported | Notes |
|
||||||
|
|---------|-----------|-------|
|
||||||
|
| Dark Mode | ✅ | True black backgrounds |
|
||||||
|
| Search | ✅ | Client-side, fast |
|
||||||
|
| TOC | ✅ | Auto-generated |
|
||||||
|
| Analytics | ✅ | Multiple providers |
|
||||||
|
|
||||||
|
### Aligned Columns
|
||||||
|
|
||||||
|
| Left Aligned | Center Aligned | Right Aligned |
|
||||||
|
|:-------------|:--------------:|--------------:|
|
||||||
|
| Left | Center | Right |
|
||||||
|
| Text | Text | 100 |
|
||||||
|
| More | Data | 250 |
|
||||||
|
|
||||||
|
### Complex Tables
|
||||||
|
|
||||||
|
| Language | Supported | Syntax Highlighting | Code Blocks |
|
||||||
|
|----------|:---------:|:-------------------:|-------------|
|
||||||
|
| JavaScript | ✅ | ✅ | Yes |
|
||||||
|
| Python | ✅ | ✅ | Yes |
|
||||||
|
| Go | ✅ | ✅ | Yes |
|
||||||
|
| Rust | ✅ | ✅ | Yes |
|
||||||
|
| TypeScript | ✅ | ✅ | Yes |
|
||||||
|
|
||||||
|
Tables are responsive and scroll horizontally on small screens.
|
||||||
|
|
||||||
|
## Images
|
||||||
|
|
||||||
|
### Basic Image
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Image with Caption
|
||||||
|
|
||||||
|
Images automatically get a lightbox overlay on hover (magnifying glass icon appears).
|
||||||
|
|
||||||
|
### Multiple Images
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> *Stock Images obtained from pexels.com*
|
||||||
|
|
||||||
|
Images are responsive and scale to fit the content width.
|
||||||
|
|
||||||
|
## Gallery Shortcode
|
||||||
|
|
||||||
|
Use the gallery shortcode for image collections:
|
||||||
|
|
||||||
|
{{< gallery >}}
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
{{< /gallery >}}
|
||||||
|
|
||||||
|
The gallery includes:
|
||||||
|
- Lightbox functionality
|
||||||
|
- Click to view full size
|
||||||
|
- Navigate between images
|
||||||
|
- Responsive grid layout
|
||||||
|
|
||||||
|
## Mermaid Diagrams
|
||||||
|
|
||||||
|
### Flowchart
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[Start] --> B{Is it dark mode?}
|
||||||
|
B -->|Yes| C[Load dark theme]
|
||||||
|
B -->|No| D[Load light theme]
|
||||||
|
C --> E[Render page]
|
||||||
|
D --> E
|
||||||
|
E --> F[User sees beautiful site]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sequence Diagram
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant User
|
||||||
|
participant Browser
|
||||||
|
participant Hugo
|
||||||
|
participant Theme
|
||||||
|
|
||||||
|
User->>Browser: Visit site
|
||||||
|
Browser->>Hugo: Request page
|
||||||
|
Hugo->>Theme: Render template
|
||||||
|
Theme->>Hugo: Return HTML
|
||||||
|
Hugo->>Browser: Serve page
|
||||||
|
Browser->>User: Display site
|
||||||
|
```
|
||||||
|
|
||||||
|
### Class Diagram
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
classDiagram
|
||||||
|
class Theme {
|
||||||
|
+String name
|
||||||
|
+String version
|
||||||
|
+render()
|
||||||
|
+configure()
|
||||||
|
}
|
||||||
|
class Config {
|
||||||
|
+Object params
|
||||||
|
+validate()
|
||||||
|
}
|
||||||
|
class Content {
|
||||||
|
+String title
|
||||||
|
+Date date
|
||||||
|
+render()
|
||||||
|
}
|
||||||
|
|
||||||
|
Theme --> Config
|
||||||
|
Theme --> Content
|
||||||
|
```
|
||||||
|
|
||||||
|
## Horizontal Rules
|
||||||
|
|
||||||
|
Separate sections with horizontal rules:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Like this one above. They create clear visual breaks in content.
|
||||||
|
|
||||||
|
## Footnotes
|
||||||
|
|
||||||
|
You can add footnotes[^1] to your content. They appear at the bottom of the page[^2].
|
||||||
|
|
||||||
|
[^1]: This is a footnote. It provides additional context without interrupting the flow.
|
||||||
|
[^2]: Footnotes are automatically numbered and linked.
|
||||||
|
|
||||||
|
## Shortcodes
|
||||||
|
|
||||||
|
### Alert Shortcode
|
||||||
|
|
||||||
|
Use the alert shortcode for callouts:
|
||||||
|
|
||||||
|
{{< alert type="note" >}}
|
||||||
|
This is a custom alert using the shortcode syntax. It's an alternative to GitHub-style alerts.
|
||||||
|
{{< /alert >}}
|
||||||
|
|
||||||
|
{{< alert type="warning" >}}
|
||||||
|
Warning alerts grab attention for important notices.
|
||||||
|
{{< /alert >}}
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
This page demonstrates the automatic table of contents:
|
||||||
|
|
||||||
|
- **Desktop:** TOC appears in left sidebar
|
||||||
|
- **Tablet:** TOC is hidden for more reading space
|
||||||
|
- **Mobile:** TOC is completely hidden
|
||||||
|
|
||||||
|
The TOC automatically:
|
||||||
|
- Tracks your scroll position
|
||||||
|
- Highlights the current section
|
||||||
|
- Links to all headings (H2-H4)
|
||||||
|
- Stays visible while scrolling (sticky)
|
||||||
|
|
||||||
|
## Dark & Light Mode
|
||||||
|
|
||||||
|
The theme supports both dark and light modes:
|
||||||
|
|
||||||
|
### Dark Mode (Default)
|
||||||
|
- True black backgrounds (#000000)
|
||||||
|
- OLED-friendly
|
||||||
|
- Purple accents (#c084fc)
|
||||||
|
- Reduced eye strain in low light
|
||||||
|
|
||||||
|
### Light Mode
|
||||||
|
- Clean white backgrounds
|
||||||
|
- High contrast for daylight reading
|
||||||
|
- Purple accents (#a855f7)
|
||||||
|
- Print-friendly
|
||||||
|
|
||||||
|
### System Mode
|
||||||
|
- Automatically matches OS preference
|
||||||
|
- Respects user's system settings
|
||||||
|
- Seamless switching
|
||||||
|
|
||||||
|
Users can toggle between modes using the theme switcher in the navigation.
|
||||||
|
|
||||||
|
## Search Functionality
|
||||||
|
|
||||||
|
Press **Ctrl/Cmd + K** to try the search:
|
||||||
|
|
||||||
|
1. Type your query
|
||||||
|
2. Results appear instantly
|
||||||
|
3. Use arrow keys to navigate
|
||||||
|
4. Press Enter to visit page
|
||||||
|
5. ESC to close
|
||||||
|
|
||||||
|
The search:
|
||||||
|
- Is client-side (no server needed)
|
||||||
|
- Searches titles and summaries
|
||||||
|
- Highlights matching text
|
||||||
|
- Works offline
|
||||||
|
|
||||||
|
## Navigation
|
||||||
|
|
||||||
|
The theme includes:
|
||||||
|
|
||||||
|
### Header Navigation
|
||||||
|
- Logo/brand name
|
||||||
|
- Main menu links
|
||||||
|
- Theme toggle
|
||||||
|
|
||||||
|
### Footer
|
||||||
|
- Copyright notice
|
||||||
|
- Social links
|
||||||
|
- Attribution
|
||||||
|
|
||||||
|
### Floating Dock (Bottom Right)
|
||||||
|
- Quick actions
|
||||||
|
- Scroll to top
|
||||||
|
|
||||||
|
## Responsive Design
|
||||||
|
|
||||||
|
The theme is fully responsive:
|
||||||
|
|
||||||
|
### Mobile (< 640px)
|
||||||
|
- Single column layout
|
||||||
|
- Collapsible menu
|
||||||
|
- Touch-friendly buttons
|
||||||
|
- Optimized images
|
||||||
|
|
||||||
|
### Tablet (641px - 1023px)
|
||||||
|
- Two column where appropriate
|
||||||
|
- Adjusted spacing
|
||||||
|
- Tablet-optimized navigation
|
||||||
|
|
||||||
|
### Desktop (1024px+)
|
||||||
|
- Full layout with TOC sidebar
|
||||||
|
- Wider content area
|
||||||
|
- Hover effects
|
||||||
|
- Keyboard shortcuts
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
The theme is optimized for performance:
|
||||||
|
|
||||||
|
- **Minimal JavaScript**
|
||||||
|
- **Optimized CSS**
|
||||||
|
- **Fast Loading**
|
||||||
|
- **SEO Optimized** — Meta tags, structured data
|
||||||
|
|
||||||
|
## Customization Examples
|
||||||
|
|
||||||
|
### Changing Accent Color
|
||||||
|
|
||||||
|
Edit `assets/css/base.css`:
|
||||||
|
|
||||||
|
```css
|
||||||
|
:root {
|
||||||
|
--color-accent: #10b981; /* Green instead of purple */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding Custom Fonts
|
||||||
|
|
||||||
|
In your `hugo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[params]
|
||||||
|
customFonts = ["https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom CSS
|
||||||
|
|
||||||
|
Create `assets/css/custom.css`:
|
||||||
|
|
||||||
|
```css
|
||||||
|
.my-custom-element {
|
||||||
|
/* Your styles */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Content Organization
|
||||||
|
|
||||||
|
1. Use clear, descriptive titles
|
||||||
|
2. Break content into sections with headings
|
||||||
|
3. Add tags and categories
|
||||||
|
4. Include descriptions in frontmatter
|
||||||
|
5. Use featured images for posts
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
|
||||||
|
1. Optimize images before uploading
|
||||||
|
2. Use SVG for logos and icons
|
||||||
|
3. Minimize custom JavaScript
|
||||||
|
4. Leverage Hugo's asset pipeline
|
||||||
|
|
||||||
|
### SEO
|
||||||
|
|
||||||
|
1. Write descriptive meta descriptions
|
||||||
|
2. Use semantic HTML headings
|
||||||
|
3. Add alt text to images
|
||||||
|
4. Create an XML sitemap
|
||||||
|
5. Submit to search engines
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
This guide covered all major features of the Minimal Black theme. You now know how to:
|
||||||
|
|
||||||
|
- ✅ Format text and create rich content
|
||||||
|
- ✅ Use code blocks with syntax highlighting
|
||||||
|
- ✅ Add images and galleries
|
||||||
|
- ✅ Create diagrams with Mermaid
|
||||||
|
- ✅ Organize content with TOC
|
||||||
|
- ✅ Customize colors and styles
|
||||||
|
- ✅ Optimize for performance
|
||||||
|
- ✅ Make content SEO-friendly
|
||||||
|
|
||||||
|
Start creating amazing content with Minimal Black!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Documentation:** [Full Docs](https://gitlab.com/jimchr12/hugo-minimal-black)
|
||||||
|
|
||||||
|
**Repository:** [GitLab](https://gitlab.com/jimchr12/hugo-minimal-black)
|
||||||
|
|
||||||
|
**Issues:** [Report a Bug](https://gitlab.com/jimchr12/hugo-minimal-black/issues)
|
||||||
@@ -0,0 +1,321 @@
|
|||||||
|
+++
|
||||||
|
title = "Minimal Black Hugo Theme"
|
||||||
|
date = "2025-01-15"
|
||||||
|
description = "A minimal, dark-mode first Hugo theme"
|
||||||
|
github = "https://gitlab.com/jimchr12/hugo-minimal-black"
|
||||||
|
demo = "https://minimal-black-demo.netlify.app"
|
||||||
|
tags = ["hugo", "theme", "web-development", "open-source"]
|
||||||
|
categories = ["web"]
|
||||||
|
featured = true
|
||||||
|
+++
|
||||||
|
|
||||||
|
A comprehensive Hugo theme designed for developers, designers, and everyone in general who value simplicity, performance, and beautiful dare I say dark mode design (maybe?).
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Minimal Black is a modern Hugo theme that combines aesthetic appeal with practical functionality.
|
||||||
|
|
||||||
|
Built with Tailwind CSS and a modular architecture, it provides everything you need for a professional personal website, portfolio or blog.
|
||||||
|
|
||||||
|
### Key Features
|
||||||
|
|
||||||
|
- **True Black Dark Mode** — With purple accents
|
||||||
|
- **Responsive Design** — Perfect on mobile, tablet, and desktop
|
||||||
|
- **Search Functionality** — Fast client-side search with Ctrl/Cmd+K
|
||||||
|
- **Table of Contents** — Auto-generated
|
||||||
|
- **Syntax Highlighting** — Beautiful code blocks with copy functionality
|
||||||
|
- **Multiple Layouts** — Flexible page templates for different content types (more to come hopefully).
|
||||||
|
|
||||||
|
## Technical Architecture
|
||||||
|
|
||||||
|
### Frontend Stack
|
||||||
|
|
||||||
|
- **Hugo Extended** (v0.120.0+) — Static site generator
|
||||||
|
- **Tailwind CSS** — Utility-first CSS framework
|
||||||
|
- **Vanilla JS** — Minimal JS used - no framework
|
||||||
|
- **PostCSS** — CSS processing and optimization
|
||||||
|
|
||||||
|
### CSS Modular Structure
|
||||||
|
|
||||||
|
The CSS is organized into logical modules:
|
||||||
|
|
||||||
|
```
|
||||||
|
assets/css/
|
||||||
|
├── base.css # Theme variables & Tailwind
|
||||||
|
├── utilities.css # Helper classes
|
||||||
|
├── components/ # Reusable UI components
|
||||||
|
│ ├── dock.css
|
||||||
|
│ ├── cards.css
|
||||||
|
│ ├── navigation.css
|
||||||
|
│ ├── search.css
|
||||||
|
│ └── tech-marquee.css
|
||||||
|
├── content/ # Content-specific styles
|
||||||
|
│ ├── markdown.css
|
||||||
|
│ └── toc.css
|
||||||
|
└── pages/ # Page-specific styles
|
||||||
|
├── about.css
|
||||||
|
└── about-alternative.css
|
||||||
|
```
|
||||||
|
|
||||||
|
This modular approach makes the theme:
|
||||||
|
- Easy to maintain and extend
|
||||||
|
- Simple to customize specific components
|
||||||
|
- Clear separation of concerns
|
||||||
|
- Better developer experience
|
||||||
|
|
||||||
|
## Design Philosophy
|
||||||
|
|
||||||
|
### Minimalism First
|
||||||
|
|
||||||
|
The theme embraces minimalism without sacrificing functionality:
|
||||||
|
|
||||||
|
1. **Clean Typography** — Careful font choices and spacing
|
||||||
|
2. **Focused Content** — Remove distractions, highlight what matters
|
||||||
|
3. **Subtle Animations** — Smooth transitions that enhance UX
|
||||||
|
4. **Dark Mode Priority** — True black backgrounds
|
||||||
|
|
||||||
|
## Feature Showcase
|
||||||
|
|
||||||
|
### Search Functionality
|
||||||
|
|
||||||
|
Built-in search with keyboard shortcuts:
|
||||||
|
|
||||||
|
- Press **Ctrl/Cmd + K** to open search
|
||||||
|
- Type to filter results in real-time
|
||||||
|
- Use **Arrow keys** to navigate
|
||||||
|
- Press **Enter** to visit page
|
||||||
|
- **ESC** to close
|
||||||
|
|
||||||
|
The search is client-side, fast, and requires no external services.
|
||||||
|
|
||||||
|
### Code Blocks
|
||||||
|
|
||||||
|
Beautiful syntax highlighting with practical features:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Copy button on hover
|
||||||
|
function greet(name) {
|
||||||
|
console.log(`Hello, ${name}!`);
|
||||||
|
return `Welcome to Minimal Black Theme`;
|
||||||
|
}
|
||||||
|
|
||||||
|
greet("Developer");
|
||||||
|
```
|
||||||
|
|
||||||
|
Features include:
|
||||||
|
|
||||||
|
- Language labels
|
||||||
|
- Copy to clipboard button
|
||||||
|
- Line highlighting
|
||||||
|
- Collapsible / Expandable block
|
||||||
|
|
||||||
|
### GitHub-Style Alerts
|
||||||
|
|
||||||
|
Support for callout boxes:
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> This is a note alert for informational content.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> This is a tip alert with helpful suggestions.
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> This is a warning alert for important notices.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> This is an important alert for critical information.
|
||||||
|
|
||||||
|
### Table of Contents
|
||||||
|
|
||||||
|
MD content automatically gets a TOC:
|
||||||
|
|
||||||
|
- **Sticky Positioning** — Stays visible while scrolling
|
||||||
|
- **Active Tracking** — Highlights current section
|
||||||
|
- **Smooth Scrolling** — Click to jump to section
|
||||||
|
- **Responsive** — Hides on mobile, shows on desktop
|
||||||
|
|
||||||
|
You're seeing it in action on this **page**!
|
||||||
|
|
||||||
|
### Mermaid Diagrams
|
||||||
|
|
||||||
|
Native support for flowcharts and diagrams:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[User visits site] --> B{Dark mode?}
|
||||||
|
B -->|Yes| C[Load dark theme]
|
||||||
|
B -->|No| D[Load light theme]
|
||||||
|
C --> E[Render content]
|
||||||
|
D --> E
|
||||||
|
E --> F[Fast, beautiful site]
|
||||||
|
```
|
||||||
|
|
||||||
|
Perfect for technical documentation.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The theme is highly configurable via `hugo.toml`:
|
||||||
|
|
||||||
|
### Basic Setup
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[params]
|
||||||
|
brand = "Your Name"
|
||||||
|
description = "Your site description"
|
||||||
|
|
||||||
|
[params.theme]
|
||||||
|
defaultTheme = "dark" # or "light" or "system"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hero Section
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[params.hero]
|
||||||
|
badge = "Software Engineer"
|
||||||
|
title = "Hi, I'm Your Name."
|
||||||
|
role = "Building things."
|
||||||
|
summary = "Description of what you do."
|
||||||
|
location = "City, Country"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tech Stack Display
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[params.home.tech]]
|
||||||
|
label = "Python"
|
||||||
|
icon = "devicon-python-plain"
|
||||||
|
|
||||||
|
[[params.home.tech]]
|
||||||
|
label = "Docker"
|
||||||
|
icon = "devicon-docker-plain"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Analytics
|
||||||
|
|
||||||
|
Support for multiple providers:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[params.analytics]
|
||||||
|
googleAnalytics = "G-XXXXXXXXXX"
|
||||||
|
|
||||||
|
# Or use Plausible, Umami, Fathom
|
||||||
|
```
|
||||||
|
|
||||||
|
## Customization Guide
|
||||||
|
|
||||||
|
### Colors
|
||||||
|
|
||||||
|
Theme colors are CSS custom properties in `assets/css/base.css`:
|
||||||
|
|
||||||
|
```css
|
||||||
|
:root {
|
||||||
|
--color-bg: #f9fafb; /* Light background */
|
||||||
|
--color-accent: #a855f7; /* Purple accent */
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme="dark"] {
|
||||||
|
--color-bg: #000000; /* True black */
|
||||||
|
--color-accent: #c084fc; /* Lighter purple */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding Custom Styles
|
||||||
|
|
||||||
|
Create `assets/css/custom.css` in your site:
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* Your custom styles */
|
||||||
|
.my-custom-class {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then reference it in your config:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[params]
|
||||||
|
customCSS = ["css/custom.css"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Content Organization
|
||||||
|
|
||||||
|
### Recommended Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
content/
|
||||||
|
├── _index.md # Homepage
|
||||||
|
├── about.md # About page
|
||||||
|
├── blog/
|
||||||
|
│ ├── _index.md
|
||||||
|
│ └── posts/
|
||||||
|
├── projects/
|
||||||
|
│ ├── _index.md
|
||||||
|
│ └── individual-projects/
|
||||||
|
└── pages/
|
||||||
|
└── custom-pages/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Frontmatter Examples
|
||||||
|
|
||||||
|
**Blog Post:**
|
||||||
|
```yaml
|
||||||
|
+++
|
||||||
|
title = "Post Title"
|
||||||
|
date = "2025-01-15"
|
||||||
|
tags = ["hugo", "web-dev"]
|
||||||
|
categories = ["tutorials"]
|
||||||
|
draft = false
|
||||||
|
+++
|
||||||
|
```
|
||||||
|
|
||||||
|
**Project:**
|
||||||
|
```yaml
|
||||||
|
+++
|
||||||
|
title = "Project Name"
|
||||||
|
description = "Brief description"
|
||||||
|
github = "https://github.com/..." # Optional
|
||||||
|
demo = "https://demo.com" # Optional
|
||||||
|
featured = true
|
||||||
|
+++
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
### Netlify
|
||||||
|
|
||||||
|
1. Connect your Git repository
|
||||||
|
2. Build command: `hugo --minify`
|
||||||
|
3. Publish directory: `public`
|
||||||
|
4. Environment: `HUGO_VERSION=0.120.0`
|
||||||
|
|
||||||
|
### Vercel
|
||||||
|
|
||||||
|
1. Import repository
|
||||||
|
2. Framework: Hugo
|
||||||
|
3. Build command: `cd themes/minimal-black && npm install && cd ../.. && hugo --minify`
|
||||||
|
4. Output: `public`
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! See [CONTRIBUTING.md](https://gitlab.com/jimchr12/hugo-minimal-black/blob/main/CONTRIBUTING.md) for guidelines.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Released under the MIT License. See [LICENSE](https://gitlab.com/jimchr12/hugo-minimal-black/blob/main/LICENSE) for details.
|
||||||
|
|
||||||
|
## Acknowledgments
|
||||||
|
|
||||||
|
Built with:
|
||||||
|
|
||||||
|
- [Hugo](https://gohugo.io/) — Static site generator
|
||||||
|
- [Tailwind CSS](https://tailwindcss.com/) — CSS framework
|
||||||
|
- [Font Awesome](https://fontawesome.com/) — Icons
|
||||||
|
- [Devicon](https://devicon.dev/) — Technology icons
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Repository:** [GitLab](https://gitlab.com/jimchr12/hugo-minimal-black)
|
||||||
|
|
||||||
|
**Demo:** [Live Preview](https://minimal-black-demo.netlify.app)
|
||||||
|
|
||||||
|
**Documentation:** [Full Docs](https://gitlab.com/jimchr12/hugo-minimal-black#readme)
|
||||||
362
themes/minimal-black/exampleSite/hugo.toml
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
baseURL = 'https://minimal-black-demo.netlify.app'
|
||||||
|
languageCode = 'en-us'
|
||||||
|
title = 'Minimal Black Theme'
|
||||||
|
theme = "minimal-black"
|
||||||
|
|
||||||
|
# Enable search index generation and web app manifest
|
||||||
|
[outputs]
|
||||||
|
home = ["HTML", "RSS", "JSON", "WebAppManifest"]
|
||||||
|
|
||||||
|
[outputFormats.WebAppManifest]
|
||||||
|
mediaType = "application/manifest+json"
|
||||||
|
rel = "manifest"
|
||||||
|
baseName = "manifest"
|
||||||
|
isPlainText = true
|
||||||
|
notAlternative = true
|
||||||
|
|
||||||
|
[params]
|
||||||
|
brand = "Hugo Minimal Black"
|
||||||
|
description = "A minimal, dark-mode first personal site, or whatever else you want it to be about"
|
||||||
|
|
||||||
|
# Favicon - Place your favicon files in /static/ directory
|
||||||
|
# Supported formats: .ico, .png, .svg
|
||||||
|
favicon = "icons/favicon.svg"
|
||||||
|
appleTouchIcon = "apple-touch-icon.png"
|
||||||
|
|
||||||
|
# Logo (optional)
|
||||||
|
logo = "images/logo.png"
|
||||||
|
|
||||||
|
# Project and blog intro text
|
||||||
|
projectsIntro = "Selected projects to display list." # Can be empty
|
||||||
|
blogIntro = "" # Can be empty
|
||||||
|
|
||||||
|
# Web App Manifest Configuration (PWA support)
|
||||||
|
[params.manifest]
|
||||||
|
themeColor = "#a855f7"
|
||||||
|
backgroundColor = "#000000"
|
||||||
|
categories = ["blog", "portfolio", "developer"]
|
||||||
|
|
||||||
|
# Custom icon configuration (optional)
|
||||||
|
# If not specified, defaults to /icons/android-chrome-*.png
|
||||||
|
# [[params.manifest.icons]]
|
||||||
|
# src = "/icons/android-chrome-192x192.png"
|
||||||
|
# sizes = "192x192"
|
||||||
|
# type = "image/png"
|
||||||
|
# purpose = "any maskable"
|
||||||
|
|
||||||
|
# Theme Configuration
|
||||||
|
[params.theme]
|
||||||
|
defaultTheme = "dark" # Options: "light", "dark", "system"
|
||||||
|
|
||||||
|
# Home Page Configuration
|
||||||
|
[params.home]
|
||||||
|
sections = ["hero", "now", "tech-marquee", "projects", "posts"]
|
||||||
|
showNowSection = true
|
||||||
|
showFeaturedProjects = true
|
||||||
|
showLatestPosts = true
|
||||||
|
featuredProjectsLimit = 3
|
||||||
|
latestPostsLimit = 3
|
||||||
|
projectsTitle = "Selected Work"
|
||||||
|
projectsSubtitle = ""
|
||||||
|
blogTitle = "Latest Writing"
|
||||||
|
blogSubtitle = ""
|
||||||
|
techMarqueeLabel = "Experienced In"
|
||||||
|
|
||||||
|
# Technology Stack Display
|
||||||
|
[[params.home.tech]]
|
||||||
|
label = "Python"
|
||||||
|
icon = "devicon-python-plain"
|
||||||
|
|
||||||
|
[[params.home.tech]]
|
||||||
|
label = "Java"
|
||||||
|
icon = "devicon-java-plain"
|
||||||
|
|
||||||
|
[[params.home.tech]]
|
||||||
|
label = "Spring"
|
||||||
|
icon = "devicon-spring-plain"
|
||||||
|
|
||||||
|
[[params.home.tech]]
|
||||||
|
label = "Vaadin"
|
||||||
|
icon = "devicon-vaadin-plain"
|
||||||
|
|
||||||
|
[[params.home.tech]]
|
||||||
|
label = "Debian"
|
||||||
|
icon = "devicon-debian-plain"
|
||||||
|
|
||||||
|
[[params.home.tech]]
|
||||||
|
label = "GitLab"
|
||||||
|
icon = "devicon-gitlab-plain"
|
||||||
|
|
||||||
|
[[params.home.tech]]
|
||||||
|
label = "Docker"
|
||||||
|
icon = "devicon-docker-plain"
|
||||||
|
|
||||||
|
[[params.home.techReverse]]
|
||||||
|
label = "PostgreSQL"
|
||||||
|
icon = "devicon-postgresql-plain"
|
||||||
|
|
||||||
|
[[params.home.techReverse]]
|
||||||
|
label = "MongoDB"
|
||||||
|
icon = "devicon-mongodb-plain"
|
||||||
|
|
||||||
|
[[params.home.techReverse]]
|
||||||
|
label = "Git"
|
||||||
|
icon = "devicon-git-plain"
|
||||||
|
|
||||||
|
[[params.home.techReverse]]
|
||||||
|
label = "Hugo"
|
||||||
|
icon = "devicon-hugo-plain"
|
||||||
|
|
||||||
|
[[params.home.techReverse]]
|
||||||
|
label = "Jenkins"
|
||||||
|
icon = "devicon-jenkins-plain"
|
||||||
|
|
||||||
|
[[params.home.techReverse]]
|
||||||
|
label = "JetBrains"
|
||||||
|
icon = "devicon-jetbrains-plain"
|
||||||
|
|
||||||
|
[[params.home.techReverse]]
|
||||||
|
label = "Json"
|
||||||
|
icon = "devicon-json-plain"
|
||||||
|
|
||||||
|
[[params.home.techReverse]]
|
||||||
|
label = "Linux"
|
||||||
|
icon = "devicon-linux-plain"
|
||||||
|
|
||||||
|
[[params.home.techReverse]]
|
||||||
|
label = "Liquibase"
|
||||||
|
icon = "devicon-liquibase-plain"
|
||||||
|
|
||||||
|
[[params.home.techReverse]]
|
||||||
|
label = "Markdown"
|
||||||
|
icon = "devicon-markdown-original"
|
||||||
|
|
||||||
|
[[params.home.techReverse]]
|
||||||
|
label = "YAML"
|
||||||
|
icon = "devicon-yaml-plain"
|
||||||
|
|
||||||
|
[[params.home.techReverse]]
|
||||||
|
label = "Wordpress"
|
||||||
|
icon = "devicon-wordpress-plain"
|
||||||
|
|
||||||
|
[[params.home.techReverse]]
|
||||||
|
label = "WooCommerce"
|
||||||
|
icon = "devicon-woocommerce-plain"
|
||||||
|
|
||||||
|
[[params.home.techReverse]]
|
||||||
|
label = "Traefik"
|
||||||
|
icon = "devicon-traefikproxy-plain"
|
||||||
|
|
||||||
|
[[params.home.techReverse]]
|
||||||
|
label = "pfSense"
|
||||||
|
icon = "devicon-pfsense-plain"
|
||||||
|
|
||||||
|
# About Page Alternative Layout Configuration - Optional
|
||||||
|
[params.about.alt]
|
||||||
|
# Stats displayed in the profile card sidebar
|
||||||
|
[[params.about.alt.stats]]
|
||||||
|
value = "5+"
|
||||||
|
label = "Years Coding"
|
||||||
|
|
||||||
|
[[params.about.alt.stats]]
|
||||||
|
value = "20+"
|
||||||
|
label = "Projects"
|
||||||
|
|
||||||
|
[[params.about.alt.stats]]
|
||||||
|
value = "∞"
|
||||||
|
label = "Hours Spent"
|
||||||
|
|
||||||
|
# Skills/Tech Stack badges with icons
|
||||||
|
[[params.about.alt.skills]]
|
||||||
|
label = "JavaScript"
|
||||||
|
icon = "devicon-javascript-plain"
|
||||||
|
|
||||||
|
[[params.about.alt.skills]]
|
||||||
|
label = "Python"
|
||||||
|
icon = "devicon-python-plain"
|
||||||
|
|
||||||
|
[[params.about.alt.skills]]
|
||||||
|
label = "React"
|
||||||
|
icon = "devicon-react-original"
|
||||||
|
|
||||||
|
[[params.about.alt.skills]]
|
||||||
|
label = "Docker"
|
||||||
|
icon = "devicon-docker-plain"
|
||||||
|
|
||||||
|
[[params.about.alt.skills]]
|
||||||
|
label = "PostgreSQL"
|
||||||
|
icon = "devicon-postgresql-plain"
|
||||||
|
|
||||||
|
[[params.about.alt.skills]]
|
||||||
|
label = "AWS"
|
||||||
|
icon = "devicon-amazonwebservices-plain"
|
||||||
|
|
||||||
|
# Hero Section Configuration
|
||||||
|
[params.hero]
|
||||||
|
badge = "Software Engineer"
|
||||||
|
title = "Hi, I'm Your Name or your interesting title."
|
||||||
|
role = "Subtitle for title with role perspective"
|
||||||
|
summary = "You can write your summary to be displayed here."
|
||||||
|
# avatar = "images/avatar.jpg" # Optional: 400x400px recommended
|
||||||
|
location = "City, Country"
|
||||||
|
focus = "Currently focused on Hugo themes & developer experience."
|
||||||
|
available = true
|
||||||
|
availableLabel = "Available for work"
|
||||||
|
|
||||||
|
nowLabel = "Quick Facts"
|
||||||
|
nowIntro = "Right now I'm mainly:"
|
||||||
|
now = [
|
||||||
|
"Building minimal Hugo themes",
|
||||||
|
"Exploring dark-mode design patterns",
|
||||||
|
"Writing about web performance"
|
||||||
|
]
|
||||||
|
|
||||||
|
[params.hero.primary]
|
||||||
|
label = "View Projects"
|
||||||
|
href = "/projects/"
|
||||||
|
|
||||||
|
[params.hero.secondary]
|
||||||
|
label = "Read the Blog"
|
||||||
|
href = "/blog/"
|
||||||
|
|
||||||
|
# Icon Libraries
|
||||||
|
[params.icons]
|
||||||
|
useFontAwesome = true
|
||||||
|
useDevicon = true
|
||||||
|
|
||||||
|
# Social Links
|
||||||
|
[[params.social]]
|
||||||
|
label = "GitLab"
|
||||||
|
url = "https://gitlab.com/jimchr12"
|
||||||
|
icon = "fa-brands fa-gitlab"
|
||||||
|
|
||||||
|
[[params.social]]
|
||||||
|
label = "LinkedIn"
|
||||||
|
url = "https://www.linkedin.com/in/jimchristopoulos-542512221/"
|
||||||
|
icon = "fa-brands fa-linkedin-in"
|
||||||
|
|
||||||
|
[[params.social]]
|
||||||
|
label = "Email"
|
||||||
|
url = "mailto:you@example.com"
|
||||||
|
icon = "fa-regular fa-envelope"
|
||||||
|
|
||||||
|
# Analytics Configuration
|
||||||
|
[params.analytics]
|
||||||
|
# Google Analytics (GA4)
|
||||||
|
# googleAnalytics = "G-XXXXXXXXXX"
|
||||||
|
|
||||||
|
# Plausible Analytics (privacy-friendly)
|
||||||
|
# [params.analytics.plausible]
|
||||||
|
# enabled = true
|
||||||
|
# domain = "yourdomain.com"
|
||||||
|
# scriptUrl = "https://plausible.io/js/script.js"
|
||||||
|
|
||||||
|
# Umami Analytics (self-hosted option)
|
||||||
|
# [params.analytics.umami]
|
||||||
|
# enabled = true
|
||||||
|
# scriptUrl = "https://analytics.yourdomain.com/script.js"
|
||||||
|
# websiteId = "your-website-id"
|
||||||
|
|
||||||
|
# Fathom Analytics
|
||||||
|
# [params.analytics.fathom]
|
||||||
|
# enabled = true
|
||||||
|
# scriptUrl = "https://cdn.usefathom.com/script.js"
|
||||||
|
# siteId = "YOUR-SITE-ID"
|
||||||
|
|
||||||
|
# Navigation Menu
|
||||||
|
[menu]
|
||||||
|
[[menu.main]]
|
||||||
|
name = "Home"
|
||||||
|
pageRef = "/"
|
||||||
|
url = "/"
|
||||||
|
weight = 1
|
||||||
|
identifier = "home"
|
||||||
|
[menu.main.params]
|
||||||
|
icon = "fa-solid fa-house"
|
||||||
|
|
||||||
|
[[menu.main]]
|
||||||
|
name = "About"
|
||||||
|
pageRef = "about"
|
||||||
|
url = "/about/"
|
||||||
|
weight = 2
|
||||||
|
identifier = "about"
|
||||||
|
[menu.main.params]
|
||||||
|
icon = "fa-regular fa-user"
|
||||||
|
|
||||||
|
[[menu.main]]
|
||||||
|
name = "About Alt"
|
||||||
|
pageRef = "about-alternative"
|
||||||
|
url = "/about-alternative/"
|
||||||
|
weight = 2
|
||||||
|
identifier = "about-alternative"
|
||||||
|
[menu.main.params]
|
||||||
|
icon = "fa-solid fa-user"
|
||||||
|
|
||||||
|
[[menu.main]]
|
||||||
|
name = "Projects"
|
||||||
|
pageRef = "projects"
|
||||||
|
url = "/projects/"
|
||||||
|
weight = 3
|
||||||
|
identifier = "projects"
|
||||||
|
[menu.main.params]
|
||||||
|
icon = "fa-regular fa-folder-open"
|
||||||
|
|
||||||
|
[[menu.main]]
|
||||||
|
name = "Blog"
|
||||||
|
pageRef = "blog"
|
||||||
|
url = "/blog/"
|
||||||
|
weight = 4
|
||||||
|
identifier = "blog"
|
||||||
|
[menu.main.params]
|
||||||
|
icon = "fa-regular fa-note-sticky"
|
||||||
|
|
||||||
|
# Markup Configuration
|
||||||
|
[markup]
|
||||||
|
# Table of Contents
|
||||||
|
[markup.tableOfContents]
|
||||||
|
startLevel = 2
|
||||||
|
endLevel = 4
|
||||||
|
|
||||||
|
# Goldmark Renderer (Markdown)
|
||||||
|
[markup.goldmark.renderer]
|
||||||
|
unsafe = true
|
||||||
|
|
||||||
|
[markup.goldmark.parser]
|
||||||
|
[markup.goldmark.parser.attribute]
|
||||||
|
block = true
|
||||||
|
|
||||||
|
[markup.goldmark.extensions]
|
||||||
|
typographer = true
|
||||||
|
linkify = true
|
||||||
|
table = true
|
||||||
|
strikethrough = true
|
||||||
|
taskList = true
|
||||||
|
definitionList = true
|
||||||
|
footnote = true
|
||||||
|
|
||||||
|
[markup.goldmark.extensions.extras.delete]
|
||||||
|
enable = true
|
||||||
|
[markup.goldmark.extensions.extras.insert]
|
||||||
|
enable = true
|
||||||
|
[markup.goldmark.extensions.extras.mark]
|
||||||
|
enable = true
|
||||||
|
|
||||||
|
# Syntax Highlighting
|
||||||
|
[markup.highlight]
|
||||||
|
codeFences = true
|
||||||
|
guessSyntax = true
|
||||||
|
lineNos = false
|
||||||
|
lineNumbersInTable = false
|
||||||
|
noClasses = false
|
||||||
|
style = "monokai"
|
||||||
|
tabWidth = 2
|
||||||
|
|
||||||
|
# Taxonomies
|
||||||
|
[taxonomies]
|
||||||
|
tag = "tags"
|
||||||
|
category = "categories"
|
||||||
|
|
||||||
|
# Privacy Configuration
|
||||||
|
[privacy]
|
||||||
|
[privacy.youtube]
|
||||||
|
privacyEnhanced = true
|
||||||
BIN
themes/minimal-black/images/about-alt.png
Normal file
|
After Width: | Height: | Size: 766 KiB |
BIN
themes/minimal-black/images/about.png
Normal file
|
After Width: | Height: | Size: 822 KiB |
BIN
themes/minimal-black/images/screenshot.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
themes/minimal-black/images/tn.png
Normal file
|
After Width: | Height: | Size: 129 KiB |
308
themes/minimal-black/layouts/404.html
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
{{ define "main" }}
|
||||||
|
<section class="layout-page">
|
||||||
|
<div class="error-page">
|
||||||
|
<div class="error-content">
|
||||||
|
<!-- Error Code -->
|
||||||
|
<div class="error-code">404</div>
|
||||||
|
|
||||||
|
<!-- Error Message -->
|
||||||
|
<h1 class="error-title">Page Not Found</h1>
|
||||||
|
<p class="error-description">
|
||||||
|
The page you're looking for doesn't exist or has been moved.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Search Suggestion -->
|
||||||
|
<div class="error-search">
|
||||||
|
<p class="error-hint">
|
||||||
|
Try searching for what you need, or return to the homepage.
|
||||||
|
</p>
|
||||||
|
<div class="error-actions">
|
||||||
|
<button
|
||||||
|
onclick="window.MinimalSearch.open()"
|
||||||
|
class="btn-primary"
|
||||||
|
aria-label="Search site"
|
||||||
|
>
|
||||||
|
<i class="fa-solid fa-magnifying-glass"></i>
|
||||||
|
<span>Search Site</span>
|
||||||
|
</button>
|
||||||
|
<a href="/" class="btn-ghost">
|
||||||
|
<i class="fa-solid fa-house"></i>
|
||||||
|
<span>Go Home</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Helpful Links -->
|
||||||
|
<div class="error-links">
|
||||||
|
<h2 class="error-links-title">You might be interested in:</h2>
|
||||||
|
<div class="error-links-grid">
|
||||||
|
{{ with .Site.GetPage "/blog" }}
|
||||||
|
<a href="{{ .Permalink }}" class="error-link-card">
|
||||||
|
<i class="fa-regular fa-note-sticky"></i>
|
||||||
|
<div>
|
||||||
|
<strong>Blog</strong>
|
||||||
|
<span>Read latest articles</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ with .Site.GetPage "/projects" }}
|
||||||
|
<a href="{{ .Permalink }}" class="error-link-card">
|
||||||
|
<i class="fa-regular fa-folder-open"></i>
|
||||||
|
<div>
|
||||||
|
<strong>Projects</strong>
|
||||||
|
<span>Explore my work</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ with .Site.GetPage "/about" }}
|
||||||
|
<a href="{{ .Permalink }}" class="error-link-card">
|
||||||
|
<i class="fa-regular fa-user"></i>
|
||||||
|
<div>
|
||||||
|
<strong>About</strong>
|
||||||
|
<span>Learn more about me</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Alternative: Show Recent Posts -->
|
||||||
|
{{ $recentPages := where .Site.RegularPages "Section" "in" (slice "blog" "projects") }}
|
||||||
|
{{ $recentPages = first 3 $recentPages }}
|
||||||
|
{{ if $recentPages }}
|
||||||
|
<div class="error-recent">
|
||||||
|
<h2 class="error-recent-title">Recent Content</h2>
|
||||||
|
<ul class="error-recent-list">
|
||||||
|
{{ range $recentPages }}
|
||||||
|
<li>
|
||||||
|
<a href="{{ .Permalink }}" class="error-recent-link">
|
||||||
|
<span class="error-recent-icon">
|
||||||
|
{{ if eq .Section "blog" }}
|
||||||
|
<i class="fa-regular fa-note-sticky"></i>
|
||||||
|
{{ else if eq .Section "projects" }}
|
||||||
|
<i class="fa-regular fa-folder-open"></i>
|
||||||
|
{{ else }}
|
||||||
|
<i class="fa-regular fa-file"></i>
|
||||||
|
{{ end }}
|
||||||
|
</span>
|
||||||
|
<span class="error-recent-text">
|
||||||
|
<strong>{{ .Title }}</strong>
|
||||||
|
{{ with .Description }}
|
||||||
|
<small>{{ . }}</small>
|
||||||
|
{{ end }}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{ end }}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.error-page {
|
||||||
|
min-height: 60vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 4rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-content {
|
||||||
|
text-align: center;
|
||||||
|
max-width: 42rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-code {
|
||||||
|
font-size: 8rem;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
color: var(--color-accent);
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-title {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-description {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-search {
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-hint {
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 1rem;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-links {
|
||||||
|
margin-top: 3rem;
|
||||||
|
padding-top: 3rem;
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-links-title {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-links-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||||
|
gap: 1rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-link-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 1.25rem;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--color-text);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-link-card:hover {
|
||||||
|
border-color: var(--color-accent);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-link-card i {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-link-card strong {
|
||||||
|
display: block;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-link-card span {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-recent {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-recent-title {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-recent-list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-recent-list li {
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-recent-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--color-text);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-recent-link:hover {
|
||||||
|
border-color: var(--color-accent);
|
||||||
|
background: color-mix(in srgb, var(--color-surface) 95%, var(--color-accent));
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-recent-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: var(--color-accent);
|
||||||
|
font-size: 1.25rem;
|
||||||
|
padding-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-recent-text {
|
||||||
|
flex: 1;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-recent-text strong {
|
||||||
|
display: block;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-recent-text small {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.error-code {
|
||||||
|
font-size: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-description {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-actions {
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-actions .btn-primary,
|
||||||
|
.error-actions .btn-ghost {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-links-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{{ end }}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<div class="md-alert md-alert-note">
|
||||||
|
<div class="md-mermaid">
|
||||||
|
<pre class="mermaid">
|
||||||
|
{{ .Text | safeHTML }}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{{- /* Check if this is a GitHub-style alert */ -}}
|
||||||
|
{{- if eq .Type "alert" -}}
|
||||||
|
<div class="md-alert md-alert-{{ .AlertType }}">
|
||||||
|
{{ .Text | safeHTML }}
|
||||||
|
</div>
|
||||||
|
{{- else -}}
|
||||||
|
<blockquote class="md-blockquote">
|
||||||
|
{{ .Text | safeHTML }}
|
||||||
|
</blockquote>
|
||||||
|
{{- end -}}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<div class="md-mermaid">
|
||||||
|
<pre class="mermaid">
|
||||||
|
{{ .Inner | safeHTML }}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,337 @@
|
|||||||
|
{{- $lang := .Type | default "text" -}}
|
||||||
|
{{- $filename := .Attributes.filename | default "" -}}
|
||||||
|
{{- $label := cond (ne $filename "") $filename ($lang | upper) -}}
|
||||||
|
{{- $id := printf "cb-%s" (printf "%d" .Ordinal | sha256 | truncate 8 "") -}}
|
||||||
|
|
||||||
|
{{- $collapseEnabled := site.Params.codeblock.collapse.enabled | default true -}}
|
||||||
|
{{- $defaultState := site.Params.codeblock.collapse.defaultState | default "expanded" -}}
|
||||||
|
{{- $collapsedHeight := site.Params.codeblock.collapse.collapsedHeight | default 200 -}}
|
||||||
|
|
||||||
|
{{- $highlighted := transform.HighlightCodeBlock . -}}
|
||||||
|
|
||||||
|
<div class="mb-codeblock" id="{{ $id }}" data-lang="{{ $lang | lower }}">
|
||||||
|
<!-- Header with language badge and actions -->
|
||||||
|
<div class="mb-codeblock-header">
|
||||||
|
<div class="mb-codeblock-left">
|
||||||
|
<span class="mb-codeblock-badge">
|
||||||
|
{{ $lang | upper }}
|
||||||
|
</span>
|
||||||
|
{{- if ne $filename "" -}}
|
||||||
|
<span class="mb-codeblock-filename">
|
||||||
|
<i class="fas fa-file-code" style="font-size: 0.65rem;"></i>
|
||||||
|
{{ $filename }}
|
||||||
|
</span>
|
||||||
|
{{- end -}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-codeblock-actions">
|
||||||
|
{{- if $collapseEnabled -}}
|
||||||
|
<button class="mb-action-btn mb-collapse-btn" data-collapsed="false" aria-label="Collapse code">
|
||||||
|
<i class="fas fa-compress-alt"></i>
|
||||||
|
<span>Collapse</span>
|
||||||
|
</button>
|
||||||
|
{{- end -}}
|
||||||
|
<button class="mb-action-btn mb-copy-btn" aria-label="Copy code">
|
||||||
|
<i class="fas fa-copy"></i>
|
||||||
|
<span>Copy</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Code content -->
|
||||||
|
<div
|
||||||
|
class="mb-codeblock-content"
|
||||||
|
data-state="{{ $defaultState }}"
|
||||||
|
{{- if eq $defaultState "collapsed" }}
|
||||||
|
style="max-height: {{ $collapsedHeight }}px; overflow: hidden;"
|
||||||
|
{{- end }}
|
||||||
|
>
|
||||||
|
{{ $highlighted.Wrapped }}
|
||||||
|
|
||||||
|
{{- if $collapseEnabled -}}
|
||||||
|
<div class="mb-collapse-overlay">
|
||||||
|
<button class="mb-expand-trigger">
|
||||||
|
<i class="fas fa-chevron-down"></i>
|
||||||
|
<span>Click to expand</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{{- end -}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const codeblock = document.getElementById('{{ $id }}');
|
||||||
|
if (!codeblock) return;
|
||||||
|
|
||||||
|
const copyBtn = codeblock.querySelector('.mb-copy-btn');
|
||||||
|
const collapseBtn = codeblock.querySelector('.mb-collapse-btn');
|
||||||
|
const content = codeblock.querySelector('.mb-codeblock-content');
|
||||||
|
const overlay = codeblock.querySelector('.mb-collapse-overlay');
|
||||||
|
const expandTrigger = overlay?.querySelector('.mb-expand-trigger');
|
||||||
|
|
||||||
|
// ==================
|
||||||
|
// COPY FUNCTIONALITY
|
||||||
|
// ==================
|
||||||
|
if (copyBtn) {
|
||||||
|
copyBtn.addEventListener('click', async function() {
|
||||||
|
let codeText = '';
|
||||||
|
|
||||||
|
// Handle line-numbered code (Hugo's table format)
|
||||||
|
const codeCell = codeblock.querySelector('.lntd:last-child code');
|
||||||
|
if (codeCell) {
|
||||||
|
codeText = codeCell.textContent || codeCell.innerText || '';
|
||||||
|
} else {
|
||||||
|
// Regular code block
|
||||||
|
const codeEl = codeblock.querySelector('pre code');
|
||||||
|
codeText = codeEl ? (codeEl.textContent || codeEl.innerText || '') : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(codeText.trim());
|
||||||
|
|
||||||
|
// Success feedback
|
||||||
|
const originalHTML = copyBtn.innerHTML;
|
||||||
|
copyBtn.innerHTML = '<i class="fas fa-check"></i><span>Copied!</span>';
|
||||||
|
copyBtn.classList.add('mb-btn-success');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
copyBtn.innerHTML = originalHTML;
|
||||||
|
copyBtn.classList.remove('mb-btn-success');
|
||||||
|
}, 2000);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to copy code:', err);
|
||||||
|
|
||||||
|
// Fallback for older browsers
|
||||||
|
const textArea = document.createElement('textarea');
|
||||||
|
textArea.value = codeText.trim();
|
||||||
|
textArea.style.position = 'fixed';
|
||||||
|
textArea.style.opacity = '0';
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.select();
|
||||||
|
|
||||||
|
try {
|
||||||
|
document.execCommand('copy');
|
||||||
|
copyBtn.innerHTML = '<i class="fas fa-check"></i><span>Copied!</span>';
|
||||||
|
setTimeout(() => {
|
||||||
|
copyBtn.innerHTML = '<i class="fas fa-copy"></i><span>Copy</span>';
|
||||||
|
}, 2000);
|
||||||
|
} catch (fallbackErr) {
|
||||||
|
console.error('Fallback copy failed:', fallbackErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// =======================
|
||||||
|
// COLLAPSE FUNCTIONALITY
|
||||||
|
// =======================
|
||||||
|
if (collapseBtn && content && overlay) {
|
||||||
|
const collapsedHeight = {{ $collapsedHeight }};
|
||||||
|
|
||||||
|
function toggleCollapse() {
|
||||||
|
const isCollapsed = content.dataset.state === 'collapsed';
|
||||||
|
|
||||||
|
if (isCollapsed) {
|
||||||
|
// EXPAND
|
||||||
|
content.style.maxHeight = '';
|
||||||
|
content.style.overflow = '';
|
||||||
|
content.dataset.state = 'expanded';
|
||||||
|
overlay.style.display = 'none';
|
||||||
|
collapseBtn.innerHTML = '<i class="fas fa-compress-alt"></i><span>Collapse</span>';
|
||||||
|
collapseBtn.dataset.collapsed = 'false';
|
||||||
|
} else {
|
||||||
|
// COLLAPSE
|
||||||
|
content.style.maxHeight = collapsedHeight + 'px';
|
||||||
|
content.style.overflow = 'hidden';
|
||||||
|
content.dataset.state = 'collapsed';
|
||||||
|
overlay.style.display = 'flex';
|
||||||
|
collapseBtn.innerHTML = '<i class="fas fa-expand-alt"></i><span>Expand</span>';
|
||||||
|
collapseBtn.dataset.collapsed = 'true';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize if default state is collapsed
|
||||||
|
if ('{{ $defaultState }}' === 'collapsed') {
|
||||||
|
content.dataset.state = 'collapsed';
|
||||||
|
overlay.style.display = 'flex';
|
||||||
|
collapseBtn.innerHTML = '<i class="fas fa-expand-alt"></i><span>Expand</span>';
|
||||||
|
collapseBtn.dataset.collapsed = 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
collapseBtn.addEventListener('click', toggleCollapse);
|
||||||
|
|
||||||
|
if (expandTrigger) {
|
||||||
|
expandTrigger.addEventListener('click', toggleCollapse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* Additional styles for improved codeblock - add to your main.css */
|
||||||
|
|
||||||
|
.mb-codeblock-filename {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.35rem;
|
||||||
|
color: var(--color-text);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 0.2rem 0.6rem;
|
||||||
|
border-radius: 0.35rem;
|
||||||
|
background: color-mix(in srgb, var(--color-bg) 40%, transparent);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 60%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-action-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.35rem;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent);
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
padding: 0.35rem 0.65rem;
|
||||||
|
border-radius: 0.4rem;
|
||||||
|
transition: all 0.15s ease-out;
|
||||||
|
font-family: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-action-btn:hover {
|
||||||
|
color: var(--color-accent);
|
||||||
|
background: color-mix(in srgb, var(--color-accent) 12%, transparent);
|
||||||
|
border-color: var(--color-accent);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-action-btn:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-action-btn i {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-btn-success {
|
||||||
|
color: #22c55e !important;
|
||||||
|
border-color: #22c55e !important;
|
||||||
|
background: color-mix(in srgb, #22c55e 12%, transparent) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-collapse-overlay {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
transparent 0%,
|
||||||
|
rgba(0, 0, 0, 0.3) 40%,
|
||||||
|
rgba(0, 0, 0, 0.85) 100%
|
||||||
|
);
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: center;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-expand-trigger {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.4rem;
|
||||||
|
padding: 0.4rem 0.8rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
border: 1px solid var(--color-accent);
|
||||||
|
background: color-mix(in srgb, var(--color-accent) 20%, transparent);
|
||||||
|
color: var(--color-accent);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease-out;
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-expand-trigger:hover {
|
||||||
|
background: color-mix(in srgb, var(--color-accent) 30%, transparent);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 12px rgba(168, 85, 247, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-expand-trigger i {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
animation: bounce 1.5s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bounce {
|
||||||
|
0%, 100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translateY(3px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Language-specific badge colors */
|
||||||
|
.mb-codeblock[data-lang="javascript"] .mb-codeblock-badge,
|
||||||
|
.mb-codeblock[data-lang="js"] .mb-codeblock-badge {
|
||||||
|
background: color-mix(in srgb, #f7df1e 25%, transparent);
|
||||||
|
color: #f7df1e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-codeblock[data-lang="typescript"] .mb-codeblock-badge,
|
||||||
|
.mb-codeblock[data-lang="ts"] .mb-codeblock-badge {
|
||||||
|
background: color-mix(in srgb, #3178c6 25%, transparent);
|
||||||
|
color: #3178c6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-codeblock[data-lang="python"] .mb-codeblock-badge,
|
||||||
|
.mb-codeblock[data-lang="py"] .mb-codeblock-badge {
|
||||||
|
background: color-mix(in srgb, #3776ab 25%, transparent);
|
||||||
|
color: #3776ab;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-codeblock[data-lang="go"] .mb-codeblock-badge {
|
||||||
|
background: color-mix(in srgb, #00add8 25%, transparent);
|
||||||
|
color: #00add8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-codeblock[data-lang="rust"] .mb-codeblock-badge,
|
||||||
|
.mb-codeblock[data-lang="rs"] .mb-codeblock-badge {
|
||||||
|
background: color-mix(in srgb, #ce422b 25%, transparent);
|
||||||
|
color: #ce422b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-codeblock[data-lang="html"] .mb-codeblock-badge {
|
||||||
|
background: color-mix(in srgb, #e34c26 25%, transparent);
|
||||||
|
color: #e34c26;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-codeblock[data-lang="css"] .mb-codeblock-badge {
|
||||||
|
background: color-mix(in srgb, #264de4 25%, transparent);
|
||||||
|
color: #264de4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-codeblock[data-lang="bash"] .mb-codeblock-badge,
|
||||||
|
.mb-codeblock[data-lang="sh"] .mb-codeblock-badge,
|
||||||
|
.mb-codeblock[data-lang="shell"] .mb-codeblock-badge {
|
||||||
|
background: color-mix(in srgb, #4eaa25 25%, transparent);
|
||||||
|
color: #4eaa25;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-codeblock[data-lang="json"] .mb-codeblock-badge {
|
||||||
|
background: color-mix(in srgb, #000000 25%, transparent);
|
||||||
|
color: #dddddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-codeblock[data-lang="yaml"] .mb-codeblock-badge,
|
||||||
|
.mb-codeblock[data-lang="yml"] .mb-codeblock-badge {
|
||||||
|
background: color-mix(in srgb, #cb171e 25%, transparent);
|
||||||
|
color: #cb171e;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<h{{ .Level }} id="{{ .Anchor }}">
|
||||||
|
<a href="#{{ .Anchor }}" class="md-heading-anchor">
|
||||||
|
{{ .Text | safeHTML }}
|
||||||
|
</a>
|
||||||
|
</h{{ .Level }}>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<figure class="md-image">
|
||||||
|
<a href="{{ .Destination | safeURL }}" class="glightbox">
|
||||||
|
<img
|
||||||
|
src="{{ .Destination | safeURL }}"
|
||||||
|
alt="{{ .Text }}"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
{{ with .Title }}
|
||||||
|
<figcaption>{{ . }}</figcaption>
|
||||||
|
{{ end }}
|
||||||
|
</figure>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<a
|
||||||
|
href="{{ .Destination | safeURL }}"
|
||||||
|
{{ if strings.HasPrefix .Destination "http" }}target="_blank" rel="noopener"{{ end }}
|
||||||
|
class="md-link"
|
||||||
|
>
|
||||||
|
{{ .Text | safeHTML }}
|
||||||
|
</a>
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<div class="table-wrap">
|
||||||
|
<table
|
||||||
|
{{- range $k, $v := .Attributes }}
|
||||||
|
{{- if $v }}
|
||||||
|
{{- printf " %s=%q" $k $v | safeHTMLAttr }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}>
|
||||||
|
<thead>
|
||||||
|
{{- range .THead }}
|
||||||
|
<tr>
|
||||||
|
{{- range . }}
|
||||||
|
<th
|
||||||
|
{{- with .Alignment }}
|
||||||
|
{{- printf " style=%q" (printf "text-align: %s" .) | safeHTMLAttr }}
|
||||||
|
{{- end -}}
|
||||||
|
>
|
||||||
|
{{- .Text -}}
|
||||||
|
</th>
|
||||||
|
{{- end }}
|
||||||
|
</tr>
|
||||||
|
{{- end }}
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{- range .TBody }}
|
||||||
|
<tr>
|
||||||
|
{{- range . }}
|
||||||
|
<td
|
||||||
|
{{- with .Alignment }}
|
||||||
|
{{- printf " style=%q" (printf "text-align: %s" .) | safeHTMLAttr }}
|
||||||
|
{{- end -}}
|
||||||
|
>
|
||||||
|
{{- .Text -}}
|
||||||
|
</td>
|
||||||
|
{{- end }}
|
||||||
|
</tr>
|
||||||
|
{{- end }}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{{- $type := .Get "type" | default "note" -}}
|
||||||
|
<div class="md-alert md-alert-{{ $type }}">
|
||||||
|
{{ .Inner | markdownify }}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{{- $images := split (.Get "images") "," -}}
|
||||||
|
{{- $captions := split (default "" (.Get "captions")) "," -}}
|
||||||
|
|
||||||
|
<div class="gallery-container" data-jg>
|
||||||
|
{{- if .Inner -}}
|
||||||
|
{{- /* If Inner content is provided, convert markdown images to lightbox-ready anchors */ -}}
|
||||||
|
{{- $content := .Inner -}}
|
||||||
|
{{- $content = replaceRE `!\[([^\]]*)\]\(([^\)]+)\)` `<a href="$2" class="glightbox" data-glightbox="description: $1"><img src="$2" alt="$1" loading="lazy"></a>` $content -}}
|
||||||
|
{{ $content | safeHTML }}
|
||||||
|
{{- else if $images -}}
|
||||||
|
{{- /* Otherwise, generate from images parameter */ -}}
|
||||||
|
{{- range $index, $image := $images -}}
|
||||||
|
{{- $imagePath := trim $image " " -}}
|
||||||
|
{{- $caption := "" -}}
|
||||||
|
{{- if $captions -}}
|
||||||
|
{{- $caption = index $captions $index | default "" | trim " " -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- if $imagePath -}}
|
||||||
|
<a href="{{ $imagePath | relURL }}" class="glightbox" data-glightbox="{{ if $caption }}description: {{ $caption }}{{ end }}">
|
||||||
|
<img src="{{ $imagePath | relURL }}" alt="{{ $caption | default $imagePath }}" loading="lazy">
|
||||||
|
</a>
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- /* Fallback: try to get images from page resources */ -}}
|
||||||
|
{{- $resources := .Page.Resources.Match "images/*" -}}
|
||||||
|
{{- if $resources -}}
|
||||||
|
{{- range $resources -}}
|
||||||
|
<a href="{{ .RelPermalink }}" class="glightbox">
|
||||||
|
<img src="{{ .Resize "300x" }}" alt="{{ .Name }}" loading="lazy">
|
||||||
|
</a>
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
</div>
|
||||||
156
themes/minimal-black/layouts/_default/about-alternative.html
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
{{ define "main" }}
|
||||||
|
<section class="layout-page">
|
||||||
|
<article class="about-alt-page">
|
||||||
|
|
||||||
|
<div class="about-alt-layout">
|
||||||
|
<!-- Left Sidebar - Profile Card -->
|
||||||
|
<aside class="about-alt-sidebar">
|
||||||
|
<div class="about-alt-profile-card">
|
||||||
|
{{ with .Site.Params.hero.avatar }}
|
||||||
|
<div class="about-alt-avatar">
|
||||||
|
<img src="{{ . | relURL }}" alt="{{ $.Site.Params.brand }}" />
|
||||||
|
</div>
|
||||||
|
{{ else }}
|
||||||
|
<div class="about-alt-avatar-placeholder">
|
||||||
|
<i class="fas fa-code"></i>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<h1 class="about-alt-name">{{ $.Site.Params.brand }}</h1>
|
||||||
|
|
||||||
|
{{ with .Params.subtitle }}
|
||||||
|
<p class="about-alt-role">{{ . }}</p>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ with .Site.Params.hero.location }}
|
||||||
|
<div class="about-alt-meta">
|
||||||
|
<i class="fas fa-map-marker-alt"></i>
|
||||||
|
<span>{{ . }}</span>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<!-- Quick Stats -->
|
||||||
|
{{ with $.Site.Params.about.alt.stats }}
|
||||||
|
<div class="about-alt-stats">
|
||||||
|
{{ range . }}
|
||||||
|
<div class="about-alt-stat">
|
||||||
|
<div class="about-alt-stat-value">{{ .value }}</div>
|
||||||
|
<div class="about-alt-stat-label">{{ .label }}</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<!-- Social Links -->
|
||||||
|
{{ with .Site.Params.social }}
|
||||||
|
<div class="about-alt-social">
|
||||||
|
{{ range . }}
|
||||||
|
<a
|
||||||
|
href="{{ .url }}"
|
||||||
|
class="about-alt-social-icon"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="{{ .label }}"
|
||||||
|
>
|
||||||
|
<i class="{{ .icon }}"></i>
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<!-- Right Content Area -->
|
||||||
|
<div class="about-alt-content">
|
||||||
|
<!-- Introduction -->
|
||||||
|
<div class="about-alt-section">
|
||||||
|
<div class="markdown-body">
|
||||||
|
{{ $content := .Content }}
|
||||||
|
{{ $content = replace $content "<hr>" "|||SPLIT|||" }}
|
||||||
|
{{ $content = replace $content "<hr />" "|||SPLIT|||" }}
|
||||||
|
{{ $content = replace $content "<hr/>" "|||SPLIT|||" }}
|
||||||
|
{{ $parts := split $content "|||SPLIT|||" }}
|
||||||
|
|
||||||
|
{{ index $parts 0 | safeHTML }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Experience Cards -->
|
||||||
|
{{ if gt (len $parts) 1 }}
|
||||||
|
{{- $experienceParts := slice -}}
|
||||||
|
{{- $additionalContent := "" -}}
|
||||||
|
{{- $foundNonExperience := false -}}
|
||||||
|
|
||||||
|
{{- range $index, $part := after 1 $parts -}}
|
||||||
|
{{- $trimmed := trim $part " \n\t" -}}
|
||||||
|
{{- if $trimmed -}}
|
||||||
|
{{- /* Check if this looks like an experience card (starts with <p><strong>) or is additional content (starts with <h) */ -}}
|
||||||
|
{{- if or (hasPrefix $trimmed "<p><strong>") (hasPrefix $trimmed "<p><strong ") (hasPrefix $trimmed "<p>\n<strong") (hasPrefix $trimmed "<p> <strong") -}}
|
||||||
|
{{- if not $foundNonExperience -}}
|
||||||
|
{{- $experienceParts = $experienceParts | append $part -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $additionalContent = printf "%s|||SPLIT|||%s" $additionalContent $part -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $foundNonExperience = true -}}
|
||||||
|
{{- $additionalContent = printf "%s|||SPLIT|||%s" $additionalContent $part -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- if gt (len $experienceParts) 0 -}}
|
||||||
|
<div class="about-alt-section">
|
||||||
|
<h2 class="about-alt-section-title">
|
||||||
|
<i class="fas fa-briefcase"></i>
|
||||||
|
<span>Experience</span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="about-alt-experience-grid">
|
||||||
|
{{- range $experienceParts -}}
|
||||||
|
<div class="about-alt-experience-card">
|
||||||
|
{{ . | safeHTML }}
|
||||||
|
</div>
|
||||||
|
{{- end -}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- /* Render additional content sections */ -}}
|
||||||
|
{{- if $additionalContent -}}
|
||||||
|
{{- $additionalParts := split $additionalContent "|||SPLIT|||" -}}
|
||||||
|
{{- range $additionalParts -}}
|
||||||
|
{{- $trimmed := trim . " \n\t" -}}
|
||||||
|
{{- if $trimmed -}}
|
||||||
|
<div class="about-alt-section">
|
||||||
|
<div class="markdown-body">
|
||||||
|
{{ . | safeHTML }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<!-- Skills Badge Cloud -->
|
||||||
|
{{ with $.Site.Params.about.alt.skills }}
|
||||||
|
<div class="about-alt-section">
|
||||||
|
<h2 class="about-alt-section-title">
|
||||||
|
<i class="fas fa-code"></i>
|
||||||
|
<span>Tech Stack</span>
|
||||||
|
</h2>
|
||||||
|
<div class="about-alt-skills">
|
||||||
|
{{ range . }}
|
||||||
|
<span class="about-alt-skill">
|
||||||
|
{{ with .icon }}<i class="{{ . }}"></i>{{ end }}
|
||||||
|
{{ .label }}
|
||||||
|
</span>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
{{ end }}
|
||||||
77
themes/minimal-black/layouts/_default/about.html
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
{{ define "main" }}
|
||||||
|
<section class="layout-page">
|
||||||
|
<article class="about-page">
|
||||||
|
<!-- Hero Section -->
|
||||||
|
<header class="about-hero">
|
||||||
|
<div class="about-hero-content">
|
||||||
|
{{ with .Site.Params.hero.avatar }}
|
||||||
|
<div class="about-avatar">
|
||||||
|
<img src="{{ . | relURL }}" alt="{{ $.Site.Params.brand }}" />
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<h1 class="about-title">{{ .Title }}</h1>
|
||||||
|
|
||||||
|
{{ with .Params.subtitle }}
|
||||||
|
<p class="about-subtitle">{{ . }}</p>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="about-content">
|
||||||
|
<div class="card card-pad markdown-body">
|
||||||
|
{{ $content := .Content }}
|
||||||
|
{{ $content = replace $content "<hr>" "|||SPLIT|||" }}
|
||||||
|
{{ $content = replace $content "<hr />" "|||SPLIT|||" }}
|
||||||
|
{{ $content = replace $content "<hr/>" "|||SPLIT|||" }}
|
||||||
|
{{ $parts := split $content "|||SPLIT|||" }}
|
||||||
|
|
||||||
|
{{ if eq (len $parts) 1 }}
|
||||||
|
<!-- No timeline, render normally -->
|
||||||
|
{{ .Content }}
|
||||||
|
{{ else }}
|
||||||
|
<!-- Render intro section (everything before first hr) -->
|
||||||
|
{{ index $parts 0 | safeHTML }}
|
||||||
|
|
||||||
|
<!-- Render timeline -->
|
||||||
|
<div class="timeline">
|
||||||
|
{{ range after 1 $parts }}
|
||||||
|
{{ $trimmed := trim . " \n\t" }}
|
||||||
|
{{ if $trimmed }}
|
||||||
|
<div class="timeline-item">
|
||||||
|
<div class="timeline-marker"></div>
|
||||||
|
<div class="timeline-content">
|
||||||
|
{{ . | safeHTML }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Social Links Footer -->
|
||||||
|
{{ with .Site.Params.social }}
|
||||||
|
<div class="about-social">
|
||||||
|
<h3 class="about-social-title">Let's Connect</h3>
|
||||||
|
<div class="about-social-links">
|
||||||
|
{{ range . }}
|
||||||
|
<a
|
||||||
|
href="{{ .url }}"
|
||||||
|
class="about-social-link"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="{{ .label }}"
|
||||||
|
>
|
||||||
|
<i class="{{ .icon }}"></i>
|
||||||
|
<span>{{ .label }}</span>
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
{{ end }}
|
||||||
30
themes/minimal-black/layouts/_default/baseof.html
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="{{ .Site.Language.Lang }}"
|
||||||
|
data-cb-collapse-enabled="{{ .Site.Params.features.codeblock.collapse.enabled }}"
|
||||||
|
data-cb-collapse-default="{{ .Site.Params.features.codeblock.collapse.defaultState }}"
|
||||||
|
data-cb-collapse-lines="{{ .Site.Params.features.codeblock.collapse.autoCollapseLines }}"
|
||||||
|
data-cb-collapse-auto-height="{{ .Site.Params.features.codeblock.collapse.autoCollapseHeight }}"
|
||||||
|
data-cb-collapse-collapsed-height="{{ .Site.Params.features.codeblock.collapse.collapsedHeight }}">
|
||||||
|
<head>
|
||||||
|
{{ partial "head.html" . }}
|
||||||
|
</head>
|
||||||
|
<body class="min-h-screen bg-bg text-text antialiased">
|
||||||
|
<div class="flex min-h-screen flex-col">
|
||||||
|
{{ partial "header.html" . }}
|
||||||
|
|
||||||
|
<main class="flex-1">
|
||||||
|
{{ block "main" . }}{{ end }}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
{{ partial "footer.html" . }}
|
||||||
|
</div>
|
||||||
|
{{ partial "search-overlay.html" . }}
|
||||||
|
{{ partial "dock.html" . }}
|
||||||
|
<script src="{{ "js/main.js" | relURL }}" defer></script>
|
||||||
|
<script src="{{ "js/search.js" | relURL }}" defer></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/glightbox/dist/js/glightbox.min.js" defer></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/justified-gallery@3.8.2/dist/js/justifiedGallery.min.js" defer></script>
|
||||||
|
<script src="{{ "js/lightbox.js" | relURL }}" defer></script>
|
||||||
|
<script src="{{ "js/gallery.js" | relURL }}" defer></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
30
themes/minimal-black/layouts/_default/list.html
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{{ define "main" }}
|
||||||
|
<section class="layout-page-tight">
|
||||||
|
<div class="page-int">
|
||||||
|
<header class="mb-8">
|
||||||
|
<h1 class="heading-page text-2xl sm:text-3xl">{{ .Title }}</h1>
|
||||||
|
{{ with .Description }}
|
||||||
|
<p class="mt-2 text-sm text-muted">{{ . }}</p>
|
||||||
|
{{ end }}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
{{ range .Pages.ByDate.Reverse }}
|
||||||
|
<article class="border-b border-border pb-6 last:border-0">
|
||||||
|
<a href="{{ .RelPermalink }}" class="group block">
|
||||||
|
<h2 class="text-lg font-medium tracking-tight group-hover:text-accent">
|
||||||
|
{{ .Title }}
|
||||||
|
</h2>
|
||||||
|
{{ with .Params.description }}
|
||||||
|
<p class="mt-1 text-sm text-muted">{{ . }}</p>
|
||||||
|
{{ end }} {{ with .Date }}
|
||||||
|
<p class="mt-2 text-xs text-muted">{{ .Format "January 2, 2006" }}</p>
|
||||||
|
{{ end }}
|
||||||
|
</a>
|
||||||
|
</article>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
</div>
|
||||||
154
themes/minimal-black/layouts/_default/single.html
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
{{ define "main" }}
|
||||||
|
<section class="layout-page section-stack">
|
||||||
|
<div class="article-layout">
|
||||||
|
<article class="article-main space-y-4">
|
||||||
|
<header class="space-y-2">
|
||||||
|
<h1 class="heading-page text-2xl sm:text-3xl">{{ .Title }}</h1>
|
||||||
|
|
||||||
|
<div class="text-[0.75rem] text-muted">
|
||||||
|
{{ with .Date }}
|
||||||
|
<span>{{ .Format "02 Jan 2006" }}</span>
|
||||||
|
{{ end }}
|
||||||
|
{{ with .ReadingTime }}
|
||||||
|
<span> • {{ . }} min read</span>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ with .Params.description }}
|
||||||
|
<p class="max-w-xl text-sm text-muted">
|
||||||
|
{{ . }}
|
||||||
|
</p>
|
||||||
|
{{ end }}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="card card-pad">
|
||||||
|
<div class="markdown-body">
|
||||||
|
{{ .Content }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
{{ if .TableOfContents }}
|
||||||
|
<aside class="article-toc">
|
||||||
|
<div class="toc-wrapper">
|
||||||
|
<div class="toc-header">
|
||||||
|
<h3 class="toc-title">
|
||||||
|
<i class="fas fa-list-ul"></i>
|
||||||
|
<span>Table of Contents</span>
|
||||||
|
</h3>
|
||||||
|
<button class="toc-toggle" aria-label="Toggle table of contents">
|
||||||
|
<i class="fas fa-chevron-down"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<nav class="toc-nav">
|
||||||
|
{{ .TableOfContents }}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const tocWrapper = document.querySelector('.toc-wrapper');
|
||||||
|
const tocToggle = document.querySelector('.toc-toggle');
|
||||||
|
const tocNav = document.querySelector('.toc-nav');
|
||||||
|
const tocLinks = document.querySelectorAll('.toc-nav a');
|
||||||
|
|
||||||
|
if (!tocWrapper || !tocNav) return;
|
||||||
|
|
||||||
|
// =====================
|
||||||
|
// MOBILE TOGGLE
|
||||||
|
// =====================
|
||||||
|
if (tocToggle) {
|
||||||
|
tocToggle.addEventListener('click', function() {
|
||||||
|
tocWrapper.classList.toggle('collapsed');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================
|
||||||
|
// SMOOTH SCROLLING
|
||||||
|
// =====================
|
||||||
|
tocLinks.forEach(link => {
|
||||||
|
link.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const targetId = this.getAttribute('href');
|
||||||
|
const targetElement = document.querySelector(targetId);
|
||||||
|
|
||||||
|
if (targetElement) {
|
||||||
|
const yOffset = -80; // offset for sticky header
|
||||||
|
const y = targetElement.getBoundingClientRect().top + window.pageYOffset + yOffset;
|
||||||
|
|
||||||
|
window.scrollTo({
|
||||||
|
top: y,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update URL without scrolling
|
||||||
|
history.pushState(null, null, targetId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// =====================
|
||||||
|
// ACTIVE LINK HIGHLIGHT
|
||||||
|
// =====================
|
||||||
|
const headings = document.querySelectorAll('.markdown-body h1[id], .markdown-body h2[id], .markdown-body h3[id], .markdown-body h4[id], .markdown-body h5[id], .markdown-body h6[id]');
|
||||||
|
|
||||||
|
let activeHeading = null;
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
// Find all currently intersecting headings
|
||||||
|
const intersectingHeadings = [];
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
intersectingHeadings.push({
|
||||||
|
element: entry.target,
|
||||||
|
top: entry.boundingClientRect.top
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// If we have intersecting headings, find the one closest to the top
|
||||||
|
if (intersectingHeadings.length > 0) {
|
||||||
|
// Sort by distance from top (smallest positive value or largest negative)
|
||||||
|
intersectingHeadings.sort((a, b) => Math.abs(a.top) - Math.abs(b.top));
|
||||||
|
|
||||||
|
const closestHeading = intersectingHeadings[0].element;
|
||||||
|
const id = closestHeading.getAttribute('id');
|
||||||
|
|
||||||
|
if (id && id !== activeHeading) {
|
||||||
|
activeHeading = id;
|
||||||
|
const tocLink = document.querySelector(`.toc-nav a[href="#${id}"]`);
|
||||||
|
|
||||||
|
if (tocLink) {
|
||||||
|
// Remove active from all links
|
||||||
|
tocLinks.forEach(link => link.classList.remove('active'));
|
||||||
|
// Add active to current link
|
||||||
|
tocLink.classList.add('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rootMargin: '-80px 0px -80%',
|
||||||
|
threshold: [0, 0.25, 0.5, 0.75, 1]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Observe all headings
|
||||||
|
headings.forEach((heading) => {
|
||||||
|
observer.observe(heading);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Highlight first item by default
|
||||||
|
if (tocLinks.length > 0) {
|
||||||
|
tocLinks[0].classList.add('active');
|
||||||
|
activeHeading = tocLinks[0].getAttribute('href').substring(1);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{{ end }}
|
||||||
48
themes/minimal-black/layouts/blog/list.html
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
{{ define "main" }}
|
||||||
|
<section class="layout-page">
|
||||||
|
<div class="page-int section-stack">
|
||||||
|
<header class="space-y-2">
|
||||||
|
<h1 class="heading-page text-2xl sm:text-3xl">Blog</h1>
|
||||||
|
{{ with .Site.Params.blogIntro }}
|
||||||
|
<p class="max-w-xl text-sm text-muted">
|
||||||
|
{{ . }}
|
||||||
|
</p>
|
||||||
|
{{ else }}
|
||||||
|
<p class="max-w-xl text-sm text-muted">
|
||||||
|
Notes on engineering, design, and building small, thoughtful tools.
|
||||||
|
</p>
|
||||||
|
{{ end }}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{{/* Paginate all posts in this section */}}
|
||||||
|
{{ $paginator := .Paginate .Pages }}
|
||||||
|
|
||||||
|
<div class="grid gap-4 md:grid-cols-2">
|
||||||
|
{{ range $paginator.Pages.ByDate.Reverse }}
|
||||||
|
{{ partial "components/post-card.html" (dict "Page" . "Root" $) }}
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{/* Simple pagination controls */}}
|
||||||
|
{{ if gt $paginator.TotalPages 1 }}
|
||||||
|
<nav class="mt-6 flex items-center justify-between text-xs text-muted">
|
||||||
|
{{ if $paginator.HasPrev }}
|
||||||
|
<a href="{{ $paginator.Prev.URL }}" class="link-underline">
|
||||||
|
← Newer posts
|
||||||
|
</a>
|
||||||
|
{{ else }}
|
||||||
|
<span></span>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if $paginator.HasNext }}
|
||||||
|
<a href="{{ $paginator.Next.URL }}" class="link-underline">
|
||||||
|
Older posts →
|
||||||
|
</a>
|
||||||
|
{{ else }}
|
||||||
|
<span></span>
|
||||||
|
{{ end }}
|
||||||
|
</nav>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{{ end }}
|
||||||
12
themes/minimal-black/layouts/index.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{{ define "main" }}
|
||||||
|
<section class="layout-page">
|
||||||
|
<div class="page-int section-stack section-stack--home">
|
||||||
|
{{ $default := slice "hero" "now" "tech-marquee" "projects" "posts" }}
|
||||||
|
{{ $sections := .Site.Params.home.sections | default $default }}
|
||||||
|
|
||||||
|
{{ range $sections }}
|
||||||
|
{{ partial (printf "home/%s.html" .) $ }}
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{{ end }}
|
||||||
17
themes/minimal-black/layouts/index.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{{- $pages := slice -}}
|
||||||
|
|
||||||
|
{{- range .Site.RegularPages -}}
|
||||||
|
{{- $summary := .Summary -}}
|
||||||
|
{{- if not $summary -}}
|
||||||
|
{{- $summary = .Description -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- $pages = $pages | append (dict
|
||||||
|
"title" .Title
|
||||||
|
"permalink" .Permalink
|
||||||
|
"section" .Section
|
||||||
|
"summary" (plainify $summary)
|
||||||
|
) -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- dict "pages" $pages | jsonify -}}
|
||||||
61
themes/minimal-black/layouts/index.webappmanifest
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{{- $title := .Site.Title -}}
|
||||||
|
{{- $shortName := .Site.Params.brand | default .Site.Title -}}
|
||||||
|
{{- $description := .Site.Params.description | default "A minimal, dark-mode first personal site" -}}
|
||||||
|
{{- $themeColor := .Site.Params.manifest.themeColor | default "#a855f7" -}}
|
||||||
|
{{- $bgColor := .Site.Params.manifest.backgroundColor | default "#000000" -}}
|
||||||
|
{{- $lang := .Site.Language.Lang | default "en" -}}
|
||||||
|
{
|
||||||
|
"name": "{{ $title }}",
|
||||||
|
"short_name": "{{ $shortName }}",
|
||||||
|
"description": "{{ $description }}",
|
||||||
|
"start_url": "{{ "/" | relURL }}",
|
||||||
|
"scope": "{{ "/" | relURL }}",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "{{ $bgColor }}",
|
||||||
|
"theme_color": "{{ $themeColor }}",
|
||||||
|
"orientation": "portrait-primary",
|
||||||
|
"icons": [
|
||||||
|
{{- if .Site.Params.manifest.icons }}
|
||||||
|
{{- range $i, $icon := .Site.Params.manifest.icons }}
|
||||||
|
{{- if $i }},{{ end }}
|
||||||
|
{
|
||||||
|
"src": "{{ $icon.src | relURL }}",
|
||||||
|
"sizes": "{{ $icon.sizes }}",
|
||||||
|
"type": "{{ $icon.type | default "image/png" }}"
|
||||||
|
{{- with $icon.purpose }},"purpose": "{{ . }}"{{ end }}
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
|
{
|
||||||
|
"src": "/icons/android-chrome-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "any maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/android-chrome-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "any maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/apple-touch-icon.png",
|
||||||
|
"sizes": "180x180",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/favicon-32x32.png",
|
||||||
|
"sizes": "32x32",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/favicon-16x16.png",
|
||||||
|
"sizes": "16x16",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
],
|
||||||
|
"categories": "{{ .Site.Params.manifest.categories | default (slice "blog" "portfolio" "developer") }}",
|
||||||
|
"lang": "{{ $lang }}",
|
||||||
|
"dir": "ltr"
|
||||||
|
}
|
||||||
46
themes/minimal-black/layouts/partials/analytics.html
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
{{- if not hugo.IsServer -}}
|
||||||
|
|
||||||
|
<!-- Google Analytics (GA4) -->
|
||||||
|
{{ with .Site.Params.analytics.googleAnalytics }}
|
||||||
|
{{ if . }}
|
||||||
|
<script async src="https://www.googletagmanager.com/gtag/js?id={{ . }}"></script>
|
||||||
|
<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag(){dataLayer.push(arguments);}
|
||||||
|
gtag('js', new Date());
|
||||||
|
gtag('config', '{{ . }}');
|
||||||
|
</script>
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<!-- Plausible Analytics -->
|
||||||
|
{{ with .Site.Params.analytics.plausible }}
|
||||||
|
{{ if .enabled }}
|
||||||
|
<script defer data-domain="{{ .domain }}" src="{{ default "https://plausible.io/js/script.js" .scriptUrl }}"></script>
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<!-- Umami Analytics -->
|
||||||
|
{{ with .Site.Params.analytics.umami }}
|
||||||
|
{{ if .enabled }}
|
||||||
|
<script defer src="{{ .scriptUrl }}" data-website-id="{{ .websiteId }}"></script>
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<!-- Fathom Analytics -->
|
||||||
|
{{ with .Site.Params.analytics.fathom }}
|
||||||
|
{{ if .enabled }}
|
||||||
|
<script src="{{ .scriptUrl }}" data-site="{{ .siteId }}" defer></script>
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<!-- Custom Analytics Scripts -->
|
||||||
|
{{ with .Site.Params.analytics.custom }}
|
||||||
|
{{ if .head }}
|
||||||
|
{{ range .head }}
|
||||||
|
{{ . | safeHTML }}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{- end -}}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
{{/* props: Page (post page) */}}
|
||||||
|
{{- $p := .Page -}}
|
||||||
|
{{- $icon := $p.Params.icon | default "fa-regular fa-file-lines" -}}
|
||||||
|
{{- $category := $p.Params.category | default "Article" -}}
|
||||||
|
|
||||||
|
<article class="card card-pad card-home card-home--post group">
|
||||||
|
<a href="{{ $p.RelPermalink }}" class="card-home-body">
|
||||||
|
<div class="card-home-header">
|
||||||
|
<div class="card-home-icon card-home-icon--post">
|
||||||
|
<i class="{{ $icon }}"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="min-w-0">
|
||||||
|
<div class="flex items-start justify-between gap-2">
|
||||||
|
<div class="min-w-0">
|
||||||
|
<h3 class="truncate text-sm font-semibold tracking-tight group-hover:text-accent">
|
||||||
|
{{ $p.Title }}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="mt-0.5 flex flex-wrap items-center gap-2 text-[0.68rem] text-muted">
|
||||||
|
{{ with $p.Date }}
|
||||||
|
<span>{{ .Format "02 Jan 2006" }}</span>
|
||||||
|
{{ end }}
|
||||||
|
{{ with $p.ReadingTime }}
|
||||||
|
<span>• {{ . }} min read</span>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ with $category }}
|
||||||
|
<span class="card-badge card-badge--soft">
|
||||||
|
{{ . }}
|
||||||
|
</span>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ with $p.Params.description }}
|
||||||
|
<p class="mt-2 text-xs text-muted">
|
||||||
|
{{ . }}
|
||||||
|
</p>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ with $p.Params.tags }}
|
||||||
|
<div class="mt-3 card-tag-row">
|
||||||
|
{{ range first 3 . }}
|
||||||
|
<span class="card-tag-pill">{{ . }}</span>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</a>
|
||||||
|
</article>
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
{{/* props: Page (project page) */}}
|
||||||
|
{{- $p := .Page -}}
|
||||||
|
|
||||||
|
{{- $icon := $p.Params.icon | default "fa-solid fa-folder-tree" -}}
|
||||||
|
{{- $badge := cond ($p.Params.featured) "Featured" "" -}}
|
||||||
|
|
||||||
|
{{- $repo := $p.Params.repo -}}
|
||||||
|
{{- $repoIcon := $p.Params.repoIcon | default "fa-brands fa-github" -}}
|
||||||
|
{{- $repoLabel := $p.Params.repoLabel | default "Repo" -}}
|
||||||
|
|
||||||
|
{{- $demo := $p.Params.demo -}}
|
||||||
|
{{- $demoIcon := $p.Params.demoIcon | default "fa-solid fa-play" -}}
|
||||||
|
{{- $demoLabel := $p.Params.demoLabel | default "Demo" -}}
|
||||||
|
|
||||||
|
{{- $website := $p.Params.website -}}
|
||||||
|
{{- $websiteIcon := $p.Params.websiteIcon | default "fa-solid fa-globe" -}}
|
||||||
|
{{- $websiteLabel := $p.Params.websiteLabel | default "Website" -}}
|
||||||
|
|
||||||
|
<article class="card card-pad card-home card-home--project group">
|
||||||
|
<!-- Entire main body is clickable -->
|
||||||
|
<a href="{{ $p.RelPermalink }}" class="card-home-body">
|
||||||
|
<div class="card-home-header">
|
||||||
|
<div class="card-home-icon">
|
||||||
|
<i class="{{ $icon }}"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="min-w-0">
|
||||||
|
<div class="inline-flex items-center gap-1">
|
||||||
|
<h3 class="truncate text-sm font-semibold tracking-tight group-hover:text-accent">
|
||||||
|
{{ $p.Title }}
|
||||||
|
</h3>
|
||||||
|
{{ with $badge }}
|
||||||
|
<span class="card-badge">{{ . }}</span>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ with $p.Params.subtitle }}
|
||||||
|
<p class="mt-0.5 truncate text-[0.7rem] text-muted">
|
||||||
|
{{ . }}
|
||||||
|
</p>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ with $p.Params.description }}
|
||||||
|
<p class="mt-2 text-xs text-muted">
|
||||||
|
{{ . }}
|
||||||
|
</p>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ with $p.Params.stack }}
|
||||||
|
<div class="mt-3 card-tag-row">
|
||||||
|
{{ range . }}
|
||||||
|
<span class="card-tag-pill">{{ . }}</span>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Footer buttons: repo, demo, website -->
|
||||||
|
<div class="card-home-footer card-home-footer--buttons">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
|
||||||
|
{{ with $repo }}
|
||||||
|
<a href="{{ . }}" class="card-cta-btn" target="_blank" rel="noopener noreferrer">
|
||||||
|
<i class="{{ $repoIcon }} text-[0.75rem]"></i>
|
||||||
|
<span>{{ $repoLabel }}</span>
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ with $demo }}
|
||||||
|
<a href="{{ . }}" class="card-cta-btn" target="_blank" rel="noopener noreferrer">
|
||||||
|
<i class="{{ $demoIcon }} text-[0.75rem]"></i>
|
||||||
|
<span>{{ $demoLabel }}</span>
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ with $website }}
|
||||||
|
<a href="{{ . }}" class="card-cta-btn" target="_blank" rel="noopener noreferrer">
|
||||||
|
<i class="{{ $websiteIcon }} text-[0.75rem]"></i>
|
||||||
|
<span>{{ $websiteLabel }}</span>
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{{/* props: Title, Url, Small (bool) */}} {{- $title := .Title | default
|
||||||
|
"Section" -}} {{- $url := .Url -}} {{- $small := .Small | default false -}}
|
||||||
|
|
||||||
|
<div class="flex items-baseline justify-between gap-2">
|
||||||
|
<h2 class="heading-section">{{ $title }}</h2>
|
||||||
|
|
||||||
|
{{ with $url }}
|
||||||
|
<a href="{{ . | relURL }}" class="link-underline text-[0.72rem] text-muted">
|
||||||
|
{{ if $small }}All{{ else }}View all{{ end }}
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
41
themes/minimal-black/layouts/partials/dark-toggle.html
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="theme-toggle"
|
||||||
|
aria-label="Toggle dark mode"
|
||||||
|
data-theme-toggle
|
||||||
|
>
|
||||||
|
<span data-theme-icon-light style="display: none">
|
||||||
|
<!-- Sun icon -->
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="h-4 w-4"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<circle cx="12" cy="12" r="4" />
|
||||||
|
<path
|
||||||
|
d="M12 3v2m0 14v2m9-9h-2M5 12H3m15.364-6.364-1.414 1.414M8.05 15.95l-1.414 1.414m0-11.314L8.05 8.05m9.9 9.9-1.414-1.414"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span data-theme-icon-dark>
|
||||||
|
<!-- Moon icon -->
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="h-4 w-4"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path d="M21 12.79A9 9 0 0 1 12.21 3 7 7 0 1 0 21 12.79z" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
55
themes/minimal-black/layouts/partials/dock.html
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{{- $isHome := .IsHome -}}
|
||||||
|
|
||||||
|
<div class="dock" data-dock>
|
||||||
|
<div class="dock-inner">
|
||||||
|
<!-- Actions panel -->
|
||||||
|
<div class="dock-panel" data-dock-panel>
|
||||||
|
{{ if not $isHome }}
|
||||||
|
<!-- Back -->
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="dock-action"
|
||||||
|
data-dock-action="back"
|
||||||
|
aria-label="Go back"
|
||||||
|
>
|
||||||
|
<i class="fa-solid fa-arrow-left text-[0.7rem]"></i>
|
||||||
|
</button>
|
||||||
|
<span class="dock-divider" aria-hidden="true"></span>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<!-- Search -->
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="dock-action"
|
||||||
|
data-dock-action="search"
|
||||||
|
aria-label="Search"
|
||||||
|
onclick="window.MinimalSearch && window.MinimalSearch.open()"
|
||||||
|
>
|
||||||
|
<i class="fa-solid fa-magnifying-glass text-[0.7rem]"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Divider -->
|
||||||
|
<span class="dock-divider" aria-hidden="true"></span>
|
||||||
|
|
||||||
|
<!-- Back to top -->
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="dock-action"
|
||||||
|
data-dock-action="top"
|
||||||
|
aria-label="Back to top"
|
||||||
|
>
|
||||||
|
<i class="fa-solid fa-arrow-up text-[0.7rem]"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Toggle -->
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="dock-toggle"
|
||||||
|
aria-label="Open quick actions"
|
||||||
|
data-dock-toggle
|
||||||
|
>
|
||||||
|
<span class="dock-toggle-dots"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
56
themes/minimal-black/layouts/partials/footer.html
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<footer class="pb-6 pt-10">
|
||||||
|
<div class="mx-auto max-w-7xl px-4 sm:px-6">
|
||||||
|
<div class="footer-shell">
|
||||||
|
<div class="footer-inner">
|
||||||
|
<!-- Left -->
|
||||||
|
<div class="space-y-1">
|
||||||
|
<p class="footer-small">
|
||||||
|
© {{ now.Format "2006" }} {{ .Site.Title }} — All rights
|
||||||
|
reserved.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="footer-small flex flex-wrap items-center gap-1">
|
||||||
|
<span>Built with</span>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://gohugo.io/"
|
||||||
|
class="footer-link footer-float link-underline"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<span>Hugo</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<span>/</span>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="{{ .Site.Params.themeGit }}"
|
||||||
|
class="footer-link footer-float link-underline"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<span>Minimal Black</span>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right -->
|
||||||
|
{{ with .Site.Params.social }}
|
||||||
|
<div class="footer-links">
|
||||||
|
{{ range . }}
|
||||||
|
<a
|
||||||
|
href="{{ .url }}"
|
||||||
|
class="footer-link footer-float link-underline"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<i class="{{ .icon }} text-[0.8rem]"></i>
|
||||||
|
<span>{{ .label }}</span>
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
103
themes/minimal-black/layouts/partials/head.html
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
{{- $title := cond (ne .Title "") (printf "%s | %s" .Title .Site.Title)
|
||||||
|
.Site.Title -}}
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
|
<title>{{ $title }}</title>
|
||||||
|
|
||||||
|
{{ partial "meta.html" . }}
|
||||||
|
|
||||||
|
<!-- Favicon -->
|
||||||
|
{{ with .Site.Params.favicon }}
|
||||||
|
<link rel="icon" type="image/x-icon" href="{{ . | relURL }}" />
|
||||||
|
{{ else }}
|
||||||
|
<!-- Default favicon paths -->
|
||||||
|
{{ if fileExists "static/favicon.ico" }}
|
||||||
|
<link rel="icon" type="image/x-icon" href="{{ "favicon.ico" | relURL }}" />
|
||||||
|
{{ end }}
|
||||||
|
{{ if fileExists "static/favicon.png" }}
|
||||||
|
<link rel="icon" type="image/png" href="{{ "favicon.png" | relURL }}" />
|
||||||
|
{{ end }}
|
||||||
|
{{ if fileExists "static/favicon.svg" }}
|
||||||
|
<link rel="icon" type="image/svg+xml" href="{{ "favicon.svg" | relURL }}" />
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<!-- Apple Touch Icon -->
|
||||||
|
{{ if .Site.Params.appleTouchIcon }}
|
||||||
|
<link rel="apple-touch-icon" href="{{ . | relURL }}" />
|
||||||
|
{{ else if fileExists "static/apple-touch-icon.png" }}
|
||||||
|
<link rel="apple-touch-icon" href="{{ "apple-touch-icon.png" | relURL }}" />
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<!-- Web App Manifest -->
|
||||||
|
{{ with .Site.GetPage "/" }}
|
||||||
|
{{ range .OutputFormats }}
|
||||||
|
{{ if eq .Name "webappmanifest" }}
|
||||||
|
<link rel="manifest" href="{{ .Permalink }}" />
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="{{ "css/main.css" | relURL }}">
|
||||||
|
|
||||||
|
{{ if .Site.Params.icons.useFontAwesome }}
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css"
|
||||||
|
>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if .Site.Params.icons.useDevicon }}
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.17.0/devicon.min.css"
|
||||||
|
>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<!-- GLightbox -->
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://cdn.jsdelivr.net/npm/glightbox/dist/css/glightbox.min.css"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Justified Gallery (Vanilla) -->
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://cdn.jsdelivr.net/npm/justified-gallery@3.8.2/dist/css/justifiedGallery.min.css"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
|
||||||
|
<script>
|
||||||
|
mermaid.initialize({ theme: "dark" });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
try {
|
||||||
|
var stored = localStorage.getItem("theme");
|
||||||
|
var systemDark =
|
||||||
|
window.matchMedia &&
|
||||||
|
window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||||
|
var defaultTheme =
|
||||||
|
'{{ default "system" .Site.Params.theme.defaultTheme }}';
|
||||||
|
|
||||||
|
var theme =
|
||||||
|
stored ||
|
||||||
|
(defaultTheme === "dark"
|
||||||
|
? "dark"
|
||||||
|
: defaultTheme === "light"
|
||||||
|
? "light"
|
||||||
|
: systemDark
|
||||||
|
? "dark"
|
||||||
|
: "light");
|
||||||
|
|
||||||
|
document.documentElement.setAttribute("data-theme", theme);
|
||||||
|
} catch (e) {
|
||||||
|
document.documentElement.setAttribute("data-theme", "light");
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Analytics -->
|
||||||
|
{{ partial "analytics.html" . }}
|
||||||
86
themes/minimal-black/layouts/partials/header.html
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<header class="pt-6">
|
||||||
|
{{/* Brand string for logo/monogram */}}
|
||||||
|
{{- $brand := .Site.Params.brand | default .Site.Title}}
|
||||||
|
{{- $mono := upper (substr $brand 0 2) -}}
|
||||||
|
|
||||||
|
<div class="mx-auto max-w-7xl px-4 sm:px-6">
|
||||||
|
<!-- Floating nav container -->
|
||||||
|
<div class="nav-shell">
|
||||||
|
<div class="nav-inner">
|
||||||
|
<!-- Brand: logo or monogram, always links to root -->
|
||||||
|
<a href="{{ "/" | relURL }}" class="flex items-center gap-2">
|
||||||
|
{{ with .Site.Params.logo }}
|
||||||
|
<div class="flex h-8 w-8 items-center justify-center overflow-hidden rounded-full bg-surface">
|
||||||
|
<img
|
||||||
|
src="{{ . | relURL }}"
|
||||||
|
alt="{{ $brand }}"
|
||||||
|
class="h-full w-full object-cover"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
{{ else }}
|
||||||
|
<div class="logo-badge">
|
||||||
|
{{ $mono }}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
<span class="text-xs font-semibold tracking-wide">
|
||||||
|
{{ $brand }}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<!-- Desktop nav (configurable) -->
|
||||||
|
<nav class="hidden items-center gap-5 md:flex">
|
||||||
|
{{- $current := . -}}
|
||||||
|
{{- range .Site.Menus.main }}
|
||||||
|
<a
|
||||||
|
href="{{ .URL | relURL }}"
|
||||||
|
class="nav-link link-underline flex items-center gap-1 {{ if $current.IsMenuCurrent "main" . }}text-text{{ end }}"
|
||||||
|
>
|
||||||
|
{{ with .Params.icon }}
|
||||||
|
<i class="{{ . }} text-[0.75rem]"></i>
|
||||||
|
{{ end }}
|
||||||
|
<span>{{ .Name }}</span>
|
||||||
|
</a>
|
||||||
|
{{- end }}
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Theme toggle, sized to match nav -->
|
||||||
|
{{ partial "dark-toggle.html" . }}
|
||||||
|
|
||||||
|
<!-- Mobile menu button -->
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="ml-1 inline-flex items-center justify-center rounded-full border border-border bg-bg p-2 text-muted shadow-sm hover:text-accent md:hidden"
|
||||||
|
aria-label="Toggle navigation"
|
||||||
|
data-mobile-nav-toggle
|
||||||
|
>
|
||||||
|
<span class="sr-only">Open navigation</span>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none"
|
||||||
|
stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<line x1="4" y1="6" x2="20" y2="6" />
|
||||||
|
<line x1="4" y1="12" x2="20" y2="12" />
|
||||||
|
<line x1="4" y1="18" x2="20" y2="18" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Mobile nav (uses same menu config) -->
|
||||||
|
<div class="mx-auto mt-2 max-w-7xl px-4 sm:px-6 md:hidden">
|
||||||
|
<nav
|
||||||
|
class="hidden rounded-2xl border border-border bg-surface px-4 py-3 text-sm text-muted shadow-md"
|
||||||
|
data-mobile-nav
|
||||||
|
>
|
||||||
|
{{ range .Site.Menus.main }}
|
||||||
|
<a href="{{ .URL | relURL }}" class="flex items-center gap-2 py-1.5">
|
||||||
|
{{ with .Params.icon }}
|
||||||
|
<i class="{{ . }} text-[0.8rem]"></i>
|
||||||
|
{{ end }}
|
||||||
|
<span>{{ .Name }}</span>
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
94
themes/minimal-black/layouts/partials/home/hero.html
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
{{- $hero := .Site.Params.hero -}}
|
||||||
|
|
||||||
|
<div class="grid gap-8 md:grid-cols-[minmax(0,2fr)_minmax(0,1.2fr)] items-start">
|
||||||
|
<div class="space-y-5 animate-fade-up">
|
||||||
|
<!-- Badge + availability -->
|
||||||
|
<div class="flex flex-wrap items-center gap-4">
|
||||||
|
{{ with $hero.badge }}
|
||||||
|
<p class="eyebrow font-medium text-sm text-accent">{{ . }}</p>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if $hero.available }}
|
||||||
|
<span class="badge-available px-3">
|
||||||
|
<span class="h-1.5 w-1.5 rounded-full bg-white/95"></span>
|
||||||
|
<span>{{ default "Available for work" $hero.availableLabel }}</span>
|
||||||
|
</span>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-2">
|
||||||
|
<h1 class="heading-page text-3xl sm:text-4xl">
|
||||||
|
{{ default "Hi, I’m Your Name." $hero.title }}
|
||||||
|
</h1>
|
||||||
|
{{ with $hero.role }}
|
||||||
|
<p class="text-sm font-medium text-muted">
|
||||||
|
{{ . }}
|
||||||
|
</p>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ with $hero.summary }}
|
||||||
|
<p class="max-w-xl text-sm text-muted">
|
||||||
|
{{ . }}
|
||||||
|
</p>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<!-- Meta row: location + focus -->
|
||||||
|
<div class="mt-3 flex flex-wrap gap-2 text-[0.7rem] text-muted">
|
||||||
|
{{ with $hero.location }}
|
||||||
|
<span class="inline-flex items-center gap-1.5 rounded-full border border-border bg-surface/90 px-3 py-1.5">
|
||||||
|
<i class="fa-solid fa-location-dot text-[0.8rem]"></i>
|
||||||
|
<span class="font-medium">{{ . }}</span>
|
||||||
|
</span>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ with $hero.focus }}
|
||||||
|
<span class="inline-flex items-center gap-1.5 rounded-full border border-border bg-surface/80 px-3 py-1.5">
|
||||||
|
<i class="fa-regular fa-circle-dot text-[0.8rem]"></i>
|
||||||
|
<span>{{ . }}</span>
|
||||||
|
</span>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Optional highlight pills -->
|
||||||
|
{{ with $hero.highlights }}
|
||||||
|
<div class="mt-3 flex flex-wrap gap-2">
|
||||||
|
{{ range . }}
|
||||||
|
<span class="inline-flex items-center rounded-full border border-border bg-surface/80 px-3 py-1 text-[0.7rem] text-muted">
|
||||||
|
{{ .label }}
|
||||||
|
</span>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<!-- CTAs -->
|
||||||
|
<div class="mt-4 flex flex-wrap items-center gap-3">
|
||||||
|
{{ with $hero.primary }}
|
||||||
|
<a href="{{ .href | default "/projects/" }}" class="btn-primary">
|
||||||
|
{{ .label | default "View projects" }}
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ with $hero.secondary }}
|
||||||
|
<a href="{{ .href | default "/blog/" }}" class="btn-ghost link-underline">
|
||||||
|
{{ .label | default "Read the blog" }}
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Avatar ONLY if provided -->
|
||||||
|
{{ with $hero.avatar }}
|
||||||
|
<div class="order-first md:order-none">
|
||||||
|
<div class="card card-pad flex items-center justify-center md:justify-end">
|
||||||
|
<div class="h-24 w-24 sm:h-28 sm:w-28 overflow-hidden rounded-2xl border border-border bg-surface shadow-md">
|
||||||
|
<img
|
||||||
|
src="{{ . | relURL }}"
|
||||||
|
alt="{{ $hero.title | default $.Site.Title }}"
|
||||||
|
class="h-full w-full object-cover"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
28
themes/minimal-black/layouts/partials/home/now.html
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{{- $hero := .Site.Params.hero -}}
|
||||||
|
{{- $home := .Site.Params.home -}}
|
||||||
|
|
||||||
|
{{ if $home.showNowSection }}
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="space-y-3">
|
||||||
|
<h2 class="heading-section">{{ default "Now" $hero.nowLabel }}</h2>
|
||||||
|
<div class="card card-pad text-xs text-muted">
|
||||||
|
{{ with $hero.nowIntro }}
|
||||||
|
<p class="mb-2">{{ . }}</p>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ with $hero.now }}
|
||||||
|
<ul class="list-disc space-y-1 pl-4">
|
||||||
|
{{ range . }}
|
||||||
|
<li>{{ . }}</li>
|
||||||
|
{{ end }}
|
||||||
|
</ul>
|
||||||
|
{{ else }}
|
||||||
|
<p>
|
||||||
|
Add a <code>hero.now</code> list in your config to describe what you’re
|
||||||
|
focused on right now.
|
||||||
|
</p>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
38
themes/minimal-black/layouts/partials/home/posts.html
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{{- $home := .Site.Params.home -}}
|
||||||
|
{{ if ne $home.showLatestPosts false }}
|
||||||
|
<div class="space-y-3 animate-fade-up">
|
||||||
|
<div class="space-y-1">
|
||||||
|
<h2 class="heading-section">
|
||||||
|
{{ default "Latest writing" $home.blogTitle }}
|
||||||
|
</h2>
|
||||||
|
{{ with $home.blogSubtitle }}
|
||||||
|
<p class="text-xs text-muted">
|
||||||
|
{{ . }}
|
||||||
|
</p>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ $limit := cond (gt (int $home.latestPostsLimit) 0) (int $home.latestPostsLimit) 3 }}
|
||||||
|
{{ $posts := first $limit (where .Site.RegularPages "Section" "blog") }}
|
||||||
|
|
||||||
|
<div class="grid gap-4 md:grid-cols-2">
|
||||||
|
{{ range $posts }}
|
||||||
|
{{ partial "components/post-card.html" (dict "Page" . "Root" $) }}
|
||||||
|
{{ else }}
|
||||||
|
<p class="text-xs text-muted">
|
||||||
|
No posts yet. Add some under <code>content/blog</code>.
|
||||||
|
</p>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-3 flex justify-end">
|
||||||
|
<a
|
||||||
|
href="{{ "/blog/" | relURL }}"
|
||||||
|
class="btn-primary btn-primary-sm inline-flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<span>View all posts</span>
|
||||||
|
<i class="fa-solid fa-arrow-right-long text-[0.8rem]"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
43
themes/minimal-black/layouts/partials/home/projects.html
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{{- $home := .Site.Params.home -}}
|
||||||
|
{{ if ne $home.showFeaturedProjects false }}
|
||||||
|
<div class="space-y-3 animate-fade-up">
|
||||||
|
<div class="space-y-1">
|
||||||
|
<h2 class="heading-section">
|
||||||
|
{{ default "Selected work" $home.projectsTitle }}
|
||||||
|
</h2>
|
||||||
|
{{ with $home.projectsSubtitle }}
|
||||||
|
<p class="text-xs text-muted">
|
||||||
|
{{ . }}
|
||||||
|
</p>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ $limit := cond (gt (int $home.featuredProjectsLimit) 0) (int $home.featuredProjectsLimit) 3 }}
|
||||||
|
{{ $allProjects := where .Site.RegularPages "Section" "projects" }}
|
||||||
|
{{ $featured := where $allProjects "Params.featured" true }}
|
||||||
|
{{ if not (gt (len $featured) 0) }}
|
||||||
|
{{ $featured = $allProjects }}
|
||||||
|
{{ end }}
|
||||||
|
{{ $list := first $limit $featured }}
|
||||||
|
|
||||||
|
<div class="grid gap-4 md:grid-cols-2">
|
||||||
|
{{ range $list }}
|
||||||
|
{{ partial "components/project-card.html" (dict "Page" . "Root" $) }}
|
||||||
|
{{ else }}
|
||||||
|
<p class="text-xs text-muted">
|
||||||
|
No projects yet. Add some under <code>content/projects</code>.
|
||||||
|
</p>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-3 flex justify-end">
|
||||||
|
<a
|
||||||
|
href="{{ "/projects/" | relURL }}"
|
||||||
|
class="btn-primary btn-primary-sm inline-flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<span>View all projects</span>
|
||||||
|
<i class="fa-solid fa-arrow-right-long text-[0.8rem]"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
59
themes/minimal-black/layouts/partials/home/tech-marquee.html
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
{{- $home := .Site.Params.home -}}
|
||||||
|
{{- $hero := .Site.Params.hero -}}
|
||||||
|
{{- $techMain := $home.tech -}}
|
||||||
|
{{- $techReverse := $home.techReverse -}}
|
||||||
|
{{- $variant := $home.techVariant | default "wide" -}}
|
||||||
|
|
||||||
|
{{ with $techMain }}
|
||||||
|
<div class="space-y-5 animate-fade-up">
|
||||||
|
<div class="space-y-2">
|
||||||
|
<h3 class="heading-section text-base">
|
||||||
|
{{ default "What I Work With" $hero.techMarqueeLabel }}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="tech-strip {{ if eq $variant "compact" }}tech-strip--compact{{ else }}tech-strip--wide{{ end }}">
|
||||||
|
<!-- primary row (always rendered) -->
|
||||||
|
<div class="tech-strip-track tech-strip-track--primary">
|
||||||
|
{{ range . }}
|
||||||
|
<div class="tech-strip-item">
|
||||||
|
{{ with .icon }}
|
||||||
|
<i class="{{ . }} tech-icon"></i>
|
||||||
|
{{ end }}
|
||||||
|
<span class="font-medium">{{ .label }}</span>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
{{ range . }}
|
||||||
|
<div class="tech-strip-item" aria-hidden="true">
|
||||||
|
{{ with .icon }}
|
||||||
|
<i class="{{ . }} tech-icon"></i>
|
||||||
|
{{ end }}
|
||||||
|
<span class="font-medium">{{ .label }}</span>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- secondary row, reverse (only if techReverse is defined) -->
|
||||||
|
{{ with $techReverse }}
|
||||||
|
<div class="tech-strip-track tech-strip-track--secondary">
|
||||||
|
{{ range . }}
|
||||||
|
<div class="tech-strip-item">
|
||||||
|
{{ with .icon }}
|
||||||
|
<i class="{{ . }} tech-icon"></i>
|
||||||
|
{{ end }}
|
||||||
|
<span class="font-medium">{{ .label }}</span>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
{{ range . }}
|
||||||
|
<div class="tech-strip-item" aria-hidden="true">
|
||||||
|
{{ with .icon }}
|
||||||
|
<i class="{{ . }} tech-icon"></i>
|
||||||
|
{{ end }}
|
||||||
|
<span class="font-medium">{{ .label }}</span>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
7
themes/minimal-black/layouts/partials/meta.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{{- with .Description -}}
|
||||||
|
<meta name="description" content="{{ . }}" />
|
||||||
|
{{- else -}}
|
||||||
|
<meta name="description" content="{{ .Site.Params.description }}" />
|
||||||
|
{{- end }} {{- with .Site.Params.author }}
|
||||||
|
<meta name="author" content="{{ . }}" />
|
||||||
|
{{- end }}
|
||||||
59
themes/minimal-black/layouts/partials/search-overlay.html
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<div class="search-overlay" data-search-overlay>
|
||||||
|
<div class="search-overlay-backdrop" data-search-close></div>
|
||||||
|
|
||||||
|
<div class="search-panel">
|
||||||
|
<div class="search-panel-header">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<i class="fa-solid fa-magnifying-glass text-[0.8rem] text-muted"></i>
|
||||||
|
<input
|
||||||
|
type="search"
|
||||||
|
class="search-input"
|
||||||
|
placeholder="Search posts..."
|
||||||
|
autocomplete="off"
|
||||||
|
data-search-input
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="search-close"
|
||||||
|
data-search-close
|
||||||
|
aria-label="Close search"
|
||||||
|
>
|
||||||
|
<i class="fa-solid fa-xmark text-[0.8rem]"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="search-panel-body">
|
||||||
|
<div class="search-results" data-search-results>
|
||||||
|
<div class="search-empty-state">
|
||||||
|
<div class="search-empty-icon">
|
||||||
|
<i class="fa-solid fa-magnifying-glass text-[1rem]"></i>
|
||||||
|
</div>
|
||||||
|
<p class="search-empty-title">Start searching</p>
|
||||||
|
<p class="search-empty-subtitle">
|
||||||
|
Enter keywords to search articles.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="search-footer-hints">
|
||||||
|
<div class="search-hint-key">
|
||||||
|
<span>↑↓</span>
|
||||||
|
<span>Navigate</span>
|
||||||
|
</div>
|
||||||
|
<div class="search-hint-key">
|
||||||
|
<span>↵</span>
|
||||||
|
<span>Select</span>
|
||||||
|
</div>
|
||||||
|
<div class="search-hint-key">
|
||||||
|
<span>ESC</span>
|
||||||
|
<span>Close</span>
|
||||||
|
</div>
|
||||||
|
<div class="search-hint-key search-hint-right">
|
||||||
|
<span>Ctrl</span><span>K</span>
|
||||||
|
<span>Shortcut</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
50
themes/minimal-black/layouts/projects/list.html
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{{ define "main" }}
|
||||||
|
<section class="layout-page">
|
||||||
|
<div class="page-int section-stack">
|
||||||
|
<header class="space-y-2">
|
||||||
|
<h1 class="heading-page text-2xl sm:text-3xl">Projects</h1>
|
||||||
|
|
||||||
|
{{ with .Site.Params.projectsIntro }}
|
||||||
|
<p class="max-w-xl text-sm text-muted">
|
||||||
|
{{ . }}
|
||||||
|
</p>
|
||||||
|
{{ else }}
|
||||||
|
<p class="max-w-xl text-sm text-muted">
|
||||||
|
A selection of things I’ve been building – themes, tools, and experiments.
|
||||||
|
</p>
|
||||||
|
{{ end }}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Cards -->
|
||||||
|
{{/* you can tweak sorting if you want; this is newest first */}}
|
||||||
|
{{ $paginator := .Paginate (.Pages.ByDate.Reverse) }}
|
||||||
|
|
||||||
|
<div class="grid gap-4 md:grid-cols-2">
|
||||||
|
{{ range $paginator.Pages }}
|
||||||
|
{{ partial "components/project-card.html" (dict "Page" . "Root" $) }}
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
{{ if gt $paginator.TotalPages 1 }}
|
||||||
|
<nav class="mt-6 flex items-center justify-between text-xs text-muted">
|
||||||
|
{{ if $paginator.HasPrev }}
|
||||||
|
<a href="{{ $paginator.Prev.URL }}" class="link-underline">
|
||||||
|
← Newer projects
|
||||||
|
</a>
|
||||||
|
{{ else }}
|
||||||
|
<span></span>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if $paginator.HasNext }}
|
||||||
|
<a href="{{ $paginator.Next.URL }}" class="link-underline">
|
||||||
|
Older projects →
|
||||||
|
</a>
|
||||||
|
{{ else }}
|
||||||
|
<span></span>
|
||||||
|
{{ end }}
|
||||||
|
</nav>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{{ end }}
|
||||||
29
themes/minimal-black/netlify.toml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
[build]
|
||||||
|
publish = "public"
|
||||||
|
command = "mkdir -p hugo-minimal-black && rsync -av --exclude='hugo-minimal-black' --exclude='.git' --exclude='public' . ./hugo-minimal-black/ && cd hugo-minimal-black/exampleSite && hugo --gc --minify --themesDir ../.. --theme hugo-minimal-black && mv public ../../public"
|
||||||
|
|
||||||
|
[build.environment]
|
||||||
|
HUGO_VERSION = "0.152.2"
|
||||||
|
HUGO_ENV = "production"
|
||||||
|
HUGO_ENABLEGITINFO = "true"
|
||||||
|
|
||||||
|
[context.production.environment]
|
||||||
|
HUGO_VERSION = "0.152.2"
|
||||||
|
HUGO_ENV = "production"
|
||||||
|
|
||||||
|
[context.deploy-preview]
|
||||||
|
command = "mkdir -p hugo-minimal-black && rsync -av --exclude='hugo-minimal-black' --exclude='.git' --exclude='public' . ./hugo-minimal-black/ && cd hugo-minimal-black/exampleSite && hugo --gc --minify --buildFuture --themesDir ../.. --theme hugo-minimal-black && mv public ../../public"
|
||||||
|
|
||||||
|
[context.deploy-preview.environment]
|
||||||
|
HUGO_VERSION = "0.152.2"
|
||||||
|
|
||||||
|
[context.branch-deploy]
|
||||||
|
command = "mkdir -p hugo-minimal-black && rsync -av --exclude='hugo-minimal-black' --exclude='.git' --exclude='public' . ./hugo-minimal-black/ && cd hugo-minimal-black/exampleSite && hugo --themesDir ../.. --theme hugo-minimal-black && mv public ../../public"
|
||||||
|
|
||||||
|
[context.branch-deploy.environment]
|
||||||
|
HUGO_VERSION = "0.152.2"
|
||||||
|
|
||||||
|
[[redirects]]
|
||||||
|
from = "/*"
|
||||||
|
to = "/404.html"
|
||||||
|
status = 404
|
||||||
19
themes/minimal-black/package.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "minimal-black",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "Jim Christopoulos",
|
||||||
|
"license": "ISC",
|
||||||
|
"type": "commonjs",
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/typography": "^0.5.19",
|
||||||
|
"autoprefixer": "^10.4.22",
|
||||||
|
"postcss": "^8.5.6",
|
||||||
|
"tailwindcss": "^3.4.18"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
themes/minimal-black/postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
5434
themes/minimal-black/static/css/main.css
Normal file
BIN
themes/minimal-black/static/icons/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
BIN
themes/minimal-black/static/icons/favicon-96x96.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
themes/minimal-black/static/icons/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
1
themes/minimal-black/static/icons/favicon.svg
Normal file
|
After Width: | Height: | Size: 35 KiB |
21
themes/minimal-black/static/icons/site.webmanifest
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "Minimal Black",
|
||||||
|
"short_name": "M-BLK",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/web-app-manifest-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/web-app-manifest-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"theme_color": "#ffffff",
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"display": "standalone"
|
||||||
|
}
|
||||||
BIN
themes/minimal-black/static/icons/web-app-manifest-192x192.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
themes/minimal-black/static/icons/web-app-manifest-512x512.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
themes/minimal-black/static/images/logo.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
16
themes/minimal-black/static/js/gallery.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
if (typeof window.$ === "undefined" && typeof window.JustifiedGallery === "undefined") {
|
||||||
|
// using vanilla JustifiedGallery from CDN, globally exposed
|
||||||
|
}
|
||||||
|
|
||||||
|
var roots = document.querySelectorAll("[data-jg]");
|
||||||
|
if (!roots.length || typeof window.JustifiedGallery === "undefined") return;
|
||||||
|
|
||||||
|
roots.forEach(function (el) {
|
||||||
|
new window.JustifiedGallery(el, {
|
||||||
|
rowHeight: 260,
|
||||||
|
lastRow: "center",
|
||||||
|
margin: 16,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
11
themes/minimal-black/static/js/lightbox.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
if (typeof GLightbox === "undefined") return;
|
||||||
|
|
||||||
|
GLightbox({
|
||||||
|
selector: ".glightbox",
|
||||||
|
loop: true,
|
||||||
|
touchNavigation: true,
|
||||||
|
zoomable: true,
|
||||||
|
draggable: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
137
themes/minimal-black/static/js/main.js
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
(function () {
|
||||||
|
var STORAGE_KEY = "theme";
|
||||||
|
/* ---------- Theme ---------- */
|
||||||
|
|
||||||
|
function getStoredTheme() {
|
||||||
|
try {
|
||||||
|
return localStorage.getItem(STORAGE_KEY);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function storeTheme(theme) {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(STORAGE_KEY, theme);
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSystemTheme() {
|
||||||
|
return window.matchMedia &&
|
||||||
|
window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||||
|
? "dark"
|
||||||
|
: "light";
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyTheme(theme) {
|
||||||
|
document.documentElement.setAttribute("data-theme", theme);
|
||||||
|
|
||||||
|
var isDark = theme === "dark";
|
||||||
|
var lightIcons = document.querySelectorAll("[data-theme-icon-light]");
|
||||||
|
var darkIcons = document.querySelectorAll("[data-theme-icon-dark]");
|
||||||
|
|
||||||
|
lightIcons.forEach(function (el) {
|
||||||
|
el.style.display = isDark ? "" : "none";
|
||||||
|
});
|
||||||
|
darkIcons.forEach(function (el) {
|
||||||
|
el.style.display = isDark ? "none" : "";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function initThemeFromDOM() {
|
||||||
|
var attr = document.documentElement.getAttribute("data-theme");
|
||||||
|
if (attr === "dark" || attr === "light") {
|
||||||
|
applyTheme(attr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var stored = getStoredTheme();
|
||||||
|
applyTheme(stored || getSystemTheme());
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleTheme() {
|
||||||
|
var current =
|
||||||
|
document.documentElement.getAttribute("data-theme") || "light";
|
||||||
|
var next = current === "dark" ? "light" : "dark";
|
||||||
|
applyTheme(next);
|
||||||
|
storeTheme(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initThemeToggle() {
|
||||||
|
var btns = document.querySelectorAll("[data-theme-toggle]");
|
||||||
|
if (!btns.length) return;
|
||||||
|
btns.forEach(function (btn) {
|
||||||
|
btn.addEventListener("click", toggleTheme);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- Mobile nav ---------- */
|
||||||
|
|
||||||
|
function initMobileNav() {
|
||||||
|
var toggle = document.querySelector("[data-mobile-nav-toggle]");
|
||||||
|
var nav = document.querySelector("[data-mobile-nav]");
|
||||||
|
if (!toggle || !nav) return;
|
||||||
|
|
||||||
|
var open = false;
|
||||||
|
function setOpen(next) {
|
||||||
|
open = next;
|
||||||
|
nav.style.display = open ? "block" : "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle.addEventListener("click", function () {
|
||||||
|
setOpen(!open);
|
||||||
|
});
|
||||||
|
|
||||||
|
nav.addEventListener("click", function (e) {
|
||||||
|
if (e.target.tagName === "A") setOpen(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- Dock ---------- */
|
||||||
|
|
||||||
|
function initDock() {
|
||||||
|
var dock = document.querySelector("[data-dock]");
|
||||||
|
if (!dock) return;
|
||||||
|
|
||||||
|
var toggle = dock.querySelector("[data-dock-toggle]");
|
||||||
|
var backTop = dock.querySelector('[data-dock-action="top"]');
|
||||||
|
var backBtn = dock.querySelector('[data-dock-action="back"]');
|
||||||
|
var open = false;
|
||||||
|
|
||||||
|
function setOpen(next) {
|
||||||
|
open = next;
|
||||||
|
dock.classList.toggle("dock--open", open);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toggle) {
|
||||||
|
toggle.addEventListener("click", function () {
|
||||||
|
setOpen(!open);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backTop) {
|
||||||
|
backTop.addEventListener("click", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
window.scrollTo({
|
||||||
|
top: 0,
|
||||||
|
behavior: "smooth",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backBtn) {
|
||||||
|
backBtn.addEventListener("click", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
window.history.back();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- Init ---------- */
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
initThemeFromDOM();
|
||||||
|
initThemeToggle();
|
||||||
|
initMobileNav();
|
||||||
|
initDock();
|
||||||
|
});
|
||||||
|
})();
|
||||||
253
themes/minimal-black/static/js/search.js
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
(function () {
|
||||||
|
var overlay, inputEl, resultsEl;
|
||||||
|
var indexLoaded = false;
|
||||||
|
var pages = [];
|
||||||
|
|
||||||
|
function ensureElements() {
|
||||||
|
if (!overlay) {
|
||||||
|
overlay = document.querySelector("[data-search-overlay]");
|
||||||
|
}
|
||||||
|
if (!inputEl && overlay) {
|
||||||
|
inputEl = overlay.querySelector("[data-search-input]");
|
||||||
|
}
|
||||||
|
if (!resultsEl && overlay) {
|
||||||
|
resultsEl = overlay.querySelector("[data-search-results]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadIndex() {
|
||||||
|
if (indexLoaded) return;
|
||||||
|
indexLoaded = true;
|
||||||
|
|
||||||
|
fetch("/index.json")
|
||||||
|
.then(function (r) {
|
||||||
|
if (!r.ok) throw new Error("index.json not found");
|
||||||
|
return r.json();
|
||||||
|
})
|
||||||
|
.then(function (data) {
|
||||||
|
pages = (data && data.pages) || [];
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
pages = [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function openOverlay() {
|
||||||
|
ensureElements();
|
||||||
|
if (!overlay) return;
|
||||||
|
|
||||||
|
overlay.classList.remove("search-overlay");
|
||||||
|
overlay.classList.add("search-overlay--open");
|
||||||
|
loadIndex();
|
||||||
|
|
||||||
|
if (inputEl) {
|
||||||
|
setTimeout(function () {
|
||||||
|
inputEl.focus();
|
||||||
|
}, 20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeOverlay() {
|
||||||
|
ensureElements();
|
||||||
|
if (!overlay) return;
|
||||||
|
|
||||||
|
if (overlay.classList.contains("search-overlay--closing")) return;
|
||||||
|
|
||||||
|
overlay.classList.add("search-overlay--closing");
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
overlay.classList.remove("search-overlay--open");
|
||||||
|
overlay.classList.remove("search-overlay--closing");
|
||||||
|
overlay.classList.add("search-overlay");
|
||||||
|
|
||||||
|
if (inputEl) inputEl.value = "";
|
||||||
|
|
||||||
|
if (resultsEl) {
|
||||||
|
resultsEl.innerHTML =
|
||||||
|
'<div class="search-empty-state">' +
|
||||||
|
'<div class="search-empty-icon"><i class="fa-solid fa-magnifying-glass text-[1rem]"></i></div>' +
|
||||||
|
'<p class="search-empty-title">Start searching</p>' +
|
||||||
|
'<p class="search-empty-subtitle">Enter keywords to search articles.</p>' +
|
||||||
|
"</div>";
|
||||||
|
}
|
||||||
|
}, 180);
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterPages(query) {
|
||||||
|
if (!pages.length) return [];
|
||||||
|
var q = (query || "").toLowerCase().trim();
|
||||||
|
if (!q) return [];
|
||||||
|
return pages
|
||||||
|
.filter(function (p) {
|
||||||
|
var t = (p.title || "").toLowerCase();
|
||||||
|
var s = (p.summary || "").toLowerCase();
|
||||||
|
return t.indexOf(q) !== -1 || s.indexOf(q) !== -1;
|
||||||
|
})
|
||||||
|
.slice(0, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
function highlightText(text, query) {
|
||||||
|
if (!query) return text;
|
||||||
|
var regex = new RegExp("(" + query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + ")", "gi");
|
||||||
|
return text.replace(regex, '<mark class="search-highlight">$1</mark>');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSectionIcon(section) {
|
||||||
|
var icons = {
|
||||||
|
blog: "fa-regular fa-note-sticky",
|
||||||
|
projects: "fa-regular fa-folder-open",
|
||||||
|
posts: "fa-regular fa-note-sticky",
|
||||||
|
};
|
||||||
|
return icons[section.toLowerCase()] || "fa-regular fa-file";
|
||||||
|
}
|
||||||
|
|
||||||
|
function truncateText(text, maxLength) {
|
||||||
|
if (!text || text.length <= maxLength) return text;
|
||||||
|
return text.substring(0, maxLength) + "...";
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderResults(query) {
|
||||||
|
ensureElements();
|
||||||
|
if (!resultsEl) return;
|
||||||
|
|
||||||
|
var q = (query || "").trim();
|
||||||
|
if (!q) {
|
||||||
|
resultsEl.innerHTML =
|
||||||
|
'<div class="search-empty-state">' +
|
||||||
|
'<div class="search-empty-icon"><i class="fa-solid fa-magnifying-glass text-[1rem]"></i></div>' +
|
||||||
|
'<p class="search-empty-title">Start searching</p>' +
|
||||||
|
'<p class="search-empty-subtitle">Enter keywords to search articles.</p>' +
|
||||||
|
"</div>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var matches = filterPages(q);
|
||||||
|
if (!matches.length) {
|
||||||
|
resultsEl.innerHTML =
|
||||||
|
'<div class="search-empty-state">' +
|
||||||
|
'<div class="search-empty-icon"><i class="fa-solid fa-circle-exclamation text-[1rem]"></i></div>' +
|
||||||
|
'<p class="search-empty-title">No results found</p>' +
|
||||||
|
'<p class="search-empty-subtitle">Try different keywords or check your spelling.</p>' +
|
||||||
|
"</div>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var html = matches
|
||||||
|
.map(function (p, index) {
|
||||||
|
var title = highlightText(p.title || "Untitled", q);
|
||||||
|
var section = p.section || "";
|
||||||
|
var summary = truncateText(p.summary || "", 120);
|
||||||
|
var highlightedSummary = highlightText(summary, q);
|
||||||
|
var icon = getSectionIcon(section);
|
||||||
|
var date = p.date ? new Date(p.date).toLocaleDateString("en-US", {
|
||||||
|
year: "numeric",
|
||||||
|
month: "short",
|
||||||
|
day: "numeric"
|
||||||
|
}) : "";
|
||||||
|
|
||||||
|
return (
|
||||||
|
'<a href="' +
|
||||||
|
p.permalink +
|
||||||
|
'" class="search-result-item" data-result-index="' +
|
||||||
|
index +
|
||||||
|
'">' +
|
||||||
|
'<div class="search-result-header">' +
|
||||||
|
'<i class="' + icon + ' search-result-icon"></i>' +
|
||||||
|
'<div class="search-result-info">' +
|
||||||
|
'<div class="search-result-title">' +
|
||||||
|
title +
|
||||||
|
"</div>" +
|
||||||
|
'<div class="search-result-meta">' +
|
||||||
|
(section ? '<span class="search-result-section">' + section + "</span>" : "") +
|
||||||
|
(date ? '<span class="search-result-date">' + date + "</span>" : "") +
|
||||||
|
"</div>" +
|
||||||
|
"</div>" +
|
||||||
|
"</div>" +
|
||||||
|
(highlightedSummary ? '<div class="search-result-summary">' + highlightedSummary + "</div>" : "") +
|
||||||
|
"</a>"
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
|
||||||
|
resultsEl.innerHTML = html;
|
||||||
|
|
||||||
|
// Add keyboard navigation
|
||||||
|
addKeyboardNavigation();
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectedIndex = -1;
|
||||||
|
|
||||||
|
function addKeyboardNavigation() {
|
||||||
|
ensureElements();
|
||||||
|
if (!inputEl) return;
|
||||||
|
|
||||||
|
var items = resultsEl.querySelectorAll(".search-result-item");
|
||||||
|
|
||||||
|
inputEl.addEventListener("keydown", function(e) {
|
||||||
|
if (e.key === "ArrowDown") {
|
||||||
|
e.preventDefault();
|
||||||
|
selectedIndex = Math.min(selectedIndex + 1, items.length - 1);
|
||||||
|
updateSelection(items);
|
||||||
|
} else if (e.key === "ArrowUp") {
|
||||||
|
e.preventDefault();
|
||||||
|
selectedIndex = Math.max(selectedIndex - 1, -1);
|
||||||
|
updateSelection(items);
|
||||||
|
} else if (e.key === "Enter" && selectedIndex >= 0) {
|
||||||
|
e.preventDefault();
|
||||||
|
items[selectedIndex].click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSelection(items) {
|
||||||
|
items.forEach(function(item, index) {
|
||||||
|
if (index === selectedIndex) {
|
||||||
|
item.classList.add("search-result-item--selected");
|
||||||
|
item.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
||||||
|
} else {
|
||||||
|
item.classList.remove("search-result-item--selected");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function initSearch() {
|
||||||
|
ensureElements();
|
||||||
|
if (!overlay) return;
|
||||||
|
|
||||||
|
// Close and ESC
|
||||||
|
overlay.querySelectorAll("[data-search-close]").forEach(function (el) {
|
||||||
|
el.addEventListener("click", closeOverlay);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("keydown", function (e) {
|
||||||
|
if (e.key === "Escape") closeOverlay();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Typing
|
||||||
|
if (inputEl) {
|
||||||
|
inputEl.addEventListener("input", function (e) {
|
||||||
|
renderResults(e.target.value || "");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ctrl/Cmd + K to open
|
||||||
|
document.addEventListener("keydown", function (e) {
|
||||||
|
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "k") {
|
||||||
|
e.preventDefault();
|
||||||
|
openOverlay();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Expose global API for inline onclick
|
||||||
|
window.MinimalSearch = {
|
||||||
|
open: openOverlay,
|
||||||
|
close: closeOverlay,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.readyState === "loading") {
|
||||||
|
document.addEventListener("DOMContentLoaded", initSearch);
|
||||||
|
} else {
|
||||||
|
initSearch();
|
||||||
|
}
|
||||||
|
})();
|
||||||
25
themes/minimal-black/tailwind.config.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
darkMode: ["class", '[data-theme="dark"]'],
|
||||||
|
content: [
|
||||||
|
"./layouts/**/*.html",
|
||||||
|
"./exampleSite/content/**/*.{md,html}",
|
||||||
|
"../../content/**/*.{md,html}",
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
bg: "var(--color-bg)",
|
||||||
|
surface: "var(--color-surface)",
|
||||||
|
text: "var(--color-text)",
|
||||||
|
muted: "var(--color-text-muted)",
|
||||||
|
border: "var(--color-border)",
|
||||||
|
accent: "var(--color-accent)",
|
||||||
|
},
|
||||||
|
maxWidth: {
|
||||||
|
"3xl": "48rem",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [require("@tailwindcss/typography")],
|
||||||
|
};
|
||||||
29
themes/minimal-black/theme.toml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
name = "Minimal Black"
|
||||||
|
license = "MIT"
|
||||||
|
licenselink = "https://gitlab.com/jimchr12/hugo-minimal-black/blob/main/LICENSE"
|
||||||
|
description = "A minimal, dark-mode first Hugo theme with true black backgrounds, purple accents, and comprehensive content styling. Features responsive design, search, TOC, and multiple page layouts."
|
||||||
|
homepage = "https://gitlab.com/jimchr12/hugo-minimal-black"
|
||||||
|
demosite = "https://minimal-black-demo.netlify.app"
|
||||||
|
tags = ["blog", "portfolio", "minimal", "dark", "tailwind", "responsive", "clean", "modern", "personal"]
|
||||||
|
features = [
|
||||||
|
"Dark Mode",
|
||||||
|
"Light Mode",
|
||||||
|
"Responsive Design",
|
||||||
|
"Search",
|
||||||
|
"Table of Contents",
|
||||||
|
"Syntax Highlighting",
|
||||||
|
"Google Analytics",
|
||||||
|
"Font Awesome Icons",
|
||||||
|
"Devicon Support",
|
||||||
|
"Multiple About Page Layouts",
|
||||||
|
"Project Portfolio",
|
||||||
|
"Blog",
|
||||||
|
"Gallery Shortcode",
|
||||||
|
"Mermaid Diagrams",
|
||||||
|
"GitHub Flavored Markdown"
|
||||||
|
]
|
||||||
|
min_version = "0.120.0"
|
||||||
|
|
||||||
|
[author]
|
||||||
|
name = "Jim Christopoulos"
|
||||||
|
homepage = "https://jimchristopoulos.com/"
|
||||||