> ## Documentation Index
> Fetch the complete documentation index at: https://mythicframework.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Dev Coding Tools

> Generate configurations and preview code with dev coding tools

export const ComponentDemo = () => {
  const [activeTab, setActiveTab] = useState('register');
  const [componentName, setComponentName] = useState('MyComponent');
  const [methodName, setMethodName] = useState('DoSomething');
  const [fetchComponent, setFetchComponent] = useState('Inventory');
  const [extendComponent, setExtendComponent] = useState('Jobs');
  const [extendMethod, setExtendMethod] = useState('NewMethod');
  const [components] = useState({
    Inventory: {
      methods: ['AddItem', 'RemoveItem', 'GetInventory']
    },
    Jobs: {
      methods: ['SetJob', 'ClockIn', 'ClockOut']
    },
    Vehicles: {
      methods: ['Spawn', 'Delete', 'GetKeys']
    }
  });
  const generateRegisterCode = () => {
    return `-- Register a new component
exports('RegisterComponent', function(component, data)
    COMPONENTS['${componentName}'] = data
end)

-- Example registration:
exports['mythic-base']:RegisterComponent('${componentName}', {
    ${methodName} = function(self, param)
        print('${methodName} called with:', param)
        return true
    end,
})`;
  };
  const generateFetchCode = () => {
    return `-- Fetch an existing component
local component = exports['mythic-base']:FetchComponent('${fetchComponent}')

-- Use the component:
if component then
    ${components[fetchComponent]?.methods[0] ? `component:${components[fetchComponent].methods[0]}(...)` : 'component:SomeMethod(...)'}
end`;
  };
  const generateExtendCode = () => {
    return `-- Extend an existing component
exports['mythic-base']:ExtendComponent('${extendComponent}', {
    ${extendMethod} = function(self, param)
        print('New method ${extendMethod} added to ${extendComponent}')
        -- Your custom logic here
        return param * 2
    end,
})

-- Now you can use the new method:
local ${extendComponent.toLowerCase()} = COMPONENTS.${extendComponent}
${extendComponent.toLowerCase()}:${extendMethod}(10) -- Returns 20`;
  };
  const renderTab = () => {
    switch (activeTab) {
      case 'register':
        return <div className="space-y-4">
            <p className="text-sm text-zinc-950/70 dark:text-white/70">
              <strong>RegisterComponent</strong> creates a new component or overrides an existing one.
              Use this when creating a new resource with its own component.
            </p>
            <div>
              <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
                Component Name:
              </label>
              <input type="text" value={componentName} onChange={e => setComponentName(e.target.value)} className="w-full px-3 py-2 bg-zinc-100 dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded text-sm" />
            </div>
            <div>
              <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
                Method Name:
              </label>
              <input type="text" value={methodName} onChange={e => setMethodName(e.target.value)} className="w-full px-3 py-2 bg-zinc-100 dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded text-sm" />
            </div>
            <pre className="bg-zinc-100 dark:bg-zinc-900 p-4 rounded border border-zinc-300 dark:border-zinc-700 overflow-auto text-xs font-mono">
              {generateRegisterCode()}
            </pre>
          </div>;
      case 'fetch':
        return <div className="space-y-4">
            <p className="text-sm text-zinc-950/70 dark:text-white/70">
              <strong>FetchComponent</strong> retrieves an existing component from COMPONENTS table.
              Use this to access functionality from other resources.
            </p>
            <div>
              <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
                Component to Fetch:
              </label>
              <select value={fetchComponent} onChange={e => setFetchComponent(e.target.value)} className="w-full px-3 py-2 bg-zinc-100 dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded text-sm">
                {Object.keys(components).map(comp => <option key={comp} value={comp}>{comp}</option>)}
              </select>
            </div>
            <div className="p-3 bg-zinc-100 dark:bg-zinc-900 rounded border border-zinc-300 dark:border-zinc-700">
              <div className="text-green-600 dark:text-green-400 text-sm font-semibold mb-2">
                Available Methods:
              </div>
              {components[fetchComponent]?.methods.map((method, idx) => <div key={idx} className="text-xs font-mono text-zinc-950/70 dark:text-white/70 py-1">
                  • {method}()
                </div>)}
            </div>
            <pre className="bg-zinc-100 dark:bg-zinc-900 p-4 rounded border border-zinc-300 dark:border-zinc-700 overflow-auto text-xs font-mono">
              {generateFetchCode()}
            </pre>
          </div>;
      case 'extend':
        return <div className="space-y-4">
            <p className="text-sm text-zinc-950/70 dark:text-white/70">
              <strong>ExtendComponent</strong> adds new methods to an existing component without overriding it.
              Perfect for adding custom functionality to core systems.
            </p>
            <div>
              <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
                Component to Extend:
              </label>
              <select value={extendComponent} onChange={e => setExtendComponent(e.target.value)} className="w-full px-3 py-2 bg-zinc-100 dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded text-sm">
                {Object.keys(components).map(comp => <option key={comp} value={comp}>{comp}</option>)}
              </select>
            </div>
            <div>
              <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
                New Method Name:
              </label>
              <input type="text" value={extendMethod} onChange={e => setExtendMethod(e.target.value)} className="w-full px-3 py-2 bg-zinc-100 dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded text-sm" />
            </div>
            <pre className="bg-zinc-100 dark:bg-zinc-900 p-4 rounded border border-zinc-300 dark:border-zinc-700 overflow-auto text-xs font-mono">
              {generateExtendCode()}
            </pre>
          </div>;
      default:
        return null;
    }
  };
  return <div className="p-6 border dark:border-zinc-950/80 rounded-xl not-prose">
      <h3 className="text-xl font-bold text-blue-500 mb-4">
        Component System Interactive Demo
      </h3>

      <div className="flex gap-2 mb-6 border-b border-zinc-300 dark:border-zinc-700">
        <button onClick={() => setActiveTab('register')} className={`px-4 py-2 text-sm font-semibold transition-colors ${activeTab === 'register' ? 'text-blue-500 border-b-2 border-blue-500' : 'text-zinc-950/70 dark:text-white/70 hover:text-blue-500'}`}>
          RegisterComponent
        </button>
        <button onClick={() => setActiveTab('fetch')} className={`px-4 py-2 text-sm font-semibold transition-colors ${activeTab === 'fetch' ? 'text-blue-500 border-b-2 border-blue-500' : 'text-zinc-950/70 dark:text-white/70 hover:text-blue-500'}`}>
          FetchComponent
        </button>
        <button onClick={() => setActiveTab('extend')} className={`px-4 py-2 text-sm font-semibold transition-colors ${activeTab === 'extend' ? 'text-blue-500 border-b-2 border-blue-500' : 'text-zinc-950/70 dark:text-white/70 hover:text-blue-500'}`}>
          ExtendComponent
        </button>
      </div>

      {renderTab()}

      <div className="mt-6 p-3 bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded">
        <div className="text-amber-800 dark:text-amber-400 text-sm font-semibold mb-2">
          Key Differences:
        </div>
        <ul className="text-xs text-amber-900/80 dark:text-amber-300/80 space-y-1 pl-4">
          <li><strong>Register:</strong> Creates new component or completely replaces existing</li>
          <li><strong>Fetch:</strong> Gets reference to existing component for use</li>
          <li><strong>Extend:</strong> Adds methods to existing component without replacing it</li>
        </ul>
      </div>
    </div>;
};

export const JobBuilder = () => {
  const [jobId, setJobId] = useState('custom_job');
  const [jobName, setJobName] = useState('Custom Job');
  const [jobType, setJobType] = useState('Company');
  const [salary, setSalary] = useState(200);
  const [grades, setGrades] = useState([{
    _key: 0,
    id: 'employee',
    name: 'Employee',
    level: 1,
    perms: {
      JOB_STORAGE: true
    }
  }, {
    _key: 1,
    id: 'manager',
    name: 'Manager',
    level: 4,
    perms: {
      JOB_STORAGE: true,
      JOB_CRAFTING: true,
      JOB_HIRE: true
    }
  }, {
    _key: 2,
    id: 'owner',
    name: 'Owner',
    level: 99,
    perms: {
      JOB_MANAGEMENT: true,
      JOB_MANAGE_EMPLOYEES: true,
      JOB_HIRE: true,
      JOB_FIRE: true,
      JOB_STORAGE: true,
      JOB_CRAFTING: true
    }
  }]);
  const [copied, setCopied] = useState(false);
  const [nextKey, setNextKey] = useState(3);
  const availablePerms = [{
    key: 'JOB_STORAGE',
    label: 'Storage'
  }, {
    key: 'JOB_CRAFTING',
    label: 'Crafting'
  }, {
    key: 'JOB_HIRE',
    label: 'Hire'
  }, {
    key: 'JOB_FIRE',
    label: 'Fire'
  }, {
    key: 'JOB_MANAGE_EMPLOYEES',
    label: 'Manage Employees'
  }, {
    key: 'JOB_MANAGEMENT',
    label: 'Management'
  }];
  const addGrade = () => {
    setGrades([...grades, {
      _key: nextKey,
      id: `grade_${nextKey}`,
      name: `Grade ${nextKey}`,
      level: 1,
      perms: {
        JOB_STORAGE: true
      }
    }]);
    setNextKey(nextKey + 1);
  };
  const removeGrade = _key => {
    if (grades.length > 1) {
      setGrades(grades.filter(g => g._key !== _key));
    }
  };
  const updateGrade = (_key, field, value) => {
    setGrades(grades.map(g => g._key === _key ? {
      ...g,
      [field]: value
    } : g));
  };
  const togglePerm = (_key, permKey) => {
    setGrades(grades.map(g => {
      if (g._key !== _key) return g;
      const newPerms = {
        ...g.perms
      };
      if (newPerms[permKey]) {
        delete newPerms[permKey];
      } else {
        newPerms[permKey] = true;
      }
      return {
        ...g,
        perms: newPerms
      };
    }));
  };
  const generateLuaCode = () => {
    const timestamp = Math.floor(Date.now() / 1000);
    let code = `table.insert(_defaultJobData, {\n`;
    code += `    Type = '${jobType}',\n`;
    code += `    LastUpdated = ${timestamp},\n`;
    code += `    Id = '${jobId}',\n`;
    code += `    Name = '${jobName}',\n`;
    code += `    Salary = ${salary},\n`;
    code += `    SalaryTier = 1,\n`;
    code += `    Grades = {\n`;
    const sorted = [...grades].sort((a, b) => a.level - b.level);
    sorted.forEach(grade => {
      const permEntries = Object.keys(grade.perms).filter(k => grade.perms[k]);
      code += `        {\n`;
      code += `            Id = '${grade.id}',\n`;
      code += `            Name = '${grade.name}',\n`;
      code += `            Level = ${grade.level},\n`;
      if (permEntries.length > 0) {
        code += `            Permissions = {\n`;
        permEntries.forEach(p => {
          code += `                ${p} = true,\n`;
        });
        code += `            },\n`;
      } else {
        code += `            Permissions = {},\n`;
      }
      code += `        },\n`;
    });
    code += `    }\n`;
    code += `})`;
    return code;
  };
  const copyToClipboard = () => {
    navigator.clipboard.writeText(generateLuaCode());
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  };
  return <div className="p-6 border dark:border-zinc-950/80 rounded-xl not-prose space-y-4">
      <h3 className="text-lg font-bold text-blue-500 mb-4">
        Job Configuration Builder
      </h3>

      <div className="grid grid-cols-2 gap-4">
        <div>
          <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
            Job ID (lowercase, no spaces)
          </label>
          <input type="text" value={jobId} onChange={e => setJobId(e.target.value.toLowerCase().replace(/\s+/g, '_'))} className="w-full px-3 py-2 bg-zinc-100 dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded text-sm" placeholder="custom_job" />
        </div>

        <div>
          <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
            Job Name
          </label>
          <input type="text" value={jobName} onChange={e => setJobName(e.target.value)} className="w-full px-3 py-2 bg-zinc-100 dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded text-sm" placeholder="Custom Job" />
        </div>
      </div>

      <div className="grid grid-cols-2 gap-4">
        <div>
          <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
            Type
          </label>
          <select value={jobType} onChange={e => setJobType(e.target.value)} className="w-full px-3 py-2 bg-zinc-100 dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded text-sm">
            <option value="Company">Company</option>
            <option value="Government">Government</option>
          </select>
        </div>

        <div>
          <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
            Salary: ${salary}
          </label>
          <input type="range" min="50" max="1000" step="5" value={salary} onChange={e => setSalary(parseInt(e.target.value))} className="w-full h-2 bg-zinc-950/20 rounded-lg appearance-none cursor-pointer dark:bg-white/20" />
        </div>
      </div>

      <div className="border-t border-zinc-300 dark:border-zinc-700 pt-4">
        <div className="flex justify-between items-center mb-3">
          <h4 className="text-sm font-semibold text-zinc-950/70 dark:text-white/70">
            Grades
          </h4>
          <button onClick={addGrade} className="px-3 py-1 bg-green-500 hover:bg-green-600 text-white rounded text-sm font-medium transition-colors">
            + Add Grade
          </button>
        </div>

        {grades.map(grade => <div key={grade._key} className="bg-zinc-100 dark:bg-zinc-900 p-3 rounded mb-3 border border-zinc-300 dark:border-zinc-700">
            <div className="grid grid-cols-4 gap-2 items-end mb-2">
              <div>
                <label className="block text-xs text-zinc-950/50 dark:text-white/50 mb-1">
                  Grade ID
                </label>
                <input type="text" value={grade.id} onChange={e => updateGrade(grade._key, 'id', e.target.value.toLowerCase().replace(/\s+/g, '_'))} className="w-full px-2 py-1 bg-white dark:bg-zinc-800 border border-zinc-300 dark:border-zinc-700 rounded text-sm" placeholder="employee" />
              </div>
              <div>
                <label className="block text-xs text-zinc-950/50 dark:text-white/50 mb-1">
                  Name
                </label>
                <input type="text" value={grade.name} onChange={e => updateGrade(grade._key, 'name', e.target.value)} className="w-full px-2 py-1 bg-white dark:bg-zinc-800 border border-zinc-300 dark:border-zinc-700 rounded text-sm" placeholder="Employee" />
              </div>
              <div>
                <label className="block text-xs text-zinc-950/50 dark:text-white/50 mb-1">
                  Level
                </label>
                <input type="number" min="1" max="99" value={grade.level} onChange={e => updateGrade(grade._key, 'level', parseInt(e.target.value) || 1)} className="w-full px-2 py-1 bg-white dark:bg-zinc-800 border border-zinc-300 dark:border-zinc-700 rounded text-sm" />
              </div>
              <button onClick={() => removeGrade(grade._key)} disabled={grades.length === 1} className="px-2 py-1 bg-red-500 hover:bg-red-600 disabled:bg-zinc-400 disabled:cursor-not-allowed text-white rounded text-sm transition-colors">
                Remove
              </button>
            </div>

            <div className="flex flex-wrap gap-2">
              {availablePerms.map(perm => <label key={perm.key} className="flex items-center space-x-1 text-xs text-zinc-950/60 dark:text-white/60 cursor-pointer">
                  <input type="checkbox" checked={!!grade.perms[perm.key]} onChange={() => togglePerm(grade._key, perm.key)} className="rounded" />
                  <span>{perm.label}</span>
                </label>)}
            </div>
          </div>)}
      </div>

      <div>
        <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-2">
          Generated Lua Code:
        </label>
        <pre className="bg-zinc-100 dark:bg-zinc-900 p-4 rounded border border-zinc-300 dark:border-zinc-700 overflow-auto text-xs font-mono max-h-80">
          {generateLuaCode()}
        </pre>
      </div>

      <button onClick={copyToClipboard} className="w-full px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded text-sm font-medium transition-colors">
        {copied ? '✓ Copied to Clipboard!' : 'Copy to Clipboard'}
      </button>

      <div className="bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded p-3">
        <p className="text-xs text-amber-900 dark:text-amber-300">
          <strong>Note:</strong> Place this in a new file under{' '}
          <code>mythic-jobs/config/defaultJobs/</code>. The file needs access to the{' '}
          <code>_defaultJobData</code> global table. Level determines grade hierarchy — higher levels
          have more authority. Owner should always be Level 99.
        </p>
      </div>
    </div>;
};

export const ItemGenerator = () => {
  const [itemName, setItemName] = useState('custom_item');
  const [label, setLabel] = useState('Custom Item');
  const [description, setDescription] = useState('');
  const [weight, setWeight] = useState(1.0);
  const [price, setPrice] = useState(100);
  const [type, setType] = useState(1);
  const [rarity, setRarity] = useState(1);
  const [isUsable, setIsUsable] = useState(false);
  const [isRemoved, setIsRemoved] = useState(false);
  const [stackable, setStackable] = useState(true);
  const [stackSize, setStackSize] = useState(10);
  const [isDestroyed, setIsDestroyed] = useState(false);
  const [hasDurability, setHasDurability] = useState(false);
  const [durabilityDays, setDurabilityDays] = useState(1);
  const [closeUi, setCloseUi] = useState(false);
  const [metalic, setMetalic] = useState(false);
  const [copied, setCopied] = useState(false);
  const typeNames = {
    1: 'Consumable',
    2: 'Weapon',
    3: 'Tool',
    4: 'Crafting Ingredient',
    5: 'Collectable',
    6: 'Junk',
    7: 'Unknown/Special',
    8: 'Evidence',
    9: 'Ammo',
    10: 'Container',
    11: 'Gem',
    12: 'Paraphernalia',
    13: 'Wearable',
    14: 'Contraband',
    15: 'Gang Chain',
    16: 'Weapon Attachment',
    17: 'Schematic'
  };
  const rarityNames = {
    0: 'Nothing',
    1: 'Common',
    2: 'Uncommon',
    3: 'Rare',
    4: 'Epic',
    5: 'Labor Objective'
  };
  const generateLuaCode = () => {
    let code = `{\n`;
    code += `\tname = '${itemName}',\n`;
    code += `\tlabel = '${label}',\n`;
    if (description) {
      code += `\tdescription = '${description}',\n`;
    }
    code += `\tprice = ${price},\n`;
    code += `\tweight = ${weight},\n`;
    code += `\ttype = ${type},\n`;
    code += `\trarity = ${rarity},\n`;
    code += `\n`;
    code += `\tisUsable = ${isUsable ? 'true' : 'false'},\n`;
    code += `\tisRemoved = ${isRemoved ? 'true' : 'false'},\n`;
    code += `\tisStackable = ${stackable ? stackSize : 'false'},\n`;
    code += `\tisDestroyed = ${isDestroyed ? 'true' : 'false'},\n`;
    code += `\tcloseUi = ${closeUi ? 'true' : 'false'},\n`;
    code += `\tmetalic = ${metalic ? 'true' : 'false'},\n`;
    if (hasDurability) {
      code += `\n`;
      code += `\t-- Durability: ${durabilityDays} day${durabilityDays !== 1 ? 's' : ''}\n`;
      code += `\tdurability = (60 * 60 * 24 * ${durabilityDays}),\n`;
    }
    code += `}`;
    return code;
  };
  const copyToClipboard = () => {
    navigator.clipboard.writeText(generateLuaCode());
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  };
  return <div className="p-6 border dark:border-zinc-950/80 rounded-xl not-prose space-y-4">
      <h3 className="text-lg font-bold text-blue-500 mb-4">
        Item Definition Generator
      </h3>

      <div className="grid grid-cols-2 gap-4">
        <div>
          <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
            Item Name (lowercase, no spaces)
          </label>
          <input type="text" value={itemName} onChange={e => setItemName(e.target.value.toLowerCase().replace(/\s+/g, '_'))} className="w-full px-3 py-2 bg-zinc-100 dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded text-sm" placeholder="custom_item" />
        </div>

        <div>
          <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
            Display Label
          </label>
          <input type="text" value={label} onChange={e => setLabel(e.target.value)} className="w-full px-3 py-2 bg-zinc-100 dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded text-sm" placeholder="Custom Item" />
        </div>
      </div>

      <div>
        <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
          Description (optional)
        </label>
        <textarea value={description} onChange={e => setDescription(e.target.value)} className="w-full px-3 py-2 bg-zinc-100 dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded text-sm" placeholder="Item description..." rows="2" />
      </div>

      <div className="grid grid-cols-2 gap-4">
        <div>
          <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
            Weight: {weight} kg
          </label>
          <input type="range" min="0" max="50" step="0.1" value={weight} onChange={e => setWeight(parseFloat(e.target.value))} className="w-full h-2 bg-zinc-950/20 rounded-lg appearance-none cursor-pointer dark:bg-white/20" />
        </div>

        <div>
          <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
            Price: ${price}
          </label>
          <input type="range" min="0" max="10000" value={price} onChange={e => setPrice(parseInt(e.target.value))} className="w-full h-2 bg-zinc-950/20 rounded-lg appearance-none cursor-pointer dark:bg-white/20" />
        </div>
      </div>

      <div className="grid grid-cols-2 gap-4">
        <div>
          <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
            Type
          </label>
          <select value={type} onChange={e => setType(parseInt(e.target.value))} className="w-full px-3 py-2 bg-zinc-100 dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded text-sm">
            {Object.entries(typeNames).map(([value, name]) => <option key={value} value={value}>
                {value} - {name}
              </option>)}
          </select>
        </div>

        <div>
          <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
            Rarity
          </label>
          <select value={rarity} onChange={e => setRarity(parseInt(e.target.value))} className="w-full px-3 py-2 bg-zinc-100 dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded text-sm">
            {Object.entries(rarityNames).map(([value, name]) => <option key={value} value={value}>
                {value} - {name}
              </option>)}
          </select>
        </div>
      </div>

      <div className="border-t border-zinc-300 dark:border-zinc-700 pt-4">
        <h4 className="text-sm font-semibold text-zinc-950/70 dark:text-white/70 mb-3">
          Item Properties
        </h4>

        <div className="grid grid-cols-2 gap-3">
          <label className="flex items-center space-x-2 text-sm text-zinc-950/70 dark:text-white/70">
            <input type="checkbox" checked={isUsable} onChange={e => setIsUsable(e.target.checked)} className="rounded" />
            <span>Usable</span>
          </label>

          <label className="flex items-center space-x-2 text-sm text-zinc-950/70 dark:text-white/70">
            <input type="checkbox" checked={isRemoved} onChange={e => setIsRemoved(e.target.checked)} className="rounded" />
            <span>Removed on Use</span>
          </label>

          <label className="flex items-center space-x-2 text-sm text-zinc-950/70 dark:text-white/70">
            <input type="checkbox" checked={isDestroyed} onChange={e => setIsDestroyed(e.target.checked)} className="rounded" />
            <span>Destroyed at 0 Durability</span>
          </label>

          <label className="flex items-center space-x-2 text-sm text-zinc-950/70 dark:text-white/70">
            <input type="checkbox" checked={closeUi} onChange={e => setCloseUi(e.target.checked)} className="rounded" />
            <span>Close UI on Use</span>
          </label>

          <label className="flex items-center space-x-2 text-sm text-zinc-950/70 dark:text-white/70">
            <input type="checkbox" checked={metalic} onChange={e => setMetalic(e.target.checked)} className="rounded" />
            <span>Metallic</span>
          </label>

          <label className="flex items-center space-x-2 text-sm text-zinc-950/70 dark:text-white/70">
            <input type="checkbox" checked={stackable} onChange={e => setStackable(e.target.checked)} className="rounded" />
            <span>Stackable</span>
          </label>
        </div>
      </div>

      {stackable && <div>
          <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
            Stack Size: {stackSize}
          </label>
          <input type="range" min="1" max="100" value={stackSize} onChange={e => setStackSize(parseInt(e.target.value))} className="w-full h-2 bg-zinc-950/20 rounded-lg appearance-none cursor-pointer dark:bg-white/20" />
        </div>}

      <div className="border-t border-zinc-300 dark:border-zinc-700 pt-4">
        <label className="flex items-center space-x-2 text-sm text-zinc-950/70 dark:text-white/70 mb-3">
          <input type="checkbox" checked={hasDurability} onChange={e => setHasDurability(e.target.checked)} className="rounded" />
          <span className="font-semibold">Has Durability/Decay</span>
        </label>

        {hasDurability && <div>
            <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">
              Durability: {durabilityDays} day{durabilityDays !== 1 ? 's' : ''}
            </label>
            <input type="range" min="1" max="30" value={durabilityDays} onChange={e => setDurabilityDays(parseInt(e.target.value))} className="w-full h-2 bg-zinc-950/20 rounded-lg appearance-none cursor-pointer dark:bg-white/20" />
            <p className="text-xs text-zinc-500 dark:text-zinc-400 mt-1">
              Time until item fully degrades: {durabilityDays * 24} hours ({durabilityDays * 24 * 60 * 60} seconds)
            </p>
          </div>}
      </div>

      <div>
        <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-2">
          Generated Lua Code:
        </label>
        <pre className="bg-zinc-100 dark:bg-zinc-900 p-4 rounded border border-zinc-300 dark:border-zinc-700 overflow-auto text-xs font-mono max-h-80">
          {generateLuaCode()}
        </pre>
      </div>

      <button onClick={copyToClipboard} className="w-full px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded text-sm font-medium transition-colors">
        {copied ? '✓ Copied to Clipboard!' : 'Copy to Clipboard'}
      </button>

      <div className="bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded p-3">
        <p className="text-xs text-amber-900 dark:text-amber-300">
          <strong>Note:</strong> This generates the item definition structure. You'll need to register this item
          with the Items component and add the image file to <code>mythic-inventory/ui/assets/items/</code>
        </p>
      </div>
    </div>;
};

export const ColorGenerator = () => {
  const [hue, setHue] = useState(180);
  const [saturation, setSaturation] = useState(50);
  const [lightness, setLightness] = useState(50);
  const [colors, setColors] = useState([]);
  const hslToHex = (h, s, l) => {
    s = s / 100;
    l = l / 100;
    const a = s * Math.min(l, 1 - l);
    const f = n => {
      const k = (n + h / 30) % 12;
      const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
      return Math.round(255 * color).toString(16).padStart(2, '0');
    };
    return `#${f(0)}${f(8)}${f(4)}`;
  };
  useEffect(() => {
    const newColors = [];
    for (let i = 0; i < 5; i++) {
      const l = Math.max(10, Math.min(90, lightness - 20 + i * 10));
      const hex = hslToHex(hue, saturation, l);
      newColors.push(hex);
    }
    setColors(newColors);
  }, [hue, saturation, lightness]);
  const copyToClipboard = color => {
    navigator.clipboard.writeText(color).then(() => {
      console.log(`Copied ${color} to clipboard!`);
    }).catch(err => {
      console.error("Failed to copy: ", err);
    });
  };
  const baseColor = hslToHex(hue, saturation, lightness);
  return <div className="p-4 border dark:border-zinc-950/80 rounded-xl not-prose">
      <div className="space-y-4">
        <div className="space-y-2">
          <label className="block text-sm text-zinc-950/70 dark:text-white/70">
            Hue: {hue}°
            <input type="range" min="0" max="360" value={hue} onChange={e => setHue(Number.parseInt(e.target.value))} className="w-full h-2 bg-zinc-950/20 rounded-lg appearance-none cursor-pointer dark:bg-white/20 mt-1" style={{
    background: `linear-gradient(to right,
                  hsl(0, ${saturation}%, ${lightness}%),
                  hsl(60, ${saturation}%, ${lightness}%),
                  hsl(120, ${saturation}%, ${lightness}%),
                  hsl(180, ${saturation}%, ${lightness}%),
                  hsl(240, ${saturation}%, ${lightness}%),
                  hsl(300, ${saturation}%, ${lightness}%),
                  hsl(360, ${saturation}%, ${lightness}%))`
  }} />
          </label>

          <label className="block text-sm text-zinc-950/70 dark:text-white/70">
            Saturation: {saturation}%
            <input type="range" min="0" max="100" value={saturation} onChange={e => setSaturation(Number.parseInt(e.target.value))} className="w-full h-2 bg-zinc-950/20 rounded-lg appearance-none cursor-pointer dark:bg-white/20 mt-1" style={{
    background: `linear-gradient(to right,
                  hsl(${hue}, 0%, ${lightness}%),
                  hsl(${hue}, 50%, ${lightness}%),
                  hsl(${hue}, 100%, ${lightness}%))`
  }} />
          </label>

          <label className="block text-sm text-zinc-950/70 dark:text-white/70">
            Lightness: {lightness}%
            <input type="range" min="0" max="100" value={lightness} onChange={e => setLightness(Number.parseInt(e.target.value))} className="w-full h-2 bg-zinc-950/20 rounded-lg appearance-none cursor-pointer dark:bg-white/20 mt-1" style={{
    background: `linear-gradient(to right,
                  hsl(${hue}, ${saturation}%, 0%),
                  hsl(${hue}, ${saturation}%, 50%),
                  hsl(${hue}, ${saturation}%, 100%))`
  }} />
          </label>
        </div>

        <div className="flex space-x-1">
          {colors.map((color, idx) => <div key={idx} className="h-16 rounded flex-1 cursor-pointer transition-transform hover:scale-105" style={{
    backgroundColor: color
  }} title={`Click to copy: ${color}`} onClick={() => copyToClipboard(color)} />)}
        </div>

        <div className="text-sm font-mono text-zinc-950/70 dark:text-white/70">
          <p>
            Base color: {baseColor}
          </p>
          <div className="flex flex-wrap gap-2 mt-2">
            {colors.map((color, idx) => <span key={idx} className="text-xs px-2 py-1 bg-zinc-200 dark:bg-zinc-800 rounded">
                {color}
              </span>)}
          </div>
        </div>
      </div>
    </div>;
};

<div className="text-center py-10 px-5">
  <h1 className="text-5xl font-extrabold mb-4 bg-gradient-to-r from-[#36A3EC] to-[#5BB5F0] bg-clip-text text-transparent inline-block">
    Dev Coding Tools
  </h1>

  <p className="text-xl text-zinc-400 mb-8 max-w-3xl mx-auto">
    Generate configs and preview code with these dev tools
  </p>
</div>

***

<AccordionGroup>
  <Accordion title="Color Theme Generator" icon="palette">
    <ColorGenerator />
  </Accordion>

  <Accordion title="Item Definition Generator" icon="box">
    <ItemGenerator />
  </Accordion>

  <Accordion title="Job Configuration Builder" icon="briefcase">
    <JobBuilder />
  </Accordion>

  <Accordion title="Component System Demo" icon="code">
    <ComponentDemo />
  </Accordion>
</AccordionGroup>

***

## Why Use Dev Tools?

<CardGroup cols={2}>
  <Card title="Live Preview" icon="eye">
    See your configurations in action before implementing them in your server.
  </Card>

  <Card title="Copy-Ready Code" icon="clipboard">
    Generate properly formatted Lua code that you can paste directly into your configs.
  </Card>

  <Card title="Learn by Doing" icon="graduation-cap">
    Understand the framework's systems by experimenting with different values.
  </Card>

  <Card title="Save Time" icon="clock">
    No more syntax errors or formatting issues - the tools handle it all for you.
  </Card>
</CardGroup>
