diff --git a/CUSTOM_BRANDING.md b/CUSTOM_BRANDING.md new file mode 100644 index 000000000..2359bf342 --- /dev/null +++ b/CUSTOM_BRANDING.md @@ -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). diff --git a/deployment/extract_brand_assets.sh b/deployment/extract_brand_assets.sh new file mode 100755 index 000000000..5f118a794 --- /dev/null +++ b/deployment/extract_brand_assets.sh @@ -0,0 +1,90 @@ +#!/bin/sh + +set -e + +if [ -z "$1" ]; then + echo "Usage: $0 . 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." diff --git a/docker-compose.coolify.yaml b/docker-compose.coolify.yaml index 2ed7c8ad7..95a785498 100644 --- a/docker-compose.coolify.yaml +++ b/docker-compose.coolify.yaml @@ -30,6 +30,7 @@ services: - BAILEYS_PROVIDER_USE_INTERNAL_HOST_URL=true - MAILER_SENDER_EMAIL=${MAILER_SENDER_EMAIL} - RESEND_API_KEY=${RESEND_API_KEY} + - BRAND_ASSETS_URL=${BRAND_ASSETS_URL} entrypoint: docker/entrypoints/rails.sh command: - bundle @@ -43,10 +44,9 @@ services: restart: always post_start: - command: - - bundle - - exec - - rails - - db:chatwoot_prepare + - 'bundle exec rails db:chatwoot_prepare &&' + - 'bundle exec rails branding:update &&' + - 'if [ -n "$${BRAND_ASSETS_URL}" ]; then deployment/extract_brand_assets.sh "$${BRAND_ASSETS_URL}"; fi' healthcheck: test: - CMD-SHELL diff --git a/lib/tasks/branding.rake b/lib/tasks/branding.rake new file mode 100644 index 000000000..1496e62fb --- /dev/null +++ b/lib/tasks/branding.rake @@ -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