Mega push vol 7 mvp lesgoooo

This commit is contained in:
AlacrisDevs
2026-02-07 21:47:47 +02:00
parent dcee479839
commit d22847f555
75 changed files with 7685 additions and 892 deletions

View File

@@ -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);

View File

@@ -43,6 +43,7 @@
setTimeout(() => (emailCopied = false), 2000);
}
// svelte-ignore state_referenced_locally
let showConnectModal = $state(initialShowConnect);
let isLoading = $state(false);
let calendarUrlInput = $state("");

View File

@@ -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}

View File

@@ -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>