generated from ooriyap/astro-docker-kit
274 lines
8.8 KiB
Markdown
274 lines
8.8 KiB
Markdown
<div align="center">
|
||
|
||
# 🚀 Astro Docker Kit
|
||
|
||
</div>
|
||
|
||
## 🚀 Quick Start
|
||
|
||
```bash
|
||
git clone https://github.com/advento-ir/astro-docker-kit
|
||
cd astro-docker-kit
|
||
npm install
|
||
npm run dev
|
||
```
|
||
|
||
Visit `http://localhost:4321`.
|
||
|
||
---
|
||
|
||
## 🐳 Deploy with Docker
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
docker network create private-net # required once
|
||
docker compose up -d
|
||
```
|
||
|
||
---
|
||
|
||
## 📁 Project Structure
|
||
|
||
```text
|
||
/
|
||
├── public/fonts/iran-yekan-x/ # IRANYekanX woff2 files
|
||
├── src/
|
||
│ ├── components/
|
||
│ │ ├── blocks/ # Content block components
|
||
│ │ ├── core/ # Base UI components
|
||
│ │ ├── layout/ # Header, footer, sidebar
|
||
│ │ └── meta/SEO.astro # SEO component
|
||
│ ├── layouts/BaseLayout.astro # RTL/FA base layout
|
||
│ ├── pages/index.astro # Homepage
|
||
│ └── styles/
|
||
│ ├── fonts.css # Persian font definitions
|
||
│ └── global.css # Global styles + Tailwind
|
||
├── Dockerfile
|
||
├── docker-compose.yml
|
||
└── nginx.conf
|
||
```
|
||
|
||
---
|
||
|
||
## 🔍 SEO Component
|
||
|
||
`src/components/meta/SEO.astro` is a full-featured, drop-in SEO component used inside `BaseLayout.astro`. It handles every layer of modern SEO — from core meta tags to structured data — with zero external dependencies.
|
||
|
||
### Features at a glance
|
||
|
||
| Category | What's included |
|
||
| --- | --- |
|
||
| Core meta | `<title>`, `description`, `keywords`, `author`, `robots`, `theme-color`, `color-scheme`, `generator` |
|
||
| Canonical | Auto-detected from `Astro.url.href` or manually overridden |
|
||
| Open Graph | `og:type`, `og:title`, `og:description`, `og:image` (+ width/height/alt), `og:locale`, `og:site_name` |
|
||
| OG Article | `article:published_time`, `article:modified_time`, `article:section`, `article:tag`, `article:author` |
|
||
| Twitter Card | `twitter:card`, `twitter:title`, `twitter:description`, `twitter:image`, `twitter:site`, `twitter:creator` |
|
||
| JSON-LD | Auto-generated `WebSite`, `WebPage` / `Article`, `BreadcrumbList` schemas + custom schema injection |
|
||
| hreflang | Alternate locale `<link>` tags for multilingual sites |
|
||
| Resource hints | `preconnect` and `dns-prefetch` link tags |
|
||
| Favicon | SVG icon, ICO fallback, Apple touch icon, Web App Manifest |
|
||
|
||
---
|
||
|
||
### Basic usage
|
||
|
||
`BaseLayout.astro` already wires the component up — just pass props when using the layout:
|
||
|
||
```astro
|
||
---
|
||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||
---
|
||
|
||
<BaseLayout
|
||
title="My Page"
|
||
description="A short description of this page."
|
||
/>
|
||
```
|
||
|
||
All other props are optional and tree-shake to nothing when unused.
|
||
|
||
---
|
||
|
||
### All props
|
||
|
||
#### Core
|
||
|
||
| Prop | Type | Default | Description |
|
||
| --- | --- | --- | --- |
|
||
| `title` | `string` | **required** | Page title (also used as OG/Twitter fallback) |
|
||
| `titleTemplate` | `string` | `'%s'` | Wraps the title — `%s` is replaced with `title`. E.g. `'%s \| Advento'` |
|
||
| `description` | `string` | **required** | Meta description (also used as OG/Twitter fallback) |
|
||
| `keywords` | `string[]` | — | Comma-joined into `<meta name="keywords">` |
|
||
| `author` | `string` | — | `<meta name="author">` |
|
||
| `themeColor` | `string` | `'#7c3aed'` | `<meta name="theme-color">` |
|
||
|
||
#### Canonical & Robots
|
||
|
||
| Prop | Type | Default | Description |
|
||
| --- | --- | --- | --- |
|
||
| `canonical` | `string` | `Astro.url.href` | Absolute canonical URL |
|
||
| `noindex` | `boolean` | `false` | Add `noindex` to the robots directive |
|
||
| `nofollow` | `boolean` | `false` | Add `nofollow` to the robots directive |
|
||
|
||
#### Open Graph
|
||
|
||
| Prop | Type | Default | Description |
|
||
| --- | --- | --- | --- |
|
||
| `ogType` | `'website' \| 'article' \| 'profile'` | `'website'` | OG object type |
|
||
| `ogTitle` | `string` | resolved `title` | Override OG title |
|
||
| `ogDescription` | `string` | `description` | Override OG description |
|
||
| `ogImage` | `string` | — | Absolute URL to the OG image (1200×630 recommended) |
|
||
| `ogImageAlt` | `string` | — | Alt text for the OG image |
|
||
| `ogImageWidth` | `number` | `1200` | OG image width in pixels |
|
||
| `ogImageHeight` | `number` | `630` | OG image height in pixels |
|
||
| `ogLocale` | `string` | `'fa_IR'` | OG locale string |
|
||
| `ogSiteName` | `string` | — | `og:site_name` |
|
||
|
||
#### Twitter Card
|
||
|
||
| Prop | Type | Default | Description |
|
||
| --- | --- | --- | --- |
|
||
| `twitterCard` | `'summary' \| 'summary_large_image' \| 'app' \| 'player'` | `'summary_large_image'` | Card type |
|
||
| `twitterSite` | `string` | — | Site Twitter handle (e.g. `@advento_ir`) |
|
||
| `twitterCreator` | `string` | — | Author Twitter handle |
|
||
| `twitterTitle` | `string` | OG title | Override Twitter title |
|
||
| `twitterDescription` | `string` | OG description | Override Twitter description |
|
||
| `twitterImage` | `string` | OG image | Override Twitter image URL |
|
||
| `twitterImageAlt` | `string` | — | Alt text for the Twitter image |
|
||
|
||
#### Article (requires `ogType="article"`)
|
||
|
||
Pass an `article` object with the following shape:
|
||
|
||
```ts
|
||
interface ArticleMeta {
|
||
publishedTime: string; // ISO 8601, e.g. "2025-01-15T10:00:00Z"
|
||
modifiedTime?: string;
|
||
authors?: string[]; // names or profile URLs
|
||
section?: string;
|
||
tags?: string[];
|
||
}
|
||
```
|
||
|
||
#### JSON-LD & Breadcrumbs
|
||
|
||
| Prop | Type | Description |
|
||
| --- | --- | --- |
|
||
| `breadcrumbs` | `BreadcrumbItem[]` | Generates a `BreadcrumbList` schema automatically |
|
||
| `jsonLd` | `Record<string, unknown> \| Record<string, unknown>[]` | Inject one or more custom schema.org objects |
|
||
|
||
```ts
|
||
interface BreadcrumbItem {
|
||
name: string;
|
||
url: string; // absolute URL
|
||
}
|
||
```
|
||
|
||
#### Alternates & Resource Hints
|
||
|
||
| Prop | Type | Description |
|
||
| --- | --- | --- |
|
||
| `alternateLocales` | `AlternateLocale[]` | Emits `<link rel="alternate" hreflang="...">` for each entry |
|
||
| `preconnect` | `string[]` | Emits `<link rel="preconnect">` for each origin |
|
||
| `dnsPrefetch` | `string[]` | Emits `<link rel="dns-prefetch">` for each origin |
|
||
|
||
```ts
|
||
interface AlternateLocale {
|
||
hreflang: string; // e.g. "en", "fa", "x-default"
|
||
href: string; // absolute URL
|
||
}
|
||
```
|
||
|
||
#### Favicon & Manifest
|
||
|
||
| Prop | Type | Default | Description |
|
||
| --- | --- | --- | --- |
|
||
| `faviconSvg` | `string` | `'/favicon.svg'` | Path to SVG favicon |
|
||
| `faviconIco` | `string` | — | Path to `.ico` favicon (legacy browsers) |
|
||
| `appleTouchIcon` | `string` | — | Path to Apple touch icon (180×180 PNG) |
|
||
| `manifestHref` | `string` | — | Path to `manifest.json` / `manifest.webmanifest` |
|
||
|
||
---
|
||
|
||
### Full example — article page
|
||
|
||
```astro
|
||
---
|
||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||
---
|
||
|
||
<BaseLayout
|
||
title="How We Built This Kit"
|
||
titleTemplate="%s | Advento"
|
||
description="A deep-dive into our Astro + Docker starter setup."
|
||
keywords={['Astro', 'Docker', 'Tailwind', 'RTL']}
|
||
author="Advento Team"
|
||
canonical="https://advento.ir/blog/how-we-built-this-kit"
|
||
ogType="article"
|
||
ogImage="https://advento.ir/og/how-we-built-this-kit.png"
|
||
ogImageAlt="Screenshot of the Astro Docker Kit starter"
|
||
ogSiteName="Advento"
|
||
twitterSite="@advento_ir"
|
||
twitterCreator="@advento_ir"
|
||
article={{
|
||
publishedTime: '2025-01-15T10:00:00Z',
|
||
modifiedTime: '2025-06-01T08:00:00Z',
|
||
authors: ['Advento Team'],
|
||
section: 'Engineering',
|
||
tags: ['Astro', 'Docker', 'SEO'],
|
||
}}
|
||
breadcrumbs={[
|
||
{ name: 'Home', url: 'https://advento.ir' },
|
||
{ name: 'Blog', url: 'https://advento.ir/blog' },
|
||
{ name: 'How We Built This Kit', url: 'https://advento.ir/blog/how-we-built-this-kit' },
|
||
]}
|
||
alternateLocales={[
|
||
{ hreflang: 'fa', href: 'https://advento.ir/fa/blog/how-we-built-this-kit' },
|
||
{ hreflang: 'x-default', href: 'https://advento.ir/blog/how-we-built-this-kit' },
|
||
]}
|
||
preconnect={['https://fonts.gstatic.com']}
|
||
/>
|
||
```
|
||
|
||
---
|
||
|
||
## 🧞 Commands
|
||
|
||
| Command | Action |
|
||
| ---------------------- | ------------------------------------ |
|
||
| `npm run dev` | Start dev server at `localhost:4321` |
|
||
| `npm run build` | Build production site to `./dist/` |
|
||
| `npm run preview` | Preview the production build locally |
|
||
| `npm run format` | Format code with Prettier |
|
||
| `npm run lint` | Lint with ESLint |
|
||
| `docker compose up -d` | Run container in background |
|
||
|
||
---
|
||
|
||
## 🤝 Contributing
|
||
|
||
1. Fork the repo
|
||
2. Create a branch: `git checkout -b feature/your-feature`
|
||
3. Commit: `git commit -m 'feat: add your feature'`
|
||
4. Push and open a Pull Request
|
||
|
||
---
|
||
|
||
## 🌌 About Advento
|
||
|
||
At [Advento](https://advento.ir), we are redefining the digital marketing landscape. By harnessing the absolute edge of Artificial Intelligence, we deliver highly scalable, data-driven, and innovative solutions. This repository is part of our commitment to pushing the boundaries of what's possible in digital marketing technology.
|
||
|
||
---
|
||
|
||
## 📄 License
|
||
|
||
MIT — see [LICENSE](LICENSE) for details.
|
||
|
||
---
|
||
|
||
<div align="center">
|
||
|
||
Made with ❤️ by [**Advento**](https://advento.ir)
|
||
|
||
</div>
|