This commit is contained in:
bignutty
2025-09-16 18:10:22 +02:00
parent 29789de5a5
commit 6a11dd3887
45 changed files with 5076 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
node_modules
dist
_pagex
.idea

21
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,21 @@
image: node:24-alpine
variables:
GIT_SUBMODULE_STRATEGY: recursive
GIT_SUBMODULE_FORCE_HTTPS: "true"
before_script:
- npm ci
pages:
script:
# Add brotli for compression
- apk add --no-cache brotli
# Build app
- npm run build
# Optimize output files via gzip & brotli
- find dist -type f -regex '.*\.\(htm\|html\|xml\|txt\|text\|js\|css\|svg\|woff2\)$' -exec gzip -f -k {} \;
- find dist -type f -regex '.*\.\(htm\|html\|xml\|txt\|text\|js\|css\|svg\|woff2\)$' -exec brotli -f -k {} \;
pages:
publish: dist
rules:
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH

18
.gitmodules vendored Normal file
View File

@@ -0,0 +1,18 @@
[submodule "webfont"]
path = webfont
url = ../webfont
[submodule "pagex"]
path = pagex
url = ../pagex
[submodule "voidcannon"]
path = voidcannon
url = ../voidcannon
[submodule "webicons"]
path = webicons
url = ../webicons
[submodule "gm3"]
path = gm3
url = ../gm3
[submodule "pagex_commons"]
path = pagex_commons
url = ../pagex_commons

1
gm3 Submodule

Submodule gm3 added at 89e8aca9ee

3908
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

19
package.json Normal file
View File

@@ -0,0 +1,19 @@
{
"name": "blog",
"version": "1.0.0",
"description": "",
"scripts": {
"build": "cd voidcannon&&npm run generate-icon-font&&cd ../pagex&&npm run build ../",
"dev": "cd voidcannon&&npm run generate-full-icon-font&&cd ../pagex&&npm run dev ../"
},
"type": "module",
"private": true,
"dependencies": {
"gm3": "file:gm3",
"pagex": "file:pagex",
"pagex_commons": "file:pagex_commons",
"voidcannon": "file:voidcannon",
"webfont": "file:webfont",
"webicons": "file:webicons"
}
}

1
pagex Submodule

Submodule pagex added at 3078ac7cde

23
pagex.config.js Normal file
View File

@@ -0,0 +1,23 @@
import {PagexTemplateType} from "pagex";
export default {
id: "voidcannon",
site_config: {
title: "voidcannon-dev"
},
base: process.env.CI_PAGES_URL ? new URL(process.env.CI_PAGES_URL).pathname + (new URL(process.env.CI_PAGES_URL).pathname.endsWith("/") ? "":"/") : "/blog" + "/" || "",
output: {
path: "dist"
},
pagex_content: {
content: "./src/",
templates: "./voidcannon/src/",
client: {
components: "./voidcannon/src/client/components.js",
entrypoint: "./voidcannon/src/client/index.js"
}
},
templates: {
[PagexTemplateType.BASE_PAGE]: "frames/Page.js"
}
}

1
pagex_commons Submodule

Submodule pagex_commons added at 29d5efe4da

View File

@@ -0,0 +1,50 @@
import {VoidcannonHeaderLayoutType, VoidcannonHeaderType, VoidcannonContentType} from "voidcannon";
import bignutty from "../../authors/bignutty.pagex.js";
import testCollection from "../../collections/test.pagex.js";
import featuredCollection from "../../collections/_featured.pagex.js";
import {PagexResourceTransformer} from "pagex";
export default {
type: VoidcannonContentType.ARTICLE,
content: {
_transform: PagexResourceTransformer.MARKDOWN,
path: "../playground/content.md"
},
id: "playground-gm3",
title: "Playground Test Article (gm3 base theme)",
created_at: 1757861297516,
header: {
type: VoidcannonHeaderType.IMMERSIVE,
layout: VoidcannonHeaderLayoutType.TEXT,
label: "Article Title (gm3)",
base: {
_transform: PagexResourceTransformer.MEDIA,
path: "../playground/assets/header/background.png"
},
immersive_content: {
left: {
base: {
_transform: PagexResourceTransformer.MEDIA,
path: "../playground/assets/header/immersive_left/full.png"
},
outer: {
_transform: PagexResourceTransformer.MEDIA,
path: "../playground/assets/header/immersive_left/outer_v2.png"
},
inner: {
_transform: PagexResourceTransformer.MEDIA,
path: "../playground/assets/header/immersive_left/base_v2.png"
}
}
},
color: "#c7f718"
},
authors: [bignutty],
collections: [
testCollection.id,
featuredCollection.id
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

View File

@@ -0,0 +1,70 @@
# Persona 3 Reload
this is sample text (p3)
[playground](./playground) [playground-partial](./playground-partial) [p3](./playground-p3) [totk](./playground-totk)
## Custom Emoji :p3smile:
- :p3smile: :p3worried: :p3surprised:
- :p3arrowup: :p3heart: :p3brokenheart: :p3burger: :p3camera: :p3cat: :p3dog: :p3cloud: :p3cup: :p3moon: :p3fullmoon: :p3pill: :p3rainbow: :p3snowman: :p3star: :p3sun: :p3thumbsup: :p3umbrella: :p3yen:
```javascript
import {VoidcannonHeaderLayoutType, VoidcannonHeaderType, VoidcannonContentType} from "voidcannon";
import bignutty from "../../authors/bignutty.pagex.js";
import testCollection from "../../collections/test.pagex.js";
import featuredCollection from "../../collections/_featured.pagex.js";
import {PagexResourceTransformer} from "pagex";
export default {
type: VoidcannonContentType.ARTICLE,
content: {
_transform: PagexResourceTransformer.MARKDOWN,
path: "./content.md"
},
id: "playground-p3",
title: "Playground P3 Test Article",
theme: {
colors: {
light: "#0eb1f4",
dark: "#0eb1f4",
},
variant: "Content",
},
header: {
type: VoidcannonHeaderType.IMMERSIVE,
layout: VoidcannonHeaderLayoutType.LOGO,
position: "100% 100%",
base: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/background_p3.png"
},
logo: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/logo_p3.png"
},
immersive_content: {
left: {
outer: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/immersive_left/outer_p3.png"
},
inner: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/immersive_left/base_p3.png"
}
}
},
color: "#0eb1f4"
},
authors: [bignutty],
collections: [
testCollection.id,
"rest",
featuredCollection.id
]
}
```

View File

@@ -0,0 +1,60 @@
import {VoidcannonHeaderLayoutType, VoidcannonHeaderType, VoidcannonContentType} from "voidcannon";
import bignutty from "../../authors/bignutty.pagex.js";
import videogamesCollection from "../../collections/videogames.pagex.js";
import testCollection from "../../collections/test.pagex.js";
import featuredCollection from "../../collections/_featured.pagex.js";
import {PagexResourceTransformer} from "pagex";
import {ThemeVariants} from "pagex_commons";
export default {
type: VoidcannonContentType.ARTICLE,
content: {
_transform: PagexResourceTransformer.MARKDOWN,
path: "./content.md"
},
id: "playground-p3",
title: "Playground P3 Test Article",
created_at: 1757861297516,
theme: {
colors: {
light: "#0eb1f4",
dark: "#0eb1f4",
},
variant: ThemeVariants.VIBRANT,
},
header: {
type: VoidcannonHeaderType.IMMERSIVE,
layout: VoidcannonHeaderLayoutType.LOGO,
position: "100% 100%",
base: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/background_p3.png"
},
logo: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/logo_p3.png"
},
immersive_content: {
left: {
outer: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/immersive_left/outer_p3.png"
},
inner: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/immersive_left/base_p3.png"
}
}
},
color: "#0eb1f4"
},
authors: [bignutty],
collections: [
videogamesCollection.id,
testCollection.id,
featuredCollection.id
]
}

View File

@@ -0,0 +1,63 @@
import {
VoidcannonHeaderLayoutType,
VoidcannonHeaderType,
VoidcannonContentType,
VoidcannonEmojiStyle
} from "voidcannon";
import bignutty from "../../authors/bignutty.pagex.js";
import testCollection from "../../collections/test.pagex.js";
import featuredCollection from "../../collections/_featured.pagex.js";
import {PagexResourceTransformer} from "pagex";
export default {
type: VoidcannonContentType.ARTICLE,
content: {
_transform: PagexResourceTransformer.MARKDOWN,
path: "../playground/content.md"
},
id: "playground-partial",
title: "Playground Test Article (partial)",
created_at: 0,
theme: {
emoji_style: VoidcannonEmojiStyle.FLUENT_FLAT,
partial: true,
colors: {
light: "#c7f718",
dark: "#c7f718",
}
},
header: {
type: VoidcannonHeaderType.IMMERSIVE,
layout: VoidcannonHeaderLayoutType.TEXT,
label: "Article Title :catsmile:",
base: {
_transform: PagexResourceTransformer.MEDIA,
path: "../playground/assets/header/background.png"
},
immersive_content: {
left: {
base: {
_transform: PagexResourceTransformer.MEDIA,
path: "../playground/assets/header/immersive_left/full.png"
},
outer: {
_transform: PagexResourceTransformer.MEDIA,
path: "../playground/assets/header/immersive_left/outer_v2.png"
},
inner: {
_transform: PagexResourceTransformer.MEDIA,
path: "../playground/assets/header/immersive_left/base_v2.png"
}
}
},
color: "#c7f718"
},
authors: [bignutty.id],
collections: [
testCollection.id,
featuredCollection.id
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1001 KiB

View File

@@ -0,0 +1,72 @@
# The Legend of Zelda: Tears of the Kingdom
this is sample text (totk)
[playground](./playground) [playground-partial](./playground-partial) [p3](./playground-p3) [totk](./playground-totk)
```javascript
console.log('hewwo') // [!code --]
console.log('hello') // [!code ++]
```
```js
import {VoidcannonHeaderLayoutType, VoidcannonHeaderType, VoidcannonContentType} from "voidcannon";
import bignutty from "../../authors/bignutty.pagex.js";
import testCollection from "../../collections/test.pagex.js";
import featuredCollection from "../../collections/_featured.pagex.js";// [!code error]
import {PagexResourceTransformer} from "pagex";// [!code warning]
export default { // [!code highlight]
type: VoidcannonContentType.ARTICLE, // [!code highlight]
content: { // [!code highlight]
_transform: PagexResourceTransformer.MARKDOWN, // [!code highlight]
path: "./content.md"
},
id: "playground-totk",
title: "Playground Totk Test Article",
theme: { // [!code --]
partial: true, // [!code --]
colors: { // [!code --]
light: "#4dc294", // [!code --]
dark: "#4dc294", // [!code --]
} // [!code --]
}, // [!code --]
theme: { // [!code ++]
partial: true, // [!code ++]
colors: { // [!code ++]
light: "#4dc294", // [!code ++]
dark: "#4dc294", // [!code ++]
} // [!code ++]
}, // [!code ++]
header: {
type: VoidcannonHeaderType.IMMERSIVE,
layout: VoidcannonHeaderLayoutType.EMPTY,
base: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/background_totk.png"
},
immersive_content: {
right: {
outer: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/immersive_right/outer.png"
},
inner: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/immersive_right/inner.png"
}
}
},
color: "#4dc294"
},
authors: [bignutty],
collections: [
testCollection.id,
"rest",
featuredCollection.id
]
}
```

View File

@@ -0,0 +1,55 @@
import {VoidcannonHeaderLayoutType, VoidcannonHeaderType, VoidcannonContentType} from "voidcannon";
import bignutty from "../../authors/bignutty.pagex.js";
import videogamesCollection from "../../collections/videogames.pagex.js";
import testCollection from "../../collections/test.pagex.js";
import featuredCollection from "../../collections/_featured.pagex.js";
import {PagexResourceTransformer} from "pagex";
export default {
type: VoidcannonContentType.ARTICLE,
content: {
_transform: PagexResourceTransformer.MARKDOWN,
path: "./content.md"
},
id: "playground-totk",
title: "Playground Totk Test Article",
created_at: 1757861297516,
updated_at: 1757861297516,
theme: {
// partial: true,
colors: {
light: "#4dc294",
dark: "#4dc294",
}
},
header: {
type: VoidcannonHeaderType.IMMERSIVE,
layout: VoidcannonHeaderLayoutType.EMPTY,
base: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/background_totk.png"
},
immersive_content: {
right: {
outer: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/immersive_right/outer.png"
},
inner: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/immersive_right/inner.png"
}
}
},
color: "#4dc294"
},
authors: [bignutty],
collections: [
videogamesCollection.id,
testCollection.id,
featuredCollection.id
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,510 @@
# Pagex Playground Article
this is sample text (playground)
## Test Articles
- [playground](./playground)
- - [playground (partially themed)](./playground-partial)
- - [playground (no theme)](./playground-gm3)
- [p3](./playground-p3)
- [totk](./playground-totk)
<voidcannon-theme-switcher></voidcannon-theme-switcher>
# Markdown Test Document
This document is designed to test all aspects of the pagex markdown renderer.
To modify the test document, make changes in `/src/content/articles/playground/content.md`.
## Custom Elements
Voidcannon provides a set of custom html elements that can be used within the standard markdown html syntax.
### &lt;voidcannon-carousel&gt;
`<voidcannon-carousel>` turns any content into a carousel. Carousels are not server-rendered.
<voidcannon-carousel>
<voidcannon-slide>
![Persona 5 Menu](media/menu.jpg "p5 menu")
</voidcannon-slide>
<voidcannon-slide>
![Persona 5 Protagonist](media/joker.jpg "p5 joker")
</voidcannon-slide>
<voidcannon-slide>
![Persona 5 Enemy](media/enemy.jpg "p5 enemy")
</voidcannon-slide>
</voidcannon-carousel>
```markdown
<voidcannon-carousel>
<voidcannon-slide>
![Persona 5 Menu](media/menu.jpg "p5 menu")
</voidcannon-slide>
<voidcannon-slide>
![Persona 5 Protagonist](media/joker.jpg "p5 joker")
</voidcannon-slide>
<voidcannon-slide>
![Persona 5 Enemy](media/enemy.jpg "p5 enemy")
</voidcannon-slide>
</voidcannon-carousel>
```
### &lt;voidcannon-slide&gt;, &lt;voidcannon-harness&gt;
The `<voidcannon-slide>` and `<voidcannon-harness>` custom elements allow for slotting content.
#### &lt;voidcannon-slide&gt;
Intended for use within carousels in order to create holding containers for slides. Automatically scales images to use
up all available visual carousel space. Will probably be replaced in favor of harness some day.
```markdown
<voidcannon-slide>
![Persona 5 Enemy](media/enemy.jpg "p5 enemy")
</voidcannon-slide>
```
#### &lt;voidcannon-harness&gt;
Makes content take up more space horizontally in the article layout. Intended for big elements like images
or important sections that should get more highlighting or emphasis. (Carousels use this style by default without
needing a harness element)
```markdown
<voidcannon-harness>
![Cat using computer](assets/Cat_using_computer.jpg "look at this cat")
</voidcannon-harness>
```
### &lt;voidcannon-cta&gt;
Call-to-action that emphasizes an action or acts as a callout/hint.
Can accept a button.
<voidcannon-cta layout="button">
<md-icon slot="icon">brightness_alert</md-icon>
Big Warning!
<md-text-button slot="button">Go to Warner</md-text-button>
</voidcannon-cta>
```html
<voidcannon-cta layout="button">
<md-icon slot="icon">brightness_alert</md-icon>
Big Warning!
<md-text-button slot="button">Go to Warner</md-text-button>
</voidcannon-cta>
```
## Other Custom Elements
The voidcannon frontend imports various other internal and external custom elements that can be server-rendered.
### @material/web
<md-filled-button>Buttons</md-filled-button>
<md-icon-button><md-icon>warning</md-icon></md-icon-button>
<md-icon>breaking_news</md-icon>
> Voidcannon ships a stripped down version of Material Symbols in production builds.
>
> If an icon doesn't display properly in `<md-icon>` or `<wf-icon>` components, make
> sure the icon is included in `voidcannon/scripts/generate-icon-font.js`.
### gm3 (p1)
<gm3-loading-indicator></gm3-loading-indicator>
<gm3-loading-indicator contained></gm3-loading-indicator>
---
To get an exhaustive list, check `voidcannon/src/client/components.js`. Client-only components are under
`voidcannon/src/client/components_client.js`.
## Headings
* # H1 Heading
* ## H2 Heading
* ### H3 Heading
* #### H4 Heading
* ##### H5 Heading
* ###### H6 Heading
> The first `h1` in an article is considered to be the "article title" and gets
different styling (size increase, smaller gap above).
## Emphasis
* **Bold text**
* *Italic text*
* ***Bold and italic text***
* ~~Strikethrough text~~
* <u>Underlined text</u> (if supported)
## Lists
### Unordered Lists
* Item 1
* Item 2
* Subitem 1
* Subitem 2
* Item 3
### Ordered Lists
1. First item
2. Second item
1. Subitem 1
2. Subitem 2
3. Third item
## Emojis
# 🦭
big seal
My favourite animals are the seal 🦭 and the otter 🦦. My favourite emoji is the skateboard 🛹 joycat 😹
🌈 ✨🤩💫☪🐟♏🦂🦀🦁🐍🐐🌃🍋‍🟩
- 🏃🏾‍♀️‍➡️
- 👨🏻‍❤️‍👨🏻
- 🧑🏼‍❤️‍🧑🏾
- 🫩
- 🇩🇪
Supports discord-style shorthands
- :tada: (`:tada:`)
- :heart_hands::skin-tone-1: (`:heart_hands::skin-tone-1:`)
- :couple_with_heart_person_person_medium_light_skin_tone_medium_dark_skin_tone: (`:couple_with_heart_person_person_medium_light_skin_tone_medium_dark_skin_tone:`)
- :person_in_motorized_wheelchair_facing_right_medium_light_skin_tone: (`:person_in_motorized_wheelchair_facing_right_medium_light_skin_tone:`)
- :regional_indicator_b::regional_indicator_i::regional_indicator_g::regional_indicator_n::regional_indicator_u::regional_indicator_t::regional_indicator_t::regional_indicator_y:
- :flag_de: :rainbow_flag:
- :face_with_bags_under_eyes: :splatter: :root_vegetable:
Supports discord custom emoji
- <:meowblob:1245470561296187504>
- <:catsmile:1271230456188375111>Love<:catsmile:1271230456188375111>:heart:
- webp-only animated emoji <a:cubus:1402437389095534623>
Custom emoji (Persona 3 Reload)
- :p3smile: :p3worried: :p3surprised:
- :p3arrowup: :p3heart: :p3brokenheart: :p3burger: :p3camera: :p3cat: :p3dog: :p3cloud: :p3cup: :p3moon: :p3fullmoon: :p3pill: :p3rainbow: :p3snowman: :p3star: :p3sun: :p3thumbsup: :p3umbrella: :p3yen:
### Task Lists
* [ ] Unchecked task
* [x] Checked task
* [ ] Another unchecked task
## Links
* [Inline link](https://www.example.com)
* [Link with title](https://www.example.com "Example.com")
* <https://www.example.com> (Autolink)
## Images
The custom `<voidcannon-harness>` element can be used to render full-width sections.
Images will automatically stretch to fill the available width.
<voidcannon-harness>
![Cat using computer](assets/Cat_using_computer.jpg "look at this cat")
</voidcannon-harness>
![Alt text](https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png "Google Logo")
![Alt text](media/menu.jpg)
## Code
### Inline Code
* `print("Hello, world!")`
### Code Blocks
```python
def greet(name):
print(f"Hello, {name}!")
greet("World")
```
This codeblock is expandable to save on space.
```javascript
import {
VoidcannonContentType,
VoidcannonSectionType
} from "voidcannon";
import {PagexResourceTransformer} from "pagex";
import CollectionContentTransformer from "voidcannon/src/transformers/CollectionContent.transformer.js";
export default {
type: VoidcannonContentType.EDITORIAL,
id: "index",
name: "Voidcannon Home",
description: "Voidcannon Home",
color: null,
sections: [
{
type: VoidcannonSectionType.CAROUSEL,
content: {
_transform: CollectionContentTransformer.id,
collection_id: "featured"
},
label: "Featured Articles",
target: "collections/featured"
},
{
type: VoidcannonSectionType.EDITORIAL,
content: {
_transform: PagexResourceTransformer.MARKDOWN,
path: "./content.md"
}
},
{
type: VoidcannonSectionType.CONTENT_GRID,
content: {
_transform: CollectionContentTransformer.id,
collection_id: "recent"
},
label: "Recent Articles"
}
]
}
```
```javascript
function sayHello(name) {
console.log("Hello, " + name + "!");
}
sayHello("World");
function foo(name) {
console.log("Hello, " + name + "!");
}
foo("bar");
```
```
No language specified
This is a plain code block.
```
### Advanced Formatting
```javascript
// Additions and Removals
Helo// [!code --]
Helo// [!code --]
Helo// [!code --]
Hello// [!code ++]
Hello// [!code ++]
Hello// [!code ++]
// Errors and Warnings
guh()
pluh()// [!code warning]
pluhey()// [!code error]
// Highlighting
// [!code highlight:5]
dong.expand();
// This is a large highlighted section
const a = "b";
console.log("a" + a);
function b(c) {return d;}
```
```diff
diff --git a/pages/resources/integration.mdx b/pages/resources/integration.mdx
index 21d48f59..49445b53 100644
--- a/pages/resources/integration.mdx
+++ b/pages/resources/integration.mdx
@@ -110,19 +110,22 @@ Integrations represent a connection between a service and a guild. This may incl
###### GIF Media Format
-| Value | Description |
-| --------- | ------------------------------------ |
-| mp4 | MP4 video |
-| tinymp4 | MP4 video in a smaller size |
-| nanomp4 | MP4 video in a very small size |
-| loopedmp4 | MP4 video that loops (same as `mp4`) |
-| webm | WebM video |
-| tinywebm | WebM video in a smaller size |
-| nanowebm | WebM video in a very small size |
-| gif | GIF image |
-| mediumgif | GIF image in a medium size |
-| tinygif | GIF image in a smaller size |
-| nanogif | GIF image in a very small size |
+| Value | Description | Description | Description |
+| --------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- |
+| mp4 | MP4 video | MP4 video | MP4 video |
+| tinymp4 | MP4 video in a smaller size | MP4 video in a smaller size | MP4 video in a smaller size |
+| nanomp4 | MP4 video in a very small size | MP4 video in a very small size | MP4 video in a very small size |
+| loopedmp4 | MP4 video that loops (same as `mp4`) | MP4 video that loops (same as `mp4`) | MP4 video that loops (same as `mp4`) |
+| webm | WebM video | WebM video | WebM video |
+| tinywebm | WebM video in a smaller size | WebM video in a smaller size | WebM video in a smaller size |
+| nanowebm | WebM video in a very small size | WebM video in a very small size | WebM video in a very small size |
+| gif | GIF image | GIF image | GIF image |
+| mediumgif | GIF image in a medium size | GIF image in a medium size | GIF image in a medium size |
+| tinygif | GIF image in a smaller size | GIF image in a smaller size | GIF image in a smaller size |
+| nanogif | GIF image in a very small size | GIF image in a very small size | GIF image in a very small size |
+| webp | Animated WebP image | Animated WebP image | Animated WebP image |
+| tinywebp | Animated WebP image in a smaller size | Animated WebP image in a smaller size | Animated WebP image in a smaller size |
+| nanowebp | Animated WebP image in a very small size | Animated WebP image in a very small size | Animated WebP image in a very small size |
###### Example GIF
@@ -337,15 +340,17 @@ Returns a list of [GIF](#gif-structure) objects based on the provided query.
###### Query String Parameters
-| Field | Type | Description |
-| ------------- | ------- | ----------------------------------------------------- |
-| q | string | The search query to use |
-| limit? ^1^ | integer | The maximum number of GIFs to return (20-500) |
-| media_format? | string | The media format to use (default `mediumgif`) |
-| locale? | string | The locale to use in search results (default `en-US`) |
+| Field | Type | Description |
+| ---------------- | ------- | ----------------------------------------------------------- |
+| q | string | The search query to use |
+| limit? ^1^ | integer | The maximum number of GIFs to return (20-500) (default 100) |
+| media_format ^2^ | string | The [media format](#gif-media-format) to use |
+| locale? | string | The locale to use in search results (default `en-US`) |
^1^ The limit is only a suggestion; the API may return fewer GIFs.
+^2^ Invalid values default to `gif`.
+
<RouteHeader method="GET" url="/gifs/trending" unauthenticated>
Get Trending GIF Categories
</RouteHeader>
@@ -354,10 +359,10 @@ Returns trending GIF categories and their associated preview GIFs.
###### Query String Parameters
-| Field | Type | Description |
-| ------------- | ------ | ----------------------------------------------------- |
-| media_format? | string | The media format to use (default `mediumgif`) |
-| locale? | string | The locale to use in search results (default `en-US`) |
+| Field | Type | Description |
+| ------------ | ------ | ----------------------------------------------------- |
+| media_format | string | The [media format](#gif-media-format) to use |
+| locale? | string | The locale to use in search results (default `en-US`) |
###### Response Body
@@ -406,11 +411,11 @@ Returns a list of [GIF](#gif-structure) objects that are currently trending.
###### Query String Parameters
-| Field | Type | Description |
-| ------------- | ------- | ----------------------------------------------------- |
-| limit? ^1^ | integer | The maximum number of GIFs to return (20-500) |
-| media_format? | string | The media format to use (default `mediumgif`) |
-| locale? | string | The locale to use in search results (default `en-US`) |
+| Field | Type | Description |
+| ------------ | ------- | ----------------------------------------------------- |
+| limit? ^1^ | integer | The maximum number of GIFs to return (20-500) |
+| media_format | string | The [media format](#gif-media-format) to use |
+| locale? | string | The locale to use in search results (default `en-US`) |
^1^ The limit is only a suggestion; the API may return fewer GIFs.
```
```protobuf
syntax = "proto3";
package bignutty.pagex;
🍋‍🟩
// Represents preprocessed metadata for pagex media items.
message PagexProcessedMedia {
// The version of this metadata payload.
int32 version = 1;
// Preprocessed LQIP value for this media item.
int32 lqip = 2;
// Attributions
repeated PagexMediaAttribution attributions = 3;
}
// An attribution (copyright, source) for a media item.
message PagexMediaAttribution {
// Text label (i.e Copyright 2025 bignutty).
string label = 1;
// URL linking to the original source or author.
optional string url = 2;
}
```
## Horizontal Rule
---
## Blockquotes
> This is a blockquote.
> It can span multiple lines.
> > And even be nested.
## Tables
| Header 1 | Header 2 | Header 3 | Header 3 | Header 3 | Header 3 | Header 3 | Header 3 | Header 3 | Header 3 | Header 3 | Header 3 | Header 3 | Header 3 | Header 3 |
| -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
| Cell 1 | Cell 2 | Cell 3 | Cell 3 | Cell 3 | Cell 3 | Cell 3 | Cell 3 | Cell 3 | Cell 3 | Cell 3 | Cell 3 | Cell 3 | Cell 3 | Cell 3 |
| Cell 4 | Cell 5 | Cell 6 | Cell 6 | Cell 6 | Cell 6 | Cell 6 | Cell 6 | Cell 6 | Cell 6 | Cell 6 | Cell 6 | Cell 6 | Cell 6 | Cell 6 |
## HTML
<p>This is some HTML text.</p>
<marquee>Test</marquee>
<voidcannon-cta style="margin-top: 1em;">
<md-icon slot="icon">convert_to_text</md-icon>
this is a cta rendered from a markdown document
<button slot="button">pluh</button>
</voidcannon-cta>
<br>
<hr>
## Line Breaks
This is a line.<br>
This is another line.
## Escaping
\* \* \* \* \*
## Special Characters
` ~ ! @ # $ % ^ & * ( ) - _ = + [ ] { } | ; : ' " , . / < > ?

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 KiB

View File

@@ -0,0 +1,64 @@
import {
VoidcannonHeaderLayoutType,
VoidcannonHeaderType,
VoidcannonContentType,
VoidcannonEmojiStyle
} from "voidcannon";
import bignutty from "../../authors/bignutty.pagex.js";
import testCollection from "../../collections/test.pagex.js";
import featuredCollection from "../../collections/_featured.pagex.js";
import {PagexResourceTransformer} from "pagex";
export default {
type: VoidcannonContentType.ARTICLE,
content: {
_transform: PagexResourceTransformer.MARKDOWN,
path: "./content.md"
},
id: "playground",
title: "Playground Test Article",
created_at: Date.now(),
abstract: "Article to quickly run tests for all pagex markdown features. Abstract has a lot of filler and padding to test if css limits work as intended across all surfaces.",
cta: "View Test Article!",
theme: {
emoji_style: VoidcannonEmojiStyle.FLUENT_FLAT,
colors: {
light: "#D02843",
dark: "#c7f718",
}
},
header: {
type: VoidcannonHeaderType.IMMERSIVE,
layout: VoidcannonHeaderLayoutType.TEXT,
label: "Article Title :catsmile:",
base: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/background.png"
},
immersive_content: {
left: {
base: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/immersive_left/full.png"
},
outer: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/immersive_left/outer_v2.png"
},
inner: {
_transform: PagexResourceTransformer.MEDIA,
path: "./assets/header/immersive_left/base_v2.png"
}
}
},
color: "#c7f718"
},
authors: [bignutty],
collections: [
testCollection.id,
featuredCollection.id
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

View File

@@ -0,0 +1,14 @@
import {PagexResourceType, PagexResourceTransformer} from "pagex";
import {VoidcannonContentType} from "voidcannon";
import {file} from "pagex/src/utils.js";
export default {
type: VoidcannonContentType.AUTHOR,
id: "bignutty",
name: "bignutty",
avatar: {
_transform: PagexResourceTransformer.MEDIA,
path: "/content/authors/assets/bignutty.png"
}
}

View File

@@ -0,0 +1,13 @@
import {VoidcannonCollectionIconType, VoidcannonCollectionType, VoidcannonContentType} from "voidcannon";
export default {
type: VoidcannonContentType.COLLECTION,
collection_type: VoidcannonCollectionType.HIDDEN,
id: "featured",
name: "Featured Content",
description: "Featured Content Collection",
icon: {
type: VoidcannonCollectionIconType.ICON,
icon: "star"
}
}

View File

@@ -0,0 +1,13 @@
import {VoidcannonCollectionColor, VoidcannonCollectionIconType, VoidcannonContentType} from "voidcannon";
export default {
type: VoidcannonContentType.COLLECTION,
id: "test",
name: "Test Collection",
description: "contains testing articles",
color: VoidcannonCollectionColor.YELLOW_VIBRANT,
icon: {
type: VoidcannonCollectionIconType.EMOJI,
emoji: "🥰"
}
}

View File

@@ -0,0 +1,13 @@
import {VoidcannonCollectionColor, VoidcannonCollectionIconType, VoidcannonContentType} from "voidcannon";
export default {
type: VoidcannonContentType.COLLECTION,
id: "videogames",
name: "Video Games",
description: "Video Game Articles",
color: VoidcannonCollectionColor.RED_VIBRANT,
icon: {
type: VoidcannonCollectionIconType.ICON,
icon: "stadia_controller"
}
}

View File

@@ -0,0 +1,9 @@
# Voidcannon
a modern blogging frontend, powered by **pagex**.
## Test Articles
- [playground](./playground)
- [p3](./playground-p3)
- [totk](./playground-totk)

View File

@@ -0,0 +1,71 @@
import {
VoidcannonContentType,
VoidcannonSectionType
} from "voidcannon";
import {PagexResourceTransformer} from "pagex";
import CollectionContentTransformer from "voidcannon/src/transformers/CollectionContent.transformer.js";
import RecentContentTransformer from "voidcannon/src/transformers/RecentContent.transformer.js";
import ContentByIdentifierTransformer from "voidcannon/src/transformers/ContentByIdentifier.transformer.js";
import playground from "../../articles/playground/playground.pagex.js";
import playgroundP3 from "../../articles/playground-p3/playground-p3.pagex.js";
import playgroundTotk from "../../articles/playground-totk/playground-totk.pagex.js";
export default {
type: VoidcannonContentType.EDITORIAL,
id: "index",
name: "Voidcannon Home",
description: "Voidcannon Home",
color: null,
sections: [
{
type: VoidcannonSectionType.STORY_HERO,
content: {
_transform: ContentByIdentifierTransformer.id,
content_ids: [
playgroundP3.id,
playground.id,
playgroundTotk.id
],
// TODO: implement this
content_types: [
VoidcannonContentType.ARTICLE
]
}
},
{
type: VoidcannonSectionType.CAROUSEL,
content: {
_transform: CollectionContentTransformer.id,
collection_id: "featured"
},
label: "Various Articles",
target: "collections/featured"
},
{
type: VoidcannonSectionType.EDITORIAL,
content: {
_transform: PagexResourceTransformer.MARKDOWN,
path: "./content.md"
}
},
{
type: VoidcannonSectionType.CONTENT_GRID,
content: {
_transform: CollectionContentTransformer.id,
collection_id: "test"
},
label: "Testing Articles",
icon: "forklift"
},
{
type: VoidcannonSectionType.CONTENT_GRID,
content: {
_transform: RecentContentTransformer.id,
amount: 15
},
label: "Recent Articles",
icon: "history"
}
]
}

1
voidcannon Submodule

Submodule voidcannon added at 8456a6b003

1
webfont Submodule

Submodule webfont added at 6501bbc1d0

1
webicons Submodule

Submodule webicons added at 2a69891f59