From 683faf6f118fa5f56907d9f2172ce1ad9f45e34a Mon Sep 17 00:00:00 2001 From: Kawa Date: Wed, 1 Apr 2026 16:27:14 +0200 Subject: [PATCH] feat(13-02): add GdriveAuthToggle and BackendIcons components - GdriveAuthToggle: two-tab segmented control (OAuth Token / Service Account) following AzureAuthToggle pattern; both fields always registered via CSS hidden/block; OAuth tab embeds OAuthInstructions component - BackendIcons: inline SVG icon map for all 18 backends (Partial>) using fill="currentColor" for MD3 dark-mode compatibility, no external deps - Created src/components/icons/ directory --- src/components/icons/BackendIcons.tsx | 192 +++++++++++++++++++++ src/components/wizard/GdriveAuthToggle.tsx | 80 +++++++++ 2 files changed, 272 insertions(+) create mode 100644 src/components/icons/BackendIcons.tsx create mode 100644 src/components/wizard/GdriveAuthToggle.tsx diff --git a/src/components/icons/BackendIcons.tsx b/src/components/icons/BackendIcons.tsx new file mode 100644 index 0000000..ed84f84 --- /dev/null +++ b/src/components/icons/BackendIcons.tsx @@ -0,0 +1,192 @@ +// BackendIcons.tsx +// Inline SVG icon map keyed by BackendType. +// All icons use fill="currentColor" for MD3 dark-mode compatibility. +// Each icon is designed for 24x24px viewBox and works as monochrome. + +import type { BackendType } from '../../schemas/registry'; + +export interface IconProps { + className?: string; +} + +// Azure Blob Storage — cloud with A shape +const AzureBlobIcon = ({ className }: IconProps) => ( + + + + +); + +// Amazon S3 — cloud with S shape +const S3Icon = ({ className }: IconProps) => ( + + + S3 + +); + +// S3-Compatible — generic cloud with layers +const S3CompatibleIcon = ({ className }: IconProps) => ( + + + + + +); + +// Google Cloud Storage — cloud with G +const GCSIcon = ({ className }: IconProps) => ( + + + G + +); + +// Backblaze B2 — cloud with B2 +const B2Icon = ({ className }: IconProps) => ( + + + B2 + +); + +// Azure Files — file-share icon (folder with network lines) +const AzureFilesIcon = ({ className }: IconProps) => ( + + + + +); + +// OpenStack Swift — server/globe icon +const SwiftIcon = ({ className }: IconProps) => ( + + + + + +); + +// OneDrive — cloud with one-drive O shape +const OnedriveIcon = ({ className }: IconProps) => ( + + + + +); + +// Google Drive — drive/triangle icon +const GdriveIcon = ({ className }: IconProps) => ( + + + + + +); + +// Dropbox — box icon +const DropboxIcon = ({ className }: IconProps) => ( + + + + + + + +); + +// Box — stylized box/square icon +const BoxIcon = ({ className }: IconProps) => ( + + + + + +); + +// pCloud — cloud with p letter +const PcloudIcon = ({ className }: IconProps) => ( + + + p + +); + +// SFTP — server with lock icon +const SftpIcon = ({ className }: IconProps) => ( + + + + + + + + +); + +// FTP — server icon (simple) +const FtpIcon = ({ className }: IconProps) => ( + + + + + + + +); + +// WebDAV — globe with network lines +const WebdavIcon = ({ className }: IconProps) => ( + + + + +); + +// SMB / Windows Share — folder with network +const SmbIcon = ({ className }: IconProps) => ( + + + + + + +); + +// HTTP — globe/web icon +const HttpIcon = ({ className }: IconProps) => ( + + + + +); + +// Seafile — sea/wave icon +const SeafileIcon = ({ className }: IconProps) => ( + + + + + +); + +export const BACKEND_ICONS: Partial>> = { + azureblob: AzureBlobIcon, + s3: S3Icon, + 's3-compatible': S3CompatibleIcon, + gcs: GCSIcon, + b2: B2Icon, + 'azure-files': AzureFilesIcon, + swift: SwiftIcon, + onedrive: OnedriveIcon, + gdrive: GdriveIcon, + dropbox: DropboxIcon, + box: BoxIcon, + pcloud: PcloudIcon, + sftp: SftpIcon, + ftp: FtpIcon, + webdav: WebdavIcon, + smb: SmbIcon, + http: HttpIcon, + seafile: SeafileIcon, +}; diff --git a/src/components/wizard/GdriveAuthToggle.tsx b/src/components/wizard/GdriveAuthToggle.tsx new file mode 100644 index 0000000..85665ce --- /dev/null +++ b/src/components/wizard/GdriveAuthToggle.tsx @@ -0,0 +1,80 @@ +import { useState } from 'react'; +import type { UseFormRegister, FieldError } from 'react-hook-form'; +import { PasswordField } from '../ui/PasswordField'; +import { OAuthInstructions } from './OAuthInstructions'; + +type GdriveAuthMethod = 'oauth' | 'service-account'; + +interface GdriveAuthToggleProps { + register: UseFormRegister; + errors: { + token?: FieldError; + service_account_credentials?: FieldError; + }; +} + +export function GdriveAuthToggle({ register, errors }: GdriveAuthToggleProps) { + const [authMethod, setAuthMethod] = useState('oauth'); + + return ( +
+ {/* Segmented control */} +
+ + +
+ + {/* Both fields always registered — only active one visible via CSS */} +
+
+ + +
+
+
+ +
+
+ ); +}