Feat/settings page redesign (#104)

* 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
This commit is contained in:
2026-03-08 21:16:36 +01:00
committed by GitHub
parent 081240c83e
commit c309016299
39 changed files with 6232 additions and 115 deletions

View File

@@ -0,0 +1,127 @@
<template>
<div class="settings-section-card">
<div class="settings-section-header">
<h2>Export Your Data</h2>
<p>
Download a copy of your account data including requests, watch history,
and preferences.
</p>
</div>
<!-- Export to JSON & CSV section -->
<div class="export-actions">
<button
class="export-btn"
@click="() => exportData('json')"
:disabled="exporting"
>
<IconActivity v-if="exporting" class="spin" />
<span v-else>Export as JSON</span>
</button>
<button
class="export-btn"
@click="() => exportData('csv')"
:disabled="exporting"
>
<IconActivity v-if="exporting" class="spin" />
<span v-else>Export as CSV</span>
</button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, defineProps } from "vue";
import IconActivity from "@/icons/IconActivity.vue";
interface Props {
data: any;
}
const props = defineProps<Props>();
const exporting = ref(false);
async function exportData(format: "json" | "csv") {
exporting.value = true;
// Mock export
await new Promise(resolve => setTimeout(resolve, 1500));
const data = {
username: "user123",
requests: props?.data,
exportDate: new Date().toISOString()
};
const blob = new Blob(
[format === "json" ? JSON.stringify(data, null, 2) : convertToCSV(data)],
{ type: format === "json" ? "application/json" : "text/csv" }
);
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = `seasoned-data-export.${format}`;
link.click();
URL.revokeObjectURL(url);
exporting.value = false;
}
function convertToCSV(data: any): string {
return `Username,Total Requests,Approved,Pending,Export Date\n${data.username},${data.requests.total},${data.requests.approved},${data.requests.pending},${data.exportDate}`;
}
</script>
<style lang="scss" scoped>
@import "scss/media-queries";
@import "scss/shared-settings";
.export-actions {
display: flex;
gap: 0.55rem;
@include mobile-only {
flex-direction: column;
gap: 0.5rem;
}
}
.export-btn {
flex: 1;
padding: 0.55rem 0.85rem;
background-color: var(--highlight-color);
color: white;
border: none;
border-radius: 0.25rem;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
gap: 0.35rem;
&:hover:not(:disabled) {
background-color: var(--color-green-90);
}
&:disabled {
opacity: 0.6;
cursor: not-allowed;
}
svg {
width: 16px;
height: 16px;
fill: white;
&.spin {
animation: spin 1s linear infinite;
}
}
}
</style>