Skip to content
This repository was archived by the owner on May 19, 2026. It is now read-only.

Custom branding - Add primary color and app name customization - #134

Open
normanalie wants to merge 7 commits into
Vito0912:personalfrom
normanalie:codex/add-theme-color-and-favicon-settings-for-owner
Open

normanalie wants to merge 7 commits into
Vito0912:personalfrom
normanalie:codex/add-theme-color-and-favicon-settings-for-owner

Conversation

@normanalie

Copy link
Copy Markdown

This pull request introduces workspace-level branding customization, allowing workspace owners to set a primary theme color and favicon. The changes span both frontend and backend, providing a new settings UI, persisting branding options, and applying them dynamically throughout the app. Additionally, the app name can now be customized via environment variables and is consistently displayed in the UI.

This changes are useful for enterprise use.

Workspace Branding Customization

  • Added a new WorkspaceBrandingForm component to the workspace settings page, allowing workspace owners to update the primary color and favicon URL for their workspace. These settings are validated and persisted, and only owners are permitted to make changes. [1] [2] [3] [4]
  • Extended workspace types to include appearance settings (primaryColor, faviconUrl) and ensured these are available on the workspace object. [1] [2] [3]
  • Implemented the applyWorkspaceBranding utility, which dynamically updates CSS variables and favicon links based on workspace settings, ensuring the UI reflects the selected branding.
  • Integrated branding application into relevant components and providers to ensure branding is applied on authentication and workspace context changes. [1] [2] [3]

App Name and UI Consistency

  • Introduced support for customizing the app name via the APP_NAME environment variable, with a fallback to "Forkmost". Updated all relevant UI components to use the new getAppName helper for consistent branding. [1] [2] [3] [4] [5] [6] [7]

Backend Enforcement

  • Updated the backend workspace controller to enforce that only workspace owners can update branding-related fields (primaryColor, faviconUrl).

Build and Environment Configuration

  • Updated the Vite configuration and .env.example to support the new APP_NAME environment variable, ensuring it is available at build time. [1] [2]

Code Quality and Formatting

  • Improved code formatting and imports in several files for better readability and maintainability. [1] [2] [3] [4] [5] [6] [7]

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This project is currently EOL.

The PR adds the option for a user to load any URL each time they visit a page. If a favicon option were added, I would require it to be downloaded to the server first and served from there.

@Vito0912

Copy link
Copy Markdown
Owner

Thanks for opening this PR!
This looks like a sensible addition.

Currently this projects reaches EOL, but I am not opposed to merge one or two smaller PRs like this one.
I am really concerned about security, thus I don't am very attracted to have the favicon an arbitrary URL.
If there a reason why you need it that way, I am open to discuss this further and then test and review the PR properly

Greetings

For security reasons custom favicon need to be uploaded rather than an URL
@normanalie

Copy link
Copy Markdown
Author

Yes, absolutely! I changed the favicon customization to use file upload, reusing AvatarIconType and limiting it to 10 KB. The file is stored locally on the server.

@Vito0912 Vito0912 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the changes!
I left some comments. If you think someone should be the case, please say so.
This is just a first look without actually running it, so maybe I missed some behavior.


preparedFile.fileName = uuid4() + preparedFile.fileExtension;
const filePath = `${getAttachmentFolderPath(AttachmentType.WorkspaceFavicon, workspaceId)}/${preparedFile.fileName}`;
const faviconUrl = `/api/attachments/favicon/${workspaceId}/${preparedFile.fileName}`;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can a workspace have multiple favicons?

I think it would make more sense to have it just as favicon.<> or something like this.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, I've copied the same logic as avatars but it's not needed for favicon


type FormValues = z.infer<typeof formSchema>;

const FAVICON_MAX_SIZE = 100 * 1024; // 100KB

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why it is 100KB here, but 10KB on the server side?

const faviconUrl =
(workspace?.settings as any)?.appearance?.faviconUrl ?? null;

if (faviconUrl && !faviconUrl.toLowerCase().startsWith('http')) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that this is probably because you run the fork for yourself. But as the URL never was introduced I would prefer not to have old handling from before paths

Or do I overlook something and this would have active usage? Also for the other functions?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introduced in my previous commit, forgot to remove it when we changed from URL to file upload

}

@Public()
@Get('attachments/favicon/:workspaceId/:fileName')

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. I think just having attachments/favicon/:workspaceId would make more sense.
This could have caching "issues" if changed, but as it is not cached that long, it should be not that big of a problem

- Removed legacy code from the first implementation of custom favicon.
- Update favicon filenaming for simplicity and update the favicon server url
@normanalie
normanalie requested a review from Vito0912 April 24, 2026 13:41
@Vito0912

Copy link
Copy Markdown
Owner

JFYI I will review it next weekend. Sorry for the delay!

@Vito0912

Vito0912 commented May 4, 2026

Copy link
Copy Markdown
Owner

Sorry, totally forgot. Next weekend. If not by Saturday, please ping me

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants