Skip to content

Icon System

DBackup uses Iconify for adapter icons — brand logos for databases, storage providers, and notifications. Icons are bundled offline (no API calls at runtime), which is critical for self-hosted deployments.

Architecture

src/components/adapter/
├── utils.ts           # Icon & color mapping (getAdapterIcon, getAdapterColor)
├── adapter-icon.tsx   # <AdapterIcon> component (renders Iconify <Icon>)
├── adapter-picker.tsx # Uses <AdapterIcon> in adapter selection grid
└── adapter-card.tsx   # Uses <AdapterIcon> in adapter config cards

Icon Packs (Priority Order)

PackNPM PackageUsageColoring
SVG Logos@iconify-icons/logosPrimary — multi-colored brand iconsColors embedded in SVG
Simple Icons@iconify-icons/simple-iconsFallback — brands not in SVG LogosMonochrome, brand color via ADAPTER_COLOR_MAP
Material Design Icons@iconify-icons/mdiProtocol, storage & generic icons (SSH, FTP, SMB, email, fallback)Inherits currentColor

Rule: Always prefer SVG Logos first. Only use Simple Icons if the brand doesn't exist in SVG Logos (e.g. Hetzner, Minio). Use MDI for protocol/storage concepts and generic icons (SSH, FTP, email, fallback).

Browsing Available Icons

How It Works

Bundled Icon Data

Icons are imported as static data objects from @iconify-icons/* packages (tree-shakeable, one file per icon). This avoids runtime API calls to api.iconify.design:

typescript
// src/components/adapter/utils.ts
import mysqlIcon from "@iconify-icons/logos/mysql-icon";
import hetznerIcon from "@iconify-icons/simple-icons/hetzner";
import emailIcon from "@iconify-icons/mdi/email";

Icon Map

The ADAPTER_ICON_MAP maps each adapter ID to its IconifyIcon data object:

typescript
const ADAPTER_ICON_MAP: Record<string, IconifyIcon> = {
    "mysql": mysqlIcon,          // logos (multi-colored)
    "s3-hetzner": hetznerIcon,   // simple-icons (monochrome + brand color)
    "sftp": sshIcon,             // mdi (protocol)
};

Color Map

Only Simple Icons (monochrome) entries need a brand color. SVG Logos have colors baked in, and Lucide icons inherit currentColor:

typescript
const ADAPTER_COLOR_MAP: Record<string, string> = {
    "mssql": "#CC2927",
    "s3-generic": "#C72E49",
    "s3-hetzner": "#D50C2D",
};

AdapterIcon Component

The <AdapterIcon> component handles everything — it reads the icon data and optional color, then renders via Iconify's <Icon>:

tsx
// Usage
<AdapterIcon adapterId="mysql" className="h-8 w-8" />
<AdapterIcon adapterId="s3-hetzner" className="h-5 w-5" />

Adding an Icon for a New Adapter

Step 1: Find the icon

  1. Search SVG Logos first
  2. If not found, search Simple Icons
  3. If neither has a brand icon, use an MDI generic icon

Note the icon name from the URL (e.g. logos:mysql-icon → import path is @iconify-icons/logos/mysql-icon).

Step 2: Add the import

In src/components/adapter/utils.ts, add the import at the top in the appropriate section:

typescript
// — SVG Logos (primary, multi-colored) —
import myBrandIcon from "@iconify-icons/logos/my-brand-icon";

// — OR Simple Icons (if not in SVG Logos) —
import myBrandIcon from "@iconify-icons/simple-icons/mybrand";

// — OR MDI (generic) —
import myGenericIcon from "@iconify-icons/mdi/some-icon";

Step 3: Add to ADAPTER_ICON_MAP

typescript
const ADAPTER_ICON_MAP: Record<string, IconifyIcon> = {
    // ... existing entries
    "my-adapter": myBrandIcon,
};

Step 4: Add brand color (Simple Icons only)

If you used a Simple Icons icon, add the brand hex color to ADAPTER_COLOR_MAP:

typescript
const ADAPTER_COLOR_MAP: Record<string, string> = {
    // ... existing entries
    "my-adapter": "#FF6600",  // Brand color from simpleicons.org
};

TIP

SVG Logos icons already contain their brand colors — do not add them to ADAPTER_COLOR_MAP or the colors will be overridden.

Step 5: Verify

bash
# Check the icon exists in the package
node -e "try { require('@iconify-icons/logos/my-brand-icon'); console.log('OK') } catch { console.log('MISSING') }"

# Build to verify
pnpm build

Current Icon Mapping

Adapter IDIcon PackIcon Name
mysqlSVG Logoslogos/mysql-icon
mariadbSVG Logoslogos/mariadb-icon
postgresSVG Logoslogos/postgresql
mongodbSVG Logoslogos/mongodb-icon
sqliteSVG Logoslogos/sqlite
redisSVG Logoslogos/redis
mssqlSimple Iconssimple-icons/microsoftsqlserver
s3-awsSVG Logoslogos/aws-s3
s3-genericSimple Iconssimple-icons/minio
s3-r2SVG Logoslogos/cloudflare-icon
s3-hetznerSimple Iconssimple-icons/hetzner
google-driveSVG Logoslogos/google-drive
dropboxSVG Logoslogos/dropbox
onedriveSVG Logoslogos/microsoft-onedrive
discordSVG Logoslogos/discord-icon
local-filesystemMDImdi/harddisk
sftpMDImdi/ssh
ftpMDImdi/swap-vertical
webdavMDImdi/cloud-upload
smbMDImdi/folder-network
rsyncMDImdi/folder-sync
emailMDImdi/email
(fallback)MDImdi/disc

Key Decisions

  • Why bundled, not API? — DBackup is self-hosted. Users may not have internet access or may block external API calls via CSP. Bundled icons render instantly without network requests.
  • Why Iconify over react-simple-icons? — Iconify's SVG Logos pack provides multi-colored brand icons (MySQL dolphin in blue, PostgreSQL elephant in blue/white, etc.) rather than flat monochrome. It also covers more brands (OneDrive, AWS S3).
  • Why three packs? — SVG Logos has the best brand icons but doesn't cover everything. Simple Icons fills the gaps (Hetzner, Minio). MDI provides expressive protocol icons (SSH lock, folder-network for SMB, folder-sync for rsync) as well as generic icons (email, disc fallback), eliminating the need for a separate Lucide pack.

Released under the GNU General Public License. | Privacy · Legal Notice