5% go into beloved community

This commit is contained in:
lovebird 2025-03-08 19:36:51 +01:00
parent 67a2d7f542
commit f61e5602b7
507 changed files with 17200 additions and 69368 deletions

View File

@ -25,6 +25,35 @@
"vendorId": {
"type": "number"
},
"shipping": {
"type": "object",
"properties": {
"price": {
"type": "number"
},
"transit": {
"type": "number"
},
"handling": {
"type": "number"
}
},
"additionalProperties": false,
"default": {
"price": 0,
"transit": 12,
"handling": 2
}
},
"manufacturing": {
"type": "object",
"properties": {
"lead_time": {
"type": "number"
}
},
"additionalProperties": false
},
"replaced_by": {
"type": "string"
},
@ -388,6 +417,7 @@
},
"required": [
"code",
"manufacturing",
"name",
"slug",
"category"

File diff suppressed because one or more lines are too long

33418
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,86 +1,87 @@
{
"name": "@plastichub/astro-site-template",
"version": "0.0.1",
"private": true,
"type": "module",
"scripts": {
"dev": "astro dev --mode dev --host=0.0.0.0 --o-images=medium",
"start": "astro dev",
"build": "astro build",
"test:build": "astro build ; cd dist ; serve",
"preview": "astro preview",
"astro": "astro",
"generate-pwa-assets": "pwa-assets-generator --preset minimal-2023 public/logo.svg",
"test": "playwright test",
"test:lighthouse": "lighthouse https://polymech.io/en --output json --output html --output-path ./dist/reports/report.html --save-assets --chrome-flags=\"--window-size=1440,700 --headless\"",
"test:debug": "playwright test",
"test:ui": "playwright test --ui",
"clean": "rm -rf dist"
},
"dependencies": {
"@astrojs/compiler": "^2.10.4",
"@astrojs/mdx": "^4.1.0",
"@astrojs/react": "^4.2.1",
"@astrojs/rss": "^4.0.10",
"@astrojs/sitemap": "^3.2.1",
"@astrolib/seo": "^1.0.0-beta.8",
"@playwright/test": "^1.50.1",
"@polymech/cache": "file:../polymech-mono/packages/cache",
"@polymech/cad": "file:../polymech-mono/packages/cad",
"@polymech/commons": "file:../polymech-mono/packages/commons",
"@polymech/fs": "file:../polymech-mono/packages/fs",
"@polymech/i18n": "file:../polymech-mono/packages/i18n",
"@polymech/kbot-d": "file:../polymech-mono/packages/kbot",
"@polymech/log": "file:../polymech-mono/packages/log",
"@tailwindcss/forms": "^0.5.10",
"@tailwindcss/postcss": "^4.0.7",
"@tailwindcss/typography": "^0.5.12",
"@tailwindcss/vite": "^4.0.7",
"astro": "^5.4.0",
"autoprefixer": "^10.4.20",
"axios": "^1.7.9",
"cacache": "^19.0.1",
"exifreader": "^4.26.1",
"file-type": "^20.0.0",
"find-cache-dir": "^5.0.0",
"find-up": "^7.0.0",
"flowbite": "^3.1.2",
"github-slugger": "^2.0.0",
"glob": "^11.0.1",
"got": "^14.4.6",
"imagetools": "file:packages/imagetools",
"lighthouse": "^12.3.0",
"markdown-it": "^14.1.0",
"marked": "^15.0.7",
"mdast": "^2.3.2",
"mdast-util-from-markdown": "^2.0.2",
"mdast-util-to-markdown": "^2.1.2",
"mdast-util-to-string": "^4.0.0",
"mkdirp": "^3.0.1",
"node-xlsx": "^0.24.0",
"object-hash": "^3.0.0",
"p-map": "^7.0.3",
"picomatch": "^4.0.2",
"potrace": "^2.1.8",
"react-jsx-parser": "^2.3.0",
"rehype-stringify": "^10.0.1",
"remark": "^15.0.1",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.1.1",
"sanitize-html": "^2.14.0",
"schema-dts": "^1.1.2",
"sharp": "^0.29.3",
"showdown": "^2.1.0",
"tailwindcss": "^4.0.7",
"type-fest": "^4.34.1",
"vite": "^6.1.1",
"xlsx": "^0.18.5",
"yargs": "^17.7.2",
"zod": "^3.24.2"
},
"devDependencies": {
"micromark-util-sanitize-uri": "^2.0.1",
"normalize-url": "^8.0.1",
"sass-embedded": "^1.83.4"
}
}
{
"name": "@plastichub/astro-site-template",
"version": "0.0.1",
"private": true,
"type": "module",
"scripts": {
"dev": "astro dev --mode dev --host=0.0.0.0 --o-images=medium",
"start": "astro dev",
"build": "astro build",
"test:build": "astro build ; cd dist ; serve",
"preview": "astro preview",
"astro": "astro",
"generate-pwa-assets": "pwa-assets-generator --preset minimal-2023 public/logo.svg",
"test": "playwright test",
"test:lighthouse": "lighthouse https://polymech.io/en --output json --output html --output-path ./dist/reports/report.html --save-assets --chrome-flags=\"--window-size=1440,700 --headless\"",
"test:debug": "playwright test",
"test:ui": "playwright test --ui",
"clean": "rm -rf dist"
},
"dependencies": {
"@astrojs/compiler": "^2.10.4",
"@astrojs/mdx": "^4.1.0",
"@astrojs/react": "^4.2.1",
"@astrojs/rss": "^4.0.10",
"@astrojs/sitemap": "^3.2.1",
"@astrolib/seo": "^1.0.0-beta.8",
"@playwright/test": "^1.50.1",
"@polymech/cache": "file:../polymech-mono/packages/cache",
"@polymech/cad": "file:../polymech-mono/packages/cad",
"@polymech/commons": "file:../polymech-mono/packages/commons",
"@polymech/fs": "file:../polymech-mono/packages/fs",
"@polymech/i18n": "file:../polymech-mono/packages/i18n",
"@polymech/kbot-d": "file:../polymech-mono/packages/kbot",
"@polymech/log": "file:../polymech-mono/packages/log",
"@tailwindcss/forms": "^0.5.10",
"@tailwindcss/postcss": "^4.0.7",
"@tailwindcss/typography": "^0.5.12",
"@tailwindcss/vite": "^4.0.7",
"astro": "^5.4.0",
"autoprefixer": "^10.4.20",
"axios": "^1.7.9",
"cacache": "^19.0.1",
"exifreader": "^4.26.1",
"file-type": "^20.0.0",
"find-cache-dir": "^5.0.0",
"find-up": "^7.0.0",
"flowbite": "^3.1.2",
"github-slugger": "^2.0.0",
"glob": "^11.0.1",
"got": "^14.4.6",
"imagetools": "file:packages/imagetools",
"lighthouse": "^12.3.0",
"markdown-it": "^14.1.0",
"marked": "^15.0.7",
"mdast": "^2.3.2",
"mdast-util-from-markdown": "^2.0.2",
"mdast-util-to-markdown": "^2.1.2",
"mdast-util-to-string": "^4.0.0",
"mkdirp": "^3.0.1",
"node-xlsx": "^0.24.0",
"object-hash": "^3.0.0",
"p-map": "^7.0.3",
"picomatch": "^4.0.2",
"potrace": "^2.1.8",
"react-jsx-parser": "^2.3.0",
"rehype-stringify": "^10.0.1",
"remark": "^15.0.1",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.1.1",
"sanitize-html": "^2.14.0",
"schema-dts": "^1.1.2",
"sharp": "^0.29.3",
"showdown": "^2.1.0",
"tailwindcss": "^4.0.7",
"type-fest": "^4.34.1",
"vite": "^6.1.1",
"xlsx": "^0.18.5",
"yargs": "^17.7.2",
"zod": "^3.24.2"
},
"devDependencies": {
"@types/google-publisher-tag": "^1.20250210.0",
"micromark-util-sanitize-uri": "^2.0.1",
"normalize-url": "^8.0.1",
"sass-embedded": "^1.83.4"
}
}

View File

@ -1,10 +1,10 @@
export default {
"environment": "dev",
"environment": "build",
"isSsrBuild": false,
"projectBase": "",
"publicDir": "C:\\Users\\zx\\Desktop\\polymech\\polymech-site\\public\\",
"rootDir": "C:\\Users\\zx\\Desktop\\polymech\\polymech-site\\",
"mode": "dev",
"mode": "production",
"outDir": "dist",
"assetsDir": "/_astro",
"sourcemap": false,

View File

@ -1,8 +0,0 @@
# Changesets
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)

View File

@ -1,14 +0,0 @@
{
"$schema": "https://unpkg.com/@changesets/config@2.0.0/schema.json",
"changelog": [
"@changesets/changelog-github",
{ "repo": "astro-community/astro-embed" }
],
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": ["@astro-community/astro-embed-demo", "@astro-community/astro-embed-docs"]
}

View File

@ -1,12 +0,0 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = false
[{*.md,*.json,*.toml,*.yml,}]
indent_style = space

View File

@ -1,27 +0,0 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
env: {
node: true,
},
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'prettier'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
rules: {
// We don't want to leak logging into our user's console unless it's an error
'no-console': ['error', { allow: ['warn', 'error'] }],
'@typescript-eslint/no-explicit-any': ['warn'],
},
ignorePatterns: ['demo/dist/**', 'docs/dist/**'],
overrides: [
{
files: ['**/*.d.ts'],
rules: {
'@typescript-eslint/triple-slash-reference': 0,
},
},
],
};

View File

@ -1,49 +0,0 @@
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
# Automatically cancel in-progress actions on the same branch
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request_target' && github.head_ref || github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 20
cache: npm
- name: Install Dependencies
run: npm ci
- name: Test
run: npm t
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 20
cache: npm
- name: Install Dependencies
run: npm ci
- name: Lint
run: npm run lint

View File

@ -1,42 +0,0 @@
name: Release
on:
push:
branches:
- main
concurrency: ${{ github.workflow }}-${{ github.ref }}
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v2
with:
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
fetch-depth: 0
- name: Setup Node.js 20
uses: actions/setup-node@v2
with:
node-version: 20
- name: Cache node_modules
uses: actions/cache@v2
with:
path: ~/.npm
key: node-${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: node-${{ matrix.node }}-
- name: Install Dependencies
run: npm ci
- name: Create Release Pull Request
uses: changesets/action@v1
with:
publish: npx changeset publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@ -1,23 +0,0 @@
# build output
dist/
.output/
# astro files
.astro
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store

View File

@ -1 +0,0 @@
20

View File

@ -1,2 +0,0 @@
dist/
.changeset/

View File

@ -1,23 +0,0 @@
/** @type {import("@types/prettier").Options */
module.exports = {
printWidth: 80,
semi: true,
singleQuote: true,
tabWidth: 2,
trailingComma: 'es5',
plugins: ['./node_modules/prettier-plugin-astro'],
overrides: [
{
files: '*.astro',
options: {
parser: 'astro',
},
},
{
files: ['*.json', '*.md', '*.toml', '*.yml'],
options: {
useTabs: false,
},
},
],
};

View File

@ -1,91 +0,0 @@
# Contributing
👋 Hi there! Welcome! Thanks for your interest in contributing to `astro-embed`.
We welcome all kinds of contributions, from one-line bug fixes or updates to documentation, to adding entire new packages. Here is some guidance on getting involved.
## 🐛 Ew! A bug!
Its really helpful to know if you encounter a bug with any of the components in this repo. You can let us know by [opening a new issue on GitHub](https://github.com/delucis/astro-embed/issues/new/choose). (You might want to take a look at any [open issues](https://github.com/delucis/astro-embed/issues) first to see if anyone else has had the same problem.)
If you can see whats causing the bug, a pull request fixing it would be amazing.
## ✨ Adding a component
This is a community effort, so wed love for you to add an embed component for your favourite service. The aim is for the components here to be as lightweight and performant as possible. You can open an issue to discuss your idea if youre not sure exactly how to implement it.
If you think youre ready to go, lets get started.
### Create a package for your component
1. Each `astro-embed` component lives in a separate directory in the `packages` directory. Create a directory for your component:
```bash
mkdir packages/astro-embed-[SERVICE-NAME]
```
2. Create a `package.json` file in your new directory that looks something like this (replacing `[SERVICE-NAME]` with the website your embed is for, e.g. Twitter, YouTube, etc.).
```json
{
"name": "@astro-community/astro-embed-[SERVICE-NAME]",
"version": "0.0.1",
"description": "Component to easily embed [SERVICE-NAME] on your Astro site",
"type": "module",
"exports": {
".": "./index.ts",
"./matcher": "./matcher.ts"
},
"repository": {
"type": "git",
"url": "git+https://github.com/delucis/astro-embed.git"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/delucis/astro-embed/issues"
},
"homepage": "https://github.com/delucis/astro-embed/tree/main/packages/astro-embed-[SERVICE-NAME]#readme"
}
```
### Create your Astro component
Add an Astro component to your package and call it something understandable like `Tweet.astro` or `YouTube.astro`. This is the tricky bit — this parts down to you! This is normal Astro component, so you can import styles, node modules etc. just like you would inside an Astro project.
One important thing: to support auto-embeds using the Astro integration, well need access to a method that will extract an ID from a valid URL from the integration. The recommended way to do that is to create a `matcher.ts` file and export a function that converts a URL to an ID. You can import and use that in your component, but having it in a separate file helps us hook up the integration functionality more easily.
### Expose your component
In order for other projects to easily import your Astro component, we need to expose it to them.
To do this, create an `index.ts` file. It usually will look something like this:
```js
export { default as Tweet } from './Tweet.astro';
```
### Preview your component
While working, youll likely want to to see how — or if! — your component renders.
You can use the Astro project in the `/demo` directory to do this. Add a page to `/demo/src/pages` for your component and try using different props etc. to see how it responds.
Running `npm start` will start Astros development server for the demo project.
### Test your component
You can write tests to make sure the component is rendering as you expect. These will also be run in CI on GitHub, so you can be sure behaviour remains consistent as things change.
See the README in the `/tests` directory for more details on how to write tests.
### Document your component
Add a README file to your component package that shows how to use it. You can check out existing READMEs for the other components for inspiration.
### Add your plugin to the integration
Import your URL matcher function and add it and your component name to the `matchers` array in `astro-embed-integration/remark-plugin.ts`.
### Open a PR!
Wow, you made it this far! Open a pull request and lets get even more things embedded!

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2022 astro-community
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,39 +0,0 @@
# Astro Embed
Welcome! This project aims to collect easy-to-use and lightweight ways to embed common media into your [Astro](https://astro.build/) site.
## 📚 Documentation
Want to get started using some embed components?
Check out the [`astro-embed` documentation](https://astro-embed.netlify.app/)
## 🚀 Project Structure
This project uses a monorepo structure with a separate workspace for each embed type. Youll find a directory for each service in the [`/packages`](packages) directory.
The Astro site in the [`/demo`](demo) directory can be used to preview the various components and the files in [`/tests`](tests) are used to run automated testing on the components.
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :------------ | :-------------------------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm start` | Starts local dev server for the `demo` site at `localhost:3000` |
| `npm t` | Run the test suite |
## 🧪 Testing
You can run unit tests by running `npm t` in a terminal or run `npm start` to start a dev server for the demo project.
## ✨ Want to contribute?
This is an Astro Community project. That means YOU!
- 🛠 Want to build a missing component? [We have a guide for that.](CONTRIBUTING.md)
- 🐛 Found a bug? Open a [new issue](https://github.com/delucis/astro-embed/issues/new/choose) to let us know.
- 💬 Want to chat? Jump into [the Astro Discord server](https://astro.build/chat).

View File

@ -1,8 +0,0 @@
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import embed from 'astro-embed/integration';
// https://astro.build/config
export default defineConfig({
integrations: [embed(), mdx()],
});

View File

@ -1,15 +0,0 @@
{
"name": "@astro-community/astro-embed-demo",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview"
},
"devDependencies": {
"@astrojs/mdx": "^2.2.2",
"astro": "^4.16.3"
}
}

View File

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

View File

@ -1,27 +0,0 @@
---
export interface Props {
content?: { title?: string };
title?: string;
}
const { content, title = content?.title || 'Astro Embed Testbed' } =
Astro.props;
const { pathname } = Astro.url;
const isHome = pathname.length <= 1;
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>{title}</title>
</head>
<body>
<div style="max-width: 40em; margin: 0 auto;">
<h1>{title}</h1>
{!isHome && <a href="/">← Home</a>}
<slot />
</div>
</body>
</html>

View File

@ -1,59 +0,0 @@
---
import { BaselineStatus } from '@astro-community/astro-embed-baseline-status';
import Base from '../layouts/Base.astro';
---
<Base title="BaselineStatus component example">
<h2>Basics</h2>
<p>
<code>&lt;BaselineStatus id="anchor-positioning" /&gt;</code>
</p>
<BaselineStatus id="anchor-positioning" />
<p>
<code>&lt;BaselineStatus id="scroll-snap" /&gt;</code>
</p>
<BaselineStatus id="scroll-snap" />
<p>
<code>&lt;BaselineStatus id="masonry" /&gt;</code>
</p>
<BaselineStatus id="masonry" />
<p>
<code>&lt;BaselineStatus id="has" /&gt;</code>
</p>
<BaselineStatus id="has" />
<h2>Missing feature</h2>
<p>
<code>&lt;BaselineStatus id="rainbow-unicorns" /&gt;</code>
</p>
<BaselineStatus id="rainbow-unicorns" />
<h2>With custom styles</h2>
<div class="styled">
<p>
<code>&lt;BaselineStatus id="anchor-positioning" /&gt;</code>
</p>
<BaselineStatus id="anchor-positioning" />
<p>
<code>&lt;BaselineStatus id="has" /&gt;</code>
</p>
<BaselineStatus id="has" />
<p>
<code>&lt;BaselineStatus id="scroll-snap" /&gt;</code>
</p>
<BaselineStatus id="scroll-snap" />
</div>
</Base>
<style>
.styled :global(.baseline-status--limited::part(root)) {
--color-outline--light: hsl(40, 100%, 80%);
--color-background--light: hsl(40, 100%, 95%);
}
.styled :global(.baseline-status--newly::part(root)) {
--color-outline--light: hsl(200, 100%, 80%);
--color-background--light: hsl(200, 100%, 95%);
}
.styled :global(.baseline-status--widely::part(root)) {
--color-outline--light: hsl(120, 100%, 80%);
--color-background--light: hsl(120, 100%, 95%);
}
</style>

View File

@ -1,36 +0,0 @@
---
import { BlueskyPost } from '@astro-community/astro-embed-bluesky';
import Base from '../layouts/Base.astro';
import post from '../post.json';
---
<Base title="BlueskyPost component example">
<div class="content">
<BlueskyPost post={post.data} />
<p>Raw data</p>
<BlueskyPost
post="https://bsky.app/profile/wesbos.com/post/3la2ezdodvu2g"
/>
<p>Basic</p>
<BlueskyPost post="https://bsky.app/profile/mk.gg/post/3la2snrsnhd2a" />
<p>Images</p>
<BlueskyPost post="https://bsky.app/profile/mk.gg/post/3l7xzeex4vf2m" />
<p>External link</p>
<BlueskyPost
post="https://bsky.app/profile/wattenberger.com/post/3la54isd7az2i"
/>
<p>Video</p>
<BlueskyPost post="https://bsky.app/profile/mk.gg/post/3l7zx4hltw62a" />
<p>External media with quote</p>
<BlueskyPost post="https://bsky.app/profile/mk.gg/post/3la4wuiii4o2e" />
<p>External link with quote</p>
<BlueskyPost post="https://bsky.app/profile/sentry.io/post/3la5clrgyw52g" />
<p>Starter pack</p>
</div>
</Base>
<style>
/* Testing leaky styles */
.content :global(a) {
text-decoration: 1px solid underline;
}
</style>

View File

@ -1,51 +0,0 @@
---
import Base from '../layouts/Base.astro';
---
<Base>
<h2>Components</h2>
<ul>
<li>
<a href="/twitter"><code>&lt;Tweet/&gt;</code> component examples</a>
</li>
<li>
<a href="/vimeo"><code>&lt;Vimeo/&gt;</code> component examples</a>
</li>
<li>
<a href="/youtube"><code>&lt;YouTube/&gt;</code> component examples</a>
</li>
<li>
<a href="/link-preview"
><code>&lt;LinkPreview/&gt;</code> component examples</a
>
</li>
<li>
<a href="/baseline-status"
><code>&lt;BaselineStatus/&gt;</code> component examples</a
>
</li>
<li>
<a href="/bluesky"><code>&lt;BlueskyPost/&gt;</code> component examples</a
>
</li>
</ul>
<h2>Other examples</h2>
<ul>
<li>
<a href="/markdown">Components in MDX examples</a>
</li>
<li>
<a href="/integration">MDX integration examples</a>
</li>
<li>
<a href="/twitter-with-js">
<code>&lt;Tweet/&gt;</code> with JavaScript (Light theme)
</a>
</li>
<li>
<a href="/twitter-with-js-dark">
<code>&lt;Tweet/&gt;</code> with JavaScript (Dark theme)
</a>
</li>
</ul>
</Base>

View File

@ -1,27 +0,0 @@
---
title: MDX integration test
layout: ../layouts/Base.astro
---
This pages Markdown just contains URLs to items you might like to embed. The integration in `astro.config.mjs` automatically converts them to an embed:
```js
// astro.config.mjs
import { defineConfig } from 'astro/config';
import embeds from 'astro-embed/integration';
defineConfig({
integrations: [embeds()],
});
```
https://twitter.com/astrodotbuild/status/1511750228428435457
https://bsky.app/profile/antfu.me/post/3la5f4i4znh2c
https://vimeo.com/32001208
http://www.youtube.com/watch?v=Hoe-woAhq_k
https://astro.build/blog/welcome-world/

View File

@ -1,14 +0,0 @@
---
import { LinkPreview } from '@astro-community/astro-embed-link-preview';
import Base from '../layouts/Base.astro';
---
<Base title="LinkPreview component example">
<h2>Default</h2>
<p>
<code
>&lt;LinkPreview id="https://astro.build/blog/welcome-world/" /&gt;</code
>
</p>
<LinkPreview id="https://astro.build/blog/welcome-world/" />
</Base>

View File

@ -1,33 +0,0 @@
---
title: Components in MDX
layout: ../layouts/Base.astro
---
import { Tweet, YouTube, LinkPreview, BlueskyPost } from 'astro-embed';
The embeds on this page are imported as components in the MDX frontmatters `setup` block and then used in the document body.
```md
---
setup: |
import { Tweet, YouTube } from 'astro-embed';
---
<Tweet id="https://twitter.com/astrodotbuild/status/1511750228428435457" />
```
## `<Tweet />`
<Tweet id="https://twitter.com/astrodotbuild/status/1511750228428435457" />
## `<YouTube />`
<YouTube id="Hoe-woAhq_k" />
## `<LinkPreview />`
<LinkPreview id="https://astro.build/blog/welcome-world/" />
## `<BlueskyPost />`
<BlueskyPost id="https://bsky.app/profile/wesbos.com/post/3la2ezdodvu2g" />

View File

@ -1,44 +0,0 @@
---
import * as Component from 'astro-embed';
import Base from '../layouts/Base.astro';
---
<Base title="Twitter component examples with dark theme">
<p>
These tweets use the same component code as the <a href="/twitter"
>main Twitter example</a
>, but also loads Twitters widget JavaScript to convert them to interactive
iframes and use dark theme:
</p>
<pre><code set:text={'<script async src="https://platform.twitter.com/widgets.js"></script>'} /></pre>
<Component.Tweet
theme="dark"
id="https://twitter.com/astrodotbuild/status/1511750228428435457"
/>
<Component.Tweet
theme="dark"
id="https://twitter.com/astrodotbuild/status/1511380091720409095"
/>
<Component.Tweet
theme="dark"
id="https://twitter.com/astrodotbuild/status/1509917444403601409"
/>
<p class="center">…</p>
<Component.Tweet
theme="dark"
id="https://twitter.com/astrodotbuild/status/1402352777020395521"
/>
<script async src="https://platform.twitter.com/widgets.js"></script>
</Base>
<style>
body {
color-scheme: dark;
background-color: #101010;
color: #fff;
}
.center {
text-align: center;
}
</style>

View File

@ -1,35 +0,0 @@
---
import * as Component from 'astro-embed';
import Base from '../layouts/Base.astro';
---
<Base title="Twitter component examples">
<p>
These tweets use the same component code as the <a href="/twitter"
>main Twitter example</a
>, but also loads Twitters widget JavaScript to convert them to interactive
iframes:
</p>
<pre><code set:text={'<script async src="https://platform.twitter.com/widgets.js"></script>'} /></pre>
<Component.Tweet
id="https://twitter.com/astrodotbuild/status/1511750228428435457"
/>
<Component.Tweet
id="https://twitter.com/astrodotbuild/status/1511380091720409095"
/>
<Component.Tweet
id="https://twitter.com/astrodotbuild/status/1509917444403601409"
/>
<p class="center">…</p>
<Component.Tweet
id="https://twitter.com/astrodotbuild/status/1402352777020395521"
/>
<script async src="https://platform.twitter.com/widgets.js"></script>
</Base>
<style>
.center {
text-align: center;
}
</style>

View File

@ -1,31 +0,0 @@
---
import * as Component from 'astro-embed';
import Base from '../layouts/Base.astro';
---
<Base title="Twitter component examples">
<Component.Tweet
id="https://twitter.com/astrodotbuild/status/1511750228428435457"
/>
<Component.Tweet
id="https://twitter.com/astrodotbuild/status/1511380091720409095"
/>
<Component.Tweet
id="https://twitter.com/astrodotbuild/status/1509917444403601409"
/>
<p class="center">…</p>
<Component.Tweet
id="https://twitter.com/astrodotbuild/status/1402352777020395521"
/>
<h2>With x.com URLs</h2>
<Component.Tweet
id="https://x.com/astrodotbuild/status/1851286331491578330"
/>
</Base>
<style>
.center {
text-align: center;
}
</style>

View File

@ -1,40 +0,0 @@
---
import { Vimeo } from '@astro-community/astro-embed-vimeo';
import Base from '../layouts/Base.astro';
---
<Base title="Vimeo component examples">
<h2>With just the ID</h2>
<p><code>&lt;Vimeo id="32001208" /&gt;</code></p>
<Vimeo id="32001208" />
<h2>With a full vimeo.com URL</h2>
<p>
<code>&lt;Vimeo id="https://vimeo.com/32001208" /&gt;</code>
</p>
<Vimeo id="https://vimeo.com/32001208" />
<h2>With “www.” in the URL</h2>
<p>
<code>&lt;Vimeo id="https://www.vimeo.com/32001208" /&gt;</code>
</p>
<Vimeo id="https://www.vimeo.com/32001208" />
<h2>With custom parameters</h2>
<p>
<code
>&lt;Vimeo id="https://vimeo.com/32001208" params="color=ff0000&muted=1"
/&gt;</code
>
</p>
<Vimeo id="https://vimeo.com/32001208" params="color=ff0000&muted=1" />
<h2>With custom timestamp</h2>
<p>
<code
>&lt;Vimeo id="https://vimeo.com/32001208" params="color=00ff00#t=2m00s"
/&gt;</code
>
</p>
<Vimeo id="https://vimeo.com/32001208" params="color=00ff00#t=2m00s" />
</Base>

View File

@ -1,55 +0,0 @@
---
import { YouTube } from '@astro-community/astro-embed-youtube';
import Base from '../layouts/Base.astro';
---
<Base title="YouTube component examples">
<h2>With just the ID</h2>
<p><code>&lt;YouTube id="Hoe-woAhq_k" /&gt;</code></p>
<YouTube id="Hoe-woAhq_k" />
<h2>With a full youtube.com URL</h2>
<p>
<code
>&lt;YouTube
id="https://www.youtube.com/watch?v=-ExcBJrXOd8&ab_channel=Astro" /&gt;</code
>
</p>
<YouTube id="https://www.youtube.com/watch?v=-ExcBJrXOd8&ab_channel=Astro" />
<h2>With a youtu.be URL</h2>
<p>
<code>&lt;YouTube id="https://youtu.be/xtTy5nKay_Y" /&gt;</code>
</p>
<YouTube id="https://youtu.be/xtTy5nKay_Y" />
<h2>With an embed URL</h2>
<p>
<code>&lt;YouTube id="https://www.youtube.com/embed/2ZEMb_H-LYE" /&gt;</code
>
</p>
<YouTube id="https://www.youtube.com/embed/2ZEMb_H-LYE" />
<h2>With a custom poster image</h2>
<p>
<code
>&lt;YouTube id="Hoe-woAhq_k" poster="https://astro.build/social.png"
/&gt;</code
>
</p>
<YouTube id="Hoe-woAhq_k" poster="https://astro.build/social.png" />
<h2>With custom params</h2>
<p>
<code
>&lt;YouTube id="2ZEMb_H-LYE" params="start=2413&modestbranding=1" /&gt;</code
>
</p>
<YouTube id="2ZEMb_H-LYE" params="start=2413&modestbranding=1" />
<h2>With a custom accessible label</h2>
<p>
<code>&lt;YouTube id="2ZEMb_H-LYE" playlabel="Play the video" /&gt;</code>
</p>
<YouTube id="2ZEMb_H-LYE" playlabel="Play the video" />
</Base>

View File

@ -1,75 +0,0 @@
{
"id": "bafyreihqnx74v7vawq6nkao7ysljobitlq4j5lsvds7y7no5imhkhvmmee",
"data": {
"uri": "at://did:plc:uwbl4k3tza7eyjv3morkrld2/app.bsky.feed.post/3khyhd5tdi32t",
"cid": "bafyreihqnx74v7vawq6nkao7ysljobitlq4j5lsvds7y7no5imhkhvmmee",
"author": {
"did": "did:plc:uwbl4k3tza7eyjv3morkrld2",
"handle": "mk.gg",
"displayName": "Matt Kane",
"avatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:uwbl4k3tza7eyjv3morkrld2/bafkreic4mwsbm2tmuonamj4jq4kcjofk35bwics2f4oorp57f3cdfusjwu@jpeg",
"associated": {
"chat": {
"allowIncoming": "following"
}
},
"labels": [],
"createdAt": "2023-05-25T20:08:01.862Z"
},
"record": {
"$type": "app.bsky.feed.post",
"createdAt": "2024-01-02T09:42:47.992Z",
"embed": {
"$type": "app.bsky.embed.external",
"external": {
"description": "Live UK train departure boards",
"thumb": {
"$type": "blob",
"ref": {
"$link": "bafkreigtng2rcb2qkucgk2l53ow63f3rk5sraw3zlsde363pvyuf7hp7by"
},
"mimeType": "image/jpeg",
"size": 512514
},
"title": "Live Trains - UK railway times - Apps on Google Play",
"uri": "https://play.google.com/store/apps/details?id=live.departures.livetrains"
}
},
"facets": [
{
"features": [
{
"$type": "app.bsky.richtext.facet#link",
"uri": "https://play.google.com/store/apps/details?id=live.departures.livetrains"
}
],
"index": {
"byteEnd": 300,
"byteStart": 269
}
}
],
"langs": ["en"],
"text": "Happy New Year! My watch app has been approved. It's a live UK train times app for Wear OS with live departures, delays etc. No fancy extra features - just the stuff you need when heading to the station. I got a free Pixel Watch 2 when I bought my phone, so made this. play.google.com/store/apps/d..."
},
"embed": {
"$type": "app.bsky.embed.external#view",
"external": {
"uri": "https://play.google.com/store/apps/details?id=live.departures.livetrains",
"title": "Live Trains - UK railway times - Apps on Google Play",
"description": "Live UK train departure boards",
"thumb": "https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:uwbl4k3tza7eyjv3morkrld2/bafkreigtng2rcb2qkucgk2l53ow63f3rk5sraw3zlsde363pvyuf7hp7by@jpeg"
}
},
"replyCount": 0,
"repostCount": 0,
"likeCount": 0,
"quoteCount": 0,
"indexedAt": "2024-01-02T09:42:47.992Z",
"labels": []
},
"rendered": {
"html": "Happy New Year! My watch app has been approved. It&#39;s a live UK train times app for Wear OS with live departures, delays etc. No fancy extra features - just the stuff you need when heading to the station. I got a free Pixel Watch 2 when I bought my phone, so made this. <a href=\"https://play.google.com/store/apps/details?id=live.departures.livetrains\">play.google.com/store/apps/d...</a>"
},
"collection": "bluesky"
}

View File

@ -1,21 +0,0 @@
# build output
dist/
# generated types
.astro/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store

View File

@ -1,18 +0,0 @@
# Astro Embed docs
[![Built with Starlight](https://astro.badg.es/v2/built-with-starlight/tiny.svg)](https://starlight.astro.build)
This is the docs website for Astro Embed.
Content can be found in [`src/content/docs/`](./src/content/docs/).
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :---------------- | :------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:4321` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |

View File

@ -1,35 +0,0 @@
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import embeds from 'astro-embed/integration';
// https://astro.build/config
export default defineConfig({
site: 'https://astro-embed.netlify.app/',
integrations: [
embeds(),
starlight({
title: 'Astro Embed',
credits: true,
logo: {
light: './src/assets/logo-light.svg',
dark: './src/assets/logo-dark.svg',
replacesTitle: true,
},
social: {
github: 'https://github.com/delucis/astro-embed',
},
sidebar: [
{ label: 'Getting started', link: '/getting-started/' },
{
label: 'Components',
autogenerate: { directory: 'components' },
},
{ label: 'Auto-embed URLs', link: '/integration/' },
],
customCss: ['./src/assets/theme.css'],
components: {
Head: './src/overrides/Head.astro',
},
}),
],
});

View File

@ -1,5 +0,0 @@
import { pluginColorChips } from 'expressive-code-color-chips';
export default {
plugins: [pluginColorChips()],
};

View File

@ -1,21 +0,0 @@
{
"name": "@astro-community/astro-embed-docs",
"type": "module",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/starlight": "^0.24.0",
"astro": "^4.16.3",
"astro-og-canvas": "^0.4.2",
"expressive-code-color-chips": "^0.1.0",
"sharp": "^0.32.5",
"starlight-package-managers": "^0.4.0"
}
}

View File

@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M4.25 2A2.25 2.25 0 0 0 2 4.25v11.5A2.25 2.25 0 0 0 4.25 18h11.5A2.25 2.25 0 0 0 18 15.75V4.25A2.25 2.25 0 0 0 15.75 2zm4.03 6.28a.75.75 0 0 0-1.06-1.06L4.97 9.47a.75.75 0 0 0 0 1.06l2.25 2.25a.75.75 0 0 0 1.06-1.06L6.56 10zm4.5-1.06a.75.75 0 1 0-1.06 1.06L13.44 10l-1.72 1.72a.75.75 0 1 0 1.06 1.06l2.25-2.25a.75.75 0 0 0 0-1.06z" clip-rule="evenodd"/>
<style>path{fill:#a700c3}@media (prefers-color-scheme:dark){path{fill:#e3b6ed}}</style>
</svg>

Before

Width:  |  Height:  |  Size: 564 B

View File

@ -1,10 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -5 313 62">
<path fill="url(#a)" fill-rule="evenodd" d="M7.2.4A7.2 7.2 0 0 0 0 7.6v36.8a7.2 7.2 0 0 0 7.2 7.2H44a7.2 7.2 0 0 0 7.2-7.2V7.6A7.2 7.2 0 0 0 44 .4H7.2Zm12.9 20.1a2.4 2.4 0 0 0-3.4-3.4l-7.2 7.2a2.4 2.4 0 0 0 0 3.4l7.2 7.2a2.4 2.4 0 0 0 3.4-3.4L14.6 26l5.5-5.5Zm14.4-3.4a2.4 2.4 0 1 0-3.4 3.4l5.5 5.5-5.5 5.5a2.4 2.4 0 1 0 3.4 3.4l7.2-7.2a2.4 2.4 0 0 0 0-3.4l-7.2-7.2Z" clip-rule="evenodd"/>
<path fill="#E3B6ED" d="M67.8 38.84h2.08l8.88-25.76h4.56l8.88 25.76h2.08V41H83.84v-2.16h3.44l-2.24-6.68H74.92l-2.24 6.68h3.44V41H67.8v-2.16Zm7.76-8.96h8.84l-4.32-13.04h-.2l-4.32 13.04Zm29.61 11.6a6.18 6.18 0 0 1-3.31-.8 4.02 4.02 0 0 1-1.69-1.76h-.16V41h-3.03v-6.2H100v.72c0 1.12.35 2 1.05 2.64.69.64 1.8.96 3.36.96 2.88 0 4.31-1.01 4.31-3.04 0-1.57-1.04-2.61-3.12-3.12l-2.16-.52c-2.13-.5-3.71-1.28-4.75-2.32a5.78 5.78 0 0 1-1.56-4.28 5.5 5.5 0 0 1 1.96-4.52c1.3-1.07 3.04-1.6 5.2-1.6 1.33 0 2.4.23 3.2.68.8.45 1.31 1 1.56 1.64h.16V20.2h3.03v6.2h-3.03v-1.16c0-2.1-1.43-3.16-4.28-3.16a4.8 4.8 0 0 0-2.84.72c-.64.45-.96 1.15-.96 2.08 0 1.65 1.06 2.75 3.2 3.28l2.03.48c2.16.48 3.78 1.21 4.84 2.2 1.07.96 1.6 2.39 1.6 4.28 0 1.92-.69 3.47-2.08 4.64-1.36 1.15-3.2 1.72-5.56 1.72Zm17.5-.16c-1.53 0-2.6-.32-3.2-.96-.62-.64-.92-1.65-.92-3.04v-14.8h-2.72V20.2h.67c1 0 1.67-.17 2.05-.52.37-.35.67-.85.92-1.52l1.23-3.52h2.33v5.56h5v2.32h-5v16.2h5v1.76c-.46.21-1.2.4-2.2.56a17 17 0 0 1-3.16.28Zm8.05-2.48h2.72V23.4l-2.72-.52v-1.76l7.08-1.4v3.72h.2a5.98 5.98 0 0 1 1.72-2.56c.42-.35.9-.63 1.44-.84a5.24 5.24 0 0 1 1.88-.32c1.22 0 2.2.3 2.92.92.74.61 1.12 1.5 1.12 2.64 0 .9-.24 1.63-.72 2.16a2.4 2.4 0 0 1-1.88.76c-.83 0-1.48-.21-1.96-.64a2.28 2.28 0 0 1-.68-1.68c0-.45.1-.83.28-1.12.18-.32.41-.5.68-.56v-.12a.89.89 0 0 0-.28-.04 3.23 3.23 0 0 0-2 .36 5.4 5.4 0 0 0-2.24 2.44 3.5 3.5 0 0 0-.36 1.52v12.48h3.52V41h-10.72v-2.16Zm28.23.28c1.68 0 2.9-.52 3.68-1.56a6.65 6.65 0 0 0 1.2-4.16v-5.6c0-1.73-.4-3.12-1.2-4.16-.77-1.04-2-1.56-3.68-1.56-1.68 0-2.92.52-3.72 1.56a6.81 6.81 0 0 0-1.16 4.16v5.6c0 1.73.39 3.12 1.16 4.16.8 1.04 2.04 1.56 3.72 1.56Zm0 2.36c-1.46 0-2.8-.25-4-.76a8.71 8.71 0 0 1-3.08-2.16 9.98 9.98 0 0 1-2-3.4 14.38 14.38 0 0 1-.68-4.56 14 14 0 0 1 .68-4.52 9.92 9.92 0 0 1 2-3.44 8.71 8.71 0 0 1 3.08-2.16c1.2-.5 2.54-.76 4-.76 1.47 0 2.8.25 4 .76a8.7 8.7 0 0 1 5.04 5.6c.48 1.33.72 2.84.72 4.52 0 1.68-.24 3.2-.72 4.56a9.48 9.48 0 0 1-1.96 3.4 8.7 8.7 0 0 1-3.08 2.16c-1.2.5-2.53.76-4 .76Zm22.71-2.64h2.92v-23.6h-2.92v-2.16h21.36v7.04h-3.64v-4.68h-10.04v9.92h6.8v-2.84h2.64v8.04h-2.64v-2.84h-6.8v10.92h10.44v-5.2h3.64V41h-21.76v-2.16Zm25.78 0h2.72V23.4l-2.72-.52v-1.76l7.08-1.4v3.72h.2a5.6 5.6 0 0 1 1.92-2.56 6.19 6.19 0 0 1 1.68-.84 6.95 6.95 0 0 1 2.2-.32c1.78 0 3.18.33 4.2 1a5.01 5.01 0 0 1 2.16 3h.12a6.66 6.66 0 0 1 6.24-4c2.48 0 4.24.65 5.28 1.96 1.04 1.28 1.56 3.21 1.56 5.8v11.36h2.72V41h-9.76v-2.16h2.56V27.72c0-1.73-.34-3-1-3.8-.64-.8-1.64-1.2-3-1.2a5.14 5.14 0 0 0-2.92.92 3.46 3.46 0 0 0-1.32 2.8v12.4h2.56V41h-9.6v-2.16h2.56V27.72c0-1.73-.34-3-1-3.8-.64-.8-1.64-1.2-3-1.2a5.14 5.14 0 0 0-2.92.92 3.46 3.46 0 0 0-1.32 2.8v12.4h2.56V41h-9.76v-2.16Zm50.68 2.64a6.76 6.76 0 0 1-4-1.08 6.3 6.3 0 0 1-2.12-2.52h-.2L249.56 41h-1.96V14.28l-2.72-.52V12l7.2-1.4v12.72h.2a6.1 6.1 0 0 1 5.84-3.6 7.8 7.8 0 0 1 3.48.76 7 7 0 0 1 2.64 2.12c.72.93 1.28 2.08 1.68 3.44.4 1.33.6 2.85.6 4.56 0 1.7-.2 3.24-.6 4.6a10.4 10.4 0 0 1-1.68 3.4 7.38 7.38 0 0 1-2.64 2.16 8.2 8.2 0 0 1-3.48.72Zm-1.4-2.88a4.6 4.6 0 0 0 3.64-1.56c.9-1.04 1.36-2.48 1.36-4.32v-4.24c0-1.84-.46-3.28-1.36-4.32a4.59 4.59 0 0 0-3.64-1.56 5.52 5.52 0 0 0-3.24 1.04c-.43.35-.78.76-1.04 1.24a3.62 3.62 0 0 0-.36 1.64v8.16c0 .61.12 1.16.36 1.64a4 4 0 0 0 1.04 1.24c.45.35.94.61 1.48.8.56.16 1.14.24 1.76.24Zm23.36 2.88c-1.54 0-2.92-.25-4.12-.76a8.52 8.52 0 0 1-3.04-2.24 10.3 10.3 0 0 1-1.92-3.44 14.54 14.54 0 0 1-.64-4.44c0-1.65.23-3.15.68-4.48a10.36 10.36 0 0 1 1.96-3.4 8.67 8.67 0 0 1 3-2.2 9.17 9.17 0 0 1 3.84-.8c1.42 0 2.68.24 3.8.72a7.64 7.64 0 0 1 2.84 1.96c.8.85 1.42 1.88 1.84 3.08.43 1.2.64 2.53.64 4v1.08H275.2v1.28c0 2.08.52 3.7 1.56 4.84a5.45 5.45 0 0 0 4.2 1.68c1.55 0 2.8-.33 3.72-1a6.3 6.3 0 0 0 2.12-2.56l1.72 1.04c-.24.7-.6 1.37-1.08 2.04a7.8 7.8 0 0 1-1.72 1.8 9.3 9.3 0 0 1-2.44 1.32c-.93.32-2 .48-3.2.48Zm-4.88-13.04h9.12V28c0-1.92-.37-3.4-1.12-4.44-.72-1.07-1.84-1.6-3.36-1.6-1.49 0-2.64.52-3.44 1.56-.8 1.01-1.2 2.48-1.2 4.4v.52Zm25.95 13.04a8.2 8.2 0 0 1-3.48-.72 7.38 7.38 0 0 1-2.64-2.16 10.4 10.4 0 0 1-1.68-3.4c-.4-1.36-.6-2.9-.6-4.6 0-1.7.2-3.23.6-4.56.4-1.36.96-2.5 1.68-3.44a7 7 0 0 1 2.64-2.12c1.04-.5 2.2-.76 3.48-.76a6 6 0 0 1 5.84 3.6h.2v-9.04l-2.72-.52V12l7.2-1.4v27.2l2.72.52v1.76l-7.2 1.4v-3.6h-.2a6.1 6.1 0 0 1-5.84 3.6Zm1.4-2.88a4.66 4.66 0 0 0 3.2-1.04 3.55 3.55 0 0 0 1.44-2.88v-8.16a3.55 3.55 0 0 0-1.44-2.88 5.4 5.4 0 0 0-3.2-1.04 4.6 4.6 0 0 0-3.64 1.56c-.9 1.04-1.36 2.48-1.36 4.32v4.24c0 1.84.45 3.28 1.36 4.32a4.59 4.59 0 0 0 3.64 1.56Z"/>
<defs>
<linearGradient id="a" x1="15.1" x2="36.1" y1="1" y2="51" gradientUnits="userSpaceOnUse">
<stop stop-color="#D779EC"/>
<stop offset="1" stop-color="#fff"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -1,10 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -5 317 62">
<path fill="url(#a)" fill-rule="evenodd" d="M7.2.4A7.2 7.2 0 0 0 0 7.6v36.8a7.2 7.2 0 0 0 7.2 7.2H44a7.2 7.2 0 0 0 7.2-7.2V7.6A7.2 7.2 0 0 0 44 .4H7.2Zm12.9 20.1a2.4 2.4 0 0 0-3.4-3.4l-7.2 7.2a2.4 2.4 0 0 0 0 3.4l7.2 7.2a2.4 2.4 0 0 0 3.4-3.4L14.6 26l5.5-5.5Zm14.4-3.4a2.4 2.4 0 1 0-3.4 3.4l5.5 5.5-5.5 5.5a2.4 2.4 0 1 0 3.4 3.4l7.2-7.2a2.4 2.4 0 0 0 0-3.4l-7.2-7.2Z" clip-rule="evenodd"/>
<path fill="#A700C3" d="M67.8 38.84h2.08l8.88-25.76h4.56l8.88 25.76h2.08V41H83.84v-2.16h3.44l-2.24-6.68H74.92l-2.24 6.68h3.44V41H67.8v-2.16Zm7.76-8.96h8.84l-4.32-13.04h-.2l-4.32 13.04Zm29.61 11.6a6.18 6.18 0 0 1-3.31-.8 4.02 4.02 0 0 1-1.69-1.76h-.16V41h-3.03v-6.2H100v.72c0 1.12.35 2 1.05 2.64.69.64 1.8.96 3.36.96 2.88 0 4.31-1.01 4.31-3.04 0-1.57-1.04-2.61-3.12-3.12l-2.16-.52c-2.13-.5-3.71-1.28-4.75-2.32a5.78 5.78 0 0 1-1.56-4.28 5.5 5.5 0 0 1 1.96-4.52c1.3-1.07 3.04-1.6 5.2-1.6 1.33 0 2.4.23 3.2.68.8.45 1.31 1 1.56 1.64h.16V20.2h3.03v6.2h-3.03v-1.16c0-2.1-1.43-3.16-4.28-3.16a4.8 4.8 0 0 0-2.84.72c-.64.45-.96 1.15-.96 2.08 0 1.65 1.06 2.75 3.2 3.28l2.03.48c2.16.48 3.78 1.21 4.84 2.2 1.07.96 1.6 2.39 1.6 4.28 0 1.92-.69 3.47-2.08 4.64-1.36 1.15-3.2 1.72-5.56 1.72Zm17.5-.16c-1.53 0-2.6-.32-3.2-.96-.62-.64-.92-1.65-.92-3.04v-14.8h-2.72V20.2h.67c1 0 1.67-.17 2.05-.52.37-.35.67-.85.92-1.52l1.23-3.52h2.33v5.56h5v2.32h-5v16.2h5v1.76c-.46.21-1.2.4-2.2.56a17 17 0 0 1-3.16.28Zm8.05-2.48h2.72V23.4l-2.72-.52v-1.76l7.08-1.4v3.72h.2a5.98 5.98 0 0 1 1.72-2.56c.42-.35.9-.63 1.44-.84a5.24 5.24 0 0 1 1.88-.32c1.22 0 2.2.3 2.92.92.74.61 1.12 1.5 1.12 2.64 0 .9-.24 1.63-.72 2.16a2.4 2.4 0 0 1-1.88.76c-.83 0-1.48-.21-1.96-.64a2.28 2.28 0 0 1-.68-1.68c0-.45.1-.83.28-1.12.18-.32.41-.5.68-.56v-.12a.89.89 0 0 0-.28-.04 3.23 3.23 0 0 0-2 .36 5.4 5.4 0 0 0-2.24 2.44 3.5 3.5 0 0 0-.36 1.52v12.48h3.52V41h-10.72v-2.16Zm28.23.28c1.68 0 2.9-.52 3.68-1.56a6.65 6.65 0 0 0 1.2-4.16v-5.6c0-1.73-.4-3.12-1.2-4.16-.77-1.04-2-1.56-3.68-1.56-1.68 0-2.92.52-3.72 1.56a6.81 6.81 0 0 0-1.16 4.16v5.6c0 1.73.39 3.12 1.16 4.16.8 1.04 2.04 1.56 3.72 1.56Zm0 2.36c-1.46 0-2.8-.25-4-.76a8.71 8.71 0 0 1-3.08-2.16 9.98 9.98 0 0 1-2-3.4 14.38 14.38 0 0 1-.68-4.56 14 14 0 0 1 .68-4.52 9.92 9.92 0 0 1 2-3.44 8.71 8.71 0 0 1 3.08-2.16c1.2-.5 2.54-.76 4-.76 1.47 0 2.8.25 4 .76a8.7 8.7 0 0 1 5.04 5.6c.48 1.33.72 2.84.72 4.52 0 1.68-.24 3.2-.72 4.56a9.48 9.48 0 0 1-1.96 3.4 8.7 8.7 0 0 1-3.08 2.16c-1.2.5-2.53.76-4 .76Zm22.71-2.64h2.92v-23.6h-2.92v-2.16h21.36v7.04h-3.64v-4.68h-10.04v9.92h6.8v-2.84h2.64v8.04h-2.64v-2.84h-6.8v10.92h10.44v-5.2h3.64V41h-21.76v-2.16Zm25.78 0h2.72V23.4l-2.72-.52v-1.76l7.08-1.4v3.72h.2a5.6 5.6 0 0 1 1.92-2.56 6.19 6.19 0 0 1 1.68-.84 6.95 6.95 0 0 1 2.2-.32c1.78 0 3.18.33 4.2 1a5.01 5.01 0 0 1 2.16 3h.12a6.66 6.66 0 0 1 6.24-4c2.48 0 4.24.65 5.28 1.96 1.04 1.28 1.56 3.21 1.56 5.8v11.36h2.72V41h-9.76v-2.16h2.56V27.72c0-1.73-.34-3-1-3.8-.64-.8-1.64-1.2-3-1.2a5.14 5.14 0 0 0-2.92.92 3.46 3.46 0 0 0-1.32 2.8v12.4h2.56V41h-9.6v-2.16h2.56V27.72c0-1.73-.34-3-1-3.8-.64-.8-1.64-1.2-3-1.2a5.14 5.14 0 0 0-2.92.92 3.46 3.46 0 0 0-1.32 2.8v12.4h2.56V41h-9.76v-2.16Zm50.68 2.64a6.76 6.76 0 0 1-4-1.08 6.3 6.3 0 0 1-2.12-2.52h-.2L249.56 41h-1.96V14.28l-2.72-.52V12l7.2-1.4v12.72h.2a6.1 6.1 0 0 1 5.84-3.6 7.8 7.8 0 0 1 3.48.76 7 7 0 0 1 2.64 2.12c.72.93 1.28 2.08 1.68 3.44.4 1.33.6 2.85.6 4.56 0 1.7-.2 3.24-.6 4.6a10.4 10.4 0 0 1-1.68 3.4 7.38 7.38 0 0 1-2.64 2.16 8.2 8.2 0 0 1-3.48.72Zm-1.4-2.88a4.6 4.6 0 0 0 3.64-1.56c.9-1.04 1.36-2.48 1.36-4.32v-4.24c0-1.84-.46-3.28-1.36-4.32a4.59 4.59 0 0 0-3.64-1.56 5.52 5.52 0 0 0-3.24 1.04c-.43.35-.78.76-1.04 1.24a3.62 3.62 0 0 0-.36 1.64v8.16c0 .61.12 1.16.36 1.64a4 4 0 0 0 1.04 1.24c.45.35.94.61 1.48.8.56.16 1.14.24 1.76.24Zm23.36 2.88c-1.54 0-2.92-.25-4.12-.76a8.52 8.52 0 0 1-3.04-2.24 10.3 10.3 0 0 1-1.92-3.44 14.54 14.54 0 0 1-.64-4.44c0-1.65.23-3.15.68-4.48a10.36 10.36 0 0 1 1.96-3.4 8.67 8.67 0 0 1 3-2.2 9.17 9.17 0 0 1 3.84-.8c1.42 0 2.68.24 3.8.72a7.64 7.64 0 0 1 2.84 1.96c.8.85 1.42 1.88 1.84 3.08.43 1.2.64 2.53.64 4v1.08H275.2v1.28c0 2.08.52 3.7 1.56 4.84a5.45 5.45 0 0 0 4.2 1.68c1.55 0 2.8-.33 3.72-1a6.3 6.3 0 0 0 2.12-2.56l1.72 1.04c-.24.7-.6 1.37-1.08 2.04a7.8 7.8 0 0 1-1.72 1.8 9.3 9.3 0 0 1-2.44 1.32c-.93.32-2 .48-3.2.48Zm-4.88-13.04h9.12V28c0-1.92-.37-3.4-1.12-4.44-.72-1.07-1.84-1.6-3.36-1.6-1.49 0-2.64.52-3.44 1.56-.8 1.01-1.2 2.48-1.2 4.4v.52Zm25.95 13.04a8.2 8.2 0 0 1-3.48-.72 7.38 7.38 0 0 1-2.64-2.16 10.4 10.4 0 0 1-1.68-3.4c-.4-1.36-.6-2.9-.6-4.6 0-1.7.2-3.23.6-4.56.4-1.36.96-2.5 1.68-3.44a7 7 0 0 1 2.64-2.12c1.04-.5 2.2-.76 3.48-.76a6 6 0 0 1 5.84 3.6h.2v-9.04l-2.72-.52V12l7.2-1.4v27.2l2.72.52v1.76l-7.2 1.4v-3.6h-.2a6.1 6.1 0 0 1-5.84 3.6Zm1.4-2.88a4.66 4.66 0 0 0 3.2-1.04 3.55 3.55 0 0 0 1.44-2.88v-8.16a3.55 3.55 0 0 0-1.44-2.88 5.4 5.4 0 0 0-3.2-1.04 4.6 4.6 0 0 0-3.64 1.56c-.9 1.04-1.36 2.48-1.36 4.32v4.24c0 1.84.45 3.28 1.36 4.32a4.59 4.59 0 0 0 3.64 1.56Z"/>
<defs>
<linearGradient id="a" x1="15.14" x2="36.06" y1=".97" y2="51.03" gradientUnits="userSpaceOnUse">
<stop stop-color="#50005D"/>
<stop offset="1" stop-color="#A700C3"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

View File

@ -1,44 +0,0 @@
/* Dark mode colors. */
:root {
--sl-color-accent-low: #36113e;
--sl-color-accent: #a400c0;
--sl-color-accent-high: #e3b6ed;
--sl-color-white: #ffffff;
--sl-color-gray-1: #efecf2;
--sl-color-gray-2: #c3c0c7;
--sl-color-gray-3: #8e8996;
--sl-color-gray-4: #5b5561;
--sl-color-gray-5: #3a3641;
--sl-color-gray-6: #29242f;
--sl-color-black: #19171c;
--tc-border-color: var(--sl-color-gray-5);
}
/* Light mode colors. */
:root[data-theme='light'] {
--sl-color-accent-low: #ebc9f3;
--sl-color-accent: #a700c3;
--sl-color-accent-high: #4e0e5b;
--sl-color-white: #19171c;
--sl-color-gray-1: #29242f;
--sl-color-gray-2: #3a3641;
--sl-color-gray-3: #5b5561;
--sl-color-gray-4: #8e8996;
--sl-color-gray-5: #c3c0c7;
--sl-color-gray-6: #efecf2;
--sl-color-gray-7: #f7f6f8;
--sl-color-black: #ffffff;
}
main {
font-family: Charter, 'Bitstream Charter', 'Sitka Text', Cambria, serif;
text-underline-offset: 0.25em;
}
.hero .tagline {
text-wrap: balance;
}
.hero > img {
filter: drop-shadow(0 0 8rem var(--sl-color-accent));
}

View File

@ -1,13 +0,0 @@
import { defineCollection, z } from 'astro:content';
import { docsSchema } from '@astrojs/starlight/schema';
export const collections = {
docs: defineCollection({
schema: docsSchema({
extend: z.object({
// Require a description for every page.
description: z.string(),
}),
}),
}),
};

View File

@ -1,22 +0,0 @@
---
import { BaselineStatus } from '@astro-community/astro-embed-baseline-status';
---
<div class="styled-baseline">
<BaselineStatus id="anchor-positioning" />
</div>
<style>
.styled-baseline :global(.baseline-status::part(root)) {
color-scheme: light;
background: floralwhite;
color: darkblue;
font-family: fantasy;
border: 1px dashed;
}
.styled-baseline :global(.baseline-status::part(feature-name)) {
color: purple;
font-weight: bold;
}
</style>

View File

@ -1,19 +0,0 @@
---
import { BaselineStatus } from '@astro-community/astro-embed-baseline-status';
import type { ComponentProps } from 'astro/types';
export type Props = ComponentProps<typeof BaselineStatus>;
---
<div class="styled-baseline">
<BaselineStatus {...Astro.props} />
</div>
<style>
.styled-baseline :global(.baseline-status--widely::part(root)) {
--color-outline--light: hsl(120, 100%, 80%);
--color-background--light: hsl(120, 100%, 95%);
--color-outline--dark: hsl(120, 100%, 20%);
--color-background--dark: hsl(120, 100%, 5%);
}
</style>

View File

@ -1,23 +0,0 @@
---
import { LinkPreview } from '@astro-community/astro-embed-link-preview';
---
<div class="styled-preview">
<LinkPreview id="https://astro-embed.netlify.app/" />
</div>
<style>
.styled-preview :global(.link-preview) {
--link-preview-corners: 0.5em;
--link-preview-padding-inline: 0.75rem;
background-color: floralwhite;
color: darkblue;
font-family: sans-serif;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}
.styled-preview :global(.link-preview a) {
color: purple;
font-weight: bold;
text-decoration: none;
}
</style>

View File

@ -1,22 +0,0 @@
---
import { Tweet } from '@astro-community/astro-embed-twitter';
---
<div class="styled-tweet">
<Tweet id="https://twitter.com/astrodotbuild/status/1767605560671969619" />
</div>
<style>
.styled-tweet :global(.twitter-tweet) {
background: floralwhite;
color: darkblue;
font-family: cursive;
font-size: 1.25rem;
border: 0;
}
.styled-tweet :global(.twitter-tweet a) {
color: purple;
font-weight: bold;
}
</style>

View File

@ -1,243 +0,0 @@
---
title: Baseline Status
description: Learn how to display the Baseline status of a web feature in your website
---
import { Tabs, TabItem } from '@astrojs/starlight/components';
import { BaselineStatus } from '@astro-community/astro-embed-baseline-status';
The `<BaselineStatus>` component displays browser support for a given web feature according to the [Baseline](https://web.dev/baseline/) project.
This component is based on the [official `<baseline-status>` custom element](https://github.com/web-platform-dx/baseline-status), but avoids using any client-side JavaScript.
## Usage
<Tabs>
<TabItem label="Astro" icon="astro">
```astro
---
import { BaselineStatus } from 'astro-embed';
---
<BaselineStatus id="scroll-snap" />
````
</TabItem>
<TabItem label="MDX" icon="seti:markdown">
```mdx
import { BaselineStatus } from 'astro-embed';
<BaselineStatus id="scroll-snap" />
````
</TabItem>
</Tabs>
The above code produces the following result:
<BaselineStatus id="scroll-snap" />
### The `id` attribute
The `<BaselineStatus>` component requires an `id` attribute which sets the web feature to display browser support data for.
This ID is the slug of the feature as stored in the [`web-platform-dx/web-features`](https://github.com/web-platform-dx/web-features) repository.
The [Web Platform Status](https://webstatus.dev/) site is also a helpful place to search for feature IDs.
For example, the ID for the CSS `:has()` selector is `"has"`:
```astro 'id="has"'
<BaselineStatus id="has" />
```
<BaselineStatus id="has" />
If the ID does not match a known web feature, the component will still render, but display an unknown availability. For example, with an ID of `"rainbow-unicorns"`:
<BaselineStatus id="rainbow-unicorns" />
## Styling the component
Due to its relatively complex layout and content, the `<BaselineStatus>` component uses [Declarative Shadow DOM](https://web.dev/articles/declarative-shadow-dom) to isolate its markup from your sites styles.
You can override the default styles using the [`::part()` pseudo-element](https://developer.mozilla.org/en-US/docs/Web/CSS/::part).
```css
.baseline-status::part(root) {
color-scheme: light;
background: floralwhite;
color: darkblue;
font-family: fantasy;
border: 1px dashed;
}
.baseline-status::part(feature-name) {
color: purple;
font-weight: bold;
}
```
The above styles would render `<BaselineStatus>` like this:
import StyledBaseline from './_examples/StyledBaseline.astro';
<StyledBaseline />
### Light/dark theming support
The default styles make a best effort to adapt automatically to a sites color theme.
By default, text color is inherited from the document styles and the component has a transparent background. Colors used in iconography adapt to the users color scheme preference using a `prefers-color-scheme` media query.
In browsers that support the [`light-dark()` CSS function](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/light-dark), if your site sets the correct `color-scheme` values, `<BaselineStatus>` will adapt to match the current theme even if it does not match system-level color scheme preferences.
<BaselineStatus id="light-dark" />
#### Supporting a custom theme picker
If your site uses a theme picker to set the current theme and you need to support older browsers, you can add custom styles to control the color variables `<BaselineStatus>` uses.
For example, if you use a `data-theme="dark"` attribute to enable dark mode on your site, configure colors when that is set:
```css
[data-theme='dark'] .baseline-status::part(root) {
--color-limited: var(--color-limited--dark);
--color-newly: var(--color-newly--dark);
--color-widely: var(--color-widely--dark);
/* ... */
}
```
See [“Custom properties API”](#custom-properties-api) below for a full list of available variables.
### Custom properties API
The `<BaselineStatus>` component supports the following API for controlling its styles with CSS custom properties.
```css
.baseline-status::part(root) {
/* Light color scheme */
--color-outline--light: #d9d9d9;
--color-background--light: transparent;
--color-text--light: inherit;
--color-link--light: #1a73e8;
--color-badge-background--light: #3367d6;
--color-badge-text--light: #fff;
--color-limited--light: #ea8600;
--color-limited-secondary--light: #c6c6c6;
--color-widely--light: #1e8e3e;
--color-widely-secondary--light: #c4eed0;
--color-newly--light: #1a73e8;
--color-newly-secondary--light: #a8c7fa;
--color-no_data--light: #707070;
--color-no_data-secondary--light: #909090;
/* Dark color scheme */
--color-outline--dark: #d9d9d9;
--color-background--dark: transparent;
--color-text--dark: inherit;
--color-link--dark: #5aa1ff;
--color-badge-background--dark: #3367d6;
--color-badge-text--dark: #fff;
--color-limited--dark: #f09418;
--color-limited-secondary--dark: #565656;
--color-widely--dark: #24a446;
--color-widely-secondary--dark: #125225;
--color-newly--dark: #4185ff;
--color-newly-secondary--dark: #2d509e;
--color-no_data--dark: #868686;
--color-no_data-secondary--dark: #666666;
}
```
### CSS class names API
The root element of the `<BaselineStatus>` component can be targeted using the `.baseline-status` selector.
In addition, the following variant class names are applied and can be used to customise appearance for the different Baseline status levels:
- `.baseline-status--limited`: applied if the feature has limited availability
- `.baseline-status--newly`: applied if the feature is newly available
- `.baseline-status--widely`: applied if the feature is widely available
- `.baseline-status--no_data`: applied if there is no data available for the feature
For example, you could use these to display custom colors only for widely available features:
```css
.baseline-status--widely::part(root) {
--color-outline--light: hsl(120, 100%, 80%);
--color-background--light: hsl(120, 100%, 95%);
--color-outline--dark: hsl(120, 100%, 20%);
--color-background--dark: hsl(120, 100%, 5%);
}
```
import BaselineVariants from './_examples/StyledBaselineVariants.astro';
<BaselineVariants id="cascade-layers" />
### Component parts API
The following component parts are exposed to set custom styles in your CSS.
#### `::part(root)`
Selects the wrapper at the base of the component.
Particularly useful for setting CSS variables that impact component styles.
#### `::part(feature-name)`
The name of the feature support information is being displayed for.
#### `::part(details)`
The `<details>` element.
#### `::part(summary)`
The `<summary>` element.
#### `::part(summary-content)`
The main content of the `<summary>` element. This includes the visible text (`summary-label`) and browser icons (`browsers`), but excludes the Baseline icon and disclosure caret (`caret`).
#### `::part(summary-label)`
Element specifying the global support level in the `<summary>`, e.g. text reading “Baseline: Widely available” or “Limited availability”.
#### `::part(badge)`
Badge element added to highlight newly available Baseline features.
#### `::part(browsers)`
Wrapper element around the browser support icons.
#### `::part(browser-support)`
A browser support lockup, including browser logo, support level icon, and accessible text label.
#### `::part(browser-support-label)`
Accessible text label for browser support, visually hidden by default.
#### `::part(caret)`
The disclosure caret displayed instead of the default `<details>` marker.
#### `::part(description)`
The detailed description of the support level visible when the component is expanded.
#### `::part(link)`
The link element visible when the component is expanded.
## Standalone installation
If you only need the `<BaselineStatus>` component, you can install the package directly instead of the main `astro-embed` package:
import { PackageManagers } from 'starlight-package-managers';
<PackageManagers pkg="@astro-community/astro-embed-baseline-status" />
The `<BaselineStatus>` component can then be imported as:
```js
import { BaselineStatus } from '@astro-community/astro-embed-baseline-status';
```

View File

@ -1,87 +0,0 @@
---
title: Bluesky Post
description: Learn how to use the Astro Embed BlueskyPost component to embed Bluesky posts in your website
---
import { Tabs, TabItem } from '@astrojs/starlight/components';
import { BlueskyPost } from '@astro-community/astro-embed-bluesky';
The `<BlueskyPost>` component embeds Bluesky posts in Astro projects.
## Usage
The `<BlueskyPost>` component generates a static HTML embed for a single Bluesky post. The HTML is designed to match the appearance of [the Bluesky Embed](https://embed.bsky.app/), but without any client-side JavaScript.
<Tabs>
<TabItem label="Astro" icon="astro">
```astro
---
import { BlueskyPost } from 'astro-embed';
---
<BlueskyPost id="https://bsky.app/profile/mk.gg/post/3la4wqeyztm2u" />
````
</TabItem>
<TabItem label="MDX" icon="seti:markdown">
```mdx
import { BlueskyPost } from 'astro-embed';
<BlueskyPost id="https://bsky.app/profile/mk.gg/post/3la4wqeyztm2u" />
````
</TabItem>
</Tabs>
The above code produces the following result:
<div>
<BlueskyPost id="https://bsky.app/profile/mk.gg/post/3la4wqeyztm2u" />
</div>
The `id` argument is either a Bluesky post URL, or an `at://` URI. These will be loaded using the Bluesky API at build time. You can also pass a `post` object, which will be used directly. You can load the post using [the Bluesky API](https://docs.bsky.app/docs/get-started), or use a post object from [the Astro Bluesky content loader](https://www.npmjs.com/package/@ascorbic/bluesky-loader).
```astro
---
import { getCollection } from 'astro:content';
import { BlueskyPost } from 'astro-embed';
const posts = await getCollection('posts');
---
{posts.map((post) => <BlueskyPost post={post.data} />)}
```
It supports various types of embedded media, including images, videos, starter packs and lists. It can also handle quoted posts and replies. These are all displayed as static HTML, so videos etc are links to the original content.
Some examples:
<div>
<BlueskyPost id="https://bsky.app/profile/astro.build/post/3la7gw63tfn26" />
</div>
<div>
<BlueskyPost id="https://bsky.app/profile/mk.gg/post/3la2snrsnhd2a" />
</div>
<div>
<BlueskyPost id="https://bsky.app/profile/fujino.dev/post/3la2llq5x2y2q" />
</div>
<div>
<BlueskyPost id="https://bsky.app/profile/dierkens.dev/post/3la2wzxzixe2c" />
</div>
## Standalone installation
If you only need the `<BlueskyPost>` component, you can install the package directly instead of the main `astro-embed` package:
import { PackageManagers } from 'starlight-package-managers';
<PackageManagers pkg="@astro-community/astro-embed-bluesky" />
The `<BlueskyPost>` component can then be imported as:
```js
import { BlueskyPost } from '@astro-community/astro-embed-bluesky';
```

View File

@ -1,134 +0,0 @@
---
title: Link Preview
description: Learn how to use the Astro Embed link preview component to embed Open Graph images and metadata in your website
---
import { Tabs, TabItem } from '@astrojs/starlight/components';
import { LinkPreview } from '@astro-community/astro-embed-link-preview';
The `<LinkPreview>` component embeds the Open Graph media and metadata for a URL in your page.
## Usage
<Tabs>
<TabItem label="Astro" icon="astro">
```astro
---
import { LinkPreview } from 'astro-embed';
---
<LinkPreview id="https://astro.build/blog/welcome-world/" />
````
</TabItem>
<TabItem label="MDX" icon="seti:markdown">
```mdx
import { LinkPreview } from 'astro-embed';
<LinkPreview id="https://astro.build/blog/welcome-world/" />
````
</TabItem>
</Tabs>
The above code produces the following result:
<LinkPreview id="https://astro.build/blog/welcome-world/" />
### Video metadata
If a URLs tags include `og:video` metadata, `<LinkPreview>` will render a video player instead of an image.
```astro
<LinkPreview id="https://fosstodon.org/@mikeneu/112123823339364565" />
```
The above code produces the following result:
<LinkPreview id="https://fosstodon.org/@mikeneu/112123823339364565" />
### Hiding media
If a URL's image or video is unwanted, add `hideMedia` as a prop.
```astro
<LinkPreview id="https://fosstodon.org/@mikeneu/112123823339364565" hideMedia />
```
The above code produces the following result:
<LinkPreview id="https://fosstodon.org/@mikeneu/112123823339364565" hideMedia />
### Limitations
The available Open Graph metadata varies from site to site.
If a site doesnt provide `og:image` metadata, no image will be displayed, only the page title and description.
If no title is detected or the metadata collection step fails, `<LinkPreview>` will display only the original link URL.
## Styling the preview
By default the `<LinkPreview>` card has some minimal layout styling, which should adapt to your sites font settings etc.
You can customise it with CSS by targeting the `.link-preview` class, for example:
```css
.link-preview {
--link-preview-corners: 0.5em;
--link-preview-padding-inline: 0.75rem;
background-color: floralwhite;
color: darkblue;
font-family: sans-serif;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}
.link-preview a {
color: purple;
font-weight: bold;
text-decoration: none;
}
```
The above styles would render `<LinkPreview>` like this:
import StyledPreview from './_examples/StyledLinkPreview.astro';
<StyledPreview />
### Custom properties API
The `<LinkPreview>` component supports the following API for controlling its styles with CSS custom properties.
```css
:root {
/** Set the maximum width of the link preview. */
--link-preview-width: 30em;
/** Set the inline padding of the card text. */
--link-preview-padding-inline: 1em;
/** Set the vertical padding around the card text. */
--link-preview-padding-block: 0.5em;
/** Round the corners of the link preview card. */
--link-preview-corners: 0.5em;
/** Set the maximum number of lines in the description to display. */
--link-preview-description-lines: 3;
}
```
### CSS class names API
- `.link-preview`: The root element of the `<LinkPreview>` card.
- `.link-preview--has-video`: Class applied to the card when it includes video instead of an image.
- `.link-preview--no-media`: Class applied to the card when it includes no image or video.
- `.link-preview--no-metadata`: Class applied when metadata scraping failed, or no valid title was found. In this case the only contents of the card is the original URL link.
## Standalone installation
If you only need the `<LinkPreview>` component, you can install the package directly instead of the main `astro-embed` package:
import { PackageManagers } from 'starlight-package-managers';
<PackageManagers pkg="@astro-community/astro-embed-link-preview" />
The `<LinkPreview>` component can then be imported as:
```js
import { LinkPreview } from '@astro-community/astro-embed-link-preview';
```

View File

@ -1,126 +0,0 @@
---
title: Tweet
description: Learn how to use the Astro Embed Tweet component to embed Twitter posts in your website
---
import { Tabs, TabItem } from '@astrojs/starlight/components';
import { Tweet } from '@astro-community/astro-embed-twitter';
The `<Tweet>` component embeds posts to Twitter (also known as X) in Astro projects.
## Usage
The `<Tweet>` component generates a static Twitter card for a single Tweet using [Twitters oEmbed API](https://developer.twitter.com/en/docs/twitter-for-websites/oembed-api).
<Tabs>
<TabItem label="Astro" icon="astro">
```astro
---
import { Tweet } from 'astro-embed';
---
<Tweet id="https://twitter.com/astrodotbuild/status/1511750228428435457" />
```
</TabItem>
<TabItem label="MDX" icon="seti:markdown">
```mdx
import { Tweet } from 'astro-embed';
<Tweet id="https://twitter.com/astrodotbuild/status/1511750228428435457" />
```
</TabItem>
</Tabs>
The above code produces the following result:
<div>
<Tweet id="https://twitter.com/astrodotbuild/status/1511750228428435457" />
</div>
:::note
The `<Tweet>` component styles are intentionally minimal.
They will match the font styles of your surrounding content. See [“Styling the Tweet component”](#styling-the-tweet-component) below for more details.
:::
## Loading Twitters JavaScript
By design, `<Tweet>` is a minimal component and loads zero JavaScript, only rendering some static HTML content.
However, this HTML is compatible with Twitters widget system.
Loading Twitters large bundle of widget JavaScript will convert each `<Tweet>` into an interactive embed.
You can do this by including the following `<script>` tag in your Astro layout file:
```html
<script async src="https://platform.twitter.com/widgets.js"></script>
```
[See an example of `<Tweet>` with Twitters JavaScript](/examples/tweet-with-js/)
### Use Twitters dark theme
When loading Twitters JavaScript, the `<Tweet>` card will render with their light theme by default.
You can use their dark theme by setting the `theme` prop:
```astro 'theme="dark"'
---
import { Tweet } from 'astro-embed';
---
<Tweet theme="dark" id="..." />
```
[See an example of `<Tweet>` with Twitters JavaScript and dark theme](/examples/tweet-with-js-dark/)
## Styling the Tweet component
By default the `<Tweet>` card has minimal styling, which should adapt to your sites font settings etc.
You can customise it by targeting the `.twitter-tweet` class, for example:
```css
.twitter-tweet {
background: floralwhite;
color: darkblue;
font-family: cursive;
font-size: 1.25rem;
border: 0;
}
.twitter-tweet a {
color: purple;
font-weight: bold;
}
```
The above styles would render `<Tweet>` like this:
import StyledTweet from './_examples/StyledTweet.astro';
<StyledTweet />
### Custom properties API
The `<Tweet>` component also supports a minimal API for controlling its styles by setting some CSS custom properties.
```css
:root {
/* Control the padding inside the Tweet card. */
--tc-padding: 1em;
/* Set the border color of the Tweet card. */
--tc-border-color: #cfd9de;
}
```
## Standalone installation
If you only need the `<Tweet>` component, you can install the package directly instead of the main `astro-embed` package:
import { PackageManagers } from 'starlight-package-managers';
<PackageManagers pkg="@astro-community/astro-embed-twitter" />
The `<Tweet>` component can then be imported as:
```js
import { Tweet } from '@astro-community/astro-embed-twitter';
```

View File

@ -1,125 +0,0 @@
---
title: Vimeo
description: Learn how to use the Astro Embed Vimeo component to embed Vimeo videos in your website
---
import { Tabs, TabItem } from '@astrojs/starlight/components';
import { Vimeo } from '@astro-community/astro-embed-vimeo';
The `<Vimeo>` component generates an embed using a lightweight custom element that will load Vimeos `<iframe>` only when a user clicks play.
Vimeo embeds will always require some JavaScript, but this is one of the most minimal and performant ways to embed a Vimeo video.
## Usage
<Tabs>
<TabItem label="Astro" icon="astro">
```astro
---
import { Vimeo } from 'astro-embed';
---
<Vimeo id="32001208" />
```
</TabItem>
<TabItem label="MDX" icon="seti:markdown">
```astro
import { Vimeo } from 'astro-embed';
<Vimeo id="32001208" />
```
</TabItem>
</Tabs>
You can also pass in the full URL for the video:
```astro
<Vimeo id="https://vimeo.com/32001208" />
```
The above code produces the following result:
<Vimeo id="32001208" />
## Optional props
In addition to the required `id` prop, the following props are available to customise how the `<Vimeo>` component renders:
### `poster`
**Type:** `string`
You can provide an alternative poster image by passing in a URL to the `poster` prop.
For example, this is the same video as above but with a custom poster image:
```astro
<Vimeo
id="32001208"
poster="https://images-assets.nasa.gov/image/0302063/0302063~medium.jpg"
/>
```
<Vimeo
id="32001208"
poster="https://images-assets.nasa.gov/image/0302063/0302063~medium.jpg"
/>
### `posterQuality`
**Type:** `'max' | 'high' | 'default' | 'low'`
**Default:** `'default'`
When using the default Vimeo poster image, set the `posterQuality` to change the size of the placeholder image.
This can be useful if displaying the embed at very large or very small sizes.
| `posterQuality` | resolution |
| --------------- | ---------- |
| `'low'` | 120px |
| `'default'` | 480px |
| `'high'` | 640px |
| `'max'` | 1280px |
```astro
<Vimeo id="32001208" posterQuality="low" />
```
<Vimeo id="32001208" posterQuality="low" />
### `params`
You can pass a `params` prop to set the [player parameters supported by Vimeo](https://vimeo.zendesk.com/hc/en-us/articles/360001494447-Player-parameters-overview). This looks like a series of URL search params.
For example, the following `params` value sets the UI color to red and mutes the audio by default:
```astro
<Vimeo id="32001208" params="color=ff0000&muted=1" />
```
<Vimeo id="32001208" params="color=ff0000&muted=1" />
### `playlabel`
**Type:** `string`
**Default:** `'Play'`
By default, the play button in the embed has an accessible label set to “Play”.
If you want to customise this, for example to match the language of your website, you can set the `playlabel` prop:
```astro
<Vimeo id="32001208" playlabel="Play the video" />
```
## Standalone installation
If you only need the `<Vimeo>` component, you can install the package directly instead of the main `astro-embed` package:
import { PackageManagers } from 'starlight-package-managers';
<PackageManagers pkg="@astro-community/astro-embed-vimeo" />
The `<Vimeo>` component can then be imported as:
```js
import { Vimeo } from '@astro-community/astro-embed-vimeo';
```

View File

@ -1,143 +0,0 @@
---
title: YouTube
description: Learn how to use the Astro Embed YouTube component to embed YouTube videos in your website
---
import { Tabs, TabItem } from '@astrojs/starlight/components';
import { YouTube } from '@astro-community/astro-embed-youtube';
The `<YouTube>` component generates an embed using the [`lite-youtube-embed`](https://github.com/paulirish/lite-youtube-embed) custom element that will load YouTubes `<iframe>` only when a user clicks play.
YouTube embeds will always require some JavaScript, but this is one of the most minimal and performant ways to embed a YouTube video.
## Usage
<Tabs>
<TabItem label="Astro" icon="astro">
```astro
---
import { YouTube } from 'astro-embed';
---
<YouTube id="TtRtkTzHVBU" />
```
</TabItem>
<TabItem label="MDX" icon="seti:markdown">
```astro
import { YouTube } from 'astro-embed';
<YouTube id="TtRtkTzHVBU" />
```
</TabItem>
</Tabs>
You can also pass in a URL in one of the various YouTube formats:
```astro
<YouTube id="https://youtu.be/TtRtkTzHVBU" />
```
The above code produces the following result:
<YouTube id="https://youtu.be/TtRtkTzHVBU" />
## Optional props
In addition to the required `id` prop, the following props are available to customise how the `<YouTube>` component renders:
### `poster`
**Type:** `string`
You can provide an alternative poster image by passing in a URL to the `poster` prop.
For example, this is the same video as above but with a custom poster image:
```astro
<YouTube
id="TtRtkTzHVBU"
poster="https://images-assets.nasa.gov/image/0302063/0302063~medium.jpg"
/>
```
<YouTube
id="TtRtkTzHVBU"
poster="https://images-assets.nasa.gov/image/0302063/0302063~medium.jpg"
/>
### `posterQuality`
**Type:** `'max' | 'high' | 'default' | 'low'`
**Default:** `'default'`
When using the default YouTube poster image, set the `posterQuality` to change the size of the placeholder image.
This can be useful if displaying the embed at very large or very small sizes.
| `posterQuality` | resolution |
| --------------- | ---------- |
| `'low'` | 120px |
| `'default'` | 480px |
| `'high'` | 640px |
| `'max'` | 1280px |
```astro
<YouTube id="TtRtkTzHVBU" posterQuality="low" />
```
<YouTube id="TtRtkTzHVBU" posterQuality="low" />
### `params`
You can pass in a `params` prop to set the [YouTube player parameters](https://developers.google.com/youtube/player_parameters#Parameters). This looks like a series of URL search params.
For example, the following `params` value sets the start and end times of the video playback:
```astro
<YouTube id="TtRtkTzHVBU" params="start=57&end=75" />
```
<YouTube id="TtRtkTzHVBU" params="start=57&end=75" />
### `playlabel`
**Type:** `string`
**Default:** `'Play'`
By default, the play button in the embed has an accessible label set to “Play”.
If you want to customise this, for example to match the language of your website, you can set the `playlabel` prop:
```astro
<YouTube id="TtRtkTzHVBU" playlabel="Play the video" />
```
### `title`
**Type:** `string`
Set a visible title to overlay on the video.
```astro
<YouTube
id="TtRtkTzHVBU"
title="The Astro Community: where contributors find a home"
/>
```
<YouTube
id="TtRtkTzHVBU"
title="The Astro Community: where contributors find a home"
/>
## Standalone installation
If you only need the `<YouTube>` component, you can install the package directly instead of the main `astro-embed` package:
import { PackageManagers } from 'starlight-package-managers';
<PackageManagers pkg="@astro-community/astro-embed-youtube" />
The `<YouTube>` component can then be imported as:
```js
import { YouTube } from '@astro-community/astro-embed-youtube';
```

View File

@ -1,31 +0,0 @@
---
title: Dark theme Tweet with JavaScript
description: Example of loading Twitters widget JavaScript to hydrate the Astro Embed Tweet component using a dark color theme
template: splash
toc: false
---
import { LinkCard } from '@astrojs/starlight/components';
import { Tweet } from '@astro-community/astro-embed-twitter';
Adding Twitters widget script will hydrate the HTML markup of `<Tweet>`.
```astro
<script async src="https://platform.twitter.com/widgets.js"></script>
<Tweet
theme="dark"
id="https://twitter.com/astrodotbuild/status/1632809919291457537"
/>
```
The above code produces the following result:
<script async src="https://platform.twitter.com/widgets.js"></script>
<Tweet
theme="dark"
id="https://twitter.com/astrodotbuild/status/1632809919291457537"
/>
<LinkCard title="See full Tweet docs" href="/components/twitter/" />

View File

@ -1,25 +0,0 @@
---
title: Tweet with JavaScript
description: Example of loading Twitters widget JavaScript to hydrate the Astro Embed Tweet component
template: splash
toc: false
---
import { LinkCard } from '@astrojs/starlight/components';
import { Tweet } from '@astro-community/astro-embed-twitter';
Adding Twitters widget script will hydrate the HTML markup of `<Tweet>`.
```astro
<script async src="https://platform.twitter.com/widgets.js"></script>
<Tweet id="https://twitter.com/astrodotbuild/status/1632809919291457537" />
```
The above code produces the following result:
<script async src="https://platform.twitter.com/widgets.js"></script>
<Tweet id="https://twitter.com/astrodotbuild/status/1632809919291457537" />
<LinkCard title="See full Tweet docs" href="/components/twitter/" />

View File

@ -1,75 +0,0 @@
---
title: Getting started
description: Set up Astro Embed to add high performance, rich media embeds to your website
---
import { CardGrid, LinkCard } from '@astrojs/starlight/components';
import { PackageManagers } from 'starlight-package-managers';
The Astro Embed package provides components for adding rich media from third-party services to your [Astro](https://astro.build/) website.
## Installation
<PackageManagers pkg="astro-embed" />
## Using the components
Astro Embed components can be used in Astro and MDX files.
Each component expects an `id` prop identifying the resource to be embedded.
### In Astro files
To use components in `.astro` files, import them in the component script and then use them in your template:
```astro
---
// src/components/Example.astro
import { Tweet, Vimeo, YouTube } from 'astro-embed';
---
<Tweet id="https://twitter.com/astrodotbuild/status/1512144306898976768" />
<Vimeo id="https://vimeo.com/32001208" />
<YouTube id="https://youtu.be/xtTy5nKay_Y" />
```
### In MDX files
When using the [Astro MDX integration](https://docs.astro.build/en/guides/integrations-guide/mdx/), you can also import and use the embed components in MDX files:
```mdx
---
# src/content/examples/page.mdx
title: My MDX page with embed components
---
import { Tweet, Vimeo, YouTube } from 'astro-embed';
Hey look! I can embed a tweet _in Markdown_!
<Tweet id="https://twitter.com/astrodotbuild/status/1512144306898976768" />
Vimeo and YouTube videos work too :-)
<Vimeo id="https://vimeo.com/32001208" />
<YouTube id="https://youtu.be/xtTy5nKay_Y" />
```
### Auto-embed URLs in MDX
Use the Astro Embed integration to automatically convert URLs in MDX files to embed components.
Learn how to set up the integration in the [“Auto-embed URLs”](/integration/) guide.
## Supported services
Astro Embed currently supports the following services:
<CardGrid>
<LinkCard title="Baseline" href="/components/baseline-status/" />
<LinkCard title="Open Graph" href="/components/link-preview/" />
<LinkCard title="Twitter" href="/components/twitter/" />
<LinkCard title="Vimeo" href="/components/vimeo/" />
<LinkCard title="YouTube" href="/components/youtube/" />
</CardGrid>

View File

@ -1,82 +0,0 @@
---
title: Astro Embed
description: High performance, rich media embed components. For your site, from the Astro community.
template: splash
hero:
tagline: High performance, rich media embed components. For your site, from the Astro community.
image:
file: ../../assets/splash.webp
actions:
- text: Get Started
link: /getting-started/
icon: right-arrow
variant: primary
- text: Star on GitHub
link: https://github.com/delucis/astro-embed
icon: star
---
import { Icon, Card, CardGrid } from '@astrojs/starlight/components';
## What can Astro Embed do?
<CardGrid stagger>
<Card title="YouTube" icon="youtube">
Dont slow your users down. Only load YouTubes JavaScript when they click.
[YouTube docs](/components/youtube/)
</Card>
<Card title="Vimeo" icon="seti:video">
Load Vimeo embeds on user interaction for faster page loads.
[Vimeo docs](/components/vimeo/)
</Card>
<Card title="Twitter" icon="twitter">
Embed the contents of a Tweet in your post without client-side JavaScript.
[Tweet docs](/components/twitter/)
</Card>
<Card title="Bluesky" icon="blueSky">
Embed a fully-styled Bluesky post with no client-side JavaScript.
[Bluesky Post docs](/components/bluesky/)
</Card>
<Card title="Link Preview" icon="seti:html">
Embed the Open Graph media and metadata for any URL in your page.
[Link Preview docs](/components/link-preview/)
</Card>
<Card title="Baseline Status" icon="laptop">
Display browser support for a web feature according to the Baseline project.
[Baseline Status docs](/components/baseline-status/)
</Card>
<Card title="Auto-embed URLs" icon="document">
Automatically convert matching URLs in your MDX content to a rich media
embed.
[Learn how to configure auto-embeds](/integration/)
</Card>
</CardGrid>

View File

@ -1,79 +0,0 @@
---
title: Auto-embed URLs in MDX
description: Learn how to set up and use the Astro Embed integration to automatically convert URLs to rich media embeds in your MDX content.
---
The Astro Embed integration automatically converts URLs in MDX files to embed components.
## Set up
To enable the integration, add it to the `integrations` array in your `astro.config.mjs` file before the `mdx()` integration:
```js ins={4} ins="embeds()"
// astro.config.mjs
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import embeds from 'astro-embed/integration';
export default defineConfig({
integrations: [embeds(), mdx()],
});
```
## Usage
With the integration enabled, any isolated URL in an MDX file that matches one of the `astro-embed` component types will be converted to the appropriate component.
For example, MDX like this will render an optimised YouTube player component in place of the URL.
```mdx
---
# src/content/examples/auto-embed.mdx
---
I saw this cool video the other day:
http://www.youtube.com/watch?v=Hoe-woAhq_k
```
Only URLs on their own line will be converted.
URLs within a paragraph will not be processed.
## Configuration options
The auto-embed integration can be configured by passing an options object in `astro.config.mjs`:
```js {8-10}
// astro.config.mjs
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import embeds from 'astro-embed/integration';
export default defineConfig({
integrations: [
embeds({
// options
}),
mdx(),
],
});
```
### `services`
import { componentNames } from '../../../../packages/astro-embed-integration/remark-plugin';
**Type:** <code>Record&lt;{componentNames.map(JSON.stringify).join(' | ')}, boolean&gt;</code>
By default, the integration enables matching all supported URL types and components.
This includes the `<LinkPreview>` component which will match any `https://` URL.
To disable one or more services, set them as `false` in the `services` option:
```js {2-4}
embeds({
services: {
LinkPreview: false,
},
}),
```

View File

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

View File

@ -1,18 +0,0 @@
---
import type { Props } from '@astrojs/starlight/props';
import Default from '@astrojs/starlight/components/Head.astro';
// Get the URL of the generated image for the current page using its
// ID and replace the file extension with `.png`.
const ogImageUrl = new URL(
`/og/${Astro.props.id.replace(/\.\w+$/, '.png')}`,
Astro.site
);
---
<!-- Render the default <Head/> component. -->
<Default {...Astro.props}><slot /></Default>
<!-- Render the <meta/> tags for the Open Graph images. -->
<meta property="og:image" content={ogImageUrl} />
<meta name="twitter:image" content={ogImageUrl} />

View File

@ -1,49 +0,0 @@
import { getCollection } from 'astro:content';
import { OGImageRoute } from 'astro-og-canvas';
// Get all entries from the `docs` content collection.
const entries = await getCollection('docs');
// Map the entry array to an object with the page ID as key and the
// frontmatter data as value.
const pages = Object.fromEntries(entries.map(({ data, id }) => [id, { data }]));
export const { getStaticPaths, GET } = OGImageRoute({
// Pass down the documentation pages.
pages,
// Define the name of the parameter used in the endpoint path, here `slug`
// as the file is named `[...slug].ts`.
param: 'slug',
// Define a function called for each page to customize the generated image.
getImageOptions: (_path, page: (typeof pages)[number]) => {
return {
// Use the page title and description as the image title and description.
title: page.data.title,
description: page.data.description,
// Customize various colors and add a border.
bgGradient: [[47, 28, 66]],
border: { color: [227, 182, 237], width: 10, side: 'block-end' },
font: {
title: {
size: 90,
color: [255, 255, 255],
families: ['IBM Plex Serif'],
weight: 'Bold',
},
description: {
color: [227, 182, 237],
families: ['IBM Plex Serif'],
lineHeight: 1.4,
},
},
fonts: [
'https://cdn.jsdelivr.net/fontsource/fonts/ibm-plex-serif@latest/latin-400-normal.woff2',
'https://cdn.jsdelivr.net/fontsource/fonts/ibm-plex-serif@latest/latin-700-normal.woff2',
],
padding: 100,
logo: {
path: './src/assets/og-logo.png',
},
};
},
});

View File

@ -1,3 +0,0 @@
{
"extends": "astro/tsconfigs/strictest"
}

File diff suppressed because it is too large Load Diff

View File

@ -1,39 +0,0 @@
{
"name": "root",
"version": "0.0.1",
"license": "MIT",
"private": true,
"scripts": {
"start": "astro --root demo dev",
"build": "astro --root demo build",
"serve": "astro --root demo preview",
"test": "uvu tests -i utils",
"format": "prettier -w .",
"lint": "eslint . --ext .ts,.js"
},
"devDependencies": {
"@changesets/changelog-github": "^0.4.4",
"@changesets/cli": "^2.22.0",
"@testing-library/dom": "^8.13.0",
"@types/eslint": "^8.44.0",
"@types/node": "^16.11.68",
"@types/prettier": "^2.7.3",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"astro": "^4.16.3",
"astro-component-tester": "^0.8.0",
"eslint": "^8.45.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"linkedom": "^0.14.7",
"prettier": "^2.8.8",
"prettier-plugin-astro": "^0.10.0",
"typescript": "^4.8.4",
"uvu": "^0.5.6"
},
"workspaces": [
"demo",
"docs",
"packages/**/*"
]
}

View File

@ -1,23 +0,0 @@
---
import type { StatusLevel } from './types';
interface Props {
support: StatusLevel;
}
const paths = {
limited: `<path fill="var(--color-limited)" d="m10 0 6 6-2 2-6-6 2-2Zm12 12-2 2 6 6 2-2-6-6Zm4-12 2 2-18 18-2-2L26 0Z"/><path fill="var(--color-limited-secondary)" d="m8 2 2 2-6 6 6 6-2 2-8-8 8-8Zm20 0 8 8-8 8-2-2 6-6-6-6 2-2Z"/>`,
widely: `<path fill="var(--color-widely)" d="m18 8 2 2-2 2-2-2 2-2Z"/><path fill="var(--color-widely)" d="m26 0 2 2-18 18L0 10l2-2 8 8L26 0Z"/><path fill="var(--color-widely-secondary)" d="m28 2-2 2 6 6-6 6-4-4-2 2 6 6 10-10-8-8ZM10 0 2 8l2 2 6-6 4 4 2-2-6-6Z"/>`,
newly: `<path fill="var(--color-newly-secondary)" d="m10 0 2 2-2 2-2-2 2-2Zm4 4 2 2-2 2-2-2 2-2Zm16 0 2 2-2 2-2-2 2-2Zm4 4 2 2-2 2-2-2 2-2Zm-4 4 2 2-2 2-2-2 2-2Zm-4 4 2 2-2 2-2-2 2-2Zm-4-4 2 2-2 2-2-2 2-2ZM6 4l2 2-2 2-2-2 2-2Z"/><path fill="var(--color-newly)" d="m26 0 2 2-18 18L0 10l2-2 8 8L26 0Z"/>`,
no_data: `<path fill="var(--color-no_data-secondary)" d="m18 8 2 2-2 2-2-2 2-2Zm10-6-2 2 6 6-6 6-4-4-2 2 6 6 10-10-8-8ZM10 0 2 8l2 2 6-6 4 4 2-2-6-6Z"/><path fill="var(--color-no_data-secondary)" d="m26 0 2 2-18 18L0 10l2-2 8 8L26 0Z"/>`,
};
---
<svg
width="36"
height="20"
viewBox="0 0 36 20"
class="baseline-icon"
aria-hidden="true"
set:html={paths[Astro.props.support]}
/>

View File

@ -1,378 +0,0 @@
---
import { safeGet } from '@astro-community/astro-embed-utils';
import BaselineIcon from './BaselineIcon.astro';
import BrowserSupport from './BrowserSupport.astro';
import type { Feature, StatusLevel } from './types';
interface Props {
/**
* ID of the feature from https://github.com/web-platform-dx/web-features/
* e.g. `"anchor-positioning"`
*/
id: string;
}
const API_ENDPOINT = 'https://api.webstatus.dev/v1/features/';
const BASELINE_DEFS = {
limited: {
title: 'Limited availability',
defaultDescription:
'This feature is not Baseline because it does not work in some of the most widely-used browsers.',
},
newly: {
title: '',
defaultDescription:
'This feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.',
},
widely: {
title: 'Widely available',
defaultDescription:
'This feature is well established and works across many devices and browser versions.',
},
no_data: {
title: 'Unknown availability',
defaultDescription:
'We currently dont have browser support information about this feature.',
},
};
/**
* Returns feature's `low_date` as mm-yyyy string or empty string if `low_date` is not present.
*/
function getBaselineDate(feature: { baseline: { low_date?: string } }): string {
return feature.baseline.low_date
? new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: 'long',
}).format(new Date(feature.baseline.low_date))
: '';
}
/**
* Returns Baseline's description.
*/
function getDescriptionDate(baseline: StatusLevel, date: string): string {
if (baseline === 'newly' && date) {
return `Since ${date} this feature works across the latest
devices and browser versions. This feature might not work in older
devices or browsers.`;
} else if (baseline === 'widely' && date) {
return `This feature is well established and works across many
devices and browser versions. Its been available across browsers
since ${date}`;
}
return BASELINE_DEFS[baseline].defaultDescription;
}
const featureData = await safeGet(API_ENDPOINT + Astro.props.id);
const feature: Feature = featureData?.baseline
? (featureData as Feature)
: {
baseline: {
status: 'no_data',
},
name: Astro.props.id || 'Unknown feature',
};
const baseline = feature.baseline.status || 'no_data';
const title = BASELINE_DEFS[baseline].title;
const baselineDate = getBaselineDate(feature);
const description = getDescriptionDate(baseline, baselineDate);
const year =
baseline === 'newly' && baselineDate ? baselineDate.split(' ')[1]! : '';
---
<div class={`baseline-status baseline-status--${baseline}`}>
<template shadowrootmode="open">
<div part="root">
<p part="feature-name">{feature.name}</p>
<details part="details">
<summary part="summary">
<BaselineIcon support={baseline} />
<div part="summary-content">
<div part="summary-label">
{
!(baseline === 'limited' || baseline === 'no_data') && (
<strong>Baseline</strong>
)
}
{title}
{year}
{
baseline === 'newly' && (
<span part="badge">newly available</span>
)
}
</div>
<div part="browsers">
<BrowserSupport browser="chrome" {feature} />
<BrowserSupport browser="edge" {feature} />
<BrowserSupport browser="firefox" {feature} />
<BrowserSupport browser="safari" {feature} />
</div>
</div>
<style>
[part='caret'] svg {
transition: transform 0.3s;
}
details[open] [part='caret'] svg {
transform: rotate(180deg);
}
</style>
<span part="caret" aria-hidden="true">
<svg width="11" height="7" fill="currentColor">
<path d="M5.5 6.45.25 1.2l.94-.94L5.5 4.6 9.8.3l.95.94L5.5 6.45Z"
></path>
</svg>
</span>
</summary>
<p part="description" set:html={description} />
{
baseline !== 'no_data' && (
<p>
<a
href={`https://webstatus.dev/features/${feature.feature_id}`}
target="_top"
part="link"
set:text={`${feature.name} on Web Platform Status`}
/>
</p>
)
}
</details>
</div>
</template>
</div>
<style>
.baseline-status::part(root) {
/* Light palette */
--color-outline--light: #d9d9d9;
--color-background--light: transparent;
--color-text--light: inherit;
--color-link--light: #1a73e8;
--color-badge-background--light: #3367d6;
--color-badge-text--light: #fff;
--color-limited--light: #ea8600;
--color-limited-secondary--light: #c6c6c6;
--color-newly--light: #1a73e8;
--color-newly-secondary--light: #a8c7fa;
--color-widely--light: #1e8e3e;
--color-widely-secondary--light: #c4eed0;
--color-no_data--light: #707070;
--color-no_data-secondary--light: #909090;
/* Dark palette */
--color-outline--dark: #666666;
--color-background--dark: transparent;
--color-text--dark: inherit;
--color-link--dark: #5aa1ff;
--color-badge-background--dark: #3367d6;
--color-badge-text--dark: #fff;
--color-limited--dark: #f09418;
--color-limited-secondary--dark: #565656;
--color-newly--dark: #4185ff;
--color-newly-secondary--dark: #2d509e;
--color-widely--dark: #24a446;
--color-widely-secondary--dark: #125225;
--color-no_data--dark: #868686;
--color-no_data-secondary--dark: #666666;
/* Set up colors for light mode */
--color-limited: var(--color-limited--light);
--color-newly: var(--color-newly--light);
--color-widely: var(--color-widely--light);
--color-no_data: var(--color-no_data--light);
--color-outline: var(--color-outline--light);
--color-background: var(--color-background--light);
--color-text: var(--color-text--light);
--color-link: var(--color-link--light);
--color-badge-background: var(--color-badge-background--light);
--color-badge-text: var(--color-badge-text--light);
--color-limited-secondary: var(--color-limited-secondary--light);
--color-widely-secondary: var(--color-widely-secondary--light);
--color-newly-secondary: var(--color-newly-secondary--light);
--color-no_data-secondary: var(--color-no_data-secondary--light);
color: var(--color-text);
border: solid 1px var(--color-outline);
border-radius: 0.5rem;
background: var(--color-background);
padding-top: 1rem;
padding-inline: 1.5rem;
max-width: 50rem;
font-family: Roboto, sans-serif;
font-size: 0.875rem;
line-height: calc(1.5 / 0.875);
font-style: normal;
}
@media (prefers-color-scheme: dark) {
.baseline-status::part(root) {
/* Set up colors for dark mode */
--color-limited: var(--color-limited--dark);
--color-newly: var(--color-newly--dark);
--color-widely: var(--color-widely--dark);
--color-no_data: var(--color-no_data--dark);
--color-outline: var(--color-outline--dark);
--color-background: var(--color-background--dark);
--color-text: var(--color-text--dark);
--color-link: var(--color-link--dark);
--color-badge-background: var(--color-badge-background--dark);
--color-badge-text: var(--color-badge-text--dark);
--color-limited-secondary: var(--color-limited-secondary--dark);
--color-widely-secondary: var(--color-widely-secondary--dark);
--color-newly-secondary: var(--color-newly-secondary--dark);
--color-no_data-secondary: var(--color-no_data-secondary--dark);
}
}
@supports (--color: light-dark(var(--a), var(--b))) {
.baseline-status::part(root) {
/* Set up dynamic light/dark colors in supporting browsers. */
--color-limited: light-dark(
var(--color-limited--light),
var(--color-limited--dark)
);
--color-newly: light-dark(
var(--color-newly--light),
var(--color-newly--dark)
);
--color-widely: light-dark(
var(--color-widely--light),
var(--color-widely--dark)
);
--color-no_data: light-dark(
var(--color-no_data--light),
var(--color-no_data--dark)
);
--color-outline: light-dark(
var(--color-outline--light),
var(--color-outline--dark)
);
--color-background: light-dark(
var(--color-background--light),
var(--color-background--dark)
);
--color-text: light-dark(
var(--color-text--light),
var(--color-text--dark)
);
--color-link: light-dark(
var(--color-link--light),
var(--color-link--dark)
);
--color-badge-background: light-dark(
var(--color-badge-background--light),
var(--color-badge-background--dark)
);
--color-badge-text: light-dark(
var(--color-badge-text--light),
var(--color-badge-text--dark)
);
--color-limited-secondary: light-dark(
var(--color-limited-secondary--light),
var(--color-limited-secondary--dark)
);
--color-widely-secondary: light-dark(
var(--color-widely-secondary--light),
var(--color-widely-secondary--dark)
);
--color-newly-secondary: light-dark(
var(--color-newly-secondary--light),
var(--color-newly-secondary--dark)
);
--color-no_data-secondary: light-dark(
var(--color-no_data-secondary--light),
var(--color-no_data-secondary--dark)
);
}
}
.baseline-status::part(feature-name) {
font-size: 1.25rem;
line-height: calc(1.5 / 1.25);
margin: 0;
}
.baseline-status::part(link),
.baseline-status::part(link):active,
.baseline-status::part(link):visited {
color: var(--color-link);
}
.baseline-status::part(summary) {
display: flex;
cursor: pointer;
font-size: 1rem;
line-height: calc(1.5 / 1);
display: flex;
flex-wrap: wrap;
gap: 1rem;
justify-content: space-between;
padding-block: 1rem;
}
.baseline-status::part(summary)::-webkit-details-marker {
display: none;
}
.baseline-status::part(summary-content) {
gap: 1rem;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
flex: 1;
}
.baseline-status::part(summary-label) {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.2rem;
}
.baseline-status::part(badge) {
background: var(--color-badge-background);
color: var(--color-badge-text);
font-size: 0.6875rem;
line-height: calc(1.25 / 0.6875);
padding-inline: 0.25rem;
border-radius: 0.125rem;
text-transform: uppercase;
margin-inline: 0.5rem;
white-space: nowrap;
}
.baseline-status::part(browsers) {
font-size: 0;
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.baseline-status::part(browser-support) {
white-space: nowrap;
}
.baseline-status::part(browser-support-label) {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
}
.baseline-status::part(caret) {
width: 10px;
height: 20px;
margin-inline-start: auto;
color: var(--text-color);
}
@media (min-width: 28rem) {
.baseline-status::part(caret) {
margin-inline-start: 3rem;
}
}
</style>

View File

@ -1,18 +0,0 @@
---
import type { Browser } from './types';
import chrome from './icons/browsers/chrome.svg';
import edge from './icons/browsers/edge.svg';
import firefox from './icons/browsers/firefox.svg';
import safari from './icons/browsers/safari.svg';
interface Props {
browser: Browser;
}
const { browser } = Astro.props;
const icons = { chrome, edge, firefox, safari };
const { src, width, height } = icons[browser];
---
<img {src} alt="" {width} {height} />

View File

@ -1,33 +0,0 @@
---
import BrowserIcon from './BrowserIcon.astro';
import SupportIcon from './SupportIcon.astro';
import type { Browser, Feature } from './types';
interface Props {
browser: Browser;
feature: Feature;
}
const { browser, feature } = Astro.props;
const baseline = feature.baseline.status || 'no_data';
const browserImplementation = feature.browser_implementations?.[browser];
const browserName = {
chrome: 'Chrome',
edge: 'Edge',
firefox: 'Firefox',
safari: 'Safari',
}[browser];
let supportLabel = browserImplementation?.status || 'no';
if (baseline === 'no_data') supportLabel = 'unknown';
if (supportLabel === 'available') supportLabel = 'yes';
---
<span part="browser-support">
<span part="browser-support-label">
Supported in {browserName}: {supportLabel}.
</span>
<BrowserIcon {browser} />
<SupportIcon {baseline} {browserImplementation} />
</span>

View File

@ -1,21 +0,0 @@
# @astro-community/astro-embed-baseline-status
## 0.1.2
### Patch Changes
- [#163](https://github.com/delucis/astro-embed/pull/163) [`0383e4e6295eea4425c4ba367d677fdb901c3515`](https://github.com/delucis/astro-embed/commit/0383e4e6295eea4425c4ba367d677fdb901c3515) Thanks [@mayank99](https://github.com/mayank99)! - Removes `max-width` from `::part(browsers)` to prevent undesirable wrapping of browser icons.
## 0.1.1
### Patch Changes
- [`a80bb8c8e0368e042ab75d6ff102d260d6400463`](https://github.com/delucis/astro-embed/commit/a80bb8c8e0368e042ab75d6ff102d260d6400463) Thanks [@delucis](https://github.com/delucis)! - Fixes missing README and docs link in the baseline-status package
## 0.1.0
### Minor Changes
- [#156](https://github.com/delucis/astro-embed/pull/156) [`bdaa3dba3be5f4f9d5da5ac4cf9f3ee65f402cca`](https://github.com/delucis/astro-embed/commit/bdaa3dba3be5f4f9d5da5ac4cf9f3ee65f402cca) Thanks [@delucis](https://github.com/delucis)! - Adds new `<BaselineStatus>` component
This component displays the status of a web feature according to the [Baseline](https://web.dev/baseline/) project.

View File

@ -1,5 +0,0 @@
# `@astro-community/astro-embed-baseline-status`
This package contains a component for embedding the status of a web feature according to the Baseline project in Astro projects.
[Read the `<BaselineStatus>` component docs](https://astro-embed.netlify.app/components/baseline-status/).

View File

@ -1,39 +0,0 @@
---
import type { BrowserImplementation, StatusLevel } from './types';
interface Props {
baseline: StatusLevel;
browserImplementation?: BrowserImplementation | undefined;
}
const { baseline, browserImplementation } = Astro.props;
const paths = {
available: `<path d="M1.25 3.31a8.84 8.84 0 0 1 5.47-1.88 8.8 8.8 0 0 1 8.84 8.77 8.8 8.8 0 0 1-8.84 8.77 8.84 8.84 0 0 1-5.47-1.88c-.23.34-.49.66-.75.97a10.07 10.07 0 0 0 6.22 2.14c5.57 0 10.07-4.48 10.07-10S12.3.2 6.72.2C4.37.2 2.21 1 .5 2.34c.26.31.52.64.75.97Z"/><path d="m11.35 8.13-5.01 4.93-3-2.96 1-.98 2 1.96 4-3.94 1 .98Z"/>`,
unavailable: `<path d="M1.25 3.31a8.84 8.84 0 0 1 5.47-1.88 8.8 8.8 0 0 1 8.84 8.77 8.8 8.8 0 0 1-8.84 8.77 8.84 8.84 0 0 1-5.47-1.88c-.23.34-.49.66-.75.97a10.07 10.07 0 0 0 6.22 2.14c5.57 0 10.08-4.48 10.08-10S12.29.2 6.73.2C4.37.2 2.2 1 .5 2.34c.27.31.52.64.75.97Z"/><path d="M10.32 8.13 8.33 10.1l2 1.97-1 .99-1.99-1.98-1.99 1.98-.99-.99 1.99-1.97-1.99-1.97 1-.99 1.98 1.97 1.99-1.97 1 .99Z"/>`,
no_data: `<path d="M7.18 12.28h-1.2c.01-.41.05-.74.12-1 .07-.27.19-.5.35-.72.16-.22.38-.47.65-.74l.54-.56c.16-.18.3-.37.4-.58.1-.2.16-.45.16-.74 0-.3-.06-.55-.16-.76a1.1 1.1 0 0 0-.47-.5 1.5 1.5 0 0 0-.75-.16c-.25 0-.48.04-.7.13-.23.09-.4.23-.54.41-.14.19-.21.43-.22.72H4.18c0-.48.12-.89.36-1.23.23-.35.55-.61.95-.8.4-.18.84-.27 1.33-.27.55 0 1 .1 1.39.3.38.2.68.47.88.84.2.36.3.79.3 1.29 0 .38-.08.73-.24 1.05-.15.32-.35.62-.6.9-.24.28-.5.55-.77.8-.24.22-.4.47-.48.74-.08.27-.12.56-.12.88ZM5.94 14.3c0-.2.06-.35.18-.49.12-.13.29-.2.52-.2.23 0 .4.07.52.2.12.14.18.3.18.49 0 .18-.06.34-.18.47-.12.13-.3.2-.52.2a.67.67 0 0 1-.52-.2.68.68 0 0 1-.18-.47Z"/><path d="M1.25 3.31a8.84 8.84 0 0 1 5.47-1.88 8.8 8.8 0 0 1 8.84 8.77 8.8 8.8 0 0 1-8.84 8.77c-2.06 0-3.96-.7-5.47-1.88-.23.34-.49.66-.75.97a10.07 10.07 0 0 0 6.22 2.14c5.57 0 10.07-4.48 10.07-10S12.3.2 6.72.2C4.37.2 2.21 1 .5 2.34c.26.31.52.64.75.97Z"/>`,
};
const support =
baseline === 'limited'
? browserImplementation?.status || 'unavailable'
: baseline;
const icon =
support === 'newly' || support === 'widely' ? 'available' : support;
const fill = {
no_data: 'var(--color-no_data)',
unavailable: 'var(--color-limited)',
newly: 'var(--color-newly)',
widely: 'var(--color-widely)',
available: 'var(--color-widely)',
}[support];
---
<svg
width="17"
height="21"
aria-hidden="true"
fill={fill}
set:html={paths[icon]}
/>

View File

@ -1,7 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="-10 -10 276 276">
<circle cx="128" cy="128" r="64" fill="#fff"/>
<path fill="#229342" d="M96 183a64 64 0 0 1-23-23L17 64a128 128 0 0 0 111 192l55-96a64 64 0 0 1-87 23Z"/>
<path fill="#FBC116" d="M192 128a64 64 0 0 1-9 32l-55 96A128 128 0 0 0 239 64H128a64 64 0 0 1 64 64Z"/>
<circle cx="128" cy="128" r="52" fill="#1a73e8"/>
<path fill="#E33B2E" d="M96 73a64 64 0 0 1 32-9h111a128 128 0 0 0-222 0l56 96a64 64 0 0 1 23-87Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 509 B

View File

@ -1,41 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="21">
<path fill="url(#b)" d="M18.416 15.18a7.485 7.485 0 0 1-.845.375 8.121 8.121 0 0 1-2.86.51c-3.77 0-7.053-2.59-7.053-5.92a2.51 2.51 0 0 1 1.307-2.176c-3.41.143-4.287 3.697-4.287 5.777 0 5.897 5.427 6.487 6.598 6.487.63 0 1.578-.184 2.152-.367l.103-.032a10.224 10.224 0 0 0 5.307-4.207.319.319 0 0 0-.422-.447Z"/>
<path fill="url(#c)" d="M18.416 15.18a7.485 7.485 0 0 1-.845.375 8.121 8.121 0 0 1-2.86.51c-3.77 0-7.053-2.59-7.053-5.92a2.51 2.51 0 0 1 1.307-2.176c-3.41.143-4.287 3.697-4.287 5.777 0 5.897 5.427 6.487 6.598 6.487.63 0 1.578-.184 2.152-.367l.103-.032a10.224 10.224 0 0 0 5.307-4.207.319.319 0 0 0-.422-.447Z" opacity=".35"/>
<path fill="url(#d)" d="M8.423 19.229a6.31 6.31 0 0 1-1.809-1.698A6.43 6.43 0 0 1 8.965 7.97c.255-.12.677-.327 1.243-.319a2.582 2.582 0 0 1 2.048 1.036c.32.431.497.953.502 1.49 0-.016 1.953-6.343-6.375-6.343-3.498 0-6.375 3.315-6.375 6.232-.014 1.54.316 3.065.964 4.462a10.2 10.2 0 0 0 12.464 5.34 6.015 6.015 0 0 1-5.005-.638h-.008Z"/>
<path fill="url(#e)" d="M8.423 19.229a6.31 6.31 0 0 1-1.809-1.698A6.43 6.43 0 0 1 8.965 7.97c.255-.12.677-.327 1.243-.319a2.582 2.582 0 0 1 2.048 1.036c.32.431.497.953.502 1.49 0-.016 1.953-6.343-6.375-6.343-3.498 0-6.375 3.315-6.375 6.232-.014 1.54.316 3.065.964 4.462a10.2 10.2 0 0 0 12.464 5.34 6.015 6.015 0 0 1-5.005-.638h-.008Z" opacity=".41"/>
<path fill="url(#f)" d="M12.145 11.857c-.072.08-.271.2-.271.447 0 .207.135.414.382.582 1.14.796 3.3.685 3.307.685a4.75 4.75 0 0 0 2.415-.662A4.893 4.893 0 0 0 20.4 8.694c.024-1.785-.637-2.972-.9-3.498C17.802 1.896 14.16 0 10.2 0A10.2 10.2 0 0 0 0 10.057c.04-2.909 2.933-5.26 6.375-5.26.28 0 1.873.024 3.347.797a5.786 5.786 0 0 1 2.463 2.335c.486.845.573 1.92.573 2.35 0 .431-.215 1.06-.621 1.587l.008-.008Z"/>
<path fill="url(#g)" d="M12.145 11.857c-.072.08-.271.2-.271.447 0 .207.135.414.382.582 1.14.796 3.3.685 3.307.685a4.75 4.75 0 0 0 2.415-.662A4.893 4.893 0 0 0 20.4 8.694c.024-1.785-.637-2.972-.9-3.498C17.802 1.896 14.16 0 10.2 0A10.2 10.2 0 0 0 0 10.057c.04-2.909 2.933-5.26 6.375-5.26.28 0 1.873.024 3.347.797a5.786 5.786 0 0 1 2.463 2.335c.486.845.573 1.92.573 2.35 0 .431-.215 1.06-.621 1.587l.008-.008Z"/>
<defs>
<radialGradient id="c" cx="0" cy="0" r="1" gradientTransform="matrix(7.6 0 0 7.2 12.527 14.212)" gradientUnits="userSpaceOnUse">
<stop offset=".7" stop-opacity="0"/>
<stop offset=".9" stop-opacity=".5"/>
<stop offset="1"/>
</radialGradient>
<radialGradient id="e" cx="0" cy="0" r="1" gradientTransform="matrix(1.7 -11.3 9.1 1.4 5.623 15.854)" gradientUnits="userSpaceOnUse">
<stop offset=".8" stop-opacity="0"/>
<stop offset=".9" stop-opacity=".5"/>
<stop offset="1"/>
</radialGradient>
<radialGradient id="f" cx="0" cy="0" r="1" gradientTransform="matrix(-.6 16.1 -34.4 -1.4 2.063 3.77)" gradientUnits="userSpaceOnUse">
<stop stop-color="#35C1F1"/>
<stop offset=".1" stop-color="#34C1ED"/>
<stop offset=".2" stop-color="#2FC2DF"/>
<stop offset=".3" stop-color="#2BC3D2"/>
<stop offset=".7" stop-color="#36C752"/>
</radialGradient>
<radialGradient id="g" cx="0" cy="0" r="1" gradientTransform="matrix(2.2 7.4 -6 1.8 19.13 6.16)" gradientUnits="userSpaceOnUse">
<stop stop-color="#66EB6E"/>
<stop offset="1" stop-color="#66EB6E" stop-opacity="0"/>
</radialGradient>
<linearGradient id="b" x1="4.678" x2="18.894" y1="14.105" y2="14.105" gradientUnits="userSpaceOnUse">
<stop stop-color="#0C59A4"/>
<stop offset="1" stop-color="#114A8B"/>
</linearGradient>
<linearGradient id="d" x1="12.168" x2="3.299" y1="7.937" y2="17.603" gradientUnits="userSpaceOnUse">
<stop stop-color="#1B9DE2"/>
<stop offset=".2" stop-color="#1595DF"/>
<stop offset=".7" stop-color="#0680D7"/>
<stop offset="1" stop-color="#0078D4"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -1,109 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="21">
<path fill="url(#b)" d="M19.66 6.85a5.59 5.59 0 0 0-2.05-2.5c.5.94.85 1.95 1.04 3v.01c-1.16-2.78-3.11-3.9-4.71-6.35L13.7.63l-.12-.2a1.76 1.76 0 0 1-.15-.4l-.02-.02h-.03A7.18 7.18 0 0 0 9.87 5.5a5.2 5.2 0 0 0-2.81 1.05 3.05 3.05 0 0 0-.27-.2 4.44 4.44 0 0 1-.03-2.41A7.53 7.53 0 0 0 4.3 5.78c-.4-.5-.38-2.14-.35-2.48-.12.05-.24.1-.34.18a8.68 8.68 0 0 0-1.95 1.94A8.22 8.22 0 0 0 .27 8.4l-.01.06-.1.62v.02A9.14 9.14 0 0 0 0 10.48v.05c0 2.47.97 4.85 2.7 6.67s4.1 2.95 6.65 3.16a10.45 10.45 0 0 0 7.1-2.02 9.84 9.84 0 0 0 3.83-6.14l.04-.38a9.88 9.88 0 0 0-.66-4.97zM7.9 14.59l.14.07-.14-.07zm10.76-7.22v-.01z"/>
<use fill="url(#c)" href="#d"/>
<use fill="url(#e)" href="#d"/>
<path fill="url(#f)" d="m14.7 8.01.06.05a5.42 5.42 0 0 0-.95-1.2A4.91 4.91 0 0 1 13.37 0a7.18 7.18 0 0 0-3.5 5.49l.35-.02c.91 0 1.8.24 2.6.68A5.07 5.07 0 0 1 14.7 8z"/>
<use fill="url(#g)" href="#h"/>
<use fill="url(#i)" href="#h"/>
<path fill="url(#j)" d="m6.58 6.22.2.14a4.44 4.44 0 0 1-.02-2.42A7.53 7.53 0 0 0 4.3 5.78c.05 0 1.53-.03 2.28.44z"/>
<path fill="url(#k)" d="M.1 10.76c.78 4.5 5 7.95 9.8 8.08 4.43.13 7.26-2.37 8.43-4.8.99-2.1 1.1-4.5.32-6.67v-.01c.36 2.3-.84 4.51-2.72 6.02v.01c-3.67 2.9-7.18 1.74-7.89 1.28l-.15-.08c-2.14-.98-3.02-2.87-2.83-4.49a2.61 2.61 0 0 1-2.42-1.47c.56-.33 1.2-.52 1.86-.55a3.96 3.96 0 0 1 1.9.4 5.24 5.24 0 0 0 3.83.15c0-.08-1.78-.76-2.47-1.43l-.7-.65a2.9 2.9 0 0 0-.27-.19l-.2-.13a5.18 5.18 0 0 0-2.28-.45c-.41-.5-.38-2.13-.36-2.47-.12.04-.24.1-.34.17a8.62 8.62 0 0 0-1.96 1.94A8.22 8.22 0 0 0 .28 8.4c0 .02-.37 1.56-.19 2.35z"/>
<path fill="url(#l)" d="M13.81 6.86c.37.35.7.76.95 1.2l.15.12c2.32 2.07 1.1 4.99 1.02 5.2 1.88-1.5 3.08-3.73 2.72-6.02-1.16-2.79-3.12-3.91-4.71-6.36L13.7.62l-.12-.2a1.76 1.76 0 0 1-.15-.4L13.41 0h-.03c-.4.19-2.74 3.78.43 6.85z"/>
<path fill="url(#m)" d="M14.91 8.18a2.1 2.1 0 0 0-.15-.12L14.7 8a3.61 3.61 0 0 0-2.47-.58c3.68 1.78 2.7 7.9-2.4 7.68a4.7 4.7 0 0 1-1.33-.25l-.3-.12-.17-.08c.72.47 4.22 1.62 7.89-1.27v-.02c.1-.2 1.31-3.12-1-5.2z"/>
<path fill="url(#n)" d="M5.63 11.42S6.1 9.72 9 9.72c.31 0 1.21-.85 1.23-1.1a5.24 5.24 0 0 1-3.84-.14 3.96 3.96 0 0 0-1.9-.4 3.9 3.9 0 0 0-1.85.54c.21.45.55.83.98 1.09s.93.4 1.44.39c-.2 1.61.7 3.5 2.83 4.49l.14.06a4.18 4.18 0 0 1-2.4-3.23z"/>
<path fill="url(#o)" d="M19.66 6.84a5.59 5.59 0 0 0-2.05-2.5 10.05 10.05 0 0 1 1.04 3v.02C17.49 4.57 15.54 3.45 13.94 1L13.7.62l-.12-.2a1.78 1.78 0 0 1-.15-.4c0-.02-.01-.02-.02-.02h-.02a7.18 7.18 0 0 0-3.52 5.5l.36-.02c.9 0 1.8.23 2.59.68A5.07 5.07 0 0 1 14.7 8a3.61 3.61 0 0 0-2.46-.58c3.67 1.77 2.69 7.9-2.4 7.67a4.7 4.7 0 0 1-1.33-.25l-.3-.12-.18-.08h.01l-.15-.07.14.07a4.18 4.18 0 0 1-2.4-3.23S6.1 9.72 9 9.72c.32 0 1.21-.85 1.23-1.1 0-.08-1.78-.76-2.47-1.43l-.7-.65a3.05 3.05 0 0 0-.27-.19 4.44 4.44 0 0 1-.03-2.42A7.53 7.53 0 0 0 4.3 5.77c-.4-.5-.38-2.13-.35-2.47-.12.04-.24.1-.34.17a8.68 8.68 0 0 0-1.95 1.94 8.22 8.22 0 0 0-1.38 3l-.01.06-.12.62A11.15 11.15 0 0 0 0 10.47v.05c0 2.48.97 4.86 2.7 6.68s4.1 2.95 6.65 3.16a10.45 10.45 0 0 0 7.1-2.02 9.84 9.84 0 0 0 3.83-6.14l.04-.39a9.88 9.88 0 0 0-.66-4.96z"/>
<defs>
<radialGradient id="c" cx="0" cy="0" r="1" gradientTransform="matrix(21 0 0 21 17.65 2.3)" href="#p">
<stop offset=".13" stop-color="#ffbd4f"/>
<stop offset=".19" stop-color="#ffac31"/>
<stop offset=".25" stop-color="#ff9d17"/>
<stop offset=".28" stop-color="#ff980e"/>
<stop offset=".4" stop-color="#ff563b"/>
<stop offset=".47" stop-color="#ff3750"/>
<stop offset=".71" stop-color="#f5156c"/>
<stop offset=".78" stop-color="#eb0878"/>
<stop offset=".86" stop-color="#e50080"/>
</radialGradient>
<radialGradient id="e" cx="0" cy="0" r="1" gradientTransform="matrix(21 0 0 21 9.75 10.72)" href="#p">
<stop offset=".3" stop-color="#960e18"/>
<stop offset=".35" stop-color="#b11927" stop-opacity=".74"/>
<stop offset=".43" stop-color="#db293d" stop-opacity=".34"/>
<stop offset=".5" stop-color="#f5334b" stop-opacity=".09"/>
<stop offset=".53" stop-color="#ff3750" stop-opacity="0"/>
</radialGradient>
<radialGradient id="f" cx="0" cy="0" r="1" gradientTransform="matrix(15 0 0 15 12.38 -2.3)" href="#p">
<stop offset=".13" stop-color="#fff44f"/>
<stop offset=".25" stop-color="#ffdc3e"/>
<stop offset=".51" stop-color="#ff9d12"/>
<stop offset=".53" stop-color="#ff980e"/>
</radialGradient>
<radialGradient id="g" cx="0" cy="0" r="1" gradientTransform="matrix(10 0 0 10 7.38 16.08)" href="#p">
<stop offset=".35" stop-color="#3a8ee6"/>
<stop offset=".47" stop-color="#5c79f0"/>
<stop offset=".67" stop-color="#9059ff"/>
<stop offset="1" stop-color="#c139e6"/>
</radialGradient>
<radialGradient id="i" cx="0" cy="0" r="1" gradientTransform="matrix(5 -1 1 6 10.78 8.95)" href="#p">
<stop offset=".21" stop-color="#9059ff" stop-opacity="0"/>
<stop offset=".28" stop-color="#8c4ff3" stop-opacity=".06"/>
<stop offset=".75" stop-color="#7716a8" stop-opacity=".45"/>
<stop offset=".97" stop-color="#6e008b" stop-opacity=".6"/>
</radialGradient>
<radialGradient id="j" cx="0" cy="0" r="1" gradientTransform="matrix(7 0 0 7 9.48 1.54)" href="#p">
<stop stop-color="#ffe226"/>
<stop offset=".12" stop-color="#ffdb27"/>
<stop offset=".29" stop-color="#ffc82a"/>
<stop offset=".5" stop-color="#ffa930"/>
<stop offset=".73" stop-color="#ff7e37"/>
<stop offset=".79" stop-color="#ff7139"/>
</radialGradient>
<radialGradient id="k" cx="0" cy="0" r="1" gradientTransform="matrix(31 0 0 30 15.28 -3.06)" href="#p">
<stop offset=".11" stop-color="#fff44f"/>
<stop offset=".46" stop-color="#ff980e"/>
<stop offset=".62" stop-color="#ff5634"/>
<stop offset=".72" stop-color="#ff3647"/>
<stop offset=".9" stop-color="#e31587"/>
</radialGradient>
<radialGradient id="l" cx="0" cy="0" r="1" gradientTransform="matrix(2 22 -15 2 12.7 -1.39)" href="#p">
<stop stop-color="#fff44f"/>
<stop offset=".06" stop-color="#ffe847"/>
<stop offset=".17" stop-color="#ffc830"/>
<stop offset=".3" stop-color="#ff980e"/>
<stop offset=".36" stop-color="#ff8b16"/>
<stop offset=".46" stop-color="#ff672a"/>
<stop offset=".57" stop-color="#ff3647"/>
<stop offset=".74" stop-color="#e31587"/>
</radialGradient>
<radialGradient id="m" cx="0" cy="0" r="1" gradientTransform="matrix(19 0 0 19 9.48 4.09)" href="#p">
<stop offset=".14" stop-color="#fff44f"/>
<stop offset=".48" stop-color="#ff980e"/>
<stop offset=".59" stop-color="#ff5634"/>
<stop offset=".66" stop-color="#ff3647"/>
<stop offset=".9" stop-color="#e31587"/>
</radialGradient>
<radialGradient id="n" cx="0" cy="0" r="1" gradientTransform="matrix(21 0 0 21 14.5 5.1)" href="#p">
<stop offset=".09" stop-color="#fff44f"/>
<stop offset=".23" stop-color="#ffe141"/>
<stop offset=".51" stop-color="#ffaf1e"/>
<stop offset=".63" stop-color="#ff980e"/>
</radialGradient>
<linearGradient id="b" x1="18.31" x2="1.88" y1="3.17" y2="19.53" href="#p">
<stop offset=".05" stop-color="#fff44f"/>
<stop offset=".11" stop-color="#ffe847"/>
<stop offset=".23" stop-color="#ffc830"/>
<stop offset=".37" stop-color="#ff980e"/>
<stop offset=".4" stop-color="#ff8b16"/>
<stop offset=".46" stop-color="#ff672a"/>
<stop offset=".53" stop-color="#ff3647"/>
<stop offset=".7" stop-color="#e31587"/>
</linearGradient>
<linearGradient id="o" x1="18.1" x2="4.14" y1="3.08" y2="17.49" href="#p">
<stop offset=".17" stop-color="#fff44f" stop-opacity=".8"/>
<stop offset=".27" stop-color="#fff44f" stop-opacity=".63"/>
<stop offset=".49" stop-color="#fff44f" stop-opacity=".22"/>
<stop offset=".6" stop-color="#fff44f" stop-opacity="0"/>
</linearGradient>
<linearGradient id="p" gradientUnits="userSpaceOnUse"/>
<path id="d" d="M19.66 6.85a5.59 5.59 0 0 0-2.05-2.5c.5.94.85 1.95 1.04 3v.02a8.7 8.7 0 0 1-.32 6.67c-1.17 2.43-4 4.92-8.44 4.8-4.79-.13-9-3.57-9.8-8.08-.14-.71 0-1.07.08-1.65-.1.45-.16.9-.17 1.36v.05c0 2.48.97 4.86 2.7 6.68s4.1 2.95 6.65 3.16a10.45 10.45 0 0 0 7.1-2.02 9.84 9.84 0 0 0 3.83-6.14l.04-.38a9.87 9.87 0 0 0-.66-4.97z"/>
<path id="h" d="M10.23 8.63C10.2 8.87 9.3 9.72 9 9.72c-2.9 0-3.38 1.7-3.38 1.7a4.18 4.18 0 0 0 2.41 3.24l.17.08.3.12c.43.14.88.23 1.33.24 5.1.23 6.08-5.9 2.4-7.67.87-.1 1.75.1 2.47.58a5.24 5.24 0 0 0-4.47-2.53l-.37.02a5.2 5.2 0 0 0-2.8 1.05c.15.12.32.3.7.65.69.66 2.46 1.34 2.47 1.42z"/>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 8.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.1 KiB

View File

@ -1 +0,0 @@
export { default as BaselineStatus } from './BaselineStatus.astro';

View File

@ -1,33 +0,0 @@
{
"name": "@astro-community/astro-embed-baseline-status",
"version": "0.1.2",
"description": "Component to easily embed the Baseline status of a web feature on your Astro site",
"type": "module",
"exports": {
".": "./index.ts"
},
"repository": {
"type": "git",
"url": "git+https://github.com/delucis/astro-embed.git",
"directory": "packages/astro-embed-baseline-status"
},
"keywords": [
"astro",
"astro-component",
"ui",
"embeds",
"baseline"
],
"author": "delucis",
"license": "MIT",
"bugs": {
"url": "https://github.com/delucis/astro-embed/issues"
},
"homepage": "https://astro-embed.netlify.app/components/baseline-status/",
"dependencies": {
"@astro-community/astro-embed-utils": "^0.1.0"
},
"peerDependencies": {
"astro": "^4.0.0-beta || ^5.0.0-beta"
}
}

View File

@ -1,14 +0,0 @@
export type StatusLevel = 'widely' | 'newly' | 'limited' | 'no_data';
export type SupportLevel = 'available' | 'unavailable' | 'no_data';
export type Browser = 'chrome' | 'edge' | 'firefox' | 'safari';
export interface BrowserImplementation {
status: SupportLevel;
}
export interface Feature {
name: string;
feature_id?: string;
browser_implementations?: Record<Browser, BrowserImplementation>;
baseline: { status?: StatusLevel; low_date?: string };
}

View File

@ -1,25 +0,0 @@
# @astro-community/astro-embed-bluesky
## 0.1.3
### Patch Changes
- [#178](https://github.com/delucis/astro-embed/pull/178) [`8c5c7f9377121bfd91d70be94584a66d29b0a5a7`](https://github.com/delucis/astro-embed/commit/8c5c7f9377121bfd91d70be94584a66d29b0a5a7) Thanks [@IsaacRF](https://github.com/IsaacRF)! - Fixes hashtag links in Bluesky embeds
## 0.1.2
### Patch Changes
- [#174](https://github.com/delucis/astro-embed/pull/174) [`c9cc93aaf756446f5feb84f68abeef8ea4816dec`](https://github.com/delucis/astro-embed/commit/c9cc93aaf756446f5feb84f68abeef8ea4816dec) Thanks [@ascorbic](https://github.com/ascorbic)! - Allow PostView to be passed to embed
## 0.1.1
### Patch Changes
- [#169](https://github.com/delucis/astro-embed/pull/169) [`a1524686a80ca1ede97853df6ba6ba7dd8a5dfd2`](https://github.com/delucis/astro-embed/commit/a1524686a80ca1ede97853df6ba6ba7dd8a5dfd2) Thanks [@ascorbic](https://github.com/ascorbic)! - Fixes Bluesky logo and styling of links in posts
## 0.1.0
### Minor Changes
- [#167](https://github.com/delucis/astro-embed/pull/167) [`22779f0a7b48283e4c6a71f7b01641d93fdb2a6f`](https://github.com/delucis/astro-embed/commit/22779f0a7b48283e4c6a71f7b01641d93fdb2a6f) Thanks [@ascorbic](https://github.com/ascorbic)! - Adds Bluesky Post embed

View File

@ -1,5 +0,0 @@
# `@astro-community/astro-embed-bluesky`
This package contains a component for embedding Bluesky posts in Astro projects.
[Read the `<BlueskyPost>` component docs](https://astro-embed.netlify.app/components/bluesky/).

View File

@ -1,39 +0,0 @@
{
"name": "@astro-community/astro-embed-bluesky",
"version": "0.1.3",
"description": "Component to embed a fully-styled Bluesky post with no client-side JavaScript in your Astro site",
"type": "module",
"files": [
"src"
],
"exports": {
".": "./src/index.ts",
"./matcher": "./src/matcher.ts"
},
"peerDependencies": {
"astro": "^4.0.0 || ^5.0.0-beta.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/delucis/astro-embed.git",
"directory": "packages/astro-embed-bluesky"
},
"bugs": {
"url": "https://github.com/delucis/astro-embed/issues"
},
"homepage": "https://astro-embed.netlify.app/components/bluesky/",
"keywords": [
"withastro",
"astro",
"astro-component",
"ui",
"embeds",
"bluesky"
],
"author": "Matt Kane",
"license": "MIT",
"dependencies": {
"@atproto/api": "^0.13.14",
"ts-pattern": "^5.5.0"
}
}

View File

@ -1,54 +0,0 @@
---
import type { AppBskyActorDefs } from '@atproto/api';
type Props = {
user: AppBskyActorDefs.ProfileViewBasic;
link?: boolean | undefined;
size?: 'small' | 'medium' | undefined;
};
const { user, link, size = 'medium' } = Astro.props;
const src = user.avatar;
---
{
link ? (
<a
class:list={['avatar', size]}
href={`https://bsky.app/profile/${user?.handle}`}
target="_blank"
rel="noopener noreferrer nofollow"
>
{src && <img src={src} alt={user.displayName ?? user.handle} />}
</a>
) : (
<div class:list={['avatar', size]}>
{src && <img src={src} alt={user.displayName ?? user.handle} />}
</div>
)
}
<style>
.avatar {
border-radius: var(--bluesky-radius-full);
overflow: hidden;
background-color: var(--bluesky-color-border);
flex-shrink: 0;
}
.avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.medium {
width: 2.5rem;
height: 2.5rem;
}
.small {
width: 1rem;
height: 1rem;
}
</style>

View File

@ -1,102 +0,0 @@
---
import { AppBskyActorDefs } from '@atproto/api';
import Avatar from './avatar.astro';
interface Props {
href: string;
image?:
| {
src: string;
alt?: string;
}
| undefined;
avatarUser: AppBskyActorDefs.ProfileViewBasic;
title: string;
subtitle: string;
description?: string | undefined;
}
const { href, image, avatarUser, title, subtitle, description } = Astro.props;
---
<a href={href} target="_blank" rel="noopener noreferrer nofollow" class="card">
{image && <img class="cover-image" src={image.src} alt={image.alt ?? ''} />}
<div class="content">
<div class="header">
<Avatar user={avatarUser} />
<div class="title-group">
<p class="title">{title}</p>
<p class="subtitle">{subtitle}</p>
</div>
</div>
{description && <p class="description">{description}</p>}
</div>
</a>
<style>
.card {
display: flex;
flex-direction: column;
width: 100%;
border: var(--bluesky-card-border);
border-radius: var(--bluesky-radius-md);
overflow: hidden;
text-decoration: none;
color: var(--bluesky-color-text);
background: var(--bluesky-color-background);
transition: var(--bluesky-card-transition);
}
.card:hover {
background: var(--bluesky-color-background-hover);
}
.cover-image {
aspect-ratio: var(--bluesky-aspect-ratio-thumb);
width: 100%;
height: auto;
object-fit: cover;
}
.content {
padding: var(--bluesky-content-padding);
}
.header {
display: flex;
gap: var(--bluesky-card-gap);
align-items: center;
}
.avatar {
width: var(--bluesky-avatar-md);
height: var(--bluesky-avatar-md);
}
.title-group {
display: flex;
flex-direction: column;
gap: var(--bluesky-space-2xs);
}
.title {
font-weight: var(--bluesky-font-weight-semibold);
line-height: var(--bluesky-line-height-title);
margin: 0;
color: var(--bluesky-color-text);
}
.subtitle {
font-size: var(--bluesky-font-size-sm);
color: var(--bluesky-color-text-secondary);
line-height: var(--bluesky-line-height-subtitle);
margin: 0;
}
.description {
font-size: var(--bluesky-font-size-sm);
color: var(--bluesky-color-text-secondary);
line-height: var(--bluesky-line-height-normal);
margin: var(--bluesky-space-xs) 0 0 0;
}
</style>

View File

@ -1,69 +0,0 @@
---
import type { EmbedView } from './types';
import { match, P } from 'ts-pattern';
import {
AppBskyEmbedExternal,
AppBskyEmbedImages,
AppBskyEmbedRecord,
AppBskyEmbedRecordWithMedia,
AppBskyEmbedVideo,
AppBskyGraphDefs,
} from '@atproto/api';
import External from './external.astro';
import ImageGrid from './image-grid.astro';
import VideoThumbnail from './video-thumbnail.astro';
import QuoteEmbed from './quote-embed.astro';
import StarterPack from './starter-pack.astro';
import List from './list.astro';
interface Props {
embed?: EmbedView | undefined | null;
postUrl: string;
compact?: boolean | undefined;
}
const { embed, postUrl, compact } = Astro.props;
---
{
match(embed)
.when(AppBskyEmbedRecordWithMedia.isView, (embed) => (
<div class="record-with-media">
<Astro.self embed={embed.media} postUrl={postUrl} compact={compact} />
<QuoteEmbed embed={embed.record} />
</div>
))
.when(AppBskyEmbedExternal.isView, (media) => (
<External embed={media} compact={compact} />
))
.when(AppBskyEmbedImages.isView, (media) => (
<a href={postUrl}>
<ImageGrid images={media.images} />
</a>
))
.when(AppBskyEmbedVideo.isView, (media) => (
<a href={postUrl}>
<VideoThumbnail
thumbnail={media.thumbnail}
aspectRatio={media.aspectRatio}
/>
</a>
))
.with(
{ record: P.when(AppBskyGraphDefs.isStarterPackViewBasic) },
(media) => <StarterPack record={media.record} />
)
.with({ record: P.when(AppBskyGraphDefs.isListView) }, (media) => (
<List record={media.record} />
))
.when(AppBskyEmbedRecord.isView, (media) => <QuoteEmbed embed={media} />)
.with(P.nullish, () => null)
.otherwise((media) => media?.$type)
}
<style>
.record-with-media {
display: flex;
flex-direction: column;
gap: var(--bluesky-space-sm);
}
</style>

View File

@ -1,87 +0,0 @@
---
import { AppBskyEmbedExternal } from '@atproto/api';
interface Props {
embed: AppBskyEmbedExternal.View;
compact?: boolean | undefined;
}
const { uri, thumb, title, description } = Astro.props.embed.external;
const domain = new URL(uri).hostname;
const { compact } = Astro.props;
---
<a
href={uri}
target="_blank"
rel="noopener noreferrer nofollow"
class="external-link"
>
{!compact && thumb && <img src={thumb} alt={title} class="thumbnail" />}
<div class="content">
<p class="domain">{domain}</p>
{
!compact && (
<>
<p class="title">{title}</p>
<p class="description">{description}</p>
</>
)
}
</div>
</a>
<style>
.external-link {
display: flex;
flex-direction: column;
width: 100%;
border: var(--bluesky-card-border);
border-radius: var(--bluesky-radius-md);
overflow: hidden;
text-decoration: none;
color: var(--bluesky-color-text);
background: var(--bluesky-color-background);
transition: var(--bluesky-card-transition);
}
.thumbnail {
aspect-ratio: var(--bluesky-aspect-ratio-thumb);
width: 100%;
height: auto;
object-fit: cover;
}
.content {
padding: var(--bluesky-content-padding);
}
.domain {
font-size: var(--bluesky-font-size-sm);
color: var(--bluesky-color-text-secondary);
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.title {
font-weight: var(--bluesky-font-weight-semibold);
margin: 0;
color: var(--bluesky-color-text);
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.description {
font-size: var(--bluesky-font-size-sm);
color: var(--bluesky-color-text-secondary);
margin: var(--bluesky-space-xs) 0 0 0;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
</style>

View File

@ -1,81 +0,0 @@
---
interface Props {
images: Array<{
thumb: string;
alt: string | undefined;
}>;
}
const { images } = Astro.props;
---
<div class="image-grid-container">
<div class:list={['image-grid', `image-grid--${images.length}`]}>
{
images.map((image) => (
<div class="image-grid-item">
<img
src={image.thumb}
alt={image.alt || ''}
loading="lazy"
decoding="async"
/>
</div>
))
}
</div>
</div>
<style>
.image-grid-container {
width: 100%;
max-width: var(--bluesky-content-max-width);
margin: 0 auto;
aspect-ratio: var(--bluesky-aspect-ratio-thumb);
}
.image-grid {
width: 100%;
height: 100%;
display: grid;
gap: var(--bluesky-space-xs);
border-radius: var(--bluesky-radius-md);
overflow: hidden;
}
.image-grid-item {
position: relative;
overflow: hidden;
width: 100%;
height: 100%;
background-color: var(--bluesky-color-border);
}
.image-grid-item img {
width: 100%;
height: 100%;
object-fit: cover;
}
/* Grid Layouts */
.image-grid--1 {
grid-template-columns: 1fr;
}
.image-grid--2 {
grid-template-columns: repeat(2, 1fr);
}
.image-grid--3 {
grid-template-columns: repeat(2, 1fr);
}
.image-grid--3 .image-grid-item:first-child {
grid-row: span 2;
}
.image-grid--4 {
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, 1fr);
}
</style>

View File

@ -1,2 +0,0 @@
export { default as BlueskyPost } from './post.astro';
export type { Post } from './types';

View File

@ -1,26 +0,0 @@
---
import { AppBskyGraphDefs } from '@atproto/api';
import { atUriToListUri } from './utils';
import Card from './card.astro';
interface Props {
record: AppBskyGraphDefs.ListView;
}
const { record } = Astro.props;
const list = AppBskyGraphDefs.isListView(record) ? record : null;
const purposes: Record<AppBskyGraphDefs.ListPurpose, string> = {
'app.bsky.graph.defs#curatelist': 'User list',
'app.bsky.graph.defs#modlist': 'Moderation list',
'app.bsky.graph.defs#referencelist': 'List',
};
const purpose = (list && purposes[list.purpose]) ?? 'List';
---
<Card
href={atUriToListUri(record.uri)}
avatarUser={record.creator}
title={list?.name || ''}
subtitle={`${purpose} by ${record.creator.displayName}`}
description={list?.description}
/>

View File

@ -1,8 +0,0 @@
const urlPattern = /^https:\/\/bsky\.app\/profile\/[^/]+\/post\/[^/]+$/;
/**
* Tests if a URL is a Bluesky post URL. If it is, returns the URL, otherwise returns undefined.
*/
export default function matcher(url: string): string | undefined {
const match = url.match(urlPattern);
return match ? url : undefined;
}

View File

@ -1,38 +0,0 @@
---
interface Props {
aspectRatio?: { width: number; height: number } | undefined;
onClick?: (() => void) | undefined;
className?: string | undefined;
}
const { aspectRatio, onClick, className = '' } = Astro.props;
---
<div
class:list={['media-container', className]}
style={{
aspectRatio: aspectRatio
? `${aspectRatio.width}/${aspectRatio.height}`
: undefined,
}}
{...onClick ? { onClick } : {}}
>
<slot />
</div>
<style>
.media-container {
width: 100%;
overflow: hidden;
border-radius: var(--bluesky-radius-md);
position: relative;
background-color: var(--bluesky-color-border);
}
/* Ensure direct img children fill container */
.media-container > img {
width: 100%;
height: 100%;
object-fit: cover;
}
</style>

View File

@ -1,163 +0,0 @@
---
import { atUriToPostUri, renderPostAsHtml, resolvePost } from './utils.js';
import Embed from './embed.astro';
import type { Post } from './types';
import './styles.css';
import Avatar from './avatar.astro';
import type { AppBskyFeedDefs } from '@atproto/api';
type Props = {
id?: string;
post?: string | Post | AppBskyFeedDefs.PostView;
};
const postRef = Astro.props.id ?? Astro.props.post;
if (!postRef) {
return new Response('');
}
const post = await resolvePost(postRef)!;
if (!post) {
return new Response('');
}
const postUrl = atUriToPostUri(post.uri);
const { record, embed, author } = post;
const authorUrl = `https://bsky.app/profile/${author?.handle}`;
const body = renderPostAsHtml(post);
const formatter = new Intl.DateTimeFormat('en-US', {
month: 'long',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: 'numeric',
timeZone: 'UTC',
timeZoneName: 'short',
});
---
<div class="bluesky-post-container not-content">
<div class="post-content">
<div class="post-header">
<Avatar user={author} link={true} />
<div class="user-info">
<a href={authorUrl} class="display-name">{author?.displayName}</a>
<a href={authorUrl} class="username">@{author?.handle}</a>
</div>
<a href={postUrl} class="logo-link">
<img
src="data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20fill='none'%20viewBox='0%200%20320%20286'%3e%3cpath%20fill='rgb(10,122,255)'%20d='M69.364%2019.146c36.687%2027.806%2076.147%2084.186%2090.636%20114.439%2014.489-30.253%2053.948-86.633%2090.636-114.439C277.107-.917%20320-16.44%20320%2032.957c0%209.865-5.603%2082.875-8.889%2094.729-11.423%2041.208-53.045%2051.719-90.071%2045.357%2064.719%2011.12%2081.182%2047.953%2045.627%2084.785-80%2082.874-106.667-44.333-106.667-44.333s-26.667%20127.207-106.667%2044.333c-35.555-36.832-19.092-73.665%2045.627-84.785-37.026%206.362-78.648-4.149-90.071-45.357C5.603%20115.832%200%2042.822%200%2032.957%200-16.44%2042.893-.917%2069.364%2019.147Z'/%3e%3c/svg%3e"
class="bluesky-logo"
alt="Bluesky"
/>
</a>
</div>
<p class="post-text" set:html={body} />
{embed && <Embed embed={embed} postUrl={postUrl} />}
<a href={postUrl} class="timestamp">
{formatter.format(new Date(record.createdAt ?? ''))}
</a>
</div>
</div>
<style>
.bluesky-post-container {
max-width: var(--bluesky-content-max-width);
min-width: var(--bluesky-content-min-width);
margin: 0 auto;
font-family: var(--bluesky-font-family);
border: var(--bluesky-card-border);
border-radius: var(--bluesky-radius-lg);
background: var(--bluesky-color-background);
transition: var(--bluesky-card-transition);
}
.bluesky-post-container .post-content :global(a) {
text-decoration: none;
}
.post-content {
padding: var(--bluesky-space-md) var(--bluesky-space-lg)
var(--bluesky-space-sm);
}
.post-header {
display: grid;
grid-template-columns: min-content 1fr min-content;
gap: var(--bluesky-space-sm);
align-items: start;
margin-bottom: var(--bluesky-space-sm);
}
.user-info {
display: flex;
flex-direction: column;
}
.display-name {
font-weight: var(--bluesky-font-weight-bold);
font-size: var(--bluesky-font-size-lg);
line-height: var(--bluesky-line-height-tight);
text-decoration: none;
color: var(--bluesky-color-text);
}
.username {
color: var(--bluesky-color-text-secondary);
font-size: var(--bluesky-font-size-base);
text-decoration: none;
}
.display-name:hover,
.username:hover {
text-decoration: underline;
text-underline-offset: 2px;
}
.logo-link {
text-decoration: none;
}
.bluesky-logo {
height: var(--bluesky-icon-size-lg);
transition: transform 0.2s ease;
}
.bluesky-logo:hover {
transform: scale(1.1);
}
.post-text {
font-size: var(--bluesky-font-size-lg);
line-height: var(--bluesky-line-height-normal);
margin: 0 0 var(--bluesky-space-md);
white-space: pre-wrap;
word-break: break-word;
color: var(--bluesky-color-text);
}
.bluesky-post-container .post-text :global(a) {
color: var(--bluesky-color-link);
text-decoration: none;
}
.bluesky-post-container .timestamp:hover,
.bluesky-post-container .post-text :global(a:hover) {
text-decoration: underline;
}
.timestamp {
display: block;
color: var(--bluesky-color-text-secondary);
font-size: var(--bluesky-font-size-sm);
margin-top: var(--bluesky-space-sm);
text-decoration: none;
}
</style>

View File

@ -1,91 +0,0 @@
---
import { AppBskyEmbedRecord, AppBskyFeedPost } from '@atproto/api';
import Embed from './embed.astro';
import { atUriToPostUri, viewRecordToEmbed } from './utils';
import Avatar from './avatar.astro';
interface Props {
embed: AppBskyEmbedRecord.View;
}
const { embed } = Astro.props;
---
{
AppBskyEmbedRecord.isViewRecord(embed.record) &&
AppBskyFeedPost.isRecord(embed.record.value) ? (
<div class="post-container">
<a href={atUriToPostUri(embed.record.uri)} class="post-link">
<div class="user-info">
<Avatar user={embed.record.author} size="small" />
<p class="user-text">
<span class="name">{embed.record.author.displayName}</span>
<span class="handle">@{embed.record.author.handle}</span>
</p>
</div>
</a>
<a href={atUriToPostUri(embed.record.uri)} class="post-link">
<p class="content">{embed.record.value.text}</p>
</a>
<Embed
embed={viewRecordToEmbed(embed.record)}
postUrl={atUriToPostUri(embed.record.uri)}
compact={true}
/>
</div>
) : null
}
<style>
.post-container {
border: var(--bluesky-card-border);
border-radius: var(--bluesky-radius-md);
display: flex;
flex-direction: column;
gap: var(--bluesky-space-xs);
padding: var(--bluesky-space-sm);
text-decoration: none;
color: var(--bluesky-color-text);
transition: var(--bluesky-card-transition);
}
.post-link {
text-decoration: none;
}
.post-container:hover {
background-color: var(--bluesky-color-background-hover);
}
.user-info {
display: flex;
gap: var(--bluesky-space-xs);
align-items: center;
}
.user-text {
font-size: var(--bluesky-font-size-sm);
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--bluesky-color-text);
}
.name {
font-weight: var(--bluesky-font-weight-bold);
color: var(--bluesky-color-text);
}
.handle {
color: var(--bluesky-color-text-secondary);
margin-left: var(--bluesky-space-xs);
}
.content {
font-size: var(--bluesky-font-size-sm);
color: var(--bluesky-color-text);
margin: 0;
line-height: var(--bluesky-line-height-normal);
}
</style>

View File

@ -1,27 +0,0 @@
---
import { AppBskyGraphDefs, AppBskyGraphStarterpack } from '@atproto/api';
import { atUriToStarterPackUri, starterPackOgImage } from './utils';
import Card from './card.astro';
interface Props {
record: AppBskyGraphDefs.StarterPackViewBasic;
}
const { record } = Astro.props;
const pack = AppBskyGraphStarterpack.isRecord(record.record)
? record.record
: null;
---
<Card
href={atUriToStarterPackUri(record.uri)}
image={{
src: starterPackOgImage(record.uri),
alt: pack?.name || 'Starter pack cover image',
}}
avatarUser={record.creator}
title={pack?.name || ''}
subtitle={`Starter pack by ${record.creator.displayName}`}
description={pack?.description}
/>

View File

@ -1,124 +0,0 @@
.bluesky-post-container {
/* Colours */
--bluesky-color-overlay: rgba(0, 0, 0, 0.5);
--bluesky-color-link: rgb(59 130 246);
/* Colour palette */
--bluesky-color-text--light: #000000;
--bluesky-color-text-secondary--light: rgb(66 87 108);
--bluesky-color-border--light: #e5e5e5;
--bluesky-color-background--light: #ffffff;
--bluesky-color-background-hover--light: #fafafa;
--bluesky-color-text--dark: white;
--bluesky-color-text-secondary--dark: rgb(174, 187, 201);
--bluesky-color-border--dark: rgb(46, 64, 82);
--bluesky-color-background--dark: hsl(211, 20%, 20%);
--bluesky-color-background-hover--dark: hsl(211, 20%, 15%);
/* Light theme */
--bluesky-color-text: var(--bluesky-color-text--light);
--bluesky-color-text-secondary: var(--bluesky-color-text-secondary--light);
--bluesky-color-border: var(--bluesky-color-border--light);
--bluesky-color-background: var(--bluesky-color-background--light);
--bluesky-color-background-hover: var(
--bluesky-color-background-hover--light
);
/* Typography */
--bluesky-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', Arial, sans-serif;
--bluesky-font-size-sm: 0.875rem; /* 14px */
--bluesky-font-size-base: 1rem; /* 16px */
--bluesky-font-size-lg: 1.125rem; /* 18px */
--bluesky-font-weight-normal: 400;
--bluesky-font-weight-medium: 500;
--bluesky-font-weight-semibold: 600;
--bluesky-font-weight-bold: 700;
--bluesky-line-height-tight: 1.2;
--bluesky-line-height-normal: 1.4;
--bluesky-line-height-relaxed: 1.6;
--bluesky-line-height-title: 21px;
--bluesky-line-height-subtitle: 18px;
/* Spacing */
--bluesky-space-2xs: 0.125rem; /* 2px */
--bluesky-space-xs: 0.25rem; /* 4px */
--bluesky-space-sm: 0.5rem; /* 8px */
--bluesky-space-md: 0.75rem; /* 12px */
--bluesky-space-lg: 1rem; /* 16px */
--bluesky-space-xl: 1.25rem; /* 20px */
--bluesky-space-2xl: 1.5rem; /* 24px */
/* Layout */
--bluesky-radius-sm: 0.25rem; /* 4px */
--bluesky-radius-md: 0.5rem; /* 8px */
--bluesky-radius-lg: 0.75rem; /* 12px */
--bluesky-radius-full: 9999px;
/* Content */
--bluesky-content-max-width: 600px;
--bluesky-content-min-width: 300px;
--bluesky-content-padding-x: var(--bluesky-space-lg);
--bluesky-content-padding-y: var(--bluesky-space-md);
--bluesky-content-padding: var(--bluesky-content-padding-y)
var(--bluesky-content-padding-x);
/* Cards & Components */
--bluesky-card-gap: var(--bluesky-space-sm);
--bluesky-card-border: 1px solid var(--bluesky-color-border);
--bluesky-card-padding: var(--bluesky-content-padding);
--bluesky-card-transition: background-color 0.2s ease;
/* Media */
--bluesky-aspect-ratio-thumb: 1.91/1;
--bluesky-aspect-ratio-square: 1/1;
--bluesky-aspect-ratio-video: 16/9;
/* Icons */
--bluesky-icon-size-sm: 1rem;
--bluesky-icon-size-md: 1.5rem;
--bluesky-icon-size-lg: 2rem;
}
/* Dark theme */
@media (prefers-color-scheme: dark) {
.bluesky-post-container {
--bluesky-color-text: var(--bluesky-color-text--light);
--bluesky-color-text-secondary: var(--bluesky-color-text-secondary--light);
--bluesky-color-border: var(--bluesky-color-border--light);
--bluesky-color-background: var(--bluesky-color-background--light);
--bluesky-color-background-hover: var(
--bluesky-color-background-hover--light
);
}
}
/* Dynamic colours when supported */
@supports (--color: light-dark(var(--a), var(--b))) {
.bluesky-post-container {
--bluesky-color-text: light-dark(
var(--bluesky-color-text--light),
var(--bluesky-color-text--dark)
);
--bluesky-color-text-secondary: light-dark(
var(--bluesky-color-text-secondary--light),
var(--bluesky-color-text-secondary--dark)
);
--bluesky-color-border: light-dark(
var(--bluesky-color-border--light),
var(--bluesky-color-border--dark)
);
--bluesky-color-background: light-dark(
var(--bluesky-color-background--light),
var(--bluesky-color-background--dark)
);
--bluesky-color-background-hover: light-dark(
var(--bluesky-color-background-hover--light),
var(--bluesky-color-background-hover--dark)
);
}
}

View File

@ -1,21 +0,0 @@
import {
AppBskyFeedPost,
AppBskyFeedDefs,
AppBskyEmbedRecord,
AppBskyEmbedExternal,
AppBskyEmbedImages,
AppBskyEmbedRecordWithMedia,
AppBskyEmbedVideo,
} from '@atproto/api';
export interface Post extends AppBskyFeedDefs.PostView {
record: AppBskyFeedPost.Record;
}
export type EmbedView =
| AppBskyEmbedRecord.View
| AppBskyEmbedImages.View
| AppBskyEmbedVideo.View
| AppBskyEmbedExternal.View
| AppBskyEmbedRecordWithMedia.View
| { [k: string]: unknown; $type: string };

View File

@ -1,159 +0,0 @@
import {
AppBskyEmbedExternal,
AppBskyEmbedImages,
AppBskyEmbedRecord,
AppBskyEmbedRecordWithMedia,
AppBskyEmbedVideo,
AppBskyFeedDefs,
AtpAgent,
RichText,
} from '@atproto/api';
import type { Post } from './types';
const escapeMap: Record<string, string> = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
};
export const escapeHTML = (str?: string) =>
str?.replace(/[&<>"']/g, (match) => escapeMap[match] || match) ?? '';
export function renderPostAsHtml(post?: AppBskyFeedDefs.PostView | Post) {
if (!post) {
return '';
}
const rt = new RichText(post.record as any);
let html = '';
for (const segment of rt.segments()) {
if (segment.isLink()) {
html += `<a href="${escapeHTML(segment.link?.uri)}">${escapeHTML(
segment.text
)}</a>`;
} else if (segment.isMention()) {
html += `<a href="https://bsky.app/profile/${escapeHTML(
segment.mention?.did
)}">${escapeHTML(segment.text)}</a>`;
} else if (segment.isTag()) {
html += `<a href="https://bsky.app/hashtag/${escapeHTML(
segment.tag?.tag
)}">#${escapeHTML(segment.tag?.tag)}</a>`;
} else {
html += escapeHTML(segment.text);
}
}
return html;
}
export function viewRecordToPostView(
viewRecord: AppBskyEmbedRecord.ViewRecord
): AppBskyFeedDefs.PostView {
const { value, embeds, ...rest } = viewRecord;
return {
...rest,
$type: 'app.bsky.feed.defs#postView',
record: value,
embed: embeds?.[0],
} as AppBskyFeedDefs.PostView;
}
export function viewRecordToEmbed(
viewRecord: AppBskyEmbedRecord.ViewRecord,
allowNestedQuotes = false
) {
const { embed } = viewRecordToPostView(viewRecord);
if (allowNestedQuotes) {
return embed;
} else {
if (
AppBskyEmbedImages.isView(embed) ||
AppBskyEmbedExternal.isView(embed) ||
AppBskyEmbedVideo.isView(embed)
) {
return embed;
} else if (
AppBskyEmbedRecordWithMedia.isView(embed) &&
(AppBskyEmbedImages.isView(embed.media) ||
AppBskyEmbedExternal.isView(embed.media) ||
AppBskyEmbedVideo.isView(embed.media))
) {
return embed.media;
}
}
return undefined;
}
const agent = new AtpAgent({
service: 'https://public.api.bsky.app',
});
export async function resolvePost(
postUrl: string | Post | AppBskyFeedDefs.PostView
): Promise<Post | undefined> {
let atUri;
if (typeof postUrl === 'object') {
return postUrl as Post;
}
if (postUrl.startsWith('at:')) {
atUri = postUrl;
} else {
if (!postUrl.startsWith('https://bsky.app/')) {
return undefined;
}
const urlParts = new URL(postUrl).pathname.split('/');
let did = urlParts[2]!;
const postId = urlParts[4]!;
if (!did || !postId) {
return undefined;
}
if (!did.startsWith('did:')) {
try {
const handleResolution = await agent.resolveHandle({ handle: did });
if (!handleResolution.data.did) {
return undefined;
}
did = handleResolution.data.did;
} catch (e: any) {
console.error(
`[error] astro-embed` + '\n ' + (e?.message ?? e)
);
return undefined;
}
}
atUri = `at://${did}/app.bsky.feed.post/${postId}`;
}
try {
const hydratedPost = await agent.getPosts({ uris: [atUri] });
return hydratedPost.data.posts[0] as unknown as Post;
} catch (e: any) {
console.error(`[error] astro-embed` + '\n ' + (e?.message ?? e));
return undefined;
}
}
export function atUriToPostUri(atUri: string) {
const [, , did, , postId] = atUri.split('/');
return `https://bsky.app/profile/${did}/post/${postId}`;
}
export function atUriToStarterPackUri(atUri: string) {
const [, , did, , packId] = atUri.split('/');
return `https://bsky.app/starter-pack/${did}/${packId}`;
}
export function atUriToListUri(atUri: string) {
const [, , did, , listId] = atUri.split('/');
return `https://bsky.app/profile/${did}/lists/${listId}`;
}
export function starterPackOgImage(uri: string) {
const [, , did, , packId] = uri.split('/');
return `https://ogcard.cdn.bsky.app/start/${did}/${packId}`;
}

View File

@ -1,49 +0,0 @@
---
import MediaContainer from './media-container.astro';
interface Props {
thumbnail?: string | undefined;
aspectRatio?: { width: number; height: number } | undefined;
}
const { thumbnail, aspectRatio } = Astro.props;
---
<MediaContainer aspectRatio={aspectRatio}>
{thumbnail && <img src={thumbnail} class="thumbnail" alt="Video thumbnail" />}
<div class="play-button">
<img
src="data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20fill='none'%20viewBox='0%200%2024%2024'%3e%3cpath%20fill='%23fff'%20d='M9.576%202.534C7.578%201.299%205%202.737%205%205.086v13.828c0%202.35%202.578%203.787%204.576%202.552l11.194-6.914c1.899-1.172%201.899-3.932%200-5.104L9.576%202.534Z'/%3e%3c/svg%3e"
class="play-icon"
alt="Play button"
/>
</div>
</MediaContainer>
<style>
.play-button {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 6rem;
height: 6rem;
border-radius: var(--bluesky-radius-full);
background-color: var(--bluesky-color-overlay);
display: flex;
align-items: center;
justify-content: center;
}
.play-icon {
width: 60%;
height: 60%;
object-fit: cover;
}
.thumbnail {
width: 100%;
height: 100%;
object-fit: cover;
}
</style>

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