Compare commits

..

No commits in common. "main" and "v2.1.8" have entirely different histories.
main ... v2.1.8

361 changed files with 1428 additions and 24783 deletions

View File

@ -1,11 +0,0 @@
{
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": ["astro-playground", "starlight-playground"]
}

2
.env.demo Normal file
View File

@ -0,0 +1,2 @@
CONTENT_API_KEY=a33da3965a3a9fb2c6b3f63b48
CONTENT_API_URL=https://ghostdemo.matthiesen.xyz

3
.github/FUNDING.yml vendored
View File

@ -1,3 +0,0 @@
# These are supported funding model platforms
custom: ['https://www.buymeacoffee.com/adammatthiesen/membership']

View File

@ -1,38 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -1,18 +0,0 @@
---
name: New Chore
about: Used to create a new Chore for a needed task
title: "Chore: [NAME]"
labels: chore
---
**Is your chore related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

View File

@ -1,18 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "npm" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
groups:
prod-dependencies:
dependency-type: "production"
dev-dependencies:
dependency-type: "development"
labels:
- "dependencies"

View File

@ -1,38 +0,0 @@
branchName: 'issue-${issue.number}-${issue.title[0,32]}'
gitReplaceChars: '/<>'
autoLinkIssue: true
openDraftPR: true
prSkipCI: true
copyIssueDescriptionToPR: true
copyIssueLabelsToPR: true
copyIssueAssigneeToPR: true
copyIssueProjectsToPR: true
copyIssueMilestoneToPR: true
conventionalPrTitles: true
conventionalLabels:
fix:
bug: '🐛'
dependencies: '⬆️'
security: '🔒'
feat:
enhancement: '✨'
new-stuff: '🚀'
build:
build: '🔧'
chore:
chore: '♻️'
ci:
ci: '👷'
docs:
documentation: '📝'
style:
style: '💎'
refactor:
refactor: '♻️'
perf:
performance: '⚡️'
test:
test: '✅'
breaking:
breaking-change: '💥'
breaking change: '💥'

View File

@ -1,18 +0,0 @@
name: Auto Issue Branch
on:
issues:
types: [ opened, assigned ]
issue_comment:
types: [ created ]
pull_request:
types: [ opened, closed ]
jobs:
create_issue_branch_job:
runs-on: ubuntu-latest
steps:
- name: Create Issue Branch
uses: robvanderleek/create-issue-branch@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,16 +0,0 @@
name: "Changesets: Build Changesets for Dependabot"
on: pull_request
permissions:
contents: write
pull-requests: write
jobs:
changesets:
runs-on: ubuntu-latest
if: ${{ github.actor == 'dependabot[bot]' }}
steps:
- name: Dependabot Changesets
uses: feelepxyz/dependabot-changesets@v1

View File

@ -1,38 +0,0 @@
name: "Changesets: Publish Packages from main"
on:
push:
branches:
- main
permissions:
pull-requests: write
contents: write
env:
CI: true
jobs:
version:
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- name: checkout code repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: setup node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: install pnpm
run: npm i pnpm@latest -g
- name: Setup npmrc
run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc
- name: install dependencies
run: pnpm install --no-frozen-lockfile
- name: create and publish versions
uses: matthiesenxyz/changeset@v1
with:
version: pnpm ci:version
commit: "chore: update versions"
title: "👷 [ci]: Ready for Release"
publish: pnpm ci:publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,17 +0,0 @@
name: Write coauthors to a pull request
permissions:
pull-requests: write
on:
issue_comment:
types:
- created
jobs:
generate-coauthors:
name: Generate Coauthor
if: ${{ github.event.issue.pull_request }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: kevinzunigacuellar/coauthor-action@v0.1.2

View File

@ -1,22 +0,0 @@
name: "Sync: GitHub => GitLab"
on:
- push
- delete
jobs:
sync:
runs-on: ubuntu-latest
name: Git Repo Sync
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: MatthiesenXYZ/git-sync-action@v1.1
with:
# Such as https://github.com/wangchucheng/git-repo-sync.git
target-url: ${{ secrets.GITLAB_URL }}
# Such as wangchucheng
target-username: ${{ secrets.GITLAB_USERNAME }}
# You can store token in your project's 'Setting > Secrets' and reference the name here. Such as ${{ secrets.ACCESS\_TOKEN }}
target-token: ${{ secrets.GITLAB_ACCESS }}

47
.github/workflows/publish.yml vendored Normal file
View File

@ -0,0 +1,47 @@
name: publish npm
on:
release:
types: [created]
jobs:
publishnpm:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- name: node
uses: actions/setup-node@v3
with:
node-version: 18
registry-url: https://registry.npmjs.org/
- name: publish-npm
run: |
# Change publish registry
echo "$(jq '.publishConfig.registry = "https://registry.npmjs.org"' package.json)" > package.json
# Publish package
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
githubpackage:
permissions:
contents: read
packages: write
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- name: node
uses: actions/setup-node@v3
with:
node-version: 18
registry-url: https://npm.pkg.github.com
- name: publish-github
run: |
# Change publish registry
echo "$(jq '.publishConfig.registry = "https://npm.pkg.github.com"' package.json)" > package.json
# Publish package
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{secrets.ACTION_TOKEN}}

27
.gitignore vendored
View File

@ -1,3 +1,24 @@
node_modules
.archive
.npmrc
# build output
dist
.vercel
# generated types
.astro/
# dependencies
node_modules/
.snowpack/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store
# editor
.idea
package-lock.json

View File

@ -1,6 +0,0 @@
{
"editor.defaultFormatter": "biomejs.biome",
"[astro]": {
"editor.defaultFormatter": "astro-build.astro-vscode"
}
}

4
.vscode/tasks.json vendored
View File

@ -1,4 +0,0 @@
{
"version": "2.0.0",
"tasks": []
}

View File

@ -1,128 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
support@matthiesen.xyz.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@ -1,50 +0,0 @@
# Contributing to Astro-GhostCMS
We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's:
- Reporting a bug
- Discussing the current state of the code
- Submitting a fix
- Proposing new features
- Becoming a maintainer
## We Develop with Github & Sync our Code to GitLab
We use github to host code, to track issues and feature requests, as well as accept pull requests. Then All of our Code is Mirrored to GitLab.
## We Use Changesets to aid with Development!
This repo uses [changesets](https://github.com/changesets/changesets) to make releasing updates easier. For you, the contributor, this means you should run `pnpm changeset` when you've got your changes ready.
For more details, see this short document on [adding a changeset](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md#i-am-in-a-single-package-repository).
## We Use Github, So All Code Changes Happen Through Pull Requests and Commits
Pull requests are the best way to propose changes to the codebase. We actively welcome your pull requests:
1. Fork the repo and create your branch from `main`.
2. If you've changed APIs or Added features, update the documentation.
3. Make sure to test your code in the `Playground`
4. Issue that pull request!
## Any contributions you make will be under the MIT Software License
In short, when you submit code changes, your submissions are understood to be under the same [MIT License](http://choosealicense.com/licenses/mit/) that covers the project. Feel free to contact the maintainers if that's a concern.
## Report bugs using Github's [issues](https://github.com/MatthiesenXYZ/astro-ghostcms/issues) or [issues@astro-ghostcms.xyz](mailto:issues@astro-ghostcms.xyz)
We use GitHub issues to track public bugs. Report a bug by [opening a new issue](); it's that easy!
## Write bug reports with detail, background, and sample code
**Great Bug Reports** tend to have:
- A quick summary and/or background
- Steps to reproduce
- Be specific!
- Give sample code if you can. Or a minimum reproduction using a empty repo, or Gitpod type setup.
- What you expected would happen
- What actually happens
- Notes (possibly including why you think this might be happening, or stuff you tried that didn't work)
People *love* thorough bug reports. I'm not even kidding.
## License
By contributing, you agree that your contributions will be licensed under its MIT License.
## References
This document was adapted from the open-source contribution guidelines for [Facebook's Draft](https://github.com/facebook/draft-js/blob/a9316a723f9e918afde44dea68b5f9f39b7d9b00/CONTRIBUTING.md)

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2024 MatthiesenXYZ - Astro-GhostCMS
Copyright (c) 2024 Adam Matthiesen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

117
README.md
View File

@ -1,56 +1,105 @@
<img src="https://repository-images.githubusercontent.com/742727289/d4fb3f65-0d5f-4a1a-9f8b-9b3e2dc90bde" />
<img src="https://ghostdemo.matthiesen.xyz/content/images/size/w50/2024/01/logo-1.png" width="64px" />
Want to Chat? Join our [Discord](https://discord.gg/u7NZqUyeAR)
# Welcome to Astro-GhostCMS
For a full always up to date documentation please checkout [Our Website](https://astro-ghostcms.xyz)
- [Live Demo](https://demo.astro-ghostcms.xyz/) of the Astro-GhostCMS integration in action!
- [Live Demo - Unlighthouse Test](https://test.demo.astro-ghostcms.xyz) for a Automatically updated Lighthouse test from every deploy!
- [Live Demo's Repo](https://github.com/MatthiesenXYZ/astro-ghostcms-demo) for an example of how the setup looks.
Don't like GitHub, and prefer GitLab? This Repo is Auto Cloned to Gitlab! Check it out here: [GitLab: Astro-GhostCMS](https://gitlab.com/matthiesenxyz/astro-ghostcms)
*Need help but don't have Github? Email us at [issues@astro-ghostcms.xyz](mailto:issues@astroghostcms.xyz) to create an issue here on github!*
## Demos
Astro minimum Version: **Astro v4.0**
- [Default Theme](https://demo.astro-ghostcms.xyz) - ( [Github Repo](https://github.com/MatthiesenXYZ/demo-astroghostcms-themedefault) )
- [Catppuccin Theme](https://catppuccindark-demo.astro-ghostcms.xyz/) - ( [Github Repo](https://github.com/MatthiesenXYZ/demo-astroghostcms-catppuccin) )
- [Brutal by Elian Theme](https://brutal-demo.astro-ghostcms.xyz) - ( [Github Repo](https://github.com/MatthiesenXYZ/demo-astroghostcms-brutalbyelian) )
- [Starlight GhostCMS](https://starlightdemo.astro-ghostcms.xyz/) - ( [Github Repo](https://github.com/MatthiesenXYZ/demo-starlightghostcms) )
This Integration is 2 parts. Firstly, there is the API portion that uses the `@tryghost/content-api` to create the link between astro and GhostCMS. From there we move to the Second Part, which is a theme pre-programmed to pull ALL of its data from GhostCMS iteself instead of storing any data locally outside of Build.
## Quick Start
- *This package contains a independent copy of the tryghost content-api.js that is used to establish the connection so this package dose not depend on `@tryghost/content-api` package.*
- If you are looking for a more Customizable option please check [astro-ghostcms-basetheme](https://github.com/MatthiesenXYZ/astro-ghostcms-basetheme)
- This project is not setup for SSR in Integration mode. As such is will most likely not function properly in that mode. You will need to build your own project around the API or customize the *basetheme* linked above.
# Astro Integration Mode
In this mode, the addon will not be just an API, but will be a full Route takeover, there is plans to add more themes in time, but for now there is only the base Casper theme based on Ghost's main Theme.
## Astro Add Installation
```sh
# Its easy run this command and follow the prompt!
npx @matthiesenxyz/create-astro-ghostcms
# For fresh Install
npm create astro@latest
# Create Empty Install with standard typescript
# Then Delete entire `pages` folder under `/src/`
npx astro add @matthiesenxyz/astro-ghostcms
```
#### Dont forget to set your environment Variables!
You must also create 2 environment variables in a `.env` file with the following:
```env
CONTENT_API_KEY=a33da3965a3a9fb2c6b3f63b48
CONTENT_API_URL=https://ghostdemo.matthiesen.xyz
```
## Manual Installation
```
npm i @matthiesenxyz/astro-ghostcms
```
## Our Supporters:
Then set your astro.config.ts to look like this:
Want to be listed here? by name or logo? [Signup Here](https://www.buymeacoffee.com/adammatthiesen/membership) for an Astro-GhostCMS Suppoter Membership *(Silver and up get listed here)* Also All Suppoter Memberships get a Discord rank!
```ts
import { defineConfig } from "astro/config";
import sitemap from "@astrojs/sitemap"; //optional but recommended
import GhostCMS from '@matthiesenxyz/astro-ghostcms';
## Repo Structure
// https://astro.build/config
export default defineConfig({
site: "https://YOUR-DOMAIN-HERE.com"
integrations: [sitemap(), GhostCMS()],
});
```
This repo is structured as a `pnpm` monorepo. All of our packages can be found under the `packages/` folder. These are all internal packages or independently published that can be found on [npmjs.com](https://npmjs.com)
#### Dont forget to set your environment Variables!
In this Repo you will find the Following:
You must also create 2 environment variables in a `.env` file with the following:
- `playgrounds/`:
- [`astro-playground`](./playgrounds/astro-playground/): Playground for Astro-GhostCMS development and testing.
- [`starlight-playground`](./playgrounds/starlight-playground/): Playground of Starlight-GhostCMS development and testing.
- `packages/`:
- [`create-astro-ghostcms`](./packages/create-astro-ghostcms/): CLI Utility to quickly deploy new Astro-GhostCMS projects.
- [`astro-ghostcms`](./packages/astro-ghostcms/): The main Integration!
- [`astro-ghostcms-theme-default`](./packages/astro-ghostcms-theme-default/): The Default theme in integration mode.
- [`astro-ghostcms-catppuccin`](./packages/astro-ghostcms-catppuccin/): A dark theme made with Catppuccin and TailwindCSS for Astro-GhostCMS Integration Mode.
- [`astro-ghostcms-brutalbyelian`](./packages/astro-ghostcms-brutalbyelian/): [ElianCodes](https://www.elian.codes/) Brutal theme modified to work with Astro-GhostCMS
- [`starlight-ghostcms`](./packages/starlight-ghostcms/) A [Starlight Plugin](https://starlight.astro.build/resources/plugins/) to integrate your GhostCMS into your documentation website
```env
CONTENT_API_KEY=a33da3965a3a9fb2c6b3f63b48
CONTENT_API_URL=https://ghostdemo.matthiesen.xyz
```
## Contributing
**When you deploy your install dont forget to set the above ENVIRONMENT VARIABLES!**
- [Contributing Doc](./CONTRIBUTING.md)
#### Created Routes
### Acknowledgments
The routes are the same as a standard Ghost Blog so you can migrate to Astro easily.
*Ghost is a trademark of [The Ghost Foundation](https://ghost.org/trademark/). This project is not directly related to or provided by The Ghost Foundation and is intended to help create a easier method to utilize their provided JavaScript tools to link a Headless GhostCMS install in to your Astro project.*
| Route | Content |
| --------------------- | ----------------------------------------- |
| `/` | Homepage with recents/features Blog Posts |
| `/404` | 404 Page |
| `/[slug]` | Post or Page |
| `/author/[slug]` | Author page with related posts |
| `/authors` | All the authors |
| `/tag[slug]` | Tag page with related posts |
| `/tags` | All the tags |
| `/archives/[...page]` | All the posts, paginated |
| `/rss.xml` | All the posts, in a FEED |
[![Built with Astro](https://astro.badg.es/v2/built-with-astro/medium.svg)](https://astro.build)
Maintained with [GitKraken](https://www.gitkraken.com/invite/hirocQWn)
# Manual Function Mode (DIY MODE)
<img width="300" alt="gitkraken-logo-stencil-color" src="https://github.com/MatthiesenXYZ/astro-ghostcms/assets/30383579/751e20a9-8f7e-4a74-9fec-665e17f8715a">
In this mode the integration will not deploy routes at all. you will have to build your own website to utilize the exported functions listed below.
```
npm i @matthiesenxyz/astro-ghostcms
```
You must also create 2 environment variables in a `.env` file with the following:
```env
CONTENT_API_KEY=a33da3965a3a9fb2c6b3f63b48
CONTENT_API_URL=https://ghostdemo.matthiesen.xyz
```
**When you deploy your install dont forget to set the above ENVIRONMENT VARIABLES!**
For more information please check our website: [Astro-GhostCMS.xyz](https://astro-ghostcms.xyz)

View File

@ -1,12 +0,0 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 3.0.x | :white_check_mark: |
| < 3.0 | :x: |
## Reporting a Vulnerability
If you find an issue with our security please report it to [issues@astro-ghostcmx.xyz](mailto:issues@astro-ghostcms.xyz) or Open a Issue on GitHub

View File

@ -1,18 +0,0 @@
{
"$schema": "https://biomejs.dev/schemas/1.5.2/schema.json",
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noExplicitAny": "off"
}
}
},
"files": {
"ignore": ["dist", ".astro"]
}
}

187
index.ts Normal file
View File

@ -0,0 +1,187 @@
import type { AstroIntegration } from "astro";
import type { SafeParseError, SafeParseSuccess } from "astro/zod";
import { UserConfigSchema, type UserConfig } from "./src/utils/UserConfigSchema";
import { ghostSitemap, ghostRobots } from "./src/integrations";
import { loadEnv } from 'vite';
import { fromZodError } from "zod-validation-error";
import { viteGhostCMS } from "./src/utils/virtual-imports";
/** INTERNAL CONSTANTS */
const IC = {
/** INTERNAL PACKAGE NAME */
PKG:'@matthiesenxyz/astro-ghostcms',
/** INTERNAL STRING */
CHECK_ENV:"Checking for Environment Variables...",
/** SET ENV GRABBER MODE */
MODE: 'all',
/** SET ENV GRABBER PREFIXES */
PREFIXES: 'CONTENT_API',
/** INTERNAL STRING */
KEY_MISSING:"CONTENT_API_KEY Missing from .env",
/** INTERNAL STRING */
URL_MISSING:"CONTENT_API_URL Missing from .env",
/** INTERNAL STRING */
IT:"Injecting Theme: ",
/** INTERNAL STRING */
IR:"Injecting Routes...",
/** INTERNAL STRING */
IRD:"Route Injection Disabled - Skipping...",
/** INTERNAL STRING */
IIR:"Injecting Integration Route: ",
/** INTERNAL STRING */
II:"Injecting Integration: ",
/** INTERNAL STRING */
AIbU:"Already Imported by User: ",
/** INTERNAL STRING */
CF:"Checking for ",
/** INTERNAL STRING */
CONFSETUPDONE:"GhostCMS Injection Complete. Integration is now ready.",
}
/** CONTENT API ENVIRONMENT VARIABLES */
const ENV = loadEnv(IC.MODE, process.cwd(), IC.PREFIXES);
/** Astro-GhostCMS Integration
* @ For more information and to see the docs check
* @ https://astro-ghostcms.xyz
*/
export default function GhostCMS(options: UserConfig): AstroIntegration {
return {
name: IC.PKG,
hooks: {
'astro:config:setup': async ({
injectRoute,
config,
updateConfig,
logger,
}) => {
// CHECK USER CONFIG AND MAKE AVAILBLE TO INTEGRATIONS
logger.info("Checking Config...")
const o = UserConfigSchema.safeParse(options || {}) as SafeParseSuccess<UserConfig>;
if (!o.success) {
const validationError = fromZodError((o as unknown as SafeParseError<UserConfig>).error);
logger.error(`Config Error - ${ validationError }`);
throw validationError;
}
/** INTERNAL USERCONFIG ALIAS */
const uconf = o.data;
/** CONFIG OPTION: ROUTE INJECTION */
const injection = uconf.disableRouteInjection;
/** CONFIG OPTION: THEME */
const entry = uconf.theme;
/** CONFIG OPTION: CONSOLE OUTPUT */
const logs = uconf.disableConsoleOutput;
// Check For ENV Variables
if(!logs) {logger.info(IC.CHECK_ENV)}
// CHECK FOR API KEY
if(ENV.CONTENT_API_KEY === undefined){
logger.error(IC.KEY_MISSING);
throw IC.KEY_MISSING;
}
// CHECK FOR API URL
if(ENV.CONTENT_API_URL === undefined){
logger.error(IC.URL_MISSING);
throw IC.URL_MISSING;
}
if(!injection){
// THEME SELECTOR
if (entry === IC.PKG) {
if(!logs) {logger.info(IC.IT + IC.PKG)}
} else {
if(!logs) {logger.info(IC.IT + entry)}
}
// INJECT ROUTES
if(!logs) {logger.info(IC.IR)}
injectRoute({
pattern: '/',
entrypoint: `${entry}/index.astro`
});
injectRoute({
pattern: '/404',
entrypoint: `${entry}/404.astro`
});
injectRoute({
pattern: '/[slug]',
entrypoint: `${entry}/[slug].astro`
});
injectRoute({
pattern: '/tags',
entrypoint: `${entry}/tags.astro`
});
injectRoute({
pattern: '/authors',
entrypoint: `${entry}/authors.astro`
});
injectRoute({
pattern: '/tag/[slug]',
entrypoint: `${entry}/tag/[slug].astro`
});
injectRoute({
pattern: '/author/[slug]',
entrypoint: `${entry}/author/[slug].astro`
});
injectRoute({
pattern: '/archives/[...page]',
entrypoint: `${entry}/archives/[...page].astro`
});
} else {
if(!logs) {logger.info(IC.IRD)}
}
// IMPORT INTEGRATIONS & INTEGRATION ROUTES
const int = [...config.integrations];
// IMPORT INTEGRATION: @ASTROJS/RSS
if(!logs) {logger.info(IC.IIR + "@astrojs/rss")}
injectRoute({
pattern: '/rss.xml',
entrypoint: `${IC.PKG}/rss.xml.js`
});
// IMPORT INTEGRATION: @ASTROJS/SITEMAP
if(!logs) {logger.info(IC.CF + "@astrojs/sitemap")}
if (!int.find(({ name }) => name === '@astrojs/sitemap')) {
if(!logs) {logger.info(IC.II + "@astrojs/sitemap")}
int.push(ghostSitemap(uconf));
} else {
if(!logs) {logger.info(IC.AIbU + "@astrojs/sitemap")}
};
// IMPORT INTEGRATION: ASTRO-ROBOTS-TXT
if(!logs) {logger.info(IC.CF + "astro-robots-txt")}
if (!int.find(({ name }) => name === 'astro-robots-txt')) {
if(!logs) {logger.info(IC.II + "astro-robots-txt")}
int.push(ghostRobots(uconf));
} else {
if(!logs) {logger.info(IC.AIbU + "astro-robots-txt")}
};
try {updateConfig({
integrations: [
ghostSitemap(uconf),
ghostRobots(uconf),
],
vite:{plugins:[viteGhostCMS(uconf,config)]},
}) } catch (e) {
logger.error(e as string);
throw e;
};
},
'astro:config:done': async ({ logger }) => {
logger.info(IC.CONFSETUPDONE);
}
}
}
}

View File

@ -1,31 +1,79 @@
{
"name": "root",
"private": true,
"packageManager": "pnpm@8.14.1",
"engines": {
"node": ">=18.19.0"
},
"scripts": {
"astro:dev": "pnpm --filter astro-playground dev",
"starlight:dev": "pnpm --filter starlight-playground dev",
"lint": "biome check .",
"lint:fix": "biome check --apply .",
"ci:version": "pnpm changeset version",
"ci:publish": "pnpm changeset publish",
"ci:test:integration": "pnpm --filter astro-ghostcms test:ci",
"test:integration": "pnpm --filter astro-ghostcms test",
"test:integration:watch": "pnpm --filter astro-ghostcms test:watch",
"test:integration:coverage": "pnpm --filter astro-ghostcms test:coverage",
"test:create-utility": "pnpm --filter create-astro-ghostcms test",
"test:starlight": "pnpm --filter starlight-ghostcms test",
"test:starlight:watch": "pnpm --filter starlight-ghostcms test:watch",
"test:starlight:coverage": "pnpm --filter starlight-ghostcms test:coverage"
},
"devDependencies": {
"@biomejs/biome": "1.6.1",
"@changesets/cli": "^2.27.1",
"@vitest/ui": "^1.4.0",
"vitest": "^1.4.0",
"vitest-fetch-mock": "^0.2.2"
}
"name": "@matthiesenxyz/astro-ghostcms",
"description": "Astro GhostCMS integration to allow easier importing of GhostCMS Content",
"version": "2.1.8",
"author": "MatthiesenXYZ (https://matthiesen.xyz)",
"type": "module",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/MatthiesenXYZ/astro-ghostcms.git"
},
"bugs": {
"url": "https://github.com/MatthiesenXYZ/astro-ghostcms/issues",
"email": "issues@astro-ghostcms.xyz"
},
"homepage": "https://astro-ghostcms.xyz/",
"exports": {
".": "./index.ts",
"./api": "./src/api/index.ts",
"./index.astro": "./src/theme/routes/index.astro",
"./404.astro": "./src/theme/routes/404.astro",
"./[slug].astro": "./src/theme/routes/[slug].astro",
"./tags.astro": "./src/theme/routes/tags.astro",
"./authors.astro": "./src/theme/routes/authors.astro",
"./tag/[slug].astro": "./src/theme/routes/tag/[slug].astro",
"./author/[slug].astro": "./src/theme/routes/author/[slug].astro",
"./archives/[...page].astro": "./src/theme/routes/archives/[...page].astro",
"./rss.xml.js": "./src/theme/routes/rss.xml.js"
},
"main": "index.ts",
"types": "src/api/tryghost-content-api.d.ts",
"files": [
"src",
"index.ts"
],
"keywords": [
"astro-component",
"astro-integration",
"withastro",
"astro",
"blog",
"content",
"integration",
"ghost",
"ghostcms",
"ghostcms-theme",
"ghost-theme",
"astro-theme"
],
"scripts": {
"dev": "astro dev",
"build": "astro build",
"typecheck": "astro check && tsc --noEmit",
"preview": "astro preview",
"format": "prettier --write .",
"lint": "eslint --cache --cache-location ./node_modules/.cache/eslint ."
},
"dependencies": {
"@astrojs/check": "^0.3.4",
"@astrojs/rss": "^4.0.2",
"@astrojs/sitemap": "^3.0.5",
"@typescript-eslint/eslint-plugin": "^6.19.0",
"@typescript-eslint/parser": "^6.19.0",
"astro": "^4.2.1",
"astro-font": "^0.0.72",
"astro-robots-txt": "^1.0.0",
"axios": "^1.6.5",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-astro": "^0.29.1",
"prettier": "^3.2.4",
"prettier-plugin-astro": "^0.12.3",
"sass": "^1.70.0",
"tiny-invariant": "^1.3.1",
"typescript": "^5.3.3",
"vite": "^4.5.2",
"zod-validation-error": "^3.0.0"
}
}

View File

@ -1,142 +0,0 @@
# @matthiesenxyz/astro-ghostcms-brutalbyelian
## 0.0.18
### Patch Changes
- f82035b: Bump dependencies:
- astro-integration-kit from to
- @unocss/astro from to
- @unocss/reset from to
- astro-font from to
- unocss from to
- sass from to
- @matthiesenxyz/astro-gists from to
- vite-tsconfig-paths from to
- astro from to
- Updated dependencies [f82035b]
- @matthiesenxyz/astro-ghostcms@3.3.5
## 0.0.17
### Patch Changes
- f097c6a: Adds a toggleswitch to allow users to disable astro-remote usage for rendering ghost-content
- Updated dependencies [f097c6a]
- @matthiesenxyz/astro-ghostcms@3.3.4
## 0.0.16
### Patch Changes
- b0218e1: fix:
- Removed CodeSlot Component that sometimes would break with some <pre> components
- Will be adding at a latter time a custom component to replace this, but at this time this is now fixed.
## 0.0.15
### Patch Changes
- 4c1002a: fix getAllTags bug for themes and bump other packages deps
- Updated dependencies [4c1002a]
- @matthiesenxyz/astro-ghostcms@3.3.2
## 0.0.14
### Patch Changes
- 746fcc5: Fix html rendering to allow custom components
## 0.0.13
### Patch Changes
- 2724119: Migrate from `astro-ghostcms-rendercontent` to `astro-remote` for internal processing of GhostCMS HTML. no user changes required.
## 0.0.12
### Patch Changes
- f921005: Bump dependencies:
- vite from to
- @eliancodes/brutal-ui from to
- typescript from to
- ultrahtml from to
- @fontsource-variable/inter from to
- astro-seo from to
- astro from to
- sass from to
- @astrojs/starlight from to
- sharp from to
- Updated dependencies [f921005]
- Updated dependencies [f921005]
- @matthiesenxyz/astro-ghostcms@3.3.1
- @matthiesenxyz/astro-ghostcms-rendercontent@0.0.8
## 0.0.11
### Patch Changes
- Updated dependencies [1f850db]
- Updated dependencies [1f850db]
- @matthiesenxyz/astro-ghostcms@3.2.9
- @matthiesenxyz/astro-ghostcms-rendercontent@0.0.7
## 0.0.10
### Patch Changes
- 3a5aea9: Updated Tests and Linted packages
- Updated dependencies [3a5aea9]
- @matthiesenxyz/astro-ghostcms-rendercontent@0.0.6
- @matthiesenxyz/astro-ghostcms@3.2.7
## 0.0.9
### Patch Changes
- e235ad0: Bump dependencies:
- @astrojs/rss from to
- vite from to
- unocss from to
- astro-font from to
- Updated dependencies [e235ad0]
- @matthiesenxyz/astro-ghostcms@3.2.6
## 0.0.8
### Patch Changes
- 0f3d47f: Bump @unocss/reset from 0.57.7 to 0.58.5
- 12be739: Depencency updates
- a358b7d: Bump @unocss/astro from 0.57.7 to 0.58.5
- Updated dependencies [455ad3f]
- Updated dependencies [12be739]
- Updated dependencies [455ad3f]
- @matthiesenxyz/astro-ghostcms-rendercontent@0.0.5
- @matthiesenxyz/astro-ghostcms@3.2.5
## 0.0.7
### Patch Changes
- Fix License File
- Updated dependencies
- @matthiesenxyz/astro-ghostcms-rendercontent@0.0.4
- @matthiesenxyz/astro-ghostcms@3.2.4
## 0.0.6
### Patch Changes
- Initialization of changeset cli
- Updated dependencies
- @matthiesenxyz/astro-ghostcms@3.2.3
- @matthiesenxyz/astro-ghostcms-rendercontent@0.0.3

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2024 MatthiesenXYZ - Astro-GhostCMS & Elian Van Cutsem
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,25 +0,0 @@
import {
definePreset,
presetIcons,
presetTypography,
presetWind,
} from "unocss";
export default definePreset(() => {
return {
name: "brutalTheme",
presets: [
presetWind(),
presetIcons({
collections: {
//@ts-expect-error
logos: () =>
import("@iconify-json/logos/icons.json").then((i) => i.default),
uil: () =>
import("@iconify-json/uil/icons.json").then((l) => l.default),
},
}),
presetTypography(),
],
};
});

View File

@ -1,68 +0,0 @@
{
"name": "@matthiesenxyz/astro-ghostcms-brutalbyelian",
"description": "ElianCodes Brutal theme modified to work with Astro-GhostCMS",
"version": "0.0.18",
"homepage": "https://astro-ghostcms.xyz/",
"type": "module",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"sideEffects": false,
"author": {
"email": "adam@matthiesen.xyz",
"name": "Adam Matthiesen - MatthiesenXYZ",
"url": "https://matthiesen.xyz"
},
"keywords": [
"astro-ghostcms"
],
"repository": {
"type": "git",
"url": "git+https://github.com/MatthiesenXYZ/astro-ghostcms.git"
},
"bugs": {
"url": "https://github.com/MatthiesenXYZ/astro-ghostcms/issues",
"email": "issues@astro-ghostcms.xyz"
},
"main": "./brutalunocss-preset.ts",
"files": [
"src",
"brutalunocss-preset.ts"
],
"exports": {
".": "./brutalunocss-preset.ts",
"./index.astro": "./src/routes/index.astro",
"./[slug].astro": "./src/routes/[slug].astro",
"./tags.astro": "./src/routes/tags.astro",
"./authors.astro": "./src/routes/authors.astro",
"./tag/[slug].astro": "./src/routes/tag/[slug].astro",
"./author/[slug].astro": "./src/routes/author/[slug].astro",
"./archives/[...page].astro": "./src/routes/archives/[...page].astro"
},
"scripts": {},
"peerDependencies": {
"@matthiesenxyz/astro-ghostcms": ">=3.3.5",
"astro": ">=4.4.1"
},
"devDependencies": {
"@typescript-eslint/parser": "^7.2.0",
"eslint": "^8.57.0",
"eslint-plugin-astro": "^0.31.4",
"eslint-plugin-jsx-a11y": "^6.8.0",
"prettier-plugin-astro": "^0.13.0",
"prettier": "^3.2.5"
},
"dependencies": {
"@eliancodes/brutal-ui": "^0.2.6",
"@iconify-json/logos": "^1.1.41",
"@iconify-json/uil": "^1.1.8",
"@unocss/astro": "^0.58.6",
"@unocss/reset": "^0.58.6",
"astro-font": "^0.0.78",
"astro-remote": "0.3.2",
"typescript": "^5.4.2",
"ultrahtml": "^1.5.3",
"unocss": "^0.58.6"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@ -1,23 +0,0 @@
---
import AuthorList from './AuthorList.astro';
import { Card } from '@eliancodes/brutal-ui';
import type { Settings, Post, Author } from "@matthiesenxyz/astro-ghostcms/api";
export type Props = {
authors: Author[];
settings: Settings;
isHome?: boolean;
};
const { authors, settings } = Astro.props as Props;
---
<section class='mt-8'>
<Card>
<div class='flex justify-between items-start'>
<h2 class='text-2xl md:text-4xl lg:text-6xl mb-8 dm-serif'>
Our Authors
</h2>
</div>
<AuthorList authors={authors} settings={settings}/>
</Card>
</section>

View File

@ -1,95 +0,0 @@
---
export type Props = {
name: string,
image?: string | null,
count: number,
bio: string | null,
location: string | null,
website: string | null,
twitter: string | null,
facebook: string | null
};
const {
name, image, bio, location, website, twitter, facebook, count
} = Astro.props as Props;
---
<header class="author-card">
{ image ? <img src={image} alt="Author Image" class="author-image"> : (
<span class="author-image">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<path
d="M3.513 18.998C4.749 15.504 8.082 13 12 13s7.251 2.504 8.487 5.998C18.47 21.442 15.417 23 12 23s-6.47-1.558-8.487-4.002zM12 12c2.21 0 4-2.79 4-5s-1.79-4-4-4-4 1.79-4 4 1.79 5 4 5z"
fill="#FFF"
/>
</g>
</svg>
</span>
)}
<div class="author-info">
<div class="author-name text-ctp-teal">{name}</div>
<div class="author-bio text-ctp-blue">
{bio ? bio : count > 0? count + " Posts" : "No Posts"}
</div>
{location && (
<div class="author-location text-ctp-sapphire">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pin-map-fill text-ctp-flamingo inline" viewBox="0 0 16 16"> <path fill-rule="evenodd" d="M3.1 11.2a.5.5 0 0 1 .4-.2H6a.5.5 0 0 1 0 1H3.75L1.5 15h13l-2.25-3H10a.5.5 0 0 1 0-1h2.5a.5.5 0 0 1 .4.2l3 4a.5.5 0 0 1-.4.8H.5a.5.5 0 0 1-.4-.8z"/> <path fill-rule="evenodd" d="M4 4a4 4 0 1 1 4.5 3.969V13.5a.5.5 0 0 1-1 0V7.97A4 4 0 0 1 4 3.999z"/> </svg> {location}
</div>
)}
<div class="author-links">
{website && (<a href={website} target="_blank" rel="noopener">Website</a>)}
{twitter && (<a href={twitter} target="_blank" rel="noopener">Twitter</a>)}
{facebook && (<a href={facebook} target="_blank" rel="noopener">Facebook</a>)}
</div>
</div>
</header>
<style>
.author-card {
display: flex;
margin-top: 8vmin;
margin-bottom: 6vmin;
overflow: hidden;
}
.author-image {
width: 180px;
height: 180px;
object-fit: cover;
border-radius: 3px;
}
.author-info {
flex: 1;
padding: 20px;
text-align: left;
}
.author-name {
font-size: 1.5em;
font-weight: bold;
margin-bottom: 10px;
}
.author-bio {
line-height: 1.4;
}
.author-location {
margin-top: 10px;
}
.author-links {
margin-top: 10px;
}
.author-links a {
text-decoration: none;
color: #FFFFFF;
margin-right: 10px;
}
</style>

View File

@ -1,21 +0,0 @@
---
import AuthorSummaryCard from './AuthorSummaryCard.astro';
import type { Settings, Post, Author } from "@matthiesenxyz/astro-ghostcms/api";
export type Props = {
authors: Author[];
settings: Settings;
};
const { authors, settings } = Astro.props as Props;
---
<ul class='grid md:grid-cols-2 lg:grid-cols-3 gap-8'>
{
authors.map((author: Author) => {
return (
<li>
<AuthorSummaryCard author={author}, settings={settings} />
</li>
);
})
}
</ul>

View File

@ -1,38 +0,0 @@
---
import SummaryCard from './AuthorSummaryCardHeader.astro';
import type { Settings, Author } from "@matthiesenxyz/astro-ghostcms/api";
import { getGhostImgPath, formatDate } from "../../utils";
import { Pill } from '@eliancodes/brutal-ui';
import Button from "../generic/button.astro"
interface Props {
author: Author;
settings: Settings;
};
const { author, settings } = Astro.props;
---
<SummaryCard
title={author.name}
imgAlt={author.name}
imgSrc={getGhostImgPath(settings.url, author.profile_image || "", 100)}
description={author.bio?author.bio:""}
>
<div class='flex justify-end my-4'>
<Button href={`/author/${author.slug}/`}>More Info &rarr;</Button>
</div>
<div class='hidden sm:inline-block'>
<div class='flex justify-between items-center'>
<ul class='flex gap-4 mt-2'>
{author.count && author.count.posts && (
<div class="sanchez">
<Pill>{author.count.posts > 0 ? `${author.count.posts} posts` : "No posts"}</Pill>
</div>
)}
</ul>
</div>
</div>
</SummaryCard>

View File

@ -1,28 +0,0 @@
---
import { Card } from '@eliancodes/brutal-ui';
import { Image } from 'astro:assets';
interface Props {
title: string;
imgSrc: string | null;
imgAlt: string;
description: string;
}
const { title, imgAlt, imgSrc, description } = Astro.props;
---
<Card color='white'>
<div class='rounded-lg'>
{imgSrc && (<Image
src={imgSrc}
alt={imgAlt}
width={100}
height={100}
class='rounded h-54 w-56'
/>)}
</div>
<h3 class='poppins text-lg font-bold md:text-xl'>{title}</h3>
<p class='poppins line-clamp-4'>{description}</p>
<slot />
</Card>

View File

@ -1,17 +0,0 @@
---
interface Props {
content: any;
}
const { content } = Astro.props;
---
<article class='prose-slate w-sm md:w-prose md:prose poppins'>
<a href='/blog/' title='Back to blog'>&larr; Back to blog</a>
<p class='text-slate text-sm md:text-base'>
Published on {content.pubDate} by {content.author}
</p>
<slot />
<p class='text-slate'>Written by {content.author}</p>
<a href='/blog/' title='Back to blog'>&larr; Back to blog</a>
</article>

View File

@ -1,21 +0,0 @@
---
import BlogSummaryCard from './BlogSummaryCard.astro';
import type { Settings, Post } from "@matthiesenxyz/astro-ghostcms/api";
export type Props = {
posts: Post[];
settings: Settings;
};
const { posts, settings } = Astro.props as Props;
---
<ul class='grid md:grid-cols-2 lg:grid-cols-3 gap-8'>
{
posts.map((post: Post) => {
return (
<li>
<BlogSummaryCard post={post}, settings={settings} />
</li>
);
})
}
</ul>

View File

@ -1,44 +0,0 @@
---
import type { Settings, Post } from "@matthiesenxyz/astro-ghostcms/api";
import { formatDate } from "../../utils";
import FeatureImage from "./FeatureImage.astro";
export type Props = {
post: Post;
settings: Settings;
};
const { post, settings } = Astro.props as Props;
---
<header class="article-header gh-canvas">
<div class="flex justify-between">
<section class="flex flex-grow align-middle">
<div class="text-ctp-overlay2">
{ post.primary_author && (
<h4 class="text-ctp-teal">Author:
<a href={`/author/${post.primary_author.slug}`}>{post.primary_author.name}</a>
</h4>
)}
<div class="text-ctp-overlay2">
<time class="text-ctp-sapphire" datetime={formatDate(post.created_at)}
>{formatDate(post.created_at)}
</time>
<span class="text-ctp-peach"
><span class="text-ctp-overlay2">&bull;</span>
{post.reading_time} min read
</span>
</div>
</div>
</section>
</div>
<center><h1 class="text-5xl righteous pb-5">{post.title}</h1></center>
{post.feature_image && (
<FeatureImage
image={post.feature_image}
alt={post.feature_image_alt ? post.feature_image_alt : post.title}
caption={post.feature_image_caption || "" }
settings={settings}
transitionName={`img-${post.title}`}
/>
)}
</header>

View File

@ -1,29 +0,0 @@
---
interface Props {
headings: Array<Object>;
}
const { headings } = Astro.props;
---
<aside>
<nav class='hidden lg:block sticky top-6'>
<ul>
{
headings.map((heading: any) => (
<li class='py-1'>
{[...Array(heading.depth - 1)].map((_, _i) => (
<span class='inline-block w-4' />
))}
<a
class='hover:text-stone transition-all duration-150 ease-in-out text-dark poppins'
href={`#${heading.slug}`}
>
{heading.text}
</a>
</li>
))
}
</ul>
</nav>
</aside>

View File

@ -1,46 +0,0 @@
---
import SummaryCard from '../generic/SummaryCard.astro';
import type { Settings, Post, Tag } from "@matthiesenxyz/astro-ghostcms/api";
import { getGhostImgPath, formatDate } from "../../utils";
import { Pill } from '@eliancodes/brutal-ui';
import Button from "../generic/button.astro"
interface Props {
post: Post;
settings: Settings;
};
const { post, settings } = Astro.props;
---
<SummaryCard
title={post.title}
imgAlt={post.feature_image_alt
? post.feature_image_alt : post.feature_image_caption
? post.feature_image_caption : post.title}
imgSrc={getGhostImgPath(settings.url, post.feature_image || "", 800)}
description={post.excerpt}
>
<div class='flex justify-end my-4'>
<Button href={`/${post.slug}/`}>Read post &rarr;</Button>
</div>
<div class='hidden sm:inline-block'>
<p class='poppins mt-2'>tags:</p>
<div class='flex justify-between items-center'>
<ul class='flex gap-4 mt-2'>
{
post.tags && post.tags.map((tag) => {
return (
<li>
<a class="sanchez" href={`/tag/${tag.slug}/`}>
<Pill>{tag.name}</Pill>
</a>
</li>
);
})
}
</ul>
</div>
</div>
</SummaryCard>

View File

@ -1,34 +0,0 @@
---
import { getGhostImgPath } from "../../utils";
import type { Settings } from "@matthiesenxyz/astro-ghostcms/api";
import { Markup } from 'astro-remote';
import config from "virtual:@matthiesenxyz/astro-ghostcms/config";
const useRemote = config.ThemeProvider.astroRemote.enable;
export type Props = {
image: string;
alt?: string;
caption?: string;
settings: Settings;
transitionName?: string;
};
const { image, alt, caption = "", settings, transitionName } = Astro.props as Props;
---
<figure class="article-image">
<img
srcset={`
${getGhostImgPath(settings.url, image, 300)} 300w,
${getGhostImgPath(settings.url, image, 600)} 600w,
`}
sizes="(min-width: 300px) 600px, 92vw"
src={getGhostImgPath(settings.url, image, 2000)}
alt={alt}
transition:name={transitionName}
/>
{caption && (
<figcaption class="text-ctp-overlay2">
{useRemote ? <Markup content={caption} /> : <Fragment set:html={caption} />}
</figcaption>)}
</figure>

View File

@ -1,16 +0,0 @@
---
---
<section class='flex flex-col gap-8 justify-between'>
<p class='text-9xl font-bold dm-serif'>404</p>
<h2 class='text-4xl outfit'>Page Not Found</h2>
<p class='text-xl sm:text-3xl sanchez'>
Sorry, we couldn't find the page you were looking for.
</p>
<a
href='/'
title='Go back home'
class='px-4 py-2 border-2 border-black hover:bg-red transition-colors duration-150 ease-in-out w-48 text-center poppins'
>&larr; Go Home</a
>
</section>

View File

@ -1,26 +0,0 @@
---
import { getGhostImgPath } from "../../utils";
import type { Settings } from "@matthiesenxyz/astro-ghostcms/api";
export type Props = {
image: string;
alt?: string;
caption?: string;
settings: Settings;
transitionName?: string;
};
const { image, alt, caption = "", settings, transitionName } = Astro.props as Props;
---
<figure class="article-image">
<img
srcset={`
${getGhostImgPath(settings.url, image, 300)} 300w,
${getGhostImgPath(settings.url, image, 600)} 600w,
`}
sizes="(min-width: 300px) 600px, 92vw"
src={getGhostImgPath(settings.url, image, 2000)}
alt={alt}
transition:name={transitionName}
/>
{caption && <figcaption class="text-ctp-overlay2"><Fragment set:html={caption}></figcaption>}
</figure>

View File

@ -1,50 +0,0 @@
---
import { AstroFont } from "astro-font";
---
<AstroFont
config={[
{
name: "Outfit",
googleFontsURL: 'https://fonts.googleapis.com/css2?family=Outfit&display=swap',
display: "swap",
selector: ".outfit",
fallback: "sans-serif",
src: [],
},
{
display: "swap",
name: "Poppins",
googleFontsURL: 'https://fonts.googleapis.com/css2?family=Poppins&display=swap',
selector: ".poppins",
fallback: "sans-serif",
preload: true,
src: [],
},
{
display: "swap",
name: "Righteous",
googleFontsURL: 'https://fonts.googleapis.com/css2?family=Righteous&display=swap',
fallback: "sans-serif",
selector: ".righteous",
preload: true,
src: [],
},
{
display: "swap",
name: "Sanchez",
googleFontsURL: 'https://fonts.googleapis.com/css2?family=Sanchez&display=swap',
fallback: "serif",
selector: ".sanchez",
preload: true,
src: [],
},
{
display: "swap",
fallback: "serif",
selector: ".dm-serif",
name: "DM Serif Text",
googleFontsURL: 'https://fonts.googleapis.com/css2?family=DM+Serif+Text&display=swap',
src: [],
},
]}
/>

View File

@ -1,23 +0,0 @@
---
import BlogList from '../blog/BlogList.astro';
import { Card } from '@eliancodes/brutal-ui';
import type { Settings, Post } from "@matthiesenxyz/astro-ghostcms/api";
export type Props = {
posts: Post[];
settings: Settings;
isHome?: boolean;
};
const { posts, settings } = Astro.props as Props;
---
<section class='mt-8'>
<Card>
<div class='flex justify-between items-start'>
<h2 class='text-2xl md:text-4xl lg:text-6xl mb-8 dm-serif'>
Recent Blogposts
</h2>
</div>
<BlogList posts={posts} settings={settings}/>
</Card>
</section>

View File

@ -1,18 +0,0 @@
---
import { Card } from '@eliancodes/brutal-ui';
interface Props {
title: string;
description: string;
}
const { title, description } = Astro.props;
---
<Card color='white'>
<center>
<h3 class='poppins text-lg md:text-xl'>{title}</h3>
<p class='poppins line-clamp-4'>{description}</p>
<slot />
</center>
</Card>

View File

@ -1,28 +0,0 @@
---
import { Card } from '@eliancodes/brutal-ui';
import { Image } from 'astro:assets';
interface Props {
title: string;
imgSrc: string | null;
imgAlt: string;
description: string;
}
const { title, imgAlt, imgSrc, description } = Astro.props;
---
<Card color='white'>
<h3 class='poppins text-lg md:text-xl'>{title}</h3>
<div class='rounded-lg border-3 border-black my-4 h-56'>
{imgSrc && (<Image
src={imgSrc}
alt={imgAlt}
width={800}
height={400}
class='rounded h-full w-full object-cover'
/>)}
</div>
<p class='poppins line-clamp-4'>{description}</p>
<slot />
</Card>

View File

@ -1,22 +0,0 @@
---
import SummaryCard from './SummaryCard-tag.astro';
import type { Settings, Tag } from "@matthiesenxyz/astro-ghostcms/api";
import Button from "./button.astro"
interface Props {
tag: Tag;
settings: Settings;
};
const { tag } = Astro.props;
---
<SummaryCard
title={tag.name}
description={tag.description?tag.description:""}
>
<div class='flex justify-end my-4'>
<Button href={`/${tag.slug}/`}>See Posts &rarr;</Button>
</div>
</SummaryCard>

View File

@ -1,47 +0,0 @@
---
interface Props {
href: string;
target?: '_blank' | '_self';
color?: string | undefined;
}
import colors from './colors.json';
if (Astro.props.target === undefined) {
Astro.props.target = '_self';
}
if (Astro.props.color === undefined) {
Astro.props.color =
colors[Math.floor(Math.random() * colors.length)];
}
const { href, target, color } = Astro.props;
---
<style define:vars={{ color: color }}>
a.brutal-btn {
filter: drop-shadow(5px 5px 0 rgb(0 0 0 / 1));
background-color: white;
display: inline-block;
padding: 0.5rem 1rem;
border: 2px solid black;
transition: all;
transition-duration: 0.5s;
animation: ease-in-out;
font-family: 'Sanchez', serif;
}
a.brutal-btn:hover {
filter: drop-shadow(3px 3px 0 rgb(0 0 0 / 1));
background-color: var(--color);
}
</style>
<a
href={href}
target={target}
class='brutal-btn'
data-astro-reload
>
<slot />
</a>

View File

@ -1,18 +0,0 @@
[
"#c084fc",
"#f472b6",
"#fb7185",
"#e879f9",
"#a78bfa",
"#818cf8",
"#60a5fa",
"#38bdf8",
"#22d3ee",
"#2dd4bf",
"#34d399",
"#4ade80",
"#a3e635",
"#facc15",
"#fb923c",
"#f87171"
]

View File

@ -1,5 +0,0 @@
---
---
<h1 class="righteous text-4xl">
<slot />
</h1>

View File

@ -1,5 +0,0 @@
---
---
<h2 class="righteous text-3xl">
<slot />
</h2>

View File

@ -1,5 +0,0 @@
---
---
<h3 class="righteous text-2xl">
<slot />
</h3>

View File

@ -1,5 +0,0 @@
---
---
<h4 class="righteous text-1xl">
<slot />
</h4>

View File

@ -1,5 +0,0 @@
---
---
<h5 class="righteous text-xl">
<slot />
</h5>

View File

@ -1,5 +0,0 @@
---
---
<h6 class="righteous text-lg">
<slot />
</h6>

View File

@ -1,21 +0,0 @@
---
---
<p class="my-5 text-base"><slot /></p>
<style is:inline>
#ghost p a {
color: rgb(0, 123, 247);
}
#ghost ul li a {
color: rgb(0, 123, 247);
}
#ghost ul li {
padding-top: 0.5rem;
margin-left: 2rem;
list-style: circle;
}
#ghost ul {
margin-top: 1rem;
margin-bottom: 1rem;
}
</style>

View File

@ -1,9 +0,0 @@
---
import { Card } from "@eliancodes/brutal-ui";
---
<div class="my-10">
<Card>
<slot />
</Card>
</div>

View File

@ -1,8 +0,0 @@
export { default as H1 } from "./H1.astro";
export { default as H2 } from "./H2.astro";
export { default as H3 } from "./H3.astro";
export { default as H4 } from "./H4.astro";
export { default as H5 } from "./H5.astro";
export { default as H6 } from "./H6.astro";
export { default as Paragraph } from "./Paragraph.astro";
export { default as astrocard } from "./astrocard.astro";

View File

@ -1,33 +0,0 @@
---
import { facebook, getSettings, invariant, twitter } from "@matthiesenxyz/astro-ghostcms/api";
const settings = await getSettings();
invariant(settings, 'Settings not found');
---
<section class='md:hidden'>
<h2 class='hidden'>Socials section</h2>
<ul class='flex justify-between'>
{ settings.facebook && (
<li class='bg-white px-4 py-2 text-green border-black border-2 rounded card-shadow'>
<a href={facebook(settings.facebook)} target='_blank' title={`Go to Facebook`}>
<div class:list={['i-uil-facebook', 'p-6']} />
</a>
</li>
)
}
{ settings.twitter && (
<li class='bg-white px-4 py-2 text-green border-black border-2 rounded card-shadow'>
<a href={twitter(settings.twitter)} target='_blank' title={`Go to Twitter "X"`}>
<div class:list={['i-uil-twitter', 'p-6']} />
</a>
</li>
)
}
<li class='bg-white px-4 py-2 text-green border-black border-2 rounded card-shadow'>
<a href='/rss.xml' target='_blank' title={`See our RSS Feed`}>
<div class:list={['i-uil-rss', 'p-6']} />
</a>
</li>
</ul>
</section>

View File

@ -1,85 +0,0 @@
---
import { getSettings, invariant } from "@matthiesenxyz/astro-ghostcms/api";
const settings = await getSettings();
invariant(settings, 'Settings not found');
export interface Props {
backToTop?: boolean;
}
const { backToTop = false } = Astro.props;
---
{
backToTop && (
<button
class:list={[
backToTop ? `backToTop` : null,
'transition-300 z-50 opacity-0 fixed flex bottom-[10px] right-[30px] w-10 h-10 bg-white border border-black card-shadow',
]}
>
<svg
xmlns='http://www.w3.org/2000/svg'
fill='none'
viewBox='0 0 24 24'
height='100%'
width='100%'
stroke-width='1.5'
stroke='currentColor'
>
<path
stroke-linecap='round'
stroke-linejoin='round'
d='m4.5 15.75 7.5-7.5 7.5 7.5'
/>
</svg>
</button>
)
}
<footer class='bg-black text-white p-6'>
<h2 class='hidden'>Footer</h2>
<p class="text-center text-sm text-slate-500">
Copyright © {new Date().getFullYear()} - {settings.title}. All rights reserved.
</p>
<p class='outfit opacity-50%'>
Brutal theme for Astro - by <a
href='https://www.elian.codes/'
target='_blank'
class='text-blue'>ElianCodes</a
>
<p class='outfit opacity-50%'>
Powered By Ghost
</p>
</p>
</footer>
<style>
.backToTop.active {
opacity: 1;
}
</style>
<script>
document.addEventListener('astro:page-load', () => {
const backToTop = document.querySelector('.backToTop');
const toggleBackToTopButton = () => {
if (window.scrollY > 250) {
backToTop?.classList.add('active');
} else {
backToTop?.classList.remove('active');
}
};
backToTop?.addEventListener('click', () => {
window.scrollTo({
top: 0,
behavior: 'smooth',
});
});
window.addEventListener('scroll', toggleBackToTopButton);
});
</script>

View File

@ -1,54 +0,0 @@
---
import LocalFont from '../generic/LocalFont.astro';
import { ViewTransitions } from 'astro:transitions';
import { getSettings, invariant } from "@matthiesenxyz/astro-ghostcms/api";
import { getOgImagePath } from "@matthiesenxyz/astro-ghostcms/satoriOG";
const settings = await getSettings();
invariant(settings, 'Settings not found');
const Ghosttitle = settings.title;
const favicon = await settings.icon;
interface Props {
title: string;
description: string;
}
const ogI = new URL(getOgImagePath(Astro.url.pathname), Astro.url.origin).href;
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
const { title, description } = Astro.props;
---
<head>
<LocalFont />
<meta charset='utf-8' />
<meta name='viewport' content='width=device-width, initial-scale=1' />
<meta name='generator' content={Astro.generator} />
<meta name='title' content={`${Ghosttitle} | ${title}`} />
<meta name='description' content={description} />
<meta property='og:type' content='website' />
<meta property='og:url' content={canonicalURL} />
<meta property='og:title' content={title} />
<meta property='og:description' content={description} />
<meta property='og:image' content={ogI} />
<meta property='twitter:card' content='summary_large_image' />
<meta property='twitter:url' content={canonicalURL} />
<meta property='twitter:title' content={title} />
<meta property='twitter:description' content={description} />
<meta property='twitter:image' content={ogI} />
<link rel='canonical' href={canonicalURL} />
<link rel='icon' type='image/svg' href={favicon} />
<title>{Ghosttitle} | {title}</title>
<ViewTransitions />
<slot />
</head>

View File

@ -1,90 +0,0 @@
---
import { facebook, getSettings, invariant, twitter } from "@matthiesenxyz/astro-ghostcms/api";
const settings = await getSettings();
invariant(settings, 'Settings not found');
interface Props {
pageTitle?: string;
}
const { pageTitle } = Astro.props;
---
<header class='border-b-4 border-black flex justify-between p-6 items-center'>
{pageTitle && <h1 class='hidden'>{pageTitle}</h1>}
<a href='/' title='Back to Home'>
<p class='righteous md:text-4xl'>{settings.icon && <img src={settings.icon} width="48" class="inline">}{settings.title}</p>
</a>
<nav class='hidden md:inline-block'>
<h2 class='hidden'>Navigation</h2>
<ul class='flex gap-8 poppins'>
{
settings.navigation.map(({label, url}) => (
<li>
<a
class='font-medium hover:text-green hover:underline transition-all duration-150 ease-in-out'
href={url}
title={`Go to ${label}`}
>
{label}
</a>
</li>
))
}
{ settings.facebook && (
<li>
<a
href={facebook(settings.facebook)}
class='hover:text-green hover:underline transition-all duration-150 ease-in-out'
target='_blank'
title={`See @${settings.facebook} on Facebook`}
>
<div class:list={['i-uil-facebook', 'w-6 h-6']} />
</a>
</li>
)
}
{ settings.twitter && (
<li>
<a
href={twitter(settings.twitter)}
class='hover:text-green hover:underline transition-all duration-150 ease-in-out'
target='_blank'
title={`See @${settings.twitter} on Twitter "X"`}
>
<div class:list={['i-uil-twitter', 'w-6 h-6']} />
</a>
</li>
)
}
<li>
<a
href='/rss.xml'
class='hover:text-green hover:underline transition-all duration-150 ease-in-out'
target='_blank'
title={`See our RSS Feed`}
>
<div class:list={['i-uil-rss', 'w-6 h-6']} />
</a>
</li>
</ul>
</nav>
<nav class='md:hidden flex'>
<h2 class='hidden'>Mobile Navigation</h2>
<ul>
{
settings.navigation.map(({label, url}) => (
<li>
<a
class='font-medium hover:text-green hover:underline transition-all duration-150 ease-in-out'
href={url}
title={`Go to ${label}`}
>
{label}
</a>
</li>
))
}
</ul>
</nav>
</header>

View File

@ -1,2 +0,0 @@
/// <reference path="../.astro/types.d.ts" />
/// <reference types="astro/client" />

View File

@ -1,25 +0,0 @@
---
import BaseNavigation from '../components/layout/BaseNavigation.astro';
import BaseFooter from '../components/layout/BaseFooter.astro';
import BaseHead from '../components/layout/BaseHead.astro';
import '../styles/global.css';
interface Props {
title: string;
description: string;
classList?: string;
pageTitle?: string;
}
const { title, description, classList, pageTitle } = Astro.props;
---
<html lang='en' class='h-full'>
<BaseHead title={title} description={description} />
<body class:list={[classList]}>
<BaseNavigation {pageTitle} />
<slot />
<BaseFooter />
</body>
</html>

View File

@ -1,59 +0,0 @@
---
import BlogPost from "../layouts/Default.astro"
import { getAllPosts, getAllPages, getSettings, invariant } from "@matthiesenxyz/astro-ghostcms/api";
import type { InferGetStaticPropsType } from "astro";
import RecentBlogPosts from "../components/generic/RecentBlogPosts.astro";
import BlogPostHeader from "../components/blog/BlogPostHeader.astro";
import { Markup } from 'astro-remote';
import * as C from "../components/ghostrender";
import { Card } from "@eliancodes/brutal-ui";
import config from "virtual:@matthiesenxyz/astro-ghostcms/config";
const useRemote = config.ThemeProvider.astroRemote.enable;
export async function getStaticPaths() {
const [posts, pages, settings] = await Promise.all([getAllPosts(), await getAllPages(), await getSettings()]);
const allPosts = [...posts, ...pages];
return allPosts.map((post) => ({
params: { slug: post.slug },
props: { post, posts, settings },
}));
}
export type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const {post, posts, settings} = Astro.props as Props;
invariant(settings, "Settings are required");
---
<BlogPost title={post.title} description={post.excerpt}>
<article class='w-auto md:w-vmax p-10 poppins'>
<Card>
<BlogPostHeader post={post} settings={settings} />
</Card>
<div class="my-5"/>
<div id="ghost">
{useRemote ? <Markup
content={post.html}
sanitize={{
allowComponents: true,
allowElements: ['a', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'img', 'figure', 'figcaption', 'ul', 'ol', 'li', 'blockquote', 'pre', 'code', 'em', 'strong', 'del', 'hr', 'br', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'caption', 'div', 'span', 'script', 'astrocard'],
}}
components={{
h1: C.H1,
h2: C.H2,
h3: C.H3,
h4: C.H4,
h5: C.H5,
h6: C.H6,
p: C.Paragraph,
astrocard: C.astrocard,
}}
/> : <Fragment set:html={post.html} />}
</div>
</article>
<section class='p-6'>
<RecentBlogPosts posts={posts} settings={settings} />
</section>
</BlogPost>

View File

@ -1,36 +0,0 @@
---
import Layout from '../../layouts/Default.astro';
import BlogList from '../../components/blog/BlogList.astro';
import { getAllPosts, getSettings, invariant, type Post } from "@matthiesenxyz/astro-ghostcms/api";
import type { GetStaticPathsOptions, Page } from "astro";
import Paginator from "../../components/generic/Paginator.astro";
export async function getStaticPaths({ paginate }:GetStaticPathsOptions) {
const posts = await getAllPosts();
return paginate(posts, {
pageSize: 5,
});
}
export type Props = {
page: Page<Post>
};
const settings = await getSettings();
invariant(settings, "Settings are required");
const title = settings.title;
const description = settings.description;
const { page } = Astro.props as Props;
---
<Layout
title='Archives'
description=`${title} | On this page you can find a collection of blogposts`
pageTitle=`${title} | Archives`
>
<main class='bg-green p-6'>
<BlogList posts={page.data} settings={settings} />
<Paginator {page} />
</main>
</Layout>

View File

@ -1,55 +0,0 @@
---
import Layout from '../../layouts/Default.astro';
import AuthorDetailCard from '../../components/authors/AuthorDetailCard.astro';
import { Card } from '@eliancodes/brutal-ui';
import { getAllPosts, getAllAuthors, getSettings, invariant, type Post, type Author } from "@matthiesenxyz/astro-ghostcms/api";
import type { InferGetStaticParamsType, InferGetStaticPropsType } from 'astro';
import BlogList from "../../components/blog/BlogList.astro"
export async function getStaticPaths() {
const posts = await getAllPosts();
const { authors } = await getAllAuthors();
const settings = await getSettings();
return authors.map((author: Author) => {
const filteredPosts = posts.filter((post: Post) =>
post.authors?.map((author) => author.slug).includes(author.slug)
);
return {
params: { slug: author.slug },
props: {
posts: filteredPosts,
settings,
author,
},
};
});
}
export type Params = InferGetStaticParamsType<typeof getStaticPaths>;
export type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const { posts, settings, author } = Astro.props;
invariant(settings, "Settings are required");
const title = `Posts by author: ${author.name}`;
const description = `All of the articles we've posted and linked so far under the author: ${author.name}`;
---
<Layout
title={title}
pageTitle=`${settings.title} | ${title}`
description={description}
>
<main class='bg-pink p-6'>
<section id='about' class='col mt-4'>
<h2 class='hidden'>{title}</h2>
<div class='flex'>
<Card>
<AuthorDetailCard name={author.name} count={author.count?.posts || 0} image={author.profile_image} bio={author.bio} location={author.location} website={author.website} twitter={author.twitter} facebook={author.facebook}/>
</Card>
</div>
</section>
<br />
<BlogList posts={posts} settings={settings} />
</main>
</Layout>

View File

@ -1,21 +0,0 @@
---
import Layout from '../layouts/Default.astro';
import AuthorCollection from '../components/authors/AuthorCollection.astro';
import { getAllAuthors, getSettings, invariant } from "@matthiesenxyz/astro-ghostcms/api";
const { authors } = await getAllAuthors();
const settings = await getSettings();
invariant(settings, 'Settings not found');
const title = settings.title;
const description = settings.description;
---
<Layout
title='Authors'
pageTitle=`${title} | Authors`
description={description}
>
<main class='bg-pink p-6'>
<AuthorCollection authors={authors} settings={settings} />
</main>
</Layout>

View File

@ -1,39 +0,0 @@
---
import Layout from '../layouts/Default.astro';
import RecentBlogPosts from '../components/generic/RecentBlogPosts.astro';
import MobileSocials from '../components/home/MobileSocials.astro';
import { Card } from '@eliancodes/brutal-ui';
import { getPosts, getSettings, invariant } from "@matthiesenxyz/astro-ghostcms/api";
const { posts } = await getPosts();
const settings = await getSettings();
invariant(settings, 'Settings not found');
const title = settings.title;
const description = settings.description;
---
<Layout
title='Home'
pageTitle=`${title} | Home`
description={description}
>
<main class='bg-pink p-6'>
<MobileSocials />
<section id='about' class='col mt-4'>
<h2 class='hidden'>{title}</h2>
<div class='flex'>
<Card>
<div class='flex flex-col justify-between items-start gap-4'>
<p class='mt-4 outfit text-2xl md:text-5xl lg:text-7xl'>
{title}
</p>
<p class='mt-2 outfit text-xl md:text-3xl lg:text-5xl'>
{description}
</p>
</div>
</Card>
</div>
</section>
<RecentBlogPosts posts={posts} settings={settings} />
</main>
</Layout>

View File

@ -1,47 +0,0 @@
---
import type { InferGetStaticParamsType, InferGetStaticPropsType } from 'astro';
import Layout from '../../layouts/Default.astro';
import BlogList from '../../components/blog/BlogList.astro';
import { Button } from '@eliancodes/brutal-ui';
import { getAllPosts, getAllTags, getSettings, invariant } from "@matthiesenxyz/astro-ghostcms/api";
export async function getStaticPaths() {
const posts = await getAllPosts();
const tags = await getAllTags();
const settings = await getSettings();
return tags.map((tag) => {
const filteredPosts = posts.filter((post) =>
post.tags?.map((tag) => tag.slug).includes(tag.slug)
);
return {
params: { slug: tag.slug },
props: {
posts: filteredPosts,
settings,
tag,
},
};
});
}
export type Params = InferGetStaticParamsType<typeof getStaticPaths>;
export type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const { posts, settings, tag } = Astro.props;
invariant(settings, "Settings are required");
---
<Layout
title={`Blog: ${tag.name}`}
description={`${settings.title} | All posts tagged with ${tag}`}
pageTitle={`${settings.title} | Blogposts tagged with ${tag}`}
>
<main class='p-6 bg-purple grid gap-4'>
<div>
<Button href='/'>&larr; Back</Button>
</div>
<BlogList posts={posts} settings={settings} />
</main>
</Layout>

View File

@ -1,28 +0,0 @@
---
import Layout from '../layouts/Default.astro';
import { getAllTags, getSettings, invariant } from "@matthiesenxyz/astro-ghostcms/api";
import TagSummaryCard from '../components/generic/TagSummaryCard.astro';
const tags = await getAllTags();
const settings = await getSettings();
invariant(settings, 'Settings not found');
const title = settings.title;
const description = settings.description;
---
<Layout
title='Tags'
pageTitle=`${title} | Tags`
description={description}
>
<main class='bg-pink p-6'>
{
tags
.filter((tag) => tag.slug && !tag.slug.startsWith("hash-"))
.map((tag) => (
<TagSummaryCard tag={tag}, settings={settings} />
<br />
))
}
</main>
</Layout>

View File

@ -1,288 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
.card-shadow {
filter: drop-shadow(7px 7px 0 rgb(0 0 0 / 1));
transition: all;
transition-duration: 0.5s;
animation: ease-in-out;
}
.card-shadow:hover {
filter: drop-shadow(5px 5px 0 rgb(0 0 0 / 1));
}
:root
{ /* ---- ⚫️ Colors ⚪️ ---- */
/* Base Tokens */
--sys-color-white: #FFFFFF;
--sys-color-black: #000000;
/* Theme Tokens */
--primary: var(--sys-color-white);
--secondary: var(--sys-color-black);
}
html {
scroll-behavior: smooth;
}
::-webkit-scrollbar {
width: 22px;
background-color: var(--primary);
}
::-webkit-scrollbar-track {
background: linear-gradient(45deg, var(--secondary) 25%, transparent 25%, transparent 75%, var(--secondary) 75%, var(--secondary)), linear-gradient(45deg, var(--secondary) 25%, transparent 25%, transparent 75%, var(--secondary) 75%, var(--secondary));
background-color: var(--primary);
background-size: 4px 4px;
background-position: 0 0, 2px 2px;
width: 10px;
border-left: 3px solid var(--secondary);
}
::-webkit-scrollbar-thumb {
width: 20px;
box-sizing: content-box;
background-color: var(--primary);
border: 2px solid var(--secondary);
border-right: none;
}
::-webkit-scrollbar-button:horizontal:start:decrement,
::-webkit-scrollbar-button:horizontal:end:increment,
::-webkit-scrollbar-button:vertical:start:decrement,
::-webkit-scrollbar-button:vertical:end:increment {
display: block;
}
::-webkit-scrollbar-button:vertical:start {
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='22' height='24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23fff' stroke='%23000' d='M.5.5h21v22.375H.5z'/%3E%3Cpath fill='%23000' d='M1 23h20v-2H1zM1.375 12.375h5.5V11h-5.5zM6.875 17.875h6.875V16.5H6.875zM6.875 17.875v-5.5H5.5v5.5zM9.625 5.5V4.125H8.25V5.5zM11 4.125V2.75H9.625v1.375zM19.25 12.375V11h-1.375v1.375zM17.875 11V9.625H16.5V11zM16.5 9.625V8.25h-1.375v1.375zM15.125 8.25V6.875H13.75V8.25zM13.75 6.875V5.5h-1.375v1.375zM12.375 5.5V4.125H11V5.5zM8.25 6.875V5.5H6.875v1.375zM6.875 8.25V6.875H5.5V8.25zM5.5 9.625V8.25H4.125v1.375zM4.125 11V9.625H2.75V11z'/%3E%3Cpath fill='%23000' d='M2.75 12.375V11H1.375v1.375zM15.125 17.875v-5.5H13.75v5.5zM13.75 12.375h5.5V11h-5.5z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
height: 23.38px;
}
::-webkit-scrollbar-button:vertical:start:active {
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='22' height='24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23fff' stroke='%23000' d='M.5.5h21v22.38H.5z'/%3E%3Cpath fill='%23000' d='M1 23.005h20v-2H1zM1.375 12.378h5.5v-1.375h-5.5zM6.875 17.879h6.875V6.877H6.875zM6.875 17.879v-5.501H5.5v5.5zM9.625 5.501V4.126H8.25v1.375zM11 4.126V2.75H9.625v1.375zM19.25 12.378v-1.375h-1.375v1.375zM17.875 11.002V9.627H13.75v1.375zM16.5 9.627V8.252h-2.75v1.375zM15.125 8.252V6.877H13.75v1.375zM13.75 6.876V5.501h-1.375v1.375zM12.375 5.501V4.126h-2.75v1.375zM12.375 6.876V5.501h-5.5v1.375zM6.875 8.252V6.877H5.5v1.375zM6.875 9.627V8.252h-2.75v1.375zM6.875 11.002V9.627H2.75v1.375z'/%3E%3Cpath fill='%23000' d='M2.75 12.378v-1.375H1.375v1.375zM15.125 17.879v-5.501H13.75v5.5zM13.75 12.378h5.5v-1.375h-5.5z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
height: 23.38px;
}
::-webkit-scrollbar-button:vertical:end {
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='22' height='24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23fff' stroke='%23000' d='M.5 22.875h21V.5H.5z'/%3E%3Cpath fill='%23000' d='M1 .375h20v2H1zM1.375 11h5.5v1.375h-5.5zM6.875 5.5h6.875v1.375H6.875zM6.875 5.5V11H5.5V5.5zM9.625 17.875v1.375H8.25v-1.375zM11 19.25v1.375H9.625V19.25zM19.25 11v1.375h-1.375V11zM17.875 12.375v1.375H16.5v-1.375zM16.5 13.75v1.375h-1.375V13.75zM15.125 15.125V16.5H13.75v-1.375zM13.75 16.5v1.375h-1.375V16.5zM12.375 17.875v1.375H11v-1.375zM8.25 16.5v1.375H6.875V16.5zM6.875 15.125V16.5H5.5v-1.375zM5.5 13.75v1.375H4.125V13.75zM4.125 12.375v1.375H2.75v-1.375z'/%3E%3Cpath fill='%23000' d='M2.75 11v1.375H1.375V11zM15.125 5.5V11H13.75V5.5zM13.75 11h5.5v1.375h-5.5z'/%3E%3C/svg%3E");
height: 23.38px;
}
::-webkit-scrollbar-button:vertical:end:active {
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='22' height='24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23fff' stroke='%23000' d='M.5 22.88h21V.5H.5z'/%3E%3Cpath fill='%23000' d='M1 .375h20v2H1zM1.375 11.002h5.5v1.375h-5.5zM6.875 5.501h6.875v11.002H6.875zM6.875 5.501v5.501H5.5v-5.5zM9.625 17.879v1.375H8.25v-1.375zM11 19.254v1.375H9.625v-1.375zM19.25 11.002v1.375h-1.375v-1.375zM17.875 12.378v1.375H13.75v-1.375zM16.5 13.753v1.375h-2.75v-1.375zM15.125 15.128v1.375H13.75v-1.375zM13.75 16.503v1.375h-1.375v-1.375zM12.375 17.879v1.375h-2.75v-1.375zM12.375 16.503v1.375h-5.5v-1.375zM6.875 15.128v1.375H5.5v-1.375zM6.875 13.753v1.375h-2.75v-1.375zM6.875 12.378v1.375H2.75v-1.375z'/%3E%3Cpath fill='%23000' d='M2.75 11.002v1.375H1.375v-1.375zM15.125 5.501v5.501H13.75v-5.5zM13.75 11.002h5.5v1.375h-5.5z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
height: 23.38px;
}
::-webkit-scrollbar-button:horizontal:start {
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='24' height='23' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23fff' stroke='%23000' d='M.813 22.187v-21h22.375v21z'/%3E%3Cpath fill='%23000' d='M23.313 21.688v-20h-2v20zM12.688 21.313v-5.5h-1.376v5.5zM18.188 15.813V8.936h-1.375v6.876z'/%3E%3Cpath fill='%23000' d='M18.188 15.813h-5.5v1.374h5.5zM5.813 13.063H4.438v1.374h1.375zM4.438 11.688H3.063v1.374h1.374zM12.688 3.438h-1.376v1.374h1.376zM11.313 4.813H9.937v1.375h1.376zM9.938 6.188H8.562v1.375h1.376zM8.563 7.563H7.187v1.375h1.375zM7.188 8.938H5.813v1.374h1.375zM5.813 10.313H4.438v1.374h1.375zM7.188 14.438H5.813v1.374h1.375zM8.563 15.813H7.187v1.374h1.375zM9.938 17.188H8.562v1.375h1.376zM11.313 18.563H9.937v1.375h1.376zM12.688 19.938h-1.376v1.375h1.376zM18.188 7.563h-5.5v1.375h5.5z'/%3E%3Cpath fill='%23000' d='M12.688 8.938v-5.5h-1.376v5.5z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
height: 23.38px;
}
::-webkit-scrollbar-button:horizontal:start:active {
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='24' height='23' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23fff' stroke='%23000' d='M.81 22.19v-21h22.38v21z'/%3E%3Cpath fill='%23000' d='M23.315 21.69v-20h-2v20zM12.688 21.315v-5.5h-1.375v5.5zM18.189 15.815V8.94H7.187v6.875z'/%3E%3Cpath fill='%23000' d='M18.189 15.815h-5.501v1.375h5.5zM5.811 13.065H4.436v1.375h1.375zM4.436 11.69H3.06v1.375h1.375zM12.688 3.44h-1.375v1.375h1.375zM11.312 4.815H9.937V8.94h1.375zM9.937 6.19H8.562v2.75h1.375z'/%3E%3Cpath fill='%23000' d='M8.562 7.565H7.187V8.94h1.375zM7.186 8.94H5.811v1.375h1.375zM5.811 10.315H4.436v2.75h1.375zM7.186 10.315H5.811v5.5h1.375zM8.562 15.815H7.187v1.375h1.375z'/%3E%3Cpath fill='%23000' d='M9.937 15.815H8.562v2.75h1.375zM11.312 15.815H9.937v4.125h1.375zM12.688 19.94h-1.375v1.375h1.375zM18.189 7.565h-5.501V8.94h5.5z'/%3E%3Cpath fill='%23000' d='M12.688 8.94v-5.5h-1.375v5.5z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
height: 23.38px;
}
::-webkit-scrollbar-button:horizontal:end {
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='24' height='23' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23fff' stroke='%23000' d='M23.188 22.188v-21H.813v21z'/%3E%3Cpath fill='%23000' d='M.688 21.687v-20h2v20zM11.313 21.312v-5.5h1.375v5.5zM5.813 15.812V8.937h1.375v6.875zM5.813 15.813h5.5v1.375h-5.5zM18.188 13.063h1.375v1.375h-1.375zM19.563 11.688h1.375v1.375h-1.375zM11.313 3.438h1.375v1.375h-1.375zM12.688 4.813h1.375v1.375h-1.375zM14.063 6.188h1.375v1.375h-1.375zM15.438 7.563h1.375v1.375h-1.375zM16.813 8.938h1.375v1.375h-1.375zM18.188 10.313h1.375v1.375h-1.375zM16.813 14.438h1.375v1.375h-1.375zM15.438 15.813h1.375v1.375h-1.375zM14.063 17.188h1.375v1.375h-1.375zM12.688 18.563h1.375v1.375h-1.375z'/%3E%3Cpath fill='%23000' d='M11.313 19.938h1.375v1.375h-1.375zM5.813 7.563h5.5v1.375h-5.5zM11.313 8.937v-5.5h1.375v5.5z'/%3E%3C/svg%3E");
height: 23.38px;
}
::-webkit-scrollbar-button:horizontal:end:active {
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='24' height='23' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23fff' stroke='%23000' d='M23.19 22.19v-21H.81v21z'/%3E%3Cpath fill='%23000' d='M.685 21.69v-20h2v20zM11.312 21.315v-5.5h1.375v5.5zM5.811 15.815V8.94h11.002v6.875z'/%3E%3Cpath fill='%23000' d='M5.811 15.815h5.501v1.375H5.811zM18.189 13.065h1.375v1.375h-1.375zM19.564 11.69h1.375v1.375h-1.375zM11.312 3.44h1.375v1.375h-1.375zM12.688 4.815h1.375V8.94h-1.375zM14.063 6.19h1.375v2.75h-1.375zM15.438 7.565h1.375V8.94h-1.375zM16.814 8.94h1.375v1.375h-1.375zM18.189 10.315h1.375v2.75h-1.375zM16.814 10.315h1.375v5.5h-1.375zM15.438 15.815h1.375v1.375h-1.375zM14.063 15.815h1.375v2.75h-1.375zM12.688 15.815h1.375v4.125h-1.375zM11.312 19.94h1.375v1.375h-1.375zM5.811 7.565h5.501V8.94H5.811z'/%3E%3Cpath fill='%23000' d='M11.312 8.94v-5.5h1.375v5.5z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
height: 23.38px;
}
.window-pane::-webkit-scrollbar {
width: 22px;
background-color: var(--primary);
}
.window-pane::-webkit-scrollbar-track {
background: linear-gradient(45deg, var(--secondary) 25%, transparent 25%, transparent 75%, var(--secondary) 75%, var(--secondary)), linear-gradient(45deg, var(--secondary) 25%, transparent 25%, transparent 75%, var(--secondary) 75%, var(--secondary));
background-color: var(--primary);
background-size: 4px 4px;
background-position: 0 0, 2px 2px;
width: 10px;
border-left: 4px solid var(--secondary);
}
.window-pane::-webkit-scrollbar-thumb {
width: 20px;
box-sizing: content-box;
background-color: var(--primary);
border: 2px solid var(--secondary);
border-right: none;
}
::selection
{
background-color: aliceblue;
}
/** GITHUB - Gists */
body .gist .highlight {
background: #272822;
}
body .gist .blob-num,
body .gist .blob-code-inner,
body .gist .pl-s2,
body .gist .pl-stj {
color: #f8f8f2;
}
body .gist .pl-c1 {
color: #ae81ff;
}
body .gist .pl-enti {
color: #a6e22e;
font-weight: 700;
}
body .gist .pl-st {
color: #66d9ef;
}
body .gist .pl-mdr {
color: #66d9ef;
font-weight: 400;
}
body .gist .pl-ms1 {
background: #fd971f;
}
body .gist .pl-c,
body .gist .pl-c span,
body .gist .pl-pdc {
color: #75715e;
font-style: italic;
}
body .gist .pl-cce,
body .gist .pl-cn,
body .gist .pl-coc,
body .gist .pl-enc,
body .gist .pl-ens,
body .gist .pl-kos,
body .gist .pl-kou,
body .gist .pl-mh .pl-pdh,
body .gist .pl-mp,
body .gist .pl-mp1 .pl-sf,
body .gist .pl-mq,
body .gist .pl-pde,
body .gist .pl-pse,
body .gist .pl-pse .pl-s2,
body .gist .pl-mp .pl-s3,
body .gist .pl-smi,
body .gist .pl-stp,
body .gist .pl-sv,
body .gist .pl-v,
body .gist .pl-vi,
body .gist .pl-vpf,
body .gist .pl-mri,
body .gist .pl-va,
body .gist .pl-vpu {
color: #66d9ef;
}
body .gist .pl-cos,
body .gist .pl-ml,
body .gist .pl-pds,
body .gist .pl-s,
body .gist .pl-s1,
body .gist .pl-sol {
color: #e6db74;
}
body .gist .pl-e,
body .gist .pl-ef,
body .gist .pl-en,
body .gist .pl-enf,
body .gist .pl-enm,
body .gist .pl-entc,
body .gist .pl-entm,
body .gist .pl-eoac,
body .gist .pl-eoac .pl-pde,
body .gist .pl-eoi,
body .gist .pl-mai .pl-sf,
body .gist .pl-mm,
body .gist .pl-pdv,
body .gist .pl-som,
body .gist .pl-sr,
body .gist .pl-vo {
color: #a6e22e;
}
body .gist .pl-ent,
body .gist .pl-eoa,
body .gist .pl-eoai,
body .gist .pl-eoai .pl-pde,
body .gist .pl-k,
body .gist .pl-ko,
body .gist .pl-kolp,
body .gist .pl-mc,
body .gist .pl-mr,
body .gist .pl-ms,
body .gist .pl-s3,
body .gist .pl-smc,
body .gist .pl-smp,
body .gist .pl-sok,
body .gist .pl-sra,
body .gist .pl-src,
body .gist .pl-sre {
color: #f92672;
}
body .gist .pl-mb,
body .gist .pl-pdb {
color: #e6db74;
font-weight: 700;
}
body .gist .pl-mi,
body .gist .pl-pdi {
color: #f92672;
font-style: italic;
}
body .gist .pl-pdc1,
body .gist .pl-scp {
color: #ae81ff;
}
body .gist .pl-sc,
body .gist .pl-sf,
body .gist .pl-mo,
body .gist .pl-entl {
color: #fd971f;
}
body .gist .pl-mi1,
body .gist .pl-mdht {
color: #a6e22e;
background: rgba(0, 64, 0, .5);
}
body .gist .pl-md,
body .gist .pl-mdhf {
color: #f92672;
background: rgba(64, 0, 0, .5);
}
body .gist .pl-mdh,
body .gist .pl-mdi {
color: #a6e22e;
font-weight: 400;
}
body .gist .pl-ib,
body .gist .pl-id,
body .gist .pl-ii,
body .gist .pl-iu {
background: #a6e22e;
color: #272822;
}
body .gist .gist-meta {
display: block;
background: #272727;
color: cyan;
}
body .gist .gist-meta a {
color: rgb(109, 172, 235);
}
body .gist .gist-file {
border-width: 0px;
border-radius: 0px;
border-bottom: 0px;
border: 0px;
}
body .gist .gist-file .gist-data td{
padding: 5px;
margin: 5px;
border: 0px;
border-width: 0px;
}

View File

@ -1,32 +0,0 @@
export const getGhostImgPath = (
baseUrl: string,
imgUrl: string,
width = 0,
): string => {
if (!imgUrl) return "";
if (!imgUrl.startsWith(baseUrl)) {
return imgUrl;
}
const relativePath = imgUrl.substring(`${baseUrl}content/images`.length);
const cleanedBaseUrl = baseUrl.replace(/\/~/, "");
if (width && width > 0) {
return `${cleanedBaseUrl}content/images/size/w${width}/${relativePath}`;
}
return `${cleanedBaseUrl}content/images/${width}${relativePath}`;
};
export const truncate = (input: string, size: number): string =>
input.length > size ? `${input.substring(0, size)}...` : input;
export const formatDate = (dateInput: string): string => {
const dateObject = new Date(dateInput);
return dateObject.toDateString();
};
export const uniqWith = <T>(
arr: Array<T>,
fn: (element: T, step: T) => number,
): Array<T> =>
arr.filter(
(element, index) => arr.findIndex((step) => fn(element, step)) === index,
);

View File

@ -1,106 +0,0 @@
# @matthiesenxyz/astro-ghostcms-catppuccin
## 0.0.14
### Patch Changes
- f097c6a: Adds a toggleswitch to allow users to disable astro-remote usage for rendering ghost-content
- Updated dependencies [f097c6a]
- @matthiesenxyz/astro-ghostcms@3.3.4
## 0.0.13
### Patch Changes
- b0218e1: fix:
- Removed CodeSlot Component that sometimes would break with some <pre> components
- Will be adding at a latter time a custom component to replace this, but at this time this is now fixed.
## 0.0.12
### Patch Changes
- 4c1002a: fix getAllTags bug for themes and bump other packages deps
- Updated dependencies [4c1002a]
- @matthiesenxyz/astro-ghostcms@3.3.2
## 0.0.11
### Patch Changes
- 746fcc5: Fix html rendering to allow custom components
## 0.0.10
### Patch Changes
- 2724119: Migrate to `astro-remote` for internal processing of GhostCMS HTML. No user changes required.
## 0.0.9
### Patch Changes
- f921005: Bump dependencies:
- vite from to
- @eliancodes/brutal-ui from to
- typescript from to
- ultrahtml from to
- @fontsource-variable/inter from to
- astro-seo from to
- astro from to
- sass from to
- @astrojs/starlight from to
- sharp from to
- Updated dependencies [f921005]
- @matthiesenxyz/astro-ghostcms@3.3.1
## 0.0.8
### Patch Changes
- 1f850db: Bump dependencies:
- astro from to
- vite from to
- astro-seo from to
- sass from to
- Updated dependencies [1f850db]
- @matthiesenxyz/astro-ghostcms@3.2.9
## 0.0.7
### Patch Changes
- 3a5aea9: Updated Tests and Linted packages
- Updated dependencies [3a5aea9]
- @matthiesenxyz/astro-ghostcms@3.2.7
## 0.0.6
### Patch Changes
- 12be739: Depencency updates
- 754d08a: Bump astro-navbar from 2.3.0 to 2.3.1
- Updated dependencies [12be739]
- Updated dependencies [455ad3f]
- @matthiesenxyz/astro-ghostcms@3.2.5
## 0.0.5
### Patch Changes
- Fix License File
- Updated dependencies
- @matthiesenxyz/astro-ghostcms@3.2.4
## 0.0.4
### Patch Changes
- Initialization of changeset cli
- Updated dependencies
- @matthiesenxyz/astro-ghostcms@3.2.3

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2024 MatthiesenXYZ - Astro-GhostCMS
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,19 +0,0 @@
/** @type {import('tailwindcss').Config} */
import { fontFamily as _fontFamily } from "tailwindcss/defaultTheme";
export const content = [
"./node_modules/@matthiesenxyz/astro-ghostcms-catppuccin/src/**/*.{astro,js,css,ts}",
];
export const theme = {
extend: {
fontFamily: {
sans: ["Inter Variable", "Inter", ..._fontFamily.sans],
},
},
};
export const plugins = [
require("@tailwindcss/typography"),
require("@catppuccin/tailwindcss")({
prefix: "ctp",
defaultFlavour: "frappe",
}),
];

View File

@ -1,19 +0,0 @@
/** @type {import('tailwindcss').Config} */
import { fontFamily as _fontFamily } from "tailwindcss/defaultTheme";
export const content = [
"./node_modules/@matthiesenxyz/astro-ghostcms-catppuccin/src/**/*.{astro,js,css,ts}",
];
export const theme = {
extend: {
fontFamily: {
sans: ["Inter Variable", "Inter", ..._fontFamily.sans],
},
},
};
export const plugins = [
require("@tailwindcss/typography"),
require("@catppuccin/tailwindcss")({
prefix: "ctp",
defaultFlavour: "latte",
}),
];

View File

@ -1,19 +0,0 @@
/** @type {import('tailwindcss').Config} */
import { fontFamily as _fontFamily } from "tailwindcss/defaultTheme";
export const content = [
"./node_modules/@matthiesenxyz/astro-ghostcms-catppuccin/src/**/*.{astro,js,css,ts}",
];
export const theme = {
extend: {
fontFamily: {
sans: ["Inter Variable", "Inter", ..._fontFamily.sans],
},
},
};
export const plugins = [
require("@tailwindcss/typography"),
require("@catppuccin/tailwindcss")({
prefix: "ctp",
defaultFlavour: "macchiato",
}),
];

View File

@ -1,19 +0,0 @@
/** @type {import('tailwindcss').Config} */
import { fontFamily as _fontFamily } from "tailwindcss/defaultTheme";
export const content = [
"./node_modules/@matthiesenxyz/astro-ghostcms-catppuccin/src/**/*.{astro,js,css,ts}",
];
export const theme = {
extend: {
fontFamily: {
sans: ["Inter Variable", "Inter", ..._fontFamily.sans],
},
},
};
export const plugins = [
require("@tailwindcss/typography"),
require("@catppuccin/tailwindcss")({
prefix: "ctp",
defaultFlavour: "mocha",
}),
];

View File

@ -1,71 +0,0 @@
{
"name": "@matthiesenxyz/astro-ghostcms-catppuccin",
"description": "A dark theme made with Catppuccin and TailwindCSS for Astro-GhostCMS",
"version": "0.0.14",
"homepage": "https://astro-ghostcms.xyz/",
"type": "module",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"sideEffects": false,
"author": {
"email": "adam@matthiesen.xyz",
"name": "Adam Matthiesen - MatthiesenXYZ",
"url": "https://matthiesen.xyz"
},
"keywords": [
"astro-ghostcms"
],
"repository": {
"type": "git",
"url": "git+https://github.com/MatthiesenXYZ/astro-ghostcms.git"
},
"bugs": {
"url": "https://github.com/MatthiesenXYZ/astro-ghostcms/issues",
"email": "issues@astro-ghostcms.xyz"
},
"main": "./cat-macchiato.js",
"files": [
"src",
"cat-frappe.js",
"cat-latte.js",
"cat-macchiato.js",
"cat-mocha.js",
"index.js"
],
"exports": {
".": "./cat-macchiato.js",
"./frappe": "./cat-frappe.js",
"./latte": "./cat-latte.js",
"./macchiato": "./cat-macchiato.js",
"./mocha": "./cat-mocha.js",
"./index.astro": "./src/routes/index.astro",
"./[slug].astro": "./src/routes/[slug].astro",
"./tags.astro": "./src/routes/tags.astro",
"./authors.astro": "./src/routes/authors.astro",
"./tag/[slug].astro": "./src/routes/tag/[slug].astro",
"./author/[slug].astro": "./src/routes/author/[slug].astro",
"./archives/[...page].astro": "./src/routes/archives/[...page].astro"
},
"scripts": {},
"peerDependencies": {
"@matthiesenxyz/astro-ghostcms": ">=3.3.5",
"astro": ">=4.4.0"
},
"devDependencies": {
"@matthiesenxyz/astro-ghostcms": "workspace:*"
},
"dependencies": {
"@astrojs/tailwind": "^5.1.0",
"@catppuccin/tailwindcss": "0.1.6",
"@fontsource-variable/inter": "^5.0.17",
"@matthiesenxyz/astro-ghostcms": "^3.3.5",
"@tailwindcss/typography": "^0.5.10",
"astro-navbar": "^2.3.1",
"astro-remote": "^0.3.2",
"astro-seo": "^0.8.3",
"tailwindcss": "^3.3.5",
"ultrahtml": "1.5.3"
}
}

View File

@ -1,61 +0,0 @@
---
import { getGhostImgPath } from "../utils";
import type { Settings, Author } from "@matthiesenxyz/astro-ghostcms/api";
export type Props = {
author: Author;
wide?: boolean;
addClass?: string;
settings: Settings;
showCover?: boolean;
};
const {
author,
wide = false,
settings,
showCover = true,
} = Astro.props as Props;
---
<div class="flex">
{author.profile_image && (
<a href={`/author/${author.slug}`} class="author-card-media">
<img
class="author-card-img"
data-srcset={`
${getGhostImgPath(settings.url, author.profile_image, 100)} 100w,
${getGhostImgPath(settings.url, author.profile_image, 300)} 300w
`}
srcset={`
${getGhostImgPath(settings.url, author.profile_image, 100)} 100w,
${getGhostImgPath(settings.url, author.profile_image, 300)} 300w
`}
data-sizes="auto"
data-src={getGhostImgPath(settings.url, author.profile_image, 300)}
src={getGhostImgPath(settings.url, author.profile_image, 300)}
alt={author.name}
sizes="316px"
/>
</a>
)}
<div class="flex flex-col ml-2">
<div class="text-ctp-teal text-3xl font-semibold">
<a href={`/author/${author.slug}`}>{author.name}</a>
</div>
{author.bio && <div class="text-ctp-blue">{author.bio}</div>}
<div class="text-ctp-red">
{author.count && author.count.posts && (
<div>
{author.count.posts > 0 ? `${author.count.posts} posts` : "No posts"}
</div>
)}
</div>
{author.location && (
<div class="text-ctp-sapphire">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pin-map-fill text-ctp-flamingo inline" viewBox="0 0 16 16"> <path fill-rule="evenodd" d="M3.1 11.2a.5.5 0 0 1 .4-.2H6a.5.5 0 0 1 0 1H3.75L1.5 15h13l-2.25-3H10a.5.5 0 0 1 0-1h2.5a.5.5 0 0 1 .4.2l3 4a.5.5 0 0 1-.4.8H.5a.5.5 0 0 1-.4-.8z"/> <path fill-rule="evenodd" d="M4 4a4 4 0 1 1 4.5 3.969V13.5a.5.5 0 0 1-1 0V7.97A4 4 0 0 1 4 3.999z"/> </svg> {author.location}
</div>
)}
</div>
</div>

View File

@ -1,95 +0,0 @@
---
export type Props = {
name: string,
image?: string | null,
count: number,
bio: string | null,
location: string | null,
website: string | null,
twitter: string | null,
facebook: string | null
};
const {
name, image, bio, location, website, twitter, facebook, count
} = Astro.props as Props;
---
<header class="author-card">
{ image ? <img src={image} alt="Author Image" class="author-image"> : (
<span class="author-image">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<path
d="M3.513 18.998C4.749 15.504 8.082 13 12 13s7.251 2.504 8.487 5.998C18.47 21.442 15.417 23 12 23s-6.47-1.558-8.487-4.002zM12 12c2.21 0 4-2.79 4-5s-1.79-4-4-4-4 1.79-4 4 1.79 5 4 5z"
fill="#FFF"
/>
</g>
</svg>
</span>
)}
<div class="author-info">
<div class="author-name text-ctp-teal">{name}</div>
<div class="author-bio text-ctp-blue">
{bio ? bio : count > 0? count + " Posts" : "No Posts"}
</div>
{location && (
<div class="author-location text-ctp-sapphire">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pin-map-fill text-ctp-flamingo inline" viewBox="0 0 16 16"> <path fill-rule="evenodd" d="M3.1 11.2a.5.5 0 0 1 .4-.2H6a.5.5 0 0 1 0 1H3.75L1.5 15h13l-2.25-3H10a.5.5 0 0 1 0-1h2.5a.5.5 0 0 1 .4.2l3 4a.5.5 0 0 1-.4.8H.5a.5.5 0 0 1-.4-.8z"/> <path fill-rule="evenodd" d="M4 4a4 4 0 1 1 4.5 3.969V13.5a.5.5 0 0 1-1 0V7.97A4 4 0 0 1 4 3.999z"/> </svg> {location}
</div>
)}
<div class="author-links">
{website && (<a href={website} target="_blank" rel="noopener">Website</a>)}
{twitter && (<a href={twitter} target="_blank" rel="noopener">Twitter</a>)}
{facebook && (<a href={facebook} target="_blank" rel="noopener">Facebook</a>)}
</div>
</div>
</header>
<style>
.author-card {
display: flex;
margin-top: 8vmin;
margin-bottom: 6vmin;
overflow: hidden;
}
.author-image {
width: 180px;
height: 180px;
object-fit: cover;
border-radius: 3px;
}
.author-info {
flex: 1;
padding: 20px;
text-align: left;
}
.author-name {
font-size: 1.5em;
font-weight: bold;
margin-bottom: 10px;
}
.author-bio {
line-height: 1.4;
}
.author-location {
margin-top: 10px;
}
.author-links {
margin-top: 10px;
}
.author-links a {
text-decoration: none;
color: #3498db;
margin-right: 10px;
}
</style>

View File

@ -1,35 +0,0 @@
---
import { getGhostImgPath } from "../utils";
import type { Settings, Post } from "@matthiesenxyz/astro-ghostcms/api";
export type Props = {
post: Post;
settings: Settings;
};
const { post, settings } = Astro.props as Props;
---
<ul class="flex flex-wrap mr-4">
{post.authors && post.authors.map((author) => (
<li class="relative flex-shrink-0 m-0 p-0">
{author.profile_image ? (
<a href={`/author/${author.slug}`} class="block overflow-hidden w-14 h-14 border-2 rounded-full">
<img
src={getGhostImgPath(settings.url, author.profile_image, 100)}
alt={author.name}
/>
</a>
) : (
<a href={`/author/${author.slug}`} class="block overflow-hidden w-14 h-14 border-2 rounded-full">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<path
d="M3.513 18.998C4.749 15.504 8.082 13 12 13s7.251 2.504 8.487 5.998C18.47 21.442 15.417 23 12 23s-6.47-1.558-8.487-4.002zM12 12c2.21 0 4-2.79 4-5s-1.79-4-4-4-4 1.79-4 4 1.79 5 4 5z"
fill="#FFF"
/>
</g>
</svg>
</a>
)}
</li>
))}
</ul>

View File

@ -1,26 +0,0 @@
---
import { getGhostImgPath } from "../utils";
import type { Settings } from "@matthiesenxyz/astro-ghostcms/api";
export type Props = {
image: string;
alt?: string;
caption?: string;
settings: Settings;
transitionName?: string;
};
const { image, alt, caption = "", settings, transitionName } = Astro.props as Props;
---
<figure class="article-image">
<img
srcset={`
${getGhostImgPath(settings.url, image, 300)} 300w,
${getGhostImgPath(settings.url, image, 600)} 600w,
`}
sizes="(min-width: 300px) 600px, 92vw"
src={getGhostImgPath(settings.url, image, 2000)}
alt={alt}
transition:name={transitionName}
/>
{caption && <figcaption class="text-ctp-overlay2"><Fragment set:html={caption}></figcaption>}
</figure>

View File

@ -1,79 +0,0 @@
---
import type { Settings, Post } from "@matthiesenxyz/astro-ghostcms/api";
import FeatureImage from "./FeatureImage.astro";
import AuthorList from "./AuthorList.astro";
import { formatDate } from "../utils";
import { Markup } from 'astro-remote';
import config from "virtual:@matthiesenxyz/astro-ghostcms/config";
const useRemote = config.ThemeProvider.astroRemote.enable;
export type Props = {
posts: Post[];
settings: Settings;
};
const { posts, settings } = Astro.props as Props;
const latestFeatured = posts[0]
---
{latestFeatured && (
<main
class="grid place-items-center pt-16 pb-8 md:pt-12 md:pb-24">
{latestFeatured.feature_image && (
<FeatureImage
image={latestFeatured.feature_image}
alt={latestFeatured.feature_image_alt ? latestFeatured.feature_image_alt : latestFeatured.title}
caption={latestFeatured.feature_image_caption || "" }
settings={settings}
transitionName={`img-${latestFeatured.title}`}
/>
)}
<div>
{latestFeatured.primary_tag && (
<section class="text-ctp-lavender">
<a href={`/tag/${latestFeatured.primary_tag.slug}`}><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-tag inline" viewBox="0 0 16 16">
<path d="M6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-1 0a.5.5 0 1 0-1 0 .5.5 0 0 0 1 0"/>
<path d="M2 1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 1 6.586V2a1 1 0 0 1 1-1m0 5.586 7 7L13.586 9l-7-7H2z"/>
</svg> {latestFeatured.primary_tag.name}</a>
</section>
)}
<h2
class="text-ctp-red text-4xl lg:text-6xl xl:text-7xl font-bold lg:tracking-tight xl:tracking-tighter">
{latestFeatured && latestFeatured.title}
</h2>
<div class="flex justify-between ml-5">
<section class="flex flex-grow align-middle">
<AuthorList post={latestFeatured} settings={settings} />
<div class="text-ctp-overlay2">
{ latestFeatured.primary_author && (
<h4 class="text-ctp-teal">
{latestFeatured.primary_author.name}
</h4>
)}
<div class="text-ctp-overlay2">
<time class="text-ctp-sapphire" datetime={formatDate(latestFeatured.published_at?latestFeatured.published_at:latestFeatured.created_at)}
>{formatDate(latestFeatured.published_at?latestFeatured.published_at:latestFeatured.created_at)}
</time>
<span class="text-ctp-peach"
><span class="text-ctp-overlay2">&bull;</span>
{latestFeatured.reading_time} min read
</span>
</div>
</div>
</section>
</div>
<div class="divider my-4"/>
<section id="ghostimport" class="text-ctp-subtext1">
{useRemote ? (latestFeatured && <Markup
content={latestFeatured.html}
sanitize={{
allowComponents: true,
allowElements: ['a', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'img', 'figure', 'figcaption', 'ul', 'ol', 'li', 'blockquote', 'pre', 'code', 'em', 'strong', 'del', 'hr', 'br', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'caption', 'div', 'span', 'script', 'astrocard'],
}}
/>) : (latestFeatured && <Fragment set:html={latestFeatured.html} />) }
</section>
</div>
</main>
)}

View File

@ -1,26 +0,0 @@
---
import type { Page } from 'astro';
const { page } = Astro.props as {page: Page};
---
<div class="page__actions">
{page.url.prev && (
<a class="action__go-to-x" href={page.url.prev} title="Go to Previous">
&larr; Prev
</a>
)}
{page.url.next && (
<a class="action__go-to-x" href={page.url.next} title="Go to Next">
Next &rarr;
</a>
)}
</div>
<style>
/* .page__actions {
@apply flex justify-center md:justify-end py-6 gap-2;
}
.action__go-to-x {
@apply text-base uppercase text-gray-500 dark:text-gray-400 hover:underline;
} */
</style>

View File

@ -1,46 +0,0 @@
---
import PostHero from "../components/PostHero.astro";
import PostFooter from "../components/PostFooter.astro";
import { getFeaturedPosts, invariant, type Post, type Settings } from "@matthiesenxyz/astro-ghostcms/api";
import { Markup } from 'astro-remote';
import config from "virtual:@matthiesenxyz/astro-ghostcms/config";
const useRemote = config.ThemeProvider.astroRemote.enable;
export type Props = {
post: Post;
settings: Settings;
posts: Post[];
};
const { post, settings, posts } = Astro.props as Props;
async function getPostsSet(){
const featuredPosts = await getFeaturedPosts();
const fposts = posts;
if(featuredPosts.posts.length === 0){ return fposts }
const featured = featuredPosts.posts[0]
return fposts.filter((p: Post)=>p.id !== featured.id)
}
const mPosts = await getPostsSet()
invariant(settings, "Settings not found");
---
<PostHero post={post} settings={settings} />
<div id="ghostimport" class="mt-4 text-ctp-subtext1">
{useRemote ? (
<Markup
content={post.html}
sanitize={{
allowComponents: true,
allowElements: ['a', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'img', 'figure', 'figcaption', 'ul', 'ol', 'li', 'blockquote', 'pre', 'code', 'em', 'strong', 'del', 'hr', 'br', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'caption', 'div', 'span', 'script', 'astrocard'],
}}
/>
) : <Fragment set:html={post.html} /> }
</div>
<PostFooter post={post} settings={settings} posts={mPosts} />

View File

@ -1,115 +0,0 @@
---
import PostPreview from "../components/PostPreview.astro";
import type { Settings, Post } from "@matthiesenxyz/astro-ghostcms/api";
export type Props = {
post: Post;
settings: Settings;
posts: Post[];
};
const { post, settings, posts } = Astro.props as Props;
---
<aside class="read-more-wrap">
<div class="read-more inner">
{posts
.filter((p: Post) => p.id !== post.id)
.slice(0, 3)
.map((post: Post) => <PostPreview post={post} settings={settings} />)}
</div>
</aside>
<style lang="scss">
/* 7.3. Subscribe
/* ---------------------------------------------------------- */
.footer-cta {
position: relative;
padding: 9vmin 4vmin 10vmin;
color: #fff;
text-align: center;
background: var(--color-darkgrey);
}
/* Increases the default h2 size by 15%, for small and large screens */
.footer-cta h2 {
margin: 0 0 30px;
font-size: 3.2rem;
}
@media (max-width: 600px) {
.footer-cta h2 {
font-size: 2.65rem;
}
}
.footer-cta-button {
position: relative;
display: inline-flex;
align-items: center;
justify-content: space-between;
width: 100%;
max-width: 500px;
padding: 5px 5px 5px 15px;
font-size: 1.8rem;
color: var(--color-midgrey);
background: #fff;
border-radius: 8px;
}
.footer-cta-button span {
display: inline-block;
padding: 10px 20px;
color: #fff;
font-weight: 500;
background: var(--ghost-accent-color);
border-radius: 5px;
}
/* 7.4. Read more
/* ---------------------------------------------------------- */
.read-more-wrap {
width: 100%;
padding: 4vmin;
margin: 0 auto -40px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
background: color-mod(var(--color-darkgrey) l(-5%));
}
.read-more {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 4vmin;
}
.read-more .post-card-title {
color: #fff;
opacity: 0.8;
}
.read-more .post-card-excerpt {
color: rgba(255, 255, 255, 0.6);
}
.read-more .post-card-byline-content a {
color: #fff;
}
@media (max-width: 1000px) {
.read-more {
grid-template-columns: 1fr 1fr;
}
.read-more article:nth-child(3) {
display: none;
}
}
@media (max-width: 700px) {
.read-more {
grid-template-columns: 1fr;
}
.read-more article:nth-child(2) {
display: none;
}
}
</style>

View File

@ -1,51 +0,0 @@
---
import FeatureImage from "../components/FeatureImage.astro";
import AuthorList from "../components/AuthorList.astro";
import { formatDate } from "../utils";
import type { Settings, Post } from "@matthiesenxyz/astro-ghostcms/api";
export type Props = {
post: Post;
settings: Settings;
};
const { post, settings } = Astro.props as Props;
---
<header class="article-header gh-canvas">
{post.primary_tag && (
<section class="text-ctp-lavender">
<a href={`/tag/${post.primary_tag.slug}`}>{post.primary_tag.name}</a>
</section>
)}
<h1 class="text-ctp-red text-4xl lg:text-6xl xl:text-7xl font-bold lg:tracking-tight xl:tracking-tighter" transition:name={post.title}>{post.title}</h1>
<div class="flex justify-between my-4">
<section class="flex flex-grow align-middle">
<AuthorList post={post} settings={settings} />
<div class="text-ctp-overlay2">
{ post.primary_author && (
<h4 class="text-ctp-teal">
{post.primary_author.name}
</h4>
)}
<div class="text-ctp-overlay2">
<time class="text-ctp-sapphire" datetime={formatDate(post.created_at)}
>{formatDate(post.created_at)}
</time>
<span class="text-ctp-peach"
><span class="text-ctp-overlay2">&bull;</span>
{post.reading_time} min read
</span>
</div>
</div>
</section>
</div>
{post.feature_image && (
<FeatureImage
image={post.feature_image}
alt={post.feature_image_alt ? post.feature_image_alt : post.title}
caption={post.feature_image_caption || "" }
settings={settings}
transitionName={`img-${post.title}`}
/>
)}
</header>

View File

@ -1,65 +0,0 @@
---
import { getGhostImgPath, formatDate } from "../utils";
import AuthorList from "./AuthorList.astro";
import type { Settings, Post, Tag } from "@matthiesenxyz/astro-ghostcms/api";
export type Props = {
post: Post;
settings: Settings;
index?: number;
isHome?: boolean;
};
const { post, settings, index, isHome = false } = Astro.props as Props;
---
<article
class={`relative flex flex-col bg-cover bg-ctp-surface0 break-words ${post.tags && post.tags
.map((tag: Tag) => `tag-${tag.slug}`)
.join(" ")} ${
isHome && post.feature_image && index == 0 ? "lg:grid-cols-1 lg:col-span-3 lg:gap-4 lg:border-t-0" : ""
}`}
>
<a class="relative grid-cols-1 col-span-2 mb-0" href={`/${post.slug}`}>
<img
class="relative flex overflow-hidden border-r-2 mb-0 object-cover h-52 min-w-full"
srcset={`
${getGhostImgPath(settings.url, post.feature_image || "", 300)} 300w,
${getGhostImgPath(settings.url, post.feature_image || "", 600)} 600w
${getGhostImgPath(settings.url, post.feature_image || "", 1000)} 1000w
${getGhostImgPath(settings.url, post.feature_image || "", 2000)} 2000w
`}
src={`${getGhostImgPath(settings.url, post.feature_image || "", 600)}`}
alt={post.title}
sizes="(max-width: 1000px) 400px, 800px"
loading="lazy"
transition:name={`img-${post.title}`}
/>
</a>
<div class="relative justify-center">
<a class="relative p-0" href={`/${post.slug}`} data-astro-reload>
<header class="mt-0 px-4 mt-3">
{post.primary_tag && (
<div class="text-ctp-lavender text-sm">{post.primary_tag.name}</div>
)}
<h2 class="my-2 text-2xl font-bold text-ctp-red line-clamp-1" transition:name={post.title}>{post.title}</h2>
</header>
<div class="px-4 text-base text-ctp-subtext1 max-w-fit line-clamp-2">
<p>{post.excerpt}</p>
</div>
</a>
<footer class="flex align-middle items-center p-4">
<AuthorList post={post} settings={settings} />
<div class="flex flex-1 flex-col text-ctp-teal text-lg">
<span class="text-sm">{post.primary_author?.name ?? ""}</span>
<span class="text-sm text-ctp-sapphire"
><time datetime={formatDate(post.created_at)}
>{formatDate(post.created_at)}
</time>
<span class="text-ctp-peach"
><span class="text-ctp-overlay2">&bull;</span>
{post.reading_time} min read
</span>
</div>
</footer>
</div>
</article>

View File

@ -1,21 +0,0 @@
---
import PostPreview from "./PostPreview.astro";
import type { Settings, Post } from "@matthiesenxyz/astro-ghostcms/api";
export type Props = {
posts: Post[];
settings: Settings;
isHome?: boolean;
};
const { posts, settings, isHome = false } = Astro.props as Props;
---
<div class="relative grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-2 lg:gap-8 p-4">
{posts.map((post: Post, index: number) => (
<PostPreview
post={post}
index={index}
settings={settings}
isHome={isHome}
/>
))}
</div>

View File

@ -1,43 +0,0 @@
---
import { getGhostImgPath } from "../utils";
import type { Settings, Tag } from "@matthiesenxyz/astro-ghostcms/api";
export type Props = {
tag: Tag;
addClass?: string;
settings: Settings;
};
const { tag, addClass = "", settings } = Astro.props;
---
<a
href={`/tag/${tag.slug}`}
title={tag.name}
aria-label={tag.name}
class={`text-center`}
>
{
tag.feature_image && (
<div class="tag-card-media">
<img
class="tag-card-img"
data-srcset={`
${getGhostImgPath(settings.url, tag.feature_image, 100)} 100w,
${getGhostImgPath(settings.url, tag.feature_image, 300)} 300w
`}
srcset={`
${getGhostImgPath(settings.url, tag.feature_image, 100)} 100w,
${getGhostImgPath(settings.url, tag.feature_image, 300)} 300w
`}
data-sizes="auto"
data-src={getGhostImgPath(settings.url, tag.feature_image, 300)}
src={getGhostImgPath(settings.url, tag.feature_image, 300)}
alt={tag.name}
sizes="200px"
/>
</div>
)
}
<h3 class="text-ctp-lavender">{tag.name}</h4>
<h4 class="text-ctp-teal">{tag.count?.posts} Posts<h4>
</a>

View File

@ -1,7 +0,0 @@
---
const { class: className } = Astro.props;
---
<div class:list={["max-w-screen-xl mx-auto px-5", className]}>
<slot />
</div>

View File

@ -1,19 +0,0 @@
---
import { getSettings, invariant } from "@matthiesenxyz/astro-ghostcms/api";
const settings = await getSettings();
invariant(settings, 'Settings not found');
---
<footer class="my-20">
<p class="text-center text-sm text-slate-500">
Copyright © {new Date().getFullYear()} {settings.title}. All rights reserved.
</p>
<p class="text-center text-xs text-slate-500 mt-1">
Powered by <a
href="https://ghost.org"
target="_blank"
rel="noopener"
class="hover:underline">
Ghost
</a>
</p>
</footer>

View File

@ -1,82 +0,0 @@
---
import { facebook, getSettings, invariant, twitter } from "@matthiesenxyz/astro-ghostcms/api";
const settings = await getSettings();
invariant(settings, 'Settings not found');
import Container from "./container.astro";
import { Astronav, MenuItems, MenuIcon } from "astro-navbar";
---
<Container>
<header class="flex flex-col lg:flex-row justify-between items-center my-5">
<Astronav>
<div class="flex w-full lg:w-auto items-center justify-between">
<a href="/" class="text-lg">
{settings.icon && <img src={settings.icon} width="64" class="flex-1 inline">}
<span class="font-bold flex-2 text-ctp-blue">{settings.title}</span>
</a>
<div class="block lg:hidden">
<MenuIcon class="w-4 h-4 text-ctp-pink" />
</div>
</div>
<MenuItems class="hidden w-full lg:w-auto mt-2 lg:flex lg:mt-0">
<ul class="flex flex-col lg:flex-row lg:gap-3">
{ settings.navigation.map(({ label, url }) => (
<li>
<a href={url}
class="flex lg:px-3 py-2 items-center text-ctp-teal hover:text-ctp-green">
<span> {label}</span>
</a>
</li>
)) }
</ul>
<div class="lg:hidden flex items-center mt-3 gap-4">
{ settings.facebook && (
<a
class=""
href={facebook(settings.facebook)}
title="Facebook"
target="_blank"
rel="noopener"
> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="text-ctp-blue bi bi-facebook" viewBox="0 0 16 16"> <path d="M16 8.049c0-4.446-3.582-8.05-8-8.05C3.58 0-.002 3.603-.002 8.05c0 4.017 2.926 7.347 6.75 7.951v-5.625h-2.03V8.05H6.75V6.275c0-2.017 1.195-3.131 3.022-3.131.876 0 1.791.157 1.791.157v1.98h-1.009c-.993 0-1.303.621-1.303 1.258v1.51h2.218l-.354 2.326H9.25V16c3.824-.604 6.75-3.934 6.75-7.951"/> </svg>
</a>
)}
{settings.twitter && (
<a
class="gh-social-twitter"
href={twitter(settings.twitter)}
title="Twitter"
target="_blank"
rel="noopener"
><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="text-ctp-subtext1 bi bi-twitter-x" viewBox="0 0 16 16"> <path d="M12.6.75h2.454l-5.36 6.142L16 15.25h-4.937l-3.867-5.07-4.425 5.07H.316l5.733-6.57L0 .75h5.063l3.495 4.633L12.601.75Zm-.86 13.028h1.36L4.323 2.145H2.865z"/> </svg>
</a>
)}
</div>
</MenuItems>
</Astronav>
<div>
<div class="hidden lg:flex items-center gap-4">
{ settings.facebook && (
<a
class=""
href={facebook(settings.facebook)}
title="Facebook"
target="_blank"
rel="noopener"
><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="text-ctp-blue bi bi-facebook" viewBox="0 0 16 16"> <path d="M16 8.049c0-4.446-3.582-8.05-8-8.05C3.58 0-.002 3.603-.002 8.05c0 4.017 2.926 7.347 6.75 7.951v-5.625h-2.03V8.05H6.75V6.275c0-2.017 1.195-3.131 3.022-3.131.876 0 1.791.157 1.791.157v1.98h-1.009c-.993 0-1.303.621-1.303 1.258v1.51h2.218l-.354 2.326H9.25V16c3.824-.604 6.75-3.934 6.75-7.951"/> </svg>
</a>
)}
{settings.twitter && (
<a
class="gh-social-twitter"
href={twitter(settings.twitter)}
title="Twitter"
target="_blank"
rel="noopener"
><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="text-ctp-subtext1 bi bi-twitter-x" viewBox="0 0 16 16"> <path d="M12.6.75h2.454l-5.36 6.142L16 15.25h-4.937l-3.867-5.07-4.425 5.07H.316l5.733-6.57L0 .75h5.063l3.495 4.633L12.601.75Zm-.86 13.028h1.36L4.323 2.145H2.865z"/> </svg>
</a>
)}
</div>
</div>
</header>
</Container>

View File

@ -1,2 +0,0 @@
/// <reference path="../.astro/types.d.ts" />
/// <reference types="astro/client" />

View File

@ -1,55 +0,0 @@
---
import { SEO } from "astro-seo";
import Footer from "../components/footer.astro";
import Navbar from "../components/navbar.astro";
import "@fontsource-variable/inter/index.css";
import { type Settings } from "@matthiesenxyz/astro-ghostcms/api";
import { getOgImagePath } from "@matthiesenxyz/astro-ghostcms/satoriOG";
import "../styles/global.css"
export interface Props {
title: string;
description: string;
settings: Settings;
}
const canonicalURL = new URL(Astro.url.pathname, Astro.site).toString();
const ogI = new URL(getOgImagePath(Astro.url.pathname), Astro.url.origin).href;
const { title, description, settings } = Astro.props;
const makeTitle = title
? title + ' | ' + settings.title
: settings.title + ' | ' + settings.description;
const makeDesc = description ? description : settings.description
---
<!DOCTYPE html>
<html lang="en" class="bg-ctp-base">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/svg+xml" href={settings.icon} />
<meta name="generator" content={Astro.generator} />
<!-- <link rel="preload" as="image" href={src} alt="Hero" /> -->
<SEO
title={makeTitle}
description={makeDesc}
canonical={canonicalURL}
openGraph={{
basic: {url: canonicalURL, type: "website",
title: makeTitle, image: ogI,},
optional: {siteName:settings.title, description: makeDesc},
image: {alt:makeTitle},
}}
/>
</head>
<body>
<Navbar />
<slot />
<Footer />
</body>
</html>

View File

@ -1,36 +0,0 @@
---
import Layout from "../layouts/Layout.astro";
import Container from "../components/container.astro";
import { getAllPosts, getAllPages, getSettings, invariant } from "@matthiesenxyz/astro-ghostcms/api";
import type { InferGetStaticPropsType } from "astro";
import Post from "../components/Post.astro";
export async function getStaticPaths() {
const [posts, pages, settings] = await Promise.all([getAllPosts(), await getAllPages(), await getSettings()]);
const allPosts = [...posts, ...pages];
return allPosts.map((post) => ({
params: { slug: post.slug },
props: { post, posts, settings },
}));
}
export type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const {post, posts, settings} = Astro.props as Props;
invariant(settings, "Settings are required");
---
<Layout
title={post.title}
description={post.excerpt}
settings={settings}>
<Container>
{ post.primary_author && (
<Post post={post} settings={settings} posts={posts} />
)
}
</Container>
</Layout>

Some files were not shown because too many files have changed in this diff Show More