Initial setup of Theater Ziefen website

- Set up Astro with TypeScript
- Integrate TinaCMS for content management
- Create homepage with hero section and recent posts
- Build blog listing and individual post pages
- Add About and Contact pages
- Implement responsive design with theater theme
- Configure Netlify deployment
- Add comprehensive documentation for developers and editors

Tech stack:
- Framework: Astro 5.x
- CMS: TinaCMS with Git-based workflow
- Content: MDX format for blog and pages
- Styling: Scoped CSS with responsive design
- Deployment: Netlify (configured)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Johannes Gasser
2026-01-28 17:47:49 +01:00
parent 8521a41e30
commit d70897a680
17 changed files with 20033 additions and 46 deletions
+7
View File
@@ -0,0 +1,7 @@
# TinaCMS Configuration
# For local development with Git-based workflow, these can be left empty
# For TinaCMS Cloud, get these values from https://app.tina.io
TINA_CLIENT_ID=
TINA_TOKEN=
TINA_BRANCH=main
+2
View File
@@ -2,6 +2,8 @@
dist/ dist/
# generated types # generated types
.astro/ .astro/
# TinaCMS generated admin
public/admin/
# dependencies # dependencies
node_modules/ node_modules/
+238
View File
@@ -0,0 +1,238 @@
# Content Editor Guide for Theater Ziefen Website
This guide is for non-technical team members who will be managing the website content.
## 📋 Quick Start
### What You Need
- The development server running (ask your developer to set this up)
- A web browser
- Basic knowledge of writing and formatting text
### Accessing the Editor
1. Open your web browser
2. Go to: `http://localhost:4321/admin`
3. You'll see the TinaCMS admin panel
## ✍️ Creating and Editing Blog Posts
### Creating a New Blog Post
1. **Navigate to Blog Posts**
- In the TinaCMS admin panel, click on "Blog Posts" in the left sidebar
2. **Create New Post**
- Click the "Create New" button
- You'll see a form with several fields
3. **Fill in the Post Details**
- **Title**: Enter your blog post title (e.g., "Rehearsal Updates for March")
- **Publication Date**: Click to select the date (usually today's date)
- **Excerpt**: Write a short summary (2-3 sentences) - this appears on the blog listing page
- **Cover Image**: (Optional) Click "Upload" to add a featured image
4. **Write Your Content**
- Use the rich text editor to write your blog post
- Formatting options available:
- **Bold**: Select text and click B
- **Italic**: Select text and click I
- **Headings**: Use ## for main headings, ### for subheadings
- **Lists**: Click the bullet or numbered list icons
- **Links**: Select text, click the link icon, enter URL
5. **Save Your Post**
- Click "Save" in the top right
- Your post will appear on the website immediately!
### Editing an Existing Blog Post
1. Go to "Blog Posts" in the sidebar
2. Click on the post you want to edit
3. Make your changes
4. Click "Save"
### Deleting a Blog Post
1. Go to "Blog Posts" in the sidebar
2. Click on the post you want to delete
3. Click the "Delete" button
4. Confirm the deletion
## 📄 Editing Static Pages
### Editing the About Page
1. In the TinaCMS admin panel, click on "Pages" in the left sidebar
2. Select "About Theater Ziefen"
3. Edit the content using the rich text editor
4. Click "Save"
### Content Tips for Pages
- **Keep it concise**: Visitors typically scan pages, so use short paragraphs
- **Use headings**: Break up content with headings (## Main Heading, ### Subheading)
- **Add lists**: Bullet points make information easy to scan
- **Include calls to action**: Encourage visitors to check the blog, contact you, etc.
## 🖼️ Working with Images
### Adding Images to Blog Posts
1. In the blog post editor, find the "Cover Image" field
2. Click "Upload"
3. Select your image file (JPG or PNG recommended)
4. The image will be uploaded and displayed
### Image Best Practices
- **Size**: Keep images under 2MB for fast loading
- **Dimensions**: 1200x630 pixels works well for blog post covers
- **Format**: Use JPG for photos, PNG for graphics with text
- **File names**: Use descriptive names (e.g., `rehearsal-march-2026.jpg` instead of `IMG_1234.jpg`)
## 📝 Formatting Tips
### Markdown Basics
The editor uses Markdown, a simple formatting language:
```
# Heading 1 (largest)
## Heading 2
### Heading 3
**Bold text**
*Italic text*
- Bullet point 1
- Bullet point 2
1. Numbered item 1
2. Numbered item 2
[Link text](https://example.com)
```
### Writing Style Guidelines
**For Blog Posts:**
- Use a conversational, friendly tone
- Include dates for time-specific information
- Add personal touches and behind-the-scenes details
- End with a call to action or question
**For Static Pages:**
- Be clear and informative
- Use headings to organize information
- Keep paragraphs short (3-4 lines max)
- Update regularly with current information
## 🔄 Publishing Workflow
### How Changes Go Live
1. **You save your changes** in the TinaCMS editor
2. **Changes are saved to Git** automatically
3. **GitHub receives the changes**
4. **Netlify deploys the updated site** (takes 2-3 minutes)
5. **Your changes are live!**
### Checking Your Published Changes
1. Wait 2-3 minutes after saving
2. Visit the live website
3. Refresh your browser to see the changes
## ⚠️ Common Issues and Solutions
### Problem: Can't access `/admin`
**Solution:** Make sure the development server is running. Ask your developer to start it with `npm run dev`.
### Problem: Changes not appearing
**Solution:**
1. Make sure you clicked "Save"
2. Wait a few minutes for deployment
3. Hard refresh your browser (Ctrl+F5 or Cmd+Shift+R)
4. Check if you're viewing the correct URL (development vs. production)
### Problem: Image won't upload
**Solution:**
1. Check file size (should be under 5MB)
2. Make sure it's a supported format (JPG, PNG, GIF)
3. Try renaming the file to remove special characters
### Problem: Formatting looks weird
**Solution:**
1. Try removing all formatting and reapplying it
2. Make sure you're using valid Markdown syntax
3. Preview your changes before saving
## 📅 Content Planning Tips
### Blog Post Ideas
- Rehearsal updates and progress reports
- Cast and crew spotlights
- Behind-the-scenes photos and stories
- Production timeline updates
- Ticket sales announcements (when ready)
- Event announcements
- Community involvement opportunities
- Historical context about the production
### Posting Frequency
- **Minimum**: 1-2 posts per month to keep the site active
- **Ideal**: 1 post per week during active production
- **Special occasions**: Extra posts for major announcements
### Content Calendar
Create a simple calendar with:
- Upcoming post topics
- Important dates to announce
- Seasonal content (holidays, seasons)
- Milestone celebrations
## 🎯 SEO Tips (Optional but Helpful)
### Make Your Content Searchable
1. **Use descriptive titles**: Instead of "Update", use "March 2026 Rehearsal Schedule"
2. **Write good excerpts**: Include key information in the first 2-3 sentences
3. **Use relevant keywords**: Include terms people might search for
4. **Add alt text to images**: Describe what's in the image
## 🆘 Getting Help
### If You Need Assistance
1. **Check this guide first**
2. **Ask your developer** for technical issues
3. **Consult the README.md** for more detailed information
4. **Visit TinaCMS documentation**: https://tina.io/docs
### Quick Reference
- Admin Panel: `http://localhost:4321/admin`
- Live Website: (your website URL)
- Save Button: Top right corner of editor
- Preview: View your page before saving
## 📞 Support Contacts
- **Technical Issues**: [Developer contact]
- **Content Questions**: [Content manager contact]
- **General Questions**: info@theater-ziefen.ch
---
**Remember**: Don't be afraid to experiment! You can always undo changes or ask for help. The system is designed to be user-friendly, so feel free to explore and learn as you go.
Happy editing! 🎭
+193 -19
View File
@@ -1,43 +1,217 @@
# Astro Starter Kit: Minimal # Theater Ziefen Website
```sh Official website for Theater Ziefen - Coming 2029
npm create astro@latest -- --template minimal
```
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun! ## 🎭 Overview
## 🚀 Project Structure This is a modern, easy-to-maintain website built for Theater Ziefen. The site features:
Inside of your Astro project, you'll see the following folders and files: - **Static pages** for general information
- **Blog** for news and updates
- **Visual CMS** (TinaCMS) for non-technical content editing
- **Future-ready** for ticket shop integration
- **Zero-cost hosting** on Netlify
## 🚀 Tech Stack
- **Framework**: [Astro](https://astro.build) - Fast, modern static site generator
- **CMS**: [TinaCMS](https://tina.io) - Git-based visual content management
- **Content**: MDX (Markdown + JSX) for blog posts and pages
- **Styling**: Scoped CSS with responsive design
- **Hosting**: Netlify (free tier)
- **Language**: TypeScript
## 📁 Project Structure
```text ```text
/ /
├── public/ ├── content/ # Content files (edited via TinaCMS)
│ ├── blog/ # Blog posts in MDX format
│ └── pages/ # Static pages in MDX format
├── public/ # Static assets (images, favicon, etc.)
│ └── images/ # Image uploads
├── src/ ├── src/
── pages/ ── layouts/ # Page layouts
└── index.astro └── BaseLayout.astro
└── package.json │ ├── pages/ # Route pages
│ │ ├── index.astro # Homepage
│ │ ├── about.astro # About page
│ │ ├── contact.astro # Contact page
│ │ └── blog/ # Blog pages
│ │ ├── index.astro # Blog listing
│ │ └── [slug].astro # Individual blog posts
│ └── components/ # Reusable components (future)
├── tina/ # TinaCMS configuration
│ └── config.ts # CMS schema and settings
├── .env # Environment variables (not in git)
├── .env.example # Environment variables template
├── netlify.toml # Netlify deployment config
└── package.json # Dependencies and scripts
``` ```
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name. ## 🛠️ Development Setup
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components. ### Prerequisites
Any static assets, like images, can be placed in the `public/` directory. - Node.js 20 or higher
- npm or yarn
- Git
### Installation
1. Clone the repository:
```bash
git clone <repository-url>
cd website-theater-ziefen
```
2. Install dependencies:
```bash
npm install
```
3. Start the development server:
```bash
npm run dev
```
The site will be available at `http://localhost:4321`
The TinaCMS admin panel will be available at `http://localhost:4321/admin`
## 📝 Content Management with TinaCMS
### For Non-Technical Content Editors
1. **Start the development server** (ask your developer if you need help)
2. **Navigate to** `http://localhost:4321/admin`
3. **Click "Edit"** on any page to start editing
4. **Make your changes** using the visual editor
5. **Save** your changes - they'll be committed to Git automatically
### Editing Blog Posts
1. Go to `/admin` in your browser
2. Click on "Blog Posts" in the sidebar
3. To create a new post:
- Click "Add New"
- Fill in the title, date, excerpt
- Write your content in the editor
- Add a cover image (optional)
- Click "Save"
4. To edit an existing post:
- Click on the post in the list
- Make your changes
- Click "Save"
### Editing Pages
1. Go to `/admin` in your browser
2. Click on "Pages" in the sidebar
3. Select the page you want to edit
4. Make your changes using the visual editor
5. Click "Save"
## 🧞 Commands ## 🧞 Commands
All commands are run from the root of the project, from a terminal: All commands are run from the root of the project:
| Command | Action | | Command | Action |
| :------------------------ | :----------------------------------------------- | | :------------------------ | :----------------------------------------------- |
| `npm install` | Installs dependencies | | `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:4321` | | `npm run dev` | Starts dev server with TinaCMS at `localhost:4321` |
| `npm run build` | Build your production site to `./dist/` | | `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying | | `npm run preview` | Preview your build locally, before deploying |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run astro -- --help` | Get help using the Astro CLI |
## 👀 Want to learn more? ## 🌐 Deployment to Netlify
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat). ### Initial Setup
1. Push your code to GitHub:
```bash
git add .
git commit -m "Initial commit"
git push origin main
```
2. Go to [Netlify](https://netlify.com) and sign in
3. Click "Add new site" → "Import an existing project"
4. Select your GitHub repository
5. Configure build settings:
- **Build command**: `npm run build`
- **Publish directory**: `dist`
- Click "Deploy site"
### Automatic Deployments
Once set up, Netlify will automatically deploy your site whenever you push changes to GitHub. This includes content changes made through TinaCMS!
### Custom Domain
To use your own domain:
1. In Netlify, go to "Domain settings"
2. Click "Add custom domain"
3. Follow the instructions to configure your DNS
## 🎨 Customization
### Changing Colors
Edit the CSS variables in `src/layouts/BaseLayout.astro`:
```css
:root {
--color-primary: #8b0000; /* Main brand color */
--color-secondary: #2c3e50; /* Secondary color */
--color-accent: #c0392b; /* Accent color */
/* ... more colors */
}
```
### Adding New Pages
1. Create a new MDX file in `content/pages/`
2. Create a corresponding `.astro` file in `src/pages/`
3. Add a link to the navigation in `src/layouts/BaseLayout.astro`
### Modifying the Homepage
Edit `src/pages/index.astro` to change the homepage content and layout.
## 🔮 Future: Adding Ticket Shop
When you're ready to add ticketing (planned for ~3 years):
### Option 1: Third-Party Integration (Easiest)
- Use services like Stripe, Eventbrite, or Ticketor
- Add embedded widgets to your pages
- No major code changes required
### Option 2: Custom Solution
- Build custom ticketing forms
- Integrate with Stripe for payments
- Add customer accounts and order management
- Requires developer assistance
## 📚 Additional Resources
- [Astro Documentation](https://docs.astro.build)
- [TinaCMS Documentation](https://tina.io/docs)
- [Netlify Documentation](https://docs.netlify.com)
- [MDX Documentation](https://mdxjs.com)
## 🤝 Support
For technical issues or questions:
- Check the documentation links above
- Contact your developer
- Open an issue in the GitHub repository
## 📄 License
Copyright © 2026 Theater Ziefen. All rights reserved.
+4 -1
View File
@@ -1,5 +1,8 @@
// @ts-check // @ts-check
import { defineConfig } from 'astro/config'; import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
// https://astro.build/config // https://astro.build/config
export default defineConfig({}); export default defineConfig({
integrations: [mdx()],
});
+26
View File
@@ -0,0 +1,26 @@
---
title: Welcome to Theater Ziefen
date: 2026-01-28T00:00:00.000Z
excerpt: We're excited to announce our upcoming theatre production in 2029. Stay tuned for more updates!
coverImage: /images/theater-placeholder.jpg
---
# Welcome to Theater Ziefen
We are thrilled to welcome you to the official website of Theater Ziefen. Our theatre production is scheduled to take place in approximately three years, and we can't wait to share this journey with you.
## What to Expect
This blog will keep you updated on:
- Production developments and announcements
- Behind-the-scenes insights
- Cast and crew introductions
- Ticket information (coming soon)
- Event schedules
## Stay Connected
Make sure to check back regularly for updates, or subscribe to our newsletter to receive the latest news directly in your inbox.
We look forward to bringing you an unforgettable theatrical experience!
+27
View File
@@ -0,0 +1,27 @@
---
title: About Theater Ziefen
description: Learn more about our upcoming theatre production and the team behind it
---
# About Theater Ziefen
Theater Ziefen is an exciting theatrical production planned for 2029. Our mission is to bring exceptional live theatre to our community and create memorable experiences for audiences of all ages.
## Our Vision
We believe in the power of theatre to inspire, entertain, and bring people together. Our upcoming production will showcase local talent and creativity while delivering a professional, high-quality performance.
## The Production
Details about our production will be announced in the coming months. Stay tuned to our blog for updates on:
- Show dates and times
- Venue information
- Cast announcements
- Ticket sales
## Get Involved
Interested in being part of Theater Ziefen? We're always looking for passionate individuals to join our team. Whether you're interested in performing, helping backstage, or volunteering, we'd love to hear from you.
Contact us for more information about opportunities to get involved.
+17
View File
@@ -0,0 +1,17 @@
[build]
command = "npm run build"
publish = "dist"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
[build.environment]
NODE_VERSION = "20"
# Enable Netlify Forms
[plugins]
[[plugins.inputs]]
[plugins.inputs.forms]
enabled = true
+18225 -7
View File
File diff suppressed because it is too large Load Diff
+7 -4
View File
@@ -1,14 +1,17 @@
{ {
"name": "evolved-escape", "name": "theater-ziefen-website",
"type": "module", "type": "module",
"version": "0.0.1", "version": "0.0.1",
"scripts": { "scripts": {
"dev": "astro dev", "dev": "tinacms dev -c \"astro dev\"",
"build": "astro build", "build": "tinacms build && astro check && astro build",
"preview": "astro preview", "preview": "astro preview",
"astro": "astro" "astro": "astro"
}, },
"dependencies": { "dependencies": {
"astro": "^5.16.16" "@astrojs/mdx": "^4.3.13",
"@tinacms/cli": "^2.1.2",
"astro": "^5.16.16",
"tinacms": "^3.3.2"
} }
} }
+166
View File
@@ -0,0 +1,166 @@
---
interface Props {
title: string;
description?: string;
}
const { title, description = "Theater Ziefen - Coming 2029" } = Astro.props;
---
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="description" content={description} />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<title>{title} | Theater Ziefen</title>
</head>
<body>
<header class="header">
<div class="container">
<nav class="nav">
<a href="/" class="logo">
<h1>Theater Ziefen</h1>
</a>
<ul class="nav-links">
<li><a href="/">Home</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
</div>
</header>
<main class="main">
<slot />
</main>
<footer class="footer">
<div class="container">
<p>&copy; {new Date().getFullYear()} Theater Ziefen. All rights reserved.</p>
<p class="footer-tagline">Coming 2029</p>
</div>
</footer>
<style>
:root {
--color-primary: #8b0000;
--color-secondary: #2c3e50;
--color-accent: #c0392b;
--color-text: #333;
--color-text-light: #666;
--color-bg: #ffffff;
--color-bg-alt: #f8f9fa;
--spacing-xs: 0.5rem;
--spacing-sm: 1rem;
--spacing-md: 2rem;
--spacing-lg: 3rem;
--spacing-xl: 4rem;
--max-width: 1200px;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
color: var(--color-text);
line-height: 1.6;
background-color: var(--color-bg);
}
.container {
max-width: var(--max-width);
margin: 0 auto;
padding: 0 var(--spacing-md);
}
/* Header Styles */
.header {
background-color: var(--color-secondary);
color: white;
padding: var(--spacing-sm) 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
position: sticky;
top: 0;
z-index: 100;
}
.nav {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
color: white;
text-decoration: none;
}
.logo h1 {
font-size: 1.5rem;
font-weight: 700;
}
.nav-links {
display: flex;
list-style: none;
gap: var(--spacing-md);
}
.nav-links a {
color: white;
text-decoration: none;
font-weight: 500;
transition: color 0.3s ease;
}
.nav-links a:hover {
color: var(--color-accent);
}
/* Main Content */
.main {
min-height: calc(100vh - 200px);
padding: var(--spacing-lg) 0;
}
/* Footer Styles */
.footer {
background-color: var(--color-secondary);
color: white;
padding: var(--spacing-md) 0;
text-align: center;
margin-top: var(--spacing-xl);
}
.footer-tagline {
margin-top: var(--spacing-xs);
color: var(--color-accent);
font-weight: 600;
}
/* Responsive Design */
@media (max-width: 768px) {
.nav {
flex-direction: column;
gap: var(--spacing-sm);
}
.nav-links {
gap: var(--spacing-sm);
}
.container {
padding: 0 var(--spacing-sm);
}
}
</style>
</body>
</html>
+120
View File
@@ -0,0 +1,120 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
const { Content, frontmatter } = await import('../../content/pages/about.mdx');
---
<BaseLayout title={frontmatter.title} description={frontmatter.description}>
<div class="page-header">
<div class="container">
<h1>{frontmatter.title}</h1>
</div>
</div>
<div class="page-content">
<div class="container">
<div class="prose">
<Content />
</div>
</div>
</div>
</BaseLayout>
<style>
.page-header {
background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%);
color: white;
padding: 4rem 0 3rem;
text-align: center;
}
.page-header h1 {
font-size: 3rem;
margin: 0;
}
.page-content {
padding: 3rem 0;
}
.prose {
max-width: 800px;
margin: 0 auto;
font-size: 1.125rem;
line-height: 1.8;
color: #333;
}
.prose :global(h1) {
font-size: 2.5rem;
margin-top: 2.5rem;
margin-bottom: 1rem;
color: #2c3e50;
line-height: 1.2;
}
.prose :global(h2) {
font-size: 2rem;
margin-top: 2rem;
margin-bottom: 0.75rem;
color: #2c3e50;
line-height: 1.3;
}
.prose :global(h3) {
font-size: 1.5rem;
margin-top: 1.5rem;
margin-bottom: 0.5rem;
color: #2c3e50;
}
.prose :global(p) {
margin-bottom: 1.5rem;
}
.prose :global(ul),
.prose :global(ol) {
margin-bottom: 1.5rem;
padding-left: 2rem;
}
.prose :global(li) {
margin-bottom: 0.5rem;
}
.prose :global(a) {
color: #8b0000;
text-decoration: underline;
}
.prose :global(a:hover) {
color: #c0392b;
}
.prose :global(strong) {
font-weight: 700;
color: #2c3e50;
}
@media (max-width: 768px) {
.page-header h1 {
font-size: 2.5rem;
}
.prose {
font-size: 1rem;
}
.prose :global(h1) {
font-size: 2rem;
}
.prose :global(h2) {
font-size: 1.5rem;
}
.prose :global(h3) {
font-size: 1.25rem;
}
}
</style>
+236
View File
@@ -0,0 +1,236 @@
---
import BaseLayout from '../../layouts/BaseLayout.astro';
export async function getStaticPaths() {
const allPosts = await import.meta.glob('../../../content/blog/*.mdx', { eager: true });
return Object.entries(allPosts).map(([path, post]) => {
const slug = path.split('/').pop()?.replace('.mdx', '') || '';
return {
params: { slug },
props: { post },
};
});
}
const { post } = Astro.props;
const { Content, frontmatter } = post;
---
<BaseLayout title={frontmatter.title} description={frontmatter.excerpt}>
<article class="blog-post">
<header class="post-header">
<div class="container">
<h1>{frontmatter.title}</h1>
<p class="post-meta">
<time datetime={frontmatter.date}>
{new Date(frontmatter.date).toLocaleDateString('de-DE', {
year: 'numeric',
month: 'long',
day: 'numeric'
})}
</time>
</p>
</div>
</header>
{frontmatter.coverImage && (
<div class="post-cover">
<img src={frontmatter.coverImage} alt={frontmatter.title} />
</div>
)}
<div class="post-content">
<div class="container">
<div class="prose">
<Content />
</div>
</div>
</div>
<footer class="post-footer">
<div class="container">
<a href="/blog" class="back-link">← Back to all posts</a>
</div>
</footer>
</article>
</BaseLayout>
<style>
.post-header {
background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%);
color: white;
padding: 4rem 0 3rem;
text-align: center;
}
.post-header h1 {
font-size: 3rem;
margin-bottom: 1rem;
line-height: 1.2;
}
.post-meta {
font-size: 1.1rem;
opacity: 0.9;
}
.post-cover {
width: 100%;
max-height: 500px;
overflow: hidden;
background-color: #f8f9fa;
}
.post-cover img {
width: 100%;
height: 100%;
object-fit: cover;
}
.post-content {
padding: 3rem 0;
}
.prose {
max-width: 800px;
margin: 0 auto;
font-size: 1.125rem;
line-height: 1.8;
color: #333;
}
.prose :global(h1) {
font-size: 2.5rem;
margin-top: 2.5rem;
margin-bottom: 1rem;
color: #2c3e50;
line-height: 1.2;
}
.prose :global(h2) {
font-size: 2rem;
margin-top: 2rem;
margin-bottom: 0.75rem;
color: #2c3e50;
line-height: 1.3;
}
.prose :global(h3) {
font-size: 1.5rem;
margin-top: 1.5rem;
margin-bottom: 0.5rem;
color: #2c3e50;
}
.prose :global(p) {
margin-bottom: 1.5rem;
}
.prose :global(ul),
.prose :global(ol) {
margin-bottom: 1.5rem;
padding-left: 2rem;
}
.prose :global(li) {
margin-bottom: 0.5rem;
}
.prose :global(a) {
color: #8b0000;
text-decoration: underline;
}
.prose :global(a:hover) {
color: #c0392b;
}
.prose :global(strong) {
font-weight: 700;
color: #2c3e50;
}
.prose :global(blockquote) {
border-left: 4px solid #8b0000;
padding-left: 1.5rem;
margin: 2rem 0;
font-style: italic;
color: #666;
}
.prose :global(code) {
background-color: #f8f9fa;
padding: 0.2rem 0.4rem;
border-radius: 3px;
font-family: 'Courier New', monospace;
font-size: 0.9em;
}
.prose :global(pre) {
background-color: #2c3e50;
color: white;
padding: 1.5rem;
border-radius: 6px;
overflow-x: auto;
margin: 2rem 0;
}
.prose :global(pre code) {
background-color: transparent;
padding: 0;
}
.prose :global(img) {
max-width: 100%;
height: auto;
border-radius: 6px;
margin: 2rem 0;
}
.post-footer {
padding: 2rem 0 3rem;
border-top: 1px solid #e1e8ed;
}
.back-link {
color: #8b0000;
text-decoration: none;
font-weight: 600;
font-size: 1.1rem;
}
.back-link:hover {
color: #c0392b;
}
@media (max-width: 768px) {
.post-header h1 {
font-size: 2rem;
}
.post-meta {
font-size: 1rem;
}
.prose {
font-size: 1rem;
}
.prose :global(h1) {
font-size: 2rem;
}
.prose :global(h2) {
font-size: 1.5rem;
}
.prose :global(h3) {
font-size: 1.25rem;
}
.post-cover {
max-height: 300px;
}
}
</style>
+180
View File
@@ -0,0 +1,180 @@
---
import BaseLayout from '../../layouts/BaseLayout.astro';
const allPosts = await Astro.glob('../../../../content/blog/*.mdx');
const sortedPosts = allPosts.sort(
(a, b) => new Date(b.frontmatter.date).valueOf() - new Date(a.frontmatter.date).valueOf()
);
---
<BaseLayout title="Blog" description="Latest news and updates from Theater Ziefen">
<div class="blog-header">
<div class="container">
<h1>Blog</h1>
<p>Stay updated with the latest news and behind-the-scenes insights</p>
</div>
</div>
<div class="blog-content">
<div class="container">
{sortedPosts.length === 0 ? (
<p class="no-posts">No blog posts yet. Check back soon!</p>
) : (
<div class="posts-list">
{sortedPosts.map((post) => (
<article class="post-item">
{post.frontmatter.coverImage && (
<div class="post-image">
<img src={post.frontmatter.coverImage} alt={post.frontmatter.title} />
</div>
)}
<div class="post-content">
<h2>
<a href={`/blog/${post.file.split('/').pop()?.replace('.mdx', '')}`}>
{post.frontmatter.title}
</a>
</h2>
<p class="post-meta">
<time datetime={post.frontmatter.date}>
{new Date(post.frontmatter.date).toLocaleDateString('de-DE', {
year: 'numeric',
month: 'long',
day: 'numeric'
})}
</time>
</p>
<p class="post-excerpt">{post.frontmatter.excerpt}</p>
<a href={`/blog/${post.file.split('/').pop()?.replace('.mdx', '')}`} class="read-more">
Read full post →
</a>
</div>
</article>
))}
</div>
)}
</div>
</div>
</BaseLayout>
<style>
.blog-header {
background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%);
color: white;
padding: 4rem 0 3rem;
text-align: center;
}
.blog-header h1 {
font-size: 3rem;
margin-bottom: 0.5rem;
}
.blog-header p {
font-size: 1.25rem;
opacity: 0.9;
}
.blog-content {
padding: 3rem 0;
}
.no-posts {
text-align: center;
font-size: 1.25rem;
color: #666;
padding: 4rem 0;
}
.posts-list {
display: flex;
flex-direction: column;
gap: 3rem;
max-width: 900px;
margin: 0 auto;
}
.post-item {
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.post-item:hover {
transform: translateY(-4px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}
.post-image {
width: 100%;
height: 300px;
overflow: hidden;
}
.post-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.post-content {
padding: 2rem;
}
.post-content h2 {
font-size: 2rem;
margin-bottom: 0.75rem;
}
.post-content h2 a {
color: #2c3e50;
text-decoration: none;
}
.post-content h2 a:hover {
color: #8b0000;
}
.post-meta {
color: #999;
font-size: 0.95rem;
margin-bottom: 1rem;
}
.post-excerpt {
color: #666;
line-height: 1.7;
margin-bottom: 1.5rem;
font-size: 1.05rem;
}
.read-more {
color: #8b0000;
text-decoration: none;
font-weight: 600;
font-size: 1rem;
}
.read-more:hover {
color: #c0392b;
}
@media (max-width: 768px) {
.blog-header h1 {
font-size: 2.5rem;
}
.blog-header p {
font-size: 1.1rem;
}
.post-content h2 {
font-size: 1.5rem;
}
.post-image {
height: 200px;
}
}
</style>
+241
View File
@@ -0,0 +1,241 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout title="Contact" description="Get in touch with Theater Ziefen">
<div class="page-header">
<div class="container">
<h1>Contact Us</h1>
<p>We'd love to hear from you</p>
</div>
</div>
<div class="page-content">
<div class="container">
<div class="contact-content">
<div class="contact-info">
<h2>Get in Touch</h2>
<p>
Have questions about our upcoming production? Interested in getting involved?
We're here to help!
</p>
<div class="info-section">
<h3>Email</h3>
<p><a href="mailto:info@theater-ziefen.ch">info@theater-ziefen.ch</a></p>
</div>
<div class="info-section">
<h3>Follow Us</h3>
<p>Stay connected on social media for the latest updates and behind-the-scenes content.</p>
<div class="social-links">
<a href="#" class="social-link">Facebook</a>
<a href="#" class="social-link">Instagram</a>
<a href="#" class="social-link">Twitter</a>
</div>
</div>
<div class="info-section">
<h3>Newsletter</h3>
<p>
Subscribe to our newsletter to receive updates directly in your inbox.
We'll keep you informed about production progress, ticket sales, and special events.
</p>
</div>
</div>
<div class="contact-form">
<h2>Send us a Message</h2>
<form name="contact" method="POST" data-netlify="true">
<input type="hidden" name="form-name" value="contact" />
<div class="form-group">
<label for="name">Name *</label>
<input type="text" id="name" name="name" required />
</div>
<div class="form-group">
<label for="email">Email *</label>
<input type="email" id="email" name="email" required />
</div>
<div class="form-group">
<label for="subject">Subject *</label>
<input type="text" id="subject" name="subject" required />
</div>
<div class="form-group">
<label for="message">Message *</label>
<textarea id="message" name="message" rows="6" required></textarea>
</div>
<button type="submit" class="btn-submit">Send Message</button>
</form>
</div>
</div>
</div>
</div>
</BaseLayout>
<style>
.page-header {
background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%);
color: white;
padding: 4rem 0 3rem;
text-align: center;
}
.page-header h1 {
font-size: 3rem;
margin: 0 0 0.5rem 0;
}
.page-header p {
font-size: 1.25rem;
opacity: 0.9;
}
.page-content {
padding: 3rem 0;
}
.contact-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4rem;
max-width: 1000px;
margin: 0 auto;
}
.contact-info h2,
.contact-form h2 {
font-size: 2rem;
color: #2c3e50;
margin-bottom: 1.5rem;
}
.contact-info p {
color: #666;
line-height: 1.7;
margin-bottom: 1rem;
}
.info-section {
margin-top: 2rem;
}
.info-section h3 {
font-size: 1.25rem;
color: #2c3e50;
margin-bottom: 0.5rem;
}
.info-section a {
color: #8b0000;
text-decoration: none;
}
.info-section a:hover {
color: #c0392b;
text-decoration: underline;
}
.social-links {
display: flex;
gap: 1rem;
margin-top: 1rem;
}
.social-link {
padding: 0.5rem 1rem;
background-color: #2c3e50;
color: white !important;
border-radius: 4px;
text-decoration: none !important;
font-weight: 600;
transition: background-color 0.3s ease;
}
.social-link:hover {
background-color: #8b0000;
}
.contact-form {
background-color: #f8f9fa;
padding: 2rem;
border-radius: 8px;
}
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
font-weight: 600;
color: #2c3e50;
margin-bottom: 0.5rem;
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: 4px;
font-family: inherit;
font-size: 1rem;
transition: border-color 0.3s ease;
}
.form-group input:focus,
.form-group textarea:focus {
outline: none;
border-color: #8b0000;
}
.form-group textarea {
resize: vertical;
}
.btn-submit {
width: 100%;
padding: 1rem;
background-color: #8b0000;
color: white;
border: none;
border-radius: 4px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: background-color 0.3s ease;
}
.btn-submit:hover {
background-color: #c0392b;
}
@media (max-width: 768px) {
.page-header h1 {
font-size: 2.5rem;
}
.page-header p {
font-size: 1.1rem;
}
.contact-content {
grid-template-columns: 1fr;
gap: 2rem;
}
.contact-info h2,
.contact-form h2 {
font-size: 1.5rem;
}
.social-links {
flex-direction: column;
}
}
</style>
+244 -14
View File
@@ -1,17 +1,247 @@
--- ---
import BaseLayout from '../layouts/BaseLayout.astro';
const recentPosts = await Astro.glob('../../../content/blog/*.mdx');
const sortedPosts = recentPosts
.sort((a, b) => new Date(b.frontmatter.date).valueOf() - new Date(a.frontmatter.date).valueOf())
.slice(0, 3);
---
--- <BaseLayout title="Home">
<div class="hero">
<div class="container">
<h1 class="hero-title">Theater Ziefen</h1>
<p class="hero-subtitle">An Unforgettable Theatrical Experience</p>
<p class="hero-date">Coming 2029</p>
<div class="hero-cta">
<a href="/about" class="btn btn-primary">Learn More</a>
<a href="/blog" class="btn btn-secondary">Latest Updates</a>
</div>
</div>
</div>
<html lang="en"> <section class="intro">
<head> <div class="container">
<meta charset="utf-8" /> <h2>Welcome to Theater Ziefen</h2>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <p>
<link rel="icon" href="/favicon.ico" /> We are excited to bring you an exceptional theatrical production in 2029.
<meta name="viewport" content="width=device-width" /> This website will be your hub for all updates, news, and information about
<meta name="generator" content={Astro.generator} /> our upcoming show.
<title>Astro</title> </p>
</head> <p>
<body> Stay connected with us through our blog, where we'll share behind-the-scenes
<h1>Astro</h1> insights, production updates, and announcements about ticket sales when they
</body> become available.
</html> </p>
</div>
</section>
{sortedPosts.length > 0 && (
<section class="recent-posts">
<div class="container">
<h2>Latest Updates</h2>
<div class="posts-grid">
{sortedPosts.map((post) => (
<article class="post-card">
<h3>
<a href={`/blog/${post.file.split('/').pop()?.replace('.mdx', '')}`}>
{post.frontmatter.title}
</a>
</h3>
<p class="post-date">
{new Date(post.frontmatter.date).toLocaleDateString('de-DE', {
year: 'numeric',
month: 'long',
day: 'numeric'
})}
</p>
<p class="post-excerpt">{post.frontmatter.excerpt}</p>
<a href={`/blog/${post.file.split('/').pop()?.replace('.mdx', '')}`} class="read-more">
Read more →
</a>
</article>
))}
</div>
<div class="view-all">
<a href="/blog" class="btn btn-secondary">View All Posts</a>
</div>
</div>
</section>
)}
</BaseLayout>
<style>
.hero {
background: linear-gradient(135deg, #2c3e50 0%, #8b0000 100%);
color: white;
padding: 6rem 0;
text-align: center;
}
.hero-title {
font-size: 3.5rem;
font-weight: 800;
margin-bottom: 1rem;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}
.hero-subtitle {
font-size: 1.5rem;
margin-bottom: 0.5rem;
opacity: 0.95;
}
.hero-date {
font-size: 1.25rem;
font-weight: 600;
color: #ffd700;
margin-bottom: 2rem;
}
.hero-cta {
display: flex;
gap: 1rem;
justify-content: center;
flex-wrap: wrap;
}
.btn {
padding: 0.75rem 2rem;
border-radius: 4px;
text-decoration: none;
font-weight: 600;
transition: all 0.3s ease;
display: inline-block;
}
.btn-primary {
background-color: #c0392b;
color: white;
}
.btn-primary:hover {
background-color: #8b0000;
transform: translateY(-2px);
}
.btn-secondary {
background-color: white;
color: #2c3e50;
}
.btn-secondary:hover {
background-color: #f8f9fa;
transform: translateY(-2px);
}
.intro {
padding: 4rem 0;
background-color: #f8f9fa;
}
.intro h2 {
font-size: 2.5rem;
margin-bottom: 1.5rem;
color: #2c3e50;
text-align: center;
}
.intro p {
font-size: 1.125rem;
line-height: 1.8;
max-width: 800px;
margin: 0 auto 1rem;
color: #666;
}
.recent-posts {
padding: 4rem 0;
}
.recent-posts h2 {
font-size: 2.5rem;
margin-bottom: 2rem;
color: #2c3e50;
text-align: center;
}
.posts-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
margin-bottom: 2rem;
}
.post-card {
background: white;
padding: 2rem;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.post-card:hover {
transform: translateY(-4px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}
.post-card h3 {
font-size: 1.5rem;
margin-bottom: 0.5rem;
}
.post-card h3 a {
color: #2c3e50;
text-decoration: none;
}
.post-card h3 a:hover {
color: #8b0000;
}
.post-date {
color: #999;
font-size: 0.9rem;
margin-bottom: 1rem;
}
.post-excerpt {
color: #666;
line-height: 1.6;
margin-bottom: 1rem;
}
.read-more {
color: #8b0000;
text-decoration: none;
font-weight: 600;
}
.read-more:hover {
color: #c0392b;
}
.view-all {
text-align: center;
margin-top: 2rem;
}
@media (max-width: 768px) {
.hero-title {
font-size: 2.5rem;
}
.hero-subtitle {
font-size: 1.25rem;
}
.intro h2,
.recent-posts h2 {
font-size: 2rem;
}
.posts-grid {
grid-template-columns: 1fr;
}
}
</style>
+99
View File
@@ -0,0 +1,99 @@
import { defineConfig } from "tinacms";
// Your TinaCMS configuration
export default defineConfig({
branch: process.env.TINA_BRANCH || "main",
clientId: process.env.TINA_CLIENT_ID || "",
token: process.env.TINA_TOKEN || "",
build: {
outputFolder: "admin",
publicFolder: "public",
},
media: {
tina: {
mediaRoot: "images",
publicFolder: "public",
},
},
schema: {
collections: [
{
name: "post",
label: "Blog Posts",
path: "content/blog",
format: "mdx",
fields: [
{
type: "string",
name: "title",
label: "Title",
isTitle: true,
required: true,
},
{
type: "datetime",
name: "date",
label: "Publication Date",
required: true,
},
{
type: "string",
name: "excerpt",
label: "Excerpt",
required: true,
description: "Short summary of the blog post",
},
{
type: "image",
name: "coverImage",
label: "Cover Image",
description: "Featured image for the blog post",
},
{
type: "rich-text",
name: "body",
label: "Body",
isBody: true,
required: true,
},
],
defaultItem: () => {
return {
title: "New Blog Post",
date: new Date().toISOString(),
excerpt: "",
};
},
},
{
name: "page",
label: "Pages",
path: "content/pages",
format: "mdx",
fields: [
{
type: "string",
name: "title",
label: "Title",
isTitle: true,
required: true,
},
{
type: "string",
name: "description",
label: "Description",
description: "Meta description for SEO",
},
{
type: "rich-text",
name: "body",
label: "Content",
isBody: true,
required: true,
},
],
},
],
},
});