Add calendar integrations and collaboration updates
This commit is contained in:
@@ -69,6 +69,33 @@
|
||||
{ key: 'workflow', label: t('workspaceSettings.tabs.workflow'), icon: mdiTuneVariant },
|
||||
{ key: 'connectors', label: t('workspaceSettings.tabs.connectors'), icon: mdiFolderGoogleDrive },
|
||||
]);
|
||||
const activeTabDetail = computed(() => {
|
||||
if (activeTab.value === 'members') {
|
||||
return {
|
||||
title: t('workspaceSettings.tabs.members'),
|
||||
description: t('workspaceSettings.inviteDescription'),
|
||||
};
|
||||
}
|
||||
|
||||
if (activeTab.value === 'workflow') {
|
||||
return {
|
||||
title: t('workspaceSettings.tabs.workflow'),
|
||||
description: t('workspaceSettings.approvals.flowDescription'),
|
||||
};
|
||||
}
|
||||
|
||||
if (activeTab.value === 'connectors') {
|
||||
return {
|
||||
title: t('workspaceSettings.tabs.connectors'),
|
||||
description: t('workspaceSettings.connectors.description'),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
title: t('workspaceSettings.tabs.general'),
|
||||
description: t('workspaceSettings.general.detailsDescription'),
|
||||
};
|
||||
});
|
||||
const approvalModeOptions = computed(() => [
|
||||
{ value: 'None', label: t('workspaceSettings.approvals.modes.none'), description: t('workspaceSettings.approvals.modeHelp.none') },
|
||||
{ value: 'Optional', label: t('workspaceSettings.approvals.modes.optional'), description: t('workspaceSettings.approvals.modeHelp.optional') },
|
||||
@@ -380,8 +407,16 @@
|
||||
<h1>{{ workspaceStore.activeWorkspace?.name || t('workspaceSettings.noWorkspaceSelected') }}</h1>
|
||||
<p>{{ t('workspaceSettings.description') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-strip">
|
||||
<div
|
||||
v-if="workspaceStore.activeWorkspace"
|
||||
class="workspace-settings-page"
|
||||
>
|
||||
<nav
|
||||
class="tab-strip"
|
||||
aria-label="Workspace settings sections"
|
||||
>
|
||||
<button
|
||||
v-for="tab in settingsTabs"
|
||||
:key="tab.key"
|
||||
@@ -393,38 +428,42 @@
|
||||
<v-icon :icon="tab.icon" />
|
||||
<span>{{ tab.label }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div
|
||||
v-if="activeTab === 'general'"
|
||||
class="workspace-settings-grid workspace-settings-grid-single"
|
||||
>
|
||||
<article class="settings-card">
|
||||
<div class="section-copy">
|
||||
<span class="section-kicker">{{ t('workspaceSettings.general.detailsTitle') }}</span>
|
||||
<p>{{ t('workspaceSettings.general.detailsDescription') }}</p>
|
||||
<div class="tab-content">
|
||||
<div class="tab-heading">
|
||||
<h2>{{ activeTabDetail.title }}</h2>
|
||||
<p>{{ activeTabDetail.description }}</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="settingsError"
|
||||
class="page-message error"
|
||||
v-if="activeTab === 'general'"
|
||||
class="workspace-settings-grid workspace-settings-grid-single"
|
||||
>
|
||||
{{ settingsError }}
|
||||
</div>
|
||||
<article class="settings-card">
|
||||
<div class="section-copy">
|
||||
<span class="section-kicker">{{ t('workspaceSettings.general.detailsTitle') }}</span>
|
||||
<p>{{ t('workspaceSettings.general.detailsDescription') }}</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="settingsStatus"
|
||||
class="page-message success"
|
||||
>
|
||||
{{ settingsStatus }}
|
||||
</div>
|
||||
<div
|
||||
v-if="settingsError"
|
||||
class="page-message error"
|
||||
>
|
||||
{{ settingsError }}
|
||||
</div>
|
||||
|
||||
<form
|
||||
v-if="workspaceStore.activeWorkspace"
|
||||
class="form-stack"
|
||||
@submit.prevent="submitWorkspaceSettings"
|
||||
>
|
||||
<div
|
||||
v-if="settingsStatus"
|
||||
class="page-message success"
|
||||
>
|
||||
{{ settingsStatus }}
|
||||
</div>
|
||||
|
||||
<form
|
||||
class="form-stack"
|
||||
@submit.prevent="submitWorkspaceSettings"
|
||||
>
|
||||
<div class="logo-picker-card">
|
||||
<AppAvatar
|
||||
:name="settingsForm.name || workspaceStore.activeWorkspace.name"
|
||||
@@ -481,22 +520,16 @@
|
||||
>
|
||||
{{ workspaceStore.isUpdating ? t('common.saving') : t('workspaceSettings.general.saveAction') }}
|
||||
</button>
|
||||
</form>
|
||||
</form>
|
||||
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="empty-state"
|
||||
v-else-if="activeTab === 'members'"
|
||||
class="workspace-settings-grid workspace-settings-grid-single"
|
||||
>
|
||||
{{ t('workspaceSettings.noWorkspaceSelected') }}
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else-if="activeTab === 'members'"
|
||||
class="workspace-settings-grid workspace-settings-grid-single"
|
||||
>
|
||||
<article class="settings-card">
|
||||
<article class="settings-card">
|
||||
<div class="section-copy">
|
||||
<span class="section-kicker">{{ t('workspaceSettings.members.inviteTitle') }}</span>
|
||||
<p>{{ t('workspaceSettings.inviteDescription') }}</p>
|
||||
@@ -530,9 +563,9 @@
|
||||
{{ workspaceStore.isInviting ? t('common.creating') : t('workspaceSettings.sendInvite') }}
|
||||
</button>
|
||||
</form>
|
||||
</article>
|
||||
</article>
|
||||
|
||||
<article class="settings-card">
|
||||
<article class="settings-card">
|
||||
<div class="section-copy">
|
||||
<span class="section-kicker">{{ t('workspaceSettings.members.pendingTitle') }}</span>
|
||||
<p>{{ t('workspaceSettings.members.pendingDescription') }}</p>
|
||||
@@ -568,9 +601,9 @@
|
||||
>
|
||||
{{ t('workspaceSettings.inviteEmpty') }}
|
||||
</div>
|
||||
</article>
|
||||
</article>
|
||||
|
||||
<article class="settings-card">
|
||||
<article class="settings-card">
|
||||
<div class="section-copy">
|
||||
<span class="section-kicker">{{ t('workspaceSettings.members.activeTitle') }}</span>
|
||||
<p>{{ t('workspaceSettings.members.activeDescription') }}</p>
|
||||
@@ -606,14 +639,14 @@
|
||||
>
|
||||
{{ t('workspaceSettings.members.activeEmpty') }}
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else-if="activeTab === 'workflow'"
|
||||
class="workflow-grid"
|
||||
>
|
||||
<article class="settings-card">
|
||||
<div
|
||||
v-else-if="activeTab === 'workflow'"
|
||||
class="workflow-grid"
|
||||
>
|
||||
<article class="settings-card">
|
||||
<div class="section-copy">
|
||||
<span class="section-kicker">{{ t('workspaceSettings.approvals.flowTitle') }}</span>
|
||||
<p>{{ t('workspaceSettings.approvals.flowDescription') }}</p>
|
||||
@@ -709,9 +742,9 @@
|
||||
{{ workspaceStore.isUpdating ? t('common.saving') : t('workspaceSettings.approvals.saveAction') }}
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
</article>
|
||||
|
||||
<article class="settings-card">
|
||||
<article class="settings-card">
|
||||
<div class="section-copy">
|
||||
<span class="section-kicker">{{ t('workspaceSettings.approvals.previewTitle') }}</span>
|
||||
<p>{{ t('workspaceSettings.approvals.previewDescription') }}</p>
|
||||
@@ -732,14 +765,14 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="workspace-settings-grid"
|
||||
>
|
||||
<article class="settings-card">
|
||||
<div
|
||||
v-else
|
||||
class="workspace-settings-grid"
|
||||
>
|
||||
<article class="settings-card">
|
||||
<div class="section-copy">
|
||||
<span class="section-kicker">{{ t('workspaceSettings.connectors.title') }}</span>
|
||||
<p>{{ t('workspaceSettings.connectors.description') }}</p>
|
||||
@@ -771,7 +804,16 @@
|
||||
<v-icon :icon="mdiImageMultipleOutline" />
|
||||
<span>{{ t('workspaceSettings.connectors.openMediaLibrary') }}</span>
|
||||
</router-link>
|
||||
</article>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="empty-state"
|
||||
>
|
||||
{{ t('workspaceSettings.noWorkspaceSelected') }}
|
||||
</div>
|
||||
|
||||
<ImageCropperDialog
|
||||
@@ -792,11 +834,12 @@
|
||||
}
|
||||
|
||||
.workspace-settings-hero {
|
||||
@apply flex flex-col gap-5 rounded-[1.75rem] border p-5 md:p-6;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(15, 118, 110, 0.16), transparent 38%),
|
||||
linear-gradient(135deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.94));
|
||||
border-color: rgba(23, 32, 51, 0.08);
|
||||
@apply flex flex-col;
|
||||
}
|
||||
|
||||
.workspace-settings-page,
|
||||
.tab-content {
|
||||
@apply flex flex-col gap-4;
|
||||
}
|
||||
|
||||
.workspace-settings-grid {
|
||||
@@ -812,10 +855,9 @@
|
||||
}
|
||||
|
||||
.settings-card {
|
||||
@apply flex flex-col gap-5 rounded-[1.75rem] border p-5;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
@apply flex flex-col gap-5 rounded-[0.75rem] border p-5;
|
||||
background: rgba(255, 255, 255, 0.94);
|
||||
border-color: rgba(23, 32, 51, 0.08);
|
||||
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.06);
|
||||
}
|
||||
|
||||
.section-copy {
|
||||
@@ -823,26 +865,45 @@
|
||||
}
|
||||
|
||||
.tab-strip {
|
||||
@apply flex flex-wrap gap-3;
|
||||
@apply flex flex-wrap gap-2 border-b pb-3;
|
||||
border-color: rgba(23, 32, 51, 0.1);
|
||||
}
|
||||
|
||||
.tab-button {
|
||||
@apply inline-flex items-center gap-3 rounded-full px-4 py-3 text-sm font-semibold transition;
|
||||
background: rgba(23, 32, 51, 0.06);
|
||||
@apply inline-flex h-10 items-center gap-2 rounded-[0.75rem] px-3 text-sm font-semibold transition-colors;
|
||||
color: #526178;
|
||||
}
|
||||
|
||||
.tab-button:hover {
|
||||
background: rgba(23, 32, 51, 0.06);
|
||||
color: #172033;
|
||||
}
|
||||
|
||||
.tab-button-active {
|
||||
background: #172033;
|
||||
color: #fffaf2;
|
||||
}
|
||||
|
||||
.tab-button :deep(.v-icon) {
|
||||
@apply text-lg;
|
||||
}
|
||||
|
||||
.tab-heading {
|
||||
@apply flex flex-col gap-1;
|
||||
}
|
||||
|
||||
.tab-heading h2 {
|
||||
@apply text-2xl font-black;
|
||||
color: #172033;
|
||||
}
|
||||
|
||||
.section-kicker {
|
||||
@apply text-xs font-bold uppercase tracking-[0.2em];
|
||||
color: #0f766e;
|
||||
color: #c2410c;
|
||||
}
|
||||
|
||||
.section-copy h1,
|
||||
.tab-heading h2,
|
||||
.invite-row strong,
|
||||
.connector-copy strong,
|
||||
.connector-status,
|
||||
@@ -852,10 +913,11 @@
|
||||
}
|
||||
|
||||
.section-copy h1 {
|
||||
@apply text-3xl font-black;
|
||||
@apply text-3xl font-black md:text-4xl;
|
||||
}
|
||||
|
||||
.section-copy p,
|
||||
.tab-heading p,
|
||||
.invite-row span,
|
||||
.invite-row small,
|
||||
.empty-state,
|
||||
@@ -868,8 +930,8 @@
|
||||
}
|
||||
|
||||
.logo-picker-card {
|
||||
@apply flex flex-col gap-4 rounded-[1rem] border p-4 sm:flex-row sm:items-center;
|
||||
background: #fffaf2;
|
||||
@apply flex flex-col gap-4 rounded-[0.75rem] border p-4 sm:flex-row sm:items-center;
|
||||
background: rgba(23, 32, 51, 0.04);
|
||||
border-color: rgba(23, 32, 51, 0.08);
|
||||
}
|
||||
|
||||
@@ -910,25 +972,40 @@
|
||||
|
||||
.field input,
|
||||
.field select {
|
||||
@apply rounded-[1rem] border px-4 py-3 text-sm;
|
||||
background: #fffdf8;
|
||||
@apply h-11 rounded-[0.5rem] border px-3 text-sm outline-none transition-colors;
|
||||
background: #ffffff;
|
||||
border-color: rgba(23, 32, 51, 0.1);
|
||||
color: #172033;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.field input:focus,
|
||||
.field select:focus {
|
||||
border-color: #0f766e;
|
||||
box-shadow: 0 0 0 3px rgba(15, 118, 110, 0.12);
|
||||
}
|
||||
|
||||
.primary-button {
|
||||
@apply inline-flex items-center justify-center rounded-full px-5 py-3 text-sm font-semibold;
|
||||
@apply inline-flex h-11 items-center justify-center rounded-[0.5rem] px-4 text-sm font-bold transition-colors;
|
||||
background: #172033;
|
||||
color: #fffaf2;
|
||||
}
|
||||
|
||||
.secondary-button {
|
||||
@apply inline-flex items-center justify-center rounded-full px-4 py-2 text-sm font-semibold;
|
||||
background: rgba(23, 32, 51, 0.08);
|
||||
@apply inline-flex h-11 items-center justify-center rounded-[0.5rem] border px-4 text-sm font-bold transition-colors;
|
||||
background: #ffffff;
|
||||
border-color: rgba(23, 32, 51, 0.14);
|
||||
color: #172033;
|
||||
}
|
||||
|
||||
.primary-button:hover:not(:disabled) {
|
||||
background: #0f766e;
|
||||
}
|
||||
|
||||
.secondary-button:hover:not(:disabled) {
|
||||
border-color: #0f766e;
|
||||
color: #0f766e;
|
||||
}
|
||||
|
||||
.primary-button:disabled,
|
||||
.secondary-button:disabled {
|
||||
cursor: not-allowed;
|
||||
@@ -948,8 +1025,8 @@
|
||||
.workflow-rule,
|
||||
.workflow-toggle,
|
||||
.workflow-step {
|
||||
@apply rounded-[1rem] border px-4 py-4;
|
||||
background: #fffaf2;
|
||||
@apply rounded-[0.75rem] border px-4 py-4;
|
||||
background: rgba(23, 32, 51, 0.04);
|
||||
border-color: rgba(23, 32, 51, 0.08);
|
||||
}
|
||||
|
||||
@@ -984,7 +1061,7 @@
|
||||
|
||||
.connector-icon,
|
||||
.workflow-step-icon {
|
||||
@apply inline-flex h-11 w-11 flex-shrink-0 items-center justify-center rounded-2xl;
|
||||
@apply inline-flex h-11 w-11 flex-shrink-0 items-center justify-center rounded-[0.75rem];
|
||||
background: rgba(15, 118, 110, 0.1);
|
||||
color: #0f766e;
|
||||
}
|
||||
@@ -995,12 +1072,12 @@
|
||||
}
|
||||
|
||||
.connector-link {
|
||||
@apply inline-flex w-fit items-center gap-3 rounded-full px-5 py-3 text-sm font-semibold no-underline transition;
|
||||
@apply inline-flex h-11 w-fit items-center gap-3 rounded-[0.5rem] px-4 text-sm font-bold no-underline transition;
|
||||
background: #172033;
|
||||
color: #fffaf2;
|
||||
}
|
||||
|
||||
.connector-link:hover {
|
||||
background: #0f172a;
|
||||
background: #0f766e;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user