Ein vollständiges Restaurant-Theme zum Kopieren
Alle Dateien eines kleinen, lauffähigen TacticTable-Themes: Layout, zwei Vorlagen, editierbare Abschnitte und Blöcke, Navigation, CSS und Sprachen.
Für EntwicklerVoraussetzungen
- Recht: website:write
- Plan mit Website
Dieses Beispiel ist ein vollständiger Text-Theme-Stand. Legen Sie die Dateien unter genau den Titeln der Codeblöcke an, verpacken Sie den Ordner als ZIP und laden Sie ihn unter Website → Theme hochladen ohne KI-Umwandlung hoch. Das Archiv darf einen gemeinsamen Wurzelordner haben. Lassen Sie AGENTS.md und agent.md beim Import weg; ein Export ergänzt sie später selbst.
Der Einstieg erfolgt über templates/index.json. Das Layout setzt die geordneten Body-Abschnitte bei content_for_layout ein und holt Header und Footer als feste Abschnitte. templates/page.json stellt den Inhalt einer Dashboard-Seite dar. Eine neue JSON-Vorlage erzeugt jedoch weder einen Seiten-Datensatz noch einen Menüpunkt; beide legen Sie im Dashboard an.
Das Beispiel bietet drei globale Designfelder, ein dynamisch auswählbares und verschachteltes Navigationsmenü, einen Bild-Aufmacher, zwei editierbare Blockkarten, aktuelle Öffnungszeiten/Produkte, eine Inhaltsseite und einen Footer. Es nutzt nur Textdateien; Bilddateien kommen aus der Mediathek und werden per image_picker als URL hinterlegt.
Nach dem Upload öffnen Sie das Theme Studio, prüfen Startseite und Inhaltsseite in der Vorschau, bearbeiten Texte/Bild/Menü und speichern. Veröffentlichen oder aktivieren Sie erst nach der Kontrolle. Der gespeicherte Entwurf und die veröffentlichte Revision können verschieden sein.
assets/theme.css.liquid verwendet Akzentfarbe und Inhaltsbreite aus den globalen Theme-Einstellungen. Der Browser lädt dieselbe Adresse theme.css, obwohl die Quelldatei auf .liquid endet. Ändern Sie die Werte im Theme-Editor und prüfen Sie die Vorschau.
Schritt für Schritt
Ordnerstruktur anlegen
theme.json im Wurzelordner, dazu config/, layout/, templates/, sections/, assets/ und locales/. Alle Dateinamen aus den Codeblöcken übernehmen.
Als ZIP hochladen
Website → Theme hochladen; ein fertiges TacticTable-Theme ohne KI-Umwandlung importieren. Binärdateien separat in die Mediathek laden.
Inhalte verbinden
Website → Navigations-Menüs: main-menu erstellen oder im Header auswählen. Website → Seiten: eine Seite veröffentlichen und die Vorlage page zuweisen.
Vorschau prüfen
Startseite und Inhaltsseite auf Mobil und Desktop testen; leere Bilder, Menülinks, Blockreihenfolge und Reservierungslink prüfen.
Codebeispiele
{ "id": "restaurant-starter", "name": "Restaurant Starter", "version": "1.0.0", "category": "restaurant", "default_locale": "de", "supported_locales": ["de", "en"]}[ { "name": "Design", "settings": [ { "type": "color", "id": "accent", "label": "Akzentfarbe", "default": "#7b3f2a" }, { "type": "image_picker", "id": "logo", "label": "Logo" }, { "type": "range", "id": "content_width", "label": "Inhaltsbreite", "min": 800, "max": 1400, "step": 20, "unit": "px", "default": 1120 } ] }]{ "current": { "accent": "#7b3f2a", "logo": "", "content_width": 1120 }}<!doctype html><html lang="{{ locale | escape }}"><head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>{{ page_meta.title | default: page_title | default: restaurant.name | escape }}</title> {% if page_meta.description %}<meta name="description" content="{{ page_meta.description | escape }}">{% endif %} <link rel="stylesheet" href="{{ 'theme.css' | asset_url }}"></head><body> <a class="skip" href="#inhalt">{{ 'accessibility.skip' | t | escape }}</a> {% section 'header' %} <main id="inhalt">{{ content_for_layout }}</main> {% section 'footer' %}</body></html>{ "name": "Startseite", "sections": { "header": { "type": "header", "settings": { "menu_id": "" } }, "hero": { "type": "hero", "settings": { "title": "{{ restaurant.name }}", "subtitle": "Willkommen bei uns", "button_label": "Tisch reservieren", "image": "" } }, "highlights": { "type": "highlights", "settings": { "heading": "Darauf freuen wir uns" }, "blocks": { "kitchen": { "type": "highlight", "settings": { "title": "Unsere Küche", "text": "Frisch und saisonal." } }, "service": { "type": "highlight", "settings": { "title": "Unser Service", "text": "Gastfreundschaft jeden Tag." } } }, "block_order": ["kitchen", "service"] }, "restaurant_data": { "type": "restaurant-data", "settings": { "heading": "Gut zu wissen" } }, "footer": { "type": "footer", "settings": {} } }, "order": ["header", "hero", "highlights", "restaurant_data", "footer"]}{ "name": "Inhaltsseite", "sections": { "header": { "type": "header", "settings": { "menu_id": "" } }, "content": { "type": "page-content", "settings": {} }, "footer": { "type": "footer", "settings": {} } }, "order": ["header", "content", "footer"]}<header class="site-header"> {% assign logo = settings.logo | default: restaurant.logo_url | safe_url %} <a class="brand" href="/"> {% if logo != blank %}<img src="{{ logo }}" alt="{{ restaurant.name | escape }}" width="160" height="64">{% else %}{{ restaurant.name | escape }}{% endif %} </a> {% assign menu = navigation_menus_by_id[section.settings.menu_id] %} {% if menu == nil %}{% assign menu = navigation_menus_by_handle['main-menu'] %}{% endif %} <nav aria-label="Hauptnavigation"> {% render 'nav-items', items: menu.items %} </nav> <a class="button" href="{{ restaurant.booking_url | safe_href }}">{{ 'nav.book' | t | escape }}</a></header><ul>{% for item in items %} <li> <a href="{{ item.url | safe_href }}"{% if item.open_in_new %} target="_blank" rel="noopener noreferrer"{% endif %}>{{ item.label | escape }}</a> {% if item.children != blank %}{% render 'nav-items', items: item.children %}{% endif %} </li>{% endfor %}</ul>{ "name": "Kopfbereich", "settings": [ { "type": "select", "id": "menu_id", "label": "Navigationsmenü", "dynamic_options": "navigation_menus", "options": [], "default": "" } ], "default": { "settings": { "menu_id": "" } }}<section class="hero" aria-labelledby="hero-title"> {% assign image = section.settings.image | safe_url %} {% if image != blank %}<img class="hero-image" src="{{ image }}" alt="" fetchpriority="high">{% endif %} <div class="wrap hero-copy"> <h1 id="hero-title">{{ section.settings.title | escape }}</h1> <p>{{ section.settings.subtitle | escape }}</p> <a class="button" href="{{ restaurant.booking_url | safe_href }}">{{ section.settings.button_label | escape }}</a> </div></section>{ "name": "Aufmacher", "settings": [ { "type": "text", "id": "title", "label": "Überschrift", "default": "Willkommen" }, { "type": "textarea", "id": "subtitle", "label": "Untertitel", "default": "" }, { "type": "text", "id": "button_label", "label": "Knopftext", "default": "Tisch reservieren" }, { "type": "image_picker", "id": "image", "label": "Titelbild" } ]}<section class="wrap highlights" aria-labelledby="highlights-title"> <h2 id="highlights-title">{{ section.settings.heading | escape }}</h2> <div class="cards"> {% for block in section.blocks %} <article class="card"> <h3>{{ block.settings.title | escape }}</h3> <p>{{ block.settings.text | escape }}</p> </article> {% else %} <p>Hier können Sie im Theme-Editor Einträge hinzufügen.</p> {% endfor %} </div></section>{ "name": "Besonderheiten", "settings": [ { "type": "text", "id": "heading", "label": "Überschrift", "default": "Besonderheiten" } ], "blocks": [ { "type": "highlight", "name": "Eintrag", "settings": [ { "type": "text", "id": "title", "label": "Titel", "default": "Neuer Eintrag" }, { "type": "textarea", "id": "text", "label": "Beschreibung", "default": "" } ] } ]}<article class="wrap page-content"> <h1>{{ page.title | escape }}</h1> {% if page.eyebrow != blank %}<p class="eyebrow">{{ page.eyebrow | escape }}</p>{% endif %} <div class="page-body">{{ page.body | escape | newline_to_br }}</div></article><section class="wrap restaurant-data" aria-labelledby="data-title"> <h2 id="data-title">{{ section.settings.heading | escape }}</h2> <div class="data-grid"> <div><h3>Öffnungszeiten</h3><ul> {% for day in restaurant.opening_hours %} <li>{{ day.label | escape }}: {% if day.closed %}Geschlossen{% else %}{{ day.times | escape }}{% endif %}</li> {% else %}<li>Zeiten folgen.</li>{% endfor %} </ul></div> <div><h3>Aus der Speisekarte</h3><ul> {% for product in products limit: 4 %} <li>{{ product.title | escape }} · {{ product.price | escape }}</li> {% else %}<li>Die Karte folgt.</li>{% endfor %} </ul></div> </div></section>{ "name": "Betriebsdaten", "settings": [ { "type": "text", "id": "heading", "label": "Überschrift", "default": "Gut zu wissen" } ]}<footer class="site-footer"> <div class="wrap"> <p>{{ restaurant.name | escape }}</p> {% if restaurant.address_full %}<p>{{ restaurant.address_full | escape }}</p>{% endif %} {% if restaurant.email %}{% assign mail = restaurant.email | prepend: 'mailto:' %}<a href="{{ mail | safe_href }}">{{ restaurant.email | escape }}</a>{% endif %} {% if rechtsseiten.impressum %}<a href="/impressum">Impressum</a>{% endif %} {% if rechtsseiten.datenschutz %}<a href="/datenschutz">Datenschutz</a>{% endif %} </div></footer>:root{font-family:system-ui,sans-serif;color:#201b18;background:#fff;--accent:{{ settings.accent | default: '#7b3f2a' }};--width:{{ settings.content_width | default: 1120 }}px}*{box-sizing:border-box}body{margin:0}a{color:inherit}.wrap{width:min(100% - 2rem,var(--width));margin-inline:auto}.skip{position:absolute;left:-9999px}.skip:focus{left:1rem;top:1rem;background:#fff;padding:.6rem}.site-header{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:1rem max(1rem,calc((100vw - var(--width))/2))}.site-header ul{display:flex;flex-wrap:wrap;gap:1rem;list-style:none;padding:0}.brand img{display:block;max-width:160px;object-fit:contain}.button{display:inline-block;padding:.8rem 1rem;background:var(--accent);color:#fff;text-decoration:none;border-radius:.25rem}.hero{position:relative;min-height:30rem;display:grid;align-items:center;background:#f5eee9}.hero-image{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:.24}.hero-copy{position:relative;padding-block:5rem}.hero h1{font-size:clamp(2.5rem,7vw,5rem)}.highlights,.restaurant-data,.page-content{padding-block:4rem}.cards,.data-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));gap:1rem}.card{padding:1.5rem;border:1px solid #ddd}.site-footer{padding:3rem 0;background:#201b18;color:#fff}@media(max-width:700px){.site-header{flex-wrap:wrap}.site-header nav{order:3;width:100%}.site-header ul{gap:.75rem}}{"accessibility":{"skip":"Zum Inhalt springen"},"nav":{"book":"Tisch reservieren"}}{"accessibility":{"skip":"Skip to content"},"nav":{"book":"Book a table"}}Siehe auch
- Wie ein Theme aufgebaut istDie Verzeichnisse eines Themes, seine Pflichtdateien und mindestens eine Seitenvorlage.
- Einen eigenen Abschnitt bauenZwei Dateien genügen: die Vorlage und ihr Schema — danach steht der Abschnitt im Theme-Editor zur Auswahl.
- CSS, JavaScript, Bilder und Schriften richtig einbindenText-Assets, Liquid-CSS und Medien-URLs im Entwurf und auf der veröffentlichten Website.
- Theme-Stände prüfen, exportieren und mit GitHub verbindenDer vollständige Revisionsstand in TacticTable, ZIP-Import/Export und der optionale GitHub-Abgleich.
- Navigationsmenü für Kopf- und Fussbereich pflegenWelche Punkte oben und unten auf Ihrer Website stehen — und wohin sie führen.