Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions content/posts/character-shortcodes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
+++
title = "Character Shortcodes Example"
date = "2025-08-11"
+++

Did you know that The oldest programming language still in use is FORTRAN which was created in 1957 by John Backus?

{{ character(name="hooded", body="Whaaaaaaaaaaaaaaaaaaat, that's almost 70 years ago???") }}

I know, it's crazy. Here's an example program:

```
PROGRAM MAIN
PRINT *, 'HELLO WORLD'
STOP
END
```

{% character(name="hooded") %}
There's also a more modern version which is a bit easier to read:
```
program helloWorld
print *, "Hello World!"
end program helloWorld
```
{% end %}

Good to know, thanks buddy!

{{ character(body=":)", position="left") }}
26 changes: 26 additions & 0 deletions content/posts/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,32 @@ Allows for the creation of togglable note sections in your content.

When enabled, you can create expandable/collapsible note sections in your blog posts.

## Character Shortcodes

We support custom character shortcodes for adding dialogue and interactive characters to your blog posts. You can use them via [shortcodes](https://www.getzola.org/documentation/content/shortcodes/):
```
{{ /* character(name="character-name", body="Character dialogue text") */ }}
```

These are the supported parameters:
- `name` (optional): The identifier for the character. Used to determine styling and appearance.
- `body` (optional): The dialogue text for the character. Works with inline shortcodes.
- `position` (optional): Position the character on the left or right. Values: "left" or default (right)


{{ character(body="Isn't it amazing?") }}

{{ character(body="Yes! And it's really easy to use", position="left") }}

{% character() %}
We can even use multiple lines with code:
```rust
fn main() {
println!("Hey there!");
}
```
{% end %}

## Anchor Links

You can add anchor links by adding the following to your `_index.md`:
Expand Down
1 change: 1 addition & 0 deletions sass/main.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@import "fonts.scss";
@import "parts/_cards.scss";
@import "parts/_character.scss";
@import "parts/_code.scss";
@import "parts/_header.scss";
@import "parts/_image.scss";
Expand Down
51 changes: 51 additions & 0 deletions sass/parts/_character.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.character-note {
display: flex;
flex-direction: row;
margin-block: 1.5rem;
margin-inline-start: auto;
margin-inline-end: auto;

&.character-right {
flex-direction: row-reverse;

.character-avatar img {
transform: scaleX(-1);
}
}

&.character-left {
flex-direction: row;
}

.character-avatar {
font-size: 2rem;
align-self: flex-start;
flex-shrink: 0;

img {
--head-size: 3.2em;
width: var(--head-size);
height: var(--head-size);
}
}

.character-content {
font-size: var(--font-size);
align-self: flex-start;
max-width: min(93%, 45em);
overflow: hidden;
}

.character-bubble {
--character-bubble-bg: var(--bg-1);
--character-bubble-border: var(--border-color);
--character-code-bg: var(--bg-0);

background: var(--character-bubble-bg);
border: 1px solid var(--character-bubble-border);
border-radius: 0.5rem;
padding-inline: 0.9em;
padding-block: 0.2em;
}

}
Binary file added static/images/characters/hooded.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions templates/shortcodes/character.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{% set character_name = name | default(value="hooded") %}
{% set character_text = body | default(value="") %}
{% set character_type = type | default(value="comment") %}
{% set character_position = position | default(value="right") %}
{% set character_image = image | default(value="") %}

<div class="character-note character-{{ character_name }} character-{{ character_type }} character-{{ character_position }}">
<div class="character-avatar">
{% if character_image and character_image != "" %}
<img src="/images/characters/{{ character_image }}"
alt="{{ character_name }}"
width="80"
height="80" />
{% elif character_name == "hooded" %}
<img src="/images/characters/hooded.png"
alt="hooded"
width="80"
height="80" />
{% else %}
{{ character_name }}
{% endif %}
</div>
<div class="character-content">
<div class="character-bubble">
{% if character_text %}
{{ character_text | markdown | safe }}
{% else %}
{{ body | markdown | safe }}
{% endif %}
</div>
</div>
</div>
49 changes: 49 additions & 0 deletions tests/visual/character-shortcodes-visual.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { test, expect } from '@playwright/test';

test.describe('Visual Regression - Character Shortcodes Post', () => {
test.skip(({ browserName }) => browserName === 'webkit', 'Skip visual tests on Safari mobile due to rendering variability');

test('character shortcodes post visual comparison - light theme', async ({ page }) => {
test.setTimeout(45000); // Timeout for screenshot

await page.goto('/posts/character-shortcodes');
await page.waitForLoadState('domcontentloaded');

// Set to light theme
await page.evaluate(() => {
document.documentElement.className = 'light';
});

// Wait for theme class to be applied
await page.waitForFunction(() => {
return document.documentElement.className === 'light';
});

// Wait a moment for CSS to apply
await page.waitForTimeout(500);

await expect(page).toHaveScreenshot('character-shortcodes-light.png');
});

test('character shortcodes post visual comparison - dark theme', async ({ page }) => {
test.setTimeout(45000); // Timeout for screenshot

await page.goto('/posts/character-shortcodes');
await page.waitForLoadState('domcontentloaded');

// Set to dark theme
await page.evaluate(() => {
document.documentElement.className = 'dark';
});

// Wait for theme class to be applied
await page.waitForFunction(() => {
return document.documentElement.className === 'dark';
});

// Wait a moment for CSS to apply
await page.waitForTimeout(500);

await expect(page).toHaveScreenshot('character-shortcodes-dark.png');
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.