Skip to main content

Theme Structure

Complete file organization for OQO themes.

Directory Layout

app/themes/my_theme/
├── assets/
│ ├── css/
│ │ ├── tailwind.css # Tailwind source (compiled locally)
│ │ ├── _variables.css.liquid # CSS variables from settings
│ │ ├── _base.css # Base element styles
│ │ ├── _layout.css # Container/section utilities
│ │ ├── _typography.css # Text styling
│ │ ├── _components.css # Cards, buttons, etc.
│ │ ├── _utilities.css # Animations, helpers
│ │ └── theme.css # Entry point (@imports all)
│ ├── framework.css # Pre-compiled CSS framework
│ └── theme.css # Final bundled output (generated)
├── config/
│ └── settings_schema.json # Theme-level settings
├── layouts/
│ └── theme.liquid # Main layout template
├── sections/
│ ├── hero/
│ │ ├── hero_01.liquid
│ │ └── hero_02.liquid
│ ├── content/
│ │ ├── recent_posts.liquid
│ │ └── featured_post.liquid
│ └── cta/
│ └── cta_01.liquid
└── snippets/
├── post_card.liquid
└── social_icons.liquid

Key Files

layouts/theme.liquid

The main layout wrapping all pages:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ page.title }} | {{ site.name }}</title>

{% theme_asset 'theme.css' %}
</head>
<body>
<header>
{% render 'navigation' %}
</header>

<main>
{{ content_for_layout }}
</main>

<footer>
{% render 'footer' %}
</footer>

{% theme_asset 'theme.js' %}
</body>
</html>

config/settings_schema.json

Theme-wide configurable settings organized in groups:

[
{
"name": "Colors",
"settings": [
{
"type": "color",
"id": "primary_color",
"label": "Primary Color",
"default": "#3B82F6"
},
{
"type": "color",
"id": "secondary_color",
"label": "Secondary Color",
"default": "#10B981"
}
]
},
{
"name": "Layout",
"settings": [
{
"type": "range",
"id": "content_width",
"label": "Max Content Width",
"min": 960,
"max": 1920,
"step": 40,
"default": 1280,
"unit": "px"
}
]
}
]

assets/css/_variables.css.liquid

Maps theme settings to CSS variables (processed with Liquid):

:root {
--theme-primary-color: {{ theme.settings.primary_color }};
--theme-secondary-color: {{ theme.settings.secondary_color }};
--theme-content-width: {{ theme.settings.content_width }}px;
}

CSS Framework Integration

Themes are framework-agnostic. You compile your CSS framework locally and include the output.

Create assets/css/tailwind.css:

@import "tailwindcss";

@source "../../sections/**/*.liquid";
@source "../../layouts/**/*.liquid";
@source "../../snippets/**/*.liquid";

Compile locally:

tailwindcss -i assets/css/tailwind.css -o assets/framework.css --watch

This produces a tree-shaken framework.css with only the utilities you use.

Bootstrap or Other Frameworks

Download or compile your framework and place it in assets/framework.css.

No Framework

Simply omit framework.css - the bundler will skip it.

Section Organization

Group sections by category:

sections/
├── hero/ # Hero banners, sliders
├── content/ # Posts, articles, text blocks
├── cta/ # Call-to-action blocks
├── features/ # Feature grids, lists
├── testimonials/ # Reviews, quotes
└── footer/ # Footer variations

Each section file includes:

  1. Liquid template markup
  2. {% schema %} block defining settings
  3. Optional {% style %} block for scoped CSS

CSS Compilation

When theme settings are saved, the platform:

  1. Loads framework.css (if present)
  2. Renders _variables.css.liquid with current settings
  3. Resolves @imports by inlining partial files (plain CSS concatenation via ThemeFileSystem)
  4. Bundles everything into single theme.css

Output is loaded via {% theme_asset 'theme.css' %}.