Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • alpha
  • beta
  • develop
  • docs/fix-readme
  • docs/update-vitepress
  • draft/rss-feed
  • feat/dashboard
  • feat/episodes-page-ux
  • feat/generator-user-agent
  • feat/headliner
  • feat/new-languages
  • feat/plugins
  • fix/federation
  • fix/forms-ux
  • i18n
  • main
  • next
  • refactor/transcripts
  • v1.0.0
  • v1.0.0-alpha.1
  • v1.0.0-alpha.10
  • v1.0.0-alpha.11
  • v1.0.0-alpha.12
  • v1.0.0-alpha.13
  • v1.0.0-alpha.14
  • v1.0.0-alpha.15
  • v1.0.0-alpha.16
  • v1.0.0-alpha.17
  • v1.0.0-alpha.18
  • v1.0.0-alpha.19
  • v1.0.0-alpha.2
  • v1.0.0-alpha.20
  • v1.0.0-alpha.21
  • v1.0.0-alpha.22
  • v1.0.0-alpha.23
  • v1.0.0-alpha.24
  • v1.0.0-alpha.25
  • v1.0.0-alpha.26
  • v1.0.0-alpha.27
  • v1.0.0-alpha.28
  • v1.0.0-alpha.29
  • v1.0.0-alpha.3
  • v1.0.0-alpha.30
  • v1.0.0-alpha.31
  • v1.0.0-alpha.32
  • v1.0.0-alpha.33
  • v1.0.0-alpha.34
  • v1.0.0-alpha.35
  • v1.0.0-alpha.36
  • v1.0.0-alpha.37
  • v1.0.0-alpha.38
  • v1.0.0-alpha.39
  • v1.0.0-alpha.4
  • v1.0.0-alpha.40
  • v1.0.0-alpha.41
  • v1.0.0-alpha.42
  • v1.0.0-alpha.43
  • v1.0.0-alpha.44
  • v1.0.0-alpha.45
  • v1.0.0-alpha.46
  • v1.0.0-alpha.47
  • v1.0.0-alpha.48
  • v1.0.0-alpha.49
  • v1.0.0-alpha.5
  • v1.0.0-alpha.50
  • v1.0.0-alpha.51
  • v1.0.0-alpha.52
  • v1.0.0-alpha.53
  • v1.0.0-alpha.54
  • v1.0.0-alpha.55
  • v1.0.0-alpha.56
  • v1.0.0-alpha.57
  • v1.0.0-alpha.58
  • v1.0.0-alpha.59
  • v1.0.0-alpha.6
  • v1.0.0-alpha.60
  • v1.0.0-alpha.61
  • v1.0.0-alpha.62
  • v1.0.0-alpha.63
  • v1.0.0-alpha.64
  • v1.0.0-alpha.65
  • v1.0.0-alpha.66
  • v1.0.0-alpha.67
  • v1.0.0-alpha.68
  • v1.0.0-alpha.69
  • v1.0.0-alpha.7
  • v1.0.0-alpha.70
  • v1.0.0-alpha.71
  • v1.0.0-alpha.72
  • v1.0.0-alpha.73
  • v1.0.0-alpha.74
  • v1.0.0-alpha.75
  • v1.0.0-alpha.76
  • v1.0.0-alpha.77
  • v1.0.0-alpha.78
  • v1.0.0-alpha.79
  • v1.0.0-alpha.8
  • v1.0.0-alpha.80
  • v1.0.0-alpha.9
  • v1.0.0-beta.1
  • v1.0.0-beta.10
  • v1.0.0-beta.11
  • v1.0.0-beta.12
  • v1.0.0-beta.13
  • v1.0.0-beta.14
  • v1.0.0-beta.15
  • v1.0.0-beta.16
  • v1.0.0-beta.17
  • v1.0.0-beta.18
  • v1.0.0-beta.19
  • v1.0.0-beta.2
  • v1.0.0-beta.20
  • v1.0.0-beta.21
  • v1.0.0-beta.22
  • v1.0.0-beta.23
  • v1.0.0-beta.24
  • v1.0.0-beta.3
  • v1.0.0-beta.4
118 results

Target

Select target project
  • adaures/castopod
  • mkljczk/castopod-host
  • spaetz/castopod-host
  • PatrykMis/castopod
  • jonas/castopod
  • ajeremias/castopod
  • misuzu/castopod
  • KrzysztofDomanczyk/castopod
  • Behel/castopod
  • nebulon/castopod
  • ewen/castopod
  • NeoluxConsulting/castopod
  • nateritter/castopod-og
  • prcutler/castopod
14 results
Select Git revision
  • alpha
  • beta
  • develop
  • docs/update-vitepress
  • feat/dashboard
  • feat/op3
  • i18n
  • main
  • v1.0.0
  • v1.0.0-alpha.1
  • v1.0.0-alpha.10
  • v1.0.0-alpha.11
  • v1.0.0-alpha.12
  • v1.0.0-alpha.13
  • v1.0.0-alpha.14
  • v1.0.0-alpha.15
  • v1.0.0-alpha.16
  • v1.0.0-alpha.17
  • v1.0.0-alpha.18
  • v1.0.0-alpha.19
  • v1.0.0-alpha.2
  • v1.0.0-alpha.20
  • v1.0.0-alpha.21
  • v1.0.0-alpha.22
  • v1.0.0-alpha.23
  • v1.0.0-alpha.24
  • v1.0.0-alpha.25
  • v1.0.0-alpha.26
  • v1.0.0-alpha.27
  • v1.0.0-alpha.28
  • v1.0.0-alpha.29
  • v1.0.0-alpha.3
  • v1.0.0-alpha.30
  • v1.0.0-alpha.31
  • v1.0.0-alpha.32
  • v1.0.0-alpha.33
  • v1.0.0-alpha.34
  • v1.0.0-alpha.35
  • v1.0.0-alpha.36
  • v1.0.0-alpha.37
  • v1.0.0-alpha.38
  • v1.0.0-alpha.39
  • v1.0.0-alpha.4
  • v1.0.0-alpha.40
  • v1.0.0-alpha.41
  • v1.0.0-alpha.42
  • v1.0.0-alpha.43
  • v1.0.0-alpha.44
  • v1.0.0-alpha.45
  • v1.0.0-alpha.46
  • v1.0.0-alpha.47
  • v1.0.0-alpha.48
  • v1.0.0-alpha.49
  • v1.0.0-alpha.5
  • v1.0.0-alpha.50
  • v1.0.0-alpha.51
  • v1.0.0-alpha.52
  • v1.0.0-alpha.53
  • v1.0.0-alpha.54
  • v1.0.0-alpha.55
  • v1.0.0-alpha.56
  • v1.0.0-alpha.57
  • v1.0.0-alpha.58
  • v1.0.0-alpha.59
  • v1.0.0-alpha.6
  • v1.0.0-alpha.60
  • v1.0.0-alpha.61
  • v1.0.0-alpha.62
  • v1.0.0-alpha.63
  • v1.0.0-alpha.64
  • v1.0.0-alpha.65
  • v1.0.0-alpha.66
  • v1.0.0-alpha.67
  • v1.0.0-alpha.68
  • v1.0.0-alpha.69
  • v1.0.0-alpha.7
  • v1.0.0-alpha.70
  • v1.0.0-alpha.71
  • v1.0.0-alpha.72
  • v1.0.0-alpha.73
  • v1.0.0-alpha.74
  • v1.0.0-alpha.75
  • v1.0.0-alpha.76
  • v1.0.0-alpha.77
  • v1.0.0-alpha.78
  • v1.0.0-alpha.79
  • v1.0.0-alpha.8
  • v1.0.0-alpha.80
  • v1.0.0-alpha.9
  • v1.0.0-beta.1
  • v1.0.0-beta.10
  • v1.0.0-beta.11
  • v1.0.0-beta.12
  • v1.0.0-beta.13
  • v1.0.0-beta.14
  • v1.0.0-beta.15
  • v1.0.0-beta.16
  • v1.0.0-beta.17
  • v1.0.0-beta.18
  • v1.0.0-beta.19
  • v1.0.0-beta.2
  • v1.0.0-beta.20
  • v1.0.0-beta.21
  • v1.0.0-beta.22
  • v1.0.0-beta.23
  • v1.0.0-beta.24
  • v1.0.0-beta.3
  • v1.0.0-beta.4
108 results
Show changes
Showing
with 10458 additions and 0 deletions
# Castopod Docs
[![Built with Starlight](https://astro.badg.es/v2/built-with-starlight/tiny.svg)](https://starlight.astro.build)
```sh
pnpm create astro@latest -- --template starlight
```
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/starlight/tree/main/examples/basics)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/starlight/tree/main/examples/basics)
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
## 🚀 Project Structure
Inside of your Astro + Starlight project, you'll see the following folders and
files:
```
.
├── public/
├── src/
│ ├── assets/
│ ├── content/
│ │ ├── docs/
│ │ └── config.ts
│ └── env.d.ts
├── astro.config.mjs
├── package.json
└── tsconfig.json
```
Starlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory.
Each file is exposed as a route based on its file name.
Images can be added to `src/assets/` and embedded in Markdown with a relative
link.
Static assets, like favicons, can be placed in the `public/` directory.
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :------------------------ | :----------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:4321` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `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?
Check out [Starlight’s docs](https://starlight.astro.build/), read
[the Astro documentation](https://docs.astro.build), or jump into the
[Astro Discord server](https://astro.build/chat).
import { defineConfig } from "astro/config";
import starlight from "@astrojs/starlight";
import starlightOpenAPI from "starlight-openapi";
import tailwind from "@astrojs/tailwind";
const site = "https://docs.castopod.org/";
const base = process.env.BASE ?? "/docs";
// https://astro.build/config
export default defineConfig({
site,
base,
integrations: [
starlight({
title: "Castopod Docs",
description:
"Check out the Castopod documentation! Install your own free & open-source podcast host, help make it better by contributing, or simply learn more about Castopod!",
components: {
Header: "./src/components/Header.astro",
MobileMenuFooter: "./src/components/MobileMenuFooter.astro",
},
logo: {
src: "./src/assets/castopod-logo-inline.svg",
replacesTitle: true,
},
favicon: "/favicon.ico",
customCss: [
"@fontsource/inter/400.css",
"@fontsource/inter/600.css",
"@fontsource/rubik/700.css",
"./src/styles/tailwind.css",
],
head: [
{
tag: "meta",
attrs: {
property: "og:type",
content: "website",
},
},
{
tag: "meta",
attrs: {
property: "og:image",
content: base + "/open-graph.jpg?v=1",
},
},
{
tag: "meta",
attrs: { property: "og:image:type", content: "image/jpeg" },
},
{ tag: "meta", attrs: { property: "og:image:width", content: "1200" } },
{ tag: "meta", attrs: { property: "og:image:height", content: "630" } },
{
tag: "meta",
attrs: {
property: "og:image:alt",
content:
"Castopod mascot waving hello and holding a browser showcasing the Castopod documentation.",
},
},
{
tag: "meta",
attrs: { property: "og:url", content: "https://docs.castopod.org/" },
},
{ tag: "meta", attrs: { name: "twitter:site", content: "@castopod" } },
{
tag: "meta",
attrs: { name: "twitter:card", content: "summary_large_image" },
},
{
tag: "meta",
attrs: { name: "twitter:creator", content: "@ad_aures" },
},
{
tag: "script",
attrs: {
src: "https://analytics.castopod.org/js/plausible.js",
"data-domain": "docs.castopod.org",
defer: true,
},
},
],
defaultLocale: "en",
locales: {
en: {
label: "English",
},
ca: {
label: "Català",
},
de: {
label: "Deutsch",
},
es: {
label: "Español",
},
fr: {
label: "Français",
},
"nn-no": {
label: "Norsk nynorsk",
lang: "nn-NO",
},
"pt-br": {
label: "Português do Brasil",
lang: "pt-BR",
},
"sr-latn": {
label: "Srpski",
lang: "sr-Latn",
},
"zh-hans": {
label: "中文",
lang: "zh-Hans",
},
},
social: {
discord: "https://castopod.org/chat",
"x.com": "https://twitter.com/castopod",
mastodon: "https://podlibre.social/@Castopod",
gitlab: "https://code.castopod.org/adaures/castopod",
github: "https://github.com/ad-aures/castopod",
},
plugins: [
starlightOpenAPI([
{
base: "en/api",
label: "API reference",
schema: "../modules/Api/Rest/V1/schema.yaml",
collapsed: true,
},
]),
],
sidebar: [
{
label: "Introduction",
link: "/",
translations: {
fr: "Installer",
"pt-br": "Instalar",
"nn-no": "Installer",
},
},
{
label: "Getting started",
translations: {
fr: "Commencer",
"pt-br": "Começando",
"nn-no": "Starter",
},
items: [
// Each item here is one entry in the navigation menu.
{
label: "Install",
link: "/getting-started/install/",
translations: {
fr: "Installer",
"pt-br": "Instalar",
"nn-no": "Installer",
},
},
{
label: "Docker",
link: "/getting-started/docker/",
},
{
label: "Security",
link: "/getting-started/security/",
translations: {
fr: "Sécurité",
"pt-br": "Segurança",
"nn-no": "Sikkerhet",
},
},
{
label: "Update",
link: "/getting-started/update/",
translations: {
fr: "Mise à jour",
"pt-br": "Atualizar",
"nn-no": "Oppdaterer",
},
},
{
label: "Auth",
link: "/getting-started/auth/",
translations: {
fr: "Authentification",
"pt-br": "Autenticação",
"nn-no": "Autentisering",
},
},
{
label: "Create your first podcast",
link: "/getting-started/create-podcast/",
translations: {},
},
{
label: "Create your first episode",
link: "/getting-started/create-episode/",
translations: {},
},
],
},
{
label: "Plugins",
badge: {
text: "Experimental",
},
items: [
{
label: "Introduction",
link: "/plugins/",
},
{
label: "Creating a plugin",
link: "/plugins/create",
},
{
label: "Reference",
items: [
{
label: "manifest.json",
link: "/plugins/manifest",
},
{
label: "hooks",
link: "/plugins/hooks",
},
],
},
],
},
// TODO: openapi plugin does not handle i18n, manual sidebar workaround
// Add the generated sidebar group to the sidebar.
// ...openAPISidebarGroups,
{
label: "API reference",
translations: {},
items: [
{
label: "Overview",
link: "/api",
},
{
label: "Operations",
items: [
{
label: "Get all podcasts",
link: "/api/operations/get-all-podcasts",
},
{
label: "Get podcast by ID",
link: "/api/operations/get-podcast-by-id",
},
{
label: "Get all episodes",
link: "/api/operations/get-all-episodes",
},
{
label: "Add a new episode",
link: "/api/operations/add-episode",
},
{
label: "Get episode by ID",
link: "/api/operations/get-episode-by-id",
},
{
label: "Publish an episode",
link: "/api/operations/publish-episode",
},
],
},
],
},
{
label: "User guide",
translations: {},
items: [
{
label: "Introduction",
link: "/user-guide/",
},
{
label: "Manage your instance",
translations: {},
collapsed: true,
items: [
{
label: "Introduction",
link: "/user-guide/instance/",
},
{
label: "Add a podcast",
link: "/user-guide/instance/podcast",
translations: {},
},
{
label: "Persons",
link: "/user-guide/instance/persons",
translations: {},
},
{
label: "Fediverse",
link: "/user-guide/instance/fediverse",
translations: {},
},
{
label: "Users",
link: "/user-guide/instance/users",
translations: {},
},
{
label: "Pages",
link: "/user-guide/instance/pages",
translations: {},
},
{
label: "Settings",
link: "/user-guide/instance/settings",
translations: {},
},
],
},
{
label: "Manage your podcasts",
translations: {},
collapsed: true,
items: [
{
label: "Introduction",
link: "/user-guide/podcast/",
},
{
label: "Podcast dashboard",
link: "/user-guide/podcast/dashboard",
translations: {},
},
{
label: "Episodes",
link: "/user-guide/podcast/episodes",
translations: {},
},
{
label: "Analytics",
link: "/user-guide/podcast/analytics",
translations: {},
},
{
label: "Broadcasting",
link: "/user-guide/podcast/broadcast",
translations: {},
},
{
label: "Contributors",
link: "/user-guide/podcast/contributors",
translations: {},
},
],
},
{
label: "Website overview",
link: "/user-guide/website/",
translations: {},
},
],
},
],
editLink: {
baseUrl: "https://code.castopod.org/adaures/castopod/-/edit/main/docs/",
},
}),
tailwind({
applyBaseStyles: false,
}),
],
});
{
"name": "civil-chasm",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro check && astro build",
"preview": "astro preview",
"astro": "astro",
"prepare": "astro telemetry disable"
},
"dependencies": {
"@astrojs/check": "^0.9.4",
"@astrojs/starlight": "^0.32.2",
"@astrojs/starlight-tailwind": "^3.0.0",
"@astrojs/tailwind": "^5.1.5",
"@fontsource/inter": "^5.2.5",
"@fontsource/rubik": "^5.2.5",
"astro": "^5.5.2",
"autoprefixer": "^10.4.21",
"cssnano": "^7.0.6",
"postcss-preset-env": "^10.1.5",
"sharp": "^0.33.5",
"starlight-openapi": "^0.14.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.2",
"zod": "3.24.2"
}
}
Source diff could not be displayed: it is too large. Options to address this: view the blob.
module.exports = {
plugins: [
require("autoprefixer"),
require("cssnano"),
require("postcss-preset-env")({
stage: 3,
features: { "nesting-rules": false },
}),
],
};
docs/public/favicon.ico

20.7 KiB

docs/public/open-graph.jpg

147 KiB

#!/bin/bash
# This script deletes language files not declared in the .i18n-filter file
set -e
# Exit if the directory isn't found
if [ ! -d $1 ]
then
echo "$1 directory does not exist."
exit
fi
cd $1
# Exit if the .i18n-filter isn't found
if [[ -f .i18n-filter ]]
then
# delete all languages not present in .i18n-filter
for i in *; do
if ! grep -qxFe "$i" .i18n-filter; then
echo "Deleting: $i"
rm -rf "$i"
fi
done
else
echo "$1/.i18n-filter file not found!"
exit
fi
en
ca
de
es
fr
nn-no
pt-br
sr-latn
zh-hans
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 324 65">
<path fill="#009486" d="M26.6 40.2c-1.4 1.3-3 2.3-4.9 3.1-1.9.7-4 1.1-6.2 1.1-3 0-5.6-.6-8-1.9-2.3-1.3-4.2-3-5.5-5.2-1.3-2.2-2-4.7-2-7.5s.7-5.3 2-7.5 3.2-3.9 5.5-5.2c2.3-1.3 5-1.9 8-1.9 2.2 0 4.3.4 6.2 1.1 1.9.7 3.5 1.7 4.9 3.1l-5.7 5.4c-1.3-1.7-3.1-2.5-5.4-2.5-2.1 0-3.8.7-5.1 2.2-1.3 1.4-2 3.2-2 5.4s.7 4 2 5.4c1.3 1.4 3 2.2 5.1 2.2 2.2 0 4-.8 5.4-2.5l5.7 5.2ZM31.1 36.1c0-1.9.5-3.5 1.6-5s2.6-2.6 4.4-3.5c1.9-.9 4.1-1.3 6.5-1.3a23.36 23.36 0 0 1 5 .5c-.6-3.1-2.8-4.6-6.7-4.6-2.3 0-4.5.9-6.8 2.6L32.3 18c1.9-.9 3.9-1.6 5.8-2.1 1.9-.4 3.7-.7 5.4-.7 2.7 0 5.1.5 7.1 1.5s3.5 2.5 4.6 4.3c1.1 1.9 1.7 4 1.7 6.6v16.2h-6.8l-.5-3c-1 1.1-2.3 2-3.8 2.6-1.5.6-3.2 1-5 1-2.8 0-5.2-.8-7-2.3a7.42 7.42 0 0 1-2.7-6Zm8-1.8c0 .9.4 1.7 1.1 2.3.7.6 1.7.9 2.8.9 1.6 0 3-.5 4.1-1.5 1.1-1 1.6-2.2 1.6-3.6v-.6c-.7-.2-1.4-.4-2.2-.5-.8-.1-1.6-.2-2.3-.2-1.6 0-2.8.3-3.7.8-.9.5-1.4 1.3-1.4 2.4ZM61.9 40.3l3.8-6.1c1.6 1.1 3.1 1.9 4.4 2.5 1.4.6 2.6.9 3.6.9.8 0 1.5-.2 2-.6.5-.4.8-.9.8-1.4 0-.8-.5-1.5-1.4-2-.9-.5-2-1-3.3-1.5-1.3-.5-2.6-1.2-3.9-1.8-1.3-.7-2.4-1.6-3.3-2.7a6.4 6.4 0 0 1-1.3-4.2c0-2.4.9-4.3 2.8-5.9 1.9-1.5 4.5-2.3 8-2.3 1.7 0 3.5.2 5.3.6 1.9.4 3.6 1.1 5.1 2l-3.6 6.1c-.8-.5-1.9-1-3.2-1.4-1.3-.4-2.4-.6-3.4-.6-.5 0-1.1.1-1.7.3-.6.2-.9.6-.9 1.2 0 .7.4 1.3 1.3 1.7.9.4 1.9.9 3.1 1.4 1.3.5 2.6 1.1 4 1.8s2.5 1.6 3.5 2.7c.9 1.1 1.4 2.6 1.4 4.4 0 1.8-.5 3.4-1.5 4.7-1 1.3-2.4 2.3-4 3-1.7.7-3.5 1.1-5.6 1.1-1.9 0-3.9-.3-6-1-2.1-.5-4.1-1.5-6-2.9ZM88.6 15.8h4.6v-7h8.1v7h6.8v7h-6.8v10.3c0 1.3.4 2.4 1.3 3.1.9.8 1.9 1.1 3.2 1.1 1 0 2-.2 3-.6v6.6c-1.8.7-3.5 1-5.2 1-3.3 0-5.9-.9-7.7-2.7-1.8-1.8-2.7-4.3-2.7-7.7V22.5h-4.6v-6.7ZM113.1 29.8c0-2.8.6-5.3 2-7.5 1.3-2.2 3.1-3.9 5.3-5.2 2.3-1.3 4.8-1.9 7.7-1.9 2.9 0 5.4.6 7.7 1.9 2.2 1.3 4 3 5.3 5.2 1.3 2.2 2 4.7 2 7.5s-.7 5.3-2 7.5-3.1 3.9-5.3 5.2c-2.2 1.3-4.8 1.9-7.7 1.9-2.9 0-5.5-.6-7.7-1.9-2.3-1.3-4-3-5.3-5.2-1.4-2.2-2-4.7-2-7.5Zm7.8 0c0 2.2.7 4 2 5.4 1.3 1.4 3 2.2 5.1 2.2 2.1 0 3.8-.7 5.1-2.2 1.3-1.4 2-3.2 2-5.4s-.7-4-2-5.4a6.87 6.87 0 0 0-5.1-2.2c-2.1 0-3.8.7-5.1 2.2-1.3 1.4-2 3.2-2 5.4ZM148.4 15.8h7.6l.2 3c1.2-1.1 2.6-2 4.1-2.7 1.6-.6 3.3-.9 5.1-.9 2.6 0 5 .6 7 1.9 2.1 1.3 3.7 3 4.9 5.2 1.2 2.2 1.8 4.7 1.8 7.5s-.6 5.3-1.8 7.5c-1.2 2.2-2.8 3.9-4.9 5.2-2.1 1.3-4.4 1.9-7 1.9-1.8 0-3.4-.3-4.9-.9-1.5-.6-2.9-1.4-4-2.5v23.8h-8.1v-49Zm15.2 6.4c-2.1 0-3.8.7-5.1 2.2-1.3 1.4-2 3.2-2 5.4s.7 4 2 5.4c1.3 1.4 3 2.2 5.1 2.2 2.1 0 3.8-.7 5.1-2.2 1.3-1.4 2-3.2 2-5.4s-.7-4-2-5.4a6.67 6.67 0 0 0-5.1-2.2ZM182.4 29.8c0-2.8.6-5.3 2-7.5 1.3-2.2 3.1-3.9 5.3-5.2 2.3-1.3 4.8-1.9 7.7-1.9 2.9 0 5.4.6 7.7 1.9 2.2 1.3 4 3 5.3 5.2 1.3 2.2 2 4.7 2 7.5s-.7 5.3-2 7.5-3.1 3.9-5.3 5.2c-2.2 1.3-4.8 1.9-7.7 1.9-2.9 0-5.5-.6-7.7-1.9-2.3-1.3-4-3-5.3-5.2-1.3-2.2-2-4.7-2-7.5Zm7.9 0c0 2.2.7 4 2 5.4 1.3 1.4 3 2.2 5.1 2.2 2.1 0 3.8-.7 5.1-2.2 1.3-1.4 2-3.2 2-5.4s-.7-4-2-5.4a6.87 6.87 0 0 0-5.1-2.2c-2.1 0-3.8.7-5.1 2.2-1.3 1.4-2 3.2-2 5.4ZM215.8 29.8c0-2.8.6-5.3 1.8-7.5 1.2-2.2 2.8-3.9 4.9-5.2 2.1-1.3 4.4-1.9 7-1.9 1.8 0 3.4.3 4.9.9 1.5.6 2.9 1.4 4 2.5V0h8.1v43.9h-7.6l-.2-3c-1.2 1.1-2.6 2-4.1 2.7-1.6.6-3.3.9-5.1.9-2.6 0-5-.6-7-1.9-2.1-1.3-3.7-3-4.9-5.2-1.2-2.3-1.8-4.8-1.8-7.6Zm8.3 0c0 2.2.7 4 2 5.4 1.3 1.4 3 2.2 5.1 2.2 2.1 0 3.8-.7 5.1-2.2 1.3-1.4 2-3.2 2-5.4s-.7-4-2-5.4a6.87 6.87 0 0 0-5.1-2.2c-2.1 0-3.8.7-5.1 2.2-1.3 1.4-2 3.2-2 5.4ZM318.7 44h-10.82s-1.13-2.41-1.6-3.26c-.45-.86-1.55-.82-1.55-.82h-29.38s-1.07-.14-1.6.82c-.57.95-1.63 3.26-1.63 3.26h-10.65a4.47 4.47 0 0 1-4.47-4.44V4.47A4.47 4.47 0 0 1 261.44 0h57.23a4.47 4.47 0 0 1 4.47 4.44v35.09a4.45 4.45 0 0 1-4.43 4.47Z"></path>
<path fill="#E7F9E4" d="M274.95 9.51h30.2a9.34 9.34 0 0 1 9.4 9.44c0 5.18-4.22 9.4-9.4 9.4h-30.2a9.42 9.42 0 0 1 0-18.84Z"></path>
<path fill="#009486" d="M302.77 15.36a4.61 4.61 0 0 0-3.64 7.46s1.58-1.18 3.8-1.18c1.67 0 3.6 1.01 3.6 1.01a4.61 4.61 0 0 0-3.76-7.29ZM277.23 15.36a4.61 4.61 0 0 0-3.77 7.3s1.94-1.02 3.6-1.02c2.23 0 3.8 1.18 3.8 1.18a4.61 4.61 0 0 0-3.64-7.45Z"></path>
</svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 261 50">
<style>
@media (prefers-color-scheme: dark) {
svg { background-color: white; }
}
</style>
<g clip-path="url(#a)"><path fill="#2A2D7C" d="M96.9 15.975v22.95h-6.1l-.675-1.625a10.875 10.875 0 0 1-6.925 2.5 11.699 11.699 0 0 1-12.05-12.3A11.65 11.65 0 0 1 83.2 15.35c2.554-.01 5.03.874 7 2.5l.825-1.775 5.875-.1Zm-7.5 11.5a5.15 5.15 0 1 0-10.275 0 5.15 5.15 0 1 0 10.275 0Zm36.725-19.75V38.95h-5.85l-.75-1.7a10.549 10.549 0 0 1-6.925 2.5 11.702 11.702 0 0 1-12.1-12.25 11.699 11.699 0 0 1 12.1-12.25c2.013-.018 3.99.537 5.7 1.6V7.725h7.825ZM118.8 27.5a5.152 5.152 0 0 0-5.137-5.509 5.151 5.151 0 0 0-5.138 5.509 5.152 5.152 0 0 0 5.138 5.509A5.15 5.15 0 0 0 118.8 27.5Zm45.925-11.525v22.95h-6.1L158 37.3a10.823 10.823 0 0 1-6.925 2.5A11.677 11.677 0 0 1 139 27.5a11.61 11.61 0 0 1 .763-4.706 11.612 11.612 0 0 1 6.564-6.633 11.626 11.626 0 0 1 4.698-.811 10.87 10.87 0 0 1 7 2.5l.825-1.775 5.875-.1Zm-7.5 11.5a5.152 5.152 0 0 0-5.137-5.509 5.151 5.151 0 0 0-5.138 5.509 5.152 5.152 0 0 0 5.138 5.509 5.15 5.15 0 0 0 5.137-5.509Zm12.2 1.625V16h7.9v12.75c0 2.5 1.3 3.85 3.425 3.85s3.375-1.45 3.375-3.85V16h7.9v13.1c0 6.425-4.5 10.6-11.275 10.6s-11.325-4.175-11.325-10.6Zm42.225-13.2v7.225h-3.075c-2.8 0-3.975 1.225-3.975 4.15V38.95h-7.9V16h5.3l1.225 2.5a7.675 7.675 0 0 1 6.325-2.65l2.1.05ZM238 27.275a14.703 14.703 0 0 1-.15 2.075H220.7a4.476 4.476 0 0 0 4.8 4 4.628 4.628 0 0 0 4.15-2.15h7.85a12.497 12.497 0 0 1-13.868 8.866A12.5 12.5 0 0 1 213 27.5a12.5 12.5 0 1 1 25-.2v-.025ZM220.85 25h9.275a4.6 4.6 0 0 0-4.625-3.55 4.425 4.425 0 0 0-4.65 3.55Zm29.5 14.7c-6.25 0-10-3.3-10-8.275h7.5a2.347 2.347 0 0 0 1.638 2.415 2.35 2.35 0 0 0 1.037.085c1.15 0 2.25-.575 2.25-1.775s-1.725-1.7-3.925-2.05c-3.6-.625-8.35-1.7-8.35-7.275 0-4.6 3.925-7.5 9.8-7.5 5.875 0 9.65 3.125 9.725 7.775h-7.5c0-1.475-.975-2.15-2.5-2.15s-2.125.625-2.125 1.675 1.75 1.625 3.925 2c3.625.65 8.45 1.4 8.45 7.225 0 4.8-4.05 7.925-10.15 7.925l.225-.075ZM.5 0v50h50V0H.5Zm33.35 31.65a9.6 9.6 0 0 1-6.275 9 9.75 9.75 0 0 1-3.325.6 9.6 9.6 0 0 1-3.325-18.6 2.5 2.5 0 0 1 3.3 1.525A2.5 2.5 0 0 1 22.7 27.5a4.454 4.454 0 0 0 3.1 8.35 4.4 4.4 0 0 0 2.9-4.175v-13.7a4.1 4.1 0 0 0-8.2 0 2.5 2.5 0 0 1-5 0 9.225 9.225 0 0 1 18.45 0l-.1 13.675Z"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h260v50H0z" transform="translate(.5)"/></clipPath></defs></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 134 50">
<style>
@media (prefers-color-scheme: dark) {
svg { background-color: white; }
}
</style>
<g clip-path="url(#a)"><path fill="#98BF00" d="m132.92 21.99.74-4.06h-3.84l1.12-5.98-4.6 1.8-.74 4.18h-2.8l-.74 4.06h2.75l-.94 5.15c-.04.28-.12.7-.19 1.23s-.12 1.01-.12 1.41c.02 1.86.46 3.4 1.34 4.6.88 1.23 2.3 1.96 4.3 2.19l1.92-3.96a3.42 3.42 0 0 1-2.35-1.22 4.13 4.13 0 0 1-.82-2.65 16.1 16.1 0 0 1 .2-1.89l.9-4.86h3.87Zm-40.45-.46a5.76 5.76 0 0 1 1.86-.39c.57 0 1.05.16 1.43.5.37.3.55.76.55 1.4 0 .18-.03.45-.09.82l-.15.93L95 29.8l-.22 1.2c-.08.44-.1.81-.1 1.12 0 1.2.32 2.22.99 3.02.64.8 1.79 1.28 3.44 1.42l1.89-3.83c-.65-.1-1.1-.34-1.39-.71a2.3 2.3 0 0 1-.44-1.5c0-.15.01-.33.04-.52l.06-.48 1.08-5.12a14.13 14.13 0 0 0 .32-2.53c0-1.47-.43-2.66-1.3-3.54a4.96 4.96 0 0 0-3.66-1.32c-.9 0-1.76.15-2.61.45-.84.28-1.85.75-3.02 1.46a5.16 5.16 0 0 0-.84-2.01l-3.98 1.7c.33.51.6 1.06.77 1.64.22.82.28 1.67.17 2.5-.03.34-.08.61-.12.8l-2.37 12.6H88l2.5-13.6c.6-.44 1.27-.8 1.97-1.03Z"/><path fill="#98BF00" fill-rule="evenodd" d="M104.39 23.83a13.59 13.59 0 0 0-.17 7.93 7.33 7.33 0 0 0 1.46 2.62c.61.7 1.38 1.26 2.25 1.62.93.38 1.92.58 2.93.57 1.3 0 2.57-.24 3.85-.72a9.01 9.01 0 0 0 3.4-2.21l-1.61-3.72a7.77 7.77 0 0 1-2.47 1.89c-.85.41-1.77.63-2.71.64a3.14 3.14 0 0 1-2.45-.99c-.6-.69-.9-1.57-.88-2.48v-.28c0-.12.01-.24.04-.36 1.92-.26 3.83-.6 5.71-1.04 1.03-.25 2.03-.54 3.01-.84.96-.3 1.83-.6 2.56-.92v-1.7a6.92 6.92 0 0 0-1.86-5 5.62 5.62 0 0 0-2.07-1.35 6.73 6.73 0 0 0-2.53-.47c-1.32 0-2.56.3-3.67.88a8.47 8.47 0 0 0-2.89 2.4 11.46 11.46 0 0 0-1.9 3.53Zm6.44-3a3.2 3.2 0 0 1 1.56-.37c.79 0 1.44.25 1.96.77.53.5.8 1.26.8 2.3-.44.12-.95.29-1.54.45-.61.15-1.22.3-1.84.43l-1.86.39-1.58.27c.07-.63.2-1.22.42-1.77a4.68 4.68 0 0 1 2.08-2.47Z" clip-rule="evenodd"/><path fill="#000" fill-rule="evenodd" d="M120.29 41.8a2.69 2.69 0 0 0-.66-1.79 2.1 2.1 0 0 0-.72-.47 2.96 2.96 0 0 0-3.1.8 3.4 3.4 0 0 0-.94 2.34c0 .37.06.7.18 1.01.1.3.27.55.48.76.2.22.45.39.73.5.28.1.6.17.93.17a2.94 2.94 0 0 0 2.18-.95 3.5 3.5 0 0 0 .92-2.37Zm-4.14-.01c.1-.27.21-.51.36-.72.16-.2.36-.37.58-.5.23-.14.48-.2.75-.2.42 0 .74.14.96.4.22.26.34.63.34 1.09a2.81 2.81 0 0 1-.48 1.55c-.16.21-.36.39-.59.52-.22.12-.47.18-.74.18-.43 0-.75-.14-.97-.39-.24-.3-.36-.7-.34-1.09 0-.28.05-.56.14-.84Z" clip-rule="evenodd"/><path fill="#000" d="M129.33 39.45h-1.06l-.56 3.29a.73.73 0 0 0-.03.22v.25h-.05l-1.9-3.76h-1l-1 5.58h1.08l.6-3.36v-.45h.05l1.95 3.85.95-.09.97-5.53Zm-17.9 0h-1.1l-.99 5.58h1.1l.99-5.58Z"/><path fill="#000" fill-rule="evenodd" d="M97.9 39.45h-1.26l-.78 1.36c-.28.48-.55.99-.82 1.5a30.55 30.55 0 0 0-1.26 2.72h1.15c.04-.1.08-.24.14-.37.06-.14.12-.29.2-.42l.18-.4.16-.36h1.93l.03.42.05.43.04.4c.02.14.02.24.02.34l1.1-.09c0-.2-.02-.44-.04-.72-.02-.29-.06-.58-.1-.9l-.16-1c-.04-.34-.1-.68-.18-1.02l-.19-1-.2-.89Zm-.7 1.65.1.54.07.52.06.38h-1.39a13.97 13.97 0 0 0 .5-.97l.28-.5.23-.42h.06l.1.45Z" clip-rule="evenodd"/><path fill="#000" d="m106.44 40.46.16-1h-3.8l-.17 1H104l-.8 4.57h1.1l.8-4.57h1.35Z"/><path fill="#000" fill-rule="evenodd" d="M88.53 39.38a8.2 8.2 0 0 0-1.83.21l-.94 5.3a7.6 7.6 0 0 0 1.95.23c.86.02 1.7-.3 2.34-.88a3.18 3.18 0 0 0 .96-2.4c0-.4-.05-.74-.17-1.05a2.2 2.2 0 0 0-1.31-1.25c-.32-.1-.66-.16-1-.16Zm-.24 1c.22 0 .43.04.63.08.19.05.35.14.49.25.15.12.27.27.34.47.07.18.12.4.12.68 0 .36-.05.67-.15.96a1.72 1.72 0 0 1-1.04 1.14c-.27.1-.55.16-.83.15-.14 0-.27 0-.44-.02a9.12 9.12 0 0 1-.41-.04l.64-3.6.34-.05.31-.01Z" clip-rule="evenodd"/><path fill="#000" d="M55.3 18.63a5.8 5.8 0 0 1 .94 4.13c-.03.34-.08.61-.12.8l-2.37 12.6h4.29l2.5-13.6c.6-.44 1.27-.8 1.97-1.03a5.76 5.76 0 0 1 1.86-.39c.57 0 1.04.16 1.43.5.37.3.55.76.55 1.4 0 .18-.03.45-.1.82l-.14.93-1.07 5.02-.22 1.2c-.08.44-.1.81-.1 1.12 0 1.2.32 2.22.99 3.02.64.8 1.78 1.28 3.44 1.42l1.89-3.83c-.64-.1-1.1-.34-1.39-.71a2.3 2.3 0 0 1-.44-1.5c0-.15.01-.33.04-.52.01-.2.04-.36.06-.48l1.09-5.12c.09-.43.16-.86.22-1.3.06-.4.09-.82.09-1.23 0-1.47-.43-2.66-1.3-3.54a4.96 4.96 0 0 0-3.66-1.32c-.9 0-1.76.15-2.62.45-.83.28-1.84.75-3.01 1.46a5.16 5.16 0 0 0-.84-2.01l-3.99 1.7Zm27.09-9.24h-4.21l-3.22 17.4a16.74 16.74 0 0 0-.43 3.57c0 1.73.33 3.14 1 4.24.67 1.1 1.8 1.76 3.4 1.97l1.93-3.96c-.3-.14-.57-.3-.84-.5a2.14 2.14 0 0 1-.62-.63 2.41 2.41 0 0 1-.39-.9 6.6 6.6 0 0 1-.07-2.17l.13-.95L82.4 9.4Zm-9.05 30.06h-1.08l-.72 4.08a1.7 1.7 0 0 1-1.28.58.98.98 0 0 1-.62-.18c-.16-.14-.24-.34-.24-.66l.03-.26.03-.3.6-3.26h-1.1l-.58 3.25-.05.4-.01.34c0 .3.04.55.13.77a1.35 1.35 0 0 0 .9.82 2.36 2.36 0 0 0 2.12-.42c0 .08 0 .17.02.26v.22l1.1-.08c-.02-.07-.02-.14-.02-.23-.02-.08-.02-.17-.02-.27l.03-.57c.02-.2.03-.4.08-.58l.68-3.9Zm8.99 0h-1.06l-.56 3.29a.72.72 0 0 0-.03.22v.25h-.05l-1.9-3.76h-1l-1 5.58h1.08l.6-3.36v-.45h.05l1.95 3.85.95-.09.97-5.53Z"/><path fill="#000" fill-rule="evenodd" d="M63.93 40.02a2 2 0 0 0-.73-.48 2.97 2.97 0 0 0-3.11.79 3.38 3.38 0 0 0-.74 3.36c.1.3.26.55.47.76.2.22.45.39.73.5a2.94 2.94 0 0 0 3.11-.79 3 3 0 0 0 .67-1.03c.16-.4.25-.85.25-1.33 0-.37-.06-.71-.18-1.01a2.7 2.7 0 0 0-.47-.78Zm-3.13 1.05c.17-.2.36-.37.58-.5.23-.14.49-.2.75-.2.43 0 .74.14.97.4.22.26.34.63.34 1.09 0 .28-.05.57-.14.85a2 2 0 0 1-.93 1.22 1.6 1.6 0 0 1-.75.18c-.43 0-.74-.14-.97-.39-.24-.3-.36-.7-.34-1.09 0-.56.17-1.1.5-1.56Z" clip-rule="evenodd"/><path fill="#000" d="M56.03 39.45h-3.07l-1 5.58h1.1l.38-2.13h2l.19-1.01h-2.01l.25-1.43h1.98l.18-1.01Z"/><path fill="#98BF00" d="M37.82 13.36a11.5 11.5 0 0 0-2.44-8.78 11.5 11.5 0 0 0-7.92-4.5 11.5 11.5 0 0 0-8.78 2.45 11.35 11.35 0 0 0-4.38 7.19c-.04.25-.09.49-.12.74l-.06.73a11.7 11.7 0 0 0 2.5 8.05 11.28 11.28 0 0 0 7.2 4.38l.73.1.4.05c.32-1.3.84-2.54 1.54-3.67-.46.01-.94 0-1.42-.05l-.06-.01a7.89 7.89 0 0 1-5.46-3.1 7.89 7.89 0 0 1-1.66-6.02v-.06a7.88 7.88 0 0 1 3.08-5.4A7.9 7.9 0 0 1 27 3.8a7.8 7.8 0 0 1 5.44 3.08 7.96 7.96 0 0 1 1.68 6.05c-.07.5-.16.98-.3 1.44a12.3 12.3 0 0 1 3.93-.6l.06-.4Z"/><path fill="#98BF00" d="M39.38 15.32c-.25-.03-.49-.06-.74-.07-1.37-.09-2.68.04-3.93.39-1.5.43-2.9 1.15-4.12 2.12a11.43 11.43 0 0 0-4.37 7.19c1.3.22 2.49.6 3.58 1.15a7.9 7.9 0 0 1 3.08-5.4 7.91 7.91 0 0 1 6.05-1.7h.04a7.9 7.9 0 0 1 5.4 3.1 7.8 7.8 0 0 1 1.68 6.02 7.97 7.97 0 0 1-3.08 5.46 7.86 7.86 0 0 1-6 1.67c.26 1.2.33 2.47.24 3.78a11.5 11.5 0 0 0 8.03-2.52 11.5 11.5 0 0 0 4.5-7.93c.4-3.25-.42-6.19-2.44-8.77a11.41 11.41 0 0 0-7.19-4.38l-.73-.12Z"/><path fill="#000" d="M38.37 23.43a3.61 3.61 0 0 0-2.75.78 3.54 3.54 0 0 0-1.4 2.47 3.54 3.54 0 0 0 .76 2.75 3.54 3.54 0 0 0 2.48 1.4 3.52 3.52 0 0 0 2.74-.76 3.6 3.6 0 0 0 1.41-2.49 3.59 3.59 0 0 0-.77-2.74 3.62 3.62 0 0 0-2.47-1.4Z"/><path fill="#98BF00" d="M3.82 21.91a7.9 7.9 0 0 1 3.1-5.45 7.77 7.77 0 0 1 5.97-1.67 13.2 13.2 0 0 1-.24-3.78 11.4 11.4 0 0 0-8.03 2.51 11.46 11.46 0 0 0-4.49 7.93c-.4 3.26.4 6.17 2.44 8.78a11.33 11.33 0 0 0 7.19 4.37c.23.05.47.08.73.12.25.03.49.06.74.07 1.37.1 2.68-.04 3.92-.38a12.43 12.43 0 0 0 7.17-5.61c.65-1.15 1.1-2.4 1.33-3.7a13.3 13.3 0 0 1-3.58-1.15 7.9 7.9 0 0 1-3.08 5.4 7.91 7.91 0 0 1-6.05 1.68l-.04-.01a7.87 7.87 0 0 1-5.4-3.08 7.83 7.83 0 0 1-1.68-6.03Z"/><path fill="#000" d="M9.66 19.98a3.58 3.58 0 0 0-1.41 2.48 3.57 3.57 0 0 0 .77 2.72 3.57 3.57 0 0 0 2.47 1.43 3.73 3.73 0 0 0 2.3-6.95c-.43-.24-.9-.4-1.4-.44a3.5 3.5 0 0 0-2.73.76Zm19.3-10.35a3.57 3.57 0 0 0-2.49-1.4 3.5 3.5 0 0 0-2.73.76 3.52 3.52 0 0 0-1.42 2.48 3.53 3.53 0 0 0 .78 2.74 3.6 3.6 0 0 0 2.47 1.41 3.72 3.72 0 0 0 3.69-1.86c.24-.43.4-.9.45-1.38a3.64 3.64 0 0 0-.75-2.75Z"/><path fill="#98BF00" d="m25.31 26.32-.4-.05c-.31 1.3-.83 2.54-1.53 3.68.46-.03.94-.02 1.43.04a7.8 7.8 0 0 1 5.5 3.11 7.8 7.8 0 0 1 1.67 6.03v.05a7.88 7.88 0 0 1-3.08 5.4 7.9 7.9 0 0 1-6.04 1.67 7.9 7.9 0 0 1-5.45-3.08 7.84 7.84 0 0 1-1.68-6.04c.06-.5.17-.98.31-1.44-1.27.4-2.6.6-3.94.6l-.06.4c-.4 3.25.4 6.17 2.44 8.77a11.5 11.5 0 0 0 7.93 4.5c3.26.4 6.17-.42 8.78-2.45a11.42 11.42 0 0 0 4.37-7.2l.12-.72c.01-.26.04-.5.06-.73a11.8 11.8 0 0 0-.39-3.93 12 12 0 0 0-2.1-4.12 11.88 11.88 0 0 0-3.5-3.07 11.53 11.53 0 0 0-3.71-1.3c-.24-.05-.48-.1-.73-.12Z"/><path fill="#000" d="M26.79 35.84a3.61 3.61 0 0 0-2.49-1.42 3.56 3.56 0 0 0-2.74.78 3.61 3.61 0 0 0-1.41 2.47 3.56 3.56 0 0 0 .77 2.75 3.48 3.48 0 0 0 2.47 1.4 3.54 3.54 0 0 0 2.76-.76 3.66 3.66 0 0 0 1.4-2.49 3.66 3.66 0 0 0-.76-2.73Z"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h133.63v50H0z"/></clipPath></defs></svg>
\ No newline at end of file
---
import Select from '@astrojs/starlight/components/Select.astro';
import type { Props } from '@astrojs/starlight/props';
---
<docs-version-select>
<Select
icon="starlight"
label="version"
value="main"
options={[
{ label: 'latest', selected: import.meta.env.BASE_URL === '/main', value: 'main' },
{ label: 'develop', selected: import.meta.env.BASE_URL === '/develop', value: 'develop' },
{ label: 'next', selected: import.meta.env.BASE_URL === '/next', value: 'next' },
]}
width="7em"
/>
</docs-version-select>
<script>
class DocsVersionSelect extends HTMLElement {
constructor() {
super();
const select = this.querySelector('select');
if (select) {
select.addEventListener('change', (e) => {
if (e.currentTarget instanceof HTMLSelectElement) {
window.location.pathname = e.currentTarget.value;
}
});
}
}
}
customElements.define('docs-version-select', DocsVersionSelect);
</script>
\ No newline at end of file
---
import config from 'virtual:starlight/user-config';
import type { Props } from '@astrojs/starlight/props';
import LanguageSelect from '@astrojs/starlight/components/LanguageSelect.astro';
import Search from '@astrojs/starlight/components/Search.astro';
import SiteTitle from '@astrojs/starlight/components/SiteTitle.astro';
import SocialIcons from '@astrojs/starlight/components/SocialIcons.astro';
import ThemeSelect from '@astrojs/starlight/components/ThemeSelect.astro';
import VersionSelect from './DocsVersionSelect.astro';
/**
* Render the `Search` component if Pagefind is enabled or the default search component has been overridden.
*/
const shouldRenderSearch =
config.pagefind || config.components.Search !== '@astrojs/starlight/components/Search.astro';
---
<div class="header sl-flex">
<div class="title-wrapper sl-flex">
<SiteTitle {...Astro.props} />
</div>
<div class="sl-flex">
{shouldRenderSearch && <Search {...Astro.props} />}
</div>
<div class="sl-hidden md:sl-flex right-group">
<div class="sl-flex social-icons">
<SocialIcons {...Astro.props} />
</div>
<ThemeSelect {...Astro.props} />
<VersionSelect {...Astro.props} />
<LanguageSelect {...Astro.props} />
</div>
</div>
<style>
.header {
gap: var(--sl-nav-gap);
justify-content: space-between;
align-items: center;
height: 100%;
}
.title-wrapper {
/* Prevent long titles overflowing and covering the search and menu buttons on narrow viewports. */
overflow: hidden;
}
.right-group,
.social-icons {
gap: 1rem;
align-items: center;
}
.social-icons::after {
content: '';
height: 2rem;
border-inline-end: 1px solid var(--sl-color-gray-5);
}
@media (min-width: 50rem) {
:global(:root[data-has-sidebar]) {
--__sidebar-pad: calc(2 * var(--sl-nav-pad-x));
}
:global(:root:not([data-has-toc])) {
--__toc-width: 0rem;
}
.header {
--__sidebar-width: max(0rem, var(--sl-content-inline-start, 0rem) - var(--sl-nav-pad-x));
--__main-column-fr: calc(
(
100% + var(--__sidebar-pad, 0rem) - var(--__toc-width, var(--sl-sidebar-width)) -
(2 * var(--__toc-width, var(--sl-nav-pad-x))) - var(--sl-content-inline-start, 0rem) -
var(--sl-content-width)
) / 2
);
display: grid;
grid-template-columns:
/* 1 (site title): runs up until the main content column’s left edge or the width of the title, whichever is the largest */
minmax(
calc(var(--__sidebar-width) + max(0rem, var(--__main-column-fr) - var(--sl-nav-gap))),
auto
)
/* 2 (search box): all free space that is available. */
1fr
/* 3 (right items): use the space that these need. */
auto;
align-content: center;
}
}
</style>
\ No newline at end of file
---
import LanguageSelect from '@astrojs/starlight/components/LanguageSelect.astro';
import SocialIcons from '@astrojs/starlight/components/SocialIcons.astro';
import ThemeSelect from '@astrojs/starlight/components/ThemeSelect.astro';
import type { Props } from '@astrojs/starlight/props';
import VersionSelect from './DocsVersionSelect.astro';
---
<div class="mobile-preferences sl-flex">
<div class="sl-flex social-icons">
<SocialIcons {...Astro.props} />
</div>
<ThemeSelect {...Astro.props} />
<VersionSelect {...Astro.props} />
<LanguageSelect {...Astro.props} />
</div>
<style>
.social-icons {
margin-inline-end: auto;
gap: 1rem;
align-items: center;
padding-block: 1rem;
}
.social-icons:empty {
display: none;
}
.mobile-preferences {
justify-content: space-between;
flex-wrap: wrap;
border-top: 1px solid var(--sl-color-gray-6);
column-gap: 1rem;
padding: 0.5rem 0;
}
</style>
\ No newline at end of file
import { defineCollection } from "astro:content";
import { docsLoader, i18nLoader } from "@astrojs/starlight/loaders";
import { docsSchema, i18nSchema } from "@astrojs/starlight/schema";
export const collections = {
docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
i18n: defineCollection({ loader: i18nLoader(), schema: i18nSchema() }),
};
---
title: Autenticação & Autorização
---
Castopod lida com autenticação e autorização usando `codeigniter/shield`
juntamente com regras personalizadas. Papéis e permissões são definidos em dois
níveis:
1. [toda instância](#1-instance-wide-roles-and-permissions)
2. [por podcast](#2-per-podcast-roles-and-permissions)
## 2. Por funções de podcast e permissões
### Instance roles
{/* AUTH-INSTANCE-ROLES-LIST:START - Do not remove or modify this section */}
| role | description | permissions |
| ----------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------ |
| Super admin | Has complete control over Castopod. | admin.\*, plugins.\*, podcasts.\*, users.manage, persons.manage, pages.manage, fediverse.manage-blocks |
| Manager | Manages Castopod's content. | podcasts.create, podcasts.import, persons.manage, pages.manage |
| Podcaster | General users of Castopod. | admin.access |
{/* AUTH-INSTANCE-ROLES-LIST:END */}
### Instance permissions
{/* AUTH-INSTANCE-PERMISSIONS-LIST:START - Do not remove or modify this section */}
| permission | description |
| ----------------------- | ------------------------------------------------------------------ |
| admin.access | Can access the Castopod admin area. |
| admin.settings | Can access the Castopod settings. |
| plugins.manage | Auth.instance_permissions.plugins.manage |
| users.manage | Can manage Castopod users. |
| persons.manage | Can manage persons. |
| pages.manage | Can manage pages. |
| podcasts.view | Can view all podcasts. |
| podcasts.create | Can create new podcasts. |
| podcasts.import | Can import podcasts. |
| fediverse.manage-blocks | Can block fediverse actors/domains from interacting with Castopod. |
{/* AUTH-INSTANCE-PERMISSIONS-LIST:END */}
## 2. Per podcast roles and permissions
### Por cargos de podcast
{/* AUTH-PODCAST-ROLES-LIST:START - Do not remove or modify this section */}
| role | description | permissions |
| ------ | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Admin | Has complete control of podcast #\{id\}. | \* |
| Editor | Manages content and publications of podcast #\{id\}. | view, edit, manage-import, manage-persons, manage-platforms, manage-publications, manage-notifications, interact-as, episodes.view, episodes.create, episodes.edit, episodes.delete, episodes.manage-persons, episodes.manage-clips, episodes.manage-publications, episodes.manage-comments |
| Author | Manages content of podcast #\{id\} but cannot publish them. | view, manage-persons, episodes.view, episodes.create, episodes.edit, episodes.manage-persons, episodes.manage-clips |
| Guest | General contributor of the podcast #\{id\}. | view, episodes.view |
{/* AUTH-PODCAST-ROLES-LIST:END */}
### Por permissões de podcast
{/* AUTH-PODCAST-PERMISSIONS-LIST:START - Do not remove or modify this section */}
| permission | description |
| ---------------------------- | -------------------------------------------------------------------------- |
| view | Can view dashboard and analytics of podcast #\{id\}. |
| edit | Can edit podcast #\{id\}. |
| delete | Can delete podcast #\{id\}. |
| manage-import | Can synchronize imported podcast #\{id\}. |
| manage-persons | Can manage subscriptions of podcast #\{id\}. |
| manage-subscriptions | Can manage subscriptions of podcast #\{id\}. |
| manage-contributors | Can manage contributors of podcast #\{id\}. |
| manage-platforms | Can set/remove platform links of podcast #\{id\}. |
| manage-publications | Can publish podcast #\{id\}. |
| manage-notifications | Can view and mark notifications as read for podcast #\{id\}. |
| interact-as | Can interact as the podcast #\{id\} to favourite, share or reply to posts. |
| episodes.view | Can view dashboards and analytics of podcast #\{id\}'s episodes. |
| episodes.create | Can create episodes for podcast #\{id\}. |
| episodes.edit | Can edit episodes of podcast #\{id\}. |
| episodes.delete | Can delete episodes of podcast #\{id\}. |
| episodes.manage-persons | Can manage episode persons of podcast #\{id\}. |
| episodes.manage-clips | Can manage video clips or soundbites of podcast #\{id\}. |
| episodes.manage-publications | Can publish/unpublish episodes and posts of podcast #\{id\}. |
| episodes.manage-comments | Can create/remove episode comments of podcast #\{id\}. |
{/* AUTH-PODCAST-PERMISSIONS-LIST:END */}
---
title: Official Docker images
---
Castopod pushes 3 Docker images to the Docker Hub during its automated build
process:
- [**`castopod/castopod`**](https://hub.docker.com/r/castopod/castopod): an all
in one castopod image using nginx unit
- [**`castopod/app`**](https://hub.docker.com/r/castopod/app): the app bundle
with all of Castopod dependencies
- [**`castopod/web-server`**](https://hub.docker.com/r/castopod/web-server): an
Nginx configuration for Castopod
Additionally, Castopod requires a MySQL-compatible database. A Redis database
can be added as a cache handler.
## Supported tags
- `develop` [unstable], latest development branch build
- `beta` [stable], latest beta version build
- `latest` [stable], latest version build
- `1.x.x` [stable], specific version build (since `1.0.0`)
## Example usage
1. Install [docker](https://docs.docker.com/get-docker/) and
[docker-compose](https://docs.docker.com/compose/install/)
2. Create a `docker-compose.yml` file with the following:
```yml
version: "3.7"
services:
app:
image: castopod/castopod:latest
container_name: "castopod-app"
volumes:
- castopod-media:/var/www/castopod/public/media
environment:
MYSQL_DATABASE: castopod
MYSQL_USER: castopod
MYSQL_PASSWORD: changeme
CP_BASEURL: "https://castopod.example.com"
CP_ANALYTICS_SALT: changeme
CP_CACHE_HANDLER: redis
CP_REDIS_HOST: redis
CP_REDIS_PASSWORD: changeme
networks:
- castopod-app
- castopod-db
ports:
- 8000:8000
restart: unless-stopped
mariadb:
image: mariadb:10.5
container_name: "castopod-mariadb"
networks:
- castopod-db
volumes:
- castopod-db:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: changeme
MYSQL_DATABASE: castopod
MYSQL_USER: castopod
MYSQL_PASSWORD: changeme
restart: unless-stopped
redis:
image: redis:7.0-alpine
container_name: "castopod-redis"
command: --requirepass changeme
volumes:
- castopod-cache:/data
networks:
- castopod-app
volumes:
castopod-media:
castopod-db:
castopod-cache:
networks:
castopod-app:
castopod-db:
```
You have to adapt some variables to your needs (e.g. `CP_BASEURL`,
`MYSQL_ROOT_PASSWORD`, `MYSQL_PASSWORD` and `CP_ANALYTICS_SALT`).
3. Setup a reverse proxy for TLS (SSL/HTTPS)
TLS is mandatory for ActivityPub to work. This job can easily be handled by a
reverse proxy, for example with [Caddy](https://caddyserver.com/):
```
#castopod
castopod.example.com {
reverse_proxy localhost:8000
}
```
4. Run `docker-compose up -d`, wait for it to initialize and head on to
`https://castopod.example.com/cp-install` to finish setting up Castopod!
5. You're all set, start podcasting! 🎙️🚀
## Environment Variables
- **castopod/castopod** and **castopod/app**
| Variable name | Type (`default`) | Default |
| ------------------------------------- | ----------------------- | ---------------- |
| **`CP_BASEURL`** | string | `undefined` |
| **`CP_MEDIA_BASEURL`** | ?string | `CP_BASEURL` |
| **`CP_ADMIN_GATEWAY`** | ?string | `"cp-admin"` |
| **`CP_AUTH_GATEWAY`** | ?string | `"cp-auth"` |
| **`CP_ANALYTICS_SALT`** | string | `undefined` |
| **`CP_DATABASE_HOSTNAME`** | ?string | `"mariadb"` |
| **`CP_DATABASE_NAME`** | ?string | `MYSQL_DATABASE` |
| **`CP_DATABASE_USERNAME`** | ?string | `MYSQL_USER` |
| **`CP_DATABASE_PASSWORD`** | ?string | `MYSQL_PASSWORD` |
| **`CP_DATABASE_PREFIX`** | ?string | `"cp_"` |
| **`CP_CACHE_HANDLER`** | [`"file"` or `"redis"`] | `"file"` |
| **`CP_REDIS_HOST`** | ?string | `"localhost"` |
| **`CP_REDIS_PASSWORD`** | ?string | `null` |
| **`CP_REDIS_PORT`** | ?number | `6379` |
| **`CP_REDIS_DATABASE`** | ?number | `0` |
| **`CP_EMAIL_SMTP_HOST`** | ?string | `undefined` |
| **`CP_EMAIL_FROM`** | ?string | `undefined` |
| **`CP_EMAIL_SMTP_USERNAME`** | ?string | `"localhost"` |
| **`CP_EMAIL_SMTP_PASSWORD`** | ?string | `null` |
| **`CP_EMAIL_SMTP_PORT`** | ?number | `25` |
| **`CP_EMAIL_SMTP_CRYPTO`** | [`"tls"` or `"ssl"`] | `"tls"` |
| **`CP_ENABLE_2FA`** | ?boolean | `undefined` |
| **`CP_MEDIA_FILE_MANAGER`** | ?string | `undefined` |
| **`CP_MEDIA_S3_ENDPOINT`** | ?string | `undefined` |
| **`CP_MEDIA_S3_KEY`** | ?string | `undefined` |
| **`CP_MEDIA_S3_SECRET`** | ?string | `undefined` |
| **`CP_MEDIA_S3_REGION`** | ?string | `undefined` |
| **`CP_MEDIA_S3_BUCKET`** | ?string | `undefined` |
| **`CP_MEDIA_S3_PROTOCOL`** | ?number | `undefined` |
| **`CP_MEDIA_S3_PATH_STYLE_ENDPOINT`** | ?boolean | `undefined` |
| **`CP_MEDIA_S3_KEY_PREFIX`** | ?string | `undefined` |
| **`CP_DISABLE_HTTPS`** | ?[`0` or `1`] | `undefined` |
| **`CP_MAX_BODY_SIZE`** | ?number (with suffix) | `512M` |
| **`CP_PHP_MEMORY_LIMIT`** | ?number (with suffix) | `512M` |
| **`CP_TIMEOUT`** | ?number | `900` |
- **castopod/web-server**
| Variable name | Type | Default |
| ---------------------- | --------------------- | ------- |
| **`CP_APP_HOSTNAME`** | ?string | `"app"` |
| **`CP_MAX_BODY_SIZE`** | ?number (with suffix) | `512M` |
| **`CP_TIMEOUT`** | ?number | `900` |
---
title: How to install Castopod?
---
import { Aside } from "@astrojs/starlight/components";
Castopod was thought-out to be easy to install. Whether using dedicated or
shared hosting, you can install it on most PHP-MySQL compatible web servers.
## Requirements
- PHP v8.4 or higher
- MySQL version 8.4 or higher or MariaDB version 11.4 or higher
- HTTPS support
- An [ntp-synced clock](https://wiki.debian.org/NTP) to validate federation's
incoming requests
### PHP v8.4 or higher
PHP version 8.4 or higher is required, with the following extensions installed:
- [intl](https://php.net/manual/en/intl.requirements.php)
- [libcurl](https://php.net/manual/en/curl.requirements.php)
- [mbstring](https://php.net/manual/en/mbstring.installation.php)
- [gd](https://www.php.net/manual/en/image.installation.php) with **JPEG**,
**PNG** and **WEBP** libraries.
- [exif](https://www.php.net/manual/en/exif.installation.php)
Additionally, make sure that the following extensions are enabled in your PHP:
- json (enabled by default - don't turn it off)
- xml (enabled by default - don't turn it off)
- [mysqlnd](https://php.net/manual/en/mysqlnd.install.php)
### MySQL compatible database
> We recommend using [MariaDB](https://mariadb.org).
You will need the server hostname, database name, username and password to
complete the installation process. If you do not have these, please contact your
server administrator.
#### Privileges
User must have at least these privileges on the database for Castopod to work:
`CREATE`, `ALTER`, `DELETE`, `EXECUTE`, `INDEX`, `INSERT`, `SELECT`, `UPDATE`,
`REFERENCES`, `CREATE VIEW`.
### (Optional) FFmpeg v4.1.8 or higher for Video Clips
[FFmpeg](https://www.ffmpeg.org/) version 4.1.8 or higher is required if you
want to generate Video Clips. The following extensions must be installed:
- **FreeType 2** library for
[gd](https://www.php.net/manual/en/image.installation.php).
### (Optional) Other recommendations
- Redis for better cache performances.
- CDN for static files caching and better performances.
- e-mail gateway for lost passwords.
## Install instructions
### Pre-requisites
0. Get a Web Server with [requirements](#requirements) installed
1. Create a MySQL database for Castopod with a user having access and
modification privileges (for more info, see
[MySQL compatible database](#mysql-compatible-database)).
2. Activate HTTPS on your domain with an _SSL certificate_.
3. Download and unzip the latest [Castopod Package](https://castopod.org/) onto
the web server if you haven’t already.
- ⚠️ Set the web server document root to the `public/` sub-folder within the
`castopod` folder.
4. Add **cron tasks** on your web server for various background processes
(replace the paths accordingly):
```bash
* * * * * /path/to/php /path/to/castopod/spark tasks:run >> /dev/null 2>&1
```
**Note** - If you do not add this cron task, the following Castopod features
will not work:
- Importing a podcast from an existing RSS feed
- Broadcasting social activities to your followers in the fediverse
- Broadcasting episodes to open hubs using
[WebSub](https://en.wikipedia.org/wiki/WebSub)
- Generating video clips -
[requires FFmpeg](#optional-ffmpeg-v418-or-higher-for-video-clips)
### (recommended) Install Wizard
1. Run the Castopod install script by going to the install wizard page
(`https://your_domain_name.com/cp-install`) in your favorite web browser.
2. Follow the instructions on your screen.
3. Začať podcastovať!
<Aside>
The install script writes a `.env` file in the package root. If you cannot go
through the install wizard, you can create and edit the `.env` file manually
based on the `.env.example` file.
</Aside>
### Using CLI
1. Create a `.env` file in the package root based on the `.env.example` file.
2. Initialize the database using:
```sh
php spark install:init-database
```
3. Create the superadmin user using:
```sh
php spark install:create-superadmin
```
4. Head on to your admin gateway to start podcasting!
### Email/SMTP setup
Email configuration is required for some features to work properly (eg.
retrieving your forgotten password, sending instructions to premium subscribers,
…)
You may add your email configuration in your instance's `.env` like so:
```ini
# […]
email.fromEmail="your_email_address"
email.SMTPHost="your_smtp_host"
email.SMTPUser="your_smtp_user"
email.SMTPPass="your_smtp_password"
```
#### Email config options
| Variable name | Type | Default |
| ---------------- | -------------------- | ------------ |
| **`fromEmail`** | string | `undefined` |
| **`fromName`** | string | `"Castopod"` |
| **`SMTPHost`** | string | `undefined` |
| **`SMTPUser`** | string | `undefined` |
| **`SMTPPass`** | string | `undefined` |
| **`SMTPPort`** | number | `25` |
| **`SMTPCrypto`** | [`"tls"` or `"ssl"`] | `"tls"` |
### Media storage
By default, files are saved to the `public/media` folder using the file system.
If you need to relocate the `media` folder to a different location, you can
specify it in your `.env` file as shown below:
```ini
# […]
media.root="media"
media.storage="/mnt/storage"
```
In this example, the files will be saved to the /mnt/storage/media folder. Make
sure to also update your web server configuration to reflect this change.
### S3
If you prefer storing your media files on an S3 compatible storage, you may
specify it in your `.env`:
```ini
# […]
media.fileManager="s3"
media.s3.endpoint="your_s3_host"
media.s3.key="your_s3_key"
media.s3.secret="your_s3_secret"
media.s3.region="your_s3_region"
```
#### S3 config options
| Variable name | Type | Default |
| ----------------------- | ------- | ----------- |
| **`endpoint`** | string | `undefined` |
| **`key`** | string | `undefined` |
| **`secret`** | string | `undefined` |
| **`region`** | string | `undefined` |
| **`bucket`** | string | `castopod` |
| **`protocol`** | number | `undefined` |
| **`pathStyleEndpoint`** | boolean | `false` |
| **`keyPrefix`** | string | `undefined` |
## Community packages
If you don't want to bother with installing Castopod manually, you may use one
of the packages created and maintained by the open-source community.
### Install with YunoHost
[YunoHost](https://yunohost.org/) is a distribution based on Debian GNU/Linux
made up of free and open-source software packages. It manages the hardships of
self-hosting for you.
<div class="flex flex-wrap items-center gap-4">
<a
href="https://install-app.yunohost.org/?app=castopod"
target="_blank"
rel="noopener noreferrer"
>
<img
src="https://install-app.yunohost.org/install-with-yunohost.svg"
alt="Install Castopod with YunoHost"
class="align-middle"
/>
</a>
<a
href="https://github.com/YunoHost-Apps/castopod_ynh"
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center px-4 py-[.3rem] mx-auto font-semibold text-center text-black rounded-md gap-x-1 border-2 border-solid border-[#333] hover:no-underline hover:bg-gray-100"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="1em"
height="1em"
class="text-xl"
>
<path fill="none" d="M0 0h24v24H0z" />
<path d="M12 2A10 10 0 0 0 2 12a10 10 0 0 0 6.84 9.49c.5.09.69-.21.69-.48l-.02-1.86c-2.51.46-3.16-.61-3.36-1.18-.11-.28-.6-1.17-1.02-1.4-.35-.2-.85-.66-.02-.67.79-.01 1.35.72 1.54 1.02.9 1.52 2.34 1.1 2.91.83a2.1 2.1 0 0 1 .64-1.34c-2.22-.25-4.55-1.11-4.55-4.94A3.9 3.9 0 0 1 6.68 8.8a3.6 3.6 0 0 1 .1-2.65s.83-.27 2.75 1.02a9.28 9.28 0 0 1 2.5-.34c.85 0 1.7.12 2.5.34 1.9-1.3 2.75-1.02 2.75-1.02.54 1.37.2 2.4.1 2.65.63.7 1.02 1.58 1.02 2.68 0 3.84-2.34 4.7-4.56 4.94.36.31.67.91.67 1.85l-.01 2.75c0 .26.19.58.69.48A10.02 10.02 0 0 0 22 12 10 10 0 0 0 12 2z" />
</svg>
Github Repo
</a>
</div>
---
title: Security concerns
---
Castopod is built on top of [CodeIgniter4](https://codeigniter.com/), a PHP
framework that encourages
[good security practices](https://codeigniter.com/user_guide/concepts/security.html).
To maximize your instance's safety and prevent any malicious attack, we
recommend you update all your Castopod files permissions after installation or
updates (to avoid any prior permission error):
- `writable/` folder must be **readable** and **writable**.
- `public/media/` folder must be **readable** and **writable**.
- any other file must be set to **readonly**.
For instance, if you are using Apache or NGINX with Ubuntu you may do the
following:
```bash
sudo chown -R root:root /path/to/castopod
sudo chown -R www-data:www-data /path/to/castopod/writable
sudo chown -R www-data:www-data /path/to/castopod/public/media
```