{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "environment-variables-manager",
  "title": "Environment Variables Manager",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/environment-variables-manager/EnvironmentVariablesManager.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport {\n  AlertCircle,\n  Check,\n  Copy,\n  Download,\n  Eye,\n  EyeOff,\n  FileCode,\n  KeyRound,\n  Lock,\n  MoreHorizontal,\n  Pencil,\n  Plus,\n  Search,\n  ShieldCheck,\n  Trash2,\n  Upload,\n  X,\n} from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Checkbox } from '@/components/ui/checkbox'\nimport {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n} from '@/components/ui/dialog'\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu'\nimport { Input } from '@/components/ui/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\nimport { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'\nimport { Textarea } from '@/components/ui/textarea'\n\nexport type EnvironmentScope = 'production' | 'preview' | 'development'\nexport type EnvVarTypeFilter = 'all' | 'secret' | 'plain'\n\nexport interface EnvironmentVariable {\n  id: string\n  key: string\n  value: string\n  environments: EnvironmentScope[]\n  isSecret: boolean\n  updatedAt: string\n  updatedBy: string\n}\n\nconst defaultVariables: EnvironmentVariable[] = [\n  {\n    id: 'env-1',\n    key: 'DATABASE_URL',\n    value: 'postgresql://postgres:p4ssw0rd_secure_vault@db.prod.aws.internal:5432/primary_db',\n    environments: ['production', 'preview', 'development'],\n    isSecret: true,\n    updatedAt: 'Updated 2h ago',\n    updatedBy: 'alex.chen',\n  },\n  {\n    id: 'env-2',\n    key: 'STRIPE_SECRET_KEY',\n    value: 'mock_key_51NwY2xK9mPqL8vR4tZa0bCeFgHiJkLmNoPqRsTuVwXyZ',\n    environments: ['production'],\n    isSecret: true,\n    updatedAt: 'Updated 3d ago',\n    updatedBy: 'sarah.dev',\n  },\n  {\n    id: 'env-3',\n    key: 'NEXT_PUBLIC_APP_URL',\n    value: 'https://app.uipkge.dev',\n    environments: ['production', 'preview', 'development'],\n    isSecret: false,\n    updatedAt: 'Updated 5d ago',\n    updatedBy: 'uday.craft',\n  },\n  {\n    id: 'env-4',\n    key: 'REDIS_PASSWORD',\n    value: 'redis_auth_98f4b6201e9d4a87b32c',\n    environments: ['production', 'preview'],\n    isSecret: true,\n    updatedAt: 'Updated 1w ago',\n    updatedBy: 'alex.chen',\n  },\n  {\n    id: 'env-5',\n    key: 'SENTRY_DSN',\n    value: 'https://o45089@sentry.io/45089234871923',\n    environments: ['production', 'preview', 'development'],\n    isSecret: false,\n    updatedAt: 'Updated 2w ago',\n    updatedBy: 'sarah.dev',\n  },\n  {\n    id: 'env-6',\n    key: 'AWS_SECRET_ACCESS_KEY',\n    value: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',\n    environments: ['production'],\n    isSecret: true,\n    updatedAt: 'Updated 1mo ago',\n    updatedBy: 'infra-bot',\n  },\n]\n\nexport interface EnvironmentVariablesManagerProps {\n  initialVariables?: EnvironmentVariable[]\n  initialAddOpen?: boolean\n  initialImportOpen?: boolean\n  defaultEnvironment?: 'all' | EnvironmentScope\n  className?: string\n}\n\nfunction maskString(val: string): string {\n  if (val.length <= 12) return '••••••••••••'\n  return '••••••••••••••••••••'\n}\n\nexport function EnvironmentVariablesManager({\n  initialVariables,\n  initialAddOpen = false,\n  initialImportOpen = false,\n  defaultEnvironment = 'all',\n  className,\n}: EnvironmentVariablesManagerProps) {\n  const [variables, setVariables] = React.useState<EnvironmentVariable[]>(() =>\n    initialVariables ? initialVariables.map((v) => ({ ...v })) : defaultVariables.map((v) => ({ ...v })),\n  )\n\n  const [activeTab, setActiveTab] = React.useState<'all' | EnvironmentScope>(defaultEnvironment)\n  const [searchQuery, setSearchQuery] = React.useState('')\n  const [typeFilter, setTypeFilter] = React.useState<EnvVarTypeFilter>('all')\n  const [revealAll, setRevealAll] = React.useState(false)\n  const [revealedMap, setRevealedMap] = React.useState<Record<string, boolean>>({})\n\n  const [isAddOpen, setIsAddOpen] = React.useState(initialAddOpen)\n  const [isImportOpen, setIsImportOpen] = React.useState(initialImportOpen)\n  const [editingVariable, setEditingVariable] = React.useState<EnvironmentVariable | null>(null)\n\n  // Add variable state\n  const [newKey, setNewKey] = React.useState('')\n  const [newValue, setNewValue] = React.useState('')\n  const [newIsSecret, setNewIsSecret] = React.useState(true)\n  const [newEnvs, setNewEnvs] = React.useState<EnvironmentScope[]>(['production', 'preview', 'development'])\n\n  // Import state\n  const [importText, setImportText] = React.useState('')\n  const [importEnvs, setImportEnvs] = React.useState<EnvironmentScope[]>(['production', 'preview', 'development'])\n  const [importEncryptAll, setImportEncryptAll] = React.useState(true)\n\n  // Copy state\n  const [copiedId, setCopiedId] = React.useState<string | null>(null)\n  const copyTimer = React.useRef<number | undefined>(undefined)\n\n  const filteredVariables = React.useMemo(() => {\n    return variables.filter((item) => {\n      // Environment filter\n      if (activeTab !== 'all' && !item.environments.includes(activeTab)) {\n        return false\n      }\n\n      // Type filter\n      if (typeFilter === 'secret' && !item.isSecret) return false\n      if (typeFilter === 'plain' && item.isSecret) return false\n\n      // Search query\n      if (searchQuery.trim()) {\n        const q = searchQuery.toLowerCase().trim()\n        const keyMatch = item.key.toLowerCase().includes(q)\n        const authorMatch = item.updatedBy.toLowerCase().includes(q)\n        if (!keyMatch && !authorMatch) return false\n      }\n\n      return true\n    })\n  }, [variables, activeTab, typeFilter, searchQuery])\n\n  const counts = React.useMemo(() => {\n    return {\n      all: variables.length,\n      production: variables.filter((v) => v.environments.includes('production')).length,\n      preview: variables.filter((v) => v.environments.includes('preview')).length,\n      development: variables.filter((v) => v.environments.includes('development')).length,\n    }\n  }, [variables])\n\n  function isRevealed(id: string): boolean {\n    if (revealAll) return true\n    return Boolean(revealedMap[id])\n  }\n\n  function toggleReveal(id: string) {\n    setRevealedMap((prev) => ({ ...prev, [id]: !prev[id] }))\n  }\n\n  function toggleRevealAll() {\n    setRevealAll((prev) => {\n      const next = !prev\n      if (!next) setRevealedMap({})\n      return next\n    })\n  }\n\n  async function copyValue(text: string, id: string) {\n    try {\n      await navigator.clipboard.writeText(text)\n      setCopiedId(id)\n      window.clearTimeout(copyTimer.current)\n      copyTimer.current = window.setTimeout(() => {\n        setCopiedId(null)\n      }, 1600)\n    } catch {\n      // Clipboard fallback\n    }\n  }\n\n  function toggleNewEnv(env: EnvironmentScope) {\n    setNewEnvs((prev) => {\n      if (prev.includes(env)) {\n        return prev.length > 1 ? prev.filter((e) => e !== env) : prev\n      }\n      return [...prev, env]\n    })\n  }\n\n  function resetAddForm() {\n    setNewKey('')\n    setNewValue('')\n    setNewIsSecret(true)\n    setNewEnvs(['production', 'preview', 'development'])\n    setIsAddOpen(false)\n  }\n\n  function handleAddVariable() {\n    const key = newKey.trim().toUpperCase()\n    const val = newValue.trim()\n    if (!key || !val) return\n\n    const newVar: EnvironmentVariable = {\n      id: `env-${Date.now()}`,\n      key,\n      value: val,\n      environments: [...newEnvs],\n      isSecret: newIsSecret,\n      updatedAt: 'Just now',\n      updatedBy: 'you',\n    }\n\n    setVariables((prev) => [newVar, ...prev])\n    resetAddForm()\n  }\n\n  function handleDuplicate(item: EnvironmentVariable) {\n    const duplicateVar: EnvironmentVariable = {\n      ...item,\n      id: `env-${Date.now()}`,\n      key: `${item.key}_COPY`,\n      updatedAt: 'Just now',\n      updatedBy: 'you',\n    }\n    setVariables((prev) => {\n      const index = prev.findIndex((v) => v.id === item.id)\n      if (index >= 0) {\n        const next = [...prev]\n        next.splice(index + 1, 0, duplicateVar)\n        return next\n      }\n      return [duplicateVar, ...prev]\n    })\n  }\n\n  function handleDelete(id: string) {\n    setVariables((prev) => prev.filter((v) => v.id !== id))\n  }\n\n  function openEdit(item: EnvironmentVariable) {\n    setEditingVariable({\n      ...item,\n      environments: [...item.environments],\n    })\n  }\n\n  function saveEdit() {\n    if (!editingVariable) return\n    const key = editingVariable.key.trim().toUpperCase()\n    const val = editingVariable.value.trim()\n    if (!key || !val) return\n\n    setVariables((prev) =>\n      prev.map((v) =>\n        v.id === editingVariable.id\n          ? {\n              ...editingVariable,\n              key,\n              value: val,\n              updatedAt: 'Just now',\n              updatedBy: 'you',\n            }\n          : v,\n      ),\n    )\n    setEditingVariable(null)\n  }\n\n  function toggleEditEnv(env: EnvironmentScope) {\n    if (!editingVariable) return\n    const current = editingVariable.environments\n    const next = current.includes(env)\n      ? current.length > 1\n        ? current.filter((e) => e !== env)\n        : current\n      : [...current, env]\n    setEditingVariable({ ...editingVariable, environments: next })\n  }\n\n  function toggleImportEnv(env: EnvironmentScope) {\n    setImportEnvs((prev) => {\n      if (prev.includes(env)) {\n        return prev.length > 1 ? prev.filter((e) => e !== env) : prev\n      }\n      return [...prev, env]\n    })\n  }\n\n  const parsedImportItems = React.useMemo(() => {\n    if (!importText.trim()) return []\n    const lines = importText.split('\\n')\n    const results: { key: string; value: string; isSecret: boolean }[] = []\n\n    for (const rawLine of lines) {\n      const line = rawLine.trim()\n      if (!line || line.startsWith('#')) continue\n      const eqIdx = line.indexOf('=')\n      if (eqIdx > 0) {\n        const k = line.slice(0, eqIdx).trim().toUpperCase()\n        let v = line.slice(eqIdx + 1).trim()\n        if ((v.startsWith('\"') && v.endsWith('\"')) || (v.startsWith(\"'\") && v.endsWith(\"'\"))) {\n          v = v.slice(1, -1)\n        }\n        if (k) {\n          const isSecret =\n            importEncryptAll ||\n            k.includes('SECRET') ||\n            k.includes('KEY') ||\n            k.includes('PASSWORD') ||\n            k.includes('TOKEN') ||\n            k.includes('PRIVATE') ||\n            k.includes('AUTH')\n          results.push({ key: k, value: v, isSecret })\n        }\n      }\n    }\n    return results\n  }, [importText, importEncryptAll])\n\n  function handleImport() {\n    const items = parsedImportItems\n    if (items.length === 0) return\n\n    const newVars: EnvironmentVariable[] = items.map((item, index) => ({\n      id: `env-imported-${Date.now()}-${index}`,\n      key: item.key,\n      value: item.value,\n      environments: [...importEnvs],\n      isSecret: item.isSecret,\n      updatedAt: 'Imported just now',\n      updatedBy: 'you',\n    }))\n\n    setVariables((prev) => [...newVars, ...prev])\n    setImportText('')\n    setIsImportOpen(false)\n  }\n\n  function exportEnvFile() {\n    const lines = variables.map((v) => `# ${v.environments.join(', ')}\\n${v.key}=${v.value}`)\n    const blob = new Blob([lines.join('\\n\\n')], { type: 'text/plain;charset=utf-8' })\n    const url = URL.createObjectURL(blob)\n    const a = document.createElement('a')\n    a.href = url\n    a.download = '.env.production'\n    a.click()\n    URL.revokeObjectURL(url)\n  }\n\n  return (\n    <div data-slot=\"environment-variables-manager\" className={cn('w-full space-y-6', className)}>\n      {/* Header Section */}\n      <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n        <div className=\"space-y-1\">\n          <div className=\"flex items-center gap-2.5\">\n            <div className=\"bg-primary/10 text-primary grid size-8 place-items-center rounded-lg border\">\n              <KeyRound className=\"size-4\" />\n            </div>\n            <h2 className=\"text-xl font-semibold tracking-tight sm:text-2xl\">Environment Variables</h2>\n          </div>\n          <p className=\"text-muted-foreground text-sm\">\n            Manage encrypted secrets, API keys, and configuration for your deployments.\n          </p>\n        </div>\n\n        <div className=\"flex flex-wrap items-center gap-2\">\n          <Button variant=\"outline\" size=\"sm\" className=\"gap-1.5 shadow-xs\" onClick={() => setIsImportOpen(true)}>\n            <Upload className=\"size-3.5\" />\n            <span>Import .env</span>\n          </Button>\n          <Button\n            aria-label=\"Download attachment\"\n            variant=\"outline\"\n            size=\"sm\"\n            className=\"gap-1.5 shadow-xs\"\n            onClick={exportEnvFile}\n          >\n            <Download className=\"size-3.5\" />\n            <span>Export</span>\n          </Button>\n          <Button\n            size=\"sm\"\n            className=\"gap-1.5 shadow-xs\"\n            variant={isAddOpen ? 'secondary' : 'default'}\n            onClick={() => setIsAddOpen(!isAddOpen)}\n          >\n            {!isAddOpen ? <Plus className=\"size-4\" /> : <X className=\"size-4\" />}\n            <span>{isAddOpen ? 'Close Form' : 'Add Variable'}</span>\n          </Button>\n        </div>\n      </div>\n\n      {/* Add Variable Expandable Card */}\n      {isAddOpen && (\n        <Card className=\"border-primary/30 bg-card/60 relative shadow-sm\">\n          <CardHeader className=\"pb-3\">\n            <div className=\"flex items-center justify-between\">\n              <div>\n                <CardTitle className=\"text-base font-semibold\">New Environment Variable</CardTitle>\n                <CardDescription className=\"text-xs\">\n                  Add a new secret key or configuration parameter to your environment scopes.\n                </CardDescription>\n              </div>\n              <Button variant=\"ghost\" size=\"icon-sm\" aria-label=\"Cancel adding variable\" onClick={resetAddForm}>\n                <X className=\"size-4\" />\n              </Button>\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-4\">\n            <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n              <div className=\"space-y-1.5\">\n                <label className=\"text-foreground text-xs font-medium\">Variable Key</label>\n                <Input\n                  value={newKey}\n                  onChange={(e) => setNewKey(e.target.value)}\n                  placeholder=\"e.g. STRIPE_SECRET_KEY\"\n                  className=\"font-mono text-xs uppercase\"\n                  onKeyDown={(e) => e.key === 'Enter' && handleAddVariable()}\n                />\n                <p className=\"text-muted-foreground text-xs\">Uppercase characters and underscores recommended.</p>\n              </div>\n              <div className=\"space-y-1.5\">\n                <label className=\"text-foreground text-xs font-medium\">Variable Value</label>\n                <Input\n                  value={newValue}\n                  onChange={(e) => setNewValue(e.target.value)}\n                  type={newIsSecret ? 'password' : 'text'}\n                  placeholder=\"Enter secret token or value...\"\n                  className=\"font-mono text-xs\"\n                  onKeyDown={(e) => e.key === 'Enter' && handleAddVariable()}\n                />\n                <p className=\"text-muted-foreground text-xs\">Values are encrypted at rest with AES-256-GCM.</p>\n              </div>\n            </div>\n\n            <div className=\"flex flex-col gap-4 pt-1 sm:flex-row sm:items-center sm:justify-between\">\n              <div className=\"space-y-2\">\n                <span className=\"text-foreground text-xs font-medium\">Environment Scopes</span>\n                <div className=\"flex flex-wrap items-center gap-3\">\n                  <label\n                    className={cn(\n                      'hover:bg-accent/50 flex cursor-pointer items-center gap-2 rounded-md border px-2.5 py-1.5 text-xs transition-colors select-none',\n                      newEnvs.includes('production') && 'border-success/40 bg-success/5',\n                    )}\n                  >\n                    <Checkbox\n                      checked={newEnvs.includes('production')}\n                      onCheckedChange={() => toggleNewEnv('production')}\n                    />\n                    <span className=\"text-success font-medium\">Production</span>\n                  </label>\n                  <label\n                    className={cn(\n                      'hover:bg-accent/50 flex cursor-pointer items-center gap-2 rounded-md border px-2.5 py-1.5 text-xs transition-colors select-none',\n                      newEnvs.includes('preview') && 'border-info/40 bg-info/5',\n                    )}\n                  >\n                    <Checkbox checked={newEnvs.includes('preview')} onCheckedChange={() => toggleNewEnv('preview')} />\n                    <span className=\"text-info font-medium\">Preview</span>\n                  </label>\n                  <label\n                    className={cn(\n                      'hover:bg-accent/50 flex cursor-pointer items-center gap-2 rounded-md border px-2.5 py-1.5 text-xs transition-colors select-none',\n                      newEnvs.includes('development') && 'border-chart-2/40 bg-chart-2/5',\n                    )}\n                  >\n                    <Checkbox\n                      checked={newEnvs.includes('development')}\n                      onCheckedChange={() => toggleNewEnv('development')}\n                    />\n                    <span className=\"text-chart-2 font-medium\">Development</span>\n                  </label>\n                </div>\n              </div>\n\n              <div className=\"flex items-center gap-2\">\n                <Checkbox\n                  id=\"react-new-is-secret\"\n                  checked={newIsSecret}\n                  onCheckedChange={(c) => setNewIsSecret(Boolean(c))}\n                />\n                <label htmlFor=\"react-new-is-secret\" className=\"cursor-pointer text-xs font-medium select-none\">\n                  Encrypt as Secret\n                </label>\n              </div>\n            </div>\n\n            <div className=\"flex items-center justify-end gap-2 border-t pt-3\">\n              <Button aria-label=\"Cancel adding variable\" variant=\"ghost\" size=\"sm\" onClick={resetAddForm}>\n                Cancel\n              </Button>\n              <Button size=\"sm\" disabled={!newKey.trim() || !newValue.trim()} onClick={handleAddVariable}>\n                Save Variable\n              </Button>\n            </div>\n          </CardContent>\n        </Card>\n      )}\n\n      {/* Environment Tabs & Search / Filter Controls */}\n      <div className=\"space-y-3\">\n        <Tabs\n          value={activeTab}\n          onValueChange={(val) => setActiveTab(val as 'all' | EnvironmentScope)}\n          className=\"w-full\"\n        >\n          <TabsList className=\"w-full justify-start overflow-x-auto sm:w-auto\">\n            <TabsTrigger value=\"all\" className=\"text-xs\">\n              All Environments\n              <Badge variant=\"secondary\" className=\"ml-1.5 px-1.5 py-0 text-xs font-semibold\">\n                {counts.all}\n              </Badge>\n            </TabsTrigger>\n            <TabsTrigger value=\"production\" className=\"text-xs\">\n              Production\n              <Badge variant=\"secondary\" className=\"ml-1.5 px-1.5 py-0 text-xs font-semibold\">\n                {counts.production}\n              </Badge>\n            </TabsTrigger>\n            <TabsTrigger value=\"preview\" className=\"text-xs\">\n              Preview\n              <Badge variant=\"secondary\" className=\"ml-1.5 px-1.5 py-0 text-xs font-semibold\">\n                {counts.preview}\n              </Badge>\n            </TabsTrigger>\n            <TabsTrigger value=\"development\" className=\"text-xs\">\n              Development\n              <Badge variant=\"secondary\" className=\"ml-1.5 px-1.5 py-0 text-xs font-semibold\">\n                {counts.development}\n              </Badge>\n            </TabsTrigger>\n          </TabsList>\n        </Tabs>\n\n        <div className=\"flex flex-col gap-2.5 sm:flex-row sm:items-center sm:justify-between\">\n          <div className=\"flex flex-1 flex-wrap items-center gap-2\">\n            <div className=\"relative max-w-sm min-w-[200px] flex-1\">\n              <Search className=\"text-muted-foreground pointer-events-none absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2\" />\n              <Input\n                value={searchQuery}\n                onChange={(e) => setSearchQuery(e.target.value)}\n                placeholder=\"Search variables by key...\"\n                className=\"h-8.5 pl-8 text-xs shadow-xs\"\n              />\n            </div>\n\n            <Select value={typeFilter} onValueChange={(val) => setTypeFilter(val as EnvVarTypeFilter)}>\n              <SelectTrigger className=\"h-8.5 w-[140px] text-xs shadow-xs\">\n                <SelectValue placeholder=\"All types\" />\n              </SelectTrigger>\n              <SelectContent>\n                <SelectItem value=\"all\">All Types</SelectItem>\n                <SelectItem value=\"secret\">Encrypted Secrets</SelectItem>\n                <SelectItem value=\"plain\">Plaintext</SelectItem>\n              </SelectContent>\n            </Select>\n          </div>\n\n          <div className=\"flex items-center gap-2\">\n            <Button\n              variant=\"outline\"\n              size=\"sm\"\n              className={cn('h-8.5 gap-1.5 text-xs shadow-xs', revealAll && 'border-primary text-primary')}\n              onClick={toggleRevealAll}\n            >\n              {revealAll ? <EyeOff className=\"size-3.5\" /> : <Eye className=\"size-3.5\" />}\n              <span>{revealAll ? 'Hide All' : 'Reveal All Values'}</span>\n            </Button>\n          </div>\n        </div>\n      </div>\n\n      {/* Variables Table */}\n      <div className=\"bg-card overflow-hidden rounded-lg border shadow-xs\">\n        <div className=\"overflow-x-auto\">\n          <Table>\n            <TableHeader>\n              <TableRow className=\"bg-muted/40 hover:bg-muted/40\">\n                <TableHead className=\"text-muted-foreground text-xs font-medium\">Variable Key</TableHead>\n                <TableHead className=\"text-muted-foreground text-xs font-medium\">Value</TableHead>\n                <TableHead className=\"text-muted-foreground text-xs font-medium\">Environments</TableHead>\n                <TableHead className=\"text-muted-foreground text-xs font-medium\">Type</TableHead>\n                <TableHead className=\"text-muted-foreground hidden text-xs font-medium md:table-cell\">\n                  Updated\n                </TableHead>\n                <TableHead className=\"w-[70px] text-right text-xs font-medium\">\n                  <span className=\"sr-only\">Actions</span>\n                </TableHead>\n              </TableRow>\n            </TableHeader>\n            <TableBody>\n              {filteredVariables.map((item) => (\n                <TableRow key={item.id} className=\"group hover:bg-muted/30 transition-colors\">\n                  {/* Key */}\n                  <TableCell className=\"py-3.5\">\n                    <div className=\"flex items-center gap-2\">\n                      <span className=\"text-foreground font-mono text-xs font-semibold tracking-tight select-all sm:text-sm\">\n                        {item.key}\n                      </span>\n                      <button\n                        type=\"button\"\n                        aria-label=\"Copy variable key\"\n                        className=\"text-muted-foreground hover:text-foreground opacity-0 transition-opacity group-hover:opacity-100 focus:opacity-100\"\n                        onClick={() => copyValue(item.key, `key-${item.id}`)}\n                      >\n                        {copiedId === `key-${item.id}` ? (\n                          <Check className=\"text-success size-3.5\" />\n                        ) : (\n                          <Copy className=\"size-3.5\" />\n                        )}\n                      </button>\n                    </div>\n                  </TableCell>\n\n                  {/* Value Mask / Plain */}\n                  <TableCell className=\"py-3.5\">\n                    <div className=\"flex max-w-[280px] items-center gap-1.5 sm:max-w-xs md:max-w-sm\">\n                      <code\n                        className=\"bg-muted/60 text-foreground max-w-[200px] min-w-0 truncate rounded border px-2 py-1 font-mono text-xs sm:max-w-[240px]\"\n                        title={isRevealed(item.id) ? item.value : 'Masked secret value'}\n                      >\n                        {isRevealed(item.id) ? item.value : maskString(item.value)}\n                      </code>\n                      <Button\n                        variant=\"ghost\"\n                        size=\"icon-xs\"\n                        className=\"text-muted-foreground hover:text-foreground size-7 shrink-0\"\n                        aria-label={isRevealed(item.id) ? 'Hide value' : 'Reveal value'}\n                        onClick={() => toggleReveal(item.id)}\n                      >\n                        {isRevealed(item.id) ? <EyeOff className=\"size-3.5\" /> : <Eye className=\"size-3.5\" />}\n                      </Button>\n                      <Button\n                        variant=\"ghost\"\n                        size=\"icon-xs\"\n                        className=\"text-muted-foreground hover:text-foreground size-7 shrink-0\"\n                        aria-label={copiedId === item.id ? 'Copied' : 'Copy value'}\n                        onClick={() => copyValue(item.value, item.id)}\n                      >\n                        {copiedId === item.id ? (\n                          <Check className=\"text-success size-3.5\" />\n                        ) : (\n                          <Copy className=\"size-3.5\" />\n                        )}\n                      </Button>\n                    </div>\n                  </TableCell>\n\n                  {/* Environments */}\n                  <TableCell className=\"py-3.5\">\n                    <div className=\"flex flex-wrap items-center gap-1\">\n                      {item.environments.includes('production') && (\n                        <Badge\n                          variant=\"outline\"\n                          className=\"border-success/30 bg-success/10 text-success px-2 py-0 text-xs font-medium\"\n                        >\n                          Production\n                        </Badge>\n                      )}\n                      {item.environments.includes('preview') && (\n                        <Badge\n                          variant=\"outline\"\n                          className=\"border-info/30 bg-info/10 text-info px-2 py-0 text-xs font-medium\"\n                        >\n                          Preview\n                        </Badge>\n                      )}\n                      {item.environments.includes('development') && (\n                        <Badge\n                          variant=\"outline\"\n                          className=\"border-chart-2/30 bg-chart-2/10 text-chart-2 px-2 py-0 text-xs font-medium\"\n                        >\n                          Development\n                        </Badge>\n                      )}\n                    </div>\n                  </TableCell>\n\n                  {/* Type */}\n                  <TableCell className=\"py-3.5\">\n                    {item.isSecret ? (\n                      <Badge\n                        variant=\"secondary\"\n                        className=\"border-warning/30 bg-warning/10 text-warning gap-1 px-2 py-0 text-xs font-medium\"\n                      >\n                        <Lock className=\"size-3\" />\n                        Encrypted Secret\n                      </Badge>\n                    ) : (\n                      <Badge variant=\"outline\" className=\"text-muted-foreground gap-1 px-2 py-0 text-xs font-medium\">\n                        <FileCode className=\"size-3\" />\n                        Plaintext\n                      </Badge>\n                    )}\n                  </TableCell>\n\n                  {/* Updated */}\n                  <TableCell className=\"text-muted-foreground hidden py-3.5 text-xs whitespace-nowrap md:table-cell\">\n                    <span>{item.updatedAt}</span>\n                    <span className=\"block text-xs opacity-75\">by {item.updatedBy}</span>\n                  </TableCell>\n\n                  {/* Actions Dropdown */}\n                  <TableCell className=\"py-3.5 text-right\">\n                    <DropdownMenu>\n                      <DropdownMenuTrigger asChild>\n                        <Button\n                          variant=\"ghost\"\n                          size=\"icon-sm\"\n                          className=\"text-muted-foreground hover:text-foreground size-8\"\n                        >\n                          <MoreHorizontal className=\"size-4\" />\n                          <span className=\"sr-only\">Actions for {item.key}</span>\n                        </Button>\n                      </DropdownMenuTrigger>\n                      <DropdownMenuContent align=\"end\" className=\"w-44 text-xs\">\n                        <DropdownMenuItem onClick={() => openEdit(item)}>\n                          <Pencil className=\"mr-2 size-3.5\" />\n                          <span>Edit variable</span>\n                        </DropdownMenuItem>\n                        <DropdownMenuItem onClick={() => handleDuplicate(item)}>\n                          <Copy className=\"mr-2 size-3.5\" />\n                          <span>Duplicate</span>\n                        </DropdownMenuItem>\n                        <DropdownMenuItem onClick={() => copyValue(item.value, item.id)}>\n                          {copiedId === item.id ? (\n                            <Check className=\"text-success mr-2 size-3.5\" />\n                          ) : (\n                            <Copy className=\"mr-2 size-3.5\" />\n                          )}\n                          <span>Copy value</span>\n                        </DropdownMenuItem>\n                        <DropdownMenuSeparator />\n                        <DropdownMenuItem\n                          className=\"text-destructive focus:text-destructive\"\n                          onClick={() => handleDelete(item.id)}\n                        >\n                          <Trash2 className=\"mr-2 size-3.5\" />\n                          <span>Delete</span>\n                        </DropdownMenuItem>\n                      </DropdownMenuContent>\n                    </DropdownMenu>\n                  </TableCell>\n                </TableRow>\n              ))}\n\n              {/* Empty State */}\n              {filteredVariables.length === 0 && (\n                <TableRow>\n                  <TableCell colSpan={6} className=\"h-44 text-center\">\n                    <div className=\"flex flex-col items-center justify-center space-y-2 py-6\">\n                      <div className=\"bg-muted text-muted-foreground grid size-10 place-items-center rounded-full border\">\n                        <AlertCircle className=\"size-5\" />\n                      </div>\n                      <p className=\"text-foreground text-sm font-medium\">No environment variables found</p>\n                      <p className=\"text-muted-foreground max-w-xs text-xs\">\n                        {searchQuery || typeFilter !== 'all' || activeTab !== 'all'\n                          ? 'Try adjusting your filters or search keywords.'\n                          : 'Add your first environment secret or configuration key.'}\n                      </p>\n                      {!searchQuery && typeFilter === 'all' && activeTab === 'all' && (\n                        <Button size=\"sm\" className=\"mt-2 text-xs\" onClick={() => setIsAddOpen(true)}>\n                          <Plus className=\"mr-1.5 size-3.5\" />\n                          Add Variable\n                        </Button>\n                      )}\n                    </div>\n                  </TableCell>\n                </TableRow>\n              )}\n            </TableBody>\n          </Table>\n        </div>\n      </div>\n\n      {/* Edit Variable Dialog */}\n      <Dialog open={Boolean(editingVariable)} onOpenChange={(open) => !open && setEditingVariable(null)}>\n        {editingVariable && (\n          <DialogContent className=\"sm:max-w-md\">\n            <DialogHeader>\n              <DialogTitle>Edit Environment Variable</DialogTitle>\n              <DialogDescription>Update variable value and configured environment scopes.</DialogDescription>\n            </DialogHeader>\n            <div className=\"space-y-4 py-2\">\n              <div className=\"space-y-1.5\">\n                <label className=\"text-xs font-medium\">Variable Key</label>\n                <Input\n                  value={editingVariable.key}\n                  onChange={(e) => setEditingVariable({ ...editingVariable, key: e.target.value })}\n                  className=\"font-mono text-xs uppercase\"\n                />\n              </div>\n\n              <div className=\"space-y-1.5\">\n                <label className=\"text-xs font-medium\">Variable Value</label>\n                <Input\n                  value={editingVariable.value}\n                  onChange={(e) => setEditingVariable({ ...editingVariable, value: e.target.value })}\n                  type={editingVariable.isSecret ? 'password' : 'text'}\n                  className=\"font-mono text-xs\"\n                />\n              </div>\n\n              <div className=\"space-y-2\">\n                <span className=\"text-xs font-medium\">Environments</span>\n                <div className=\"flex flex-wrap items-center gap-2\">\n                  <label\n                    className={cn(\n                      'hover:bg-accent/50 flex cursor-pointer items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs select-none',\n                      editingVariable.environments.includes('production') && 'border-success/40 bg-success/5',\n                    )}\n                  >\n                    <Checkbox\n                      checked={editingVariable.environments.includes('production')}\n                      onCheckedChange={() => toggleEditEnv('production')}\n                    />\n                    <span className=\"text-success font-medium\">Production</span>\n                  </label>\n                  <label\n                    className={cn(\n                      'hover:bg-accent/50 flex cursor-pointer items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs select-none',\n                      editingVariable.environments.includes('preview') && 'border-info/40 bg-info/5',\n                    )}\n                  >\n                    <Checkbox\n                      checked={editingVariable.environments.includes('preview')}\n                      onCheckedChange={() => toggleEditEnv('preview')}\n                    />\n                    <span className=\"text-info font-medium\">Preview</span>\n                  </label>\n                  <label\n                    className={cn(\n                      'hover:bg-accent/50 flex cursor-pointer items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs select-none',\n                      editingVariable.environments.includes('development') && 'border-chart-2/40 bg-chart-2/5',\n                    )}\n                  >\n                    <Checkbox\n                      checked={editingVariable.environments.includes('development')}\n                      onCheckedChange={() => toggleEditEnv('development')}\n                    />\n                    <span className=\"text-chart-2 font-medium\">Development</span>\n                  </label>\n                </div>\n              </div>\n\n              <div className=\"flex items-center gap-2 pt-1\">\n                <Checkbox\n                  id=\"react-edit-is-secret\"\n                  checked={editingVariable.isSecret}\n                  onCheckedChange={(c) => setEditingVariable({ ...editingVariable, isSecret: Boolean(c) })}\n                />\n                <label htmlFor=\"react-edit-is-secret\" className=\"cursor-pointer text-xs font-medium select-none\">\n                  Encrypt as Secret\n                </label>\n              </div>\n            </div>\n            <DialogFooter>\n              <Button variant=\"ghost\" size=\"sm\" onClick={() => setEditingVariable(null)}>\n                Cancel\n              </Button>\n              <Button size=\"sm\" onClick={saveEdit}>\n                Save Changes\n              </Button>\n            </DialogFooter>\n          </DialogContent>\n        )}\n      </Dialog>\n\n      {/* Import .env Dialog */}\n      <Dialog open={isImportOpen} onOpenChange={setIsImportOpen}>\n        <DialogContent className=\"sm:max-w-lg\">\n          <DialogHeader>\n            <div className=\"flex items-center gap-2\">\n              <div className=\"bg-primary/10 text-primary grid size-7 place-items-center rounded-md border\">\n                <Upload className=\"size-3.5\" />\n              </div>\n              <DialogTitle>Import .env File</DialogTitle>\n            </div>\n            <DialogDescription>\n              Paste your raw .env, .env.local, or .env.production file contents to bulk add variables.\n            </DialogDescription>\n          </DialogHeader>\n\n          <div className=\"space-y-4 py-2\">\n            <div className=\"space-y-1.5\">\n              <label className=\"text-xs font-medium\">.env File Content</label>\n              <Textarea\n                value={importText}\n                onValueChange={(v) => setImportText(v)}\n                rows={6}\n                placeholder=\"DATABASE_URL=postgresql://user:pass@host:5432/db&#10;STRIPE_SECRET_KEY=mock_key_...&#10;NEXT_PUBLIC_APP_URL=https://app.example.com\"\n                className=\"font-mono text-xs\"\n              />\n            </div>\n\n            <div className=\"space-y-2\">\n              <span className=\"text-xs font-medium\">Assign to Environments</span>\n              <div className=\"flex flex-wrap items-center gap-2\">\n                <label\n                  className={cn(\n                    'hover:bg-accent/50 flex cursor-pointer items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs select-none',\n                    importEnvs.includes('production') && 'border-success/40 bg-success/5',\n                  )}\n                >\n                  <Checkbox\n                    checked={importEnvs.includes('production')}\n                    onCheckedChange={() => toggleImportEnv('production')}\n                  />\n                  <span className=\"text-success font-medium\">Production</span>\n                </label>\n                <label\n                  className={cn(\n                    'hover:bg-accent/50 flex cursor-pointer items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs select-none',\n                    importEnvs.includes('preview') && 'border-info/40 bg-info/5',\n                  )}\n                >\n                  <Checkbox\n                    checked={importEnvs.includes('preview')}\n                    onCheckedChange={() => toggleImportEnv('preview')}\n                  />\n                  <span className=\"text-info font-medium\">Preview</span>\n                </label>\n                <label\n                  className={cn(\n                    'hover:bg-accent/50 flex cursor-pointer items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs select-none',\n                    importEnvs.includes('development') && 'border-chart-2/40 bg-chart-2/5',\n                  )}\n                >\n                  <Checkbox\n                    checked={importEnvs.includes('development')}\n                    onCheckedChange={() => toggleImportEnv('development')}\n                  />\n                  <span className=\"text-chart-2 font-medium\">Development</span>\n                </label>\n              </div>\n            </div>\n\n            <div className=\"flex items-center gap-2 pt-1\">\n              <Checkbox\n                id=\"react-import-encrypt-all\"\n                checked={importEncryptAll}\n                onCheckedChange={(c) => setImportEncryptAll(Boolean(c))}\n              />\n              <label htmlFor=\"react-import-encrypt-all\" className=\"cursor-pointer text-xs font-medium select-none\">\n                Encrypt all variables by default\n              </label>\n            </div>\n\n            {parsedImportItems.length > 0 && (\n              <div className=\"bg-muted/60 flex items-center gap-2 rounded-md border px-3 py-2 text-xs\">\n                <ShieldCheck className=\"text-success size-4 shrink-0\" />\n                <span>\n                  Ready to import <strong>{parsedImportItems.length}</strong> variable(s).\n                </span>\n              </div>\n            )}\n          </div>\n\n          <DialogFooter>\n            <Button variant=\"ghost\" size=\"sm\" onClick={() => setIsImportOpen(false)}>\n              Cancel\n            </Button>\n            <Button size=\"sm\" disabled={parsedImportItems.length === 0} onClick={handleImport}>\n              Import {parsedImportItems.length > 0 ? `(${parsedImportItems.length})` : ''}\n            </Button>\n          </DialogFooter>\n        </DialogContent>\n      </Dialog>\n    </div>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/EnvironmentVariablesManager.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/badge.json",
    "https://uipkge.dev/r/react/button.json",
    "https://uipkge.dev/r/react/card.json",
    "https://uipkge.dev/r/react/checkbox.json",
    "https://uipkge.dev/r/react/dialog.json",
    "https://uipkge.dev/r/react/dropdown-menu.json",
    "https://uipkge.dev/r/react/input.json",
    "https://uipkge.dev/r/react/select.json",
    "https://uipkge.dev/r/react/table.json",
    "https://uipkge.dev/r/react/tabs.json",
    "https://uipkge.dev/r/react/textarea.json"
  ],
  "description": "Vercel and Supabase style environment variables and secrets manager with environment scoping, mask/reveal toggles, bulk import, and inline editing.",
  "categories": [
    "devops",
    "dashboard",
    "data",
    "developer"
  ]
}