mirror of
https://github.com/KevinMidboe/seasoned.git
synced 2026-04-25 01:03:36 +00:00
* include credentials on login fetch requests, allows set header response * Add theme composable and utility improvements - Create useTheme composable for centralized theme management - Update main.ts to use useTheme for initialization - Generalize getCookie utility in user module - Add utility functions for data formatting * Add Plex integration composables and icons - Create usePlexAuth composable for Plex OAuth flow - Create usePlexApi composable for Plex API interactions - Create useRandomWords composable for password generation - Add Plex-related icons (IconPlex, IconServer, IconSync) - Add Plex helper utilities - Update API with Plex-related endpoints * Add storage management components for data & privacy section - Create StorageManager component for browser storage overview - Create StorageSectionBrowser for localStorage/sessionStorage/cookies - Create StorageSectionServer for server-side data (mock) - Create ExportSection for data export functionality - Refactor DataExport component with modular sections - Add storage icons (IconCookie, IconDatabase, IconTimer) - Implement collapsible sections with visual indicators - Add colored borders per storage type - Display item counts and total size in headers * Add theme, password, and security settings components - Create ThemePreferences with visual theme selector - Create PasswordGenerator with passphrase and random modes - Create SecuritySettings wrapper for password management - Update ChangePassword to work with new layout - Implement improved slider UX with visual feedback - Add theme preview cards with gradients - Standardize component styling and typography * Add Plex settings and authentication components - Create PlexSettings component for Plex account management - Create PlexAuthButton with improved OAuth flow - Create PlexServerInfo for server details display - Use icon components instead of inline SVGs - Add sync and unlink functionality - Implement user-friendly authentication flow * Redesign settings page with two-column layout and ProfileHero - Create ProfileHero component with avatar and user info - Create RequestHistory component for Plex requests (placeholder) - Redesign SettingsPage with modern two-column grid layout - Add shared-settings.scss for consistent styling - Organize sections: Appearance, Security, Integrations, Data & Privacy - Implement responsive mobile layout - Standardize typography (h2: 1.5rem, 700 weight) - Add compact modifier for tighter sections
234 lines
4.9 KiB
Vue
234 lines
4.9 KiB
Vue
<template>
|
|
<div class="profile-hero">
|
|
<div class="profile-hero__main">
|
|
<div class="profile-hero__avatar">
|
|
<div class="avatar-large">{{ userInitials }}</div>
|
|
</div>
|
|
<div class="profile-hero__info">
|
|
<h1 class="profile-hero__name">{{ username }}</h1>
|
|
<span :class="['profile-hero__badge', `badge--${userRole}`]">
|
|
<a v-if="userRole === 'admin'" href="/admin">{{ userRole }}</a>
|
|
<span v-else>{{ userRole }}</span>
|
|
</span>
|
|
<p class="profile-hero__member">Member since {{ memberSince }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="profile-hero__stats">
|
|
<div class="stat-large">
|
|
<span class="stat-large__value">{{ stats.totalRequests }}</span>
|
|
<span class="stat-large__label">Requests</span>
|
|
</div>
|
|
<div class="stat-divider"></div>
|
|
<div class="stat-large">
|
|
<span class="stat-large__value">{{ stats.magnetsAdded }}</span>
|
|
<span class="stat-large__label">Magnets Added</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from "vue";
|
|
import { useStore } from "vuex";
|
|
|
|
const store = useStore();
|
|
|
|
const username = computed(() => store.getters["user/username"] || "User");
|
|
const userRole = computed(() =>
|
|
store.getters["user/admin"] ? "admin" : "user"
|
|
);
|
|
|
|
const userInitials = computed(() => {
|
|
return username.value.slice(0, 2).toUpperCase();
|
|
});
|
|
|
|
const memberSince = computed(() => {
|
|
const date = new Date();
|
|
date.setMonth(date.getMonth() - 6);
|
|
return date.toLocaleDateString("en-US", {
|
|
month: "short",
|
|
year: "numeric"
|
|
});
|
|
});
|
|
|
|
const stats = {
|
|
totalRequests: 45,
|
|
magnetsAdded: 127
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
@import "scss/media-queries";
|
|
|
|
.profile-hero {
|
|
background-color: var(--background-color-secondary);
|
|
border-radius: 0.75rem;
|
|
padding: 1.5rem;
|
|
border: 1px solid var(--background-40);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 2rem;
|
|
|
|
@include mobile-only {
|
|
flex-direction: column;
|
|
padding: 1.5rem 1.25rem;
|
|
border-radius: 0.5rem;
|
|
text-align: center;
|
|
gap: 1rem;
|
|
}
|
|
|
|
&__main {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1.5rem;
|
|
|
|
@include mobile-only {
|
|
flex-direction: column;
|
|
gap: 0.75rem;
|
|
}
|
|
}
|
|
|
|
&__avatar {
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
&__info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.35rem;
|
|
|
|
@include mobile-only {
|
|
align-items: center;
|
|
}
|
|
}
|
|
|
|
&__name {
|
|
margin: 0;
|
|
font-size: 1.75rem;
|
|
font-weight: 600;
|
|
line-height: 1.1;
|
|
|
|
@include mobile-only {
|
|
font-size: 1.5rem;
|
|
}
|
|
}
|
|
|
|
&__badge {
|
|
display: inline-block;
|
|
padding: 0.25rem 0.7rem;
|
|
border-radius: 2rem;
|
|
font-size: 0.75rem;
|
|
text-transform: uppercase;
|
|
font-weight: 600;
|
|
width: fit-content;
|
|
|
|
@include mobile-only {
|
|
padding: 0.2rem 0.6rem;
|
|
font-size: 0.7rem;
|
|
}
|
|
|
|
&.badge--admin {
|
|
background-color: var(--color-warning);
|
|
color: black;
|
|
}
|
|
|
|
&.badge--user {
|
|
background-color: var(--background-40);
|
|
}
|
|
}
|
|
|
|
&__member {
|
|
margin: 0;
|
|
font-size: 0.85rem;
|
|
color: var(--text-color-70);
|
|
|
|
@include mobile-only {
|
|
font-size: 0.8rem;
|
|
}
|
|
}
|
|
|
|
&__stats {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1.75rem;
|
|
padding-left: 1.75rem;
|
|
border-left: 1px solid var(--background-40);
|
|
|
|
@include mobile-only {
|
|
width: 100%;
|
|
padding: 1rem 0 0 0;
|
|
border-left: none;
|
|
border-top: 1px solid var(--background-40);
|
|
justify-content: center;
|
|
gap: 1.25rem;
|
|
}
|
|
}
|
|
}
|
|
|
|
.avatar-large {
|
|
width: 70px;
|
|
height: 70px;
|
|
border-radius: 50%;
|
|
background: linear-gradient(
|
|
135deg,
|
|
var(--highlight-color),
|
|
var(--color-green-70)
|
|
);
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 1.75rem;
|
|
font-weight: 700;
|
|
color: white;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
|
|
|
@include mobile-only {
|
|
width: 80px;
|
|
height: 80px;
|
|
font-size: 2rem;
|
|
}
|
|
}
|
|
|
|
.stat-large {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 0.25rem;
|
|
|
|
&__value {
|
|
font-size: 1.75rem;
|
|
font-weight: 700;
|
|
color: var(--highlight-color);
|
|
line-height: 1;
|
|
|
|
@include mobile-only {
|
|
font-size: 1.75rem;
|
|
}
|
|
}
|
|
|
|
&__label {
|
|
font-size: 0.75rem;
|
|
color: var(--text-color-70);
|
|
text-transform: uppercase;
|
|
font-weight: 500;
|
|
letter-spacing: 0.5px;
|
|
|
|
@include mobile-only {
|
|
font-size: 0.75rem;
|
|
}
|
|
}
|
|
}
|
|
|
|
.stat-divider {
|
|
width: 1px;
|
|
height: 45px;
|
|
background-color: var(--background-40);
|
|
|
|
@include mobile-only {
|
|
height: 45px;
|
|
}
|
|
}
|
|
</style>
|