feat: custom branding (#68)
* feat: add custom branding support with environment variables and asset extraction * chore: wrap brand assets url in quotes
This commit is contained in:
parent
3cd273d2d0
commit
c350ba15ec
73
CUSTOM_BRANDING.md
Normal file
73
CUSTOM_BRANDING.md
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# Custom branding
|
||||||
|
|
||||||
|
## Brand configuration
|
||||||
|
|
||||||
|
Export environment variables and run rake task with `bundle exec rails branding:update`.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> Unset environment variables are reset to default values.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
INSTALLATION_NAME="Chatwoot fazer.ai" \
|
||||||
|
BRAND_NAME="My Company" \
|
||||||
|
LOGO_THUMBNAIL="https://fazer.ai/logo-thumbnail.svg" \
|
||||||
|
LOGO="https://fazer.ai/logo.svg" \
|
||||||
|
bundle exec rails branding:update
|
||||||
|
```
|
||||||
|
|
||||||
|
| Environment variable | Default Value | Description |
|
||||||
|
| :--------------------| :------------------------------------------ | :-------------------------------------------------------------------- |
|
||||||
|
| `INSTALLATION_NAME` | `Chatwoot` | The installation-wide name used in the dashboard, title, etc. |
|
||||||
|
| `LOGO_THUMBNAIL` | `/brand-assets/logo_thumbnail.svg` | The thumbnail used for favicon (512px X 512px). |
|
||||||
|
| `LOGO` | `/brand-assets/logo.svg` | The logo used on the dashboard, login page, etc. |
|
||||||
|
| `LOGO_DARK` | `/brand-assets/logo_dark.svg` | The logo used on the dashboard, login page, etc. for dark mode. |
|
||||||
|
| `BRAND_URL` | `https://www.chatwoot.com` | The URL used in emails under the section “Powered By”. |
|
||||||
|
| `WIDGET_BRAND_URL` | `https://www.chatwoot.com` | The URL used in the widget under the section “Powered By”. |
|
||||||
|
| `BRAND_NAME` | `Chatwoot` | The name used in emails and the widget. |
|
||||||
|
| `TERMS_URL` | `https://www.chatwoot.com/terms-of-service` | The terms of service URL displayed on the Signup Page. |
|
||||||
|
| `PRIVACY_URL` | `https://www.chatwoot.com/privacy-policy` | The privacy policy URL displayed in the app. |
|
||||||
|
| `DISPLAY_MANIFEST` | `true` | Display default Chatwoot metadata like favicons and upgrade warnings. |
|
||||||
|
|
||||||
|
## Favicon and other assets
|
||||||
|
|
||||||
|
Update the favicon files in the [`public/`](public/) folder.
|
||||||
|
|
||||||
|
Can also be done by creating a zip file with relevant files, and running [`deployment/extract_brand_assets.sh`](deployment/extract_brand_assets.sh) to override the existing favicons with your own.
|
||||||
|
In this case, the zip file should be a flat archive containing the following files:
|
||||||
|
|
||||||
|
```
|
||||||
|
android-icon-36x36.png
|
||||||
|
android-icon-48x48.png
|
||||||
|
android-icon-72x72.png
|
||||||
|
android-icon-96x96.png
|
||||||
|
android-icon-144x144.png
|
||||||
|
android-icon-192x192.png
|
||||||
|
apple-icon-57x57.png
|
||||||
|
apple-icon-60x60.png
|
||||||
|
apple-icon-72x72.png
|
||||||
|
apple-icon-76x76.png
|
||||||
|
apple-icon-114x114.png
|
||||||
|
apple-icon-120x120.png
|
||||||
|
apple-icon-144x144.png
|
||||||
|
apple-icon-152x152.png
|
||||||
|
apple-icon-180x180.png
|
||||||
|
apple-icon.png
|
||||||
|
apple-icon-precomposed.png
|
||||||
|
apple-touch-icon.png
|
||||||
|
apple-touch-icon-precomposed.png
|
||||||
|
favicon-16x16.png
|
||||||
|
favicon-32x32.png
|
||||||
|
favicon-96x96.png
|
||||||
|
favicon-512x512.png
|
||||||
|
favicon-badge-16x16.png
|
||||||
|
favicon-badge-32x32.png
|
||||||
|
favicon-badge-96x96.png
|
||||||
|
ms-icon-70x70.png
|
||||||
|
ms-icon-144x144.png
|
||||||
|
ms-icon-150x150.png
|
||||||
|
ms-icon-310x310.png
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> You can include other assets in the zip file, and use them when running the rake task for `LOGO_THUMBNAIL`, `LOGO`, and `LOGO_DARK`.
|
||||||
|
> See [Brand configuration](#brand-configuration).
|
||||||
90
deployment/extract_brand_assets.sh
Executable file
90
deployment/extract_brand_assets.sh
Executable file
@ -0,0 +1,90 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "Usage: $0 <url to zip file with favicons>. See https://github.com/fazer-ai/chatwoot/blob/main/CUSTOM_BRANDING.md for more info."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
URL="$1"
|
||||||
|
TEMP_DIR=$(mktemp -d)
|
||||||
|
ZIP_FILE="$TEMP_DIR/downloaded_favicons.zip"
|
||||||
|
EXTRACT_DIR="$TEMP_DIR/extracted_favicons"
|
||||||
|
TARGET_DIR="public"
|
||||||
|
|
||||||
|
EXPECTED_FILES="
|
||||||
|
android-icon-36x36.png
|
||||||
|
android-icon-48x48.png
|
||||||
|
android-icon-72x72.png
|
||||||
|
android-icon-96x96.png
|
||||||
|
android-icon-144x144.png
|
||||||
|
android-icon-192x192.png
|
||||||
|
apple-icon-57x57.png
|
||||||
|
apple-icon-60x60.png
|
||||||
|
apple-icon-72x72.png
|
||||||
|
apple-icon-76x76.png
|
||||||
|
apple-icon-114x114.png
|
||||||
|
apple-icon-120x120.png
|
||||||
|
apple-icon-144x144.png
|
||||||
|
apple-icon-152x152.png
|
||||||
|
apple-icon-180x180.png
|
||||||
|
apple-icon.png
|
||||||
|
apple-icon-precomposed.png
|
||||||
|
apple-touch-icon.png
|
||||||
|
apple-touch-icon-precomposed.png
|
||||||
|
favicon-16x16.png
|
||||||
|
favicon-32x32.png
|
||||||
|
favicon-96x96.png
|
||||||
|
favicon-512x512.png
|
||||||
|
favicon-badge-16x16.png
|
||||||
|
favicon-badge-32x32.png
|
||||||
|
favicon-badge-96x96.png
|
||||||
|
ms-icon-70x70.png
|
||||||
|
ms-icon-144x144.png
|
||||||
|
ms-icon-150x150.png
|
||||||
|
ms-icon-310x310.png
|
||||||
|
"
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
echo "Cleaning up temporary files..."
|
||||||
|
rm -rf "$TEMP_DIR"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
echo "Downloading zip file from $URL..."
|
||||||
|
if wget -q -O "$ZIP_FILE" "$URL"; then
|
||||||
|
echo "Download successful."
|
||||||
|
else
|
||||||
|
echo "Error: Failed to download file from $URL"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Creating extraction directory: $EXTRACT_DIR"
|
||||||
|
mkdir -p "$EXTRACT_DIR"
|
||||||
|
|
||||||
|
echo "Unzipping $ZIP_FILE to $EXTRACT_DIR..."
|
||||||
|
if unzip -q "$ZIP_FILE" -d "$EXTRACT_DIR"; then
|
||||||
|
echo "Unzip successful."
|
||||||
|
else
|
||||||
|
echo "Error: Failed to unzip $ZIP_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Checking for expected files..."
|
||||||
|
MISSING_FILES=0
|
||||||
|
for filename in $EXPECTED_FILES; do
|
||||||
|
if ! find "$EXTRACT_DIR" -name "$filename" -print | grep -q .; then
|
||||||
|
echo "Warning: Expected file '$filename' not found in the zip archive."
|
||||||
|
MISSING_FILES=$((MISSING_FILES + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$MISSING_FILES" -gt 0 ]; then
|
||||||
|
echo "$MISSING_FILES expected file(s) were not found in the zip archive."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Moving extracted files to $TARGET_DIR/..."
|
||||||
|
mv "$EXTRACT_DIR"/* "$TARGET_DIR/" 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "Process completed."
|
||||||
@ -30,6 +30,7 @@ services:
|
|||||||
- BAILEYS_PROVIDER_USE_INTERNAL_HOST_URL=true
|
- BAILEYS_PROVIDER_USE_INTERNAL_HOST_URL=true
|
||||||
- MAILER_SENDER_EMAIL=${MAILER_SENDER_EMAIL}
|
- MAILER_SENDER_EMAIL=${MAILER_SENDER_EMAIL}
|
||||||
- RESEND_API_KEY=${RESEND_API_KEY}
|
- RESEND_API_KEY=${RESEND_API_KEY}
|
||||||
|
- BRAND_ASSETS_URL=${BRAND_ASSETS_URL}
|
||||||
entrypoint: docker/entrypoints/rails.sh
|
entrypoint: docker/entrypoints/rails.sh
|
||||||
command:
|
command:
|
||||||
- bundle
|
- bundle
|
||||||
@ -43,10 +44,9 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
post_start:
|
post_start:
|
||||||
- command:
|
- command:
|
||||||
- bundle
|
- 'bundle exec rails db:chatwoot_prepare &&'
|
||||||
- exec
|
- 'bundle exec rails branding:update &&'
|
||||||
- rails
|
- 'if [ -n "$${BRAND_ASSETS_URL}" ]; then deployment/extract_brand_assets.sh "$${BRAND_ASSETS_URL}"; fi'
|
||||||
- db:chatwoot_prepare
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test:
|
test:
|
||||||
- CMD-SHELL
|
- CMD-SHELL
|
||||||
|
|||||||
41
lib/tasks/branding.rake
Normal file
41
lib/tasks/branding.rake
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# NOTE: See https://github.com/fazer-ai/chatwoot/blob/main/CUSTOM_BRANDING.md for more details.
|
||||||
|
namespace :branding do
|
||||||
|
desc 'Updates branding configurations from environment variables or defaults'
|
||||||
|
task update: :environment do
|
||||||
|
configurable_items = {
|
||||||
|
# The installation wide name that would be used in the dashboard, title etc.
|
||||||
|
'INSTALLATION_NAME' => 'Chatwoot',
|
||||||
|
# The thumbnail that would be used for favicon (512px X 512px)
|
||||||
|
'LOGO_THUMBNAIL' => '/brand-assets/logo_thumbnail.svg',
|
||||||
|
# The logo that would be used on the dashboard, login page etc.
|
||||||
|
'LOGO' => '/brand-assets/logo.svg',
|
||||||
|
# The logo that would be used on the dashboard, login page etc. for dark mode
|
||||||
|
'LOGO_DARK' => '/brand-assets/logo_dark.svg',
|
||||||
|
# The URL that would be used in emails under the section “Powered By”
|
||||||
|
'BRAND_URL' => 'https://www.chatwoot.com',
|
||||||
|
# The URL that would be used in the widget under the section “Powered By”
|
||||||
|
'WIDGET_BRAND_URL' => 'https://www.chatwoot.com',
|
||||||
|
# The name that would be used in emails and the widget
|
||||||
|
'BRAND_NAME' => 'Chatwoot',
|
||||||
|
# The terms of service URL displayed in Signup Page
|
||||||
|
'TERMS_URL' => 'https://www.chatwoot.com/terms-of-service',
|
||||||
|
# The privacy policy URL displayed in the app
|
||||||
|
'PRIVACY_URL' => 'https://www.chatwoot.com/privacy-policy',
|
||||||
|
# Display default Chatwoot metadata like favicons and upgrade warnings
|
||||||
|
'DISPLAY_MANIFEST' => true
|
||||||
|
}
|
||||||
|
|
||||||
|
configurable_items.each do |config_name, default_value|
|
||||||
|
value = if default_value.in?([true, false])
|
||||||
|
ENV.fetch(config_name, default_value.to_s) == 'true'
|
||||||
|
else
|
||||||
|
ENV.fetch(config_name, default_value)
|
||||||
|
end
|
||||||
|
|
||||||
|
InstallationConfig.find_by!(name: config_name).update!(value: value)
|
||||||
|
puts "Updated '#{config_name}' to '#{value}'."
|
||||||
|
end
|
||||||
|
|
||||||
|
puts 'Branding configuration update finished.'
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in New Issue
Block a user