Ctrl K
ComunidadGuías…

mockups/admin_settings.html

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
<!DOCTYPE html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Admin settings — Cloudzilla</title>
<link rel="stylesheet" href="/assets/tailwind.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500&family=Geist:wght@400;500;600&display=swap" rel="stylesheet" />
</head>
<body class="min-h-screen flex flex-col antialiased font-sans">
<a href="#main-content" class="skip-link">Skip to main content</a>

<div id="cz-header"></div>

<main id="main-content" tabindex="-1" class="max-w-[1400px] mx-auto px-6 pt-6 pb-20 flex-1 w-full">
<div class="space-y-6">
<nav aria-label="Admin sections" class="flex items-center gap-1 border-b border-border text-sm">
  <a href="admin_settings.html" aria-current="page" class="px-3 py-2.5 border-b -mb-px border-foreground text-foreground font-medium inline-flex items-center gap-1.5">Settings</a>
  <a href="admin_users.html" class="px-3 py-2.5 border-b -mb-px border-transparent text-muted-foreground hover:text-foreground inline-flex items-center gap-1.5">Users</a>
  <a href="audit_log.html" class="px-3 py-2.5 border-b -mb-px border-transparent text-muted-foreground hover:text-foreground inline-flex items-center gap-1.5">Audit log</a>
  <a href="sso_settings.html" class="px-3 py-2.5 border-b -mb-px border-transparent text-muted-foreground hover:text-foreground inline-flex items-center gap-1.5">Single sign-on</a>
</nav>
<div class="flex justify-between items-center">
  <h1 class="text-2xl font-semibold tracking-tight">Admin settings</h1>
</div>

<div class="rounded-lg border border-border bg-card text-card-foreground">
  <div class="flex flex-col space-y-1.5 p-5 border-b border-border">
    <h2 class="text-[13px] font-semibold leading-none tracking-tight">Instance settings</h2>
    <p class="text-[12px] text-muted-foreground">Toggle site-wide feature flags.</p>
  </div>
  <div class="p-5">
    <div id="admin-settings-list" class="space-y-3">
        <form onsubmit="return false" class="flex items-center justify-between py-3 border-b border-border last:border-0">
          <label class="flex flex-1 items-center justify-between gap-4 cursor-pointer">
            <span class="text-sm font-medium text-foreground">Allow sign-ups</span>
            <span class="relative inline-flex items-center"><input type="checkbox" role="switch" id="setting-allow_registration" data-setting="allow_registration" checked class="peer sr-only" /><span aria-hidden="true" class="relative w-9 h-5 bg-input dark:bg-border-strong rounded-full transition-colors peer-checked:bg-switch dark:peer-checked:bg-switch peer-focus-visible:outline-solid peer-focus-visible:outline-2 peer-focus-visible:outline-ring peer-focus-visible:outline-offset-2 peer-disabled:opacity-50 peer-disabled:cursor-not-allowed after:absolute after:content-[''] after:top-0.5 after:left-0.5 after:bg-white after:shadow-sm after:rounded-full after:h-4 after:w-4 after:transition-transform peer-checked:after:translate-x-4"></span></span>
          </label>
        </form>
        <form onsubmit="return false" class="flex items-center justify-between py-3 border-b border-border last:border-0">
          <label class="flex flex-1 items-center justify-between gap-4 cursor-pointer">
            <span class="text-sm font-medium text-foreground">Allow sign-in</span>
            <span class="relative inline-flex items-center"><input type="checkbox" role="switch" id="setting-allow_login" data-setting="allow_login" checked class="peer sr-only" /><span aria-hidden="true" class="relative w-9 h-5 bg-input dark:bg-border-strong rounded-full transition-colors peer-checked:bg-switch dark:peer-checked:bg-switch peer-focus-visible:outline-solid peer-focus-visible:outline-2 peer-focus-visible:outline-ring peer-focus-visible:outline-offset-2 peer-disabled:opacity-50 peer-disabled:cursor-not-allowed after:absolute after:content-[''] after:top-0.5 after:left-0.5 after:bg-white after:shadow-sm after:rounded-full after:h-4 after:w-4 after:transition-transform peer-checked:after:translate-x-4"></span></span>
          </label>
        </form>
    </div>
  </div>
</div>

<div class="rounded-lg border border-border bg-card text-card-foreground">
  <div class="flex flex-col space-y-1.5 p-5 border-b border-border">
    <h2 class="text-[13px] font-semibold leading-none tracking-tight">Invitations</h2>
    <p class="text-[12px] text-muted-foreground">Invite users to join this instance by email.</p>
  </div>
  <div class="p-5">
    <form id="invite-form" class="flex gap-3 mb-6">
      <label for="invite-email" class="sr-only">Invitee email</label>
      <input id="invite-email" type="email" name="email" placeholder="user@example.com" required class="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 flex-1" />
      <button type="submit" class="inline-flex items-center justify-center gap-1.5 rounded-md font-medium transition-colors disabled:opacity-50 disabled:pointer-events-none h-9 px-4 text-sm bg-primary text-primary-foreground hover:bg-primary/90">Send invite</button>
    </form>
    <div id="admin-invitations-list" class="space-y-2">
      <div class="rounded-md border border-border p-4 flex justify-between items-start">
        <div class="space-y-1">
          <p class="text-sm font-medium text-foreground">hana@example.test</p>
          <p class="text-xs text-muted-foreground font-mono break-all">/invite/k3Vt9mQx7LpB2wRd</p>
          <div class="flex gap-3 text-xs text-muted-foreground">
            <span>Expires: <time datetime="2026-11-13T00:00:00Z">2026-11-13</time></span>
            <span class="text-warning">Pending</span>
          </div>
        </div>
        <button type="button" data-delete-invite data-email="hana@example.test" class="inline-flex items-center justify-center gap-1.5 rounded-md font-medium transition-colors disabled:opacity-50 disabled:pointer-events-none bg-destructive text-destructive-foreground hover:bg-destructive/90 h-8 px-3 text-[13px] ml-4 shrink-0">Delete</button>
      </div>
      <div class="rounded-md border border-border p-4 flex justify-between items-start">
        <div class="space-y-1">
          <p class="text-sm font-medium text-foreground">contractor@example.test</p>
          <p class="text-xs text-muted-foreground font-mono break-all">/invite/Zr8nYc4HgF1sJe6u</p>
          <div class="flex gap-3 text-xs text-muted-foreground">
            <span>Expires: <time datetime="2026-11-02T00:00:00Z">2026-11-02</time></span>
            <span class="text-success">Accepted</span>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

<div class="rounded-lg border border-border bg-card text-card-foreground">
  <div class="flex flex-col space-y-1.5 p-5 border-b border-border">
    <h2 class="text-[13px] font-semibold leading-none tracking-tight">Email verification</h2>
    <p class="text-[12px] text-muted-foreground">Mark a user's email address verified by hand, for instances that can't send the verification link. A verified address lets the Google account with that address sign in to the user's account, so only vouch for addresses you know are theirs.</p>
  </div>
  <div class="p-5">
    <form id="verify-form" class="flex flex-col sm:flex-row gap-3">
      <label for="verify-username" class="sr-only">Username</label>
      <input id="verify-username" type="text" name="username" placeholder="username" required autocomplete="off" class="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 flex-1" />
      <label for="verify-email" class="sr-only">Email</label>
      <input id="verify-email" type="email" name="email" placeholder="user@example.com" required autocomplete="off" class="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 flex-1" />
      <button type="submit" class="inline-flex items-center justify-center gap-1.5 rounded-md font-medium transition-colors disabled:opacity-50 disabled:pointer-events-none h-9 px-4 text-sm bg-primary text-primary-foreground hover:bg-primary/90">Mark verified</button>
    </form>
  </div>
</div>
</div>
</main>

<dialog id="cz-confirm-dialog" aria-labelledby="cz-confirm-title" class="rounded-lg border border-border bg-popover text-popover-foreground p-0 w-[420px] max-w-[calc(100vw-2rem)] mt-[28vh] mb-auto backdrop:bg-black/60 backdrop:backdrop-blur-xs">
  <div class="p-5">
    <h2 id="cz-confirm-title" class="text-base font-semibold tracking-tight mb-1"></h2>
    <p id="cz-confirm-msg" class="text-[13px] text-muted-foreground leading-relaxed mb-5"></p>
    <div class="flex justify-end gap-2">
      <button type="button" id="cz-confirm-cancel" class="inline-flex items-center justify-center rounded-md text-sm font-medium border border-input bg-transparent hover:bg-accent hover:text-accent-foreground h-9 px-4">Cancel</button>
      <button type="button" id="cz-confirm-ok" class="inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-4 bg-primary text-primary-foreground hover:bg-primary/90">Confirm</button>
    </div>
  </div>
</dialog>
<div id="cz-footer"></div>
<script>
  var dlg = document.getElementById('cz-confirm-dialog');
  var okBtn = document.getElementById('cz-confirm-ok');
  var OK_BASE = 'inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-4 ';
  var pending = null;
  function confirmAction(o, done) {
    document.getElementById('cz-confirm-title').textContent = o.title;
    document.getElementById('cz-confirm-msg').textContent = o.msg;
    okBtn.textContent = o.label;
    okBtn.className = OK_BASE + (o.danger ? 'bg-destructive text-destructive-foreground hover:bg-destructive/90' : 'bg-primary text-primary-foreground hover:bg-primary/90');
    pending = done;
    dlg.returnValue = '';
    dlg.showModal();
  }
  okBtn.addEventListener('click', function () { dlg.close('confirm'); });
  document.getElementById('cz-confirm-cancel').addEventListener('click', function () { dlg.close('cancel'); });
  dlg.addEventListener('click', function (e) { if (e.target === dlg) dlg.close('cancel'); });
  dlg.addEventListener('close', function () {
    var f = pending; pending = null;
    if (f && dlg.returnValue === 'confirm') f();
  });

  document.querySelectorAll('[data-setting]').forEach(function (sw) {
    sw.addEventListener('change', function () {
      var on = sw.checked;
      sw.checked = !on;
      confirmAction({
        title: (on ? 'Turn on ' : 'Turn off ') + sw.dataset.setting + '?',
        msg: 'This changes the setting for the whole instance.',
        label: on ? 'Turn on' : 'Turn off',
        danger: !on
      }, function () { sw.checked = on; czToast('Setting updated'); });
    });
  });

  var list = document.getElementById('admin-invitations-list');
  list.addEventListener('click', function (e) {
    var b = e.target.closest('[data-delete-invite]');
    if (!b) return;
    confirmAction({
      title: 'Delete this invitation?',
      msg: 'The invite link for ' + b.dataset.email + ' will stop working immediately.',
      label: 'Delete',
      danger: true
    }, function () {
      b.parentElement.remove();
      if (!list.children.length) list.innerHTML = '<p class="text-sm text-muted-foreground">No invitations yet.</p>';
      czToast('Invitation deleted');
    });
  });

  document.getElementById('invite-form').addEventListener('submit', function (e) {
    e.preventDefault();
    var input = document.getElementById('invite-email');
    var email = input.value.trim();
    if (!email) return;
    var empty = list.querySelector(':scope > p');
    if (empty) empty.remove();
    var row = document.createElement('div');
    row.className = 'rounded-md border border-border p-4 flex justify-between items-start';
    var info = document.createElement('div');
    info.className = 'space-y-1';
    var name = document.createElement('p');
    name.className = 'text-sm font-medium text-foreground';
    name.textContent = email;
    var link = document.createElement('p');
    link.className = 'text-xs text-muted-foreground font-mono break-all';
    link.textContent = '/invite/Qw5eT2yUiO9pAs3d';
    var meta = document.createElement('div');
    meta.className = 'flex gap-3 text-xs text-muted-foreground';
    meta.innerHTML = '<span>Expires: <time datetime="2026-11-13T00:00:00Z">2026-11-13</time></span> <span class="text-warning">Pending</span>';
    info.append(name, link, meta);
    var del = document.createElement('button');
    del.type = 'button';
    del.setAttribute('data-delete-invite', '');
    del.dataset.email = email;
    del.className = 'inline-flex items-center justify-center gap-1.5 rounded-md font-medium transition-colors disabled:opacity-50 disabled:pointer-events-none bg-destructive text-destructive-foreground hover:bg-destructive/90 h-8 px-3 text-[13px] ml-4 shrink-0';
    del.textContent = 'Delete';
    row.append(info, del);
    list.prepend(row);
    input.value = '';
    czToast('Invitation sent');
  });

  document.getElementById('verify-form').addEventListener('submit', function (e) {
    e.preventDefault();
    this.reset();
    czToast('Email marked verified');
  });
</script>
<script src="shell.js"></script>
</body>
</html>