Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 24 additions & 12 deletions assets/scss/_onboarding.scss
Original file line number Diff line number Diff line change
Expand Up @@ -96,18 +96,25 @@
}

.step-icon {
width: 60px;
height: 60px;
background: $primary-light;
border-radius: 50%;
width: 88px;
height: 88px;
border-radius: 26px;
background:
radial-gradient(120% 120% at 30% 18%, $primary-light, transparent 72%),
linear-gradient(
135deg,
rgba(var(--color-primary-rgb), 0.16),
rgba(var(--color-primary-rgb), 0.04)
);
box-shadow: $elevation-1;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto;

svg {
width: 28px;
height: 28px;
width: 46px;
height: 46px;
color: $primary;
}
}
Expand Down Expand Up @@ -178,10 +185,12 @@
align-items: center;
justify-content: center;
gap: 0.5rem;
box-shadow: 0 6px 16px -6px rgba(var(--color-primary-rgb), 0.55);

&:hover:not(:disabled) {
background: $primary-hover;
transform: translateY(-1px);
box-shadow: 0 10px 22px -8px rgba(var(--color-primary-rgb), 0.6);
}

&:disabled {
Expand Down Expand Up @@ -218,18 +227,21 @@
}

.completion-icon {
width: 80px;
height: 80px;
background: linear-gradient(135deg, $success 0%, $primary-dark 100%);
border-radius: 50%;
width: 96px;
height: 96px;
background:
radial-gradient(120% 120% at 30% 18%, rgba(255, 255, 255, 0.28), transparent 60%),
linear-gradient(135deg, $success 0%, $primary-dark 100%);
border-radius: 30px;
box-shadow: $elevation-2;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 1.5rem auto;

svg {
width: 40px;
height: 40px;
width: 48px;
height: 48px;
color: $text-inverse;
}
}
Expand Down
143 changes: 56 additions & 87 deletions components/EmptyState.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<template>
<div class="empty-state">
<img class="empty-icon" src="/box.svg" :alt="t('Empty Icon')" />
<div class="empty-art">
<component :is="resolvedIcon" class="empty-illustration" />
</div>
<h2 class="empty-title">
{{
t("You don't have any {item} at the moment.", {
Expand All @@ -23,18 +25,27 @@
</template>

<script setup>
import { computed } from 'vue';
import { PlusIcon } from '@heroicons/vue/24/outline';
import IconBox from '~icons/solar/box-minimalistic-bold-duotone';

const { t } = useI18n();

defineProps({
const props = defineProps({
pageName: {
type: String,
required: true
},
// A Solar (or any) icon component to theme the empty state for its content.
icon: {
type: [Object, Function],
default: null
}
});

defineEmits(['create']);

const resolvedIcon = computed(() => props.icon || IconBox);
</script>

<style scoped lang="scss">
Expand All @@ -46,133 +57,91 @@ defineEmits(['create']);
align-items: center;
justify-content: center;
text-align: center;
margin-top: 3rem;
margin-bottom: 0;
padding: 2rem 1rem;
padding: 3rem 1rem;
min-height: 50vh;

@media (max-width: $breakpoint-md) {
margin-top: 2rem;
padding: 1.5rem 1rem;
@media (max-width: $breakpoint-sm) {
padding: 2rem 0.5rem;
min-height: 40vh;
}
}

.empty-art {
display: flex;
align-items: center;
justify-content: center;
width: 140px;
height: 140px;
margin-bottom: 1.5rem;
border-radius: 50%;
background: radial-gradient(circle at 30% 25%, $primary-light, $bg-light 70%);

@media (max-width: $breakpoint-sm) {
margin-top: 1rem;
padding: 1rem 0.5rem;
min-height: 35vh;
width: 112px;
height: 112px;
margin-bottom: 1rem;
}
}

.empty-icon {
width: 220px;
height: 220px;
margin-bottom: 1rem;

@media (max-width: $breakpoint-md) {
width: 180px;
height: 180px;
margin-bottom: 0.75rem;
}
.empty-illustration {
width: 72px;
height: 72px;
color: $primary;

@media (max-width: $breakpoint-sm) {
width: 140px;
height: 140px;
margin-bottom: 0.5rem;
width: 58px;
height: 58px;
}
}

.empty-title {
color: $text-primary;
font-size: 2.2rem;
font-weight: 700;
margin: 1rem 2rem;
line-height: 1.2;

@media (max-width: $breakpoint-md) {
font-size: 1.8rem;
margin: 0.75rem 1.5rem;
}
font-size: 1.6rem;
font-weight: $font-bold;
margin: 0 1rem 0.5rem;
line-height: 1.25;
max-width: 28ch;

@media (max-width: $breakpoint-sm) {
font-size: 1.4rem;
margin: 0.5rem 1rem;
line-height: 1.3;
}

@media (max-width: 480px) {
font-size: 1.2rem;
margin: 0.5rem 0.5rem;
font-size: 1.3rem;
}
}

.empty-subtitle {
color: $text-secondary;
font-size: 1.2rem;
margin-bottom: 2.5rem;
line-height: 1.4;
max-width: 90%;

@media (max-width: $breakpoint-md) {
font-size: 1.1rem;
margin-bottom: 2rem;
}
color: $text-muted;
font-size: 1rem;
margin: 0 0 2rem;
line-height: 1.5;
max-width: 42ch;

@media (max-width: $breakpoint-sm) {
font-size: 1rem;
font-size: 0.95rem;
margin-bottom: 1.5rem;
max-width: 95%;
}

@media (max-width: 480px) {
font-size: 0.9rem;
margin-bottom: 1.25rem;
}
}

.add-entity-btn {
background: $primary;
color: $bg-white;
font-size: 1.3rem;
font-weight: 600;
color: $text-inverse;
font-size: 1rem;
font-weight: $font-semibold;
border: none;
border-radius: $radius-xl;
padding: 1rem 2.5rem;
padding: 0.8rem 1.75rem;
cursor: pointer;
transition: background 0.2s;
display: flex;
transition: background $duration-fast $easing-standard;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
min-width: 160px;

.button-icon {
width: 1.2rem;
height: 1.2rem;
width: 1.1rem;
height: 1.1rem;
flex-shrink: 0;
stroke-width: 2;
}

@media (max-width: $breakpoint-md) {
font-size: 1.1rem;
padding: 0.875rem 2rem;
border-radius: $radius-lg;
min-width: 140px;
}

@media (max-width: $breakpoint-sm) {
font-size: 1rem;
padding: 0.75rem 1.5rem;
border-radius: $radius-lg;
min-width: 120px;
}

@media (max-width: 480px) {
font-size: 0.9rem;
padding: 0.625rem 1.25rem;
min-width: 110px;
}

&:hover {
background: $primary-hover;
}
Expand Down
11 changes: 10 additions & 1 deletion components/TAvatar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
<Settings class="menu-icon" />
<span>{{ t('Settings') }}</span>
</button>
<button v-if="user?.is_admin" class="menu-item" @click="goToAdmin">
<ShieldCheck class="menu-icon" />
<span>{{ t('Admin') }}</span>
</button>
<button class="menu-item menu-item--danger" @click="handleLogout">
<LogOut class="menu-icon" />
<span>{{ t('Logout') }}</span>
Expand All @@ -33,7 +37,7 @@

<script setup>
import { useRouter } from 'vue-router';
import { Settings, LogOut } from 'lucide-vue-next';
import { Settings, LogOut, ShieldCheck } from 'lucide-vue-next';
import { useAuth } from '@/composables/useAuth';
import { useDropdown } from '@/composables/useDropdown';

Expand Down Expand Up @@ -67,6 +71,11 @@ const goToSettings = () => {
router.push('/settings');
};

const goToAdmin = () => {
close();
router.push('/admin');
};

const handleLogout = async () => {
close();
await logout();
Expand Down
Loading
Loading