Converti chill-theme en dossier classique
@@ -0,0 +1,30 @@
|
||||
# Dependencies
|
||||
node_modules/
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
# Hugo
|
||||
public/
|
||||
resources/
|
||||
.hugo_build.lock
|
||||
hugo_stats.json
|
||||
|
||||
# Build output
|
||||
assets/css/style.css
|
||||
static/css/
|
||||
|
||||
# IDE/Editor
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
.DS_Store
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Chaoming Li
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,470 @@
|
||||
# Hugo Saasify Theme
|
||||
|
||||
A modern and elegant Hugo theme specifically designed for building **SaaS marketing websites**. Built with TailwindCSS, this theme provides a clean, professional look while maintaining excellent performance and customization options.
|
||||
|
||||
## Why Hugo Saasify Theme?
|
||||
|
||||
Perfect for creating high-converting SaaS landing pages, product marketing sites, and company websites with:
|
||||
|
||||
- **SEO Optimized** - Built-in SEO best practices, semantic HTML, and optimized meta tags to help you rank better
|
||||
- **Lightning Fast** - Static site generation delivers blazing-fast load times (90+ Lighthouse scores)
|
||||
- **Global Ready** - Full internationalization (i18n) support with automatic language detection powered by [VisitorAPI](https://visitorapi.com/)
|
||||
- **Developer Friendly** - Clean code structure, comprehensive documentation, and easy customization
|
||||
- **Production Ready** - Battle-tested with real SaaS companies, mobile-responsive, and accessibility compliant
|
||||
|
||||
Whether you're launching a new SaaS product or refreshing your marketing site, Hugo Saasify Theme helps you build a professional web presence quickly and efficiently.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
[Demo Site](https://saasify-demo.chaoming.li)
|
||||
|
||||
## Features
|
||||
|
||||
- 🎨 Modern design with TailwindCSS
|
||||
- 📱 Fully responsive layout
|
||||
- 🚀 Performance optimized
|
||||
- 💅 Clean typography with Inter & Plus Jakarta Sans fonts
|
||||
- 🎯 Perfect for SaaS and business websites
|
||||
- 🛠 Easy to customize
|
||||
- 📦 No jQuery, minimal JavaScript
|
||||
- 📊 Google Analytics support
|
||||
- 📈 Google Tag Manager support
|
||||
- 🔧 Custom head content support for additional tracking scripts
|
||||
- 🎪 21 pre-built shortcodes for rapid page building
|
||||
- 📚 Documentation layout with automatic sidebar navigation
|
||||
- 🌍 Full multilingual (i18n) support with automatic language switcher (powered by [VisitorAPI](https://visitorapi.com/))
|
||||
|
||||
## Documentation
|
||||
|
||||
**📖 [Complete Documentation →](docs/README.md)**
|
||||
|
||||
Comprehensive guides covering everything you need:
|
||||
|
||||
- **[Installation Guide](docs/INSTALLATION.md)** - Get started quickly
|
||||
- **[Configuration Guide](docs/CONFIGURATION.md)** - All configuration options
|
||||
- **[Internationalization Guide](docs/INTERNATIONALIZATION.md)** - Complete i18n and multilingual setup guide
|
||||
- **[Layouts Guide](docs/LAYOUTS.md)** - Understanding layouts and templates
|
||||
- **[Shortcodes Reference](docs/SHORTCODES.md)** - All 21 shortcodes documented
|
||||
- **[Styling Guide](docs/STYLING.md)** - Customize colors, fonts, and styles
|
||||
- **[Content Creation Guide](docs/CONTENT-CREATION.md)** - Create pages and blog posts
|
||||
- **[Deployment Guide](docs/DEPLOYMENT.md)** - Deploy to various platforms
|
||||
- **[Troubleshooting Guide](docs/TROUBLESHOOTING.md)** - Common issues and solutions
|
||||
|
||||
## Requirements
|
||||
|
||||
- Hugo Extended Version (>= 0.80.0)
|
||||
- Node.js (>= 14.x)
|
||||
- npm or yarn
|
||||
|
||||
## Installation
|
||||
|
||||
### 1. Create a new Hugo site (skip if you have an existing site)
|
||||
|
||||
```bash
|
||||
hugo new site your-site-name
|
||||
cd your-site-name
|
||||
```
|
||||
|
||||
### 2. Add the theme as a submodule
|
||||
|
||||
```bash
|
||||
git init
|
||||
git submodule add https://github.com/chaoming/chill-theme themes/chill-theme
|
||||
```
|
||||
|
||||
### 3. Example Site (Optional)
|
||||
|
||||
The theme comes with a fully functional example site that demonstrates its features and capabilities. You can use this as a reference when building your own site.
|
||||
|
||||
### Using the Example Site
|
||||
|
||||
The example site provides a great starting point to understand how to:
|
||||
- Structure your content
|
||||
- Use different page layouts
|
||||
- Configure navigation menus
|
||||
- Set up site parameters
|
||||
- Implement common SaaS website features
|
||||
|
||||
1. Copy the example site content:
|
||||
```bash
|
||||
cp -r themes/chill-theme/exampleSite/* .
|
||||
```
|
||||
|
||||
2. The example site includes:
|
||||
- Complete content structure with sample pages
|
||||
- Blog posts with various layouts
|
||||
- Feature pages
|
||||
- Career/Jobs section
|
||||
- Pricing page
|
||||
- Company information page
|
||||
- Properly configured hugo.toml
|
||||
|
||||
### 4. Install dependencies
|
||||
|
||||
```bash
|
||||
# Copy package.json and other config files to your site root
|
||||
cp themes/chill-theme/package.json .
|
||||
cp themes/chill-theme/postcss.config.js .
|
||||
cp themes/chill-theme/tailwind.config.copy.js ./tailwind.config.js
|
||||
```
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
```
|
||||
|
||||
### 5. Configure your Hugo site
|
||||
|
||||
Create or update your `hugo.toml` with the following configuration:
|
||||
|
||||
```toml
|
||||
# Basic Configuration
|
||||
baseURL = "/"
|
||||
title = "Your Site Title"
|
||||
theme = "chill-theme"
|
||||
defaultContentLanguage = "en"
|
||||
|
||||
# Required Features
|
||||
enableEmoji = true # Enable emoji support
|
||||
enableGitInfo = true # Enable Git info for lastmod
|
||||
|
||||
# Pagination
|
||||
paginate = 6
|
||||
paginatePath = "page"
|
||||
|
||||
# Required Module Configuration
|
||||
[module]
|
||||
[module.hugoVersion]
|
||||
extended = true
|
||||
min = "0.80.0"
|
||||
|
||||
# Required Build Configuration
|
||||
[build]
|
||||
writeStats = true # Required for TailwindCSS
|
||||
|
||||
[build.buildStats]
|
||||
enable = true
|
||||
|
||||
# Security Configuration
|
||||
[security.funcs]
|
||||
getenv = ['^HUGO_', '^CI$']
|
||||
|
||||
# Required Markup Configuration
|
||||
[markup]
|
||||
[markup.highlight]
|
||||
noClasses = false
|
||||
lineNos = true
|
||||
codeFences = true
|
||||
guessSyntax = true
|
||||
lineNumbersInTable = true
|
||||
[markup.goldmark.renderer]
|
||||
unsafe = true # Allow HTML in markdown
|
||||
[markup.tableOfContents]
|
||||
endLevel = 3
|
||||
ordered = false
|
||||
startLevel = 2
|
||||
|
||||
# Taxonomies
|
||||
[taxonomies]
|
||||
category = 'categories'
|
||||
tag = 'tags'
|
||||
|
||||
# Theme Parameters
|
||||
[params]
|
||||
description = "Your site description"
|
||||
author = "Your Name"
|
||||
logo = "/images/logo.svg" # Path to your logo
|
||||
# Google Analytics ID (e.g., "G-XXXXXXXXXX")
|
||||
googleAnalytics = "G-XXXXXXXXXX" # Only enabled in production
|
||||
|
||||
# Google Tag Manager ID (e.g., "GTM-XXXXXXX")
|
||||
# Only enabled in production
|
||||
googleTagManager = "GTM-XXXXXXX"
|
||||
|
||||
# Header Configuration
|
||||
[params.header]
|
||||
background = "bg-white/80 backdrop-blur-sm"
|
||||
border = "border-b border-gray-100"
|
||||
|
||||
# Header Logo
|
||||
[params.header.logo]
|
||||
src = "/images/logo.svg"
|
||||
|
||||
# Header Buttons (optional)
|
||||
[params.header.buttons]
|
||||
[params.header.buttons.signIn]
|
||||
text = "Sign in"
|
||||
url = "/signin"
|
||||
[params.header.buttons.getStarted]
|
||||
text = "Get Started"
|
||||
url = "/get-started"
|
||||
|
||||
# Global CTA Configuration (optional)
|
||||
[params.cta]
|
||||
enable = true
|
||||
title = "Ready to Get Started?"
|
||||
description = "Join companies using our platform"
|
||||
[params.cta.primary_button]
|
||||
text = "Get Started Free"
|
||||
url = "/get-started"
|
||||
[params.cta.secondary_button]
|
||||
text = "Book Demo"
|
||||
url = "/demo"
|
||||
|
||||
# Social Media Links (optional)
|
||||
[params.social]
|
||||
linkedin = "https://linkedin.com/in/yourusername"
|
||||
twitter = "https://twitter.com/yourusername"
|
||||
bluesky = "https://bsky.app/profile/yourblueskyhandle"
|
||||
github = "https://github.com/yourusername"
|
||||
|
||||
# Navigation Menu
|
||||
[menu]
|
||||
[[menu.main]]
|
||||
name = "Features"
|
||||
weight = 1
|
||||
[menu.main.params]
|
||||
has_submenu = true
|
||||
submenu = [
|
||||
{ name = "Feature 1", url = "/features/feature-1/" },
|
||||
{ name = "Feature 2", url = "/features/feature-2/" }
|
||||
]
|
||||
[[menu.main]]
|
||||
name = "Pricing"
|
||||
url = "/pricing"
|
||||
weight = 2
|
||||
[[menu.main]]
|
||||
name = "Blog"
|
||||
url = "/blog"
|
||||
weight = 3
|
||||
```
|
||||
|
||||
This configuration includes:
|
||||
|
||||
- **Basic Settings**: Site title, theme selection, and default language
|
||||
- **Required Features**: Emoji support and Git integration
|
||||
- **Pagination**: Posts per page configuration
|
||||
- **Module Configuration**: Hugo Extended version requirements
|
||||
- **Build Settings**: Required for TailwindCSS integration with build stats
|
||||
- **Security Settings**: Environment variable access control
|
||||
- **Markup Settings**: Syntax highlighting and markdown rendering options
|
||||
- **Taxonomies**: Categories and tags support
|
||||
- **Theme Parameters**:
|
||||
- Header configuration with logo and navigation
|
||||
- Call-to-action (CTA) sections
|
||||
- Social media links
|
||||
- Google Analytics configuration (only enabled in production)
|
||||
- Google Tag Manager configuration (only enabled in production)
|
||||
- Custom head content for additional tracking scripts and meta tags
|
||||
- **Navigation Menu**: Main menu structure with dropdown support
|
||||
|
||||
**Note**: For multilingual sites, see the [Multilingual Support](#multilingual-support) section below for additional language configuration.
|
||||
|
||||
## Development
|
||||
|
||||
To start the development server with live reload:
|
||||
|
||||
```bash
|
||||
npm run start
|
||||
```
|
||||
|
||||
This will:
|
||||
- Watch for changes in your TailwindCSS styles
|
||||
- Run the Hugo development server
|
||||
- Automatically rebuild when changes are detected
|
||||
|
||||
To build your site for production:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
This will:
|
||||
- Build and minify your TailwindCSS styles
|
||||
- Generate minified Hugo site in the `public` directory
|
||||
|
||||
## Customization
|
||||
|
||||
### Colors
|
||||
|
||||
The theme uses a primary and secondary color scheme that can be customized in `tailwind.config.js`:
|
||||
|
||||
```js
|
||||
colors: {
|
||||
primary: {
|
||||
// Your primary color palette
|
||||
},
|
||||
secondary: {
|
||||
// Your secondary color palette
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Typography
|
||||
|
||||
The theme uses Inter for body text and Plus Jakarta Sans for headings. You can modify this in `tailwind.config.js`:
|
||||
|
||||
```js
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'system-ui', 'sans-serif'],
|
||||
heading: ['Plus Jakarta Sans', 'sans-serif'],
|
||||
}
|
||||
```
|
||||
|
||||
### Layout Components
|
||||
|
||||
Common components like buttons, cards, and sections can be customized in `assets/scss/main.scss`.
|
||||
|
||||
### Custom Head Content
|
||||
|
||||
Add custom tracking scripts or meta tags by creating `layouts/partials/custom-head.html` in your site:
|
||||
|
||||
```html
|
||||
<!-- layouts/partials/custom-head.html -->
|
||||
<!-- Example: Adding Hotjar tracking -->
|
||||
<script>
|
||||
(function(h,o,t,j,a,r){
|
||||
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
|
||||
h._hjSettings={hjid:YOUR_HOTJAR_ID,hjsv:6};
|
||||
a=o.getElementsByTagName('head')[0];
|
||||
r=o.createElement('script');r.async=1;
|
||||
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
|
||||
a.appendChild(r);
|
||||
})(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');
|
||||
</script>
|
||||
|
||||
<!-- Example: Site verification -->
|
||||
<meta name="google-site-verification" content="your-code" />
|
||||
```
|
||||
|
||||
This is perfect for:
|
||||
- Third-party analytics (Hotjar, Mixpanel, Heap, etc.)
|
||||
- Site verification meta tags
|
||||
- Custom fonts or stylesheets
|
||||
- A/B testing scripts
|
||||
- Chat widgets
|
||||
|
||||
See the [Configuration Guide](docs/CONFIGURATION.md#custom-head-content) for more details.
|
||||
|
||||
## Multilingual Support
|
||||
|
||||
The theme has full multilingual (i18n) support with:
|
||||
- Automatic language switcher in the header
|
||||
- Language-specific content directories
|
||||
- Translatable UI strings via i18n files
|
||||
- Language-specific menus and parameters
|
||||
|
||||
### Quick Setup
|
||||
|
||||
1. **Configure languages in `hugo.toml`:**
|
||||
|
||||
```toml
|
||||
defaultContentLanguage = "en"
|
||||
|
||||
[languages]
|
||||
[languages.en]
|
||||
languageCode = "en-us"
|
||||
languageName = "English"
|
||||
weight = 1
|
||||
contentDir = "content"
|
||||
|
||||
[languages.zh-cn]
|
||||
languageCode = "zh-cn"
|
||||
languageName = "简体中文"
|
||||
weight = 2
|
||||
contentDir = "content/zh-cn"
|
||||
```
|
||||
|
||||
2. **Create translation files:**
|
||||
|
||||
Copy `themes/chill-theme/i18n/en.toml` to your site's `i18n/` directory and create language-specific versions (e.g., `i18n/zh-cn.toml`).
|
||||
|
||||
3. **Organize content by language:**
|
||||
|
||||
```
|
||||
content/
|
||||
├── _index.md # English homepage
|
||||
├── blog/ # English blog posts
|
||||
└── zh-cn/ # Chinese content
|
||||
├── _index.md # Chinese homepage
|
||||
└── blog/ # Chinese blog posts
|
||||
```
|
||||
|
||||
4. **Configure language-specific menus:**
|
||||
|
||||
```toml
|
||||
# English menu
|
||||
[[languages.en.menu.main]]
|
||||
name = "Features"
|
||||
url = "/features"
|
||||
|
||||
# Chinese menu
|
||||
[[languages.zh-cn.menu.main]]
|
||||
name = "功能特性"
|
||||
url = "/zh-cn/features"
|
||||
```
|
||||
|
||||
The language switcher will automatically appear in the header when multiple languages are configured.
|
||||
|
||||
**📖 [Full Multilingual Guide →](docs/INTERNATIONALIZATION.md)**
|
||||
|
||||
**💡 Want to see a complete working example?** Check out the [demo site repository](https://github.com/chaoming/hugo-saasify-demo) for a full multilingual setup with English and Simplified Chinese, including all configuration files, translated content, and i18n files.
|
||||
|
||||
## Content Structure
|
||||
|
||||
```
|
||||
content/
|
||||
├── _index.md # Homepage content
|
||||
├── blog/ # Blog posts
|
||||
├── features/ # Feature pages
|
||||
├── docs/ # Documentation pages
|
||||
└── zh-cn/ # Additional language (optional)
|
||||
├── _index.md
|
||||
└── blog/
|
||||
```
|
||||
|
||||
## Build Your Complete SaaS Solution
|
||||
|
||||
Hugo Saasify Theme is perfect for your **marketing site**, but what about your actual SaaS application? Check out [**Fireact.dev**](https://fireact.dev/) - an open-source framework that complements this theme perfectly.
|
||||
|
||||
[Fireact.dev](https://github.com/fireact-dev/main) is a production-ready SaaS application starter built with **React, Firebase, and Stripe**. It provides everything you need for the application side of your SaaS business:
|
||||
|
||||
- **Stripe Integration** - Complete billing system with subscription management, payment processing, invoices, and customer portal
|
||||
- **User Management** - Built-in authentication, team collaboration, user invitations, and role-based access control (admin/user roles)
|
||||
- **Multi-tenancy** - Full support for multiple subscription accounts with isolated data and permissions
|
||||
- **Production Ready** - TypeScript, internationalization (i18n), Firebase Cloud Functions, and comprehensive documentation
|
||||
|
||||
**Perfect Combination**: Use Hugo Saasify Theme for your public-facing marketing website (landing pages, blog, documentation) and Fireact.dev for your authenticated SaaS application. Together, they provide a complete solution for launching your SaaS product quickly.
|
||||
|
||||
Learn more at [fireact.dev](https://fireact.dev/) or view the [GitHub repository](https://github.com/fireact-dev/main).
|
||||
|
||||
## License
|
||||
|
||||
This theme is released under the [MIT license](https://github.com/chaoming/chill-theme/blob/main/LICENSE).
|
||||
|
||||
## Quick Links
|
||||
|
||||
- 📖 [Documentation](docs/README.md)
|
||||
- 🎨 [Demo Site](https://saasify-demo.chaoming.li)
|
||||
- 🐛 [Report Issues](https://github.com/chaoming/chill-theme/issues)
|
||||
- 💬 [Discussions](https://github.com/chaoming/chill-theme/discussions)
|
||||
|
||||
## Support
|
||||
|
||||
Need help? Check the documentation first:
|
||||
|
||||
1. **[Complete Documentation](docs/README.md)** - Start here
|
||||
2. **[Troubleshooting Guide](docs/TROUBLESHOOTING.md)** - Common issues
|
||||
3. **[GitHub Issues](https://github.com/chaoming/chill-theme/issues)** - Report bugs or request features
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please feel free to submit a Pull Request.
|
||||
|
||||
## Author
|
||||
|
||||
Created by [Chaoming Li](https://chaoming.li)
|
||||
@@ -0,0 +1,199 @@
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
|
||||
@layer base {
|
||||
html {
|
||||
@apply scroll-smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply font-sans text-gray-700 antialiased;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.rounded-lg {
|
||||
border-radius: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@layer components {
|
||||
.cta-section {
|
||||
padding-top: 3rem;
|
||||
padding-bottom: 3rem;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.cta-gradient {
|
||||
background: linear-gradient(calc(var(--gradient-angle) * 1deg), var(--gradient-from), var(--gradient-to));
|
||||
}
|
||||
|
||||
.btn {
|
||||
@apply inline-flex items-center justify-center px-6 py-3 font-medium transition duration-200 ease-in-out;
|
||||
border-radius: 2rem;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
@apply btn bg-primary-600 text-white hover:bg-primary-700 hover:scale-105;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
@apply btn bg-secondary-600 text-white hover:bg-secondary-700 hover:scale-105;
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
@apply btn border-2 border-primary-600 text-primary-600 hover:scale-105;
|
||||
}
|
||||
|
||||
.container {
|
||||
@apply mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl;
|
||||
}
|
||||
|
||||
.section {
|
||||
@apply py-16 md:py-24;
|
||||
}
|
||||
|
||||
.card {
|
||||
@apply bg-white p-6 transition duration-200 hover:shadow-md;
|
||||
border-radius: 2rem;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
@apply text-gray-600 hover:text-primary-600 font-bold transition duration-200;
|
||||
}
|
||||
|
||||
.feature-grid {
|
||||
@apply grid gap-8 md:grid-cols-2 lg:grid-cols-3;
|
||||
}
|
||||
|
||||
/* Blog and Syntax Highlighting Styles */
|
||||
.highlight {
|
||||
@apply text-sm font-mono text-gray-200;
|
||||
}
|
||||
|
||||
.highlight table {
|
||||
@apply w-full border-separate border-spacing-0;
|
||||
}
|
||||
|
||||
.highlight table td {
|
||||
@apply p-0;
|
||||
}
|
||||
|
||||
.highlight table td:first-child {
|
||||
@apply pr-4 text-right select-none text-gray-500 border-r border-gray-700;
|
||||
}
|
||||
|
||||
.highlight table td:last-child {
|
||||
@apply pl-4 w-full;
|
||||
}
|
||||
|
||||
.highlight .k, .highlight .kd {
|
||||
@apply text-purple-400 font-semibold;
|
||||
}
|
||||
|
||||
.highlight .nf, .highlight .nx {
|
||||
@apply text-blue-400;
|
||||
}
|
||||
|
||||
.highlight .s, .highlight .s1, .highlight .s2 {
|
||||
@apply text-green-400;
|
||||
}
|
||||
|
||||
.highlight .mi, .highlight .mf {
|
||||
@apply text-orange-400;
|
||||
}
|
||||
|
||||
.highlight .c, .highlight .c1, .highlight .cm {
|
||||
@apply text-gray-500 italic;
|
||||
}
|
||||
|
||||
.highlight .o {
|
||||
@apply text-yellow-400;
|
||||
}
|
||||
|
||||
.highlight .p {
|
||||
@apply text-gray-400;
|
||||
}
|
||||
|
||||
.prose {
|
||||
@apply max-w-none;
|
||||
}
|
||||
|
||||
.prose h1, .prose h2, .prose h3, .prose h4 {
|
||||
@apply font-heading font-bold text-gray-900;
|
||||
}
|
||||
|
||||
.prose h1 {
|
||||
@apply text-4xl mb-8;
|
||||
}
|
||||
|
||||
.prose h2 {
|
||||
@apply text-3xl mt-12 mb-6;
|
||||
}
|
||||
|
||||
.prose h3 {
|
||||
@apply text-2xl mt-8 mb-4;
|
||||
}
|
||||
|
||||
.prose p {
|
||||
@apply text-gray-700 leading-relaxed mb-6;
|
||||
}
|
||||
|
||||
.prose a {
|
||||
@apply text-primary-600 hover:text-primary-700 no-underline;
|
||||
}
|
||||
|
||||
.prose ul, .prose ol {
|
||||
@apply my-6 ml-6;
|
||||
}
|
||||
|
||||
.prose li {
|
||||
@apply mb-2;
|
||||
}
|
||||
|
||||
.prose blockquote {
|
||||
@apply border-l-4 border-gray-200 pl-4 italic text-gray-700 my-8;
|
||||
}
|
||||
|
||||
.prose img {
|
||||
@apply rounded-lg shadow-lg my-8;
|
||||
}
|
||||
|
||||
.prose code:not(pre code) {
|
||||
@apply bg-gray-100 text-gray-900 px-1.5 py-0.5 rounded text-sm font-mono;
|
||||
}
|
||||
|
||||
.table-of-contents {
|
||||
@apply bg-gray-50 p-6 rounded-lg my-8;
|
||||
}
|
||||
|
||||
.table-of-contents nav {
|
||||
@apply space-y-2;
|
||||
}
|
||||
|
||||
.table-of-contents a {
|
||||
@apply text-gray-700 hover:text-primary-600 no-underline;
|
||||
}
|
||||
|
||||
.table-of-contents ul {
|
||||
@apply list-none ml-4 space-y-2;
|
||||
}
|
||||
}
|
||||
.features-carousel__nav { margin-bottom: 1rem; text-align: center; }
|
||||
.features-carousel__nav button {
|
||||
@apply btn text-gray-900 hover:text-primary-700;
|
||||
max-height:40px;
|
||||
}
|
||||
|
||||
.features-carousel__nav button.active {
|
||||
@apply btn bg-primary-600 text-white hover:bg-primary-700 hover:scale-105;
|
||||
}
|
||||
|
||||
.features-carousel__slides { min-height: 150px; }
|
||||
.feature { display: none; }
|
||||
@@ -0,0 +1,4 @@
|
||||
[module]
|
||||
[module.hugoVersion]
|
||||
extended = true
|
||||
min = "0.80.0"
|
||||
@@ -0,0 +1,989 @@
|
||||
# Content Creation Guide
|
||||
|
||||
Complete guide to creating and managing content in the Hugo Saasify Theme. Learn how to create different types of pages, blog posts, documentation, and optimize for SEO.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Content Structure](#content-structure)
|
||||
- [Front Matter Reference](#front-matter-reference)
|
||||
- [Page Types](#page-types)
|
||||
- [Blog Posts](#blog-posts)
|
||||
- [Documentation Pages](#documentation-pages)
|
||||
- [Creating Pages](#creating-pages)
|
||||
- [Taxonomies](#taxonomies)
|
||||
- [Media Management](#media-management)
|
||||
- [SEO Optimization](#seo-optimization)
|
||||
|
||||
## Content Structure
|
||||
|
||||
Hugo content is organized in the `content/` directory with a hierarchical structure.
|
||||
|
||||
### Directory Layout
|
||||
|
||||
```
|
||||
content/
|
||||
├── _index.md # Homepage
|
||||
├── blog/
|
||||
│ ├── _index.md # Blog listing page
|
||||
│ ├── my-first-post.md # Blog post
|
||||
│ └── another-post.md # Blog post
|
||||
├── docs/
|
||||
│ ├── _index.md # Docs home
|
||||
│ ├── getting-started/
|
||||
│ │ ├── _index.md
|
||||
│ │ └── installation.md
|
||||
│ └── guides/
|
||||
│ ├── _index.md
|
||||
│ └── advanced.md
|
||||
├── features/
|
||||
│ ├── _index.md
|
||||
│ ├── performance.md
|
||||
│ └── security.md
|
||||
├── pricing.md
|
||||
├── about.md
|
||||
└── contact.md
|
||||
```
|
||||
|
||||
### Content Types
|
||||
|
||||
- **Single Pages**: Individual pages (About, Contact, Pricing)
|
||||
- **List Pages**: Section indexes (`_index.md`)
|
||||
- **Blog Posts**: Content in `blog/` directory
|
||||
- **Documentation**: Content in `docs/` directory
|
||||
- **Custom Types**: Any custom content sections
|
||||
|
||||
## Front Matter Reference
|
||||
|
||||
Front matter is metadata at the top of your markdown files.
|
||||
|
||||
### Common Front Matter
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "Page Title"
|
||||
date: 2025-10-06
|
||||
lastmod: 2025-10-06
|
||||
draft: false
|
||||
description: "Page description for SEO and social sharing"
|
||||
slug: "custom-url-slug"
|
||||
aliases:
|
||||
- /old-url/
|
||||
- /another-old-url/
|
||||
---
|
||||
```
|
||||
|
||||
### Complete Front Matter Options
|
||||
|
||||
```yaml
|
||||
---
|
||||
# Basic Info
|
||||
title: "Complete Page Title"
|
||||
date: 2025-10-06T10:00:00-07:00
|
||||
lastmod: 2025-10-06T15:30:00-07:00
|
||||
draft: false
|
||||
publishDate: 2025-10-06T10:00:00-07:00
|
||||
expiryDate: 2026-10-06T10:00:00-07:00
|
||||
|
||||
# Content
|
||||
description: "Detailed description for meta tags and previews"
|
||||
summary: "Short summary for listing pages"
|
||||
keywords: ["keyword1", "keyword2", "keyword3"]
|
||||
|
||||
# Layout
|
||||
layout: "single" # or: simple, pricing, company, career, feature
|
||||
type: "blog" # Content type
|
||||
|
||||
# URL
|
||||
slug: "custom-url-slug"
|
||||
url: "/custom/path/"
|
||||
aliases:
|
||||
- /old-path/
|
||||
- /another-old-path/
|
||||
|
||||
# Taxonomies
|
||||
categories: ["Technology", "Web Development"]
|
||||
tags: ["Hugo", "SaaS", "Tutorial"]
|
||||
series: ["Getting Started"]
|
||||
|
||||
# Author
|
||||
author: "John Doe"
|
||||
authors: ["John Doe", "Jane Smith"]
|
||||
|
||||
# Media
|
||||
images:
|
||||
- /images/featured-image.jpg
|
||||
- /images/social-share.jpg
|
||||
|
||||
# SEO
|
||||
robots: "index, follow"
|
||||
canonical: "https://example.com/canonical-url/"
|
||||
|
||||
# Features
|
||||
toc: true # Show table of contents
|
||||
comments: true # Enable comments
|
||||
share: true # Show share buttons
|
||||
featured: true # Mark as featured
|
||||
weight: 10 # Sort order (lower = earlier)
|
||||
|
||||
# Custom Parameters
|
||||
custom_field: "value"
|
||||
---
|
||||
```
|
||||
|
||||
### Field Descriptions
|
||||
|
||||
**Basic Info**:
|
||||
- `title`: Page title (required)
|
||||
- `date`: Publication date
|
||||
- `draft`: If true, page won't be published
|
||||
- `publishDate`: Schedule future publication
|
||||
- `expiryDate`: Auto-expire content
|
||||
|
||||
**Content**:
|
||||
- `description`: Meta description (150-160 chars recommended)
|
||||
- `summary`: Short summary for cards/listings
|
||||
- `keywords`: SEO keywords (optional, less important today)
|
||||
|
||||
**Layout**:
|
||||
- `layout`: Template to use
|
||||
- `type`: Content type for organization
|
||||
|
||||
**URL**:
|
||||
- `slug`: Custom URL slug (defaults to filename)
|
||||
- `url`: Full custom URL path
|
||||
- `aliases`: Redirects from old URLs
|
||||
|
||||
**Taxonomies**:
|
||||
- `categories`: Broad categories
|
||||
- `tags`: Specific tags
|
||||
- `series`: Part of a series
|
||||
|
||||
## Page Types
|
||||
|
||||
### Homepage
|
||||
|
||||
**File**: `content/_index.md`
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "Home"
|
||||
description: "Build your SaaS faster with our modern Hugo theme"
|
||||
---
|
||||
|
||||
{{< hero
|
||||
headline="Build Your SaaS <span class='text-primary-600'>Faster</span>"
|
||||
sub_headline="A modern, responsive Hugo theme for SaaS companies"
|
||||
primary_button_text="Get Started"
|
||||
primary_button_url="/signup"
|
||||
hero_image="/images/hero.png"
|
||||
>}}
|
||||
|
||||
{{< features-section title="Why Choose Us" >}}
|
||||
{{< feature icon="zap" title="Fast" description="Lightning fast performance" >}}
|
||||
{{< feature icon="lock" title="Secure" description="Enterprise security" >}}
|
||||
{{< /features-section >}}
|
||||
```
|
||||
|
||||
### Simple Page
|
||||
|
||||
For clean, focused content pages.
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "Privacy Policy"
|
||||
layout: simple
|
||||
description: "Our privacy policy and data handling practices"
|
||||
---
|
||||
|
||||
# Privacy Policy
|
||||
|
||||
Last updated: October 6, 2025
|
||||
|
||||
## Introduction
|
||||
|
||||
Your privacy is important to us...
|
||||
|
||||
## Data Collection
|
||||
|
||||
We collect the following information...
|
||||
```
|
||||
|
||||
**Use Cases**:
|
||||
- Privacy Policy
|
||||
- Terms of Service
|
||||
- Legal pages
|
||||
- Documentation
|
||||
|
||||
### Feature Page
|
||||
|
||||
Showcase a specific feature or product.
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "Performance Features"
|
||||
layout: feature
|
||||
description: "Lightning-fast performance for your SaaS application"
|
||||
featured_image: "/images/feature-performance.jpg"
|
||||
---
|
||||
|
||||
{{< hero
|
||||
headline="Unmatched Performance"
|
||||
sub_headline="Built for speed from the ground up"
|
||||
hero_image="/images/performance.png"
|
||||
>}}
|
||||
|
||||
## Lightning Fast
|
||||
|
||||
Our platform is optimized for speed...
|
||||
|
||||
{{< stat value="<50ms" label="Response Time" >}}
|
||||
{{< stat value="99.9%" label="Uptime" >}}
|
||||
```
|
||||
|
||||
### Pricing Page
|
||||
|
||||
Display your pricing plans.
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "Pricing"
|
||||
layout: pricing
|
||||
description: "Choose the perfect plan for your needs"
|
||||
---
|
||||
|
||||
{{< pricing-table-1 >}}
|
||||
{
|
||||
"title": "Simple, Transparent Pricing",
|
||||
"plans": [...]
|
||||
}
|
||||
{{< /pricing-table-1 >}}
|
||||
|
||||
{{< faq >}}
|
||||
{
|
||||
"title": "Pricing FAQ",
|
||||
"questions": [...]
|
||||
}
|
||||
{{< /faq >}}
|
||||
```
|
||||
|
||||
### Company/About Page
|
||||
|
||||
For company information and team pages.
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "About Us"
|
||||
layout: company
|
||||
description: "Learn about our mission, vision, and team"
|
||||
---
|
||||
|
||||
{{< hero headline="Our Story" sub_headline="Building the future of SaaS" >}}
|
||||
|
||||
## Our Mission
|
||||
|
||||
We're on a mission to...
|
||||
|
||||
{{< stat value="100+" label="Customers" >}}
|
||||
{{< stat value="50+" label="Team Members" >}}
|
||||
{{< stat value="10+" label="Countries" >}}
|
||||
|
||||
## Our Team
|
||||
|
||||
{{< team-member
|
||||
name="Jane Doe"
|
||||
title="CEO & Founder"
|
||||
image="/images/team/jane.jpg"
|
||||
bio="Jane has 15 years of experience..."
|
||||
linkedin="https://linkedin.com/in/janedoe"
|
||||
>}}
|
||||
```
|
||||
|
||||
### Career Page
|
||||
|
||||
Job listings and career information.
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "Careers"
|
||||
layout: career
|
||||
description: "Join our team and build the future"
|
||||
---
|
||||
|
||||
## Why Work With Us
|
||||
|
||||
Great benefits, amazing culture...
|
||||
|
||||
## Open Positions
|
||||
|
||||
Our job listings are below...
|
||||
```
|
||||
|
||||
### Job Single
|
||||
|
||||
Individual job postings.
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "Senior Software Engineer"
|
||||
layout: job-single
|
||||
date: 2025-10-06
|
||||
department: "Engineering"
|
||||
location: "Remote"
|
||||
type: "Full-time"
|
||||
salary_range: "$120k - $180k"
|
||||
---
|
||||
|
||||
## About the Role
|
||||
|
||||
We're looking for a senior software engineer...
|
||||
|
||||
## Requirements
|
||||
|
||||
- 5+ years of experience
|
||||
- Strong knowledge of Go/Python
|
||||
- Experience with distributed systems
|
||||
|
||||
## Benefits
|
||||
|
||||
- Competitive salary
|
||||
- Health insurance
|
||||
- Remote work
|
||||
- Unlimited PTO
|
||||
```
|
||||
|
||||
## Blog Posts
|
||||
|
||||
Creating and managing blog content.
|
||||
|
||||
### Creating a Blog Post
|
||||
|
||||
```bash
|
||||
# Create new post
|
||||
hugo new blog/my-awesome-post.md
|
||||
```
|
||||
|
||||
### Blog Post Front Matter
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "How to Build a SaaS Application"
|
||||
date: 2025-10-06
|
||||
lastmod: 2025-10-06
|
||||
author: "John Doe"
|
||||
description: "Complete guide to building your first SaaS application"
|
||||
categories: ["Tutorials"]
|
||||
tags: ["SaaS", "Web Development", "Tutorial"]
|
||||
featured_image: "/images/blog/saas-guide.jpg"
|
||||
draft: false
|
||||
toc: true
|
||||
---
|
||||
|
||||
Your blog post content here...
|
||||
```
|
||||
|
||||
### Blog Post Structure
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: "Complete Blog Post Example"
|
||||
date: 2025-10-06
|
||||
author: "John Doe"
|
||||
categories: ["Technology"]
|
||||
tags: ["Hugo", "Web Development"]
|
||||
featured_image: "/images/blog/featured.jpg"
|
||||
description: "Learn how to write great blog posts"
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
Start with a hook that grabs attention...
|
||||
|
||||
## Main Content
|
||||
|
||||
### Subsection 1
|
||||
|
||||
Detailed content with examples...
|
||||
|
||||
```javascript
|
||||
// Code example
|
||||
function example() {
|
||||
return "Hello, World!";
|
||||
}
|
||||
```
|
||||
|
||||
### Subsection 2
|
||||
|
||||
More content...
|
||||
|
||||
## Conclusion
|
||||
|
||||
Wrap up with key takeaways...
|
||||
|
||||
## Further Reading
|
||||
|
||||
- [Related Article 1](#)
|
||||
- [Related Article 2](#)
|
||||
```
|
||||
|
||||
### Blog Features
|
||||
|
||||
**Table of Contents**:
|
||||
```yaml
|
||||
---
|
||||
toc: true
|
||||
---
|
||||
```
|
||||
|
||||
**Featured Image**:
|
||||
```yaml
|
||||
---
|
||||
featured_image: "/images/blog/my-post.jpg"
|
||||
---
|
||||
```
|
||||
|
||||
**Author Info**:
|
||||
```yaml
|
||||
---
|
||||
author: "John Doe"
|
||||
# or multiple authors
|
||||
authors: ["John Doe", "Jane Smith"]
|
||||
---
|
||||
```
|
||||
|
||||
**Categories & Tags**:
|
||||
```yaml
|
||||
---
|
||||
categories: ["Technology", "Business"]
|
||||
tags: ["Hugo", "SaaS", "Web", "Tutorial"]
|
||||
---
|
||||
```
|
||||
|
||||
## Documentation Pages
|
||||
|
||||
Create structured documentation with sidebar navigation.
|
||||
|
||||
### Documentation Structure
|
||||
|
||||
```
|
||||
content/docs/
|
||||
├── _index.md # Docs home
|
||||
├── getting-started/
|
||||
│ ├── _index.md # Section index
|
||||
│ ├── installation.md # weight: 1
|
||||
│ ├── configuration.md # weight: 2
|
||||
│ └── first-steps.md # weight: 3
|
||||
├── guides/
|
||||
│ ├── _index.md
|
||||
│ ├── customization.md
|
||||
│ └── deployment.md
|
||||
└── reference/
|
||||
├── _index.md
|
||||
├── api.md
|
||||
└── configuration.md
|
||||
```
|
||||
|
||||
### Documentation Front Matter
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "Installation Guide"
|
||||
description: "How to install the theme"
|
||||
weight: 1 # Sort order in sidebar
|
||||
draft: false
|
||||
toc: true # Show table of contents
|
||||
---
|
||||
|
||||
# Installation Guide
|
||||
|
||||
Complete installation instructions...
|
||||
```
|
||||
|
||||
### Documentation Index Pages
|
||||
|
||||
**Section Index** (`_index.md`):
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "Getting Started"
|
||||
description: "Start here to learn the basics"
|
||||
weight: 1
|
||||
---
|
||||
|
||||
# Getting Started
|
||||
|
||||
Welcome to our documentation!
|
||||
|
||||
## In This Section
|
||||
|
||||
- [Installation](installation/)
|
||||
- [Configuration](configuration/)
|
||||
- [First Steps](first-steps/)
|
||||
```
|
||||
|
||||
### Sidebar Navigation
|
||||
|
||||
The sidebar automatically generates from:
|
||||
1. Directory structure
|
||||
2. `weight` parameter (lower = earlier)
|
||||
3. Front matter titles
|
||||
|
||||
**Example Sidebar Order**:
|
||||
|
||||
```yaml
|
||||
# content/docs/getting-started/_index.md
|
||||
---
|
||||
title: "Getting Started"
|
||||
weight: 1
|
||||
---
|
||||
|
||||
# content/docs/getting-started/installation.md
|
||||
---
|
||||
title: "Installation"
|
||||
weight: 1
|
||||
---
|
||||
|
||||
# content/docs/getting-started/configuration.md
|
||||
---
|
||||
title: "Configuration"
|
||||
weight: 2
|
||||
---
|
||||
|
||||
# content/docs/guides/_index.md
|
||||
---
|
||||
title: "Guides"
|
||||
weight: 2
|
||||
---
|
||||
```
|
||||
|
||||
### Documentation Best Practices
|
||||
|
||||
1. **Hierarchical Structure**: Organize content logically
|
||||
2. **Clear Titles**: Use descriptive, searchable titles
|
||||
3. **Weight Ordering**: Use weights for custom ordering
|
||||
4. **Cross-Linking**: Link related documentation
|
||||
5. **Examples**: Include code examples and screenshots
|
||||
6. **Table of Contents**: Enable TOC for long pages
|
||||
7. **Keep Updated**: Review and update regularly
|
||||
|
||||
### Documentation Features
|
||||
|
||||
**Table of Contents**:
|
||||
```markdown
|
||||
---
|
||||
toc: true
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
# Your Content
|
||||
```
|
||||
|
||||
**Code Examples**:
|
||||
```markdown
|
||||
{{< code lang="bash" title="Installation" >}}
|
||||
hugo new site mysite
|
||||
{{< /code >}}
|
||||
```
|
||||
|
||||
**Callouts/Alerts**:
|
||||
```markdown
|
||||
> **Note**: Important information here
|
||||
|
||||
> **Warning**: Caution about this action
|
||||
```
|
||||
|
||||
**Cross-References**:
|
||||
```markdown
|
||||
See [Installation Guide](../getting-started/installation/) for details.
|
||||
```
|
||||
|
||||
## Creating Pages
|
||||
|
||||
### Using Hugo CLI
|
||||
|
||||
```bash
|
||||
# Create a blog post
|
||||
hugo new blog/my-post.md
|
||||
|
||||
# Create a documentation page
|
||||
hugo new docs/guides/my-guide.md
|
||||
|
||||
# Create a custom page
|
||||
hugo new features/new-feature.md
|
||||
```
|
||||
|
||||
### Manual Creation
|
||||
|
||||
Create file directly in `content/` directory:
|
||||
|
||||
```bash
|
||||
touch content/about.md
|
||||
```
|
||||
|
||||
Add front matter and content:
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "About Us"
|
||||
description: "Learn about our company"
|
||||
layout: simple
|
||||
---
|
||||
|
||||
# About Us
|
||||
|
||||
Our story begins...
|
||||
```
|
||||
|
||||
### Content Organization
|
||||
|
||||
**Flat Structure** (simple sites):
|
||||
```
|
||||
content/
|
||||
├── _index.md
|
||||
├── about.md
|
||||
├── pricing.md
|
||||
└── contact.md
|
||||
```
|
||||
|
||||
**Hierarchical Structure** (complex sites):
|
||||
```
|
||||
content/
|
||||
├── _index.md
|
||||
├── blog/
|
||||
│ └── posts...
|
||||
├── docs/
|
||||
│ └── documentation...
|
||||
├── features/
|
||||
│ └── feature pages...
|
||||
└── company/
|
||||
├── about.md
|
||||
├── team.md
|
||||
└── careers/
|
||||
└── jobs...
|
||||
```
|
||||
|
||||
## Taxonomies
|
||||
|
||||
Organize content with categories, tags, and custom taxonomies.
|
||||
|
||||
### Using Categories
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "My Post"
|
||||
categories: ["Technology", "Web Development"]
|
||||
---
|
||||
```
|
||||
|
||||
**Category Page**: Automatically created at `/categories/technology/`
|
||||
|
||||
### Using Tags
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "My Post"
|
||||
tags: ["Hugo", "SaaS", "Tutorial", "Beginner"]
|
||||
---
|
||||
```
|
||||
|
||||
**Tag Page**: Automatically created at `/tags/hugo/`
|
||||
|
||||
### Custom Taxonomies
|
||||
|
||||
1. **Define in `hugo.toml`**:
|
||||
```toml
|
||||
[taxonomies]
|
||||
category = 'categories'
|
||||
tag = 'tags'
|
||||
series = 'series'
|
||||
author = 'authors'
|
||||
```
|
||||
|
||||
2. **Use in Content**:
|
||||
```yaml
|
||||
---
|
||||
title: "My Post"
|
||||
series: ["Getting Started Guide"]
|
||||
authors: ["John Doe"]
|
||||
---
|
||||
```
|
||||
|
||||
3. **Access**: `/series/getting-started-guide/`, `/authors/john-doe/`
|
||||
|
||||
### Taxonomy Best Practices
|
||||
|
||||
- **Categories**: Broad topics (5-10 total)
|
||||
- **Tags**: Specific keywords (unlimited)
|
||||
- **Consistent Naming**: Use consistent case and format
|
||||
- **Don't Over-Tag**: 3-7 tags per post is ideal
|
||||
|
||||
## Media Management
|
||||
|
||||
### Images
|
||||
|
||||
**Storage Location**: `static/images/`
|
||||
|
||||
```
|
||||
static/
|
||||
└── images/
|
||||
├── logo.svg
|
||||
├── hero.png
|
||||
├── blog/
|
||||
│ ├── post-1.jpg
|
||||
│ └── post-2.jpg
|
||||
└── team/
|
||||
├── john.jpg
|
||||
└── jane.jpg
|
||||
```
|
||||
|
||||
**Using in Content**:
|
||||
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||
**Using with Shortcode**:
|
||||
|
||||
```markdown
|
||||
{{< figure
|
||||
src="/images/diagram.png"
|
||||
alt="System Architecture"
|
||||
caption="Our microservices architecture"
|
||||
>}}
|
||||
```
|
||||
|
||||
### Image Optimization
|
||||
|
||||
**Best Practices**:
|
||||
- Compress images before uploading
|
||||
- Use appropriate formats (WebP, JPEG, PNG)
|
||||
- Use responsive images
|
||||
- Include alt text for accessibility
|
||||
|
||||
**Tools**:
|
||||
- [TinyPNG](https://tinypng.com/) - Compression
|
||||
- [Squoosh](https://squoosh.app/) - Format conversion
|
||||
- ImageOptim (Mac)
|
||||
- ImageMagick (CLI)
|
||||
|
||||
### Featured Images
|
||||
|
||||
**Blog Posts**:
|
||||
```yaml
|
||||
---
|
||||
featured_image: "/images/blog/post-featured.jpg"
|
||||
---
|
||||
```
|
||||
|
||||
**Social Sharing**:
|
||||
```yaml
|
||||
---
|
||||
images:
|
||||
- /images/social-share.jpg
|
||||
---
|
||||
```
|
||||
|
||||
### Videos
|
||||
|
||||
**YouTube Embed**:
|
||||
```markdown
|
||||
{{< youtube VIDEO_ID >}}
|
||||
```
|
||||
|
||||
**Vimeo Embed**:
|
||||
```markdown
|
||||
{{< vimeo VIDEO_ID >}}
|
||||
```
|
||||
|
||||
**Self-Hosted**:
|
||||
```html
|
||||
<video controls>
|
||||
<source src="/videos/demo.mp4" type="video/mp4">
|
||||
Your browser doesn't support video.
|
||||
</video>
|
||||
```
|
||||
|
||||
### Files & Downloads
|
||||
|
||||
**PDFs and Documents**:
|
||||
|
||||
Store in `static/files/`:
|
||||
|
||||
```markdown
|
||||
[Download PDF](/files/whitepaper.pdf)
|
||||
```
|
||||
|
||||
## SEO Optimization
|
||||
|
||||
### Essential SEO Elements
|
||||
|
||||
**Title & Description**:
|
||||
```yaml
|
||||
---
|
||||
title: "How to Build a SaaS Application in 2025"
|
||||
description: "Complete guide to building, launching, and scaling your SaaS application with modern tools and best practices."
|
||||
---
|
||||
```
|
||||
|
||||
**URL Structure**:
|
||||
```yaml
|
||||
---
|
||||
slug: "build-saas-application-2025"
|
||||
---
|
||||
```
|
||||
|
||||
**Canonical URL**:
|
||||
```yaml
|
||||
---
|
||||
canonical: "https://example.com/blog/original-post/"
|
||||
---
|
||||
```
|
||||
|
||||
### Open Graph Tags
|
||||
|
||||
Automatically generated from:
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "Page Title"
|
||||
description: "Page description"
|
||||
images:
|
||||
- /images/social-share.jpg
|
||||
---
|
||||
```
|
||||
|
||||
### Twitter Cards
|
||||
|
||||
Same as Open Graph:
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "Twitter-friendly Title"
|
||||
description: "Compelling description under 200 characters"
|
||||
images:
|
||||
- /images/twitter-card.jpg
|
||||
---
|
||||
```
|
||||
|
||||
### Structured Data
|
||||
|
||||
Add JSON-LD structured data for rich results:
|
||||
|
||||
```html
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BlogPosting",
|
||||
"headline": "{{ .Title }}",
|
||||
"description": "{{ .Description }}",
|
||||
"datePublished": "{{ .Date.Format "2006-01-02" }}"
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### SEO Best Practices
|
||||
|
||||
1. **Descriptive Titles**: 50-60 characters
|
||||
2. **Meta Descriptions**: 150-160 characters
|
||||
3. **Headings Hierarchy**: Use h1, h2, h3 properly
|
||||
4. **Image Alt Text**: Describe images accurately
|
||||
5. **Internal Linking**: Link related content
|
||||
6. **Fast Loading**: Optimize performance
|
||||
7. **Mobile Friendly**: Ensure responsive design
|
||||
8. **HTTPS**: Use secure connections
|
||||
9. **Sitemap**: Auto-generated by Hugo
|
||||
10. **robots.txt**: Control crawler access
|
||||
|
||||
### Keywords
|
||||
|
||||
```yaml
|
||||
---
|
||||
keywords: ["SaaS", "web development", "Hugo", "tutorial"]
|
||||
---
|
||||
```
|
||||
|
||||
**Note**: Less important for SEO today, but can help with organization.
|
||||
|
||||
## Content Best Practices
|
||||
|
||||
### Writing Guidelines
|
||||
|
||||
1. **Clear Headlines**: Descriptive, engaging titles
|
||||
2. **Short Paragraphs**: 2-3 sentences max
|
||||
3. **Bullet Points**: Break up long lists
|
||||
4. **Visual Elements**: Images, diagrams, videos
|
||||
5. **Code Examples**: Syntax highlighted, tested
|
||||
6. **Internal Links**: Guide readers to related content
|
||||
7. **CTAs**: Clear next steps
|
||||
8. **Proofreading**: Check spelling and grammar
|
||||
|
||||
### Content Workflow
|
||||
|
||||
1. **Plan**: Outline structure and key points
|
||||
2. **Draft**: Write content in markdown
|
||||
3. **Review**: Check for accuracy and clarity
|
||||
4. **Optimize**: Add SEO elements, images
|
||||
5. **Preview**: Test with `hugo server -D`
|
||||
6. **Publish**: Remove `draft: true`
|
||||
7. **Promote**: Share on social media
|
||||
8. **Update**: Review and refresh periodically
|
||||
|
||||
### Markdown Tips
|
||||
|
||||
**Bold & Italic**:
|
||||
```markdown
|
||||
**bold text**
|
||||
*italic text*
|
||||
***bold and italic***
|
||||
```
|
||||
|
||||
**Lists**:
|
||||
```markdown
|
||||
- Unordered item
|
||||
- Another item
|
||||
|
||||
1. Ordered item
|
||||
2. Another ordered item
|
||||
```
|
||||
|
||||
**Links**:
|
||||
```markdown
|
||||
[Link text](https://example.com)
|
||||
[Internal link](/about/)
|
||||
```
|
||||
|
||||
**Code**:
|
||||
```markdown
|
||||
Inline `code` with backticks
|
||||
|
||||
```language
|
||||
code block
|
||||
```
|
||||
```
|
||||
|
||||
**Blockquotes**:
|
||||
```markdown
|
||||
> This is a quote
|
||||
> Second line
|
||||
```
|
||||
|
||||
**Tables**:
|
||||
```markdown
|
||||
| Column 1 | Column 2 |
|
||||
|----------|----------|
|
||||
| Data 1 | Data 2 |
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [SHORTCODES.md](SHORTCODES.md) - Available shortcodes
|
||||
- [LAYOUTS.md](LAYOUTS.md) - Layout templates
|
||||
- [CONFIGURATION.md](CONFIGURATION.md) - Site configuration
|
||||
- [STYLING.md](STYLING.md) - Styling customization
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Hugo Content Management](https://gohugo.io/content-management/)
|
||||
- [Markdown Guide](https://www.markdownguide.org/)
|
||||
- [SEO Best Practices](https://developers.google.com/search/docs)
|
||||
- [Schema.org Documentation](https://schema.org/)
|
||||
@@ -0,0 +1,811 @@
|
||||
# Deployment Guide
|
||||
|
||||
Complete guide to deploying your Hugo Saasify Theme site to production. Learn how to deploy to popular platforms and optimize for performance.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Building for Production](#building-for-production)
|
||||
- [Platform Deployment Guides](#platform-deployment-guides)
|
||||
- [Netlify](#netlify)
|
||||
- [Vercel](#vercel)
|
||||
- [GitHub Pages](#github-pages)
|
||||
- [Cloudflare Pages](#cloudflare-pages)
|
||||
- [AWS S3 + CloudFront](#aws-s3--cloudfront)
|
||||
- [Custom Server Deployment](#custom-server-deployment)
|
||||
- [Environment Variables](#environment-variables)
|
||||
- [Performance Optimization](#performance-optimization)
|
||||
- [CI/CD Setup](#cicd-setup)
|
||||
- [Post-Deployment](#post-deployment)
|
||||
|
||||
## Building for Production
|
||||
|
||||
Before deploying, build your site for production.
|
||||
|
||||
### Build Command
|
||||
|
||||
```bash
|
||||
# Basic build
|
||||
hugo
|
||||
|
||||
# Build with minification
|
||||
hugo --minify
|
||||
|
||||
# Build with specific environment
|
||||
hugo --environment production
|
||||
```
|
||||
|
||||
### Build Output
|
||||
|
||||
The build creates a `public/` directory containing:
|
||||
```
|
||||
public/
|
||||
├── index.html
|
||||
├── css/
|
||||
│ └── main.min.[hash].css
|
||||
├── js/
|
||||
│ └── main.min.[hash].js
|
||||
├── images/
|
||||
├── blog/
|
||||
├── docs/
|
||||
└── ...
|
||||
```
|
||||
|
||||
### Pre-Deployment Checklist
|
||||
|
||||
- [ ] Update `baseURL` in `hugo.toml` to production URL
|
||||
- [ ] Remove draft posts (`draft: false` or remove drafts)
|
||||
- [ ] Test build locally: `hugo && hugo server -s public`
|
||||
- [ ] Verify all links work
|
||||
- [ ] Check image paths and assets
|
||||
- [ ] Test responsive design
|
||||
- [ ] Validate HTML/CSS
|
||||
- [ ] Check analytics integration
|
||||
- [ ] Review SEO meta tags
|
||||
- [ ] Test performance with Lighthouse
|
||||
|
||||
### Environment Configuration
|
||||
|
||||
**Development**:
|
||||
```toml
|
||||
# hugo.toml
|
||||
baseURL = "http://localhost:1313/"
|
||||
```
|
||||
|
||||
**Production** (update before deploying):
|
||||
```toml
|
||||
# hugo.toml
|
||||
baseURL = "https://yourdomain.com/"
|
||||
```
|
||||
|
||||
## Platform Deployment Guides
|
||||
|
||||
### Netlify
|
||||
|
||||
Netlify offers automatic deployments from Git with continuous deployment.
|
||||
|
||||
#### Quick Deploy
|
||||
|
||||
1. **Push to Git**:
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Ready for deployment"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
2. **Connect to Netlify**:
|
||||
- Visit [netlify.com](https://netlify.com)
|
||||
- Click "Add new site" → "Import an existing project"
|
||||
- Choose Git provider (GitHub, GitLab, Bitbucket)
|
||||
- Select your repository
|
||||
|
||||
3. **Configure Build Settings**:
|
||||
- **Build command**: `hugo --minify`
|
||||
- **Publish directory**: `public`
|
||||
- **Production branch**: `main`
|
||||
|
||||
4. **Environment Variables** (click "Show advanced"):
|
||||
```
|
||||
HUGO_VERSION = 0.120.0
|
||||
HUGO_ENV = production
|
||||
```
|
||||
|
||||
5. **Deploy**: Click "Deploy site"
|
||||
|
||||
#### Netlify Configuration File
|
||||
|
||||
Create `netlify.toml` in project root:
|
||||
|
||||
```toml
|
||||
[build]
|
||||
publish = "public"
|
||||
command = "hugo --minify"
|
||||
|
||||
[build.environment]
|
||||
HUGO_VERSION = "0.120.0"
|
||||
HUGO_ENV = "production"
|
||||
HUGO_ENABLEGITINFO = "true"
|
||||
|
||||
[context.production.environment]
|
||||
HUGO_ENV = "production"
|
||||
|
||||
[context.deploy-preview]
|
||||
command = "hugo --minify --buildFuture -b $DEPLOY_PRIME_URL"
|
||||
|
||||
[context.branch-deploy]
|
||||
command = "hugo --minify -b $DEPLOY_PRIME_URL"
|
||||
|
||||
[[redirects]]
|
||||
from = "/old-page"
|
||||
to = "/new-page"
|
||||
status = 301
|
||||
|
||||
[[headers]]
|
||||
for = "/*"
|
||||
[headers.values]
|
||||
X-Frame-Options = "DENY"
|
||||
X-XSS-Protection = "1; mode=block"
|
||||
X-Content-Type-Options = "nosniff"
|
||||
```
|
||||
|
||||
#### Custom Domain
|
||||
|
||||
1. Go to **Site settings** → **Domain management**
|
||||
2. Click "Add custom domain"
|
||||
3. Enter your domain: `yourdomain.com`
|
||||
4. Configure DNS:
|
||||
- **A Record**: Point to Netlify's load balancer IP
|
||||
- **CNAME**: Point `www` to `[your-site].netlify.app`
|
||||
5. Enable HTTPS (automatic with Let's Encrypt)
|
||||
|
||||
### Vercel
|
||||
|
||||
Vercel provides zero-configuration deployments with global CDN.
|
||||
|
||||
#### Deploy to Vercel
|
||||
|
||||
1. **Install Vercel CLI** (optional):
|
||||
```bash
|
||||
npm install -g vercel
|
||||
```
|
||||
|
||||
2. **Deploy via CLI**:
|
||||
```bash
|
||||
vercel
|
||||
```
|
||||
|
||||
Or deploy via web interface:
|
||||
|
||||
3. **Connect Repository**:
|
||||
- Visit [vercel.com](https://vercel.com)
|
||||
- Click "Add New" → "Project"
|
||||
- Import your Git repository
|
||||
|
||||
4. **Configure Project**:
|
||||
- **Framework Preset**: Hugo
|
||||
- **Build Command**: `hugo --minify`
|
||||
- **Output Directory**: `public`
|
||||
- **Install Command**: Leave empty
|
||||
|
||||
5. **Environment Variables**:
|
||||
```
|
||||
HUGO_VERSION=0.120.0
|
||||
```
|
||||
|
||||
6. **Deploy**: Click "Deploy"
|
||||
|
||||
#### Vercel Configuration
|
||||
|
||||
Create `vercel.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"build": {
|
||||
"env": {
|
||||
"HUGO_VERSION": "0.120.0"
|
||||
}
|
||||
},
|
||||
"redirects": [
|
||||
{
|
||||
"source": "/old-page",
|
||||
"destination": "/new-page",
|
||||
"permanent": true
|
||||
}
|
||||
],
|
||||
"headers": [
|
||||
{
|
||||
"source": "/(.*)",
|
||||
"headers": [
|
||||
{
|
||||
"key": "X-Frame-Options",
|
||||
"value": "DENY"
|
||||
},
|
||||
{
|
||||
"key": "X-Content-Type-Options",
|
||||
"value": "nosniff"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### GitHub Pages
|
||||
|
||||
Free hosting directly from your GitHub repository.
|
||||
|
||||
#### Setup GitHub Pages
|
||||
|
||||
1. **Create Repository**:
|
||||
- Name: `username.github.io` (user site)
|
||||
- Or: `repository-name` (project site)
|
||||
|
||||
2. **Update Base URL**:
|
||||
```toml
|
||||
# hugo.toml
|
||||
baseURL = "https://username.github.io/"
|
||||
# or for project site:
|
||||
baseURL = "https://username.github.io/repository-name/"
|
||||
```
|
||||
|
||||
3. **Create GitHub Action**:
|
||||
|
||||
`.github/workflows/hugo.yml`:
|
||||
|
||||
```yaml
|
||||
name: Deploy Hugo site to Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: false
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
HUGO_VERSION: 0.120.0
|
||||
steps:
|
||||
- name: Install Hugo CLI
|
||||
run: |
|
||||
wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
|
||||
&& sudo dpkg -i ${{ runner.temp }}/hugo.deb
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup Pages
|
||||
id: pages
|
||||
uses: actions/configure-pages@v4
|
||||
|
||||
- name: Install Node.js dependencies
|
||||
run: |
|
||||
cp themes/chill-theme/package.json .
|
||||
cp themes/chill-theme/postcss.config.js .
|
||||
cp themes/chill-theme/tailwind.config.copy.js ./tailwind.config.js
|
||||
npm install
|
||||
|
||||
- name: Build with Hugo
|
||||
env:
|
||||
HUGO_ENVIRONMENT: production
|
||||
HUGO_ENV: production
|
||||
run: |
|
||||
hugo \
|
||||
--minify \
|
||||
--baseURL "${{ steps.pages.outputs.base_url }}/"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v2
|
||||
with:
|
||||
path: ./public
|
||||
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v3
|
||||
```
|
||||
|
||||
4. **Enable GitHub Pages**:
|
||||
- Go to repository **Settings** → **Pages**
|
||||
- **Source**: GitHub Actions
|
||||
- Save
|
||||
|
||||
5. **Push and Deploy**:
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Deploy to GitHub Pages"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
### Cloudflare Pages
|
||||
|
||||
Fast, global CDN with automatic deployments.
|
||||
|
||||
#### Deploy to Cloudflare Pages
|
||||
|
||||
1. **Connect Repository**:
|
||||
- Visit [pages.cloudflare.com](https://pages.cloudflare.com)
|
||||
- Click "Create a project"
|
||||
- Connect your Git account
|
||||
- Select repository
|
||||
|
||||
2. **Configure Build**:
|
||||
- **Framework preset**: Hugo
|
||||
- **Build command**: `hugo --minify`
|
||||
- **Build output directory**: `public`
|
||||
- **Root directory**: Leave blank
|
||||
|
||||
3. **Environment Variables**:
|
||||
```
|
||||
HUGO_VERSION=0.120.0
|
||||
```
|
||||
|
||||
4. **Deploy**: Click "Save and Deploy"
|
||||
|
||||
#### Custom Domain
|
||||
|
||||
1. Go to project → **Custom domains**
|
||||
2. Add your domain
|
||||
3. Configure DNS (Cloudflare handles this automatically)
|
||||
4. SSL/TLS is automatic
|
||||
|
||||
### AWS S3 + CloudFront
|
||||
|
||||
Enterprise-grade hosting with AWS infrastructure.
|
||||
|
||||
#### S3 Setup
|
||||
|
||||
1. **Create S3 Bucket**:
|
||||
```bash
|
||||
aws s3 mb s3://your-bucket-name --region us-east-1
|
||||
```
|
||||
|
||||
2. **Enable Static Website Hosting**:
|
||||
```bash
|
||||
aws s3 website s3://your-bucket-name \
|
||||
--index-document index.html \
|
||||
--error-document 404.html
|
||||
```
|
||||
|
||||
3. **Set Bucket Policy**:
|
||||
|
||||
Create `bucket-policy.json`:
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "PublicReadGetObject",
|
||||
"Effect": "Allow",
|
||||
"Principal": "*",
|
||||
"Action": "s3:GetObject",
|
||||
"Resource": "arn:aws:s3:::your-bucket-name/*"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Apply:
|
||||
```bash
|
||||
aws s3api put-bucket-policy \
|
||||
--bucket your-bucket-name \
|
||||
--policy file://bucket-policy.json
|
||||
```
|
||||
|
||||
4. **Deploy Site**:
|
||||
```bash
|
||||
hugo --minify
|
||||
aws s3 sync public/ s3://your-bucket-name --delete
|
||||
```
|
||||
|
||||
#### CloudFront Setup
|
||||
|
||||
1. **Create Distribution**:
|
||||
- Origin: Your S3 bucket
|
||||
- Viewer protocol: Redirect HTTP to HTTPS
|
||||
- Price class: Choose based on needs
|
||||
- Alternate domain names: your-domain.com
|
||||
- SSL certificate: Request from ACM
|
||||
|
||||
2. **Configure DNS**:
|
||||
- Add CNAME record pointing to CloudFront distribution
|
||||
|
||||
3. **Invalidate Cache After Deployment**:
|
||||
```bash
|
||||
aws cloudfront create-invalidation \
|
||||
--distribution-id YOUR_DISTRIBUTION_ID \
|
||||
--paths "/*"
|
||||
```
|
||||
|
||||
#### Deployment Script
|
||||
|
||||
Create `deploy.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Build site
|
||||
echo "Building site..."
|
||||
hugo --minify
|
||||
|
||||
# Sync to S3
|
||||
echo "Uploading to S3..."
|
||||
aws s3 sync public/ s3://your-bucket-name \
|
||||
--delete \
|
||||
--cache-control "max-age=3600"
|
||||
|
||||
# Invalidate CloudFront cache
|
||||
echo "Invalidating CloudFront cache..."
|
||||
aws cloudfront create-invalidation \
|
||||
--distribution-id YOUR_DISTRIBUTION_ID \
|
||||
--paths "/*"
|
||||
|
||||
echo "Deployment complete!"
|
||||
```
|
||||
|
||||
Make executable:
|
||||
```bash
|
||||
chmod +x deploy.sh
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
## Custom Server Deployment
|
||||
|
||||
### Nginx
|
||||
|
||||
1. **Build Site**:
|
||||
```bash
|
||||
hugo --minify
|
||||
```
|
||||
|
||||
2. **Upload to Server**:
|
||||
```bash
|
||||
rsync -avz --delete public/ user@server:/var/www/html/
|
||||
```
|
||||
|
||||
3. **Nginx Configuration**:
|
||||
|
||||
`/etc/nginx/sites-available/yoursite`:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name yourdomain.com www.yourdomain.com;
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name yourdomain.com www.yourdomain.com;
|
||||
|
||||
ssl_certificate /path/to/cert.pem;
|
||||
ssl_certificate_key /path/to/key.pem;
|
||||
|
||||
root /var/www/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# Cache static assets
|
||||
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options "DENY" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
}
|
||||
```
|
||||
|
||||
4. **Enable Site**:
|
||||
```bash
|
||||
sudo ln -s /etc/nginx/sites-available/yoursite /etc/nginx/sites-enabled/
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### Apache
|
||||
|
||||
**Apache Configuration**:
|
||||
|
||||
`/etc/apache2/sites-available/yoursite.conf`:
|
||||
|
||||
```apache
|
||||
<VirtualHost *:80>
|
||||
ServerName yourdomain.com
|
||||
ServerAlias www.yourdomain.com
|
||||
Redirect permanent / https://yourdomain.com/
|
||||
</VirtualHost>
|
||||
|
||||
<VirtualHost *:443>
|
||||
ServerName yourdomain.com
|
||||
ServerAlias www.yourdomain.com
|
||||
|
||||
DocumentRoot /var/www/html
|
||||
|
||||
SSLEngine on
|
||||
SSLCertificateFile /path/to/cert.pem
|
||||
SSLCertificateKeyFile /path/to/key.pem
|
||||
|
||||
<Directory /var/www/html>
|
||||
Options -Indexes +FollowSymLinks
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
# Cache static files
|
||||
<FilesMatch "\.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2)$">
|
||||
Header set Cache-Control "max-age=31536000, public, immutable"
|
||||
</FilesMatch>
|
||||
|
||||
# Compression
|
||||
<IfModule mod_deflate.c>
|
||||
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/javascript
|
||||
</IfModule>
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### Common Variables
|
||||
|
||||
```bash
|
||||
# Hugo version
|
||||
HUGO_VERSION=0.120.0
|
||||
|
||||
# Environment
|
||||
HUGO_ENV=production
|
||||
|
||||
# Enable Git info
|
||||
HUGO_ENABLEGITINFO=true
|
||||
|
||||
# Google Analytics
|
||||
HUGO_GOOGLE_ANALYTICS=G-XXXXXXXXXX
|
||||
|
||||
# Google Tag Manager
|
||||
HUGO_GOOGLE_TAG_MANAGER=GTM-XXXXXXX
|
||||
```
|
||||
|
||||
### Platform-Specific
|
||||
|
||||
**Netlify** - Set in UI or `netlify.toml`
|
||||
**Vercel** - Set in UI or `vercel.json`
|
||||
**GitHub Actions** - Use secrets
|
||||
**AWS** - Use Parameter Store or Secrets Manager
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Build Optimization
|
||||
|
||||
1. **Minify Output**:
|
||||
```bash
|
||||
hugo --minify
|
||||
```
|
||||
|
||||
2. **Enable Caching**:
|
||||
```toml
|
||||
[caches]
|
||||
[caches.images]
|
||||
dir = ":resourceDir/_gen"
|
||||
maxAge = "1440h"
|
||||
```
|
||||
|
||||
3. **Optimize Images**:
|
||||
- Compress before uploading
|
||||
- Use WebP format
|
||||
- Implement lazy loading
|
||||
|
||||
### CDN Configuration
|
||||
|
||||
**Cache Headers**:
|
||||
```nginx
|
||||
# Static assets - 1 year
|
||||
location ~* \.(jpg|png|css|js|woff2)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# HTML - short cache
|
||||
location ~* \.html$ {
|
||||
expires 1h;
|
||||
add_header Cache-Control "public, must-revalidate";
|
||||
}
|
||||
```
|
||||
|
||||
### Compression
|
||||
|
||||
Enable gzip/brotli compression on server or CDN.
|
||||
|
||||
**Nginx**:
|
||||
```nginx
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript;
|
||||
gzip_min_length 1000;
|
||||
```
|
||||
|
||||
### Performance Checklist
|
||||
|
||||
- [ ] Enable minification
|
||||
- [ ] Optimize images (compress, WebP)
|
||||
- [ ] Use CDN for static assets
|
||||
- [ ] Enable HTTP/2
|
||||
- [ ] Configure caching headers
|
||||
- [ ] Enable gzip/brotli compression
|
||||
- [ ] Lazy load images
|
||||
- [ ] Minimize CSS/JS
|
||||
- [ ] Use resource hints (preload, prefetch)
|
||||
- [ ] Test with Lighthouse/PageSpeed
|
||||
|
||||
## CI/CD Setup
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
Already covered in [GitHub Pages](#github-pages) section.
|
||||
|
||||
### GitLab CI/CD
|
||||
|
||||
`.gitlab-ci.yml`:
|
||||
|
||||
```yaml
|
||||
image: registry.gitlab.com/pages/hugo/hugo_extended:latest
|
||||
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
|
||||
pages:
|
||||
script:
|
||||
- cp themes/chill-theme/package.json .
|
||||
- cp themes/chill-theme/postcss.config.js .
|
||||
- cp themes/chill-theme/tailwind.config.copy.js ./tailwind.config.js
|
||||
- npm install
|
||||
- hugo --minify
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
only:
|
||||
- main
|
||||
```
|
||||
|
||||
### CircleCI
|
||||
|
||||
`.circleci/config.yml`:
|
||||
|
||||
```yaml
|
||||
version: 2.1
|
||||
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: cibuilds/hugo:latest
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Install theme dependencies
|
||||
command: |
|
||||
cp themes/chill-theme/package.json .
|
||||
cp themes/chill-theme/postcss.config.js .
|
||||
cp themes/chill-theme/tailwind.config.copy.js ./tailwind.config.js
|
||||
npm install
|
||||
- run:
|
||||
name: Build site
|
||||
command: hugo --minify
|
||||
- run:
|
||||
name: Deploy
|
||||
command: |
|
||||
# Your deployment command
|
||||
```
|
||||
|
||||
## Post-Deployment
|
||||
|
||||
### Verification
|
||||
|
||||
1. **Check Site Loads**: Visit your domain
|
||||
2. **Test Navigation**: Click through all pages
|
||||
3. **Verify Assets**: Images, CSS, JS loading
|
||||
4. **Check Forms**: Test contact/signup forms
|
||||
5. **Test Mobile**: Responsive design working
|
||||
6. **Check Analytics**: Tracking installed correctly
|
||||
7. **SSL Certificate**: HTTPS working
|
||||
8. **Performance**: Run Lighthouse audit
|
||||
|
||||
### Monitoring
|
||||
|
||||
- **Uptime Monitoring**: UptimeRobot, Pingdom
|
||||
- **Analytics**: Google Analytics, Plausible
|
||||
- **Error Tracking**: Sentry, Rollbar
|
||||
- **Performance**: Lighthouse CI, SpeedCurve
|
||||
|
||||
### Maintenance
|
||||
|
||||
1. **Regular Updates**: Keep Hugo and dependencies updated
|
||||
2. **Content Review**: Update outdated content
|
||||
3. **Backup**: Regular backups of content and config
|
||||
4. **Security**: Monitor for vulnerabilities
|
||||
5. **Performance**: Regular performance audits
|
||||
|
||||
## Troubleshooting Deployment
|
||||
|
||||
### Build Fails
|
||||
|
||||
**Problem**: Build fails with errors
|
||||
|
||||
**Solutions**:
|
||||
- Check Hugo version matches local
|
||||
- Verify all dependencies installed
|
||||
- Check for syntax errors in config
|
||||
- Review build logs for specific errors
|
||||
|
||||
### Assets Not Loading
|
||||
|
||||
**Problem**: CSS/JS/Images not loading
|
||||
|
||||
**Solutions**:
|
||||
- Verify `baseURL` is correct
|
||||
- Check asset paths are absolute (`/images/...`)
|
||||
- Clear browser cache
|
||||
- Check CDN/server configuration
|
||||
|
||||
### 404 Errors
|
||||
|
||||
**Problem**: Pages return 404
|
||||
|
||||
**Solutions**:
|
||||
- Verify content files exist
|
||||
- Check front matter is correct
|
||||
- Ensure `draft: false`
|
||||
- Check URL structure
|
||||
|
||||
### Slow Build Times
|
||||
|
||||
**Problem**: Builds taking too long
|
||||
|
||||
**Solutions**:
|
||||
- Enable caching
|
||||
- Optimize images before build
|
||||
- Remove unused content
|
||||
- Check for infinite loops in templates
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [INSTALLATION.md](INSTALLATION.md) - Installation guide
|
||||
- [CONFIGURATION.md](CONFIGURATION.md) - Configuration options
|
||||
- [TROUBLESHOOTING.md](TROUBLESHOOTING.md) - Common issues
|
||||
- [Performance Optimization](https://gohugo.io/troubleshooting/build-performance/)
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Netlify Docs](https://docs.netlify.com/)
|
||||
- [Vercel Docs](https://vercel.com/docs)
|
||||
- [GitHub Pages Docs](https://docs.github.com/en/pages)
|
||||
- [Cloudflare Pages Docs](https://developers.cloudflare.com/pages)
|
||||
- [AWS S3 Static Hosting](https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteHosting.html)
|
||||
@@ -0,0 +1,644 @@
|
||||
# Installation Guide
|
||||
|
||||
Complete guide to installing and setting up the Hugo Saasify Theme for your SaaS website.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Installation Methods](#installation-methods)
|
||||
- [Method 1: New Site](#method-1-new-site)
|
||||
- [Method 2: Existing Site](#method-2-existing-site)
|
||||
- [Method 3: Manual Installation](#method-3-manual-installation)
|
||||
- [Initial Configuration](#initial-configuration)
|
||||
- [Verifying Installation](#verifying-installation)
|
||||
- [Next Steps](#next-steps)
|
||||
- [Updating the Theme](#updating-the-theme)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before installing the Hugo Saasify Theme, ensure you have the following installed on your system:
|
||||
|
||||
### Required Software
|
||||
|
||||
1. **Hugo Extended** (v0.80.0 or later)
|
||||
- The theme requires Hugo Extended edition for Tailwind CSS processing
|
||||
- Download from [Hugo Releases](https://github.com/gohugoio/hugo/releases)
|
||||
- Verify installation: `hugo version`
|
||||
- Expected output should include "extended"
|
||||
|
||||
2. **Git** (latest version recommended)
|
||||
- Required for theme installation and updates
|
||||
- Download from [git-scm.com](https://git-scm.com/)
|
||||
- Verify installation: `git --version`
|
||||
|
||||
3. **Node.js and npm** (v14.0.0 or later)
|
||||
- Required for Tailwind CSS compilation
|
||||
- Download from [nodejs.org](https://nodejs.org/)
|
||||
- Verify installation: `node --version` and `npm --version`
|
||||
|
||||
### System Requirements
|
||||
|
||||
- Operating System: Windows, macOS, or Linux
|
||||
- Disk Space: At least 100MB free
|
||||
- Internet Connection: Required for initial setup and dependencies
|
||||
|
||||
### Recommended Tools
|
||||
|
||||
- Code editor (VS Code, Sublime Text, or similar)
|
||||
- Terminal/Command line familiarity
|
||||
- Basic understanding of Hugo and Markdown
|
||||
|
||||
## Installation Methods
|
||||
|
||||
Choose the installation method that best fits your use case.
|
||||
|
||||
### Method 1: New Site
|
||||
|
||||
This is the recommended method if you're starting a new project from scratch.
|
||||
|
||||
#### Step 1: Create a New Hugo Site
|
||||
|
||||
```bash
|
||||
# Create a new Hugo site
|
||||
hugo new site my-saas-website
|
||||
|
||||
# Navigate into the new site directory
|
||||
cd my-saas-website
|
||||
```
|
||||
|
||||
#### Step 2: Initialize Git Repository
|
||||
|
||||
```bash
|
||||
# Initialize git repository
|
||||
git init
|
||||
|
||||
# Create initial commit
|
||||
git add .
|
||||
git commit -m "Initial commit"
|
||||
```
|
||||
|
||||
#### Step 3: Add the Theme as a Git Submodule
|
||||
|
||||
```bash
|
||||
# Add theme as submodule
|
||||
git submodule add https://github.com/chaoming/chill-theme.git themes/chill-theme
|
||||
|
||||
# Update submodule
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
#### Step 4: Example Site (Optional)
|
||||
|
||||
The theme comes with a fully functional example site that demonstrates its features and capabilities. You can use this as a reference when building your own site.
|
||||
|
||||
##### Using the Example Site
|
||||
|
||||
The example site provides a great starting point to understand how to:
|
||||
|
||||
- Structure your content
|
||||
- Use different page layouts
|
||||
- Configure navigation menus
|
||||
- Set up site parameters
|
||||
- Implement common SaaS website features
|
||||
|
||||
1. Copy the example site content:
|
||||
|
||||
```bash
|
||||
cp -r themes/chill-theme/exampleSite/* .
|
||||
```
|
||||
|
||||
The example site includes:
|
||||
|
||||
- Complete content structure with sample pages
|
||||
- Blog posts with various layouts
|
||||
- Feature pages
|
||||
- Career/Jobs section
|
||||
- Pricing page
|
||||
- Company information page
|
||||
- Properly configured hugo.toml
|
||||
|
||||
#### Step 5: Install Dependencies
|
||||
|
||||
```bash
|
||||
# Copy package.json and other config files to your site root
|
||||
cp themes/chill-theme/package.json .
|
||||
cp themes/chill-theme/postcss.config.js .
|
||||
cp themes/chill-theme/tailwind.config.copy.js ./tailwind.config.js
|
||||
```
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
```
|
||||
|
||||
#### Step 6: Set the theme in hugo.toml
|
||||
|
||||
Open your `hugo.toml` and check that the theme is correctly set:
|
||||
|
||||
```toml
|
||||
# Theme Configuration
|
||||
theme = "chill-theme"
|
||||
```
|
||||
|
||||
#### Step 7: Start Development Server
|
||||
|
||||
```bash
|
||||
# Start development server (builds TailwindCSS and runs Hugo server)
|
||||
npm run start
|
||||
|
||||
# Your site will be available at http://localhost:1313
|
||||
```
|
||||
|
||||
### Method 2: Existing Site
|
||||
|
||||
If you already have a Hugo site and want to add the Saasify theme.
|
||||
|
||||
#### Step 1: Add Theme as Submodule
|
||||
|
||||
```bash
|
||||
# From your site root directory
|
||||
git submodule add https://github.com/chaoming/chill-theme.git themes/chill-theme
|
||||
|
||||
# Update submodule
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
#### Step 2: Update Configuration
|
||||
|
||||
Add or update the following in your `hugo.toml`:
|
||||
|
||||
```toml
|
||||
theme = "chill-theme"
|
||||
|
||||
# Required Features
|
||||
pygmentsCodeFences = true
|
||||
pygmentsUseClasses = true
|
||||
enableEmoji = true
|
||||
enableGitInfo = true
|
||||
|
||||
# Required Module Configuration
|
||||
[module]
|
||||
[module.hugoVersion]
|
||||
extended = true
|
||||
min = "0.80.0"
|
||||
|
||||
# Required Build Configuration
|
||||
[build]
|
||||
writeStats = true
|
||||
|
||||
# Required Markup Configuration
|
||||
[markup]
|
||||
[markup.highlight]
|
||||
noClasses = false
|
||||
lineNos = true
|
||||
codeFences = true
|
||||
[markup.goldmark.renderer]
|
||||
unsafe = true
|
||||
[markup.tableOfContents]
|
||||
endLevel = 3
|
||||
ordered = false
|
||||
startLevel = 2
|
||||
```
|
||||
|
||||
#### Step 3: Install Theme Dependencies
|
||||
|
||||
```bash
|
||||
# Copy package.json and other config files to your site root
|
||||
cp themes/chill-theme/package.json .
|
||||
cp themes/chill-theme/postcss.config.js .
|
||||
cp themes/chill-theme/tailwind.config.copy.js ./tailwind.config.js
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
```
|
||||
|
||||
#### Step 4: Configure Theme Settings
|
||||
|
||||
Copy relevant configuration from the example site:
|
||||
|
||||
```bash
|
||||
# View example configuration for reference
|
||||
cat themes/chill-theme/exampleSite/hugo.toml
|
||||
```
|
||||
|
||||
Merge the configuration settings into your existing `hugo.toml`. See [CONFIGURATION.md](CONFIGURATION.md) for detailed options.
|
||||
|
||||
#### Step 5: Test the Theme
|
||||
|
||||
```bash
|
||||
# Start development server
|
||||
npm run start
|
||||
```
|
||||
|
||||
### Method 3: Manual Installation
|
||||
|
||||
For users who prefer not to use Git submodules or need more control over the installation.
|
||||
|
||||
#### Step 1: Download Theme
|
||||
|
||||
```bash
|
||||
# Download and extract theme
|
||||
curl -L https://github.com/chaoming/chill-theme/archive/refs/heads/main.zip -o theme.zip
|
||||
unzip theme.zip
|
||||
mv chill-theme-main themes/chill-theme
|
||||
rm theme.zip
|
||||
```
|
||||
|
||||
Alternatively, download the ZIP file from GitHub and extract it manually to `themes/chill-theme`.
|
||||
|
||||
#### Step 2: Install Dependencies
|
||||
|
||||
```bash
|
||||
# Copy package.json and other config files to your site root
|
||||
cp themes/chill-theme/package.json .
|
||||
cp themes/chill-theme/postcss.config.js .
|
||||
cp themes/chill-theme/tailwind.config.copy.js ./tailwind.config.js
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
```
|
||||
|
||||
#### Step 3: Configure Hugo
|
||||
|
||||
Update your `hugo.toml` to reference the theme:
|
||||
|
||||
```toml
|
||||
theme = "chill-theme"
|
||||
```
|
||||
|
||||
Add all required configuration settings from the example site.
|
||||
|
||||
#### Step 4: Verify Installation
|
||||
|
||||
```bash
|
||||
# Check theme is recognized
|
||||
hugo config
|
||||
|
||||
# Start development server
|
||||
npm run start
|
||||
```
|
||||
|
||||
## Initial Configuration
|
||||
|
||||
After installing the theme, configure the essential settings.
|
||||
|
||||
### Basic Configuration
|
||||
|
||||
Edit your `hugo.toml` file:
|
||||
|
||||
```toml
|
||||
# Basic Configuration
|
||||
baseURL = "/"
|
||||
languageCode = "en-us"
|
||||
title = "Your Site Title"
|
||||
theme = "chill-theme"
|
||||
|
||||
# Required Features
|
||||
pygmentsCodeFences = true # Enable syntax highlighting
|
||||
pygmentsUseClasses = true
|
||||
enableEmoji = true # Enable emoji support
|
||||
enableGitInfo = true # Enable Git info for lastmod
|
||||
|
||||
# Required Module Configuration
|
||||
[module]
|
||||
[module.hugoVersion]
|
||||
extended = true
|
||||
min = "0.80.0"
|
||||
|
||||
# Required Build Configuration
|
||||
[build]
|
||||
writeStats = true # Required for TailwindCSS
|
||||
|
||||
# Required Markup Configuration
|
||||
[markup]
|
||||
[markup.highlight]
|
||||
noClasses = false
|
||||
lineNos = true
|
||||
codeFences = true
|
||||
[markup.goldmark.renderer]
|
||||
unsafe = true # Allow HTML in markdown
|
||||
[markup.tableOfContents]
|
||||
endLevel = 3
|
||||
ordered = false
|
||||
startLevel = 2
|
||||
|
||||
# Theme Parameters
|
||||
[params]
|
||||
description = "Your site description"
|
||||
author = "Your Name"
|
||||
logo = "/images/logo.svg"
|
||||
```
|
||||
|
||||
### Tailwind CSS Setup
|
||||
|
||||
The theme uses Tailwind CSS for styling. The build process is integrated into Hugo.
|
||||
|
||||
During installation, you should have copied the Tailwind configuration file:
|
||||
|
||||
- `tailwind.config.js` - Copied from `themes/chill-theme/tailwind.config.copy.js` to your site root
|
||||
- `postcss.config.js` - PostCSS configuration in your site root
|
||||
- Dependencies installed via `npm install`
|
||||
|
||||
The `npm run start` command automatically watches and compiles Tailwind CSS during development.
|
||||
|
||||
### Menu Configuration
|
||||
|
||||
Add your navigation menu to `hugo.toml`:
|
||||
|
||||
```toml
|
||||
[menu]
|
||||
[[menu.main]]
|
||||
name = "Features"
|
||||
weight = 1
|
||||
[menu.main.params]
|
||||
has_submenu = true
|
||||
submenu = [
|
||||
{ name = "Feature 1", url = "/features/feature-1/" },
|
||||
{ name = "Feature 2", url = "/features/feature-2/" }
|
||||
]
|
||||
|
||||
[[menu.main]]
|
||||
name = "Pricing"
|
||||
url = "/pricing"
|
||||
weight = 2
|
||||
|
||||
[[menu.main]]
|
||||
name = "Blog"
|
||||
url = "/blog"
|
||||
weight = 3
|
||||
```
|
||||
|
||||
See [CONFIGURATION.md](CONFIGURATION.md) for complete menu options.
|
||||
|
||||
## Verifying Installation
|
||||
|
||||
### Check Hugo Version
|
||||
|
||||
```bash
|
||||
hugo version
|
||||
```
|
||||
|
||||
Expected output should include "extended" and version 0.80.0 or higher.
|
||||
|
||||
### Check Theme Files
|
||||
|
||||
```bash
|
||||
# Verify theme directory structure
|
||||
ls -la themes/chill-theme/
|
||||
|
||||
# Should show:
|
||||
# - layouts/
|
||||
# - assets/
|
||||
# - static/
|
||||
# - exampleSite/
|
||||
# - package.json
|
||||
# - tailwind.config.js
|
||||
```
|
||||
|
||||
### Test Development Server
|
||||
|
||||
```bash
|
||||
# Start server
|
||||
npm run start
|
||||
|
||||
# Check for errors in terminal
|
||||
# Visit http://localhost:1313 in browser
|
||||
```
|
||||
|
||||
### Verify Build Output
|
||||
|
||||
```bash
|
||||
# Build site
|
||||
hugo
|
||||
|
||||
# Check public directory was created
|
||||
ls public/
|
||||
|
||||
# Should contain:
|
||||
# - index.html
|
||||
# - css/
|
||||
# - js/
|
||||
# - images/
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Starting the Development Server
|
||||
|
||||
To start the development server with live reload and TailwindCSS compilation:
|
||||
|
||||
```bash
|
||||
npm run start
|
||||
```
|
||||
|
||||
This will:
|
||||
|
||||
- Watch for changes in your TailwindCSS styles
|
||||
- Run the Hugo development server
|
||||
- Automatically rebuild when changes are detected
|
||||
- Serve your site at <http://localhost:1313>
|
||||
|
||||
### Building for Production
|
||||
|
||||
To build your site for production:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
This will:
|
||||
|
||||
- Build and minify your TailwindCSS styles
|
||||
- Generate minified Hugo site in the `public` directory
|
||||
|
||||
## Next Steps
|
||||
|
||||
After successful installation:
|
||||
|
||||
1. **Customize Configuration**: Review [CONFIGURATION.md](CONFIGURATION.md) for all available options
|
||||
2. **Create Content**: Learn about content creation in [CONTENT-CREATION.md](CONTENT-CREATION.md)
|
||||
3. **Customize Styling**: See [STYLING.md](STYLING.md) for theme customization
|
||||
4. **Add Pages**: Use available layouts documented in [LAYOUTS.md](LAYOUTS.md)
|
||||
5. **Use Shortcodes**: Explore components in [SHORTCODES.md](SHORTCODES.md)
|
||||
6. **Deploy**: Follow deployment guides in [DEPLOYMENT.md](DEPLOYMENT.md)
|
||||
|
||||
## Updating the Theme
|
||||
|
||||
### For Git Submodule Installations
|
||||
|
||||
```bash
|
||||
# Update to latest version
|
||||
git submodule update --remote themes/chill-theme
|
||||
|
||||
# If there are npm dependency updates, copy the updated files
|
||||
cp themes/chill-theme/package.json .
|
||||
cp themes/chill-theme/postcss.config.js .
|
||||
cp themes/chill-theme/tailwind.config.copy.js ./tailwind.config.js
|
||||
npm install
|
||||
|
||||
# Commit the update
|
||||
git add themes/chill-theme
|
||||
git commit -m "Update chill-theme"
|
||||
```
|
||||
|
||||
### For Manual Installations
|
||||
|
||||
```bash
|
||||
# Backup your current theme (if you made custom changes)
|
||||
cp -r themes/chill-theme themes/chill-theme-backup
|
||||
|
||||
# Download latest version
|
||||
curl -L https://github.com/chaoming/chill-theme/archive/refs/heads/main.zip -o theme.zip
|
||||
unzip theme.zip
|
||||
rm -rf themes/chill-theme
|
||||
mv chill-theme-main themes/chill-theme
|
||||
rm theme.zip
|
||||
|
||||
# Copy updated config files and install dependencies
|
||||
cp themes/chill-theme/package.json .
|
||||
cp themes/chill-theme/postcss.config.js .
|
||||
cp themes/chill-theme/tailwind.config.copy.js ./tailwind.config.js
|
||||
npm install
|
||||
```
|
||||
|
||||
### Update Best Practices
|
||||
|
||||
1. **Always backup** before updating
|
||||
2. **Review changelog** for breaking changes
|
||||
3. **Test locally** before deploying updates
|
||||
4. **Check configuration** for new options
|
||||
5. **Update dependencies** after theme updates
|
||||
|
||||
### Version Pinning
|
||||
|
||||
To pin to a specific version using Git submodule:
|
||||
|
||||
```bash
|
||||
cd themes/chill-theme
|
||||
git checkout v1.0.0 # Replace with desired version tag
|
||||
cd ../..
|
||||
git add themes/chill-theme
|
||||
git commit -m "Pin theme to v1.0.0"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Theme Not Found
|
||||
|
||||
**Problem**: Hugo can't find the theme
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Check theme directory exists
|
||||
ls themes/
|
||||
|
||||
# Verify theme name in hugo.toml matches directory name
|
||||
grep "^theme" hugo.toml
|
||||
|
||||
# Should output: theme = "chill-theme"
|
||||
```
|
||||
|
||||
### Extended Version Error
|
||||
|
||||
**Problem**: Error about Hugo Extended being required
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Check Hugo version includes "extended"
|
||||
hugo version
|
||||
|
||||
# If not extended, download extended version from:
|
||||
# https://github.com/gohugoio/hugo/releases
|
||||
```
|
||||
|
||||
### CSS Not Loading
|
||||
|
||||
**Problem**: Site loads without styling
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Ensure build stats are enabled in hugo.toml
|
||||
[build]
|
||||
writeStats = true
|
||||
|
||||
# Ensure theme dependencies are installed in site root
|
||||
cp themes/chill-theme/package.json .
|
||||
cp themes/chill-theme/postcss.config.js .
|
||||
cp themes/chill-theme/tailwind.config.copy.js ./tailwind.config.js
|
||||
npm install
|
||||
|
||||
# Clear Hugo cache
|
||||
hugo --gc
|
||||
|
||||
# Rebuild and start server
|
||||
npm run start
|
||||
```
|
||||
|
||||
### Submodule Empty
|
||||
|
||||
**Problem**: Theme directory exists but is empty
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Initialize and update submodules
|
||||
git submodule init
|
||||
git submodule update --recursive
|
||||
|
||||
# If still empty, remove and re-add
|
||||
git submodule deinit -f themes/chill-theme
|
||||
rm -rf .git/modules/themes/chill-theme
|
||||
git rm -f themes/chill-theme
|
||||
git submodule add https://github.com/chaoming/chill-theme.git themes/chill-theme
|
||||
```
|
||||
|
||||
### npm Dependencies Error
|
||||
|
||||
**Problem**: npm install fails
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Clear npm cache
|
||||
npm cache clean --force
|
||||
|
||||
# Delete node_modules and reinstall in site root
|
||||
rm -rf node_modules package-lock.json
|
||||
npm install
|
||||
```
|
||||
|
||||
### Port Already in Use
|
||||
|
||||
**Problem**: Hugo server won't start due to port conflict
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Use different port (modify package.json start script to add --port flag)
|
||||
# Or find and kill process using port 1313
|
||||
lsof -ti:1313 | xargs kill -9 # macOS/Linux
|
||||
# For Windows, use: netstat -ano | findstr :1313
|
||||
|
||||
# Then restart
|
||||
npm run start
|
||||
```
|
||||
|
||||
For more troubleshooting help, see [TROUBLESHOOTING.md](TROUBLESHOOTING.md) or visit the [GitHub Issues](https://github.com/chaoming/chill-theme/issues) page.
|
||||
|
||||
## Getting Help
|
||||
|
||||
If you encounter issues not covered in this guide:
|
||||
|
||||
1. Check [TROUBLESHOOTING.md](TROUBLESHOOTING.md)
|
||||
2. Review [example site configuration](../exampleSite/)
|
||||
3. Search [GitHub Issues](https://github.com/chaoming/chill-theme/issues)
|
||||
4. Create a new issue with:
|
||||
- Hugo version (`hugo version`)
|
||||
- Operating system
|
||||
- Error messages
|
||||
- Steps to reproduce
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Hugo Documentation](https://gohugo.io/documentation/)
|
||||
- [Tailwind CSS Documentation](https://tailwindcss.com/docs)
|
||||
- [Theme Repository](https://github.com/chaoming/chill-theme)
|
||||
- [Demo Site](https://saasify-demo.chaoming.li)
|
||||
@@ -0,0 +1,737 @@
|
||||
# Internationalization (i18n) Guide
|
||||
|
||||
Complete guide for implementing multilingual support in Hugo Saasify Theme.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Configuration](#configuration)
|
||||
- [Language Preference Persistence](#language-preference-persistence)
|
||||
- [Translation Keys](#translation-keys)
|
||||
- [Content Organization](#content-organization)
|
||||
- [Date Formatting](#date-formatting)
|
||||
- [Common Issues](#common-issues)
|
||||
- [Adding a New Language](#adding-a-new-language)
|
||||
|
||||
## Overview
|
||||
|
||||
Hugo Saasify Theme provides full multilingual support with:
|
||||
- Automatic language switcher in the header
|
||||
- Persistent language preference (remembers user's choice)
|
||||
- 40+ translation keys for UI elements
|
||||
- Language-specific content directories
|
||||
- Language-specific menus and parameters
|
||||
- Date format localization
|
||||
- Translated blog sidebar, post navigation, and more
|
||||
|
||||
## Quick Start
|
||||
|
||||
The theme comes with **three fully implemented language examples** in the demo site:
|
||||
- **English** (`en`) - Default language
|
||||
- **Chinese** (`zh-cn`) - Complete translation
|
||||
- **German** (`de`) - Complete translation
|
||||
|
||||
You can use these as references when adding your own languages.
|
||||
|
||||
### Basic Setup
|
||||
|
||||
1. **Configure languages in `hugo.toml`:**
|
||||
|
||||
```toml
|
||||
defaultContentLanguage = "en"
|
||||
|
||||
[languages]
|
||||
[languages.en]
|
||||
languageCode = "en-us"
|
||||
languageName = "English"
|
||||
title = "Your Site"
|
||||
weight = 1
|
||||
contentDir = "content"
|
||||
|
||||
[languages.zh-cn]
|
||||
languageCode = "zh-cn"
|
||||
languageName = "简体中文"
|
||||
title = "Your Site"
|
||||
weight = 2
|
||||
contentDir = "content/zh-cn"
|
||||
```
|
||||
|
||||
**Tip:** Check the demo site's `hugo.toml` for complete English, Chinese, and German configurations you can copy and adapt.
|
||||
|
||||
2. **Copy translation files:**
|
||||
|
||||
```bash
|
||||
# Copy English translations (already included in theme)
|
||||
cp themes/chill-theme/i18n/en.toml i18n/en.toml
|
||||
|
||||
# Copy Chinese example and rename
|
||||
cp themes/chill-theme/docs/zh-cn.toml.example i18n/zh-cn.toml
|
||||
```
|
||||
|
||||
3. **Create language-specific content:**
|
||||
|
||||
```
|
||||
content/
|
||||
├── _index.md # English homepage
|
||||
├── blog/
|
||||
│ └── my-post.md # English blog post
|
||||
└── zh-cn/
|
||||
├── _index.md # Chinese homepage
|
||||
└── blog/
|
||||
└── my-post.md # Chinese blog post
|
||||
```
|
||||
|
||||
4. **Configure language-specific menus:**
|
||||
|
||||
```toml
|
||||
# English menu
|
||||
[[languages.en.menu.main]]
|
||||
name = "Blog"
|
||||
url = "/blog"
|
||||
weight = 1
|
||||
|
||||
# Chinese menu
|
||||
[[languages.zh-cn.menu.main]]
|
||||
name = "博客"
|
||||
url = "/zh-cn/blog"
|
||||
weight = 1
|
||||
```
|
||||
|
||||
The language switcher will automatically appear in the header!
|
||||
|
||||
## Configuration
|
||||
|
||||
### Language Preference Persistence
|
||||
|
||||
**New Feature:** The theme now automatically remembers the user's language preference using browser localStorage. This provides a seamless multilingual experience.
|
||||
|
||||
#### How It Works
|
||||
|
||||
1. **First Visit**: User sees the default language (no redirect)
|
||||
2. **User Selects Language**: When clicking a language in the switcher:
|
||||
- Their preference is saved to localStorage
|
||||
- They navigate to the selected language
|
||||
3. **Return Visits**: On subsequent page loads:
|
||||
- The system checks for a saved preference
|
||||
- If found, automatically redirects to their preferred language
|
||||
- This happens once per session to avoid interfering with manual navigation
|
||||
|
||||
#### User Experience Examples
|
||||
|
||||
**Scenario 1: New User**
|
||||
```
|
||||
1. User lands on https://example.com/ (English, default)
|
||||
2. Clicks "简体中文" in language switcher
|
||||
3. Navigates to https://example.com/zh-cn/
|
||||
4. Preference saved: zh-cn
|
||||
5. Next visit: automatically redirects to Chinese version
|
||||
```
|
||||
|
||||
**Scenario 2: Deep Links**
|
||||
```
|
||||
1. User has preference: zh-cn
|
||||
2. Clicks link to https://example.com/blog/my-post
|
||||
3. Auto-redirects to https://example.com/zh-cn/blog/my-post
|
||||
4. Original path preserved, just language changed
|
||||
```
|
||||
|
||||
**Scenario 3: Manual Navigation**
|
||||
```
|
||||
1. User has preference: zh-cn (currently on Chinese site)
|
||||
2. Types https://example.com/en/contact directly in address bar
|
||||
3. Sees English contact page (no forced redirect)
|
||||
4. Can still use language switcher to change languages
|
||||
```
|
||||
|
||||
#### Technical Details
|
||||
|
||||
- **Storage**: Uses browser `localStorage` with key `hugo_preferred_language`
|
||||
- **Fallback**: Works gracefully without JavaScript (standard links still function)
|
||||
- **Privacy**: Stored locally in user's browser only
|
||||
- **Session Safety**: Uses `sessionStorage` flag to prevent redirect loops
|
||||
- **Progressive Enhancement**: Site works perfectly with JavaScript disabled
|
||||
|
||||
#### Disabling the Feature
|
||||
|
||||
If you want to disable language preference persistence:
|
||||
|
||||
1. Remove the script include from `layouts/_default/baseof.html`:
|
||||
```html
|
||||
<!-- Remove or comment out these lines: -->
|
||||
{{ if .Site.IsMultiLingual }}
|
||||
<script src="{{ "js/language-preference.js" | relURL }}"></script>
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
2. Or delete the file: `static/js/language-preference.js`
|
||||
|
||||
The language switcher will still work; it just won't remember the user's choice.
|
||||
|
||||
#### Automatic Language Detection with VisitorAPI
|
||||
|
||||
**New Feature:** The theme supports automatic language detection using [VisitorAPI](https://visitorapi.com/) to detect the visitor's language based on their location.
|
||||
|
||||
##### How It Works
|
||||
|
||||
1. **Every Page Load (No Stored Preference)**: If the user has no stored language preference:
|
||||
- The system calls VisitorAPI on every page load to detect the visitor's language
|
||||
- If a matching language is available, the user is automatically redirected
|
||||
- The detected language is stored as their preference for future visits
|
||||
2. **After Preference is Stored**: Once a language preference is saved (either from auto-detection or manual selection):
|
||||
- Uses the stored preference (no API call)
|
||||
- Fast redirect based on localStorage
|
||||
3. **Manual Selection**: User can always override by selecting a different language
|
||||
|
||||
##### Setup Instructions
|
||||
|
||||
1. **Sign up for VisitorAPI**:
|
||||
- Visit [visitorapi.com](https://visitorapi.com/) and create a free account
|
||||
- Create a new project to get your Project ID
|
||||
|
||||
2. **Add the Project ID to your configuration**:
|
||||
|
||||
```toml
|
||||
[params]
|
||||
# VisitorAPI Project ID for automatic language detection
|
||||
# Set this to enable auto-detection of visitor's language
|
||||
# If not set, language detection will be disabled
|
||||
visitorapi_pid = "YOUR_PROJECT_ID_HERE"
|
||||
```
|
||||
|
||||
3. **That's it!** The feature is automatically enabled when the Project ID is configured.
|
||||
|
||||
##### How Language Matching Works
|
||||
|
||||
The system uses **dynamic language matching** based on the first two characters of language codes. This means it automatically works for any language you add to Hugo without requiring any code changes.
|
||||
|
||||
**Matching Logic:**
|
||||
|
||||
- VisitorAPI returns language codes like `"en"`, `"zh"`, `"de"`, `"fr"`, `"es"`, `"pt"`, etc.
|
||||
- The system extracts the first 2 characters from the VisitorAPI response
|
||||
- It compares these with the first 2 characters of your Hugo language codes
|
||||
- When they match, the user is redirected to that language
|
||||
|
||||
**Examples:**
|
||||
|
||||
- VisitorAPI returns `"en"` → Matches Hugo language `"en"` ✓
|
||||
- VisitorAPI returns `"zh"` or `"zho"` → Matches Hugo language `"zh-cn"` ✓ (both start with "zh")
|
||||
- VisitorAPI returns `"de"` or `"deu"` → Matches Hugo language `"de"` ✓
|
||||
- VisitorAPI returns `"pt"` or `"por"` → Matches Hugo language `"pt"` or `"pt-br"` ✓
|
||||
- VisitorAPI returns `"es"` or `"spa"` → Matches Hugo language `"es"` ✓
|
||||
- VisitorAPI returns `"fr"` or `"fra"` → Matches Hugo language `"fr"` or `"fr-ca"` ✓
|
||||
|
||||
**Adding a New Language:**
|
||||
|
||||
When you add a new language to your Hugo site, VisitorAPI auto-detection will automatically work for it:
|
||||
|
||||
1. Add the language to your `hugo.toml`:
|
||||
|
||||
```toml
|
||||
[languages.ja]
|
||||
languageCode = "ja-jp"
|
||||
languageName = "日本語"
|
||||
# ... rest of config
|
||||
```
|
||||
|
||||
2. That's it! The system will automatically detect visitors from Japan and redirect them to `/ja/` because:
|
||||
- VisitorAPI will return `"ja"` or `"jpn"` for Japanese visitors
|
||||
- The first 2 characters (`"ja"`) match your Hugo language code `"ja"`
|
||||
- No code changes needed
|
||||
|
||||
**Technical Details:**
|
||||
|
||||
The matching happens in `language-preference.js`:
|
||||
|
||||
```javascript
|
||||
// Extract first 2 characters from VisitorAPI response (e.g., "zh" from "zh" or "zho")
|
||||
var langPrefix = visitorLang.substring(0, 2);
|
||||
|
||||
// Get all available Hugo languages from the language switcher
|
||||
var languageLinks = document.querySelectorAll('.language-switch-link');
|
||||
|
||||
// Compare first 2 characters with each Hugo language
|
||||
for (var j = 0; j < languageLinks.length; j++) {
|
||||
var hugoLang = languageLinks[j].getAttribute('data-lang');
|
||||
var hugoPrefix = hugoLang.substring(0, 2);
|
||||
|
||||
if (langPrefix === hugoPrefix) {
|
||||
// Match found! Redirect to this language
|
||||
detectedLang = hugoLang;
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This approach ensures:
|
||||
- No hardcoded language mappings to maintain
|
||||
- Automatic support for any language you add
|
||||
- Works with both 2-character codes (`"en"`) and extended codes (`"zh-cn"`)
|
||||
- Handles VisitorAPI's various language code formats (ISO 639-1 and ISO 639-2)
|
||||
|
||||
##### Privacy & Performance
|
||||
|
||||
- **API Call**: Called on every page load when no language preference is stored
|
||||
- **Caching**: Once a language is detected and stored, no more API calls are made
|
||||
- **Efficient**: After first detection, uses localStorage for instant redirects
|
||||
- **Fallback**: Works gracefully if API is unavailable
|
||||
- **No Tracking**: VisitorAPI detects language, doesn't track user behavior
|
||||
- **User Control**: Users can clear localStorage to reset and re-detect
|
||||
|
||||
##### Disabling Auto-Detection
|
||||
|
||||
To disable automatic language detection while keeping manual preference persistence:
|
||||
|
||||
1. Simply remove or comment out the `visitorapi_pid` parameter from your `hugo.toml`
|
||||
2. Or set it to an empty string: `visitorapi_pid = ""`
|
||||
|
||||
The language preference system will continue to work; it just won't auto-detect on first visit.
|
||||
|
||||
### Basic Setup
|
||||
|
||||
```toml
|
||||
# Set the default language
|
||||
defaultContentLanguage = "en"
|
||||
|
||||
# Whether to include default language in URL path
|
||||
# false: English at / (example.com/)
|
||||
# true: English at /en/ (example.com/en/)
|
||||
defaultContentLanguageInSubdir = false
|
||||
```
|
||||
|
||||
### Language-Specific Parameters
|
||||
|
||||
Each language can have its own configuration for CTAs, headers, etc:
|
||||
|
||||
```toml
|
||||
[languages.en.params.cta]
|
||||
enable = true
|
||||
title = "Ready to Get Started?"
|
||||
description = "Join companies using our platform"
|
||||
[languages.en.params.cta.primary_button]
|
||||
text = "Get Started Free"
|
||||
url = "/get-started"
|
||||
|
||||
[languages.zh-cn.params.cta]
|
||||
enable = true
|
||||
title = "准备好开始了吗?"
|
||||
description = "加入使用我们平台的公司"
|
||||
[languages.zh-cn.params.cta.primary_button]
|
||||
text = "免费开始"
|
||||
url = "/zh-cn/get-started"
|
||||
```
|
||||
|
||||
### Sidebar Configuration
|
||||
|
||||
**Important:** Do NOT set title/description/text in global sidebar config, as this overrides i18n translations:
|
||||
|
||||
```toml
|
||||
# ❌ DON'T: This prevents translation
|
||||
[params.blog.sidebar.recent]
|
||||
enable = true
|
||||
title = "Recent Articles" # This overrides i18n
|
||||
|
||||
# ✅ DO: Let i18n handle the translations
|
||||
[params.blog.sidebar.recent]
|
||||
enable = true
|
||||
count = 5 # Only set non-text configuration
|
||||
```
|
||||
|
||||
## Translation Keys
|
||||
|
||||
### Complete List
|
||||
|
||||
The theme includes 40+ translation keys. Here are the most important ones:
|
||||
|
||||
#### Blog & Content
|
||||
- `readMore` - "Read More" link text
|
||||
- `readTime` - Reading time suffix
|
||||
- `categories` - Categories heading
|
||||
- `tags` - Tags heading
|
||||
|
||||
#### Blog Post
|
||||
- `tableOfContents` - TOC heading
|
||||
- `minRead` - Reading time text
|
||||
- `previousPost` - Previous navigation
|
||||
- `nextPost` - Next navigation
|
||||
- `dateFormat` - Date format string
|
||||
|
||||
#### Blog Sidebar
|
||||
- `recentArticles` - Recent articles heading
|
||||
- `popularTags` - Popular tags heading
|
||||
- `subscribeNewsletter` - Newsletter heading
|
||||
- `subscribeDescription` - Newsletter description
|
||||
- `emailPlaceholder` - Email input placeholder
|
||||
- `subscribe` - Subscribe button
|
||||
|
||||
#### Navigation
|
||||
- `previous` - Previous page
|
||||
- `next` - Next page
|
||||
- `documentation` - Documentation heading
|
||||
- `language` - Language label
|
||||
|
||||
#### Features & Pricing
|
||||
- `seeItInAction` - Feature demo heading
|
||||
- `popular` - Popular badge
|
||||
- `mostPopular` - Most popular badge
|
||||
- `perMonth` - Pricing suffix
|
||||
|
||||
#### Homepage
|
||||
- `trustedByCompanies` - Company logos heading
|
||||
- `lovedByTeams` - Testimonials heading
|
||||
|
||||
For the complete list with default values, see `themes/chill-theme/i18n/en.toml`
|
||||
|
||||
### Example Translation File
|
||||
|
||||
**i18n/en.toml:**
|
||||
```toml
|
||||
[readMore]
|
||||
other = "Read More"
|
||||
|
||||
[minRead]
|
||||
other = "min read"
|
||||
|
||||
[previousPost]
|
||||
other = "Previous Post"
|
||||
|
||||
[nextPost]
|
||||
other = "Next Post"
|
||||
|
||||
[dateFormat]
|
||||
other = "January 2, 2006"
|
||||
```
|
||||
|
||||
**i18n/zh-cn.toml:**
|
||||
```toml
|
||||
[readMore]
|
||||
other = "阅读更多"
|
||||
|
||||
[minRead]
|
||||
other = "分钟阅读"
|
||||
|
||||
[previousPost]
|
||||
other = "上一篇"
|
||||
|
||||
[nextPost]
|
||||
other = "下一篇"
|
||||
|
||||
[dateFormat]
|
||||
other = "2006年1月2日"
|
||||
```
|
||||
|
||||
## Content Organization
|
||||
|
||||
### Directory Structure
|
||||
|
||||
```
|
||||
content/
|
||||
├── _index.md # English homepage
|
||||
├── blog/
|
||||
│ ├── post-1.md # English blog posts
|
||||
│ └── post-2.md
|
||||
├── features/
|
||||
│ └── performance.md # English feature page
|
||||
└── zh-cn/ # Chinese content
|
||||
├── _index.md # Chinese homepage
|
||||
├── blog/
|
||||
│ ├── post-1.md # Chinese blog posts
|
||||
│ └── post-2.md
|
||||
└── features/
|
||||
└── performance.md # Chinese feature page
|
||||
```
|
||||
|
||||
### Creating Translated Content
|
||||
|
||||
1. **Duplicate the structure** from your default language
|
||||
2. **Translate the content** including front matter
|
||||
3. **Keep the same file names** for better URL consistency
|
||||
|
||||
**Example - English post:**
|
||||
```yaml
|
||||
---
|
||||
title: "Getting Started with Hugo"
|
||||
date: 2024-01-15
|
||||
categories: ["Tutorial"]
|
||||
tags: ["hugo", "web development"]
|
||||
---
|
||||
Content in English...
|
||||
```
|
||||
|
||||
**Example - Chinese post:**
|
||||
```yaml
|
||||
---
|
||||
title: "Hugo入门指南"
|
||||
date: 2024-01-15
|
||||
categories: ["教程"]
|
||||
tags: ["hugo", "网站开发"]
|
||||
---
|
||||
中文内容...
|
||||
```
|
||||
|
||||
## Date Formatting
|
||||
|
||||
The theme uses the `dateFormat` i18n key for locale-specific date formatting:
|
||||
|
||||
```toml
|
||||
# English format
|
||||
[dateFormat]
|
||||
other = "January 2, 2006" # Output: July 20, 2023
|
||||
|
||||
# Chinese format
|
||||
[dateFormat]
|
||||
other = "2006年1月2日" # Output: 2023年7月20日
|
||||
|
||||
# French format example
|
||||
[dateFormat]
|
||||
other = "2 January 2006" # Output: 20 juillet 2023
|
||||
```
|
||||
|
||||
Hugo's date format reference:
|
||||
- `2006` - Year (4 digits)
|
||||
- `06` - Year (2 digits)
|
||||
- `January` - Month (full name)
|
||||
- `Jan` - Month (abbreviated)
|
||||
- `01` - Month (2 digits)
|
||||
- `1` - Month (1-2 digits)
|
||||
- `02` - Day (2 digits)
|
||||
- `2` - Day (1-2 digits)
|
||||
- `Monday` - Weekday (full name)
|
||||
- `Mon` - Weekday (abbreviated)
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Issue: Sidebar Still Showing English
|
||||
|
||||
**Problem:** Blog sidebar shows English text even in Chinese version.
|
||||
|
||||
**Solution:** Remove hardcoded titles from global `[params.blog.sidebar]` configuration. The theme's i18n will handle the translations automatically.
|
||||
|
||||
```toml
|
||||
# Remove these from global config:
|
||||
[params.blog.sidebar.recent]
|
||||
enable = true
|
||||
# title = "Recent Articles" ← Remove this
|
||||
count = 5
|
||||
```
|
||||
|
||||
### Issue: Language Switcher Not Appearing
|
||||
|
||||
**Problem:** Language switcher doesn't show in header.
|
||||
|
||||
**Solution:** Ensure you have defined multiple languages in your `hugo.toml`:
|
||||
|
||||
```toml
|
||||
[languages]
|
||||
[languages.en]
|
||||
# ...
|
||||
[languages.zh-cn]
|
||||
# ...
|
||||
```
|
||||
|
||||
The language switcher automatically appears when 2+ languages are configured.
|
||||
|
||||
### Issue: Wrong Language on Home Link
|
||||
|
||||
**Problem:** Logo/home link goes to wrong language homepage.
|
||||
|
||||
**Solution:** This is already fixed in the theme. The header uses `{{ "/" | relLangURL }}` which automatically links to the correct language homepage.
|
||||
|
||||
## Adding a New Language
|
||||
|
||||
Let's add French as an example.
|
||||
|
||||
### Quick Reference (For Experienced Users)
|
||||
|
||||
If you're familiar with Hugo i18n, here's what you need:
|
||||
|
||||
1. **Config:** `hugo.toml` - Add `languages.fr` section with `languageCode`, `languageName`, `title`, `weight`, `contentDir`
|
||||
2. **Translations:** `i18n/fr.toml` - Copy from `i18n/en.toml` and translate all keys
|
||||
3. **Content:** `content/fr/` - Create directory structure and translate content
|
||||
4. **Menus:** `languages.fr.menu.main` + 3 footer menus
|
||||
5. **Params:** `languages.fr.params` - **Must include**: `cta`, `footer` (with uppercase column titles), `header`, `blog`
|
||||
|
||||
**Critical:** Don't forget the `footer` configuration - it's required for footer to display correctly!
|
||||
|
||||
### Detailed Step-by-Step Guide
|
||||
|
||||
### 1. Add Language Configuration
|
||||
|
||||
```toml
|
||||
[languages.fr]
|
||||
languageCode = "fr-fr"
|
||||
languageName = "Français"
|
||||
title = "Votre Site"
|
||||
weight = 3
|
||||
contentDir = "content/fr"
|
||||
```
|
||||
|
||||
### 2. Create Translation File
|
||||
|
||||
Copy the example and translate:
|
||||
|
||||
```bash
|
||||
cp themes/chill-theme/docs/zh-cn.toml.example i18n/fr.toml
|
||||
```
|
||||
|
||||
Edit `i18n/fr.toml`:
|
||||
```toml
|
||||
[readMore]
|
||||
other = "Lire la suite"
|
||||
|
||||
[minRead]
|
||||
other = "min de lecture"
|
||||
|
||||
[previousPost]
|
||||
other = "Article précédent"
|
||||
|
||||
[nextPost]
|
||||
other = "Article suivant"
|
||||
|
||||
[dateFormat]
|
||||
other = "2 January 2006"
|
||||
|
||||
[recentArticles]
|
||||
other = "Articles récents"
|
||||
|
||||
[categories]
|
||||
other = "Catégories"
|
||||
|
||||
[popularTags]
|
||||
other = "Tags populaires"
|
||||
|
||||
# ... translate all keys
|
||||
```
|
||||
|
||||
### 3. Create French Content
|
||||
|
||||
```
|
||||
content/fr/
|
||||
├── _index.md
|
||||
├── blog/
|
||||
└── features/
|
||||
```
|
||||
|
||||
### 4. Configure French Menu
|
||||
|
||||
```toml
|
||||
[[languages.fr.menu.main]]
|
||||
name = "Fonctionnalités"
|
||||
url = "/fr/features"
|
||||
weight = 1
|
||||
|
||||
[[languages.fr.menu.main]]
|
||||
name = "Blog"
|
||||
url = "/fr/blog"
|
||||
weight = 2
|
||||
```
|
||||
|
||||
### 5. Language-Specific Parameters (Required)
|
||||
|
||||
Configure language-specific parameters for your new language. **Important:** These parameters are required for proper navigation and UI display.
|
||||
|
||||
```toml
|
||||
# French language specific params
|
||||
[languages.fr.params]
|
||||
# Global CTA Configuration
|
||||
[languages.fr.params.cta]
|
||||
enable = true
|
||||
title = "Prêt à commencer?"
|
||||
description = "Rejoignez les entreprises qui utilisent notre plateforme"
|
||||
gradient_from = "#2563eb"
|
||||
gradient_to = "#7c3aed"
|
||||
gradient_angle = 30
|
||||
[languages.fr.params.cta.primary_button]
|
||||
text = "Commencer"
|
||||
url = "/fr/get-started"
|
||||
[languages.fr.params.cta.secondary_button]
|
||||
text = "Démo"
|
||||
url = "/fr/demo"
|
||||
|
||||
# Footer Configuration (IMPORTANT - Required for footer to display correctly)
|
||||
[languages.fr.params.footer]
|
||||
column_1_title = "FONCTIONNALITÉS"
|
||||
column_2_title = "ENTREPRISE"
|
||||
column_3_title = "LÉGAL"
|
||||
|
||||
# Header Configuration
|
||||
[languages.fr.params.header]
|
||||
[languages.fr.params.header.buttons]
|
||||
[languages.fr.params.header.buttons.signIn]
|
||||
text = "Connexion"
|
||||
url = "/fr/signin"
|
||||
[languages.fr.params.header.buttons.getStarted]
|
||||
text = "Commencer"
|
||||
url = "/fr/get-started"
|
||||
|
||||
# Blog configuration
|
||||
[languages.fr.params.blog]
|
||||
enable = true
|
||||
title = "Derniers Articles"
|
||||
subtitle = "Apprenez-en plus sur le développement web et les meilleures pratiques"
|
||||
```
|
||||
|
||||
**Important Notes:**
|
||||
- **Footer Configuration:** The `footer` section is required. Without it, footer column titles may not display correctly in the new language.
|
||||
- **Use uppercase** for footer column titles to maintain consistency with other languages
|
||||
- **URL paths:** Include the language prefix (e.g., `/fr/`) in all button URLs
|
||||
- All parameters should mirror the structure used in other languages (check English or Chinese examples)
|
||||
|
||||
### 6. Complete Checklist
|
||||
|
||||
Use this checklist to ensure you've configured everything correctly:
|
||||
|
||||
- [ ] **Language Config:** Added language configuration in `hugo.toml` with `languageCode`, `languageName`, `title`, `weight`, and `contentDir`
|
||||
- [ ] **Translation File:** Created `i18n/[lang].toml` with all UI translations (50+ keys)
|
||||
- [ ] **Content Directory:** Created `content/[lang]/` directory structure
|
||||
- [ ] **Homepage:** Created `content/[lang]/_index.md` with translated homepage content
|
||||
- [ ] **Navigation Menus:** Configured `languages.[lang].menu.main`, `footer_column_1`, `footer_column_2`, `footer_column_3`
|
||||
- [ ] **Language Params - CTA:** Added `languages.[lang].params.cta` configuration
|
||||
- [ ] **Language Params - Footer:** Added `languages.[lang].params.footer` with all three column titles (UPPERCASE)
|
||||
- [ ] **Language Params - Header:** Added `languages.[lang].params.header.buttons` configuration
|
||||
- [ ] **Language Params - Blog:** Added `languages.[lang].params.blog` configuration
|
||||
- [ ] **URL Prefixes:** All menu URLs include the language prefix (e.g., `/fr/features`)
|
||||
- [ ] **Test:** Verified language switcher appears in header with new language
|
||||
- [ ] **Test:** Verified homepage displays correctly in new language
|
||||
- [ ] **Test:** Verified top navigation menu shows translated items
|
||||
- [ ] **Test:** Verified footer navigation shows translated items
|
||||
- [ ] **Test:** Verified footer column titles display in new language
|
||||
|
||||
### Common Mistakes to Avoid
|
||||
|
||||
1. **Missing Footer Config:** Forgetting to add `languages.[lang].params.footer` will cause footer titles to not display
|
||||
2. **Inconsistent Capitalization:** Footer column titles should be UPPERCASE to match the theme's style
|
||||
3. **Missing URL Prefixes:** All language-specific URLs must include the language code (e.g., `/fr/`, not just `/`)
|
||||
4. **Incomplete Menus:** Ensure all three footer menus (`footer_column_1`, `footer_column_2`, `footer_column_3`) are configured
|
||||
5. **Missing i18n Keys:** Make sure all 50+ translation keys are present in your translation file
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Consistent Structure:** Mirror your content directory structure across all languages
|
||||
2. **Translation Keys:** Use descriptive i18n keys like `readMore` instead of abbreviations
|
||||
3. **Avoid Hardcoding:** Don't set text parameters in global config; let i18n handle it
|
||||
4. **Test Switching:** Verify language switching works correctly on all pages
|
||||
5. **Date Formats:** Define appropriate date formats for each language
|
||||
6. **Menus:** Configure language-specific menus with translated labels
|
||||
7. **URLs:** Include language code in URLs for non-default languages
|
||||
|
||||
## Resources
|
||||
|
||||
- **Hugo i18n Documentation:** https://gohugo.io/content-management/multilingual/
|
||||
- **Theme i18n Files:** `themes/chill-theme/i18n/`
|
||||
- **Demo Site Configuration:** See complete trilingual setup in demo site's `hugo.toml`
|
||||
- **Translation Examples:**
|
||||
- English: `i18n/en.toml` (reference for all keys)
|
||||
- Chinese: `i18n/zh-cn.toml` (complete translation)
|
||||
- German: `i18n/de.toml` (complete translation)
|
||||
- **Content Structure Examples:**
|
||||
- `content/` (English)
|
||||
- `content/zh-cn/` (Chinese)
|
||||
- `content/de/` (German)
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions about i18n:
|
||||
1. Check [TROUBLESHOOTING.md](TROUBLESHOOTING.md)
|
||||
2. Review the demo site's working multilingual setup
|
||||
3. Open an issue on GitHub with details about your configuration
|
||||
@@ -0,0 +1,785 @@
|
||||
# Layouts Guide
|
||||
|
||||
Complete guide to the Hugo Saasify Theme's layout system, templates, and components.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Layout Architecture](#layout-architecture)
|
||||
- [Base Template](#base-template)
|
||||
- [Default Layouts](#default-layouts)
|
||||
- [Page Templates](#page-templates)
|
||||
- [Partial Components](#partial-components)
|
||||
- [Custom Layouts](#custom-layouts)
|
||||
- [Layout Variables](#layout-variables)
|
||||
- [Best Practices](#best-practices)
|
||||
|
||||
## Layout Architecture
|
||||
|
||||
The Hugo Saasify Theme follows Hugo's template lookup order with specialized layouts for different page types.
|
||||
|
||||
### Directory Structure
|
||||
|
||||
```
|
||||
layouts/
|
||||
├── _default/
|
||||
│ ├── baseof.html # Base template (all pages)
|
||||
│ ├── single.html # Single page layout
|
||||
│ ├── list.html # List page layout
|
||||
│ ├── simple.html # Simple page layout
|
||||
│ ├── pricing.html # Pricing page layout
|
||||
│ ├── company.html # Company/About page layout
|
||||
│ ├── career.html # Careers page layout
|
||||
│ ├── job-single.html # Single job posting layout
|
||||
│ └── feature.html # Feature page layout
|
||||
├── docs/
|
||||
│ └── single.html # Documentation page layout
|
||||
├── partials/
|
||||
│ ├── header.html # Site header
|
||||
│ ├── footer.html # Site footer
|
||||
│ ├── sidebar.html # Blog sidebar
|
||||
│ ├── docs-sidebar.html # Documentation sidebar
|
||||
│ ├── post-card.html # Blog post card
|
||||
│ ├── post-meta.html # Post metadata
|
||||
│ ├── google-analytics.html # GA4 tracking
|
||||
│ ├── google-tag-manager.html # GTM tracking
|
||||
│ └── components/
|
||||
│ ├── cta.html # CTA component
|
||||
│ └── subscribe-form.html # Newsletter form
|
||||
├── taxonomy/
|
||||
│ ├── list.html # Category/tag listing
|
||||
│ └── terms.html # All categories/tags
|
||||
├── shortcodes/
|
||||
│ └── [various shortcodes] # See SHORTCODES.md
|
||||
└── index.html # Homepage template
|
||||
```
|
||||
|
||||
## Base Template
|
||||
|
||||
The `baseof.html` template provides the HTML structure for all pages.
|
||||
|
||||
### Location
|
||||
`layouts/_default/baseof.html`
|
||||
|
||||
### Structure
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ .Site.Language.Lang }}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{ block "title" . }}{{ .Title }} | {{ .Site.Title }}{{ end }}</title>
|
||||
|
||||
<!-- Meta tags -->
|
||||
<meta name="description" content="{{ block "description" . }}{{ .Description | default .Site.Params.description }}{{ end }}">
|
||||
|
||||
<!-- Styles -->
|
||||
{{ $styles := resources.Get "scss/main.scss" }}
|
||||
{{ $styles = $styles | postCSS | minify | fingerprint }}
|
||||
<link rel="stylesheet" href="{{ $styles.RelPermalink }}">
|
||||
|
||||
<!-- Analytics -->
|
||||
{{ partial "google-tag-manager.html" . }}
|
||||
{{ partial "google-analytics.html" . }}
|
||||
</head>
|
||||
<body>
|
||||
<!-- GTM noscript -->
|
||||
{{ partial "google-tag-manager.html" . }}
|
||||
|
||||
<!-- Header -->
|
||||
{{ partial "header.html" . }}
|
||||
|
||||
<!-- Main content -->
|
||||
<main>
|
||||
{{ block "main" . }}{{ end }}
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
{{ partial "footer.html" . }}
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### Available Blocks
|
||||
|
||||
1. **title** - Page title (default: `{{ .Title }} | {{ .Site.Title }}`)
|
||||
2. **description** - Meta description
|
||||
3. **main** - Main content area
|
||||
|
||||
### Customizing Base Template
|
||||
|
||||
To override the base template, create:
|
||||
```
|
||||
layouts/baseof.html
|
||||
```
|
||||
|
||||
Or extend it in your custom layouts:
|
||||
```html
|
||||
{{ define "main" }}
|
||||
<!-- Your content -->
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
## Default Layouts
|
||||
|
||||
### Single Page Layout
|
||||
|
||||
**File**: `layouts/_default/single.html`
|
||||
|
||||
Used for individual blog posts and standard pages.
|
||||
|
||||
**Features**:
|
||||
- Full-width content area
|
||||
- Post metadata (date, author, reading time)
|
||||
- Table of contents support
|
||||
- Related posts
|
||||
- CTA section
|
||||
- Social sharing buttons
|
||||
|
||||
**Front Matter Example**:
|
||||
```yaml
|
||||
---
|
||||
title: "My Blog Post"
|
||||
date: 2025-10-06
|
||||
author: "John Doe"
|
||||
description: "Post description"
|
||||
layout: single # Optional, default for posts
|
||||
---
|
||||
```
|
||||
|
||||
**Template Structure**:
|
||||
```html
|
||||
{{ define "main" }}
|
||||
<article class="max-w-4xl mx-auto px-4 py-12">
|
||||
<!-- Post header -->
|
||||
<header class="mb-8">
|
||||
<h1 class="text-4xl font-bold mb-4">{{ .Title }}</h1>
|
||||
{{ partial "post-meta.html" . }}
|
||||
</header>
|
||||
|
||||
<!-- Post content -->
|
||||
<div class="prose prose-lg">
|
||||
{{ .Content }}
|
||||
</div>
|
||||
|
||||
<!-- CTA section -->
|
||||
{{ if .Site.Params.blog.cta.enable }}
|
||||
{{ partial "components/cta.html" . }}
|
||||
{{ end }}
|
||||
</article>
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
### List Page Layout
|
||||
|
||||
**File**: `layouts/_default/list.html`
|
||||
|
||||
Used for blog index, category pages, and section listings.
|
||||
|
||||
**Features**:
|
||||
- Grid layout for posts
|
||||
- Pagination
|
||||
- Filtering by category/tag
|
||||
- Sidebar with widgets
|
||||
- Post previews
|
||||
|
||||
**Template Structure**:
|
||||
```html
|
||||
{{ define "main" }}
|
||||
<div class="container py-12">
|
||||
<div class="grid lg:grid-cols-3 gap-12">
|
||||
<!-- Main content -->
|
||||
<div class="lg:col-span-2">
|
||||
<div class="grid gap-8">
|
||||
{{ range .Paginator.Pages }}
|
||||
{{ partial "post-card.html" . }}
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
{{ template "_internal/pagination.html" . }}
|
||||
</div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<aside class="lg:col-span-1">
|
||||
{{ partial "sidebar.html" . }}
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
### Simple Page Layout
|
||||
|
||||
**File**: `layouts/_default/simple.html`
|
||||
|
||||
Used for clean, content-focused pages like privacy policy, terms of service.
|
||||
|
||||
**Features**:
|
||||
- Centered content
|
||||
- No sidebar
|
||||
- Minimal chrome
|
||||
- Full prose styling
|
||||
|
||||
**Front Matter**:
|
||||
```yaml
|
||||
---
|
||||
title: "Privacy Policy"
|
||||
layout: simple
|
||||
---
|
||||
```
|
||||
|
||||
**Use Cases**:
|
||||
- Legal pages
|
||||
- Documentation
|
||||
- Long-form content
|
||||
- Landing pages
|
||||
|
||||
## Page Templates
|
||||
|
||||
### Pricing Page Layout
|
||||
|
||||
**File**: `layouts/_default/pricing.html`
|
||||
|
||||
Specialized layout for pricing pages.
|
||||
|
||||
**Features**:
|
||||
- Pricing table support
|
||||
- Feature comparison
|
||||
- FAQ section
|
||||
- CTA integration
|
||||
- Custom pricing shortcodes
|
||||
|
||||
**Front Matter**:
|
||||
```yaml
|
||||
---
|
||||
title: "Pricing"
|
||||
layout: pricing
|
||||
description: "Choose the perfect plan for your needs"
|
||||
---
|
||||
```
|
||||
|
||||
**Content Example**:
|
||||
```markdown
|
||||
---
|
||||
title: "Pricing"
|
||||
layout: pricing
|
||||
---
|
||||
|
||||
{{< pricing-table-1 >}}
|
||||
{
|
||||
"title": "Choose Your Plan",
|
||||
"description": "Start free, upgrade as you grow",
|
||||
"plans": [...]
|
||||
}
|
||||
{{< /pricing-table-1 >}}
|
||||
|
||||
{{< faq >}}
|
||||
# Frequently Asked Questions
|
||||
...
|
||||
{{< /faq >}}
|
||||
```
|
||||
|
||||
### Company/About Page Layout
|
||||
|
||||
**File**: `layouts/_default/company.html`
|
||||
|
||||
Designed for company and about pages.
|
||||
|
||||
**Features**:
|
||||
- Team member showcase
|
||||
- Company stats
|
||||
- Mission/vision sections
|
||||
- Investor logos
|
||||
- Value propositions
|
||||
|
||||
**Front Matter**:
|
||||
```yaml
|
||||
---
|
||||
title: "About Us"
|
||||
layout: company
|
||||
description: "Learn about our mission and team"
|
||||
---
|
||||
```
|
||||
|
||||
**Typical Structure**:
|
||||
```markdown
|
||||
{{< hero headline="About Our Company" ... >}}
|
||||
|
||||
{{< section-container >}}
|
||||
## Our Mission
|
||||
...
|
||||
{{< /section-container >}}
|
||||
|
||||
{{< stat value="100+" label="Happy Clients" >}}
|
||||
{{< stat value="50+" label="Team Members" >}}
|
||||
|
||||
{{< team-member name="John Doe" ... >}}
|
||||
{{< team-member name="Jane Smith" ... >}}
|
||||
```
|
||||
|
||||
### Career Page Layout
|
||||
|
||||
**File**: `layouts/_default/career.html`
|
||||
|
||||
For careers/jobs listing pages.
|
||||
|
||||
**Features**:
|
||||
- Job listings grid
|
||||
- Department filtering
|
||||
- Location filtering
|
||||
- Application CTA
|
||||
- Company culture section
|
||||
|
||||
**Front Matter**:
|
||||
```yaml
|
||||
---
|
||||
title: "Careers"
|
||||
layout: career
|
||||
description: "Join our team"
|
||||
---
|
||||
```
|
||||
|
||||
### Job Single Layout
|
||||
|
||||
**File**: `layouts/_default/job-single.html`
|
||||
|
||||
Individual job posting pages.
|
||||
|
||||
**Features**:
|
||||
- Job details
|
||||
- Requirements list
|
||||
- Benefits list
|
||||
- Apply button
|
||||
- Share functionality
|
||||
|
||||
**Front Matter**:
|
||||
```yaml
|
||||
---
|
||||
title: "Senior Developer"
|
||||
layout: job-single
|
||||
department: "Engineering"
|
||||
location: "Remote"
|
||||
type: "Full-time"
|
||||
---
|
||||
```
|
||||
|
||||
### Feature Page Layout
|
||||
|
||||
**File**: `layouts/_default/feature.html`
|
||||
|
||||
Showcase individual features or products.
|
||||
|
||||
**Features**:
|
||||
- Hero section
|
||||
- Feature highlights
|
||||
- Screenshots/demos
|
||||
- Use cases
|
||||
- Integration info
|
||||
|
||||
**Front Matter**:
|
||||
```yaml
|
||||
---
|
||||
title: "Performance Features"
|
||||
layout: feature
|
||||
description: "Lightning-fast performance"
|
||||
---
|
||||
```
|
||||
|
||||
## Partial Components
|
||||
|
||||
Reusable components used across layouts.
|
||||
|
||||
### Header Partial
|
||||
|
||||
**File**: `layouts/partials/header.html`
|
||||
|
||||
**Features**:
|
||||
- Responsive navigation
|
||||
- Dropdown menus
|
||||
- Logo
|
||||
- CTA buttons
|
||||
- Mobile menu
|
||||
|
||||
**Variables**:
|
||||
- `Site.Params.header.*` - Header configuration
|
||||
- `Site.Menus.main` - Navigation menu items
|
||||
|
||||
**Customization**:
|
||||
```toml
|
||||
[params.header]
|
||||
background = "bg-white"
|
||||
[params.header.logo]
|
||||
src = "/images/logo.svg"
|
||||
```
|
||||
|
||||
### Footer Partial
|
||||
|
||||
**File**: `layouts/partials/footer.html`
|
||||
|
||||
**Features**:
|
||||
- Multi-column layout
|
||||
- Footer menus
|
||||
- Social media links
|
||||
- Newsletter signup
|
||||
- Copyright notice
|
||||
|
||||
**Variables**:
|
||||
- `Site.Params.footer.*` - Footer configuration
|
||||
- `Site.Params.social.*` - Social media links
|
||||
- `Site.Menus.footer_column_*` - Footer menus
|
||||
|
||||
### Sidebar Partial
|
||||
|
||||
**File**: `layouts/partials/sidebar.html`
|
||||
|
||||
Blog sidebar with widgets.
|
||||
|
||||
**Features**:
|
||||
- Recent posts
|
||||
- Categories
|
||||
- Tags cloud
|
||||
- Newsletter subscription
|
||||
- Search (optional)
|
||||
|
||||
**Configuration**:
|
||||
```toml
|
||||
[params.blog.sidebar]
|
||||
[params.blog.sidebar.recent]
|
||||
enable = true
|
||||
count = 5
|
||||
```
|
||||
|
||||
### Documentation Sidebar
|
||||
|
||||
**File**: `layouts/partials/docs-sidebar.html`
|
||||
|
||||
Navigation for documentation pages.
|
||||
|
||||
**Features**:
|
||||
- Hierarchical navigation
|
||||
- Active page highlighting
|
||||
- Collapsible sections
|
||||
- Search integration
|
||||
|
||||
**Usage**:
|
||||
Automatically included in `layouts/docs/single.html`
|
||||
|
||||
### Post Card Partial
|
||||
|
||||
**File**: `layouts/partials/post-card.html`
|
||||
|
||||
Blog post preview card.
|
||||
|
||||
**Features**:
|
||||
- Featured image
|
||||
- Title and excerpt
|
||||
- Post metadata
|
||||
- Read more link
|
||||
- Category badge
|
||||
|
||||
**Usage**:
|
||||
```html
|
||||
{{ range .Pages }}
|
||||
{{ partial "post-card.html" . }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
### Post Meta Partial
|
||||
|
||||
**File**: `layouts/partials/post-meta.html`
|
||||
|
||||
Display post metadata.
|
||||
|
||||
**Shows**:
|
||||
- Publication date
|
||||
- Author
|
||||
- Reading time
|
||||
- Categories
|
||||
- Tags
|
||||
|
||||
**Usage**:
|
||||
```html
|
||||
{{ partial "post-meta.html" . }}
|
||||
```
|
||||
|
||||
### CTA Component
|
||||
|
||||
**File**: `layouts/partials/components/cta.html`
|
||||
|
||||
Call-to-action section.
|
||||
|
||||
**Features**:
|
||||
- Gradient background
|
||||
- Primary/secondary buttons
|
||||
- Customizable text
|
||||
|
||||
**Configuration**:
|
||||
```toml
|
||||
[params.cta]
|
||||
enable = true
|
||||
title = "Ready to start?"
|
||||
```
|
||||
|
||||
### Subscribe Form Component
|
||||
|
||||
**File**: `layouts/partials/components/subscribe-form.html`
|
||||
|
||||
Newsletter subscription form.
|
||||
|
||||
**Features**:
|
||||
- Email input
|
||||
- Submit button
|
||||
- Privacy notice
|
||||
- Form validation
|
||||
|
||||
**Configuration**:
|
||||
```toml
|
||||
[params.blog.sidebar.subscribe]
|
||||
enable = true
|
||||
action = "https://formspree.io/f/xxx"
|
||||
```
|
||||
|
||||
### Analytics Partials
|
||||
|
||||
**Google Analytics**: `layouts/partials/google-analytics.html`
|
||||
- GA4 tracking code
|
||||
- Automatic page views
|
||||
- Event tracking ready
|
||||
|
||||
**Google Tag Manager**: `layouts/partials/google-tag-manager.html`
|
||||
- GTM container code
|
||||
- Head and body scripts
|
||||
- DataLayer support
|
||||
|
||||
**Custom Head**: `layouts/partials/custom-head.html`
|
||||
- User-overridable partial for custom code
|
||||
- Add any tracking scripts not covered by GA/GTM
|
||||
- Add verification meta tags
|
||||
- Include custom fonts or stylesheets
|
||||
- Loaded at the end of `<head>` section
|
||||
|
||||
To use, create `layouts/partials/custom-head.html` in your site with your custom content.
|
||||
|
||||
## Custom Layouts
|
||||
|
||||
### Creating Custom Layouts
|
||||
|
||||
1. **Single Page Custom Layout**
|
||||
|
||||
Create `layouts/_default/mycustom.html`:
|
||||
```html
|
||||
{{ define "main" }}
|
||||
<div class="custom-layout">
|
||||
<h1>{{ .Title }}</h1>
|
||||
{{ .Content }}
|
||||
</div>
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
Use in front matter:
|
||||
```yaml
|
||||
---
|
||||
title: "My Page"
|
||||
layout: mycustom
|
||||
---
|
||||
```
|
||||
|
||||
2. **Section-Specific Layout**
|
||||
|
||||
For pages in `content/products/`, create:
|
||||
`layouts/products/single.html`
|
||||
|
||||
3. **Type-Based Layout**
|
||||
|
||||
Specify type in front matter:
|
||||
```yaml
|
||||
---
|
||||
title: "My Page"
|
||||
type: custom
|
||||
---
|
||||
```
|
||||
|
||||
Create `layouts/custom/single.html`
|
||||
|
||||
### Layout Lookup Order
|
||||
|
||||
Hugo looks for templates in this order:
|
||||
|
||||
For `content/blog/my-post.md`:
|
||||
1. `layouts/blog/single.html`
|
||||
2. `layouts/_default/single.html`
|
||||
|
||||
For `content/blog/_index.md`:
|
||||
1. `layouts/blog/list.html`
|
||||
2. `layouts/_default/list.html`
|
||||
|
||||
## Layout Variables
|
||||
|
||||
### Page Variables
|
||||
|
||||
Available in all layouts:
|
||||
|
||||
```html
|
||||
{{ .Title }} <!-- Page title -->
|
||||
{{ .Content }} <!-- Page content -->
|
||||
{{ .Description }} <!-- Page description -->
|
||||
{{ .Date }} <!-- Publication date -->
|
||||
{{ .Lastmod }} <!-- Last modified date -->
|
||||
{{ .WordCount }} <!-- Word count -->
|
||||
{{ .ReadingTime }} <!-- Reading time in minutes -->
|
||||
{{ .Permalink }} <!-- Absolute URL -->
|
||||
{{ .RelPermalink }} <!-- Relative URL -->
|
||||
{{ .Params.custom }} <!-- Custom front matter -->
|
||||
```
|
||||
|
||||
### Site Variables
|
||||
|
||||
```html
|
||||
{{ .Site.Title }} <!-- Site title -->
|
||||
{{ .Site.Params.description }} <!-- Site description -->
|
||||
{{ .Site.Params.logo }} <!-- Logo path -->
|
||||
{{ .Site.BaseURL }} <!-- Base URL -->
|
||||
{{ .Site.Language.Lang }} <!-- Language code -->
|
||||
{{ .Site.Menus.main }} <!-- Main menu -->
|
||||
{{ .Site.Params.social.twitter }} <!-- Social links -->
|
||||
```
|
||||
|
||||
### Taxonomy Variables
|
||||
|
||||
```html
|
||||
{{ .Data.Terms }} <!-- All terms in taxonomy -->
|
||||
{{ .Data.Singular }} <!-- Singular name -->
|
||||
{{ .Data.Plural }} <!-- Plural name -->
|
||||
```
|
||||
|
||||
### Page Context
|
||||
|
||||
```html
|
||||
{{ .IsHome }} <!-- Is homepage? -->
|
||||
{{ .IsPage }} <!-- Is single page? -->
|
||||
{{ .IsSection }} <!-- Is section? -->
|
||||
{{ .Kind }} <!-- Page kind -->
|
||||
{{ .Type }} <!-- Page type -->
|
||||
{{ .Section }} <!-- Section name -->
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Extend, Don't Replace
|
||||
|
||||
Prefer extending base template:
|
||||
```html
|
||||
{{ define "main" }}
|
||||
<!-- Your content -->
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
Over replacing entire baseof.html.
|
||||
|
||||
### 2. Use Partials
|
||||
|
||||
Break complex layouts into partials:
|
||||
```html
|
||||
{{ partial "components/hero.html" . }}
|
||||
{{ partial "components/features.html" . }}
|
||||
{{ partial "components/testimonials.html" . }}
|
||||
```
|
||||
|
||||
### 3. Conditional Content
|
||||
|
||||
Use configuration to control features:
|
||||
```html
|
||||
{{ if .Site.Params.blog.sidebar.recent.enable }}
|
||||
{{ partial "sidebar-recent.html" . }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
### 4. Responsive Design
|
||||
|
||||
Use Tailwind responsive classes:
|
||||
```html
|
||||
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
```
|
||||
|
||||
### 5. Semantic HTML
|
||||
|
||||
Use proper HTML5 elements:
|
||||
```html
|
||||
<article>
|
||||
<header>
|
||||
<h1>{{ .Title }}</h1>
|
||||
<time datetime="{{ .Date }}">{{ .Date.Format "Jan 2, 2006" }}</time>
|
||||
</header>
|
||||
<main>{{ .Content }}</main>
|
||||
</article>
|
||||
```
|
||||
|
||||
### 6. Performance
|
||||
|
||||
Optimize images and assets:
|
||||
```html
|
||||
{{ $image := resources.Get "images/hero.jpg" }}
|
||||
{{ $image = $image.Resize "1200x" }}
|
||||
<img src="{{ $image.RelPermalink }}" loading="lazy">
|
||||
```
|
||||
|
||||
### 7. Accessibility
|
||||
|
||||
Include ARIA attributes:
|
||||
```html
|
||||
<nav aria-label="Main navigation">
|
||||
<!-- Menu items -->
|
||||
</nav>
|
||||
```
|
||||
|
||||
### 8. SEO
|
||||
|
||||
Include proper meta tags:
|
||||
```html
|
||||
<meta name="description" content="{{ .Description }}">
|
||||
<meta property="og:title" content="{{ .Title }}">
|
||||
<meta property="og:description" content="{{ .Description }}">
|
||||
```
|
||||
|
||||
## Testing Layouts
|
||||
|
||||
### Local Testing
|
||||
|
||||
```bash
|
||||
# Test with development server
|
||||
hugo server -D
|
||||
|
||||
# Test specific page
|
||||
hugo server -D --navigateToChanged
|
||||
|
||||
# Test with different baseURL
|
||||
hugo server -D --baseURL http://localhost:1313
|
||||
```
|
||||
|
||||
### Build Testing
|
||||
|
||||
```bash
|
||||
# Build without drafts
|
||||
hugo
|
||||
|
||||
# Build with drafts
|
||||
hugo -D
|
||||
|
||||
# Build with verbose output
|
||||
hugo --verbose
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [SHORTCODES.md](SHORTCODES.md) - Available shortcodes
|
||||
- [STYLING.md](STYLING.md) - Styling and customization
|
||||
- [CONTENT-CREATION.md](CONTENT-CREATION.md) - Creating content
|
||||
- [CONFIGURATION.md](CONFIGURATION.md) - Configuration options
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Hugo Template Documentation](https://gohugo.io/templates/)
|
||||
- [Hugo Lookup Order](https://gohugo.io/templates/lookup-order/)
|
||||
- [Hugo Variables](https://gohugo.io/variables/)
|
||||
- [Hugo Functions](https://gohugo.io/functions/)
|
||||
@@ -0,0 +1,313 @@
|
||||
# Hugo Saasify Theme Documentation
|
||||
|
||||
Welcome to the complete documentation for Hugo Saasify Theme - a modern, high-performance Hugo theme built specifically for SaaS websites.
|
||||
|
||||
## 📚 Documentation Overview
|
||||
|
||||
This documentation is organized into focused guides to help you get started quickly and master every aspect of the theme.
|
||||
|
||||
### Getting Started
|
||||
|
||||
Start here if you're new to the theme:
|
||||
|
||||
1. **[Installation Guide](INSTALLATION.md)** - Set up the theme and its dependencies
|
||||
2. **[Configuration Guide](CONFIGURATION.md)** - Configure your site settings
|
||||
3. **[Content Creation Guide](CONTENT-CREATION.md)** - Create pages and blog posts
|
||||
|
||||
### Core Concepts
|
||||
|
||||
Learn about the theme's architecture and features:
|
||||
|
||||
4. **[Layouts Guide](LAYOUTS.md)** - Understanding layout templates and structure
|
||||
5. **[Shortcodes Reference](SHORTCODES.md)** - Complete guide to all 21 shortcodes
|
||||
6. **[Styling Guide](STYLING.md)** - TailwindCSS configuration and customization
|
||||
|
||||
### Deployment & Production
|
||||
|
||||
Ready to go live?
|
||||
|
||||
7. **[Deployment Guide](DEPLOYMENT.md)** - Deploy to Netlify, Vercel, GitHub Pages, and more
|
||||
8. **[Troubleshooting Guide](TROUBLESHOOTING.md)** - Common issues and solutions
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
Get your site running in 5 minutes:
|
||||
|
||||
```bash
|
||||
# 1. Create new Hugo site
|
||||
hugo new site my-saas-site
|
||||
cd my-saas-site
|
||||
|
||||
# 2. Add theme as submodule
|
||||
git init
|
||||
git submodule add https://github.com/chaoming/chill-theme themes/chill-theme
|
||||
|
||||
# 3. Copy example site
|
||||
cp -r themes/chill-theme/exampleSite/* .
|
||||
|
||||
# 4. Install dependencies
|
||||
npm install
|
||||
|
||||
# 5. Start development server
|
||||
npm run start
|
||||
```
|
||||
|
||||
Visit `http://localhost:1313` to see your site!
|
||||
|
||||
## 📖 Documentation Guides
|
||||
|
||||
### [Installation Guide](INSTALLATION.md)
|
||||
|
||||
Learn how to install and set up the Hugo Saasify Theme:
|
||||
|
||||
- System requirements (Hugo Extended, Node.js)
|
||||
- Installation methods (new site vs. existing site)
|
||||
- Configuration setup
|
||||
- Troubleshooting installation issues
|
||||
- Updating the theme
|
||||
|
||||
**Start here if:** You're installing the theme for the first time.
|
||||
|
||||
---
|
||||
|
||||
### [Configuration Guide](CONFIGURATION.md)
|
||||
|
||||
Complete reference for all configuration options:
|
||||
|
||||
- Basic site configuration
|
||||
- Header and footer customization
|
||||
- Call-to-action (CTA) settings
|
||||
- Blog configuration
|
||||
- Social media links
|
||||
- Google Analytics and Tag Manager
|
||||
- Menu configuration
|
||||
- Build settings
|
||||
|
||||
**Start here if:** You need to customize site settings.
|
||||
|
||||
---
|
||||
|
||||
### [Layouts Guide](LAYOUTS.md)
|
||||
|
||||
Understanding the theme's layout system:
|
||||
|
||||
- Layout architecture overview
|
||||
- Base template structure
|
||||
- Default layouts (single, list, etc.)
|
||||
- Page templates (pricing, company, careers, features)
|
||||
- Partial components
|
||||
- Creating custom layouts
|
||||
- Layout variables reference
|
||||
|
||||
**Start here if:** You want to understand or modify page templates.
|
||||
|
||||
---
|
||||
|
||||
### [Shortcodes Reference](SHORTCODES.md)
|
||||
|
||||
Complete documentation for all 21 shortcodes:
|
||||
|
||||
**Hero & Layout:**
|
||||
- `hero` - Hero sections with gradient backgrounds
|
||||
- `hero-image` - Simple hero images
|
||||
- `section-container` - Section wrappers
|
||||
- `features-section` - Feature collection containers
|
||||
|
||||
**Features & Benefits:**
|
||||
- `feature` - Feature displays with images
|
||||
- `features-list` - Vertical feature lists
|
||||
- `benefits-grid` - Benefit card grids
|
||||
- `value-card` - Company value cards
|
||||
|
||||
**Social Proof:**
|
||||
- `testimonials` - Customer testimonial carousels
|
||||
- `client-logos` - Animated logo carousels
|
||||
- `stat` - Statistics display
|
||||
|
||||
**Pricing:**
|
||||
- `pricing-table-1` - Simple pricing tables
|
||||
- `pricing-table-2` - Advanced pricing tables
|
||||
|
||||
**Team & Company:**
|
||||
- `team-member` - Team member cards
|
||||
- `investor-logo` - Investor/partner logos
|
||||
- `case-study-card` - Case study cards
|
||||
|
||||
**Content:**
|
||||
- `cta` - Call-to-action sections
|
||||
- `faq` - FAQ accordions
|
||||
- `toc` - Table of contents
|
||||
- `figure` - Images with captions
|
||||
- `code` - Code blocks with syntax highlighting
|
||||
|
||||
**Start here if:** You're building pages with shortcodes.
|
||||
|
||||
---
|
||||
|
||||
### [Styling Guide](STYLING.md)
|
||||
|
||||
Everything about the theme's styling system:
|
||||
|
||||
- TailwindCSS integration and configuration
|
||||
- Color system (primary and secondary palettes)
|
||||
- Typography (Inter and Plus Jakarta Sans)
|
||||
- Custom components (buttons, cards, etc.)
|
||||
- Responsive design patterns
|
||||
- Syntax highlighting themes
|
||||
- Custom CSS and utilities
|
||||
- Performance optimization
|
||||
|
||||
**Start here if:** You want to customize colors, fonts, or styles.
|
||||
|
||||
---
|
||||
|
||||
### [Content Creation Guide](CONTENT-CREATION.md)
|
||||
|
||||
Learn how to create and organize content:
|
||||
|
||||
- Content structure and organization
|
||||
- Front matter options
|
||||
- Page types (homepage, features, pricing, etc.)
|
||||
- Creating blog posts
|
||||
- Creating documentation pages
|
||||
- Using taxonomies (categories and tags)
|
||||
- Media management and image optimization
|
||||
- SEO best practices
|
||||
- Markdown formatting
|
||||
- Draft and scheduled content
|
||||
|
||||
**Start here if:** You're ready to add content to your site.
|
||||
|
||||
---
|
||||
|
||||
### [Deployment Guide](DEPLOYMENT.md)
|
||||
|
||||
Deploy your site to production:
|
||||
|
||||
- Building for production
|
||||
- Platform-specific guides:
|
||||
- Netlify
|
||||
- Vercel
|
||||
- GitHub Pages
|
||||
- Cloudflare Pages
|
||||
- AWS S3 + CloudFront
|
||||
- Custom server deployment (Nginx, Apache)
|
||||
- Environment variables
|
||||
- Performance optimization
|
||||
- Continuous deployment
|
||||
- Testing before deployment
|
||||
|
||||
**Start here if:** You're ready to launch your site.
|
||||
|
||||
---
|
||||
|
||||
### [Troubleshooting Guide](TROUBLESHOOTING.md)
|
||||
|
||||
Solutions to common problems:
|
||||
|
||||
- Installation issues
|
||||
- Build errors
|
||||
- Styling problems
|
||||
- Content issues
|
||||
- Deployment problems
|
||||
- Performance issues
|
||||
- Browser compatibility
|
||||
- Getting help and reporting issues
|
||||
|
||||
**Start here if:** You're experiencing issues.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Common Tasks
|
||||
|
||||
### How do I...?
|
||||
|
||||
**...install the theme?**
|
||||
→ See [Installation Guide](INSTALLATION.md)
|
||||
|
||||
**...customize colors?**
|
||||
→ See [Styling Guide - Color System](STYLING.md#color-system)
|
||||
|
||||
**...create a blog post?**
|
||||
→ See [Content Creation - Blog Posts](CONTENT-CREATION.md#blog-posts)
|
||||
|
||||
**...add a pricing page?**
|
||||
→ See [Shortcodes - Pricing Tables](SHORTCODES.md#pricing)
|
||||
|
||||
**...configure the header menu?**
|
||||
→ See [Configuration - Menu Configuration](CONFIGURATION.md#menu-configuration)
|
||||
|
||||
**...deploy to Netlify?**
|
||||
→ See [Deployment - Netlify](DEPLOYMENT.md#netlify)
|
||||
|
||||
**...add team members?**
|
||||
→ See [Shortcodes - Team Member](SHORTCODES.md#team-member)
|
||||
|
||||
**...enable Google Analytics?**
|
||||
→ See [Configuration - Analytics](CONFIGURATION.md#analytics-configuration)
|
||||
|
||||
**...customize fonts?**
|
||||
→ See [Styling - Typography](STYLING.md#typography)
|
||||
|
||||
**...fix build errors?**
|
||||
→ See [Troubleshooting - Build Errors](TROUBLESHOOTING.md#build-errors)
|
||||
|
||||
## 🌟 Key Features
|
||||
|
||||
This theme includes:
|
||||
|
||||
- ✅ **21 Pre-built Shortcodes** - Hero sections, features, pricing tables, testimonials, and more
|
||||
- ✅ **TailwindCSS Integration** - Modern, utility-first CSS framework
|
||||
- ✅ **Responsive Design** - Mobile-first, looks great on all devices
|
||||
- ✅ **Performance Optimized** - Fast builds, minimal JavaScript, optimized assets
|
||||
- ✅ **SEO Ready** - Meta tags, Open Graph, Twitter Cards
|
||||
- ✅ **Blog System** - Categories, tags, sidebar, table of contents
|
||||
- ✅ **Multiple Page Templates** - Pricing, features, company, careers, jobs
|
||||
- ✅ **Analytics Integration** - Google Analytics and Tag Manager support
|
||||
- ✅ **Syntax Highlighting** - Beautiful code blocks with dark theme
|
||||
- ✅ **Easy Customization** - Configurable colors, fonts, and layouts
|
||||
|
||||
## 📋 Requirements
|
||||
|
||||
- **Hugo Extended** v0.80.0 or higher
|
||||
- **Node.js** v14.x or higher
|
||||
- **npm** or **yarn**
|
||||
- **Git** (for submodule installation)
|
||||
|
||||
## 🔗 Useful Links
|
||||
|
||||
- [Demo Site](https://saasify-demo.chaoming.li)
|
||||
- [GitHub Repository](https://github.com/chaoming/chill-theme)
|
||||
- [Report Issues](https://github.com/chaoming/chill-theme/issues)
|
||||
- [Hugo Documentation](https://gohugo.io/documentation/)
|
||||
- [TailwindCSS Documentation](https://tailwindcss.com/docs)
|
||||
|
||||
## 🤝 Support
|
||||
|
||||
Need help?
|
||||
|
||||
1. **Check the Documentation** - Start with the relevant guide above
|
||||
2. **Review Troubleshooting** - See [Troubleshooting Guide](TROUBLESHOOTING.md)
|
||||
3. **Search Issues** - Check [existing issues](https://github.com/chaoming/chill-theme/issues)
|
||||
4. **Ask for Help** - Open a [new issue](https://github.com/chaoming/chill-theme/issues/new) with:
|
||||
- Hugo version (`hugo version`)
|
||||
- Node version (`node --version`)
|
||||
- Error messages
|
||||
- Steps to reproduce
|
||||
- Your configuration
|
||||
|
||||
## 📝 License
|
||||
|
||||
This theme is released under the [MIT License](../LICENSE).
|
||||
|
||||
## 👨💻 Author
|
||||
|
||||
Created by [Chaoming Li](https://chaoming.li)
|
||||
|
||||
## 🎉 Contributing
|
||||
|
||||
Contributions are welcome! Please feel free to submit a Pull Request.
|
||||
|
||||
---
|
||||
|
||||
**Ready to get started?** Begin with the [Installation Guide](INSTALLATION.md) →
|
||||
@@ -0,0 +1,866 @@
|
||||
# Shortcodes Guide
|
||||
|
||||
Complete reference for all shortcodes available in the Hugo Saasify Theme. Shortcodes are reusable content components that help you build beautiful pages quickly.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Hero & Layout](#hero--layout)
|
||||
- [Features & Benefits](#features--benefits)
|
||||
- [Social Proof](#social-proof)
|
||||
- [Pricing](#pricing)
|
||||
- [Team & Company](#team--company)
|
||||
- [Content Components](#content-components)
|
||||
- [Utility Shortcodes](#utility-shortcodes)
|
||||
- [Usage Tips](#usage-tips)
|
||||
|
||||
## Hero & Layout
|
||||
|
||||
### hero
|
||||
|
||||
Create an eye-catching hero section for your pages.
|
||||
|
||||
**Parameters:**
|
||||
- `headline` (string, required) - Main headline text
|
||||
- `sub_headline` (string, required) - Subheading text
|
||||
- `primary_button_text` (string, optional) - Primary CTA button text
|
||||
- `primary_button_url` (string, optional) - Primary button link
|
||||
- `secondary_button_text` (string, optional) - Secondary button text
|
||||
- `secondary_button_url` (string, optional) - Secondary button link
|
||||
- `hero_image` (string, optional) - Path to hero image
|
||||
- `background_image` (string, optional) - Background image path
|
||||
- `gradient-from` (string, optional) - Gradient start color (hex)
|
||||
- `gradient-to` (string, optional) - Gradient end color (hex)
|
||||
- `gradient-angle` (integer, optional) - Gradient angle in degrees (default: 180)
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< hero
|
||||
headline="Build Your SaaS <span class='text-primary-600'>Faster</span>"
|
||||
sub_headline="A modern Hugo theme designed for SaaS and technology companies"
|
||||
primary_button_text="Get Started Free"
|
||||
primary_button_url="/signup"
|
||||
secondary_button_text="View Demo"
|
||||
secondary_button_url="/demo"
|
||||
hero_image="/images/hero-dashboard.png"
|
||||
gradient-from="#2563eb"
|
||||
gradient-to="#7c3aed"
|
||||
gradient-angle="30"
|
||||
>}}
|
||||
```
|
||||
|
||||
**With Background Image:**
|
||||
```markdown
|
||||
{{< hero
|
||||
headline="Welcome to Our Platform"
|
||||
sub_headline="Everything you need in one place"
|
||||
background_image="/images/hero-bg.jpg"
|
||||
primary_button_text="Learn More"
|
||||
primary_button_url="/features"
|
||||
>}}
|
||||
```
|
||||
|
||||
### hero-image
|
||||
|
||||
Standalone hero image component.
|
||||
|
||||
**Parameters:**
|
||||
- `src` (string, required) - Image source path
|
||||
- `alt` (string, optional) - Alternative text
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< hero-image src="/images/product-screenshot.png" alt="Product Dashboard" >}}
|
||||
```
|
||||
|
||||
### section-container
|
||||
|
||||
Wrapper for creating consistent section spacing and layout.
|
||||
|
||||
**Parameters:**
|
||||
- `background` (string, optional) - Background color or class
|
||||
- `padding` (string, optional) - Custom padding classes
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< section-container background="bg-gray-50" >}}
|
||||
## Your Content Here
|
||||
This content will be wrapped in a properly spaced section.
|
||||
{{< /section-container >}}
|
||||
```
|
||||
|
||||
## Features & Benefits
|
||||
|
||||
### feature
|
||||
|
||||
Display a single feature with icon, title, and description.
|
||||
|
||||
**Parameters:**
|
||||
- `icon` (string, required) - Icon name or SVG
|
||||
- `title` (string, required) - Feature title
|
||||
- `description` (string, required) - Feature description
|
||||
- `image` (string, optional) - Feature image path
|
||||
- `image_position` (string, optional) - "left" or "right" (default: "right")
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< feature
|
||||
icon="zap"
|
||||
title="Lightning Fast"
|
||||
description="Built with performance in mind. Your site loads in milliseconds."
|
||||
image="/images/feature-performance.png"
|
||||
image_position="right"
|
||||
>}}
|
||||
```
|
||||
|
||||
**With Custom Icon:**
|
||||
```markdown
|
||||
{{< feature
|
||||
title="Secure by Default"
|
||||
description="Enterprise-grade security built into every layer"
|
||||
>}}
|
||||
<svg>...</svg>
|
||||
{{< /feature >}}
|
||||
```
|
||||
|
||||
### features-section
|
||||
|
||||
Wrapper for multiple features with section header.
|
||||
|
||||
**Parameters:**
|
||||
- `title` (string, optional) - Section title
|
||||
- `description` (string, optional) - Section description
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< features-section
|
||||
title="Why Choose Our Platform"
|
||||
description="Everything you need to build and grow your business"
|
||||
>}}
|
||||
|
||||
{{< feature icon="rocket" title="Fast Deployment" description="Deploy in minutes" >}}
|
||||
{{< feature icon="shield" title="Secure" description="Bank-level security" >}}
|
||||
{{< feature icon="chart" title="Analytics" description="Deep insights" >}}
|
||||
|
||||
{{< /features-section >}}
|
||||
```
|
||||
|
||||
### features-list
|
||||
|
||||
Display features in a list format.
|
||||
|
||||
**Parameters:**
|
||||
- `title` (string, optional) - List title
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< features-list title="Key Features" >}}
|
||||
- Real-time collaboration
|
||||
- Advanced analytics
|
||||
- 99.9% uptime SLA
|
||||
- 24/7 customer support
|
||||
- Enterprise SSO
|
||||
- Custom integrations
|
||||
{{< /features-list >}}
|
||||
```
|
||||
|
||||
### benefits-grid
|
||||
|
||||
Display benefits in a grid layout.
|
||||
|
||||
**Parameters:**
|
||||
- `columns` (integer, optional) - Number of columns (default: 3)
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< benefits-grid columns="3" >}}
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"icon": "clock",
|
||||
"title": "Save Time",
|
||||
"description": "Automate repetitive tasks and focus on what matters"
|
||||
},
|
||||
{
|
||||
"icon": "dollar",
|
||||
"title": "Reduce Costs",
|
||||
"description": "Cut operational expenses by up to 50%"
|
||||
},
|
||||
{
|
||||
"icon": "users",
|
||||
"title": "Scale Easily",
|
||||
"description": "Grow from 10 to 10,000 users effortlessly"
|
||||
}
|
||||
]
|
||||
}
|
||||
{{< /benefits-grid >}}
|
||||
```
|
||||
|
||||
### value-card
|
||||
|
||||
Display a value proposition card.
|
||||
|
||||
**Parameters:**
|
||||
- `icon` (string, required) - Icon name
|
||||
- `title` (string, required) - Card title
|
||||
- `description` (string, required) - Card description
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< value-card
|
||||
icon="heart"
|
||||
title="Customer First"
|
||||
description="We put our customers at the center of everything we do"
|
||||
>}}
|
||||
```
|
||||
|
||||
## Social Proof
|
||||
|
||||
### testimonials
|
||||
|
||||
Display customer testimonials in a scrolling carousel.
|
||||
|
||||
**Parameters:**
|
||||
- `title` (string, optional) - Section title
|
||||
- `description` (string, optional) - Section description
|
||||
- `background-color` (string, optional) - Background color
|
||||
- `animate` (boolean, optional) - Enable auto-scroll animation (default: true)
|
||||
|
||||
**Note:** Testimonials data comes from page front matter.
|
||||
|
||||
**Front Matter:**
|
||||
```yaml
|
||||
---
|
||||
title: "Home"
|
||||
testimonials:
|
||||
- name: "Sarah Johnson"
|
||||
title: "CEO, TechCorp"
|
||||
avatar: "/images/avatar-sarah.jpg"
|
||||
quote: "This platform transformed how we work. Highly recommended!"
|
||||
- name: "Michael Chen"
|
||||
title: "CTO, StartupXYZ"
|
||||
avatar: "/images/avatar-michael.jpg"
|
||||
quote: "Amazing product with outstanding support. 5 stars!"
|
||||
- name: "Emma Davis"
|
||||
title: "Product Manager, BigCo"
|
||||
avatar: "/images/avatar-emma.jpg"
|
||||
quote: "Best decision we made this year. Game changer!"
|
||||
---
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< testimonials
|
||||
title="Loved by Teams Worldwide"
|
||||
description="See what our customers have to say"
|
||||
animate="true"
|
||||
>}}
|
||||
```
|
||||
|
||||
### client-logos
|
||||
|
||||
Display client or partner logos.
|
||||
|
||||
**Parameters:**
|
||||
- `title` (string, optional) - Section title
|
||||
- `background` (string, optional) - Background color class
|
||||
|
||||
**Note:** Logos should be passed as inner content in JSON format.
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< client-logos title="Trusted by Industry Leaders" >}}
|
||||
{
|
||||
"logos": [
|
||||
{ "src": "/images/clients/company1.svg", "alt": "Company 1" },
|
||||
{ "src": "/images/clients/company2.svg", "alt": "Company 2" },
|
||||
{ "src": "/images/clients/company3.svg", "alt": "Company 3" },
|
||||
{ "src": "/images/clients/company4.svg", "alt": "Company 4" },
|
||||
{ "src": "/images/clients/company5.svg", "alt": "Company 5" }
|
||||
]
|
||||
}
|
||||
{{< /client-logos >}}
|
||||
```
|
||||
|
||||
### case-study-card
|
||||
|
||||
Display a case study preview card.
|
||||
|
||||
**Parameters:**
|
||||
- `title` (string, required) - Case study title
|
||||
- `company` (string, required) - Company name
|
||||
- `industry` (string, required) - Industry
|
||||
- `result` (string, required) - Key result/metric
|
||||
- `image` (string, required) - Card image
|
||||
- `url` (string, required) - Link to full case study
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< case-study-card
|
||||
title="How Acme Corp Increased Revenue by 300%"
|
||||
company="Acme Corp"
|
||||
industry="E-commerce"
|
||||
result="300% revenue increase"
|
||||
image="/images/case-studies/acme.jpg"
|
||||
url="/case-studies/acme"
|
||||
>}}
|
||||
```
|
||||
|
||||
## Pricing
|
||||
|
||||
### pricing-table-1
|
||||
|
||||
Three-column pricing table with feature lists.
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< pricing-table-1 >}}
|
||||
{
|
||||
"title": "Choose Your Plan",
|
||||
"description": "Start free, upgrade as you grow",
|
||||
"plans": [
|
||||
{
|
||||
"name": "Starter",
|
||||
"description": "Perfect for individuals",
|
||||
"price": "0",
|
||||
"featured": false,
|
||||
"features": [
|
||||
"Up to 10 projects",
|
||||
"Basic analytics",
|
||||
"Email support",
|
||||
"1 GB storage"
|
||||
],
|
||||
"button": {
|
||||
"text": "Start Free",
|
||||
"url": "/signup"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Professional",
|
||||
"description": "For growing teams",
|
||||
"price": "29",
|
||||
"featured": true,
|
||||
"features": [
|
||||
"Unlimited projects",
|
||||
"Advanced analytics",
|
||||
"Priority support",
|
||||
"10 GB storage",
|
||||
"Custom integrations"
|
||||
],
|
||||
"button": {
|
||||
"text": "Get Started",
|
||||
"url": "/signup?plan=pro"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Enterprise",
|
||||
"description": "For large organizations",
|
||||
"price": "99",
|
||||
"featured": false,
|
||||
"features": [
|
||||
"Everything in Pro",
|
||||
"Dedicated support",
|
||||
"Unlimited storage",
|
||||
"Custom contracts",
|
||||
"SLA guarantee"
|
||||
],
|
||||
"button": {
|
||||
"text": "Contact Sales",
|
||||
"url": "/contact"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
{{< /pricing-table-1 >}}
|
||||
```
|
||||
|
||||
### pricing-table-2
|
||||
|
||||
Alternative pricing table design with comparison features.
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< pricing-table-2 >}}
|
||||
{
|
||||
"title": "Flexible Pricing for Every Team",
|
||||
"plans": [
|
||||
{
|
||||
"name": "Basic",
|
||||
"price": "19",
|
||||
"period": "month",
|
||||
"features": [
|
||||
"5 team members",
|
||||
"10 GB storage",
|
||||
"Basic support"
|
||||
],
|
||||
"highlighted": false,
|
||||
"cta": {
|
||||
"text": "Choose Basic",
|
||||
"url": "/signup?plan=basic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Premium",
|
||||
"price": "49",
|
||||
"period": "month",
|
||||
"features": [
|
||||
"Unlimited team members",
|
||||
"100 GB storage",
|
||||
"Priority support",
|
||||
"Advanced features"
|
||||
],
|
||||
"highlighted": true,
|
||||
"cta": {
|
||||
"text": "Choose Premium",
|
||||
"url": "/signup?plan=premium"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
{{< /pricing-table-2 >}}
|
||||
```
|
||||
|
||||
## Team & Company
|
||||
|
||||
### team-member
|
||||
|
||||
Display a team member card.
|
||||
|
||||
**Parameters:**
|
||||
- `name` (string, required) - Team member name
|
||||
- `title` (string, required) - Job title
|
||||
- `image` (string, required) - Profile image path
|
||||
- `bio` (string, optional) - Short biography
|
||||
- `linkedin` (string, optional) - LinkedIn URL
|
||||
- `twitter` (string, optional) - Twitter URL
|
||||
- `github` (string, optional) - GitHub URL
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< team-member
|
||||
name="Jane Doe"
|
||||
title="Chief Technology Officer"
|
||||
image="/images/team/jane.jpg"
|
||||
bio="Jane leads our engineering team with 15 years of experience in SaaS"
|
||||
linkedin="https://linkedin.com/in/janedoe"
|
||||
twitter="https://twitter.com/janedoe"
|
||||
>}}
|
||||
```
|
||||
|
||||
### investor-logo
|
||||
|
||||
Display investor or partner logo.
|
||||
|
||||
**Parameters:**
|
||||
- `src` (string, required) - Logo image path
|
||||
- `alt` (string, required) - Alternative text
|
||||
- `url` (string, optional) - Link URL
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< investor-logo
|
||||
src="/images/investors/vc-firm.svg"
|
||||
alt="VC Firm"
|
||||
url="https://vcfirm.com"
|
||||
>}}
|
||||
```
|
||||
|
||||
### stat
|
||||
|
||||
Display a statistic or metric.
|
||||
|
||||
**Parameters:**
|
||||
- `value` (string, required) - The number/metric
|
||||
- `label` (string, required) - Description label
|
||||
- `icon` (string, optional) - Icon name
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< stat value="10,000+" label="Happy Customers" icon="users" >}}
|
||||
{{< stat value="99.9%" label="Uptime SLA" icon="check" >}}
|
||||
{{< stat value="24/7" label="Support Available" icon="headphones" >}}
|
||||
```
|
||||
|
||||
## Content Components
|
||||
|
||||
### cta
|
||||
|
||||
Call-to-action section.
|
||||
|
||||
**Parameters:**
|
||||
- `title` (string, required) - CTA heading
|
||||
- `description` (string, optional) - CTA description
|
||||
- `button_text` (string, required) - Button text
|
||||
- `button_url` (string, required) - Button link
|
||||
- `background` (string, optional) - Background color/gradient
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< cta
|
||||
title="Ready to Get Started?"
|
||||
description="Join thousands of teams already using our platform"
|
||||
button_text="Start Free Trial"
|
||||
button_url="/signup"
|
||||
background="gradient"
|
||||
>}}
|
||||
```
|
||||
|
||||
### faq
|
||||
|
||||
Frequently Asked Questions accordion.
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< faq >}}
|
||||
{
|
||||
"title": "Frequently Asked Questions",
|
||||
"description": "Find answers to common questions",
|
||||
"questions": [
|
||||
{
|
||||
"question": "How do I get started?",
|
||||
"answer": "Simply sign up for a free account and follow our onboarding guide. You'll be up and running in minutes."
|
||||
},
|
||||
{
|
||||
"question": "What payment methods do you accept?",
|
||||
"answer": "We accept all major credit cards, PayPal, and wire transfers for enterprise customers."
|
||||
},
|
||||
{
|
||||
"question": "Can I cancel anytime?",
|
||||
"answer": "Yes, you can cancel your subscription at any time. No questions asked, no hidden fees."
|
||||
},
|
||||
{
|
||||
"question": "Do you offer refunds?",
|
||||
"answer": "We offer a 30-day money-back guarantee. If you're not satisfied, contact us for a full refund."
|
||||
}
|
||||
]
|
||||
}
|
||||
{{< /faq >}}
|
||||
```
|
||||
|
||||
### toc
|
||||
|
||||
Generate a table of contents from page headings.
|
||||
|
||||
**Parameters:**
|
||||
- None (automatically generates from page content)
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< toc >}}
|
||||
```
|
||||
|
||||
**Custom Title:**
|
||||
```markdown
|
||||
<div class="table-of-contents">
|
||||
<h2>Table of Contents</h2>
|
||||
{{< toc >}}
|
||||
</div>
|
||||
```
|
||||
|
||||
## Utility Shortcodes
|
||||
|
||||
### code
|
||||
|
||||
Enhanced code block with syntax highlighting.
|
||||
|
||||
**Parameters:**
|
||||
- `lang` (string, required) - Programming language
|
||||
- `title` (string, optional) - Code block title
|
||||
- `lineNumbers` (boolean, optional) - Show line numbers (default: true)
|
||||
- `highlight` (string, optional) - Lines to highlight (e.g., "1-3,5")
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< code lang="javascript" title="app.js" lineNumbers="true" highlight="2-4" >}}
|
||||
function greet(name) {
|
||||
return `Hello, ${name}!`;
|
||||
}
|
||||
|
||||
console.log(greet('World'));
|
||||
{{< /code >}}
|
||||
```
|
||||
|
||||
**Without Line Numbers:**
|
||||
```markdown
|
||||
{{< code lang="python" lineNumbers="false" >}}
|
||||
def hello_world():
|
||||
print("Hello, World!")
|
||||
{{< /code >}}
|
||||
```
|
||||
|
||||
### figure
|
||||
|
||||
Enhanced image with caption and optional link.
|
||||
|
||||
**Parameters:**
|
||||
- `src` (string, required) - Image source
|
||||
- `alt` (string, required) - Alternative text
|
||||
- `caption` (string, optional) - Image caption
|
||||
- `link` (string, optional) - Link URL
|
||||
- `width` (string, optional) - Image width
|
||||
- `height` (string, optional) - Image height
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
{{< figure
|
||||
src="/images/architecture-diagram.png"
|
||||
alt="System Architecture"
|
||||
caption="Our microservices architecture overview"
|
||||
width="800"
|
||||
>}}
|
||||
```
|
||||
|
||||
**With Link:**
|
||||
```markdown
|
||||
{{< figure
|
||||
src="/images/product-thumbnail.jpg"
|
||||
alt="Product Screenshot"
|
||||
caption="Click to see full size"
|
||||
link="/images/product-full.jpg"
|
||||
>}}
|
||||
```
|
||||
|
||||
## Advanced Shortcodes
|
||||
|
||||
### Nested Shortcodes
|
||||
|
||||
You can nest shortcodes for complex layouts:
|
||||
|
||||
```markdown
|
||||
{{< section-container background="bg-white" >}}
|
||||
|
||||
{{< features-section title="Our Platform" >}}
|
||||
|
||||
{{< feature
|
||||
icon="zap"
|
||||
title="Fast"
|
||||
description="Lightning fast performance"
|
||||
>}}
|
||||
|
||||
{{< feature
|
||||
icon="lock"
|
||||
title="Secure"
|
||||
description="Enterprise-grade security"
|
||||
>}}
|
||||
|
||||
{{< /features-section >}}
|
||||
|
||||
{{< /section-container >}}
|
||||
```
|
||||
|
||||
### Combining Shortcodes
|
||||
|
||||
Create rich page layouts:
|
||||
|
||||
```markdown
|
||||
{{< hero headline="Welcome" ... >}}
|
||||
|
||||
{{< client-logos title="Trusted by" >}}
|
||||
...
|
||||
{{< /client-logos >}}
|
||||
|
||||
{{< features-section title="Features" >}}
|
||||
...
|
||||
{{< /features-section >}}
|
||||
|
||||
{{< testimonials >}}
|
||||
|
||||
{{< pricing-table-1 >}}
|
||||
...
|
||||
{{< /pricing-table-1 >}}
|
||||
|
||||
{{< faq >}}
|
||||
...
|
||||
{{< /faq >}}
|
||||
|
||||
{{< cta title="Get Started" ... >}}
|
||||
```
|
||||
|
||||
## Usage Tips
|
||||
|
||||
### 1. JSON Formatting
|
||||
|
||||
For shortcodes that accept JSON (pricing, FAQ, client logos):
|
||||
- Use valid JSON syntax
|
||||
- Ensure proper quotes (double quotes for JSON)
|
||||
- Validate JSON before adding to content
|
||||
- Use online JSON validators if needed
|
||||
|
||||
### 2. Images
|
||||
|
||||
Always use proper image paths:
|
||||
- Absolute paths from site root: `/images/photo.jpg`
|
||||
- Or use Hugo's resource management
|
||||
- Optimize images before uploading
|
||||
- Use appropriate formats (WebP, PNG, JPG)
|
||||
|
||||
### 3. Accessibility
|
||||
|
||||
- Always provide `alt` text for images
|
||||
- Use semantic headings in correct order
|
||||
- Ensure sufficient color contrast
|
||||
- Test keyboard navigation
|
||||
|
||||
### 4. Performance
|
||||
|
||||
- Lazy load images when possible
|
||||
- Minimize the number of shortcodes per page
|
||||
- Optimize JSON data structures
|
||||
- Use appropriate image sizes
|
||||
|
||||
### 5. Responsive Design
|
||||
|
||||
All shortcodes are mobile-responsive by default:
|
||||
- Test on multiple screen sizes
|
||||
- Check touch interactions
|
||||
- Verify text readability
|
||||
- Ensure buttons are tappable
|
||||
|
||||
### 6. Customization
|
||||
|
||||
You can override shortcode templates:
|
||||
1. Copy shortcode from `themes/chill-theme/layouts/shortcodes/`
|
||||
2. Paste to `layouts/shortcodes/` in your site
|
||||
3. Modify as needed
|
||||
|
||||
### 7. Testing
|
||||
|
||||
Before deploying:
|
||||
- Preview with `hugo server -D`
|
||||
- Test all interactive elements
|
||||
- Verify links work
|
||||
- Check on mobile devices
|
||||
- Validate HTML output
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Landing Page
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: "Home"
|
||||
layout: single
|
||||
---
|
||||
|
||||
{{< hero ... >}}
|
||||
{{< client-logos ... >}}
|
||||
{{< features-section ... >}}
|
||||
{{< testimonials >}}
|
||||
{{< cta ... >}}
|
||||
```
|
||||
|
||||
### Pricing Page
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: "Pricing"
|
||||
layout: pricing
|
||||
---
|
||||
|
||||
{{< pricing-table-1 >}}
|
||||
...
|
||||
{{< /pricing-table-1 >}}
|
||||
|
||||
{{< faq >}}
|
||||
...
|
||||
{{< /faq >}}
|
||||
|
||||
{{< cta ... >}}
|
||||
```
|
||||
|
||||
### About Page
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: "About Us"
|
||||
layout: company
|
||||
---
|
||||
|
||||
{{< hero ... >}}
|
||||
|
||||
{{< section-container >}}
|
||||
## Our Story
|
||||
...
|
||||
{{< /section-container >}}
|
||||
|
||||
{{< stat ... >}}
|
||||
{{< stat ... >}}
|
||||
{{< stat ... >}}
|
||||
|
||||
{{< team-member ... >}}
|
||||
{{< team-member ... >}}
|
||||
```
|
||||
|
||||
### Feature Page
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: "Features"
|
||||
layout: feature
|
||||
---
|
||||
|
||||
{{< hero ... >}}
|
||||
|
||||
{{< features-section ... >}}
|
||||
{{< feature ... >}}
|
||||
{{< feature ... >}}
|
||||
{{< /features-section >}}
|
||||
|
||||
{{< case-study-card ... >}}
|
||||
|
||||
{{< cta ... >}}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Shortcode Not Rendering
|
||||
|
||||
**Problem**: Shortcode appears as text
|
||||
|
||||
**Solutions**:
|
||||
- Check syntax: `{{<` not `{<`
|
||||
- Verify shortcode name spelling
|
||||
- Ensure shortcode file exists
|
||||
- Check Hugo version compatibility
|
||||
|
||||
### JSON Parse Error
|
||||
|
||||
**Problem**: Error parsing JSON in shortcode
|
||||
|
||||
**Solutions**:
|
||||
- Validate JSON syntax
|
||||
- Use double quotes, not single
|
||||
- Escape special characters
|
||||
- Check for trailing commas
|
||||
|
||||
### Images Not Showing
|
||||
|
||||
**Problem**: Images don't display
|
||||
|
||||
**Solutions**:
|
||||
- Verify image path is correct
|
||||
- Check image exists in `static/` folder
|
||||
- Use correct path format (`/images/...`)
|
||||
- Check file permissions
|
||||
|
||||
### Styling Issues
|
||||
|
||||
**Problem**: Shortcode styling doesn't match
|
||||
|
||||
**Solutions**:
|
||||
- Clear Hugo cache: `hugo --gc`
|
||||
- Rebuild site: `hugo`
|
||||
- Check Tailwind compilation
|
||||
- Verify CSS is loading
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [LAYOUTS.md](LAYOUTS.md) - Layout templates
|
||||
- [CONTENT-CREATION.md](CONTENT-CREATION.md) - Creating content
|
||||
- [STYLING.md](STYLING.md) - Customizing styles
|
||||
- [TROUBLESHOOTING.md](TROUBLESHOOTING.md) - Common issues
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Hugo Shortcodes Documentation](https://gohugo.io/content-management/shortcodes/)
|
||||
- [Creating Custom Shortcodes](https://gohugo.io/templates/shortcode-templates/)
|
||||
- [Theme Shortcode Examples](../exampleSite/content/)
|
||||
@@ -0,0 +1,751 @@
|
||||
# Styling Guide
|
||||
|
||||
Complete guide to styling and customization in the Hugo Saasify Theme. Learn how to customize colors, typography, components, and create your own design system.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Tailwind CSS Integration](#tailwind-css-integration)
|
||||
- [Color System](#color-system)
|
||||
- [Typography](#typography)
|
||||
- [Custom Components](#custom-components)
|
||||
- [Responsive Design](#responsive-design)
|
||||
- [Syntax Highlighting](#syntax-highlighting)
|
||||
- [Customization](#customization)
|
||||
- [Best Practices](#best-practices)
|
||||
|
||||
## Tailwind CSS Integration
|
||||
|
||||
The Hugo Saasify Theme is built with Tailwind CSS v3, providing a utility-first approach to styling.
|
||||
|
||||
### How It Works
|
||||
|
||||
1. **Main CSS File**: `themes/chill-theme/assets/scss/main.scss`
|
||||
2. **Tailwind Config**: `tailwind.config.js` (copied to site root during installation)
|
||||
3. **PostCSS Config**: `postcss.config.js` (copied to site root during installation)
|
||||
4. **Hugo Processing**: Automatic PostCSS compilation
|
||||
5. **Build Stats**: Required for PurgeCSS optimization
|
||||
|
||||
### Configuration File
|
||||
|
||||
**Location**: `tailwind.config.js` (in your site root)
|
||||
|
||||
During installation, you copied this file from `themes/chill-theme/tailwind.config.copy.js` to your site root as `tailwind.config.js`.
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
content: ["./layouts/**/*.html"],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: { /* custom colors */ },
|
||||
secondary: { /* custom colors */ }
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'system-ui', 'sans-serif'],
|
||||
heading: ['Plus Jakarta Sans', 'sans-serif']
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
require('@tailwindcss/forms'),
|
||||
require('@tailwindcss/typography')
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Tailwind Plugins
|
||||
|
||||
The theme includes two official plugins:
|
||||
|
||||
1. **@tailwindcss/forms** - Beautiful form styling
|
||||
2. **@tailwindcss/typography** - Prose content styling
|
||||
|
||||
## Color System
|
||||
|
||||
The theme uses a comprehensive color palette with primary and secondary colors.
|
||||
|
||||
### Primary Colors
|
||||
|
||||
Blue-based palette for main brand elements.
|
||||
|
||||
```javascript
|
||||
primary: {
|
||||
50: '#eef1fc', // Lightest
|
||||
100: '#dde3f9',
|
||||
200: '#bbc7f3',
|
||||
300: '#99abec',
|
||||
400: '#778fe6',
|
||||
500: '#5573df', // Base
|
||||
600: '#425ad6', // Main (default)
|
||||
700: '#3548ab',
|
||||
800: '#283680',
|
||||
900: '#1b2456' // Darkest
|
||||
}
|
||||
```
|
||||
|
||||
### Secondary Colors
|
||||
|
||||
Purple-based palette for accents and highlights.
|
||||
|
||||
```javascript
|
||||
secondary: {
|
||||
50: '#faf5ff', // Lightest
|
||||
100: '#f3e8ff',
|
||||
200: '#e9d5ff',
|
||||
300: '#d8b4fe',
|
||||
400: '#c084fc',
|
||||
500: '#a855f7', // Base
|
||||
600: '#9333ea', // Main (default)
|
||||
700: '#7e22ce',
|
||||
800: '#6b21a8',
|
||||
900: '#581c87' // Darkest
|
||||
}
|
||||
```
|
||||
|
||||
### Using Colors
|
||||
|
||||
**In Templates**:
|
||||
```html
|
||||
<div class="bg-primary-600 text-white">Primary background</div>
|
||||
<div class="text-secondary-600">Secondary text</div>
|
||||
<button class="bg-primary-600 hover:bg-primary-700">Button</button>
|
||||
```
|
||||
|
||||
**In Custom CSS**:
|
||||
```css
|
||||
.custom-element {
|
||||
@apply bg-primary-50 text-primary-900;
|
||||
}
|
||||
```
|
||||
|
||||
### Customizing Colors
|
||||
|
||||
To change the color scheme, edit `tailwind.config.js`:
|
||||
|
||||
```javascript
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#your-color',
|
||||
100: '#your-color',
|
||||
// ... continue for all shades
|
||||
900: '#your-color'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Quick Method** - Use a color palette generator:
|
||||
1. Choose your base color
|
||||
2. Generate shades using tools like [Tailwind Shades](https://tailwindshades.com/)
|
||||
3. Replace values in `tailwind.config.js`
|
||||
|
||||
### Gray Scale
|
||||
|
||||
Default Tailwind gray scale is available:
|
||||
|
||||
```html
|
||||
<div class="bg-gray-50">Light gray background</div>
|
||||
<div class="bg-gray-100">...</div>
|
||||
<!-- ... -->
|
||||
<div class="bg-gray-900">Dark gray background</div>
|
||||
```
|
||||
|
||||
## Typography
|
||||
|
||||
The theme uses two modern typefaces for optimal readability and visual appeal.
|
||||
|
||||
### Font Families
|
||||
|
||||
**Body Text**: Inter
|
||||
- Variable font for optimal loading
|
||||
- Used for all body text, UI elements
|
||||
- Applied to: paragraphs, lists, forms, buttons
|
||||
|
||||
**Headings**: Plus Jakarta Sans
|
||||
- Bold, modern sans-serif
|
||||
- Used for all headings (h1-h6)
|
||||
- Applied to: titles, section headers
|
||||
|
||||
### Font Configuration
|
||||
|
||||
**Tailwind Config**:
|
||||
```javascript
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'system-ui', 'sans-serif'],
|
||||
heading: ['Plus Jakarta Sans', 'sans-serif']
|
||||
}
|
||||
```
|
||||
|
||||
**CSS Application**:
|
||||
```css
|
||||
body {
|
||||
@apply font-sans text-gray-700;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
@apply font-heading font-bold text-gray-900;
|
||||
}
|
||||
```
|
||||
|
||||
### Font Loading
|
||||
|
||||
Fonts are loaded via Google Fonts CDN in the base template:
|
||||
|
||||
```html
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@700;800&display=swap" rel="stylesheet">
|
||||
```
|
||||
|
||||
### Typography Scale
|
||||
|
||||
**Headings**:
|
||||
```html
|
||||
<h1 class="text-4xl md:text-5xl lg:text-6xl">Main Heading</h1>
|
||||
<h2 class="text-3xl md:text-4xl">Section Heading</h2>
|
||||
<h3 class="text-2xl md:text-3xl">Subsection Heading</h3>
|
||||
<h4 class="text-xl md:text-2xl">Small Heading</h4>
|
||||
```
|
||||
|
||||
**Body Text**:
|
||||
```html
|
||||
<p class="text-base">Normal text (16px)</p>
|
||||
<p class="text-lg">Large text (18px)</p>
|
||||
<p class="text-xl">XL text (20px)</p>
|
||||
<p class="text-sm">Small text (14px)</p>
|
||||
```
|
||||
|
||||
### Custom Fonts
|
||||
|
||||
To use different fonts:
|
||||
|
||||
1. **Add Font Files** to `static/fonts/` or use CDN
|
||||
2. **Update Tailwind Config**:
|
||||
```javascript
|
||||
fontFamily: {
|
||||
sans: ['Your Font', 'system-ui', 'sans-serif'],
|
||||
heading: ['Your Heading Font', 'sans-serif']
|
||||
}
|
||||
```
|
||||
3. **Load Font** in baseof.html or CSS
|
||||
|
||||
## Custom Components
|
||||
|
||||
Pre-built component classes for common UI elements.
|
||||
|
||||
### Buttons
|
||||
|
||||
**Primary Button**:
|
||||
```html
|
||||
<a href="#" class="btn-primary">Get Started</a>
|
||||
```
|
||||
|
||||
CSS:
|
||||
```css
|
||||
.btn {
|
||||
@apply inline-flex items-center justify-center px-6 py-3 font-medium transition duration-200 ease-in-out;
|
||||
border-radius: 2rem;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
@apply btn bg-primary-600 text-white hover:bg-primary-700 hover:scale-105;
|
||||
}
|
||||
```
|
||||
|
||||
**Secondary Button**:
|
||||
```html
|
||||
<a href="#" class="btn-secondary">Learn More</a>
|
||||
```
|
||||
|
||||
**Outline Button**:
|
||||
```html
|
||||
<a href="#" class="btn-outline">View Demo</a>
|
||||
```
|
||||
|
||||
### Cards
|
||||
|
||||
**Standard Card**:
|
||||
```html
|
||||
<div class="card">
|
||||
<h3>Card Title</h3>
|
||||
<p>Card content goes here</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
CSS:
|
||||
```css
|
||||
.card {
|
||||
@apply bg-white p-6 transition duration-200 hover:shadow-md;
|
||||
border-radius: 2rem;
|
||||
}
|
||||
```
|
||||
|
||||
### Container
|
||||
|
||||
**Responsive Container**:
|
||||
```html
|
||||
<div class="container">
|
||||
<!-- Content automatically centered with responsive padding -->
|
||||
</div>
|
||||
```
|
||||
|
||||
CSS:
|
||||
```css
|
||||
.container {
|
||||
@apply mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl;
|
||||
}
|
||||
```
|
||||
|
||||
### Sections
|
||||
|
||||
**Section Spacing**:
|
||||
```html
|
||||
<section class="section">
|
||||
<!-- Consistent vertical spacing -->
|
||||
</section>
|
||||
```
|
||||
|
||||
CSS:
|
||||
```css
|
||||
.section {
|
||||
@apply py-16 md:py-24;
|
||||
}
|
||||
```
|
||||
|
||||
### Navigation
|
||||
|
||||
**Nav Links**:
|
||||
```html
|
||||
<a href="#" class="nav-link">Features</a>
|
||||
```
|
||||
|
||||
CSS:
|
||||
```css
|
||||
.nav-link {
|
||||
@apply text-gray-600 hover:text-primary-600 font-bold transition duration-200;
|
||||
}
|
||||
```
|
||||
|
||||
### Grids
|
||||
|
||||
**Feature Grid**:
|
||||
```html
|
||||
<div class="feature-grid">
|
||||
<div>Feature 1</div>
|
||||
<div>Feature 2</div>
|
||||
<div>Feature 3</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
CSS:
|
||||
```css
|
||||
.feature-grid {
|
||||
@apply grid gap-8 md:grid-cols-2 lg:grid-cols-3;
|
||||
}
|
||||
```
|
||||
|
||||
## Responsive Design
|
||||
|
||||
The theme is mobile-first and fully responsive.
|
||||
|
||||
### Breakpoints
|
||||
|
||||
Tailwind's default breakpoints:
|
||||
|
||||
```javascript
|
||||
sm: '640px', // Small devices
|
||||
md: '768px', // Medium devices
|
||||
lg: '1024px', // Large devices
|
||||
xl: '1280px', // Extra large devices
|
||||
2xl: '1536px' // 2X large devices
|
||||
```
|
||||
|
||||
### Responsive Utilities
|
||||
|
||||
**Responsive Visibility**:
|
||||
```html
|
||||
<div class="hidden md:block">Visible on medium screens and up</div>
|
||||
<div class="block md:hidden">Visible only on small screens</div>
|
||||
```
|
||||
|
||||
**Responsive Spacing**:
|
||||
```html
|
||||
<div class="py-8 md:py-12 lg:py-16">
|
||||
Responsive padding
|
||||
</div>
|
||||
```
|
||||
|
||||
**Responsive Grid**:
|
||||
```html
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
<!-- Responsive columns -->
|
||||
</div>
|
||||
```
|
||||
|
||||
**Responsive Text**:
|
||||
```html
|
||||
<h1 class="text-3xl md:text-4xl lg:text-5xl">
|
||||
Responsive heading
|
||||
</h1>
|
||||
```
|
||||
|
||||
### Mobile Menu
|
||||
|
||||
The header includes a responsive mobile menu that automatically adapts to smaller screens.
|
||||
|
||||
## Syntax Highlighting
|
||||
|
||||
Code blocks are styled with custom syntax highlighting.
|
||||
|
||||
### Configuration
|
||||
|
||||
**Hugo Config** (`hugo.toml`):
|
||||
```toml
|
||||
[markup.highlight]
|
||||
noClasses = false
|
||||
lineNos = true
|
||||
codeFences = true
|
||||
guessSyntax = true
|
||||
lineNumbersInTable = true
|
||||
```
|
||||
|
||||
### Highlight Styles
|
||||
|
||||
**Base Styles**:
|
||||
```css
|
||||
.highlight {
|
||||
@apply text-sm font-mono text-gray-200;
|
||||
}
|
||||
```
|
||||
|
||||
**Syntax Colors**:
|
||||
```css
|
||||
/* Keywords */
|
||||
.highlight .k, .highlight .kd {
|
||||
@apply text-purple-400 font-semibold;
|
||||
}
|
||||
|
||||
/* Functions */
|
||||
.highlight .nf, .highlight .nx {
|
||||
@apply text-blue-400;
|
||||
}
|
||||
|
||||
/* Strings */
|
||||
.highlight .s, .highlight .s1, .highlight .s2 {
|
||||
@apply text-green-400;
|
||||
}
|
||||
|
||||
/* Numbers */
|
||||
.highlight .mi, .highlight .mf {
|
||||
@apply text-orange-400;
|
||||
}
|
||||
|
||||
/* Comments */
|
||||
.highlight .c, .highlight .c1, .highlight .cm {
|
||||
@apply text-gray-500 italic;
|
||||
}
|
||||
|
||||
/* Operators */
|
||||
.highlight .o {
|
||||
@apply text-yellow-400;
|
||||
}
|
||||
|
||||
/* Punctuation */
|
||||
.highlight .p {
|
||||
@apply text-gray-400;
|
||||
}
|
||||
```
|
||||
|
||||
### Line Numbers
|
||||
|
||||
Line numbers are styled with table layout for better copy/paste experience:
|
||||
|
||||
```css
|
||||
.highlight table td:first-child {
|
||||
@apply pr-4 text-right select-none text-gray-500 border-r border-gray-700;
|
||||
}
|
||||
```
|
||||
|
||||
### Customizing Syntax Theme
|
||||
|
||||
To use a different color scheme, modify the `.highlight` classes in `assets/scss/main.scss`.
|
||||
|
||||
## Prose Styling
|
||||
|
||||
Blog posts and content pages use prose styling.
|
||||
|
||||
### Prose Classes
|
||||
|
||||
The theme includes custom prose styling:
|
||||
|
||||
```css
|
||||
.prose {
|
||||
@apply max-w-none;
|
||||
}
|
||||
|
||||
.prose h1 {
|
||||
@apply text-4xl mb-8;
|
||||
}
|
||||
|
||||
.prose h2 {
|
||||
@apply text-3xl mt-12 mb-6;
|
||||
}
|
||||
|
||||
.prose h3 {
|
||||
@apply text-2xl mt-8 mb-4;
|
||||
}
|
||||
|
||||
.prose p {
|
||||
@apply text-gray-700 leading-relaxed mb-6;
|
||||
}
|
||||
|
||||
.prose a {
|
||||
@apply text-primary-600 hover:text-primary-700 no-underline;
|
||||
}
|
||||
|
||||
.prose ul, .prose ol {
|
||||
@apply my-6 ml-6;
|
||||
}
|
||||
|
||||
.prose blockquote {
|
||||
@apply border-l-4 border-gray-200 pl-4 italic text-gray-700 my-8;
|
||||
}
|
||||
|
||||
.prose code:not(pre code) {
|
||||
@apply bg-gray-100 text-gray-900 px-1.5 py-0.5 rounded text-sm font-mono;
|
||||
}
|
||||
```
|
||||
|
||||
### Using Prose
|
||||
|
||||
Wrap content in prose class:
|
||||
|
||||
```html
|
||||
<article class="prose prose-lg">
|
||||
{{ .Content }}
|
||||
</article>
|
||||
```
|
||||
|
||||
## Customization
|
||||
|
||||
### Adding Custom CSS
|
||||
|
||||
1. **Create Custom CSS File**:
|
||||
`static/css/custom.css`
|
||||
|
||||
```css
|
||||
/* Your custom styles */
|
||||
.my-custom-class {
|
||||
background: linear-gradient(to right, #your-colors);
|
||||
}
|
||||
```
|
||||
|
||||
2. **Add to Configuration**:
|
||||
```toml
|
||||
[params]
|
||||
customCSS = ["css/custom.css"]
|
||||
```
|
||||
|
||||
### Extending Tailwind
|
||||
|
||||
**Add to `tailwind.config.js`**:
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
theme: {
|
||||
extend: {
|
||||
// Custom spacing
|
||||
spacing: {
|
||||
'128': '32rem',
|
||||
'144': '36rem'
|
||||
},
|
||||
// Custom colors
|
||||
colors: {
|
||||
'brand': '#your-color'
|
||||
},
|
||||
// Custom border radius
|
||||
borderRadius: {
|
||||
'xl': '1.5rem',
|
||||
'2xl': '2rem'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Overriding Component Styles
|
||||
|
||||
To override existing components:
|
||||
|
||||
1. **Copy Original** from `themes/.../assets/scss/main.scss`
|
||||
2. **Add to Your CSS** in project root `assets/css/custom.css`
|
||||
3. **Import After Main** in your build process
|
||||
|
||||
Or use `@layer` directive:
|
||||
|
||||
```css
|
||||
@layer components {
|
||||
.btn-primary {
|
||||
@apply bg-red-600 hover:bg-red-700;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Custom Color Scheme
|
||||
|
||||
Complete color scheme override:
|
||||
|
||||
```javascript
|
||||
// tailwind.config.js in your site root
|
||||
module.exports = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#f0f9ff',
|
||||
100: '#e0f2fe',
|
||||
// ... your colors
|
||||
900: '#0c4a6e'
|
||||
},
|
||||
secondary: {
|
||||
// ... your secondary palette
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Dark Mode Support
|
||||
|
||||
To add dark mode support:
|
||||
|
||||
1. **Enable in Tailwind Config**:
|
||||
```javascript
|
||||
module.exports = {
|
||||
darkMode: 'class', // or 'media'
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
2. **Add Dark Variants**:
|
||||
```html
|
||||
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
|
||||
Content
|
||||
</div>
|
||||
```
|
||||
|
||||
3. **Toggle Script** (add to baseof.html):
|
||||
```javascript
|
||||
// Dark mode toggle logic
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Use Tailwind Utilities First
|
||||
|
||||
Prefer Tailwind utilities over custom CSS:
|
||||
|
||||
```html
|
||||
<!-- Good -->
|
||||
<div class="flex items-center justify-between p-4 bg-white rounded-lg shadow">
|
||||
|
||||
<!-- Avoid -->
|
||||
<div class="custom-header" style="...">
|
||||
```
|
||||
|
||||
### 2. Extract Repeated Patterns
|
||||
|
||||
For repeated patterns, create component classes:
|
||||
|
||||
```css
|
||||
@layer components {
|
||||
.product-card {
|
||||
@apply bg-white rounded-2xl p-6 shadow-sm hover:shadow-lg transition;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Maintain Consistency
|
||||
|
||||
Use the theme's design tokens:
|
||||
- Colors from the palette
|
||||
- Spacing from the scale
|
||||
- Typography from defined classes
|
||||
|
||||
### 4. Optimize for Performance
|
||||
|
||||
- Use PurgeCSS (automatic with Hugo)
|
||||
- Minimize custom CSS
|
||||
- Avoid `!important`
|
||||
- Use efficient selectors
|
||||
|
||||
### 5. Accessibility
|
||||
|
||||
- Maintain color contrast ratios (WCAG AA minimum)
|
||||
- Use semantic HTML
|
||||
- Include focus states
|
||||
- Test with keyboard navigation
|
||||
|
||||
### 6. Mobile-First
|
||||
|
||||
Build mobile layouts first:
|
||||
|
||||
```html
|
||||
<!-- Mobile first, then desktop -->
|
||||
<div class="text-sm md:text-base lg:text-lg">
|
||||
```
|
||||
|
||||
### 7. Test Across Browsers
|
||||
|
||||
- Chrome/Edge (Chromium)
|
||||
- Firefox
|
||||
- Safari
|
||||
- Mobile browsers
|
||||
|
||||
## Testing Styles
|
||||
|
||||
### Local Development
|
||||
|
||||
```bash
|
||||
# Watch for changes
|
||||
hugo server -D
|
||||
|
||||
# Clear cache if styles don't update
|
||||
hugo --gc
|
||||
hugo server -D
|
||||
```
|
||||
|
||||
### Build for Production
|
||||
|
||||
```bash
|
||||
# Build with minification
|
||||
hugo --minify
|
||||
|
||||
# Check file sizes
|
||||
ls -lh public/css/
|
||||
```
|
||||
|
||||
### Browser Testing
|
||||
|
||||
1. Chrome DevTools - Responsive mode
|
||||
2. Firefox Developer Tools
|
||||
3. Safari Web Inspector
|
||||
4. Real device testing
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [CONFIGURATION.md](CONFIGURATION.md) - Theme configuration
|
||||
- [LAYOUTS.md](LAYOUTS.md) - Layout templates
|
||||
- [CONTENT-CREATION.md](CONTENT-CREATION.md) - Creating content
|
||||
- [TROUBLESHOOTING.md](TROUBLESHOOTING.md) - Common issues
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Tailwind CSS Documentation](https://tailwindcss.com/docs)
|
||||
- [Tailwind CSS Typography Plugin](https://tailwindcss.com/docs/typography-plugin)
|
||||
- [Hugo Asset Processing](https://gohugo.io/hugo-pipes/)
|
||||
- [PostCSS Documentation](https://postcss.org/)
|
||||
@@ -0,0 +1,895 @@
|
||||
# Troubleshooting Guide
|
||||
|
||||
Common issues and solutions when working with the Hugo Saasify Theme. Find quick fixes for installation, build, styling, content, deployment, and performance problems.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Installation Issues](#installation-issues)
|
||||
- [Build Errors](#build-errors)
|
||||
- [Styling Problems](#styling-problems)
|
||||
- [Content Issues](#content-issues)
|
||||
- [Deployment Problems](#deployment-problems)
|
||||
- [Performance Issues](#performance-issues)
|
||||
- [Browser Compatibility](#browser-compatibility)
|
||||
- [Getting Help](#getting-help)
|
||||
|
||||
## Installation Issues
|
||||
|
||||
### Theme Not Found
|
||||
|
||||
**Problem**: Hugo can't find the theme
|
||||
|
||||
```
|
||||
Error: unable to locate theme directory "chill-theme"
|
||||
```
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Verify theme directory exists**:
|
||||
```bash
|
||||
ls themes/chill-theme
|
||||
```
|
||||
|
||||
2. **Check theme name in config**:
|
||||
```toml
|
||||
# hugo.toml
|
||||
theme = "chill-theme" # Must match directory name exactly
|
||||
```
|
||||
|
||||
3. **If using Git submodule, initialize it**:
|
||||
```bash
|
||||
git submodule init
|
||||
git submodule update --recursive
|
||||
```
|
||||
|
||||
4. **Check directory structure**:
|
||||
```bash
|
||||
# Should show theme files
|
||||
ls -la themes/chill-theme/layouts/
|
||||
```
|
||||
|
||||
### Hugo Extended Not Installed
|
||||
|
||||
**Problem**: Error about Hugo Extended being required
|
||||
|
||||
```
|
||||
Error: this theme requires Hugo Extended
|
||||
```
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check your Hugo version**:
|
||||
```bash
|
||||
hugo version
|
||||
```
|
||||
|
||||
Expected output should include "extended":
|
||||
```
|
||||
hugo v0.120.0+extended darwin/amd64
|
||||
```
|
||||
|
||||
2. **Install Hugo Extended**:
|
||||
- Visit [Hugo Releases](https://github.com/gohugoio/hugo/releases)
|
||||
- Download version with "extended" in the name
|
||||
- Install and verify
|
||||
|
||||
3. **On macOS with Homebrew**:
|
||||
```bash
|
||||
brew install hugo
|
||||
```
|
||||
|
||||
### Submodule Empty
|
||||
|
||||
**Problem**: Theme directory exists but is empty
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Update submodules**:
|
||||
```bash
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
2. **If still empty, remove and re-add**:
|
||||
```bash
|
||||
git submodule deinit -f themes/chill-theme
|
||||
rm -rf .git/modules/themes/chill-theme
|
||||
git rm -f themes/chill-theme
|
||||
git submodule add https://github.com/chaoming/chill-theme.git themes/chill-theme
|
||||
```
|
||||
|
||||
### npm Dependencies Failed
|
||||
|
||||
**Problem**: npm install fails
|
||||
|
||||
```
|
||||
npm ERR! code ENOENT
|
||||
```
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check Node.js is installed**:
|
||||
```bash
|
||||
node --version
|
||||
npm --version
|
||||
```
|
||||
|
||||
2. **Ensure config files are copied to site root**:
|
||||
```bash
|
||||
cp themes/chill-theme/package.json .
|
||||
cp themes/chill-theme/postcss.config.js .
|
||||
cp themes/chill-theme/tailwind.config.copy.js ./tailwind.config.js
|
||||
```
|
||||
|
||||
3. **Clear npm cache**:
|
||||
```bash
|
||||
npm cache clean --force
|
||||
```
|
||||
|
||||
4. **Delete and reinstall**:
|
||||
```bash
|
||||
rm -rf node_modules package-lock.json
|
||||
npm install
|
||||
```
|
||||
|
||||
5. **Use different npm registry** (if blocked):
|
||||
```bash
|
||||
npm config set registry https://registry.npmjs.org/
|
||||
npm install
|
||||
```
|
||||
|
||||
## Build Errors
|
||||
|
||||
### Tailwind CSS Not Processing
|
||||
|
||||
**Problem**: Site loads without styling
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Enable build stats** in `hugo.toml`:
|
||||
```toml
|
||||
[build]
|
||||
writeStats = true
|
||||
|
||||
[build.buildStats]
|
||||
enable = true
|
||||
```
|
||||
|
||||
2. **Clear Hugo cache**:
|
||||
```bash
|
||||
hugo --gc
|
||||
```
|
||||
|
||||
3. **Verify Tailwind config exists**:
|
||||
```bash
|
||||
ls themes/chill-theme/tailwind.config.js
|
||||
```
|
||||
|
||||
4. **Rebuild from clean state**:
|
||||
```bash
|
||||
rm -rf public resources
|
||||
hugo server -D
|
||||
```
|
||||
|
||||
### Template Errors
|
||||
|
||||
**Problem**: Error in template execution
|
||||
|
||||
```
|
||||
Error: error calling partial: template: partials/header.html...
|
||||
```
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check the error message** - it usually points to the specific line
|
||||
2. **Common causes**:
|
||||
- Missing closing tags
|
||||
- Incorrect variable names
|
||||
- Missing required parameters
|
||||
- Syntax errors in shortcodes
|
||||
|
||||
3. **Validate configuration**:
|
||||
```bash
|
||||
hugo config
|
||||
```
|
||||
|
||||
4. **Test with minimal config**:
|
||||
- Copy `exampleSite/hugo.toml`
|
||||
- Gradually add your customizations
|
||||
|
||||
### Shortcode Errors
|
||||
|
||||
**Problem**: Shortcode fails to render
|
||||
|
||||
```
|
||||
Error: failed to render shortcode "pricing-table-1"
|
||||
```
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check JSON syntax** (for shortcodes accepting JSON):
|
||||
- Use double quotes, not single quotes
|
||||
- No trailing commas
|
||||
- Valid JSON structure
|
||||
- Use JSON validator online
|
||||
|
||||
2. **Verify shortcode exists**:
|
||||
```bash
|
||||
ls themes/chill-theme/layouts/shortcodes/pricing-table-1.html
|
||||
```
|
||||
|
||||
3. **Check shortcode syntax**:
|
||||
```markdown
|
||||
# Correct
|
||||
{{< shortcode-name >}}
|
||||
|
||||
# Incorrect
|
||||
{< shortcode-name >} # Missing one brace
|
||||
{{<shortcode-name>}} # Missing spaces
|
||||
```
|
||||
|
||||
### Build Fails in CI/CD
|
||||
|
||||
**Problem**: Builds work locally but fail in CI
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Match Hugo versions**:
|
||||
- Check local: `hugo version`
|
||||
- Set in CI config: `HUGO_VERSION=0.120.0`
|
||||
|
||||
2. **Install theme dependencies**:
|
||||
```yaml
|
||||
# GitHub Actions example
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
cp themes/chill-theme/package.json .
|
||||
cp themes/chill-theme/postcss.config.js .
|
||||
cp themes/chill-theme/tailwind.config.copy.js ./tailwind.config.js
|
||||
npm install
|
||||
```
|
||||
|
||||
3. **Check environment variables**:
|
||||
- Verify all required env vars are set
|
||||
- Check for typos in variable names
|
||||
|
||||
4. **Review build logs**:
|
||||
- Look for specific error messages
|
||||
- Check file paths are correct
|
||||
- Verify permissions
|
||||
|
||||
## Styling Problems
|
||||
|
||||
### Custom CSS Not Loading
|
||||
|
||||
**Problem**: Custom CSS changes don't appear
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Clear browser cache**:
|
||||
- Hard refresh: Ctrl+Shift+R (Windows/Linux) or Cmd+Shift+R (Mac)
|
||||
- Or use incognito/private mode
|
||||
|
||||
2. **Verify CSS file path**:
|
||||
```toml
|
||||
[params]
|
||||
customCSS = ["css/custom.css"] # File must be in static/css/
|
||||
```
|
||||
|
||||
3. **Check file exists**:
|
||||
```bash
|
||||
ls static/css/custom.css
|
||||
```
|
||||
|
||||
4. **Clear Hugo cache**:
|
||||
```bash
|
||||
hugo --gc
|
||||
rm -rf resources
|
||||
hugo server -D
|
||||
```
|
||||
|
||||
### Tailwind Classes Not Working
|
||||
|
||||
**Problem**: Tailwind utility classes have no effect
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check class is in content paths**:
|
||||
```javascript
|
||||
// tailwind.config.js
|
||||
content: ["./layouts/**/*.html"]
|
||||
```
|
||||
|
||||
2. **Avoid dynamic class names**:
|
||||
```html
|
||||
<!-- Don't do this -->
|
||||
<div class="text-{{ .Color }}-600">
|
||||
|
||||
<!-- Do this instead -->
|
||||
<div class="{{ if eq .Color "blue" }}text-blue-600{{ end }}">
|
||||
```
|
||||
|
||||
3. **Rebuild site**:
|
||||
```bash
|
||||
hugo --gc
|
||||
hugo
|
||||
```
|
||||
|
||||
4. **Check Tailwind version compatibility**:
|
||||
```bash
|
||||
npm list tailwindcss
|
||||
```
|
||||
|
||||
### Colors Not Matching Design
|
||||
|
||||
**Problem**: Colors appear different than expected
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check color values in `tailwind.config.js`**:
|
||||
```javascript
|
||||
colors: {
|
||||
primary: {
|
||||
600: '#425ad6', // Your primary color
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Verify you're using correct shade**:
|
||||
```html
|
||||
<div class="bg-primary-600"> <!-- Not bg-primary -->
|
||||
```
|
||||
|
||||
3. **Check for color overrides** in custom CSS
|
||||
|
||||
4. **Test in different browsers** to rule out rendering differences
|
||||
|
||||
### Responsive Design Issues
|
||||
|
||||
**Problem**: Layout broken on mobile/tablet
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Test with DevTools**:
|
||||
- Open Chrome DevTools (F12)
|
||||
- Toggle device toolbar (Ctrl+Shift+M)
|
||||
- Test various screen sizes
|
||||
|
||||
2. **Check responsive classes**:
|
||||
```html
|
||||
<!-- Use responsive prefixes -->
|
||||
<div class="text-sm md:text-base lg:text-lg">
|
||||
```
|
||||
|
||||
3. **Verify viewport meta tag** (should be in baseof.html):
|
||||
```html
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
```
|
||||
|
||||
4. **Test breakpoints**:
|
||||
- sm: 640px
|
||||
- md: 768px
|
||||
- lg: 1024px
|
||||
- xl: 1280px
|
||||
|
||||
## Content Issues
|
||||
|
||||
### Page Not Rendering
|
||||
|
||||
**Problem**: Page exists but shows 404
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check front matter**:
|
||||
```yaml
|
||||
---
|
||||
title: "My Page"
|
||||
draft: false # Make sure this is false
|
||||
---
|
||||
```
|
||||
|
||||
2. **Verify file location**:
|
||||
```bash
|
||||
ls content/my-page.md
|
||||
```
|
||||
|
||||
3. **Check URL structure**:
|
||||
- `content/about.md` → `/about/`
|
||||
- `content/blog/post.md` → `/blog/post/`
|
||||
|
||||
4. **Restart server**:
|
||||
```bash
|
||||
hugo server -D # -D shows drafts
|
||||
```
|
||||
|
||||
### Images Not Displaying
|
||||
|
||||
**Problem**: Images don't show on page
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check file path**:
|
||||
```markdown
|
||||
# Correct - absolute from static/
|
||||

|
||||
|
||||
# Incorrect - relative path
|
||||

|
||||
```
|
||||
|
||||
2. **Verify file exists**:
|
||||
```bash
|
||||
ls static/images/photo.jpg
|
||||
```
|
||||
|
||||
3. **Check file permissions**:
|
||||
```bash
|
||||
chmod 644 static/images/photo.jpg
|
||||
```
|
||||
|
||||
4. **Test URL directly**:
|
||||
- Visit `http://localhost:1313/images/photo.jpg`
|
||||
- Should display the image
|
||||
|
||||
5. **Check file extension** matches exactly (case-sensitive on some systems)
|
||||
|
||||
### Shortcode Shows as Text
|
||||
|
||||
**Problem**: Shortcode appears as plain text instead of rendering
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check syntax**:
|
||||
```markdown
|
||||
# Correct
|
||||
{{< shortcode >}}
|
||||
|
||||
# Incorrect
|
||||
{{ < shortcode > }}
|
||||
{< shortcode >}
|
||||
```
|
||||
|
||||
2. **Verify shortcode exists**:
|
||||
```bash
|
||||
ls themes/chill-theme/layouts/shortcodes/
|
||||
```
|
||||
|
||||
3. **Check if content uses correct format**:
|
||||
- Markdown files: Use `{{< >}}`
|
||||
- HTML files: Use `{{ .Inner }}`
|
||||
|
||||
### Taxonomy Pages Empty
|
||||
|
||||
**Problem**: Category or tag pages show no posts
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Enable taxonomies** in `hugo.toml`:
|
||||
```toml
|
||||
[taxonomies]
|
||||
category = 'categories'
|
||||
tag = 'tags'
|
||||
```
|
||||
|
||||
2. **Check front matter**:
|
||||
```yaml
|
||||
categories: ["Technology"] # Use array, not string
|
||||
tags: ["Hugo", "Tutorial"]
|
||||
```
|
||||
|
||||
3. **Verify taxonomy matches config**:
|
||||
```toml
|
||||
# If you have:
|
||||
[taxonomies]
|
||||
category = 'categories'
|
||||
|
||||
# Use in front matter:
|
||||
categories: ["Tech"] # Not category:
|
||||
```
|
||||
|
||||
## Deployment Problems
|
||||
|
||||
### Build Fails on Platform
|
||||
|
||||
**Problem**: Build works locally but fails on Netlify/Vercel/etc.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Set Hugo version**:
|
||||
|
||||
Netlify:
|
||||
```toml
|
||||
# netlify.toml
|
||||
[build.environment]
|
||||
HUGO_VERSION = "0.120.0"
|
||||
```
|
||||
|
||||
Vercel:
|
||||
```json
|
||||
// vercel.json
|
||||
{
|
||||
"build": {
|
||||
"env": {
|
||||
"HUGO_VERSION": "0.120.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Install theme dependencies**:
|
||||
|
||||
Add to build command:
|
||||
```bash
|
||||
cp themes/chill-theme/package.json . && cp themes/chill-theme/postcss.config.js . && cp themes/chill-theme/tailwind.config.copy.js ./tailwind.config.js && npm install && hugo --minify
|
||||
```
|
||||
|
||||
3. **Check environment variables** are set in platform UI
|
||||
|
||||
### Assets Not Loading After Deploy
|
||||
|
||||
**Problem**: CSS/JS/images don't load on deployed site
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Verify baseURL** in `hugo.toml`:
|
||||
```toml
|
||||
baseURL = "https://yourdomain.com/" # Must match your domain
|
||||
```
|
||||
|
||||
2. **Use absolute paths**:
|
||||
```html
|
||||
<!-- Correct -->
|
||||
<img src="/images/logo.svg">
|
||||
|
||||
<!-- Incorrect -->
|
||||
<img src="images/logo.svg">
|
||||
```
|
||||
|
||||
3. **Check CDN/cache**:
|
||||
- Clear CDN cache
|
||||
- Wait for propagation
|
||||
- Hard refresh browser
|
||||
|
||||
4. **Verify build output**:
|
||||
```bash
|
||||
# Check public/ directory
|
||||
ls -la public/css/
|
||||
ls -la public/images/
|
||||
```
|
||||
|
||||
### SSL Certificate Issues
|
||||
|
||||
**Problem**: HTTPS not working or certificate errors
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Wait for provisioning** (can take 24-48 hours)
|
||||
|
||||
2. **Check DNS configuration**:
|
||||
- A record points to correct IP
|
||||
- CNAME points to correct host
|
||||
|
||||
3. **Force HTTPS** in platform settings
|
||||
|
||||
4. **Clear browser SSL cache**
|
||||
|
||||
### 404 on Deployed Site
|
||||
|
||||
**Problem**: Pages work locally but 404 on deployed site
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check baseURL** includes trailing slash:
|
||||
```toml
|
||||
baseURL = "https://example.com/" # Note the /
|
||||
```
|
||||
|
||||
2. **Verify case sensitivity**:
|
||||
- URLs are case-sensitive on most servers
|
||||
- Use lowercase for consistency
|
||||
|
||||
3. **Check redirects** (if you have them):
|
||||
- Verify redirect rules are correct
|
||||
- Check for infinite redirect loops
|
||||
|
||||
## Performance Issues
|
||||
|
||||
### Slow Build Times
|
||||
|
||||
**Problem**: Site takes too long to build
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Enable caching**:
|
||||
```toml
|
||||
[caches]
|
||||
[caches.images]
|
||||
dir = ":resourceDir/_gen"
|
||||
maxAge = "1440h"
|
||||
```
|
||||
|
||||
2. **Optimize images** before adding:
|
||||
- Compress images
|
||||
- Reduce dimensions
|
||||
- Use appropriate formats
|
||||
|
||||
3. **Limit content during development**:
|
||||
```bash
|
||||
hugo server -D --buildFuture=false --buildExpired=false
|
||||
```
|
||||
|
||||
4. **Check for template loops**:
|
||||
- Review custom templates
|
||||
- Look for inefficient queries
|
||||
|
||||
### Site Loads Slowly
|
||||
|
||||
**Problem**: Pages take long time to load in browser
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Enable minification**:
|
||||
```bash
|
||||
hugo --minify
|
||||
```
|
||||
|
||||
2. **Optimize images**:
|
||||
- Compress all images
|
||||
- Use WebP format
|
||||
- Implement lazy loading
|
||||
|
||||
3. **Use CDN** for static assets
|
||||
|
||||
4. **Enable caching** on server:
|
||||
```nginx
|
||||
# Nginx example
|
||||
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
|
||||
expires 1y;
|
||||
}
|
||||
```
|
||||
|
||||
5. **Run Lighthouse audit**:
|
||||
- Open Chrome DevTools
|
||||
- Go to Lighthouse tab
|
||||
- Run performance audit
|
||||
- Follow recommendations
|
||||
|
||||
### Large CSS File
|
||||
|
||||
**Problem**: Generated CSS is too large
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Verify PurgeCSS is working**:
|
||||
```bash
|
||||
# Check file size
|
||||
ls -lh public/css/*.css
|
||||
```
|
||||
|
||||
2. **Ensure build stats enabled**:
|
||||
```toml
|
||||
[build]
|
||||
writeStats = true
|
||||
```
|
||||
|
||||
3. **Check content paths** in `tailwind.config.js`:
|
||||
```javascript
|
||||
content: ["./layouts/**/*.html"]
|
||||
```
|
||||
|
||||
## Browser Compatibility
|
||||
|
||||
### Works in Chrome, Not Safari
|
||||
|
||||
**Problem**: Site works in Chrome but has issues in Safari
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check for unsupported CSS**:
|
||||
- Avoid bleeding-edge features
|
||||
- Test CSS properties on [Can I Use](https://caniuse.com/)
|
||||
|
||||
2. **Add vendor prefixes** if needed:
|
||||
```css
|
||||
-webkit-transition: all 0.3s;
|
||||
transition: all 0.3s;
|
||||
```
|
||||
|
||||
3. **Test in multiple browsers**:
|
||||
- Chrome
|
||||
- Firefox
|
||||
- Safari
|
||||
- Edge
|
||||
|
||||
### JavaScript Errors in IE11
|
||||
|
||||
**Problem**: Site broken in Internet Explorer
|
||||
|
||||
**Note**: IE11 is deprecated. Modern browsers only.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Display upgrade message** for old browsers
|
||||
2. **Focus on modern browsers** (Chrome, Firefox, Safari, Edge)
|
||||
3. **IE11 usage is <1%** globally - consider if support is needed
|
||||
|
||||
## Getting Help
|
||||
|
||||
### Before Asking for Help
|
||||
|
||||
1. **Check this guide** for your issue
|
||||
2. **Review documentation**:
|
||||
- [INSTALLATION.md](INSTALLATION.md)
|
||||
- [CONFIGURATION.md](CONFIGURATION.md)
|
||||
- [LAYOUTS.md](LAYOUTS.md)
|
||||
- [SHORTCODES.md](SHORTCODES.md)
|
||||
3. **Search existing issues** on GitHub
|
||||
4. **Try example site** to isolate problem
|
||||
|
||||
### Gathering Information
|
||||
|
||||
When reporting issues, include:
|
||||
|
||||
1. **Hugo version**:
|
||||
```bash
|
||||
hugo version
|
||||
```
|
||||
|
||||
2. **Operating system**:
|
||||
```bash
|
||||
uname -a # Linux/Mac
|
||||
# or
|
||||
ver # Windows
|
||||
```
|
||||
|
||||
3. **Error messages** (complete output)
|
||||
|
||||
4. **Configuration** (relevant parts of `hugo.toml`)
|
||||
|
||||
5. **Steps to reproduce**:
|
||||
- What you did
|
||||
- What you expected
|
||||
- What actually happened
|
||||
|
||||
6. **Minimal reproduction**:
|
||||
- Simplest case that shows the problem
|
||||
- Remove unrelated code/config
|
||||
|
||||
### Where to Get Help
|
||||
|
||||
1. **Documentation**: Check all docs in `/docs` directory
|
||||
|
||||
2. **Example Site**: Review working examples in `/exampleSite`
|
||||
|
||||
3. **GitHub Issues**:
|
||||
- Search: [Existing Issues](https://github.com/chaoming/chill-theme/issues)
|
||||
- Create: [New Issue](https://github.com/chaoming/chill-theme/issues/new)
|
||||
|
||||
4. **Hugo Community**:
|
||||
- [Hugo Discourse](https://discourse.gohugo.io/)
|
||||
- [Hugo Documentation](https://gohugo.io/documentation/)
|
||||
|
||||
5. **Stack Overflow**:
|
||||
- Tag: `hugo`, `hugo-theme`
|
||||
|
||||
### Creating a Good Issue Report
|
||||
|
||||
**Template**:
|
||||
|
||||
```markdown
|
||||
## Description
|
||||
Brief description of the problem
|
||||
|
||||
## Environment
|
||||
- Hugo version: 0.120.0+extended
|
||||
- OS: macOS 14.0
|
||||
- Theme version: main branch
|
||||
|
||||
## Steps to Reproduce
|
||||
1. Step one
|
||||
2. Step two
|
||||
3. Step three
|
||||
|
||||
## Expected Behavior
|
||||
What should happen
|
||||
|
||||
## Actual Behavior
|
||||
What actually happens
|
||||
|
||||
## Error Messages
|
||||
```
|
||||
Paste error messages here
|
||||
```
|
||||
|
||||
## Configuration
|
||||
```toml
|
||||
Relevant parts of hugo.toml
|
||||
```
|
||||
|
||||
## Additional Context
|
||||
Any other relevant information
|
||||
```
|
||||
|
||||
## Common Error Messages
|
||||
|
||||
### "Page Not Found"
|
||||
|
||||
**Cause**: Content file doesn't exist or is draft
|
||||
|
||||
**Fix**:
|
||||
- Check file exists
|
||||
- Verify `draft: false`
|
||||
- Restart server
|
||||
|
||||
### "Template Not Found"
|
||||
|
||||
**Cause**: Missing or misnamed template file
|
||||
|
||||
**Fix**:
|
||||
- Check template file exists
|
||||
- Verify layout name in front matter
|
||||
- Check template lookup order
|
||||
|
||||
### "Failed to Process"
|
||||
|
||||
**Cause**: CSS/Asset processing error
|
||||
|
||||
**Fix**:
|
||||
- Check PostCSS configuration
|
||||
- Verify Hugo Extended installed
|
||||
- Review asset file syntax
|
||||
|
||||
### "Submodule Not Found"
|
||||
|
||||
**Cause**: Git submodule not initialized
|
||||
|
||||
**Fix**:
|
||||
```bash
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
## Quick Fixes Checklist
|
||||
|
||||
When something isn't working:
|
||||
|
||||
- [ ] Restart Hugo server
|
||||
- [ ] Clear browser cache (Ctrl+Shift+R)
|
||||
- [ ] Clear Hugo cache (`hugo --gc`)
|
||||
- [ ] Delete `public/` and `resources/` directories
|
||||
- [ ] Verify Hugo version (`hugo version`)
|
||||
- [ ] Check `hugo.toml` syntax
|
||||
- [ ] Review error messages carefully
|
||||
- [ ] Test with example site configuration
|
||||
- [ ] Check file permissions
|
||||
- [ ] Verify file paths are correct
|
||||
|
||||
## Prevention Best Practices
|
||||
|
||||
Avoid issues before they happen:
|
||||
|
||||
1. **Use Version Control**: Commit working states
|
||||
2. **Test Locally**: Before deploying
|
||||
3. **Keep Updated**: Update Hugo and dependencies
|
||||
4. **Follow Documentation**: Don't guess
|
||||
5. **Start Simple**: Add complexity gradually
|
||||
6. **Backup Configuration**: Save working configs
|
||||
7. **Use Example Site**: Reference working examples
|
||||
8. **Read Error Messages**: They usually tell you what's wrong
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [INSTALLATION.md](INSTALLATION.md) - Installation guide
|
||||
- [CONFIGURATION.md](CONFIGURATION.md) - Configuration options
|
||||
- [DEPLOYMENT.md](DEPLOYMENT.md) - Deployment guides
|
||||
- [Hugo Troubleshooting](https://gohugo.io/troubleshooting/)
|
||||
|
||||
## Still Stuck?
|
||||
|
||||
If you've tried everything and still have issues:
|
||||
|
||||
1. **Create minimal reproduction** - Simplest case showing problem
|
||||
2. **Open GitHub issue** with all relevant information
|
||||
3. **Be patient** - Maintainers are volunteers
|
||||
4. **Be detailed** - More info = faster resolution
|
||||
5. **Follow up** - Respond to questions
|
||||
|
||||
Remember: Most issues have been encountered before. Search first, then ask.
|
||||
@@ -0,0 +1,155 @@
|
||||
# Simplified Chinese translations for Hugo Saasify Theme (Example)
|
||||
# Copy this file to your site's i18n directory as zh-cn.toml and customize as needed
|
||||
# 简体中文翻译示例文件
|
||||
|
||||
# 常用UI翻译
|
||||
[readMore]
|
||||
other = "阅读更多"
|
||||
|
||||
[readTime]
|
||||
other = "分钟阅读"
|
||||
|
||||
[published]
|
||||
other = "发布于"
|
||||
|
||||
[updated]
|
||||
other = "更新于"
|
||||
|
||||
[by]
|
||||
other = "作者"
|
||||
|
||||
[shareOn]
|
||||
other = "分享到"
|
||||
|
||||
[relatedPosts]
|
||||
other = "相关文章"
|
||||
|
||||
[categories]
|
||||
other = "分类"
|
||||
|
||||
[tags]
|
||||
other = "标签"
|
||||
|
||||
[allPosts]
|
||||
other = "所有文章"
|
||||
|
||||
[search]
|
||||
other = "搜索"
|
||||
|
||||
[searchPlaceholder]
|
||||
other = "搜索文章..."
|
||||
|
||||
[noResults]
|
||||
other = "未找到结果"
|
||||
|
||||
[backToHome]
|
||||
other = "返回首页"
|
||||
|
||||
[404Title]
|
||||
other = "页面未找到"
|
||||
|
||||
[404Message]
|
||||
other = "您查找的页面不存在或已被移动。"
|
||||
|
||||
# 导航
|
||||
[home]
|
||||
other = "首页"
|
||||
|
||||
[about]
|
||||
other = "关于"
|
||||
|
||||
[contact]
|
||||
other = "联系我们"
|
||||
|
||||
# 博客
|
||||
[latestPosts]
|
||||
other = "最新文章"
|
||||
|
||||
[recentArticles]
|
||||
other = "最近文章"
|
||||
|
||||
[popularTags]
|
||||
other = "热门标签"
|
||||
|
||||
[subscribeNewsletter]
|
||||
other = "订阅新闻通讯"
|
||||
|
||||
[subscribeDescription]
|
||||
other = "将最新文章直接发送到您的收件箱"
|
||||
|
||||
[emailPlaceholder]
|
||||
other = "输入您的邮箱"
|
||||
|
||||
[subscribe]
|
||||
other = "订阅"
|
||||
|
||||
[subscribeDisclaimer]
|
||||
other = "我们尊重您的隐私。您可以随时取消订阅。"
|
||||
|
||||
# 页脚
|
||||
[copyright]
|
||||
other = "© {{ .Year }} {{ .SiteName }}。保留所有权利。"
|
||||
|
||||
[builtWith]
|
||||
other = "使用"
|
||||
|
||||
[and]
|
||||
other = "和"
|
||||
|
||||
# 语言切换
|
||||
[language]
|
||||
other = "语言"
|
||||
|
||||
[switchLanguage]
|
||||
other = "切换语言"
|
||||
|
||||
# 功能特性
|
||||
[seeItInAction]
|
||||
other = "实际演示"
|
||||
|
||||
# 定价
|
||||
[popular]
|
||||
other = "热门"
|
||||
|
||||
[mostPopular]
|
||||
other = "最受欢迎"
|
||||
|
||||
[perMonth]
|
||||
other = "/月"
|
||||
|
||||
# 文档
|
||||
[documentation]
|
||||
other = "文档"
|
||||
|
||||
# 分页
|
||||
[previous]
|
||||
other = "上一页"
|
||||
|
||||
[next]
|
||||
other = "下一页"
|
||||
|
||||
# 首页
|
||||
[trustedByCompanies]
|
||||
other = "受全球领先企业信任"
|
||||
|
||||
[lovedByTeams]
|
||||
other = "受全球团队喜爱"
|
||||
|
||||
[testimonialsDescription]
|
||||
other = "看看我们的客户对使用我们平台的体验有何评价。"
|
||||
|
||||
# 博客文章
|
||||
[tableOfContents]
|
||||
other = "目录"
|
||||
|
||||
[minRead]
|
||||
other = "分钟阅读"
|
||||
|
||||
[previousPost]
|
||||
other = "上一篇"
|
||||
|
||||
[nextPost]
|
||||
other = "下一篇"
|
||||
|
||||
[dateFormat]
|
||||
other = "2006年1月2日"
|
||||
@@ -0,0 +1,154 @@
|
||||
# English translations for Hugo Saasify Theme
|
||||
# Copy this file to your site's i18n directory and customize as needed
|
||||
|
||||
# Common UI translations
|
||||
[readMore]
|
||||
other = "Read More"
|
||||
|
||||
[readTime]
|
||||
other = "min read"
|
||||
|
||||
[published]
|
||||
other = "Published"
|
||||
|
||||
[updated]
|
||||
other = "Updated"
|
||||
|
||||
[by]
|
||||
other = "by"
|
||||
|
||||
[shareOn]
|
||||
other = "Share on"
|
||||
|
||||
[relatedPosts]
|
||||
other = "Related Posts"
|
||||
|
||||
[categories]
|
||||
other = "Categories"
|
||||
|
||||
[tags]
|
||||
other = "Tags"
|
||||
|
||||
[allPosts]
|
||||
other = "All Posts"
|
||||
|
||||
[search]
|
||||
other = "Search"
|
||||
|
||||
[searchPlaceholder]
|
||||
other = "Search articles..."
|
||||
|
||||
[noResults]
|
||||
other = "No results found"
|
||||
|
||||
[backToHome]
|
||||
other = "Back to Home"
|
||||
|
||||
[404Title]
|
||||
other = "Page Not Found"
|
||||
|
||||
[404Message]
|
||||
other = "The page you are looking for doesn't exist or has been moved."
|
||||
|
||||
# Navigation
|
||||
[home]
|
||||
other = "Home"
|
||||
|
||||
[about]
|
||||
other = "About"
|
||||
|
||||
[contact]
|
||||
other = "Contact"
|
||||
|
||||
# Blog
|
||||
[latestPosts]
|
||||
other = "Latest Posts"
|
||||
|
||||
[recentArticles]
|
||||
other = "Recent Articles"
|
||||
|
||||
[popularTags]
|
||||
other = "Popular Tags"
|
||||
|
||||
[subscribeNewsletter]
|
||||
other = "Subscribe to Newsletter"
|
||||
|
||||
[subscribeDescription]
|
||||
other = "Get the latest posts delivered right to your inbox"
|
||||
|
||||
[emailPlaceholder]
|
||||
other = "Enter your email"
|
||||
|
||||
[subscribe]
|
||||
other = "Subscribe"
|
||||
|
||||
[subscribeDisclaimer]
|
||||
other = "We respect your privacy. Unsubscribe at any time."
|
||||
|
||||
# Footer
|
||||
[copyright]
|
||||
other = "© {{ .Year }} {{ .SiteName }}. All rights reserved."
|
||||
|
||||
[builtWith]
|
||||
other = "Built with"
|
||||
|
||||
[and]
|
||||
other = "and"
|
||||
|
||||
# Language switcher
|
||||
[language]
|
||||
other = "Language"
|
||||
|
||||
[switchLanguage]
|
||||
other = "Switch Language"
|
||||
|
||||
# Features
|
||||
[seeItInAction]
|
||||
other = "See it in action"
|
||||
|
||||
# Pricing
|
||||
[popular]
|
||||
other = "Popular"
|
||||
|
||||
[mostPopular]
|
||||
other = "Most Popular"
|
||||
|
||||
[perMonth]
|
||||
other = "/month"
|
||||
|
||||
# Documentation
|
||||
[documentation]
|
||||
other = "Documentation"
|
||||
|
||||
# Pagination
|
||||
[previous]
|
||||
other = "Previous"
|
||||
|
||||
[next]
|
||||
other = "Next"
|
||||
|
||||
# Homepage
|
||||
[trustedByCompanies]
|
||||
other = "Trusted by leading companies worldwide"
|
||||
|
||||
[lovedByTeams]
|
||||
other = "Loved by Teams Worldwide"
|
||||
|
||||
[testimonialsDescription]
|
||||
other = "See what our customers have to say about their experience with our platform."
|
||||
|
||||
# Blog Post
|
||||
[tableOfContents]
|
||||
other = "Table of Contents"
|
||||
|
||||
[minRead]
|
||||
other = "min read"
|
||||
|
||||
[previousPost]
|
||||
other = "Previous Post"
|
||||
|
||||
[nextPost]
|
||||
other = "Next Post"
|
||||
|
||||
[dateFormat]
|
||||
other = "January 2, 2006"
|
||||
@@ -0,0 +1,20 @@
|
||||
# Traductions françaises pour les shortcodes pricing
|
||||
|
||||
[popular]
|
||||
other = "Populaire"
|
||||
|
||||
[mostPopular]
|
||||
other = "Le plus populaire"
|
||||
|
||||
|
||||
[perVATHour]
|
||||
other = "HT/heure"
|
||||
|
||||
[perVATDay]
|
||||
other = "HT/jour"
|
||||
|
||||
[perVATMonth]
|
||||
other = "HT/mois"
|
||||
|
||||
[perVATYear]
|
||||
other = "HT/an"
|
||||
@@ -0,0 +1,10 @@
|
||||
# Nederlandse vertalingen voor pricing shortcodes
|
||||
|
||||
[popular]
|
||||
other = "Populair"
|
||||
|
||||
[mostPopular]
|
||||
other = "Meest populair"
|
||||
|
||||
[perMonth]
|
||||
other = "/maand"
|
||||
|
After Width: | Height: | Size: 302 KiB |
|
After Width: | Height: | Size: 153 KiB |
@@ -0,0 +1,118 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ .Site.LanguageCode | default "en" }}" class="h-full">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<!-- Google Tag Manager -->
|
||||
{{ partial "google-tag-manager" . }}
|
||||
|
||||
<!-- Google Analytics -->
|
||||
{{ partial "google-analytics" . }}
|
||||
|
||||
<!-- Title -->
|
||||
<title>{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ .Title }} | {{ .Site.Title }}{{ end }}</title>
|
||||
|
||||
<!-- Meta Tags -->
|
||||
<meta name="description" content="{{ with .Description }}{{ . }}{{ else }}{{ with .Site.Params.description }}{{ . }}{{ end }}{{ end }}">
|
||||
<meta name="author" content="{{ .Site.Params.author | default .Site.Title }}">
|
||||
<meta name="robots" content="{{ with .Params.robots }}{{ . }}{{ else }}index, follow{{ end }}">
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:title" content="{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ .Title }} | {{ .Site.Title }}{{ end }}">
|
||||
<meta property="og:description" content="{{ with .Description }}{{ . }}{{ else }}{{ with .Site.Params.description }}{{ . }}{{ end }}{{ end }}">
|
||||
<meta property="og:type" content="{{ if .IsHome }}website{{ else }}article{{ end }}">
|
||||
<meta property="og:url" content="{{ .Permalink }}">
|
||||
<meta property="og:site_name" content="{{ .Site.Title }}">
|
||||
{{ with .Params.image }}
|
||||
<meta property="og:image" content="{{ . | absURL }}">
|
||||
{{ else }}
|
||||
{{ with .Site.Params.image }}
|
||||
<meta property="og:image" content="{{ . | absURL }}">
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
<!-- Twitter Card -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ .Title }} | {{ .Site.Title }}{{ end }}">
|
||||
<meta name="twitter:description" content="{{ with .Description }}{{ . }}{{ else }}{{ with .Site.Params.description }}{{ . }}{{ end }}{{ end }}">
|
||||
{{ with .Site.Params.twitter }}
|
||||
<meta name="twitter:site" content="@{{ . }}">
|
||||
{{ end }}
|
||||
{{ with .Params.image }}
|
||||
<meta name="twitter:image" content="{{ . | absURL }}">
|
||||
{{ else }}
|
||||
{{ with .Site.Params.image }}
|
||||
<meta property="twitter:image" content="{{ . | absURL }}">
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/x-icon" href="{{ "images/favicon.ico" | relURL }}">
|
||||
|
||||
<!-- Canonical URL -->
|
||||
<link rel="canonical" href="{{ .Permalink }}">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@600;700;800&display=swap" rel="stylesheet">
|
||||
|
||||
<!-- Main CSS -->
|
||||
<link rel="stylesheet" href="{{ "css/style.css" | relURL }}">
|
||||
|
||||
<!-- Additional Meta Tags from Front Matter -->
|
||||
{{ with .Params.customMeta }}
|
||||
{{ range . }}
|
||||
<meta {{ range $key, $value := . }} {{ $key }}="{{ $value }}"{{ end }}>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
<!-- Custom Head Content -->
|
||||
{{ partial "custom-head" . }}
|
||||
</head>
|
||||
<body class="min-h-screen flex flex-col">
|
||||
<!-- Google Tag Manager (noscript) -->
|
||||
{{ if and hugo.IsProduction .Site.Params.googleTagManager }}
|
||||
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id={{ .Site.Params.googleTagManager }}"
|
||||
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
|
||||
{{ end }}
|
||||
<!-- End Google Tag Manager (noscript) -->
|
||||
<!-- Header -->
|
||||
<div class="fixed top-0 left-0 right-0 z-50">
|
||||
{{ partial "header" . }}
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="pt-20">
|
||||
{{ block "main" . }}{{ end }}
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
{{ partial "footer" . }}
|
||||
|
||||
<!-- Language Preference Script -->
|
||||
{{ if .Site.IsMultiLingual }}
|
||||
{{ if .Site.Params.visitorapi_pid }}
|
||||
<script>
|
||||
// Inject VisitorAPI project ID from Hugo config
|
||||
window.HUGO_VISITOR_API_PID = "{{ .Site.Params.visitorapi_pid }}";
|
||||
</script>
|
||||
{{ end }}
|
||||
<script src="{{ "js/language-preference.js" | relURL }}"></script>
|
||||
{{ end }}
|
||||
|
||||
<!-- Mobile Menu Script -->
|
||||
<script>
|
||||
const mobileMenuButton = document.getElementById('mobile-menu-button');
|
||||
if (mobileMenuButton) {
|
||||
mobileMenuButton.addEventListener('click', function() {
|
||||
const mobileMenu = document.getElementById('mobile-menu');
|
||||
if (mobileMenu) {
|
||||
mobileMenu.classList.toggle('hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,115 @@
|
||||
{{ define "main" }}
|
||||
<div class="bg-gray-50">
|
||||
<!-- Hero Section -->
|
||||
<div class="bg-gradient-to-r from-primary-600 to-primary-700">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-24">
|
||||
<div class="text-center">
|
||||
<h1 class="text-4xl font-bold text-white mb-6">{{ .Title }}</h1>
|
||||
<p class="text-xl text-white max-w-2xl mx-auto leading-relaxed">{{ .Description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Team Culture Section -->
|
||||
{{ with .Params.culture_section }}
|
||||
<div class="bg-white py-16">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="bg-gray-50 rounded-xl shadow-sm p-8 lg:p-12">
|
||||
<div class="grid lg:grid-cols-2 gap-12 items-center">
|
||||
<div>
|
||||
<h2 class="text-3xl font-bold text-gray-900 mb-6">{{ .title }}</h2>
|
||||
<div class="space-y-6">
|
||||
{{ range .values }}
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0">
|
||||
<div class="flex items-center justify-center h-12 w-12 rounded-md bg-primary-600 text-white">
|
||||
{{ .icon }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<h3 class="text-xl font-semibold text-gray-900">{{ .title }}</h3>
|
||||
<p class="mt-2 text-gray-600">{{ .description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative">
|
||||
<img src="{{ .image }}" alt="{{ .image_alt }}" class="rounded-lg shadow-xl">
|
||||
<div class="absolute -bottom-4 -right-4 bg-white rounded-lg shadow-lg px-6 py-4">
|
||||
<p class="text-gray-900 font-semibold">{{ .image_caption }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<!-- Benefits Section -->
|
||||
{{ with .Params.benefits_section }}
|
||||
<div class="bg-white py-16">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<h2 class="text-3xl font-bold text-gray-900 text-center mb-12">{{ .title }}</h2>
|
||||
<div class="grid md:grid-cols-3 gap-8">
|
||||
{{ range .benefits }}
|
||||
<div class="bg-gray-50 rounded-lg p-6 hover:shadow-md transition-shadow duration-200">
|
||||
<div class="text-2xl mb-4">{{ .icon }}</div>
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">{{ .title }}</h3>
|
||||
<p class="text-gray-600">{{ .description }}</p>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<!-- Open Positions Section -->
|
||||
{{ with .Params.positions_section }}
|
||||
<div class="bg-white py-16">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="bg-gray-50 rounded-xl shadow-sm p-8 lg:p-12">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-3xl font-bold text-gray-900 mb-4">{{ .title }}</h2>
|
||||
<p class="text-lg text-gray-600 max-w-2xl mx-auto">Join our team and help shape the future of SaaS. We're always looking for talented individuals who share our passion for innovation.</p>
|
||||
</div>
|
||||
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
{{ range where $.Site.RegularPages "Section" "jobs" }}
|
||||
<a href="{{ .RelPermalink }}" class="group">
|
||||
<div class="h-full bg-white rounded-lg shadow-sm group-hover:shadow-md transition-all duration-200 overflow-hidden border border-gray-100 group-hover:border-primary-100">
|
||||
<div class="p-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 class="text-xl font-semibold text-gray-900 group-hover:text-primary-600 transition-colors duration-200">{{ .Title }}</h3>
|
||||
<span class="flex items-center justify-center w-8 h-8 rounded-full bg-primary-50 text-primary-600 group-hover:bg-primary-100 transition-colors duration-200">
|
||||
→
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center text-gray-600 text-sm mb-4 space-x-4">
|
||||
{{ with .Params.location }}
|
||||
<span class="flex items-center">
|
||||
<span class="mr-2">📍</span>
|
||||
{{ . }}
|
||||
</span>
|
||||
{{ end }}
|
||||
{{ with .Params.type }}
|
||||
<span class="flex items-center">
|
||||
<span class="mr-2">💼</span>
|
||||
{{ . }}
|
||||
</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
<p class="text-gray-600 mb-4 line-clamp-2">{{ .Description | default .Summary }}</p>
|
||||
<div class="text-primary-600 font-medium group-hover:text-primary-700 transition-colors duration-200">
|
||||
{{ $.Params.positions_section.view_position_text }} →
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -0,0 +1,6 @@
|
||||
{{ define "main" }}
|
||||
<article class="post">
|
||||
<!-- Hero section will be rendered by the hero shortcode -->
|
||||
{{ .Content }}
|
||||
</article>
|
||||
{{ end }}
|
||||
@@ -0,0 +1,76 @@
|
||||
{{ define "main" }}
|
||||
<article class="feature-page" style="--badge-color: {{ .Params.badgeColor }}">
|
||||
<!-- Hero Section -->
|
||||
<div class="relative isolate overflow-hidden">
|
||||
<style>
|
||||
.badge {
|
||||
background-color: color-mix(in srgb, var(--badge-color) 10%, transparent);
|
||||
color: var(--badge-color);
|
||||
}
|
||||
.gradient-bg {
|
||||
background-image: linear-gradient(180deg, color-mix(in srgb, var(--badge-color) 5%, white), white);
|
||||
}
|
||||
</style>
|
||||
<div class="absolute inset-x-0 top-0 h-96 gradient-bg opacity-75"></div>
|
||||
<div class="relative pt-24 pb-16 sm:pt-32">
|
||||
<div class="mx-auto max-w-7xl px-6 lg:px-8">
|
||||
<div class="mx-auto max-w-2xl text-center">
|
||||
{{ with .Params.badge }}
|
||||
<div class="mb-6">
|
||||
<span class="badge inline-flex items-center rounded-full px-4 py-1.5 text-sm font-medium">
|
||||
{{ . }}
|
||||
</span>
|
||||
</div>
|
||||
{{ end }}
|
||||
<h1 class="text-4xl font-bold tracking-tight text-gray-900 sm:text-6xl">{{ .Title }}</h1>
|
||||
<p class="mt-6 text-lg leading-8 text-gray-600">{{ .Description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="mx-auto max-w-7xl px-6 lg:px-8">
|
||||
<!-- Key Features Grid -->
|
||||
{{ if .Params.features }}
|
||||
<div class="mx-auto mt-16 max-w-2xl sm:mt-20 lg:mt-24 lg:max-w-none">
|
||||
<div class="grid max-w-xl grid-cols-1 gap-x-8 gap-y-16 lg:max-w-none lg:grid-cols-2 xl:grid-cols-4">
|
||||
{{ range .Params.features }}
|
||||
<div class="flex flex-col bg-white rounded-2xl shadow-sm ring-1 ring-gray-200 p-8">
|
||||
<dt class="text-lg font-semibold leading-7 text-gray-900">
|
||||
{{ .title }}
|
||||
</dt>
|
||||
<dd class="mt-4 flex flex-auto flex-col text-base leading-7 text-gray-600">
|
||||
<p class="flex-auto">{{ .description }}</p>
|
||||
</dd>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<!-- Content Section -->
|
||||
<div class="prose prose-lg mx-auto mt-16 pb-24">
|
||||
{{ .Content }}
|
||||
</div>
|
||||
|
||||
<!-- Demo Section -->
|
||||
{{ if .Params.demo }}
|
||||
<div class="bg-gray-50 -mx-6 px-6 py-24 sm:py-32">
|
||||
<div class="mx-auto max-w-2xl lg:text-center">
|
||||
<h2 class="text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">{{ i18n "seeItInAction" }}</h2>
|
||||
<p class="mt-6 text-lg leading-8 text-gray-600">{{ .Params.demo.description }}</p>
|
||||
</div>
|
||||
<div class="mt-16 flex justify-center">
|
||||
<div class="relative rounded-xl bg-white p-8 shadow-2xl ring-1 ring-gray-200">
|
||||
<img src="{{ .Params.demo.image }}" alt="Demo" class="rounded-lg">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
<!-- Global CTA -->
|
||||
{{ partial "components/cta.html" . }}
|
||||
</article>
|
||||
{{ end }}
|
||||
@@ -0,0 +1,51 @@
|
||||
{{ define "main" }}
|
||||
<div class="bg-gray-50 min-h-screen">
|
||||
<!-- Job Header -->
|
||||
<div class="bg-gradient-to-r from-primary-600 to-primary-700">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
|
||||
<div class="text-center">
|
||||
<h1 class="text-3xl font-bold text-white mb-6">{{ .Title }}</h1>
|
||||
<div class="flex items-center justify-center text-white space-x-8 text-lg">
|
||||
{{ with .Params.location }}
|
||||
<span class="flex items-center">
|
||||
<span class="mr-2">📍</span>
|
||||
{{ . }}
|
||||
</span>
|
||||
{{ end }}
|
||||
{{ with .Params.type }}
|
||||
<span class="flex items-center">
|
||||
<span class="mr-2">💼</span>
|
||||
{{ . }}
|
||||
</span>
|
||||
{{ end }}
|
||||
{{ with .Params.salary }}
|
||||
<span class="flex items-center">
|
||||
<span class="mr-2">💰</span>
|
||||
{{ . }}
|
||||
</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Job Content -->
|
||||
<div class="bg-white py-16">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="bg-gray-50 rounded-xl shadow-sm p-8 lg:p-12">
|
||||
<div class="prose prose-lg max-w-none">
|
||||
<div class="text-gray-600 text-lg mb-8">{{ .Description }}</div>
|
||||
{{ .Content }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 text-center">
|
||||
<a href="/careers" class="inline-flex items-center text-primary-600 hover:text-primary-700">
|
||||
<span class="mr-2">←</span>
|
||||
View All Positions
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -0,0 +1,70 @@
|
||||
{{ define "main" }}
|
||||
<div class="container mx-auto px-4 py-12">
|
||||
<div class="max-w-7xl mx-auto">
|
||||
{{ if .IsHome }}
|
||||
<h1 class="text-4xl font-bold mb-8">{{ .Site.Title }}</h1>
|
||||
{{ else if eq .Section "blog" }}
|
||||
<h1 class="text-4xl font-bold mb-8">{{ .Site.Params.blog.title }}</h1>
|
||||
{{ with .Site.Params.blog.subtitle }}
|
||||
<div class="text-xl text-gray-600 mb-8">{{ . }}</div>
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
<h1 class="text-4xl font-bold mb-8">{{ .Title }}</h1>
|
||||
{{ with .Description }}
|
||||
<div class="text-xl text-gray-600 mb-8">{{ . }}</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{{ $paginator := .Paginate .Pages }}
|
||||
{{ range $paginator.Pages }}
|
||||
{{ partial "post-card.html" . }}
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
{{ $paginator := .Paginate .Pages }}
|
||||
{{ if gt $paginator.TotalPages 1 }}
|
||||
<nav class="mt-12 flex justify-between items-center">
|
||||
{{ if $paginator.HasPrev }}
|
||||
<a href="{{ $paginator.Prev.URL }}"
|
||||
class="inline-flex items-center px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors duration-200">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
|
||||
</svg>
|
||||
{{ i18n "previous" }}
|
||||
</a>
|
||||
{{ else }}
|
||||
<div></div>
|
||||
{{ end }}
|
||||
|
||||
<div class="flex space-x-2">
|
||||
{{ range $paginator.Pagers }}
|
||||
{{ if eq . $paginator }}
|
||||
<span class="px-4 py-2 bg-primary-600 text-white rounded-lg">
|
||||
{{ .PageNumber }}
|
||||
</span>
|
||||
{{ else }}
|
||||
<a href="{{ .URL }}"
|
||||
class="px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors duration-200">
|
||||
{{ .PageNumber }}
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
{{ if $paginator.HasNext }}
|
||||
<a href="{{ $paginator.Next.URL }}"
|
||||
class="inline-flex items-center px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors duration-200">
|
||||
{{ i18n "next" }}
|
||||
<svg class="w-5 h-5 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3"></path>
|
||||
</svg>
|
||||
</a>
|
||||
{{ else }}
|
||||
<div></div>
|
||||
{{ end }}
|
||||
</nav>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -0,0 +1,12 @@
|
||||
{{ define "main" }}
|
||||
<div class="container mx-auto px-4 py-8 mb-12 flex-1">
|
||||
<h1 class="text-4xl font-bold text-center mb-5">{{ .Title }}</h1>
|
||||
{{ with .Params.description }}
|
||||
<p class="text-center font-light text-gray-500 sm:text-xl">{{ . }}</p>
|
||||
{{ end }}
|
||||
|
||||
<div class="!max-w-none">
|
||||
{{ .Content }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -0,0 +1,8 @@
|
||||
{{ define "main" }}
|
||||
<div class="container mx-auto px-4 py-8 mb-12 flex-1">
|
||||
<h1 class="text-4xl font-bold text-center mb-12">{{ .Title }}</h1>
|
||||
<div class="prose prose-lg !max-w-none">
|
||||
{{ .Content }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -0,0 +1,86 @@
|
||||
{{ define "main" }}
|
||||
<div class="container mx-auto px-4 py-12">
|
||||
<!-- Two Column Layout for Content and Sidebar -->
|
||||
<div class="flex flex-col lg:flex-row gap-8 mb-12">
|
||||
<!-- Main Content -->
|
||||
<article class="flex-1">
|
||||
<header class="mb-8">
|
||||
{{ with .Params.categories }}
|
||||
<div class="mb-4">
|
||||
{{ range . }}
|
||||
<a href="{{ "/categories/" | relLangURL }}{{ . | urlize }}"
|
||||
class="inline-block px-3 py-1 text-sm font-medium text-primary-600 bg-primary-50 rounded-full hover:bg-primary-100 mr-2">
|
||||
{{ . }}
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<h1 class="text-4xl font-bold mb-4">{{ .Title }}</h1>
|
||||
|
||||
{{ partial "post-meta.html" . }}
|
||||
</header>
|
||||
|
||||
{{ with .Params.featured_image }}
|
||||
<div class="mb-8">
|
||||
<img src="{{ . }}"
|
||||
alt="{{ $.Title }}"
|
||||
class="w-full h-auto rounded-lg"
|
||||
loading="lazy">
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div class="prose prose-lg max-w-none">
|
||||
{{ .Content }}
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<aside class="lg:w-80 xl:w-96">
|
||||
{{ partial "sidebar.html" . }}
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<!-- Full-width Navigation Section -->
|
||||
<nav class="border-t border-gray-200 mt-12 pt-8">
|
||||
<div class="flex justify-between items-center">
|
||||
{{ with .PrevInSection }}
|
||||
<a href="{{ .RelPermalink }}"
|
||||
class="group flex items-center">
|
||||
<svg class="w-5 h-5 mr-2 text-gray-600 group-hover:text-primary-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
|
||||
</svg>
|
||||
<div>
|
||||
<div class="text-sm text-gray-600">{{ i18n "previousPost" $ }}</div>
|
||||
<div class="font-medium group-hover:text-primary-600">{{ .Title }}</div>
|
||||
</div>
|
||||
</a>
|
||||
{{ else }}
|
||||
<div></div>
|
||||
{{ end }}
|
||||
|
||||
{{ with .NextInSection }}
|
||||
<a href="{{ .RelPermalink }}"
|
||||
class="group flex items-center text-right">
|
||||
<div>
|
||||
<div class="text-sm text-gray-600">{{ i18n "nextPost" $ }}</div>
|
||||
<div class="font-medium group-hover:text-primary-600">{{ .Title }}</div>
|
||||
</div>
|
||||
<svg class="w-5 h-5 ml-2 text-gray-600 group-hover:text-primary-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3"></path>
|
||||
</svg>
|
||||
</a>
|
||||
{{ else }}
|
||||
<div></div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Full-width CTA Section -->
|
||||
{{ if and .Site.Params.blog.cta.enable .Site.Params.cta.enable }}
|
||||
<div class="mt-16">
|
||||
{{ partial "components/cta.html" . }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -0,0 +1,20 @@
|
||||
{{ define "main" }}
|
||||
<div class="pt-2">
|
||||
<div class="container mx-auto px-4 py-6">
|
||||
<div class="flex flex-col md:flex-row gap-6 items-start">
|
||||
<!-- Sidebar -->
|
||||
<div class="w-full md:w-1/4 lg:w-1/5 pt-1">
|
||||
{{ partial "docs-sidebar.html" . }}
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="w-full md:w-3/4 lg:w-4/5 pt-2">
|
||||
<article class="prose max-w-none -mt-2 pt-6">
|
||||
{{ .Content }}
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ end }}
|
||||
@@ -0,0 +1,3 @@
|
||||
{{ define "main" }}
|
||||
{{ .Content }}
|
||||
{{ end }}
|
||||
@@ -0,0 +1,28 @@
|
||||
{{ if .Site.Params.cta.enable }}
|
||||
<section class="cta-section">
|
||||
<div class="container">
|
||||
{{ $angle := .Site.Params.cta.gradient_angle | default 45 }}
|
||||
{{ $from := .Site.Params.cta.gradient_from }}
|
||||
{{ $to := .Site.Params.cta.gradient_to }}
|
||||
<div class="relative rounded-lg overflow-hidden bg-primary-600 cta-gradient"
|
||||
style="--gradient-angle: {{ $angle }}; --gradient-from: {{ $from }}; --gradient-to: {{ $to }}">
|
||||
<div class="relative text-center max-w-3xl mx-auto px-6 py-10">
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-white mb-6">{{ .Site.Params.cta.title }}</h2>
|
||||
<p class="text-xl text-primary-100 mb-8">{{ .Site.Params.cta.description }}</p>
|
||||
<div class="flex flex-col sm:flex-row justify-center gap-4">
|
||||
{{ with .Site.Params.cta.primary_button }}
|
||||
<a href="{{ .url }}" class="btn bg-white text-primary-600 hover:bg-gray-100">
|
||||
{{ .text }}
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.cta.secondary_button }}
|
||||
<a href="{{ .url }}" class="btn border-2 border-white text-white hover:bg-primary-700">
|
||||
{{ .text }}
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{{ end }}
|
||||
@@ -0,0 +1,46 @@
|
||||
{{ $lang := .Language.Lang }}
|
||||
<div class="bg-primary-50 p-6 rounded-lg">
|
||||
<h3 class="text-lg font-bold text-gray-900 mb-2">
|
||||
{{ if .title }}
|
||||
{{ .title }}
|
||||
{{ else }}
|
||||
{{ if eq $lang "zh-cn" }}订阅新闻通讯{{ else }}Subscribe to Newsletter{{ end }}
|
||||
{{ end }}
|
||||
</h3>
|
||||
<p class="text-sm text-gray-600 mb-4">
|
||||
{{ if .description }}
|
||||
{{ .description }}
|
||||
{{ else }}
|
||||
{{ if eq $lang "zh-cn" }}将最新文章直接发送到您的收件箱{{ else }}Get the latest posts delivered right to your inbox{{ end }}
|
||||
{{ end }}
|
||||
</p>
|
||||
|
||||
<form action="{{ .action | default "#" }}" method="POST" class="space-y-3">
|
||||
{{ with .hidden }}
|
||||
{{ range $name, $value := . }}
|
||||
<input type="hidden" name="{{ $name }}" value="{{ $value }}">
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
<div>
|
||||
<input
|
||||
type="email"
|
||||
name="{{ .emailName | default "email" }}"
|
||||
placeholder="{{ if .placeholder }}{{ .placeholder }}{{ else }}{{ if eq $lang "zh-cn" }}输入您的邮箱{{ else }}Enter your email{{ end }}{{ end }}"
|
||||
required
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||
>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors duration-200"
|
||||
>
|
||||
{{ if .buttonText }}{{ .buttonText }}{{ else }}{{ if eq $lang "zh-cn" }}订阅{{ else }}Subscribe{{ end }}{{ end }}
|
||||
</button>
|
||||
|
||||
{{ with .disclaimer }}
|
||||
<p class="text-xs text-gray-500 mt-2">{{ . }}</p>
|
||||
{{ end }}
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,18 @@
|
||||
<!-- Custom Head Content -->
|
||||
<!--
|
||||
This partial is intentionally left empty in the theme.
|
||||
Users can override this partial in their own site by creating:
|
||||
layouts/partials/custom-head.html
|
||||
|
||||
Example usage - Add any custom code to the <head> section:
|
||||
|
||||
- Custom tracking scripts (Hotjar, Mixpanel, etc.)
|
||||
- Meta tags for verification (Google Search Console, Pinterest, etc.)
|
||||
- Custom CSS or JavaScript libraries
|
||||
- Any other HTML that should be in the <head>
|
||||
|
||||
Example:
|
||||
<script>
|
||||
// Your custom tracking code
|
||||
</script>
|
||||
-->
|
||||
@@ -0,0 +1,22 @@
|
||||
<div class="docs-sidebar bg-white shadow-sm rounded-lg p-4 sticky top-20 mt-2">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-3 mt-1">{{ i18n "documentation" }}</h3>
|
||||
<nav class="docs-nav">
|
||||
<ul class="space-y-1">
|
||||
{{ range (where .Site.Pages "Section" "docs").ByWeight }}
|
||||
{{ if and .Title (not .IsHome) (ne .Kind "section") }}
|
||||
<li>
|
||||
<a href="{{ .RelPermalink }}"
|
||||
class="block px-4 py-2 rounded-md transition-colors duration-200
|
||||
{{ if eq .RelPermalink $.RelPermalink }}
|
||||
bg-indigo-50 text-indigo-600 font-medium
|
||||
{{ else }}
|
||||
text-gray-700 hover:bg-gray-50 hover:text-gray-900
|
||||
{{ end }}">
|
||||
{{ .Title }}
|
||||
</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
@@ -0,0 +1,151 @@
|
||||
<footer class="footer py-12 ">
|
||||
<div class="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl">
|
||||
<div class="flex flex-col md:flex-row justify-between space-y-4 md:space-y-0">
|
||||
<!-- Logo and Social Media -->
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<a href="{{ .Site.BaseURL }}" class="inline-block">
|
||||
{{ with .Site.Params.logo }}
|
||||
<img src="{{ . | relURL }}" alt="{{ $.Site.Title }}" class="h-6">
|
||||
{{ end }}
|
||||
</a>
|
||||
<span class="text-xl font-bold text-gray-900">{{ .Site.Title }}</span>
|
||||
</div>
|
||||
<div class="flex space-x-3 p-2">
|
||||
{{ with .Site.Params.social.linkedin }}
|
||||
<a href="{{ . }}" class="text-gray-600 hover:text-gray-900" target="_blank" rel="noopener noreferrer">
|
||||
<span class="sr-only">LinkedIn</span>
|
||||
<img src="/images/social/linkedin.svg" alt="LinkedIn" class="h-5 w-5">
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.social.bluesky }}
|
||||
<a href="{{ . }}" class="text-gray-600 hover:text-gray-900" target="_blank" rel="noopener noreferrer">
|
||||
<span class="sr-only">Bluesky</span>
|
||||
<img src="/images/social/bluesky.svg" alt="Bluesky" class="h-5 w-5">
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.social.twitter }}
|
||||
<a href="{{ . }}" class="text-gray-600 hover:text-gray-900" target="_blank" rel="noopener noreferrer">
|
||||
<span class="sr-only">Twitter (X)</span>
|
||||
<img src="/images/social/twitter.svg" alt="Twitter" class="h-5 w-5">
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.social.youtube }}
|
||||
<a href="{{ . }}" class="text-gray-600 hover:text-gray-900" target="_blank" rel="noopener noreferrer">
|
||||
<span class="sr-only">YouTube</span>
|
||||
<img src="/images/social/youtube.svg" alt="YouTube" class="h-5 w-5">
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.social.facebook }}
|
||||
<a href="{{ . }}" class="text-gray-600 hover:text-gray-900" target="_blank" rel="noopener noreferrer">
|
||||
<span class="sr-only">Facebook</span>
|
||||
<img src="/images/social/facebook.svg" alt="Facebook" class="h-5 w-5">
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.social.instagram }}
|
||||
<a href="{{ . }}" class="text-gray-600 hover:text-gray-900" target="_blank" rel="noopener noreferrer">
|
||||
<span class="sr-only">Instagram</span>
|
||||
<img src="/images/social/instagram.svg" alt="Instagram" class="h-5 w-5">
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.social.github }}
|
||||
<a href="{{ . }}" class="text-gray-600 hover:text-gray-900" target="_blank" rel="noopener noreferrer">
|
||||
<span class="sr-only">GitHub</span>
|
||||
<img src="/images/social/github.svg" alt="GitHub" class="h-5 w-5">
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.social.telegram }}
|
||||
<a href="{{ . }}" class="text-gray-600 hover:text-gray-900" target="_blank" rel="noopener noreferrer">
|
||||
<span class="sr-only">Telegram</span>
|
||||
<img src="/images/social/telegram.svg" alt="Telegram" class="h-5 w-5">
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.social.discord }}
|
||||
<a href="{{ . }}" class="text-gray-600 hover:text-gray-900" target="_blank" rel="noopener noreferrer">
|
||||
<span class="sr-only">Discord</span>
|
||||
<img src="/images/social/discord.svg" alt="Discord" class="h-5 w-5">
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.social.slack }}
|
||||
<a href="{{ . }}" class="text-gray-600 hover:text-gray-900" target="_blank" rel="noopener noreferrer">
|
||||
<span class="sr-only">Slack</span>
|
||||
<img src="/images/social/slack.svg" alt="Slack" class="h-5 w-5">
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.social.medium }}
|
||||
<a href="{{ . }}" class="text-gray-600 hover:text-gray-900" target="_blank" rel="noopener noreferrer">
|
||||
<span class="sr-only">Medium</span>
|
||||
<img src="/images/social/medium.svg" alt="Medium" class="h-5 w-5">
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.social.dribbble }}
|
||||
<a href="{{ . }}" class="text-gray-600 hover:text-gray-900" target="_blank" rel="noopener noreferrer">
|
||||
<span class="sr-only">Dribbble</span>
|
||||
<img src="/images/social/dribbble.svg" alt="Dribbble" class="h-5 w-5">
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.social.behance }}
|
||||
<a href="{{ . }}" class="text-gray-600 hover:text-gray-900" target="_blank" rel="noopener noreferrer">
|
||||
<span class="sr-only">Behance</span>
|
||||
<img src="/images/social/behance.svg" alt="Behance" class="h-5 w-5">
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.social.mastodon }}
|
||||
<a href="{{ . }}" class="text-gray-600 hover:text-gray-900" target="_blank" rel="noopener noreferrer">
|
||||
<span class="sr-only">mastodon</span>
|
||||
<img src="/images/social/mastodon.svg" alt="mastodon" class="h-5 w-5">
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.social.gitlab }}
|
||||
<a href="{{ . }}" class="text-gray-600 hover:text-gray-900" target="_blank" rel="noopener noreferrer">
|
||||
<span class="sr-only">gitlab</span>
|
||||
<img src="/images/social/gitlab.svg" alt="gitlab" class="h-5 w-5">
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Column 1 -->
|
||||
<div class="flex-1">
|
||||
<h3 class="text-sm font-semibold uppercase tracking-wider text-gray-900 mb-4">{{ .Site.Params.footer.column_1_title }}</h3>
|
||||
<ul class="space-y-2">
|
||||
{{ range .Site.Menus.footer_column_1 }}
|
||||
<li><a href="{{ .URL }}" class="text-gray-600 hover:text-primary-600">{{ .Name }}</a></li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Column 2 -->
|
||||
<div class="flex-1">
|
||||
<h3 class="text-sm font-semibold uppercase tracking-wider text-gray-900 mb-4">{{ .Site.Params.footer.column_2_title }}</h3>
|
||||
<ul class="space-y-2">
|
||||
{{ range .Site.Menus.footer_column_2 }}
|
||||
<li><a href="{{ .URL }}" class="text-gray-600 hover:text-primary-600">{{ .Name }}</a></li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Column 3 -->
|
||||
<div class="flex-1">
|
||||
<h3 class="text-sm font-semibold uppercase tracking-wider text-gray-900 mb-4">{{ .Site.Params.footer.column_3_title }}</h3>
|
||||
<ul class="space-y-2">
|
||||
{{ range .Site.Menus.footer_column_3 }}
|
||||
<li><a href="{{ .URL }}" class="text-gray-600 hover:text-primary-600">{{ .Name }}</a></li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom -->
|
||||
<div class="mt-12 pt-8 border-t border-gray-600">
|
||||
<div class="flex flex-col md:flex-row justify-between items-center space-y-4 md:space-y-0">
|
||||
<p class="text-gray-600 text-sm">
|
||||
© {{ now.Format "2006" }} {{ .Site.Title }}. All rights reserved.
|
||||
</p>
|
||||
<a href="https://www.champs-libres.coop/" class="text-sm text-gray-600 hover:text-primary-600" target="_blank" rel="noopener noreferrer">
|
||||
Designed by Champs-Libres
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -0,0 +1,10 @@
|
||||
{{ if and hugo.IsProduction .Site.Params.googleAnalytics }}
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id={{ .Site.Params.googleAnalytics }}"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', '{{ .Site.Params.googleAnalytics }}');
|
||||
</script>
|
||||
{{ end }}
|
||||
@@ -0,0 +1,9 @@
|
||||
{{ if and hugo.IsProduction .Site.Params.googleTagManager }}
|
||||
<!-- Google Tag Manager -->
|
||||
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
||||
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
||||
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
||||
})(window,document,'script','dataLayer','{{ .Site.Params.googleTagManager }}');</script>
|
||||
<!-- End Google Tag Manager -->
|
||||
{{ end }}
|
||||
@@ -0,0 +1,160 @@
|
||||
{{ $headerConfig := .Site.Params.header }}
|
||||
{{ $dropdownConfig := $headerConfig.menu.dropdown }}
|
||||
<div class="mobile-menu-wrapper">
|
||||
<input type="checkbox" id="nav-toggle" class="nav-toggle">
|
||||
<header class="fixed w-full top-0 z-50 {{ with $headerConfig.background }}{{ . }}{{ else }}bg-white/80 backdrop-blur-sm{{ end }} {{ with $headerConfig.border }}{{ . }}{{ else }}border-b border-gray-100{{ end }}">
|
||||
<div class="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl">
|
||||
<nav class="flex items-center justify-between h-20">
|
||||
<!-- Logo and Title -->
|
||||
<a href="{{ "/" | relLangURL }}" class="flex items-center space-x-4">
|
||||
{{ with $headerConfig.logo }}
|
||||
<img src="{{ .src | relURL }}" alt="{{ $.Site.Title }}" class="{{ with .class }}{{ . }}{{ else }}h-12{{ end }}">
|
||||
{{ else }}
|
||||
<span class="text-3xl font-bold text-gray-900">{{ .Site.Title }}</span>
|
||||
{{ end }}
|
||||
{{ if .Site.Title }}
|
||||
<span class="text-3xl font-semibold text-gray-800">{{ .Site.Title }}</span>
|
||||
{{ end }}
|
||||
</a>
|
||||
|
||||
<!-- Navigation -->
|
||||
<div class="hidden md:flex items-center {{ with $headerConfig.menu.spacing }}{{ . }}{{ else }}space-x-8{{ end }}">
|
||||
{{ range .Site.Menus.main }}
|
||||
{{ if .Params.has_submenu }}
|
||||
<div class="relative group">
|
||||
<button class="flex items-center {{ with $headerConfig.menu.linkClass }}{{ . }}{{ else }}text-base text-gray-900 hover:text-primary-600 font-bold transition duration-200{{ end }}">
|
||||
{{ .Name }}
|
||||
<svg class="ml-2 w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="absolute left-0 mt-2 {{ $dropdownConfig.width | default "w-72" }} opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 ease-in-out">
|
||||
<div class="{{ $dropdownConfig.container_padding | default "py-6" }} {{ $dropdownConfig.background | default "bg-white" }} {{ $dropdownConfig.border | default "border border-gray-100" }} {{ $dropdownConfig.shadow | default "shadow-xl" }} {{ $dropdownConfig.radius | default "rounded-lg" }}">
|
||||
{{ range .Params.submenu }}
|
||||
<a href="{{ .url }}" class="block {{ $dropdownConfig.item_padding | default "px-8 py-3" }} {{ $dropdownConfig.text_size | default "text-sm" }} {{ $dropdownConfig.text_color | default "text-gray-700" }} {{ $dropdownConfig.hover_background | default "hover:bg-gray-50" }}">{{ .name }}</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ else }}
|
||||
<a href="{{ .URL }}" class="{{ with $headerConfig.menu.linkClass }}{{ . }}{{ else }}text-base text-gray-900 hover:text-primary-600 font-bold transition duration-200{{ end }}">{{ .Name }}</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
<!-- Language Switcher -->
|
||||
{{ partial "language-switcher" . }}
|
||||
</div>
|
||||
|
||||
<!-- CTA Buttons -->
|
||||
{{ if not $headerConfig.hideButtons }}
|
||||
<div class="hidden md:flex items-center space-x-4">
|
||||
{{ with $headerConfig.buttons.signIn }}
|
||||
<a href="{{ .url | default "#" }}" class="{{ with .class }}{{ . }}{{ else }}inline-flex items-center justify-center px-6 py-3 rounded-lg font-bold transition duration-200 ease-in-out border-2 border-gray-200 hover:border-primary-600 hover:text-primary-600{{ end }}">
|
||||
{{ .text | default "Sign in" }}
|
||||
</a>
|
||||
{{ end }}
|
||||
|
||||
{{ with $headerConfig.buttons.getStarted }}
|
||||
<a href="{{ .url | default "#" }}" class="{{ with .class }}{{ . }}{{ else }}inline-flex items-center justify-center px-6 py-3 rounded-lg font-bold transition duration-200 ease-in-out bg-primary-600 text-white hover:bg-primary-700 hover:scale-105{{ end }}">
|
||||
{{ .text | default "Get Started" }}
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<!-- Mobile Menu Toggle -->
|
||||
<div class="md:hidden">
|
||||
<label for="nav-toggle" class="p-2 rounded-lg hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-primary-600 focus:ring-offset-2 transition-colors cursor-pointer">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
|
||||
</svg>
|
||||
</label>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- Mobile Menu -->
|
||||
<div class="nav-content md:hidden w-full fixed left-0 right-0 top-20 bg-white border-t border-gray-100 shadow-lg max-h-[calc(100vh-5rem)] overflow-y-auto">
|
||||
<div class="w-full px-6 py-4">
|
||||
{{ range .Site.Menus.main }}
|
||||
{{ if .Params.has_submenu }}
|
||||
<div class="py-2">
|
||||
<div class="text-xl text-gray-900 font-bold mb-2">{{ .Name }}</div>
|
||||
<div class="pl-4">
|
||||
{{ range .Params.submenu }}
|
||||
<a href="{{ .url }}" class="block text-gray-700 hover:text-primary-600 py-2">{{ .name }}</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ else }}
|
||||
<a href="{{ .URL }}" class="{{ with $headerConfig.menu.mobileLinkClass }}{{ . }}{{ else }}block text-xl text-gray-900 hover:text-primary-600 font-bold transition duration-200 py-2{{ end }}">{{ .Name }}</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
<!-- Mobile Language Switcher -->
|
||||
{{ if .Site.IsMultiLingual }}
|
||||
<div class="py-4 border-t border-gray-200 mt-4">
|
||||
<div class="text-lg text-gray-600 font-semibold mb-2">{{ i18n "language" }}</div>
|
||||
{{ range .Site.Languages }}
|
||||
{{ if eq $.Site.Language.Lang .Lang }}
|
||||
<span class="block py-2 text-primary-600 font-bold">{{ .LanguageName }}</span>
|
||||
{{ else }}
|
||||
{{ $langURL := printf "/%s/" .Lang }}
|
||||
<a href="{{ $langURL }}" class="language-switch-link block py-2 text-gray-700 hover:text-primary-600" data-lang="{{ .Lang }}">
|
||||
{{ .LanguageName }}
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{ if not $headerConfig.hideButtons }}
|
||||
<div class="pt-4 space-y-4">
|
||||
{{ with $headerConfig.buttons.signIn }}
|
||||
<a href="{{ .url | default "#" }}" class="{{ with .mobileClass }}{{ . }}{{ else }}block text-center px-6 py-3 rounded-lg font-bold transition duration-200 ease-in-out border-2 border-gray-200 hover:border-primary-600 hover:text-primary-600{{ end }}">
|
||||
{{ .text | default "Sign in" }}
|
||||
</a>
|
||||
{{ end }}
|
||||
|
||||
{{ with $headerConfig.buttons.getStarted }}
|
||||
<a href="{{ .url | default "#" }}" class="{{ with .mobileClass }}{{ . }}{{ else }}block text-center px-6 py-3 rounded-lg font-bold transition duration-200 ease-in-out bg-primary-600 text-white hover:bg-primary-700 hover:scale-105{{ end }}">
|
||||
{{ .text | default "Get Started" }}
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<style>
|
||||
.mobile-menu-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
.nav-toggle {
|
||||
display: none;
|
||||
}
|
||||
.nav-content {
|
||||
display: none;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.nav-toggle:checked ~ header .nav-content {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
var navToggle = document.getElementById('nav-toggle');
|
||||
if (navToggle) {
|
||||
navToggle.addEventListener('change', function() {
|
||||
if (this.checked) {
|
||||
document.body.style.overflow = 'hidden';
|
||||
} else {
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
@@ -0,0 +1,22 @@
|
||||
{{- $iconClass := printf "w-%s h-%s" (.size | default "6") (.size | default "6") -}}
|
||||
{{- $color := .color | default "#000000" -}}
|
||||
|
||||
<svg class="{{ $iconClass }}" style="color: {{ $color }};" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
{{- if eq .name "chart" -}}
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
|
||||
{{- else if eq .name "attribution" -}}
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"></path>
|
||||
{{- else if eq .name "roi" -}}
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
{{- else if eq .name "check" -}}
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
{{- else if eq .name "analytics" -}}
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 8v8m-4-5v5m-4-2v2m-2 4h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
||||
{{- else if eq .name "funnel" -}}
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4h18M5 8h14M7 12h10M9 16h6M11 20h2"></path>
|
||||
{{- else if eq .name "target" -}}
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
{{- else if eq .name "custom" -}}
|
||||
{{ .path | safeHTML }}
|
||||
{{- end -}}
|
||||
</svg>
|
||||
@@ -0,0 +1,24 @@
|
||||
{{ if .Site.IsMultiLingual }}
|
||||
{{ $headerConfig := .Site.Params.header }}
|
||||
{{ $dropdownConfig := $headerConfig.menu.dropdown }}
|
||||
<div class="relative group">
|
||||
<button class="flex items-center {{ with $headerConfig.menu.linkClass }}{{ . }}{{ else }}text-base text-gray-900 hover:text-primary-600 font-bold transition duration-200{{ end }}">
|
||||
{{ .Site.Language.LanguageName }}
|
||||
<svg class="ml-2 w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="absolute right-0 mt-2 {{ $dropdownConfig.width | default "w-72" }} opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 ease-in-out">
|
||||
<div class="{{ $dropdownConfig.container_padding | default "py-6" }} {{ $dropdownConfig.background | default "bg-white" }} {{ $dropdownConfig.border | default "border border-gray-100" }} {{ $dropdownConfig.shadow | default "shadow-xl" }} {{ $dropdownConfig.radius | default "rounded-lg" }}">
|
||||
{{ range .Site.Languages }}
|
||||
{{ if ne $.Site.Language.Lang .Lang }}
|
||||
{{ $langURL := printf "/%s/" .Lang }}
|
||||
<a href="{{ $langURL }}" class="language-switch-link block {{ $dropdownConfig.item_padding | default "px-8 py-3" }} {{ $dropdownConfig.text_size | default "text-sm" }} {{ $dropdownConfig.text_color | default "text-gray-700" }} {{ $dropdownConfig.hover_background | default "hover:bg-gray-50" }}" data-lang="{{ .Lang }}">
|
||||
{{ .LanguageName }}
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -0,0 +1,80 @@
|
||||
<article class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300">
|
||||
{{ with .Params.featured_image }}
|
||||
<a href="{{ $.RelPermalink }}" class="block aspect-w-16 aspect-h-9 overflow-hidden">
|
||||
<img
|
||||
src="{{ . }}"
|
||||
alt="{{ $.Title }}"
|
||||
class="object-cover w-full h-full transform hover:scale-105 transition-transform duration-300"
|
||||
loading="lazy"
|
||||
>
|
||||
</a>
|
||||
{{ end }}
|
||||
|
||||
<div class="p-6">
|
||||
<!-- Category -->
|
||||
{{ with .Params.categories }}
|
||||
<div class="mb-4">
|
||||
{{ range first 1 . }}
|
||||
<a href="{{ "/categories/" | relLangURL }}{{ . | urlize }}"
|
||||
class="inline-block px-3 py-1 text-sm font-medium text-primary-600 bg-primary-50 rounded-full hover:bg-primary-100">
|
||||
{{ . }}
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<!-- Title -->
|
||||
<h2 class="text-2xl font-bold mb-3 hover:text-primary-600 transition-colors duration-200">
|
||||
<a href="{{ .RelPermalink }}">{{ .Title }}</a>
|
||||
</h2>
|
||||
|
||||
<!-- Description -->
|
||||
<p class="text-gray-600 mb-4 line-clamp-2">
|
||||
{{ with .Description }}
|
||||
{{ . }}
|
||||
{{ else }}
|
||||
{{ .Summary | truncate 160 }}
|
||||
{{ end }}
|
||||
</p>
|
||||
|
||||
<!-- Author and Date in a cleaner layout -->
|
||||
<div class="flex items-center justify-between text-sm text-gray-500 mb-4">
|
||||
{{ with .Params.author }}
|
||||
<div class="flex items-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
|
||||
</svg>
|
||||
<span>{{ . }}</span>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div class="flex items-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
<time datetime="{{ .Date.Format "2006-01-02" }}">
|
||||
{{ .Date.Format "Jan 2, 2006" }}
|
||||
</time>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Read More link and Reading Time -->
|
||||
<div class="flex justify-between items-center">
|
||||
<a href="{{ .RelPermalink }}"
|
||||
class="inline-flex items-center text-primary-600 hover:text-primary-700 font-medium">
|
||||
{{ i18n "readMore" }}
|
||||
<svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3"></path>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<!-- Reading Time -->
|
||||
<span class="text-sm text-gray-500 flex items-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"></path>
|
||||
</svg>
|
||||
<span>{{ .ReadingTime }} {{ i18n "readTime" }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
@@ -0,0 +1,45 @@
|
||||
<div class="flex flex-col space-y-4">
|
||||
|
||||
|
||||
<!-- Author and Date -->
|
||||
<div class="flex items-center justify-between text-sm text-gray-500">
|
||||
{{ with .Params.author }}
|
||||
<div class="flex items-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
|
||||
</svg>
|
||||
<span>{{ . }}</span>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div class="flex items-center space-x-6">
|
||||
<div class="flex items-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"></path>
|
||||
</svg>
|
||||
<span>{{ .ReadingTime }} {{ i18n "minRead" . }}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
<time datetime="{{ .Date.Format "2006-01-02" }}">
|
||||
{{ .Date.Format (i18n "dateFormat" .) }}
|
||||
</time>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tags -->
|
||||
{{ with .Params.tags }}
|
||||
<div class="flex items-center flex-wrap gap-2">
|
||||
{{ range . }}
|
||||
<a href="{{ "/tags/" | relLangURL }}{{ . | urlize }}"
|
||||
class="px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-full text-sm text-gray-700 transition-colors duration-200">
|
||||
#{{ . }}
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
@@ -0,0 +1,52 @@
|
||||
{{/* Feature Partial (utilisé par le carousel) */}}
|
||||
{{ $title := .title }}
|
||||
{{ $titleBtn := .titleBtn}}
|
||||
{{ $description := .description }}
|
||||
{{ $badge := .badge }}
|
||||
{{ $badgeColor := .badgeColor | default "chill-blue" }}
|
||||
{{ $image := .image }}
|
||||
{{ $buttonText := .buttonText | default "Learn More" }}
|
||||
{{ $buttonLink := .buttonLink | default "#" }}
|
||||
{{ $imagePosition := .imagePosition | default "right" }}
|
||||
|
||||
{{ $features := split (.features) "," }}
|
||||
|
||||
<div class="grid lg:grid-cols-2 gap-12 items-center badge-{{ $badgeColor }}">
|
||||
{{ if eq $imagePosition "left" }}
|
||||
<div class="order-2 lg:order-1">
|
||||
<img src="{{ $image | relURL }}" alt="{{ $title }}" class="rounded-xl shadow-elevation">
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div class="space-y-6 {{ if eq $imagePosition "left" }}order-1 lg:order-2{{ end }}">
|
||||
<style>
|
||||
.badge {
|
||||
background-color: color-mix(in srgb, var(--badge-color) 30%, transparent);
|
||||
color: #222;
|
||||
}
|
||||
.badge-icon {
|
||||
color: var(--badge-color);
|
||||
}
|
||||
</style>
|
||||
<div class="badge inline-block px-4 py-2 rounded-full font-medium">{{ $badge }}</div>
|
||||
<h3 class="text-2xl md:text-3xl font-bold">{{ $title }}</h3>
|
||||
<p class="text-lg text-gray-600">{{ $description }}</p>
|
||||
<ul class="space-y-4">
|
||||
{{ range $features }}
|
||||
<li class="flex items-center space-x-3">
|
||||
<svg class="badge-icon w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
<span>{{ . | default "" }}</span>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
<a href="{{ $buttonLink }}" class="btn-primary inline-block">{{ $buttonText }}</a>
|
||||
</div>
|
||||
|
||||
{{ if ne $imagePosition "left" }}
|
||||
<div>
|
||||
<img src="{{ $image | relURL }}" alt="{{ $title }}" class="rounded-xl shadow-elevation">
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
@@ -0,0 +1,88 @@
|
||||
<div class="space-y-8">
|
||||
<!-- Subscribe Form -->
|
||||
{{ if .Site.Params.blog.sidebar.subscribe.enable }}
|
||||
{{ $params := dict
|
||||
"Site" .Site
|
||||
"Language" .Site.Language
|
||||
"title" .Site.Params.blog.sidebar.subscribe.title
|
||||
"description" .Site.Params.blog.sidebar.subscribe.description
|
||||
"action" .Site.Params.blog.sidebar.subscribe.action
|
||||
"emailName" .Site.Params.blog.sidebar.subscribe.emailName
|
||||
"buttonText" .Site.Params.blog.sidebar.subscribe.buttonText
|
||||
"placeholder" .Site.Params.blog.sidebar.subscribe.placeholder
|
||||
"disclaimer" .Site.Params.blog.sidebar.subscribe.disclaimer
|
||||
"hidden" .Site.Params.blog.sidebar.subscribe.hidden
|
||||
}}
|
||||
{{ partial "components/subscribe-form" $params }}
|
||||
{{ end }}
|
||||
|
||||
<!-- Recent Articles -->
|
||||
{{ if .Site.Params.blog.sidebar.recent.enable }}
|
||||
<div class="bg-white rounded-lg shadow-md p-6">
|
||||
<h3 class="text-lg font-bold mb-4">{{ .Site.Params.blog.sidebar.recent.title | default (i18n "recentArticles" .) }}</h3>
|
||||
<div class="space-y-4">
|
||||
{{ $recentCount := .Site.Params.blog.sidebar.recent.count | default 5 }}
|
||||
{{ range first $recentCount (where .Site.RegularPages "Type" "blog") }}
|
||||
<div class="group">
|
||||
<a href="{{ .RelPermalink }}" class="block">
|
||||
{{ with .Params.featured_image }}
|
||||
<div class="aspect-w-16 aspect-h-9 mb-3 overflow-hidden rounded-lg">
|
||||
<img
|
||||
src="{{ . }}"
|
||||
alt="{{ $.Title }}"
|
||||
class="object-cover w-full h-full transform group-hover:scale-105 transition-transform duration-300"
|
||||
loading="lazy"
|
||||
>
|
||||
</div>
|
||||
{{ end }}
|
||||
<h4 class="font-medium text-gray-900 group-hover:text-primary-600 transition-colors duration-200 line-clamp-2">
|
||||
{{ .Title }}
|
||||
</h4>
|
||||
<div class="flex items-center text-sm text-gray-500 mt-2">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
<time datetime="{{ .Date.Format "2006-01-02" }}">
|
||||
{{ .Date.Format "Jan 2, 2006" }}
|
||||
</time>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<!-- Categories -->
|
||||
{{ if .Site.Params.blog.sidebar.categories.enable }}
|
||||
<div class="bg-white rounded-lg shadow-md p-6">
|
||||
<h3 class="text-lg font-bold mb-4">{{ .Site.Params.blog.sidebar.categories.title | default (i18n "categories" .) }}</h3>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{{ range $name, $taxonomy := .Site.Taxonomies.categories }}
|
||||
<a href="{{ "/categories/" | relLangURL }}{{ $name | urlize }}"
|
||||
class="inline-block px-3 py-1 text-sm font-medium text-primary-600 bg-primary-50 rounded-full hover:bg-primary-100">
|
||||
{{ $name }}
|
||||
<span class="text-gray-500 ml-1">({{ $taxonomy.Count }})</span>
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<!-- Tags Cloud -->
|
||||
{{ if .Site.Params.blog.sidebar.tags.enable }}
|
||||
<div class="bg-white rounded-lg shadow-md p-6">
|
||||
<h3 class="text-lg font-bold mb-4">{{ .Site.Params.blog.sidebar.tags.title | default (i18n "popularTags" .) }}</h3>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{{ $tagCount := .Site.Params.blog.sidebar.tags.count | default 20 }}
|
||||
{{ range first $tagCount .Site.Taxonomies.tags.ByCount }}
|
||||
<a href="{{ "/tags/" | relLangURL }}{{ .Name | urlize }}"
|
||||
class="text-sm text-gray-600 hover:text-primary-600">
|
||||
#{{ .Name }}
|
||||
<span class="text-gray-500">({{ .Count }})</span>
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
@@ -0,0 +1,25 @@
|
||||
{{ $title := .Get "title" }}
|
||||
{{ $subtitle := .Get "subtitle" }}
|
||||
|
||||
<div class="text-center mb-16">
|
||||
<h2 class="text-3xl font-bold mb-4">{{ $title }}</h2>
|
||||
<p class="text-xl text-gray-600">{{ $subtitle }}</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
{{ range $index := (seq 1 10) }}
|
||||
{{ $benefit := printf "benefit%d" $index }}
|
||||
{{ with $.Get $benefit }}
|
||||
{{ $parts := split . "|" }}
|
||||
{{ if ge (len $parts) 4 }}
|
||||
<div class="p-6 bg-white rounded-xl shadow-lg hover:shadow-xl transition-shadow">
|
||||
<div class="w-12 h-12 rounded-lg flex items-center justify-center mb-4" style="background-color: {{ index $parts 1 }}15;">
|
||||
{{ partial "icons" (dict "name" (index $parts 0) "color" (index $parts 1) "size" "6") }}
|
||||
</div>
|
||||
<h3 class="text-xl font-bold mb-2">{{ index $parts 2 }}</h3>
|
||||
<p class="text-gray-600">{{ index $parts 3 }}</p>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
@@ -0,0 +1,15 @@
|
||||
<div class="not-prose">
|
||||
<div class="bg-white rounded-2xl shadow-xl overflow-hidden">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2">
|
||||
<div class="p-8 md:p-12">
|
||||
<div class="inline-block px-4 py-2 rounded-full text-sm font-semibold mb-6" style="background-color: {{ .Get 0 }}15; color: {{ .Get 0 }};">{{ .Get 1 }}</div>
|
||||
<div class="text-3xl font-bold mb-4 !mt-0">{{ .Get 2 }}</div>
|
||||
<div class="text-gray-600 mb-6">{{ .Get 3 }}</div>
|
||||
<a href="{{ .Get 5 }}" class="inline-block px-6 py-3 text-white font-bold rounded-lg transition-colors hover:opacity-90 !no-underline !text-white" style="background-color: {{ .Get 0 }};">{{ .Get 4 }}</a>
|
||||
</div>
|
||||
<div class="p-8 md:p-12 flex items-center justify-center" style="background: linear-gradient(135deg, {{ .Get 0 }}03, {{ .Get 0 }}30);">
|
||||
<img src="{{ .Get 6 }}" alt="{{ .Get 7 }}" class="max-w-[200px] !my-0 !rounded-none !shadow-none">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,82 @@
|
||||
<section class="border-y border-gray-100 overflow-hidden">
|
||||
<div class="container mx-auto">
|
||||
<div class="py-12">
|
||||
<p class="text-center text-3xl md:text-2xl font-bold mb-6">{{ .Get "title" | default (i18n "trustedByCompanies") }}</p>
|
||||
<div class="logo-scroll">
|
||||
<div class="logos-slide{{ if ne (.Get "animate" | default "true") "false" }} animate{{ end }}">
|
||||
{{ range .Page.Params.client_logos }}
|
||||
<img src="{{ .logo | relURL }}" class="h-20" alt="{{ .name }}" />
|
||||
{{ end }}
|
||||
{{ if ne (.Get "animate" | default "true") "false" }}
|
||||
{{ range .Page.Params.client_logos }}
|
||||
<img src="{{ .logo | relURL }}" class="h-20" alt="{{ .name }}" />
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.logo-scroll {
|
||||
overflow: hidden;
|
||||
padding: 20px 0;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.logo-scroll.static {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.logo-scroll.static .logos-slide {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 40px;
|
||||
}
|
||||
|
||||
.logos-slide {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.logos-slide.animate {
|
||||
animation: 30s slide infinite linear;
|
||||
}
|
||||
|
||||
.logos-slide img {
|
||||
max-height: 1.5rem;
|
||||
margin: 0 40px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
filter: grayscale(100%);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.logo-scroll.static .logos-slide img {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@keyframes slide {
|
||||
from {
|
||||
transform: translateX(0);
|
||||
}
|
||||
to {
|
||||
transform: translateX(calc(-100% / 2));
|
||||
}
|
||||
}
|
||||
|
||||
.logo-scroll:hover .logos-slide.animate {
|
||||
animation-play-state: paused;
|
||||
}
|
||||
|
||||
/* Mobile-specific animation speed */
|
||||
@media (max-width: 768px) {
|
||||
.logos-slide.animate {
|
||||
animation: 15s slide infinite linear;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,19 @@
|
||||
{{ $lang := .Get 0 }}
|
||||
{{ $code := .Inner }}
|
||||
{{ $filename := .Get 1 }}
|
||||
|
||||
<div class="not-prose my-8 overflow-hidden rounded-lg bg-gray-900 shadow-lg">
|
||||
{{ with $filename }}
|
||||
<div class="flex items-center justify-between px-4 py-2 bg-gray-800 border-b border-gray-700">
|
||||
<div class="text-sm text-gray-200 font-mono">{{ . }}</div>
|
||||
<div class="flex space-x-2">
|
||||
<div class="w-3 h-3 rounded-full bg-red-500"></div>
|
||||
<div class="w-3 h-3 rounded-full bg-yellow-500"></div>
|
||||
<div class="w-3 h-3 rounded-full bg-green-500"></div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="p-4 overflow-x-auto">
|
||||
{{ highlight $code $lang "linenos=table,linenostart=1,hl_lines=,lineanchors=line" }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,17 @@
|
||||
{{ $params := dict
|
||||
"title" (.Get "title")
|
||||
"description" (.Get "description")
|
||||
"primary_button" (dict
|
||||
"text" (.Get "primary_button_text")
|
||||
"url" (.Get "primary_button_url")
|
||||
)
|
||||
"secondary_button" (dict
|
||||
"text" (.Get "secondary_button_text")
|
||||
"url" (.Get "secondary_button_url")
|
||||
)
|
||||
"gradient_from" (.Get "gradient-from")
|
||||
"gradient_to" (.Get "gradient-to")
|
||||
"gradient_angle" (.Get "gradient-angle")
|
||||
}}
|
||||
|
||||
{{ partial "components/cta" (dict "Site" .Site "Params" (dict "cta" $params "enable" true)) }}
|
||||
@@ -0,0 +1,31 @@
|
||||
{{ $data := .Inner | transform.Unmarshal }}
|
||||
<section class="bg-white">
|
||||
<div class="py-8 px-4 mx-auto max-w-screen-xl lg:py-16 lg:px-6">
|
||||
<div class="mx-auto max-w-screen-md text-center mb-8 lg:mb-12">
|
||||
<h2 class="mb-4 text-4xl tracking-tight font-extrabold text-gray-900">{{ $data.title | default "Frequently Asked Questions" }}</h2>
|
||||
{{ with $data.description }}
|
||||
<p class="mb-5 font-light text-gray-500 sm:text-xl">{{ . }}</p>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
<div class="space-y-6">
|
||||
{{ range $data.questions }}
|
||||
<div class="border rounded-lg overflow-hidden bg-white shadow-sm hover:shadow-md transition-shadow duration-200">
|
||||
<button class="w-full flex justify-between items-center p-6 text-left hover:bg-gray-50 transition-colors duration-200 focus:outline-none"
|
||||
onclick="this.parentElement.querySelector('.faq-content').classList.toggle('hidden');
|
||||
this.querySelector('svg').classList.toggle('rotate-180')">
|
||||
<span class="text-lg font-medium text-gray-900">{{ .question }}</span>
|
||||
<svg class="w-5 h-5 text-gray-500 transform transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="faq-content hidden border-t">
|
||||
<div class="p-6 prose prose-sm sm:prose lg:prose-lg max-w-none">
|
||||
{{ .answer | markdownify }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,51 @@
|
||||
{{/* Feature Shortcode */}}
|
||||
{{ $title := .Get "title" }}
|
||||
{{ $description := .Get "description" }}
|
||||
{{ $badge := .Get "badge" }}
|
||||
{{ $badgeColor := .Get "badgeColor" | default "#5573df" }}
|
||||
{{ $image := .Get "image" }}
|
||||
{{ $buttonText := .Get "buttonText" | default "Learn More" }}
|
||||
{{ $buttonLink := .Get "buttonLink" | default "#" }}
|
||||
{{ $imagePosition := .Get "imagePosition" | default "right" }}
|
||||
|
||||
{{ $features := split (.Get "features") "," }}
|
||||
|
||||
<div class="grid lg:grid-cols-2 gap-12 items-center" style="--badge-color: {{ $badgeColor }}">
|
||||
{{ if eq $imagePosition "left" }}
|
||||
<div class="order-2 lg:order-1">
|
||||
<img src="{{ $image | relURL }}" alt="{{ $title }}" class="rounded-xl shadow-elevation">
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div class="space-y-6 {{ if eq $imagePosition "left" }}order-1 lg:order-2{{ end }}">
|
||||
<style>
|
||||
.badge {
|
||||
background-color: color-mix(in srgb, var(--badge-color) 10%, transparent);
|
||||
color: var(--badge-color);
|
||||
}
|
||||
.badge-icon {
|
||||
color: var(--badge-color);
|
||||
}
|
||||
</style>
|
||||
<div class="badge inline-block px-4 py-2 rounded-full font-medium">{{ $badge }}</div>
|
||||
<h3 class="text-2xl md:text-3xl font-bold">{{ $title }}</h3>
|
||||
<p class="text-lg text-gray-600">{{ $description }}</p>
|
||||
<ul class="space-y-4">
|
||||
{{ range $features }}
|
||||
<li class="flex items-center space-x-3">
|
||||
<svg class="badge-icon w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
<span>{{ . | default "" }}</span>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
<a href="{{ $buttonLink }}" class="btn-primary inline-block">{{ $buttonText }}</a>
|
||||
</div>
|
||||
|
||||
{{ if ne $imagePosition "left" }}
|
||||
<div>
|
||||
<img src="{{ $image | relURL }}" alt="{{ $title }}" class="rounded-xl shadow-elevation">
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
@@ -0,0 +1,81 @@
|
||||
{{/*
|
||||
Usage :
|
||||
{{< features-carousel title="Vos fonctionnalités clés" >}}
|
||||
{
|
||||
"features": [
|
||||
{
|
||||
"title": "Performance",
|
||||
"titleBtn": "Performance",
|
||||
"description": "Leverage Hugo's blazing-fast build times and optimized output.",
|
||||
"badge": "Performance",
|
||||
"badgeColor": "#2563eb",
|
||||
"image": "/images/feature-1.svg",
|
||||
"buttonText": "Learn More",
|
||||
"buttonLink": "/features/performance/",
|
||||
"features": "Sub-second page loads,Optimized assets,Minimal JavaScript,CDN-ready output",
|
||||
"imagePosition": "right"
|
||||
},
|
||||
]
|
||||
}
|
||||
{{< /features-carousel >}}
|
||||
*/}}
|
||||
|
||||
{{ $title := .Get "title" | default "" }}
|
||||
{{ $data := .Inner | transform.Unmarshal }}
|
||||
{{ $background_color := .Get "background-color" }}
|
||||
<section id="features-carousel" class="section{{ if not $background_color }} bg-gray-50{{ end }}" {{ if $background_color }}style="background-color:{{ $background_color }};"{{ end }}>
|
||||
<div class="container">
|
||||
{{ if $title }}
|
||||
<h1 class="text-3xl font-bold mb-4 text-center">{{ $title }}</h1>
|
||||
{{ end }}
|
||||
<div class="features-carousel__nav"></div>
|
||||
<div class="features-carousel__slides">
|
||||
{{ range $i, $f := $data.features }}
|
||||
<div class="feature" data-title-btn="{{ $f.titleBtn }}">
|
||||
{{ partial "shortcodes/feature.html" (dict
|
||||
"title" $f.title
|
||||
"titleBtn" $f.titleBtn
|
||||
"description" $f.description
|
||||
"badge" $f.badge
|
||||
"badgeColor" $f.badgeColor
|
||||
"image" $f.image
|
||||
"buttonText" $f.buttonText
|
||||
"buttonLink" $f.buttonLink
|
||||
"features" $f.features
|
||||
"imagePosition" $f.imagePosition
|
||||
) }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<script>
|
||||
(function() {
|
||||
const carousel = document.getElementById('features-carousel');
|
||||
if (!carousel) return;
|
||||
const slides = carousel.querySelectorAll('.feature');
|
||||
const nav = carousel.querySelector('.features-carousel__nav');
|
||||
let current = 0;
|
||||
|
||||
slides.forEach((slide, i) => {
|
||||
const btn = document.createElement('button');
|
||||
btn.innerText = slide.dataset.titleBtn || `Feature ${i+1}`;
|
||||
btn.onclick = () => {
|
||||
current = i;
|
||||
showSlide(current);
|
||||
};
|
||||
nav.appendChild(btn);
|
||||
});
|
||||
|
||||
function showSlide(idx) {
|
||||
slides.forEach((slide, i) => {
|
||||
slide.style.display = i === idx ? 'block' : 'none';
|
||||
});
|
||||
Array.from(nav.children).forEach((btn, i) => {
|
||||
btn.classList.toggle('active', i === idx);
|
||||
});
|
||||
}
|
||||
|
||||
showSlide(current);
|
||||
})();
|
||||
</script>
|
||||
@@ -0,0 +1,26 @@
|
||||
{{ $title := .Get "title" }}
|
||||
{{ $color := .Get "color" | default "#2563eb" }}
|
||||
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<h2 class="text-3xl font-bold text-center !mb-24">{{ $title }}</h2>
|
||||
|
||||
<div class="space-y-12">
|
||||
{{ range $index := (seq 1 10) }}
|
||||
{{ $feature := printf "feature%d" $index }}
|
||||
{{ with $.Get $feature }}
|
||||
{{ $parts := split . "|" }}
|
||||
{{ if ge (len $parts) 2 }}
|
||||
<div class="flex gap-6">
|
||||
<div class="w-10 h-10 rounded-xl flex items-center justify-center flex-shrink-0" style="background-color: {{ $color }}15;">
|
||||
{{ partial "icons" (dict "name" "check" "color" $color "size" "6") }}
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-2xl font-bold mb-3 !mt-0">{{ index $parts 0 }}</h3>
|
||||
<p class="text-gray-600 text-lg leading-relaxed">{{ index $parts 1 }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,17 @@
|
||||
{{/* Features Section Wrapper Shortcode */}}
|
||||
{{ $title := .Get "title" | default "Powerful Features for Modern Teams" }}
|
||||
{{ $description := .Get "description" | default "Discover how our platform helps you understand and optimize every aspect of your user experience." }}
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="text-center max-w-3xl mx-auto mb-16">
|
||||
<h2 class="text-3xl md:text-4xl font-bold mb-6">{{ $title }}</h2>
|
||||
<p class="text-xl text-gray-600">{{ $description }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Feature Grid -->
|
||||
<div class="space-y-32">
|
||||
{{ .Inner }}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,18 @@
|
||||
{{ $src := .Get "src" }}
|
||||
{{ $alt := .Get "alt" }}
|
||||
{{ $caption := .Get "caption" }}
|
||||
{{ $class := .Get "class" | default "w-full" }}
|
||||
|
||||
<figure class="my-8">
|
||||
<img
|
||||
src="{{ $src }}"
|
||||
alt="{{ $alt }}"
|
||||
class="{{ $class }} rounded-lg shadow-lg"
|
||||
loading="lazy"
|
||||
>
|
||||
{{ with $caption }}
|
||||
<figcaption class="mt-2 text-center text-sm text-gray-600">
|
||||
{{ . | markdownify }}
|
||||
</figcaption>
|
||||
{{ end }}
|
||||
</figure>
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="not-prose">
|
||||
<img src="{{ .Get 0 }}" alt="{{ .Get 1 }}" class="w-full no-prose-img">
|
||||
</div>
|
||||
@@ -0,0 +1,51 @@
|
||||
{{ $headline := .Get "headline" }}
|
||||
{{ $sub_headline := .Get "sub_headline" }}
|
||||
{{ $primary_button_text := .Get "primary_button_text" }}
|
||||
{{ $primary_button_url := .Get "primary_button_url" }}
|
||||
{{ $secondary_button_text := .Get "secondary_button_text" }}
|
||||
{{ $secondary_button_url := .Get "secondary_button_url" }}
|
||||
{{ $hero_image := .Get "hero_image" }}
|
||||
{{ $background_image := .Get "background_image" }}
|
||||
{{ $custom_class := .Get "custom_class" }}
|
||||
|
||||
<section class="relative overflow-hidden {{ $custom_class }}" >
|
||||
{{ if $background_image }}
|
||||
<div class="absolute inset-0">
|
||||
<img src="{{ $background_image | relURL }}" alt="Background" class="w-full h-full object-cover">
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="container pt-16 pb-20 md:pt-24 md:pb-28">
|
||||
<div class="grid lg:grid-cols-2 gap-12 items-center">
|
||||
<div class="space-y-8">
|
||||
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold leading-tight">
|
||||
{{ $headline | safeHTML }}
|
||||
</h1>
|
||||
<p class="text-xl text-gray-200">
|
||||
{{ $sub_headline | safeHTML }}
|
||||
</p>
|
||||
<div class="flex flex-col sm:flex-row gap-4">
|
||||
{{ if and $primary_button_text $primary_button_url }}
|
||||
<a href="{{ $primary_button_url }}" class="btn-primary text-center">
|
||||
{{ $primary_button_text }}
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ if and $secondary_button_text $secondary_button_url }}
|
||||
<a href="{{ $secondary_button_url }}" class="btn-outline text-center">
|
||||
{{ $secondary_button_text }}
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative">
|
||||
{{ if $hero_image }}
|
||||
<div class="relative z-10">
|
||||
<img src="{{ $hero_image | relURL }}" alt="Hero Image" class="rounded-xl shadow-elevation">
|
||||
</div>
|
||||
{{ end }}
|
||||
<!-- Background decoration -->
|
||||
<div class="absolute -top-20 -right-20 w-64 h-64 bg-primary-100 rounded-full filter blur-3xl opacity-50"></div>
|
||||
<div class="absolute -bottom-20 -left-20 w-64 h-64 bg-secondary-100 rounded-full filter blur-3xl opacity-50"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,7 @@
|
||||
<div class="investor-logo p-6 flex items-center justify-center">
|
||||
{{ if .Get "image" }}
|
||||
<img src="{{ .Get "image" }}" alt="{{ .Get "name" }}" class="max-h-12 grayscale hover:grayscale-0 transition-all duration-300">
|
||||
{{ else }}
|
||||
<div class="text-xl font-bold text-gray-400">{{ .Get "name" }}</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
@@ -0,0 +1,63 @@
|
||||
{{ $json := .Inner | transform.Unmarshal }}
|
||||
<section class="py-16 bg-white">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
{{ with $json.title }}
|
||||
<div class="text-center">
|
||||
<h2 class="text-3xl font-bold text-gray-900">{{ . }}</h2>
|
||||
{{ with $json.description }}
|
||||
<p class="mt-4 text-xl text-gray-600">{{ . }}</p>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div class="mt-16">
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
{{ range $json.plans }}
|
||||
<div class="w-full">
|
||||
<div class="h-full flex flex-col rounded-2xl border border-gray-200 bg-white shadow-sm hover:shadow-lg transition-shadow duration-300 relative">
|
||||
{{ if .featured }}
|
||||
<div class="absolute top-4 right-4 inline-block rounded-full bg-blue-100 px-4 py-1 text-sm font-semibold text-blue-800">
|
||||
{{ i18n "popular" }}
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="p-8 flex flex-col flex-grow">
|
||||
<div class="mb-6">
|
||||
<h3 class="text-2xl font-bold text-gray-900">{{ .name }}</h3>
|
||||
<p class="mt-2 text-gray-500">{{ .description }}</p>
|
||||
</div>
|
||||
<div class="mb-8">
|
||||
<p class="flex items-baseline">
|
||||
<span class="text-4xl font-bold tracking-tight text-gray-900">{{ .price }}</span>
|
||||
<span class="ml-2 text-gray-500">{{ i18n "perMonth" }}</span>
|
||||
</p>
|
||||
<p class="flex items-baseline">
|
||||
<span class="font-bold tracking-tight text-gray-900">{{ .additional_price }}</span>
|
||||
<span class="ml-2 text-gray-500">{{ i18n "perMonth" }}</span>
|
||||
</p>
|
||||
</div>
|
||||
<ul class="space-y-4 text-gray-600 flex-grow">
|
||||
{{ range .features }}
|
||||
<li class="flex items-start">
|
||||
<svg class="h-6 w-6 flex-shrink-0 text-blue-500" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M20.285 2l-11.285 11.567-5.286-5.011-3.714 3.716 9 8.728 15-15.285z"/>
|
||||
</svg>
|
||||
<span class="ml-3">{{ . }}</span>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
{{ with .additional_description }}
|
||||
<div class="mt-4 text-sm text-gray-500">{{ . }}</div>
|
||||
{{ end }}
|
||||
<div class="mt-8">
|
||||
<a href="{{ .button.url }}" class="btn btn-primary w-full">
|
||||
{{ .button.text }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,60 @@
|
||||
{{ $data := .Inner | unmarshal }}
|
||||
<section class="bg-white">
|
||||
<div class="py-8 px-4 mx-auto max-w-screen-xl lg:py-16 lg:px-6">
|
||||
{{ with $data.title }}
|
||||
<div class="mx-auto max-w-screen-md text-center mb-8 lg:mb-12">
|
||||
<h2 class="mb-4 text-4xl tracking-tight font-extrabold text-gray-900">{{ . }}</h2>
|
||||
{{ with $data.description }}
|
||||
<p class="mb-5 font-light text-gray-500 sm:text-xl">{{ . }}</p>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
|
||||
{{ range $index, $plan := $data.plans }}
|
||||
<div class="relative flex flex-col p-6 {{ if $plan.featured }}bg-primary-600 text-white{{ else }}bg-white{{ end }} rounded-2xl shadow-xl transform hover:-translate-y-1 transition duration-300">
|
||||
{{ if $plan.featured }}
|
||||
<div class="absolute -top-4 left-1/2 transform -translate-x-1/2">
|
||||
<span class="bg-yellow-400 text-gray-900 text-xs font-semibold px-4 py-1 rounded-full">{{ i18n "mostPopular" }}</span>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div class="mb-4">
|
||||
<h3 class="text-2xl font-bold {{ if $plan.featured }}text-white{{ else }}text-gray-900{{ end }}">{{ $plan.name }}</h3>
|
||||
<p class="mt-2 {{ if not $plan.featured }}text-gray-500{{ end }}">{{ $plan.description }}</p>
|
||||
</div>
|
||||
|
||||
{{ if $plan.price }}
|
||||
<div class="mb-6">
|
||||
<div class="flex items-baseline">
|
||||
<span class="text-5xl font-extrabold tracking-tight {{ if not $plan.featured }}text-gray-900{{ end }}">{{ $plan.price }}</span>
|
||||
<span class="ml-1 {{ if not $plan.featured }}text-gray-500{{ end }}">{{ i18n $plan.price_unit }}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-baseline">
|
||||
<span class="font-extrabold tracking-tight {{ if not $plan.featured }}text-gray-900{{ end }}">{{ $plan.additional_price }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<ul class="mb-8 space-y-4 flex-grow">
|
||||
{{ range $plan.features }}
|
||||
<li class="flex items-center">
|
||||
<svg class="w-5 h-5 {{ if $plan.featured }}text-white{{ else }}text-green-500{{ end }} mr-2" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span class="{{ if not $plan.featured }}text-gray-600{{ end }}">{{ . }}</span>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
{{ with .additional_description }}
|
||||
<div class="text-sm text-gray-500">{{ . }}</div>
|
||||
{{ end }}
|
||||
<a href="{{ $plan.button.url }}" class="mt-4 text-center w-full px-5 py-3 rounded-lg {{ if $plan.featured }}bg-white text-primary-600 hover:bg-gray-100{{ else }}bg-primary-600 text-white hover:bg-primary-700{{ end }} font-medium transition duration-300">
|
||||
{{ $plan.button.text }}
|
||||
</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,5 @@
|
||||
<section class="{{ .Get "class" }}">
|
||||
<div class="container mx-auto px-4">
|
||||
{{ .Inner }}
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,4 @@
|
||||
<div class="stat-card">
|
||||
<div class="text-3xl md:text-4xl font-bold text-blue-600 mb-2">{{ .Get "number" }}</div>
|
||||
<div class="text-gray-600 font-medium">{{ .Get "label" }}</div>
|
||||
</div>
|
||||
@@ -0,0 +1,22 @@
|
||||
<div class="team-member text-center">
|
||||
<div class="relative mb-4 rounded-lg overflow-hidden aspect-square">
|
||||
{{ if .Get "image" }}
|
||||
<img src="{{ .Get "image" }}" alt="{{ .Get "name" }}" class="w-full h-full object-cover">
|
||||
{{ else }}
|
||||
<div class="w-full h-full bg-gray-200 flex items-center justify-center">
|
||||
<svg class="w-20 h-20 text-gray-400" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 14c3.31 0 6-2.69 6-6s-2.69-6-6-6-6 2.69-6 6 2.69 6 6 6zm0 2c-4 0-12 2-12 6v2h24v-2c0-4-8-6-12-6z"/>
|
||||
</svg>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ if .Get "linkedin" }}
|
||||
<a href="{{ .Get "linkedin" }}" target="_blank" rel="noopener" class="absolute bottom-2 right-2 bg-white rounded-full p-2 shadow-md hover:shadow-lg transition-shadow">
|
||||
<svg class="w-5 h-5 text-blue-600" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/>
|
||||
</svg>
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
<h3 class="text-xl font-bold mb-1">{{ .Get "name" }}</h3>
|
||||
<p class="text-gray-600">{{ .Get "title" }}</p>
|
||||
</div>
|
||||
@@ -0,0 +1,183 @@
|
||||
{{ $background_color := .Get "background-color" }}
|
||||
<section class="section{{ if not $background_color }} bg-gray-50{{ end }}" {{ if $background_color }}style="background-color:{{ $background_color }};"{{ end }}>
|
||||
<div class="container">
|
||||
<div class="text-center max-w-3xl mx-auto mb-16">
|
||||
<h2 class="text-3xl md:text-4xl font-bold mb-6">{{ .Get "title" | default (i18n "lovedByTeams") }}</h2>
|
||||
<p class="text-xl text-gray-600">{{ .Get "description" | default (i18n "testimonialsDescription") }}</p>
|
||||
</div>
|
||||
|
||||
<div class="testimonials-container overflow-hidden">
|
||||
<div class="testimonials-track{{ if ne (.Get "animate" | default "true") "false" }} animate{{ end }}">
|
||||
{{ range .Page.Params.testimonials }}
|
||||
<div class="testimonial-card">
|
||||
<div class="flex items-center space-x-4 mb-6">
|
||||
<img src="{{ .avatar | relURL }}" alt="{{ .name }}" class="w-12 h-12 rounded-full">
|
||||
<div>
|
||||
<h4 class="font-bold">{{ .name }}</h4>
|
||||
<p class="text-gray-600">{{ .title }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-gray-600">{{ .quote }}</p>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ if ne (.Get "animate" | default "true") "false" }}
|
||||
{{ range .Page.Params.testimonials }}
|
||||
<div class="testimonial-card" aria-hidden="true">
|
||||
<div class="flex items-center space-x-4 mb-6">
|
||||
<img src="{{ .avatar | relURL }}" alt="{{ .name }}" class="w-12 h-12 rounded-full">
|
||||
<div>
|
||||
<h4 class="font-bold">{{ .name }}</h4>
|
||||
<p class="text-gray-600">{{ .title }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-gray-600">{{ .quote }}</p>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{{ if ne (.Get "animate" | default "true") "false" }}
|
||||
<script>
|
||||
(function() {
|
||||
// Wait for DOM to be ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initTestimonialsScroll);
|
||||
} else {
|
||||
initTestimonialsScroll();
|
||||
}
|
||||
|
||||
function initTestimonialsScroll() {
|
||||
const tracks = document.querySelectorAll('.testimonials-track.animate');
|
||||
|
||||
tracks.forEach(track => {
|
||||
// Remove CSS animation and use JS for smoother control
|
||||
track.style.animation = 'none';
|
||||
|
||||
const container = track.parentElement;
|
||||
|
||||
// Calculate the width of one set of testimonials (50% of track)
|
||||
const trackWidth = track.scrollWidth;
|
||||
const halfWidth = trackWidth / 2;
|
||||
|
||||
// Ensure track has valid dimensions before animating
|
||||
if (trackWidth === 0 || halfWidth === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let position = 0; // Current position in pixels
|
||||
let isPaused = false;
|
||||
let lastTime = performance.now();
|
||||
|
||||
// Check for mobile and set duration - responsive to window resize
|
||||
function getDuration() {
|
||||
return window.innerWidth <= 768 ? 15000 : 40000;
|
||||
}
|
||||
|
||||
// Speed in pixels per millisecond (recalculated on resize)
|
||||
let speed = halfWidth / getDuration();
|
||||
|
||||
function animate(currentTime) {
|
||||
if (!isPaused) {
|
||||
const delta = currentTime - lastTime;
|
||||
position += speed * delta;
|
||||
|
||||
// Reset position seamlessly when we've moved one full set
|
||||
if (position >= halfWidth) {
|
||||
position = position - halfWidth;
|
||||
}
|
||||
|
||||
track.style.transform = `translateX(-${position}px)`;
|
||||
}
|
||||
|
||||
lastTime = currentTime;
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
// Start animation
|
||||
requestAnimationFrame(animate);
|
||||
|
||||
// Pause on hover
|
||||
container.addEventListener('mouseenter', () => {
|
||||
isPaused = true;
|
||||
});
|
||||
|
||||
container.addEventListener('mouseleave', () => {
|
||||
isPaused = false;
|
||||
lastTime = performance.now(); // Reset lastTime to avoid jump
|
||||
});
|
||||
|
||||
// Handle window resize to adjust speed
|
||||
let resizeTimeout;
|
||||
window.addEventListener('resize', () => {
|
||||
clearTimeout(resizeTimeout);
|
||||
resizeTimeout = setTimeout(() => {
|
||||
speed = halfWidth / getDuration();
|
||||
}, 250); // Debounce resize events
|
||||
});
|
||||
});
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
{{ end }}
|
||||
|
||||
<style>
|
||||
.testimonials-container {
|
||||
padding: 20px 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.testimonials-container.static {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 2rem;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.testimonials-track {
|
||||
display: flex;
|
||||
gap: 2rem;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.testimonials-track.animate {
|
||||
animation: 40s testimonials-scroll infinite linear;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.testimonial-card {
|
||||
flex: 0 0 auto;
|
||||
width: 300px;
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.testimonials-container.static .testimonial-card {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@keyframes testimonials-scroll {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
.testimonials-container:hover .testimonials-track.animate {
|
||||
animation-play-state: paused;
|
||||
}
|
||||
|
||||
/* Mobile-specific animation speed */
|
||||
@media (max-width: 768px) {
|
||||
.testimonials-track.animate {
|
||||
animation: 15s testimonials-scroll infinite linear;
|
||||
will-change: transform;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,4 @@
|
||||
<div class="bg-gray-50 p-6 rounded-lg mb-8">
|
||||
<h2 class="text-xl font-semibold mb-4">{{ i18n "tableOfContents" }}</h2>
|
||||
{{ .Page.TableOfContents }}
|
||||
</div>
|
||||
@@ -0,0 +1,21 @@
|
||||
<div class="value-card bg-white p-8 rounded-lg shadow-sm hover:shadow-md transition-shadow">
|
||||
<div class="mb-4">
|
||||
{{ $icon := .Get "icon" }}
|
||||
{{ if eq $icon "lightbulb" }}
|
||||
<svg class="w-12 h-12 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/>
|
||||
</svg>
|
||||
{{ else if eq $icon "users" }}
|
||||
<svg class="w-12 h-12 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"/>
|
||||
</svg>
|
||||
{{ else if eq $icon "eye" }}
|
||||
<svg class="w-12 h-12 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>
|
||||
</svg>
|
||||
{{ end }}
|
||||
</div>
|
||||
<h3 class="text-xl font-bold mb-2">{{ .Get "title" }}</h3>
|
||||
<p class="text-gray-600">{{ .Get "description" }}</p>
|
||||
</div>
|
||||
@@ -0,0 +1,70 @@
|
||||
{{ define "main" }}
|
||||
<div class="container mx-auto px-4 py-12">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<header class="mb-12">
|
||||
<h1 class="text-4xl font-bold mb-4">
|
||||
{{ .Data.Singular | title }}: {{ .Title }}
|
||||
</h1>
|
||||
<div class="text-xl text-gray-600">
|
||||
{{ $count := len .Pages }}
|
||||
{{ if eq $count 1 }}
|
||||
1 post
|
||||
{{ else }}
|
||||
{{ $count }} posts
|
||||
{{ end }}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="grid gap-8">
|
||||
{{ $paginator := .Paginate .Pages }}
|
||||
{{ range $paginator.Pages }}
|
||||
{{ partial "post-card.html" . }}
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
{{ $paginator := .Paginate .Pages }}
|
||||
{{ if gt $paginator.TotalPages 1 }}
|
||||
<nav class="mt-12 flex justify-between items-center">
|
||||
{{ if $paginator.HasPrev }}
|
||||
<a href="{{ $paginator.Prev.URL }}"
|
||||
class="inline-flex items-center px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors duration-200">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
|
||||
</svg>
|
||||
Previous
|
||||
</a>
|
||||
{{ else }}
|
||||
<div></div>
|
||||
{{ end }}
|
||||
|
||||
<div class="flex space-x-2">
|
||||
{{ range $paginator.Pagers }}
|
||||
{{ if eq . $paginator }}
|
||||
<span class="px-4 py-2 bg-primary-600 text-white rounded-lg">
|
||||
{{ .PageNumber }}
|
||||
</span>
|
||||
{{ else }}
|
||||
<a href="{{ .URL }}"
|
||||
class="px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors duration-200">
|
||||
{{ .PageNumber }}
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
{{ if $paginator.HasNext }}
|
||||
<a href="{{ $paginator.Next.URL }}"
|
||||
class="inline-flex items-center px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors duration-200">
|
||||
Next
|
||||
<svg class="w-5 h-5 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3"></path>
|
||||
</svg>
|
||||
</a>
|
||||
{{ else }}
|
||||
<div></div>
|
||||
{{ end }}
|
||||
</nav>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -0,0 +1,39 @@
|
||||
{{ define "main" }}
|
||||
<div class="container mx-auto px-4 py-12">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<header class="mb-12">
|
||||
<h1 class="text-4xl font-bold mb-4">
|
||||
{{ .Title }}
|
||||
</h1>
|
||||
<div class="text-xl text-gray-600">
|
||||
Browse all {{ .Data.Plural }}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
{{ range .Data.Terms.ByCount }}
|
||||
<a href="{{ .Page.RelPermalink }}"
|
||||
class="group p-6 bg-white rounded-lg shadow-md hover:shadow-lg transition-shadow duration-200">
|
||||
<h2 class="text-xl font-semibold mb-2 group-hover:text-primary-600">
|
||||
{{ .Page.Title }}
|
||||
</h2>
|
||||
<div class="text-gray-600">
|
||||
{{ .Count }}
|
||||
{{ if eq .Count 1 }}
|
||||
post
|
||||
{{ else }}
|
||||
posts
|
||||
{{ end }}
|
||||
</div>
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
{{ if not .Data.Terms }}
|
||||
<div class="text-center py-12 text-gray-600">
|
||||
No {{ .Data.Plural }} found
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "hugo-sassify-theme",
|
||||
"version": "1.0.0",
|
||||
"description": "A modern Hugo theme for SaaS websites",
|
||||
"author": "Chaoming Li",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "concurrently \"npx tailwindcss -i themes/chill-theme/assets/scss/main.scss -o static/css/style.css --watch\" \"hugo server -D\"",
|
||||
"build": "tailwindcss -i themes/chill-theme/assets/scss/main.scss -o static/css/style.css --minify && hugo --minify"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"concurrently": "^8.2.2",
|
||||
"postcss": "^8.4.31",
|
||||
"postcss-cli": "^10.1.0",
|
||||
"tailwindcss": "^3.3.5"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 281 KiB |
|
After Width: | Height: | Size: 302 KiB |
|
After Width: | Height: | Size: 863 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 392 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 419 KiB |
|
After Width: | Height: | Size: 279 KiB |
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="400" height="400" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="400" height="400" fill="#e0e7ff"/>
|
||||
<circle cx="200" cy="150" r="80" fill="#818cf8"/>
|
||||
<circle cx="200" cy="400" r="160" fill="#818cf8"/>
|
||||
<rect x="120" y="130" width="160" height="40" rx="20" fill="#c7d2fe"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 370 B |
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="400" height="400" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="400" height="400" fill="#fee2e2"/>
|
||||
<circle cx="200" cy="150" r="80" fill="#f87171"/>
|
||||
<circle cx="200" cy="400" r="160" fill="#f87171"/>
|
||||
<rect x="120" y="130" width="160" height="40" rx="20" fill="#fecaca"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 370 B |
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="400" height="400" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="400" height="400" fill="#dcfce7"/>
|
||||
<circle cx="200" cy="150" r="80" fill="#4ade80"/>
|
||||
<circle cx="200" cy="400" r="160" fill="#4ade80"/>
|
||||
<rect x="120" y="130" width="160" height="40" rx="20" fill="#bbf7d0"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 370 B |
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="200" height="60" viewBox="0 0 200 60" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="200" height="60" fill="white"/>
|
||||
<circle cx="40" cy="30" r="20" fill="#3b82f6"/>
|
||||
<rect x="70" y="20" width="120" height="8" rx="4" fill="#3b82f6"/>
|
||||
<rect x="70" y="35" width="80" height="8" rx="4" fill="#93c5fd"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 374 B |
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="200" height="60" viewBox="0 0 200 60" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="200" height="60" fill="white"/>
|
||||
<polygon points="30,10 50,10 40,40" fill="#3b82f6"/>
|
||||
<rect x="70" y="20" width="100" height="8" rx="4" fill="#3b82f6"/>
|
||||
<rect x="70" y="35" width="60" height="8" rx="4" fill="#93c5fd"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 379 B |
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="200" height="60" viewBox="0 0 200 60" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="200" height="60" fill="white"/>
|
||||
<rect x="20" y="15" width="30" height="30" rx="6" fill="#3b82f6"/>
|
||||
<circle cx="35" cy="30" r="8" fill="white"/>
|
||||
<rect x="70" y="20" width="110" height="8" rx="4" fill="#3b82f6"/>
|
||||
<rect x="70" y="35" width="70" height="8" rx="4" fill="#93c5fd"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 442 B |
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="200" height="60" viewBox="0 0 200 60" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="200" height="60" fill="white"/>
|
||||
<circle cx="30" cy="30" r="15" fill="#3b82f6"/>
|
||||
<circle cx="45" cy="30" r="15" fill="#60a5fa" fill-opacity="0.7"/>
|
||||
<rect x="70" y="20" width="90" height="8" rx="4" fill="#3b82f6"/>
|
||||
<rect x="70" y="35" width="50" height="8" rx="4" fill="#93c5fd"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 444 B |
|
After Width: | Height: | Size: 188 KiB |
@@ -0,0 +1,28 @@
|
||||
<svg width="600" height="400" viewBox="0 0 600 400" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="600" height="400" fill="#f3f4f6"/>
|
||||
<rect x="20" y="20" width="560" height="360" rx="8" fill="#ffffff" stroke="#e5e7eb" stroke-width="2"/>
|
||||
|
||||
<!-- Header -->
|
||||
<rect x="40" y="40" width="200" height="24" rx="4" fill="#e5e7eb"/>
|
||||
<rect x="40" y="72" width="160" height="16" rx="4" fill="#f3f4f6"/>
|
||||
|
||||
<!-- Analytics Graph -->
|
||||
<rect x="40" y="120" width="520" height="220" rx="4" fill="#f9fafb"/>
|
||||
|
||||
<!-- Graph Lines -->
|
||||
<path d="M60 300 C 140 200, 220 280, 300 180 S 460 220, 540 120"
|
||||
stroke="#60a5fa" stroke-width="3" fill="none"/>
|
||||
<path d="M60 320 C 140 280, 220 300, 300 240 S 460 260, 540 200"
|
||||
stroke="#818cf8" stroke-width="3" fill="none" opacity="0.6"/>
|
||||
|
||||
<!-- Data Points -->
|
||||
<circle cx="140" cy="200" r="6" fill="#60a5fa"/>
|
||||
<circle cx="220" cy="280" r="6" fill="#60a5fa"/>
|
||||
<circle cx="300" cy="180" r="6" fill="#60a5fa"/>
|
||||
<circle cx="380" cy="220" r="6" fill="#60a5fa"/>
|
||||
<circle cx="460" cy="220" r="6" fill="#60a5fa"/>
|
||||
|
||||
<!-- Legend -->
|
||||
<rect x="40" y="360" width="80" height="8" rx="4" fill="#60a5fa"/>
|
||||
<rect x="140" y="360" width="80" height="8" rx="4" fill="#818cf8"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,35 @@
|
||||
<svg width="600" height="400" viewBox="0 0 600 400" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="600" height="400" fill="#f3f4f6"/>
|
||||
<rect x="20" y="20" width="560" height="360" rx="8" fill="#ffffff" stroke="#e5e7eb" stroke-width="2"/>
|
||||
|
||||
<!-- Session Player Header -->
|
||||
<rect x="40" y="40" width="520" height="40" rx="4" fill="#f9fafb"/>
|
||||
<circle cx="70" cy="60" r="12" fill="#a855f7"/>
|
||||
<rect x="100" y="50" width="120" height="20" rx="4" fill="#e5e7eb"/>
|
||||
<circle cx="500" cy="60" r="12" fill="#ef4444"/>
|
||||
|
||||
<!-- Timeline -->
|
||||
<rect x="40" y="100" width="520" height="20" rx="4" fill="#f9fafb"/>
|
||||
<rect x="40" y="100" width="200" height="20" rx="4" fill="#a855f7" opacity="0.3"/>
|
||||
<circle cx="240" cy="110" r="8" fill="#a855f7"/>
|
||||
|
||||
<!-- Session Content -->
|
||||
<rect x="40" y="140" width="520" height="220" rx="4" fill="#f9fafb"/>
|
||||
|
||||
<!-- Mouse Movement Path -->
|
||||
<path d="M100 200 C 200 180, 300 280, 400 200 S 500 220, 520 180"
|
||||
stroke="#a855f7" stroke-width="2" stroke-dasharray="4 4" fill="none"/>
|
||||
|
||||
<!-- Click Points -->
|
||||
<circle cx="200" cy="180" r="8" fill="#a855f7" opacity="0.3"/>
|
||||
<circle cx="300" cy="280" r="8" fill="#a855f7" opacity="0.3"/>
|
||||
<circle cx="400" cy="200" r="8" fill="#a855f7" opacity="0.3"/>
|
||||
|
||||
<!-- Cursor -->
|
||||
<path d="M520 180 L 530 190 L 515 185 Z" fill="#a855f7"/>
|
||||
|
||||
<!-- Event List -->
|
||||
<rect x="40" y="320" width="120" height="24" rx="4" fill="#e5e7eb"/>
|
||||
<rect x="180" y="320" width="120" height="24" rx="4" fill="#e5e7eb"/>
|
||||
<rect x="320" y="320" width="120" height="24" rx="4" fill="#e5e7eb"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,34 @@
|
||||
<svg width="600" height="400" viewBox="0 0 600 400" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="600" height="400" fill="#f3f4f6"/>
|
||||
<rect x="20" y="20" width="560" height="360" rx="8" fill="#ffffff" stroke="#e5e7eb" stroke-width="2"/>
|
||||
|
||||
<!-- Header -->
|
||||
<rect x="40" y="40" width="200" height="24" rx="4" fill="#e5e7eb"/>
|
||||
<rect x="40" y="72" width="160" height="16" rx="4" fill="#f3f4f6"/>
|
||||
|
||||
<!-- Code Editor Window -->
|
||||
<rect x="40" y="120" width="520" height="220" rx="4" fill="#f3f4f6"/>
|
||||
|
||||
<!-- Code Lines -->
|
||||
<rect x="60" y="140" width="120" height="16" rx="2" fill="#9333ea" opacity="0.6"/>
|
||||
<rect x="60" y="164" width="180" height="16" rx="2" fill="#60a5fa" opacity="0.6"/>
|
||||
<rect x="80" y="188" width="160" height="16" rx="2" fill="#818cf8" opacity="0.6"/>
|
||||
<rect x="80" y="212" width="140" height="16" rx="2" fill="#818cf8" opacity="0.6"/>
|
||||
<rect x="60" y="236" width="200" height="16" rx="2" fill="#60a5fa" opacity="0.6"/>
|
||||
<rect x="60" y="260" width="160" height="16" rx="2" fill="#9333ea" opacity="0.6"/>
|
||||
<rect x="80" y="284" width="180" height="16" rx="2" fill="#818cf8" opacity="0.6"/>
|
||||
|
||||
<!-- Line Numbers -->
|
||||
<text x="45" y="152" font-family="monospace" font-size="12" fill="#6b7280">1</text>
|
||||
<text x="45" y="176" font-family="monospace" font-size="12" fill="#6b7280">2</text>
|
||||
<text x="45" y="200" font-family="monospace" font-size="12" fill="#6b7280">3</text>
|
||||
<text x="45" y="224" font-family="monospace" font-size="12" fill="#6b7280">4</text>
|
||||
<text x="45" y="248" font-family="monospace" font-size="12" fill="#6b7280">5</text>
|
||||
<text x="45" y="272" font-family="monospace" font-size="12" fill="#6b7280">6</text>
|
||||
<text x="45" y="296" font-family="monospace" font-size="12" fill="#6b7280">7</text>
|
||||
|
||||
<!-- Status Bar -->
|
||||
<rect x="40" y="360" width="520" height="20" rx="4" fill="#f3f4f6"/>
|
||||
<circle cx="60" cy="370" r="4" fill="#34d399"/>
|
||||
<rect x="80" y="366" width="80" height="8" rx="4" fill="#9ca3af"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,26 @@
|
||||
<svg width="800" height="600" viewBox="0 0 800 600" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="800" height="600" fill="#f3f4f6"/>
|
||||
<rect x="40" y="40" width="720" height="520" rx="8" fill="#ffffff" stroke="#e5e7eb" stroke-width="2"/>
|
||||
|
||||
<!-- Header -->
|
||||
<rect x="60" y="60" width="680" height="60" rx="4" fill="#f9fafb"/>
|
||||
<circle cx="100" cy="90" r="15" fill="#60a5fa"/>
|
||||
<rect x="140" y="80" width="120" height="20" rx="4" fill="#e5e7eb"/>
|
||||
|
||||
<!-- Charts -->
|
||||
<rect x="60" y="140" width="320" height="200" rx="4" fill="#f9fafb"/>
|
||||
<path d="M80 300 L140 260 L200 280 L260 220 L320 240 L360 200" stroke="#60a5fa" stroke-width="2" fill="none"/>
|
||||
|
||||
<!-- Stats -->
|
||||
<rect x="400" y="140" width="340" height="200" rx="4" fill="#f9fafb"/>
|
||||
<rect x="420" y="160" width="140" height="20" rx="4" fill="#e5e7eb"/>
|
||||
<rect x="420" y="200" width="300" height="8" rx="4" fill="#60a5fa"/>
|
||||
<rect x="420" y="220" width="260" height="8" rx="4" fill="#818cf8"/>
|
||||
<rect x="420" y="240" width="220" height="8" rx="4" fill="#a78bfa"/>
|
||||
|
||||
<!-- Bottom Section -->
|
||||
<rect x="60" y="360" width="680" height="180" rx="4" fill="#f9fafb"/>
|
||||
<rect x="80" y="380" width="200" height="140" rx="4" fill="#ffffff" stroke="#e5e7eb" stroke-width="1"/>
|
||||
<rect x="300" y="380" width="200" height="140" rx="4" fill="#ffffff" stroke="#e5e7eb" stroke-width="1"/>
|
||||
<rect x="520" y="380" width="200" height="140" rx="4" fill="#ffffff" stroke="#e5e7eb" stroke-width="1"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="35 36 130 128">
|
||||
<!-- outline around oval -->
|
||||
<ellipse cx="100" cy="100" rx="60" ry="45" fill="none" stroke="#778fe6" stroke-width="8"/>
|
||||
<!-- Blue oval background -->
|
||||
<ellipse cx="100" cy="100" rx="56" ry="41" fill="#425ad6"/>
|
||||
<!-- Yellow lightning bolt -->
|
||||
<path d="M90 40 L130 40 L100 85 L130 85 L70 160 L90 105 L70 105 Z" fill="#f59e0b" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 441 B |
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,20 @@
|
||||
<svg width="145" height="26" viewBox="0 0 145 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_2011_8848)">
|
||||
<path d="M81.0508 19.0453H84.1348V7.88073H81.0508V19.0453ZM81.0508 6.13968H84.1348V3.48456H81.0508V6.13968Z" fill="#1E1E1E"/>
|
||||
<path d="M86.1221 22.7016H89.2061V17.783H89.2511C89.9085 18.7406 90.9747 19.3718 92.607 19.3718C95.6004 19.3718 97.6414 17.0866 97.6414 13.474C97.6414 9.99177 95.6685 7.57605 92.5845 7.57605C90.9971 7.57605 89.9085 8.29428 89.1605 9.2736H89.0924V7.88074H86.1221V22.7016ZM91.9495 16.9125C90.1129 16.9125 89.138 15.585 89.138 13.561C89.138 11.5587 89.9085 9.97006 91.8364 9.97006C93.7412 9.97006 94.5117 11.4499 94.5117 13.561C94.5117 15.672 93.5144 16.9125 91.9495 16.9125Z" fill="#1E1E1E"/>
|
||||
<path d="M103.793 19.3718C106.696 19.3718 108.692 18.0225 108.692 15.7808C108.692 13.1693 106.538 12.6469 104.587 12.2552C102.932 11.9287 101.39 11.8417 101.39 10.8841C101.39 10.0789 102.184 9.6436 103.385 9.6436C104.701 9.6436 105.495 10.0789 105.63 11.2758H108.419C108.193 9.03423 106.492 7.57605 103.431 7.57605C100.778 7.57605 98.6915 8.72954 98.6915 11.1453C98.6915 13.5828 100.733 14.1268 102.819 14.5186C104.406 14.8233 105.879 14.9321 105.879 15.9985C105.879 16.782 105.109 17.2825 103.748 17.2825C102.365 17.2825 101.412 16.7166 101.209 15.4326H98.3516C98.5328 17.8048 100.415 19.3718 103.793 19.3718Z" fill="#1E1E1E"/>
|
||||
<path d="M120.4 19.0453V7.88074H117.316V14.3227C117.316 15.8026 116.432 16.8472 114.981 16.8472C113.666 16.8472 113.054 16.129 113.054 14.8233V7.88074H109.992V15.3238C109.992 17.7613 111.443 19.35 114.029 19.35C115.662 19.35 116.568 18.7624 117.362 17.7396H117.43V19.0453H120.4Z" fill="#1E1E1E"/>
|
||||
<path d="M122.395 19.0453H125.479V12.5599C125.479 11.0799 126.318 10.1224 127.565 10.1224C128.699 10.1224 129.356 10.7753 129.356 12.0375V19.0453H132.44V12.5599C132.44 11.0799 133.234 10.1224 134.526 10.1224C135.661 10.1224 136.318 10.7753 136.318 12.0375V19.0453H139.402V11.537C139.402 9.09948 138.018 7.57605 135.569 7.57605C134.096 7.57605 132.871 8.31599 132.077 9.53474H132.032C131.465 8.35954 130.286 7.57605 128.812 7.57605C127.202 7.57605 126.069 8.35954 125.434 9.3824H125.365V7.88074H122.395V19.0453Z" fill="#1E1E1E"/>
|
||||
<path d="M0.672852 19.0453H3.75679V3.48456H0.672852V19.0453Z" fill="#1E1E1E"/>
|
||||
<path d="M11.2969 19.3718C14.9024 19.3718 17.3741 16.8037 17.3741 13.474C17.3741 10.1441 14.9024 7.57605 11.2969 7.57605C7.6914 7.57605 5.21973 10.1441 5.21973 13.474C5.21973 16.8037 7.6914 19.3718 11.2969 19.3718ZM11.2969 17.1084C9.39215 17.1084 8.34902 15.6502 8.34902 13.474C8.34902 11.2976 9.39215 9.81772 11.2969 9.81772C13.179 9.81772 14.2448 11.2976 14.2448 13.474C14.2448 15.6502 13.179 17.1084 11.2969 17.1084Z" fill="#1E1E1E"/>
|
||||
<path d="M23.9329 22.8539C25.6563 22.8539 27.1529 22.4622 28.1279 21.5916C28.9896 20.8299 29.5112 19.7635 29.5112 18.1966V7.88074H26.5407V9.056H26.4953C25.7923 8.12017 24.7266 7.57605 23.2753 7.57605C20.3274 7.57605 18.2412 9.70885 18.2412 13.0386C18.2412 16.412 20.7809 18.3706 23.366 18.3706C24.8399 18.3706 25.7243 17.8048 26.4046 17.0649H26.4726V18.2836C26.4726 19.8071 25.6336 20.6123 23.8875 20.6123C22.4589 20.6123 21.8013 20.0682 21.5519 19.3718H18.4906C18.8081 21.5481 20.7582 22.8539 23.9329 22.8539ZM23.8875 15.9985C22.3002 15.9985 21.2571 14.8885 21.2571 12.9952C21.2571 11.1235 22.3002 9.94829 23.8648 9.94829C25.7243 9.94829 26.6313 11.3411 26.6313 12.9734C26.6313 14.6274 25.8377 15.9985 23.8875 15.9985Z" fill="#1E1E1E"/>
|
||||
<path d="M37.0059 19.3718C40.6114 19.3718 43.0831 16.8037 43.0831 13.474C43.0831 10.1441 40.6114 7.57605 37.0059 7.57605C33.4004 7.57605 30.9287 10.1441 30.9287 13.474C30.9287 16.8037 33.4004 19.3718 37.0059 19.3718ZM37.0059 17.1084C35.1011 17.1084 34.0581 15.6502 34.0581 13.474C34.0581 11.2976 35.1011 9.81772 37.0059 9.81772C38.888 9.81772 39.9538 11.2976 39.9538 13.474C39.9538 15.6502 38.888 17.1084 37.0059 17.1084Z" fill="#1E1E1E"/>
|
||||
<path d="M140.522 6.0478C140.522 5.54698 140.946 5.14099 141.468 5.14099H143.357C143.879 5.14099 144.302 5.54698 144.302 6.0478C144.302 6.54861 143.879 6.95461 143.357 6.95461H141.468C140.946 6.95461 140.522 6.54861 140.522 6.0478Z" fill="#1E1E1E"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M61.7863 0.304749C69.0915 0.304749 75.0142 5.98862 75.0142 13C75.0142 20.0114 69.0915 25.6953 61.7863 25.6953C54.4808 25.6953 48.5586 20.0114 48.5586 13C48.5586 5.98862 54.4808 0.304749 61.7863 0.304749ZM61.3082 1.25473C59.7991 1.45855 58.3622 2.62232 57.2467 4.56871C56.9232 5.13329 56.6313 5.75702 56.3769 6.43049C57.8936 6.0647 59.5597 5.84904 61.3082 5.81568V1.25473ZM55.2589 6.73541C55.5753 5.78249 55.9623 4.90577 56.4089 4.12644C56.9618 3.16156 57.618 2.32834 58.3574 1.68839C54.3369 2.80904 51.1679 5.85054 50.0002 9.70921C50.667 8.99961 51.5352 8.3698 52.5405 7.83914C53.3526 7.41048 54.266 7.03902 55.2589 6.73541ZM54.9412 7.80835C54.5601 9.26399 54.3354 10.863 54.3006 12.5411H49.5484C49.7607 11.0928 50.9733 9.71372 53.0014 8.64326C53.5896 8.33273 54.2395 8.05254 54.9412 7.80835ZM55.257 12.5411C55.2965 10.7098 55.5713 8.99047 56.0258 7.47135C57.6086 7.03515 59.4 6.77146 61.3082 6.73357V8.71587C60.5963 10.4649 59.1445 11.8582 57.322 12.5411H55.257ZM54.3006 13.4589H49.5484C49.7607 14.9072 50.9733 16.2863 53.0014 17.3568C53.5896 17.6673 54.2395 17.9475 54.9412 18.1917C54.5601 16.736 54.3354 15.137 54.3006 13.4589ZM56.0258 18.5287C55.5713 17.0096 55.2965 15.2902 55.257 13.4589H57.322C59.1445 14.1418 60.5963 15.5351 61.3082 17.2842V19.2665C59.4 19.2286 57.6086 18.9649 56.0258 18.5287ZM55.2589 19.2646C54.266 18.961 53.3526 18.5896 52.5405 18.1609C51.5352 17.6302 50.667 17.0004 50.0002 16.2908C51.1679 20.1495 54.3369 23.191 58.3574 24.3116C57.618 23.6717 56.9618 22.8385 56.4089 21.8736C55.9623 21.0943 55.5753 20.2175 55.2589 19.2646ZM61.3082 24.7453C59.7991 24.5415 58.3622 23.3777 57.2467 21.4313C56.9232 20.8668 56.6313 20.243 56.3769 19.5696C57.8936 19.9353 59.5597 20.151 61.3082 20.1843V24.7453ZM65.2151 24.3116C65.9545 23.6717 66.6106 22.8385 67.1636 21.8736C67.61 21.0943 67.9976 20.2175 68.3137 19.2646C69.3064 18.961 70.2198 18.5896 71.032 18.1609C72.0373 17.6302 72.9057 17.0004 73.5724 16.2908C72.4044 20.1495 69.2357 23.191 65.2151 24.3116ZM67.196 19.5696C66.9413 20.243 66.649 20.8668 66.3256 21.4313C65.2104 23.3777 63.7734 24.5415 62.2643 24.7453V20.1843C64.0129 20.151 65.6789 19.9353 67.196 19.5696ZM68.6312 18.1917C69.3329 17.9475 69.983 17.6673 70.571 17.3568C72.5995 16.2863 73.8118 14.9072 74.0241 13.4589H69.2721C69.237 15.137 69.0121 16.736 68.6312 18.1917ZM68.3157 13.4589C68.276 15.2902 68.0015 17.0096 67.5465 18.5287C65.9639 18.9649 64.1725 19.2286 62.2643 19.2665V17.2856C62.976 15.536 64.4282 14.142 66.2511 13.4589H68.3157ZM69.2721 12.5411H74.0241C73.8118 11.0928 72.5995 9.71372 70.571 8.64326C69.983 8.33273 69.3329 8.05254 68.6312 7.80835C69.0121 9.26399 69.237 10.863 69.2721 12.5411ZM67.5465 7.47135C68.0015 8.99047 68.276 10.7098 68.3157 12.5411H66.2512C64.4282 11.858 62.976 10.4641 62.2643 8.71441V6.73357C64.1725 6.77146 65.9639 7.03515 67.5465 7.47135ZM68.3137 6.73541C69.3064 7.03902 70.2198 7.41048 71.032 7.83914C72.0373 8.3698 72.9057 8.99961 73.5724 9.70921C72.4044 5.85054 69.2357 2.80904 65.2151 1.68839C65.9545 2.32834 66.6106 3.16156 67.1636 4.12644C67.61 4.90577 67.9976 5.78249 68.3137 6.73541ZM62.2643 1.25473C63.7734 1.45855 65.2104 2.62232 66.3256 4.56871C66.649 5.13329 66.9413 5.75702 67.196 6.43049C65.6789 6.0647 64.0129 5.84904 62.2643 5.81568V1.25473Z" fill="#1E1E1E"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2011_8848">
|
||||
<rect width="144.182" height="25.3905" fill="white" transform="translate(0.126953 0.304749)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.6 KiB |