# LaysanX Theme Designer Guide

LaysanX custom themes are normal HTML, CSS, and JavaScript packages with LaysanX template placeholders for dynamic data. Designers do not need to write .NET code.

## Quick Start

1. Download or clone the LaysanX Atlas reference theme.
2. Edit normal HTML, CSS, and JavaScript.
3. Keep placeholders and loops.
4. If you downloaded the Atlas ZIP, upload it directly. If you cloned the repo, zip the theme folder without `.git` or hidden files.
5. Upload it from Client Admin theme customization.
6. Preview it.
7. Publish it.

Reference theme download:

`/downloads/laysanx-atlas.zip`

## Client-Scoped Uploads And Exports

When a plan includes `Download Code/Assets & Data Export`, the client can download uploaded assets or theme ZIPs, plus client data exports in JSON or SQL format, from Client Admin for backup, transfer, or external deployment.

Client theme editing stays scoped to the active theme package only:

- file search and search/replace work on the current uploaded theme
- custom page templates can be created under theme-owned page folders and remain editable after save
- file delete only removes files from the active client theme package
- exports keep client-owned assets and data together while excluding server-side code, secrets, and private config

## Security And Widget Policy

If a theme needs third-party widgets or embeds, add an optional `security.csp` block inside `theme.json` so the runtime can build a narrower CSP around the exact hosts that theme needs.

Prefer the smallest practical allowlist:

- keep inline script and style support only when the theme needs it
- keep `unsafe-eval` disabled unless a widget truly depends on it
- allow only the trusted HTTPS hosts used by the theme
- prefer iframe embeds for heavy third-party widgets when possible

This keeps uploaded themes usable for real business widgets without opening the storefront more than necessary.

Reference theme Git repository:

`https://github.com/LaysanX/atlas-theme`

Clone command:

```bash
git clone https://github.com/LaysanX/atlas-theme.git
```

## Package Structure

```txt
laysanx-atlas.zip
  theme.json
  README.md
  LICENSE.md
  templates/        # Home, content, commerce, and customer pages
  sections/         # Shared and page-specific components
  assets/css/style.css
  assets/js/main.js
```

The complete template and section list is defined in Atlas `theme.json`. Keep its paths and files in sync when editing. GitHub's Download ZIP includes one wrapping folder, which the theme uploader also accepts.

## Allowed Files

- `.html`
- `.css`
- `.js`
- `.json`
- `.md`
- images such as `.jpg`, `.jpeg`, `.png`, `.webp`, `.svg`, `.gif`
- fonts such as `.woff`, `.woff2`, `.ttf`

## Not Allowed

- `.cshtml`, `.cs`, `.dll`, `.exe`, `.php`, `.py`, `.sh`
- server-side scripts
- files outside the uploaded theme folder
- hidden executable payloads

## Common Placeholders

```liquid
{{ site.name }}
{{ site.logo }}
{{ site.email }}
{{ site.phone }}
{{ site.address }}
{{ page.title }}
{{ page.subheading }}
{{ page.content }}
{{ seo.title }}
{{ seo.description }}
{{ seo.keywords }}
{{ settings.primary_color }}
{{ 'assets/css/style.css' | asset_url }}
```

## Common Loops

```liquid
{% for item in menus.header %}
  <a href="{{ item.url }}">{{ item.title }}</a>
{% endfor %}

{% for service in services limit: section_controls.services.count %}
  <article>
    <img src="{{ service.image }}" alt="{{ service.title }}">
    <h3>{{ service.title }}</h3>
    <p>{{ service.short_description }}</p>
    <a href="{{ service.url }}">View More</a>
  </article>
{% endfor %}

{% for item in news limit: section_controls.news.count %}
  <a href="{{ item.url }}">{{ item.title }}</a>
{% endfor %}

{% for plan in pricing_plans limit: section_controls.pricing_plans.count %}
  <h3>{{ plan.title }}</h3>
  <strong>{{ plan.primary_price_formatted | default: plan.price_formatted | default: plan.price }}</strong>
  <a href="{{ plan.checkout_url | default: plan.checkoutUrl | default: plan.direct_checkout_url | default: plan.directCheckoutUrl }}">
    {{ plan.cta_text | default: 'Buy Now' }}
  </a>
{% endfor %}
```

Other list objects available to designers: `products`, `projects`, `blogs`, `events`, `notifications`, `gallery`, `faqs`, `jobs`, `team`, `testimonials`, `clients`, and `partners`.

## Ecommerce, Currency, And Pricing Placeholders

Uploaded themes receive storefront ecommerce context when commerce is enabled:

```liquid
{{ ecommerce.enabled }}
{{ ecommerce.cart_count }}
{{ ecommerce.urls.cart }}
{{ ecommerce.urls.checkout }}
{{ ecommerce.urls.orders }}
{{ ecommerce.urls.returns }}
{{ ecommerce.urls.account }}
{{ ecommerce.urls.login }}
{{ ecommerce.urls.wishlist }}
```

Currency context:

```liquid
{{ currency.code }}
{{ currency.symbol }}
{{ currency.switch_url }}

{% for item in currencies %}
  <option value="{{ item.code }}" {% if currency.code == item.code %}selected{% endif %}>{{ item.symbol }} {{ item.code }}</option>
{% endfor %}
```

Header currency selector example:

```liquid
{% if currencies.size > 0 %}
  <form class="currency-switcher" method="post" action="{{ currency.switch_url | default: '/currency' }}">
    <input type="hidden" name="returnUrl" value="{{ routes.current | default: routes.home | default: '/' }}">
    <select name="currencyCode" onchange="this.form.submit()" aria-label="Currency">
      {% for item in currencies %}
        <option value="{{ item.code }}" {% if currency.code == item.code %}selected{% endif %}>{{ item.symbol }} {{ item.code }}</option>
      {% endfor %}
    </select>
  </form>
{% endif %}
```

Product prices should prefer formatted symbol-first fields:

```liquid
{{ product.primary_price_formatted | default: product.selling_price_formatted | default: product.price_formatted | default: product.price }}
{{ product.compare_at_price_formatted | default: product.compare_at_price }}
```

Pricing plans also expose formatted prices and direct checkout:

```liquid
{{ plan.primary_price_formatted | default: plan.selling_price_formatted | default: plan.price_formatted | default: plan.price }}
{{ plan.checkout_url | default: plan.checkoutUrl | default: plan.direct_checkout_url | default: plan.directCheckoutUrl }}
{{ plan.cart_line_type | default: plan.cartLineType }}
```

For product cards:

```liquid
{% if ecommerce.enabled %}
  {% if product.has_variants %}
    <a href="{{ product.url }}">Choose Options</a>
  {% else %}
    <form method="post" action="{{ ecommerce.urls.cart }}?handler=Add">
      <input type="hidden" name="productId" value="{{ product.id }}">
      <input type="hidden" name="quantity" value="1">
      <button type="submit">Add to Cart</button>
    </form>
  {% endif %}
{% endif %}
```

## Product Detail Expectations

- Product gallery should include the main image, gallery images, and variant images.
- Variant selection should switch the main gallery image instead of showing a separate small image near quantity.
- Wishlist actions should use the runtime customer wishlist route and return to the current page.
- Keep quantity, add-to-cart, and wishlist controls compact on mobile and desktop.

## AI Website Builder Themes

AI Website Builder-generated uploaded theme ZIPs now preserve the exact copied sample theme templates, CSS, JavaScript, and image assets. Generated fallback files only fill missing templates. Designers can therefore treat `sample-projects/*-theme` as the canonical design source for AI theme output.

## Dynamic Forms

Do not hard-code contact form fields. Render the assigned form:

```liquid
{% render 'sections/contact-form.html', form: forms.contact %}
```

The platform controls required fields, file uploads, captcha, and button CTA text.

## Responsive Rules

- Design for mobile, tablet, and desktop.
- Do not allow horizontal scrolling.
- Keep buttons at 10px border radius unless the brand requires less.
- Service cards should include image, title, short description, and View More.
- Menus with more than 10 child items may use two columns, but must stay inside the viewport.

## Upload Flow

When the custom theme upload feature is enabled:

1. Open Client Admin.
2. Go to Themes.
3. Upload ZIP.
4. Validate package.
5. Preview theme.
6. Publish theme.

Publishing should not require an app restart because theme assets and templates are runtime files.
