Skip to content
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2143b09
chore(skills): add create-an-edge-app skill with Edge App setup guide…
nicomiguelino Jan 27, 2026
180917b
chore: ignore `.claude/` when running Super-Linter
nicomiguelino Jan 27, 2026
fbd6a31
chore: update .claude/skills/create-an-edge-app/SKILL.md
nicomiguelino Jan 27, 2026
070c405
chore(skills): improve HTML organization guidance in create-an-edge-a…
nicomiguelino Jan 27, 2026
a397ecc
feat: add birthday-greeting edge app with responsive design
nicomiguelino Jan 28, 2026
56b1616
chore(birthday-greeting): add a language identifier for fenced code b…
nicomiguelino Jan 28, 2026
7159fdd
docs(skill): remove code blocks and reference live examples in create…
nicomiguelino Jan 28, 2026
7adc7dd
chore(skills): resolve Markdown linting errors
nicomiguelino Jan 28, 2026
085d082
chore(skills): fix grammatical errors in create-an-edge-app skill
nicomiguelino Jan 28, 2026
b3c732a
added app icon
salmanfarisvp Jan 28, 2026
10447f0
Merge branch 'master' into create-claude-skills
nicomiguelino Jan 28, 2026
bc2054d
docs: add Figma design consultation to Edge App creation workflow
nicomiguelino Jan 28, 2026
120533b
chore(skills): replace bare URLS with links
nicomiguelino Jan 28, 2026
edc897b
Merge branch 'create-claude-skills' into new-edge-app/birthday-app
nicomiguelino Jan 28, 2026
faba107
Merge branch 'master' into new-edge-app/birthday-app
nicomiguelino Jan 28, 2026
36f4ad1
fix(birthday-greeting): prevent race condition in image loading
nicomiguelino Jan 28, 2026
6326ebe
chore(birthday-greeting): add accessibility attributes to the logo SVG
nicomiguelino Jan 28, 2026
8653405
chore(birthday-greeting): assign value to the empty `alt` attribute i…
nicomiguelino Jan 28, 2026
a1f8f78
fix(birthday-greeting): update regex checks for Base64 values so that…
nicomiguelino Jan 28, 2026
abcc2d1
chore(birthday-greeting): address formatting errors
nicomiguelino Jan 28, 2026
4c81b67
test(birthday-greeting): add comprehensive tests for image validation
nicomiguelino Jan 28, 2026
2ba3bc5
refactor(birthday-greeting): make image required and prevent duplicat…
nicomiguelino Jan 28, 2026
f142d0c
refactor(birthday-greeting): extract SVG logo to separate TypeScript …
nicomiguelino Jan 29, 2026
02872ab
style(birthday-greeting): improve responsive design with rem units an…
nicomiguelino Jan 29, 2026
6df6769
style(birthday-greeting): lay groundwork for portrait display support
nicomiguelino Jan 29, 2026
f3c2077
Merge branch 'master' into new-edge-app/birthday-app
nicomiguelino Jan 29, 2026
69be24f
Merge branch 'master' into new-edge-app/birthday-app
nicomiguelino Jan 30, 2026
381ff69
Merge branch 'master' into new-edge-app/birthday-app
nicomiguelino Jan 31, 2026
02f5fc9
Merge branch 'master' into new-edge-app/birthday-app
nicomiguelino Feb 4, 2026
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
67 changes: 67 additions & 0 deletions edge-apps/birthday-greeting/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Birthday Greeting

A vibrant and responsive birthday greeting app for digital signage displays. This app displays personalized birthday messages with the person's name, role, and optional photo.

## Features

- Personalized birthday greeting with name and role
- Optional photo support with Base64 image encoding
- Fallback placeholder when no photo is provided

## Deployment

Create and deploy the Edge App:

```bash
bun install
screenly edge-app create --name birthday-greeting --in-place
bun run deploy
```

## Configuration

The app accepts the following settings via `screenly.yml`:

- `name` (required) - The name of the person having a birthday (e.g., "Amy Smith")
- `role` (required) - The role or position of the person (e.g., "Sales Manager")
- `image` (optional) - A Base64-encoded image of the person. If not provided or if the image fails to load, a placeholder will be displayed

### Example Configuration

```yaml
name: 'Amy Smith'
role: 'Sales Manager'
image: 'data:image/jpeg;base64,/9j/4AAQSkZJRg...'
```

## Image Format

The `image` setting accepts Base64-encoded images in the following formats:

1. **Full data URI** (recommended):

```text
data:image/jpeg;base64,/9j/4AAQSkZJRg...
```

2. **Pure Base64 string** (will be automatically formatted):
```text
/9j/4AAQSkZJRg...
```

## Development

```bash
bun install # Install dependencies
bun run build # Build the app
bun run dev # Start development server
bun run lint # Lint and fix code
```

## Testing

The app includes comprehensive tests for settings retrieval and image handling.

```bash
bun run test # Run all tests
```
1,124 changes: 1,124 additions & 0 deletions edge-apps/birthday-greeting/bun.lock

Large diffs are not rendered by default.

90 changes: 90 additions & 0 deletions edge-apps/birthday-greeting/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Birthday Greeting - Screenly Edge App</title>
<script src="screenly.js?version=1"></script>
<link rel="stylesheet" href="dist/css/style.css" />
</head>
<body>
<div class="container max-w-full">
<main class="main-content">
<div class="left-column h-full">
<svg
width="1009"
height="231"
viewBox="0 0 1009 231"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="logo"
role="img"
aria-label="Screenly"
>
<title>Screenly</title>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M37.0851 155.432L6.54627 137.798C4.62149 136.685 2.9505 135.071 1.75707 133.006C0.563651 130.94 0.00181166 128.683 0.00181166 126.458V89.9405C0.00181166 82.6208 1.84813 75.2073 5.76938 68.4185C9.68773 61.6297 15.187 56.3173 21.5183 52.6643L109.369 1.91903C111.55 0.660664 114.03 0 116.552 0C118.986 0 121.454 0.616104 123.711 1.91903L167.336 27.1202C165.074 25.8173 162.611 25.1934 160.174 25.1934C157.656 25.1934 155.177 25.8618 152.995 27.1202L65.1432 77.8577C58.8118 81.5107 53.3155 86.8231 49.3972 93.6119C45.473 100.402 43.6325 107.814 43.6325 115.134V151.654C43.6325 153.16 42.8469 154.626 41.4481 155.432C40.0493 156.241 38.388 156.186 37.0851 155.432ZM163.587 33.6037C162.53 32.9925 161.376 32.6834 160.166 32.6834C158.962 32.6834 157.766 33.0002 156.726 33.6037L123.395 52.856L160.478 74.2714C161.781 75.0251 163.442 75.0803 164.838 74.2714C166.237 73.4654 167.019 71.9988 167.019 70.4934V39.5546C167.019 37.1095 165.706 34.8262 163.587 33.6037ZM136.453 85.3296L160.794 99.3895C162.629 100.448 164.224 101.985 165.356 103.953C166.492 105.919 167.025 108.066 167.025 110.186V115.977V142.743C167.025 148.979 165.375 155.126 162.259 160.526C159.147 165.925 154.651 170.425 149.254 173.543L61.3926 224.28C60.3522 224.884 59.1617 225.201 57.9528 225.201C56.7458 225.201 55.595 224.892 54.5304 224.28C52.4197 223.059 51.1061 220.783 51.1061 218.339V187.035C51.1061 184.914 50.5704 182.768 49.4351 180.799L105.623 148.348C111.025 145.231 115.522 140.73 118.637 135.332C119.74 133.418 120.658 131.415 121.388 129.346C122.714 125.568 123.4 121.571 123.4 117.549V85.3509C123.4 83.8455 124.184 82.3789 125.582 81.5729C126.982 80.7669 128.64 80.8193 129.946 81.5729L136.453 85.3296ZM43.6317 191.363V218.348C43.6317 223.302 46.2 228.111 50.7863 230.762L7.16829 205.572C2.57477 202.915 0 198.101 0 193.148V166.527C0 165.023 0.785606 163.555 2.18149 162.747C3.58027 161.94 5.24254 161.995 6.54446 162.747L37.3952 180.564C39.229 181.623 40.8234 183.159 41.9587 185.127C43.096 187.096 43.6317 189.244 43.6317 191.363Z"
fill="white"
/>
<path
d="M237.541 120.644L261.009 121.059C262.255 138.089 275.754 149.512 296.107 149.512C313.344 149.512 325.805 141.827 325.805 127.913C325.805 112.544 310.644 109.221 287.592 105.067C263.501 100.913 240.656 93.2291 240.656 64.3609C240.656 39.2309 261.84 21.5777 292.369 21.5777C324.144 21.5777 345.95 40.477 347.196 66.6454H323.728C322.067 51.8997 309.814 41.7232 292.369 41.7232C275.962 41.7232 264.54 48.9921 264.54 62.6994C264.54 77.6527 279.492 80.768 302.337 84.714C326.428 89.0754 349.896 96.7598 349.688 125.42C349.688 151.173 327.259 169.657 295.899 169.657C260.801 169.657 238.164 149.304 237.541 120.644Z"
fill="white"
/>
<path
d="M460.684 130.197C456.53 154.496 438.877 169.657 411.671 169.657C379.689 169.657 358.713 147.85 358.713 115.036C358.713 82.4295 379.896 60.8302 412.294 60.8302C439.085 60.8302 456.53 75.9912 460.684 99.8751H437.631C434.724 87.8293 425.171 79.9373 411.671 79.9373C393.603 79.9373 381.766 94.2676 381.766 115.036C381.766 136.012 393.603 150.55 411.671 150.55C425.586 150.55 435.139 142.658 437.839 130.197H460.684Z"
fill="white"
/>
<path
d="M526.687 62.0763H531.672V83.0525H521.703C501.766 83.0525 495.328 98.6289 495.328 115.036V168.411H472.899V62.0763H492.836L495.328 78.0681C500.728 69.1376 509.242 62.0763 526.687 62.0763Z"
fill="white"
/>
<path
d="M531.126 115.451C531.126 82.4295 552.101 60.8302 582.838 60.8302C613.574 60.8302 634.758 80.3526 635.381 111.505C635.381 114.205 635.173 117.113 634.758 120.021H554.594V121.267C555.632 139.543 566.639 151.381 584.292 151.381C597.998 151.381 607.967 144.527 611.082 132.689H633.512C629.773 153.666 612.121 169.657 585.953 169.657C552.309 169.657 531.126 148.058 531.126 115.451ZM555.424 103.613H612.536C610.667 87.8293 599.245 78.8988 583.669 78.8988C569.339 78.8988 557.086 88.4524 555.424 103.613Z"
fill="white"
/>
<path
d="M643.799 115.451C643.799 82.4295 664.775 60.8302 695.511 60.8302C726.248 60.8302 747.431 80.3526 748.054 111.505C748.054 114.205 747.846 117.113 747.431 120.021H667.267V121.267C668.305 139.543 679.312 151.381 696.965 151.381C710.672 151.381 720.64 144.527 723.755 132.689H746.185C742.447 153.666 724.794 169.657 698.626 169.657C664.982 169.657 643.799 148.058 643.799 115.451ZM668.097 103.613H725.209C723.34 87.8293 711.918 78.8988 696.342 78.8988C682.012 78.8988 669.759 88.4524 668.097 103.613Z"
fill="white"
/>
<path
d="M816.492 60.8302C839.336 60.8302 859.273 73.0836 859.273 109.844V168.411H836.636V111.09C836.636 90.9446 828.122 80.145 811.3 80.145C793.439 80.145 782.847 93.2291 782.847 114.828V168.411H760.418V62.0763H779.94L782.432 75.9912C789.078 67.6838 799.254 60.8302 816.492 60.8302Z"
fill="white"
/>
<path
d="M873.903 23.0315H896.332V168.411H873.903V23.0315Z"
fill="white"
/>
<path
d="M901.958 62.0763H925.841L955.539 144.112L984.407 62.0763H1008.29L960.108 185.026C953.462 202.264 948.893 209.948 933.318 209.948H909.227V190.218H925.01C933.733 190.218 935.602 188.141 939.133 179.419L943.494 169.242L901.958 62.0763Z"
fill="white"
/>
</svg>
<h1 class="greeting-title">
Happy<br />Birthday,<br /><span id="person-name"></span>!
</h1>
<p class="greeting-message">Wishing you all the best!</p>
</div>

<div class="right-column h-full">
<div class="photo-frame">
<div class="photo-container">
<div id="photo-placeholder" class="photo-placeholder"></div>
<img
id="person-photo"
class="person-photo hidden"
alt="Birthday photo"
/>
</div>
</div>
<div class="role-badge">
<p class="role-label">Our very own</p>
<p id="person-role" class="role-title"></p>
</div>
</div>
</main>
</div>
<script src="dist/js/main.js"></script>
</body>
</html>
35 changes: 35 additions & 0 deletions edge-apps/birthday-greeting/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "birthday-greeting",
"version": "1.0.0",
"type": "module",
"scripts": {
"prebuild": "bun run type-check",
"generate-mock-data": "screenly edge-app run --generate-mock-data",
"predev": "bun run generate-mock-data && edge-apps-scripts build",
"dev": "run-p build:dev edge-app-server",
"edge-app-server": "screenly edge-app run",
"build": "edge-apps-scripts build",
"build:dev": "edge-apps-scripts build:dev",
"build:prod": "edge-apps-scripts build",
"test": "bun test",
"test:unit": "bun test",
"lint": "edge-apps-scripts lint --fix",
"format": "prettier --write src/ README.md index.html",
"format:check": "prettier --check src/ README.md index.html",
"deploy": "bun run build && screenly edge-app deploy",
"type-check": "edge-apps-scripts type-check",
"prepare": "cd ../edge-apps-library && bun install && bun run build"
},
"dependencies": {},
"prettier": "../edge-apps-library/.prettierrc.json",
"devDependencies": {
"@screenly/edge-apps": "workspace:../edge-apps-library",
"@types/bun": "^1.3.6",
"@types/jsdom": "^27.0.0",
"bun-types": "^1.3.6",
"jsdom": "^27.4.0",
"npm-run-all2": "^8.0.4",
"prettier": "^3.8.1",
"typescript": "^5.9.3"
}
}
39 changes: 39 additions & 0 deletions edge-apps/birthday-greeting/screenly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
syntax: manifest_v1
description: A birthday greeting app that displays a personalized message with the person's name, role, and optional photo.
icon: https://playground.srly.io/edge-apps/birthday-greeting/static/img/icon.svg
author: Screenly, Inc.
ready_signal: true
settings:
display_errors:
type: string
default_value: 'false'
title: Display Errors
optional: true
help_text:
properties:
advanced: true
help_text: For debugging purposes to display errors on the screen.
type: boolean
schema_version: 1
image:
type: string
default_value: ''
title: Image
optional: true
help_text: |
A base64-encoded image of the person. If not provided, a placeholder will be displayed.
name:
type: string
default_value: ''
title: Name
optional: false
help_text: |
The name of the person having a birthday (e.g., "Amy Smith").
role:
type: string
default_value: ''
title: Role
optional: false
help_text: |
The role or position of the person (e.g., "Sales Manager").
39 changes: 39 additions & 0 deletions edge-apps/birthday-greeting/screenly_qc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
syntax: manifest_v1
description: A birthday greeting app that displays a personalized message with the person's name, role, and optional photo.
icon: https://playground.srly.io/edge-apps/birthday-greeting/static/img/icon.svg
author: Screenly, Inc.
ready_signal: true
settings:
display_errors:
type: string
default_value: 'false'
title: Display Errors
optional: true
help_text:
properties:
advanced: true
help_text: For debugging purposes to display errors on the screen.
type: boolean
schema_version: 1
image:
type: string
default_value: ''
title: Image
optional: true
help_text: |
A base64-encoded image of the person. If not provided, a placeholder will be displayed.
name:
type: string
default_value: ''
title: Name
optional: false
help_text: |
The name of the person having a birthday (e.g., "Amy Smith").
role:
type: string
default_value: ''
title: Role
optional: false
help_text: |
The role or position of the person (e.g., "Sales Manager").
Loading
Loading