Mega push vol 7 mvp lesgoooo
This commit is contained in:
@@ -20,8 +20,11 @@
|
||||
|
||||
let { supabase, org, isOwner, onLeave, onDelete }: Props = $props();
|
||||
|
||||
// svelte-ignore state_referenced_locally
|
||||
let orgName = $state(org.name);
|
||||
// svelte-ignore state_referenced_locally
|
||||
let orgSlug = $state(org.slug);
|
||||
// svelte-ignore state_referenced_locally
|
||||
let avatarUrl = $state(org.avatar_url ?? null);
|
||||
let isSaving = $state(false);
|
||||
let isUploading = $state(false);
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
setTimeout(() => (emailCopied = false), 2000);
|
||||
}
|
||||
|
||||
// svelte-ignore state_referenced_locally
|
||||
let showConnectModal = $state(initialShowConnect);
|
||||
let isLoading = $state(false);
|
||||
let calendarUrlInput = $state("");
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
|
||||
<!-- Pending Invites -->
|
||||
{#if invites.length > 0}
|
||||
<div class="bg-dark/30 border border-light/5 rounded-xl p-4">
|
||||
<div class="bg-dark/30 border border-light/5 rounded-2xl p-4">
|
||||
<h3 class="text-body-sm font-heading text-light/60 mb-3">
|
||||
{m.settings_members_pending()}
|
||||
</h3>
|
||||
@@ -229,7 +229,7 @@
|
||||
{/if}
|
||||
|
||||
<!-- Members List -->
|
||||
<div class="bg-dark/30 border border-light/5 rounded-xl overflow-hidden">
|
||||
<div class="bg-dark/30 border border-light/5 rounded-2xl overflow-hidden">
|
||||
<div class="divide-y divide-light/5">
|
||||
{#each members as member}
|
||||
{@const rawProfile = member.profiles}
|
||||
@@ -288,42 +288,40 @@
|
||||
onClose={() => (showInviteModal = false)}
|
||||
title="Invite Member"
|
||||
>
|
||||
<div class="space-y-4">
|
||||
<Input
|
||||
type="email"
|
||||
label="Email address"
|
||||
bind:value={inviteEmail}
|
||||
placeholder="colleague@example.com"
|
||||
/>
|
||||
<Select
|
||||
label="Role"
|
||||
bind:value={inviteRole}
|
||||
placeholder=""
|
||||
options={[
|
||||
{ value: "viewer", label: "Viewer - Can view content" },
|
||||
{
|
||||
value: "commenter",
|
||||
label: "Commenter - Can view and comment",
|
||||
},
|
||||
{
|
||||
value: "editor",
|
||||
label: "Editor - Can create and edit content",
|
||||
},
|
||||
{
|
||||
value: "admin",
|
||||
label: "Admin - Can manage members and settings",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<div class="flex justify-end gap-2 pt-2">
|
||||
<Button variant="tertiary" onclick={() => (showInviteModal = false)}
|
||||
>Cancel</Button
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<label for="invite-email" class="text-body-sm text-light/60 font-body">Email address</label>
|
||||
<input
|
||||
id="invite-email"
|
||||
type="email"
|
||||
bind:value={inviteEmail}
|
||||
placeholder="colleague@example.com"
|
||||
class="bg-dark border border-light/10 rounded-xl px-3 py-2 text-body-sm text-white placeholder:text-light/30 focus:outline-none focus:border-primary"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<label for="invite-role" class="text-body-sm text-light/60 font-body">Role</label>
|
||||
<select
|
||||
id="invite-role"
|
||||
bind:value={inviteRole}
|
||||
class="bg-dark border border-light/10 rounded-xl px-3 py-2 text-body-sm text-white focus:outline-none focus:border-primary"
|
||||
>
|
||||
<Button
|
||||
<option value="viewer">Viewer - Can view content</option>
|
||||
<option value="commenter">Commenter - Can view and comment</option>
|
||||
<option value="editor">Editor - Can create and edit content</option>
|
||||
<option value="admin">Admin - Can manage members and settings</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex items-center justify-end gap-3 pt-2 border-t border-light/5">
|
||||
<button type="button" class="px-4 py-2 text-body-sm text-light/60 hover:text-white transition-colors" onclick={() => (showInviteModal = false)}>Cancel</button>
|
||||
<button
|
||||
type="button"
|
||||
disabled={!inviteEmail.trim() || isSendingInvite}
|
||||
class="px-4 py-2 bg-primary text-background rounded-xl font-body text-body-sm hover:bg-primary-hover transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
onclick={sendInvite}
|
||||
loading={isSendingInvite}
|
||||
disabled={!inviteEmail.trim()}>Send Invite</Button
|
||||
>
|
||||
{isSendingInvite ? "..." : "Send Invite"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
@@ -337,46 +335,45 @@
|
||||
{#if selectedMember}
|
||||
{@const rawP = selectedMember.profiles}
|
||||
{@const memberProfile = Array.isArray(rawP) ? rawP[0] : rawP}
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center gap-3 p-3 bg-light/5 rounded-lg">
|
||||
<div
|
||||
class="w-10 h-10 rounded-full bg-primary/20 flex items-center justify-center text-primary font-medium"
|
||||
>
|
||||
{(memberProfile?.full_name ||
|
||||
memberProfile?.email ||
|
||||
"?")[0].toUpperCase()}
|
||||
</div>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex items-center gap-3 p-3 bg-dark/50 rounded-xl">
|
||||
<Avatar
|
||||
name={memberProfile?.full_name || memberProfile?.email || "?"}
|
||||
src={memberProfile?.avatar_url}
|
||||
size="sm"
|
||||
/>
|
||||
<div>
|
||||
<p class="text-light font-medium">
|
||||
<p class="text-body-sm text-white">
|
||||
{memberProfile?.full_name || "No name"}
|
||||
</p>
|
||||
<p class="text-sm text-light/50">
|
||||
<p class="text-[11px] text-light/40">
|
||||
{memberProfile?.email || "No email"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Select
|
||||
label="Role"
|
||||
bind:value={selectedMemberRole}
|
||||
placeholder=""
|
||||
options={[
|
||||
{ value: "viewer", label: "Viewer" },
|
||||
{ value: "commenter", label: "Commenter" },
|
||||
{ value: "editor", label: "Editor" },
|
||||
{ value: "admin", label: "Admin" },
|
||||
]}
|
||||
/>
|
||||
<div class="flex items-center justify-between pt-2">
|
||||
<Button variant="danger" onclick={removeMember}
|
||||
>Remove from Org</Button
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<label for="member-role" class="text-body-sm text-light/60 font-body">Role</label>
|
||||
<select
|
||||
id="member-role"
|
||||
bind:value={selectedMemberRole}
|
||||
class="bg-dark border border-light/10 rounded-xl px-3 py-2 text-body-sm text-white focus:outline-none focus:border-primary"
|
||||
>
|
||||
<div class="flex gap-2">
|
||||
<Button
|
||||
variant="tertiary"
|
||||
onclick={() => (showMemberModal = false)}>Cancel</Button
|
||||
>
|
||||
<Button onclick={updateMemberRole}>Save</Button>
|
||||
</div>
|
||||
<option value="viewer">Viewer</option>
|
||||
<option value="commenter">Commenter</option>
|
||||
<option value="editor">Editor</option>
|
||||
<option value="admin">Admin</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="button" class="text-[11px] text-error hover:underline self-start" onclick={removeMember}>
|
||||
Remove from organization
|
||||
</button>
|
||||
<div class="flex items-center justify-end gap-3 pt-2 border-t border-light/5">
|
||||
<button type="button" class="px-4 py-2 text-body-sm text-light/60 hover:text-white transition-colors" onclick={() => (showMemberModal = false)}>Cancel</button>
|
||||
<button
|
||||
type="button"
|
||||
class="px-4 py-2 bg-primary text-background rounded-xl font-body text-body-sm hover:bg-primary-hover transition-colors"
|
||||
onclick={updateMemberRole}
|
||||
>Save</button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -203,7 +203,7 @@
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each roles as role}
|
||||
<div class="bg-dark/30 border border-light/5 rounded-xl px-4 py-3 hover:border-light/10 transition-colors">
|
||||
<div class="bg-dark/30 border border-light/5 rounded-2xl px-4 py-3 hover:border-light/10 transition-colors">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
@@ -264,25 +264,27 @@
|
||||
onClose={() => (showRoleModal = false)}
|
||||
title={editingRole ? "Edit Role" : "Create Role"}
|
||||
>
|
||||
<div class="space-y-4">
|
||||
<Input
|
||||
label="Name"
|
||||
bind:value={newRoleName}
|
||||
placeholder="e.g., Moderator"
|
||||
disabled={editingRole?.is_system}
|
||||
/>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-light mb-2"
|
||||
>Color</label
|
||||
>
|
||||
<div class="flex gap-2">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<label for="role-name" class="text-body-sm text-light/60 font-body">Name</label>
|
||||
<input
|
||||
id="role-name"
|
||||
type="text"
|
||||
bind:value={newRoleName}
|
||||
placeholder="e.g., Moderator"
|
||||
disabled={editingRole?.is_system}
|
||||
class="bg-dark border border-light/10 rounded-xl px-3 py-2 text-body-sm text-white placeholder:text-light/30 focus:outline-none focus:border-primary disabled:opacity-50"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<span class="text-body-sm text-light/60 font-body">Color</span>
|
||||
<div class="flex items-center gap-2">
|
||||
{#each roleColors as color}
|
||||
<button
|
||||
type="button"
|
||||
class="w-8 h-8 rounded-full transition-transform {newRoleColor ===
|
||||
color.value
|
||||
? 'ring-2 ring-white scale-110'
|
||||
: ''}"
|
||||
class="w-6 h-6 rounded-full border-2 transition-all {newRoleColor === color.value
|
||||
? 'border-white scale-110'
|
||||
: 'border-transparent hover:border-light/30'}"
|
||||
style="background-color: {color.value}"
|
||||
onclick={() => (newRoleColor = color.value)}
|
||||
title={color.label}
|
||||
@@ -290,30 +292,26 @@
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-light mb-2"
|
||||
>Permissions</label
|
||||
>
|
||||
<div class="space-y-3 max-h-64 overflow-y-auto">
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<span class="text-body-sm text-light/60 font-body">Permissions</span>
|
||||
<div class="flex flex-col gap-2 max-h-64 overflow-y-auto">
|
||||
{#each permissionGroups as group}
|
||||
<div class="p-3 bg-light/5 rounded-lg">
|
||||
<p class="text-sm font-medium text-light mb-2">
|
||||
<div class="p-3 bg-dark/50 rounded-xl">
|
||||
<p class="text-body-sm font-body text-white mb-2">
|
||||
{group.name}
|
||||
</p>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
{#each group.permissions as perm}
|
||||
<label
|
||||
class="flex items-center gap-2 text-sm text-light/70 cursor-pointer"
|
||||
class="flex items-center gap-2 text-[12px] text-light/50 cursor-pointer hover:text-white transition-colors"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={newRolePermissions.includes(
|
||||
perm,
|
||||
)}
|
||||
checked={newRolePermissions.includes(perm)}
|
||||
onchange={() => togglePermission(perm)}
|
||||
class="rounded"
|
||||
class="rounded accent-primary"
|
||||
/>
|
||||
{perm.split(".")[1]}
|
||||
<span class="capitalize">{perm.split(".")[1]}</span>
|
||||
</label>
|
||||
{/each}
|
||||
</div>
|
||||
@@ -321,16 +319,16 @@
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end gap-2 pt-2">
|
||||
<Button variant="tertiary" onclick={() => (showRoleModal = false)}
|
||||
>Cancel</Button
|
||||
>
|
||||
<Button
|
||||
<div class="flex items-center justify-end gap-3 pt-2 border-t border-light/5">
|
||||
<button type="button" class="px-4 py-2 text-body-sm text-light/60 hover:text-white transition-colors" onclick={() => (showRoleModal = false)}>{m.btn_cancel()}</button>
|
||||
<button
|
||||
type="button"
|
||||
disabled={!newRoleName.trim() || isSavingRole}
|
||||
class="px-4 py-2 bg-primary text-background rounded-xl font-body text-body-sm hover:bg-primary-hover transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
onclick={saveRole}
|
||||
loading={isSavingRole}
|
||||
disabled={!newRoleName.trim()}
|
||||
>{editingRole ? "Save" : "Create"}</Button
|
||||
>
|
||||
{isSavingRole ? "..." : editingRole ? m.btn_save() : m.btn_create()}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
Reference in New Issue
Block a user