Skip to content

Commit cad2e93

Browse files
committed
feat: add blog post
1 parent 507e94d commit cad2e93

File tree

10 files changed

+130
-46
lines changed

10 files changed

+130
-46
lines changed

apps/backend/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "web"
3-
version = "3.1.3"
3+
version = "3.1.4"
44
edition = "2024"
55

66
[dependencies]

apps/frontend/content.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export default defineContentConfig({
1111
description: z.string().optional(),
1212
category: z.string().default('uncategorized'),
1313
order: z.number().optional(),
14+
unlisted: z.boolean().optional().default(false),
1415
}),
1516
}),
1617

apps/frontend/content/blog/theme-migrate.md

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
---
2+
title: The state of themes on Blueprint
3+
description: An update on our recent efforts to make theming easier on our platform
4+
author: Emma
5+
thumbnail: themes-on-blueprint.jpg
6+
date: 12/8/2025 20:00 (CEDST)
7+
num: 1
8+
---
9+
10+
Ever since the first functional version of Blueprint, themes have been complicated to build and maintain. I recently introduced a new, easier way to build consistent themes through CSS variables and shipped it with [beta-2025-11](/releases/beta-2025-11).
11+
12+
It broke, often.
13+
14+
After weeks of experimenting, **I'm making the difficult decision to remove the "improved" theming functionality in beta-2025-12**.
15+
16+
### The need for consistent theming support
17+
18+
Creating a consistent theme in Blueprint has been difficult, unmaintainable and confusing to say the least. Themes such as [Nebula](/browse/nebula) modify hundreds of seemingly-random class names and deal with complicated CSS selectors to adjust styling.
19+
20+
> I've written an [unofficial guide about making Blueprint themes](https://prpl.blog/#read/custom-pterodactyl-theme) over on my personal blog. I think it can give you enough of an idea of the wizard knowledge you need to make proper themes in Blueprint. I was quite optimistic about it back then, huh.
21+
22+
Despite this, the community has [built](/browse/darkenate) [some](/browse/euphoriatheme) [great](/browse/catppuccindactyl) [themes](/browse/recolor) with Blueprint.
23+
24+
### The theoretical solution
25+
26+
Pterodactyl's user-side frontend is built with React, [Tailwind](https://tailwindcss.com) and a few other technologies. Tailwind condenses CSS properties to simple CSS classes. To change the background color of an element to white, for example, you would add `bg-white` to the list it's classes. This is similar to [inline styles](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style), but much shorter and the preferred method for many developers.
27+
28+
Tailwind allows for defining a list of colors, fonts, etc for your website (the "Tailwind configuration"). This helps with keeping your site consistent, while retaining the flexibility. Tailwind is often compared to [Bootstrap](https://getbootstrap.com) (of which an old version is used for the Pterodactyl admin panel), but with more flexibility over Bootstrap's more standard UI.
29+
30+
> I've personally used both Tailwind and Bootstrap on a few websites. The Blueprint site you're on is actually built with Tailwind, while our legacy site was built with Bootstrap.
31+
32+
In theory, allowing extensions to modify the Tailwind configuration would allow themes to change the colors, fonts, spacing and more through a simple configuration. The best way I could think of doing this was through CSS variables.
33+
34+
CSS variables;
35+
36+
- Wouldn't require the panel's frontend assets to be rebuilt when adjusting the color scheme. This would allow them to be adjusted on the fly through, for example, a theme's admin dashboard.
37+
- Could be edited in and outside of the panel's frontend asset bundle.
38+
- Priority would be handled by the browser, and would prevent me from having to build out a complicated parser to handle theme values.
39+
40+
### The first roadblock
41+
42+
Pterodactyl uses a few (outdated) libraries. Lots of extensions and panel components rely on these libraries. Upgrading them to their latest versions would break more than it would fix.
43+
44+
The version of Tailwind used by the Pterodactyl panel (v3.0.24, [package.json](https://github.com/pterodactyl/panel/blob/9b703fb40f2c8d0fe08c15a08d9f919a9cee7fa3/package.json#L47)) was able to use CSS variables for configuration options. It ran into problems, however, when calculating the [opacity](https://v3.tailwindcss.com/docs/text-color#changing-the-opacity) of colors set this way.
45+
46+
> It's worth noting that Tailwind v4's configuration is written in a CSS file. Tailwind v3's configuration **is not**.
47+
48+
Upgrading Tailwind to v3.4.17 seemed to fix this issue, so we went with that and it worked.. sort of.
49+
50+
### The second roadblock
51+
52+
I wrote [a simple theme](https://github.com/prplwtf/tailwindfourblueprint) to test the theming functionality. It seemed to only apply the changes to a few of the panel's elements.
53+
54+
After diving deeper, the issue seemed to lie in Pterodactyl's heavy use of [twin.macro](https://github.com/ben-rogerson/twin.macro). Removing Twin would require editing it out of basically the entire frontend, and existing themes for Blueprint breaking. Besides, a lot of extensions depend on it, so kicking it out isn't really an option.
55+
56+
> Projects like Twin aren't built to be hyper-extensible, especially in the way we're doing it. Our use-case is anything but standard.
57+
58+
At this point, I was pretty much a week into building this feature already, and it seemed to work, so I called it a day.
59+
60+
### Don't deploy on Fridays
61+
62+
On November 28th, I shipped [beta-2025-11](/releases/beta-2025-11).
63+
64+
A portion of users immediately started experiencing errors when building the frontend asset bundle. I shipped a few patches until it (largely) worked.
65+
66+
The final patch solved most issues. A percentage of users, however, started experiencing issues with a few elements' colors turning black (bug was often referred to "black graphs"). The exact reason why it worked on my and a few others' Pterodactyl panels wasn't found, but there's a good chance cache was to blame.
67+
68+
### The third and final roadblock
69+
70+
I spent the next week experimenting even more;
71+
72+
- Using PostCSS together with a script to go through CSS variables and apply them to the Tailwind configuration on build time. Even though it didn't even work properly in the first place, it also removed the ability for these CSS variables to be adjusted on the fly, as they'd be indexed only when building the frontend asset bundle.
73+
- Replacing Twin's `theme()` function. This was moreso a proof of concept. It was abandoned as it only fixed issues for a small amount of the affected components that made use of the function.
74+
- Messing with libraries' configuration options.
75+
76+
None of these seemed to fix the "black graphs" bug, and when they did, I couldn't replicate the fix on other Pterodactyl installations.
77+
78+
> I was generally just pushing buttons until something happened, with a large amount of the "fixes" coded by AI. The fixes listed above never made it to a release. I was pretty desperate to find a solution to have this **just work**, but after weeks of trying, it's time to admit defeat.
79+
80+
### A final decision
81+
82+
This December there will be a release that will roll-back the theming-related changes made in [beta-2025-11](/releases/beta-2025-11). The [related documentation article](/docs/themes/colors) has been unlisted and [beta-2025-11](/releases/beta-2025-11) will be marked as unsupported once beta-2025-12 releases.
83+
84+
Thank you for your patience with me and the rest of the team.
85+
86+
#### Things break sometimes
87+
88+
Blueprint has been in a stable state over the past year. Due to this, it might be easy to forget that Blueprint, after all, is still in it's beta stage.
89+
90+
That said, I should have never released Blueprint in this state. I think it's important for us to do more extensive testing before shipping a release, through CI and test deployments for example.
91+
92+
People are people, and people make mistakes.

apps/frontend/content/docs/themes/colors.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@
22
title: Dashboard colors
33
description: Default Tailwind colors for the user-side dashboard
44
category: themes
5+
unlisted: true
56
---
67

8+
::card
9+
This document has been unlisted following [this blog post](/blog/update-on-themes). Theme color customization only applies to [beta-2025-11](/releases/beta-2025-11) and is no longer supported.
10+
::
11+
712
::card
813
A large amount of colors provided on this page originate from the [default Tailwind v3 color palette](https://v3.tailwindcss.com/docs/customizing-colors). We allow modifying these colors through CSS variables.
914
::
-291 KB
Binary file not shown.
733 KB
Loading

apps/frontend/src/layouts/docs.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,11 @@ const form = ref({
195195
})
196196
197197
const { data: docs } = await useAsyncData('docs-sidebar', () => {
198-
return queryCollection('docs').all()
198+
return queryCollection('docs')
199+
.orWhere((query) =>
200+
query.where('unlisted', '=', false).where('unlisted', 'IS NULL')
201+
)
202+
.all()
199203
})
200204
201205
// Group docs by category

apps/frontend/src/pages/docs/[...slug].vue

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,24 @@
22
<div v-if="data" class="space-y-8">
33
<div class="mb-12 space-y-1.5">
44
<div>
5-
<div
6-
class="inline-block rounded-full border border-neutral-700 bg-neutral-950"
7-
>
8-
<div class="flex items-center">
9-
<div class="px-2 py-1.5 pe-1.5">
10-
<Icon :name="category?.icon || ''" mode="svg" :size="20" />
5+
<div class="mb-1 flex items-center gap-2">
6+
<div
7+
class="inline-block rounded-full border border-neutral-700 bg-neutral-950"
8+
>
9+
<div class="flex items-center">
10+
<div class="px-2 py-1.5 pe-1.5">
11+
<Icon :name="category?.icon || ''" mode="svg" :size="20" />
12+
</div>
13+
<span
14+
class="border-s border-neutral-700 px-2 py-1.5 ps-1.5 font-bold"
15+
>
16+
{{ category?.label }}
17+
</span>
1118
</div>
12-
<span
13-
class="border-s border-neutral-700 px-2 py-1.5 ps-1.5 font-bold"
14-
>
15-
{{ category?.label }}
16-
</span>
1719
</div>
20+
<span v-if="data.unlisted" class="text-default-font/60">
21+
Unlisted
22+
</span>
1823
</div>
1924
<h1
2025
class="!display leading-14 md:leading-18 truncate !text-5xl !font-normal md:!text-6xl"
@@ -105,7 +110,11 @@ if (!data.value) {
105110
}
106111
107112
const { data: allDocs } = await useAsyncData('all-docs-nav', () =>
108-
queryCollection('docs').all()
113+
queryCollection('docs')
114+
.orWhere((query) =>
115+
query.where('unlisted', '=', false).where('unlisted', 'IS NULL')
116+
)
117+
.all()
109118
)
110119
111120
const category = computed(

apps/frontend/src/pages/docs/index.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@ definePageMeta({
4141
import { docsCategories, defaultCategory } from '~/assets/docs.config'
4242
4343
const { data: docs } = await useAsyncData('docs-index', () => {
44-
return queryCollection('docs').all()
44+
return queryCollection('docs')
45+
.orWhere((query) =>
46+
query.where('unlisted', '=', false).where('unlisted', 'IS NULL')
47+
)
48+
.all()
4549
})
4650
4751
const categories = computed(() => {

0 commit comments

Comments
 (0)