mirror of
https://github.com/KevinMidboe/seasoned.git
synced 2026-03-11 03:49:07 +00:00
Refactor: Modernize Activity page UI to match site design
Update page structure:
- Rename wrapper class to 'activity' (matches AdminPage pattern)
- Update h1 to activity__title with consistent styling
- Organize content with BEM naming convention
Redesign controls:
- Replace basic input with styled input-wrapper component
- Add input-suffix "days" label inside input container
- Custom number input styling with hover/focus states
- Better ToggleButton integration with control-label
- Responsive flex layout with proper mobile handling
Enhance chart presentation:
- Wrap each graph in chart-card component
- Add background, borders, and rounded corners
- Clear chart-card__title headers
- Fixed height charts (35vh desktop, 30vh mobile)
- Minimum height prevents squashing (300px/250px)
- Consistent spacing and padding
Improve top content section:
- Grid layout for top content items (3 cols → 1 col mobile)
- Card-based items with borders and hover effects
- Hover: border highlight + translateY animation
- Better visual hierarchy with section-title
Styling details:
- Use CSS variables (--background-ui, --text-color-50, etc.)
- Match AdminPage typography (2rem title, 300 weight)
- Consistent border-radius (12px cards, 8px inputs)
- Proper mobile-only responsive breakpoints
- Remove old commented-out code
Result: Professional, cohesive design matching rest of site ✨
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div v-if="plexUserId && plexUsername" class="wrapper">
|
||||
<h1>Your watch activity</h1>
|
||||
<div v-if="plexUserId && plexUsername" class="activity">
|
||||
<h1 class="activity__title">Watch Activity</h1>
|
||||
|
||||
<!-- Stats Overview -->
|
||||
<div v-if="watchStats" class="stats-overview">
|
||||
@@ -22,34 +22,36 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; flex-direction: row">
|
||||
<label class="filter" for="dayinput">
|
||||
<span>Days:</span>
|
||||
<div class="controls">
|
||||
<div class="control-group">
|
||||
<label class="control-label">Time Range</label>
|
||||
<div class="input-wrapper">
|
||||
<input
|
||||
id="dayinput"
|
||||
v-model="days"
|
||||
class="dayinput"
|
||||
placeholder="days"
|
||||
v-model.number="days"
|
||||
class="days-input"
|
||||
type="number"
|
||||
pattern="[0-9]*"
|
||||
min="1"
|
||||
max="365"
|
||||
@change="fetchChartData"
|
||||
/>
|
||||
</label>
|
||||
<span class="input-suffix">days</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="filter">
|
||||
<span>Data sorted by:</span>
|
||||
<div class="control-group">
|
||||
<label class="control-label">View Mode</label>
|
||||
<toggle-button
|
||||
v-model:selected="graphViewMode"
|
||||
class="filter-item"
|
||||
:options="[GraphTypes.Plays, GraphTypes.Duration]"
|
||||
@change="fetchChartData"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chart-section">
|
||||
<h3 class="chart-header">Activity per day:</h3>
|
||||
<div class="graph">
|
||||
<div class="activity__charts">
|
||||
<div class="chart-card">
|
||||
<h3 class="chart-card__title">Daily Activity</h3>
|
||||
<div class="chart-card__graph">
|
||||
<Graph
|
||||
v-if="playsByDayData"
|
||||
:data="playsByDayData"
|
||||
@@ -60,9 +62,11 @@
|
||||
:graph-value-type="selectedGraphViewMode.valueType"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="chart-header">Activity by media type:</h3>
|
||||
<div class="graph">
|
||||
<div class="chart-card">
|
||||
<h3 class="chart-card__title">Activity by Media Type</h3>
|
||||
<div class="chart-card__graph">
|
||||
<Graph
|
||||
v-if="playsByDayofweekData"
|
||||
:data="playsByDayofweekData"
|
||||
@@ -73,9 +77,11 @@
|
||||
:graph-value-type="GraphValueTypes.Number"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="chart-header">Watch time by hour:</h3>
|
||||
<div class="graph">
|
||||
<div class="chart-card">
|
||||
<h3 class="chart-card__title">Viewing Patterns by Hour</h3>
|
||||
<div class="chart-card__graph">
|
||||
<Graph
|
||||
v-if="hourlyData"
|
||||
:data="hourlyData"
|
||||
@@ -87,10 +93,11 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Top Content -->
|
||||
<div v-if="topContent.length > 0" class="top-content-section">
|
||||
<h3 class="chart-header">Most watched:</h3>
|
||||
<div v-if="topContent.length > 0" class="activity__top-content">
|
||||
<h3 class="section-title">Most Watched</h3>
|
||||
<div class="top-content-list">
|
||||
<div
|
||||
v-for="(item, index) in topContent"
|
||||
@@ -262,38 +269,41 @@
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
|
||||
.wrapper {
|
||||
padding: 2rem;
|
||||
.activity {
|
||||
padding: 3rem;
|
||||
max-width: 100%;
|
||||
|
||||
@include mobile-only {
|
||||
padding: 0 0.8rem;
|
||||
}
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.filter {
|
||||
margin-top: 0.5rem;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
font-size: 1.2rem;
|
||||
|
||||
&:not(:first-of-type) {
|
||||
margin-left: 1.25rem;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
font-size: inherit;
|
||||
max-width: 6rem;
|
||||
background-color: $background-ui;
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: inherit;
|
||||
line-height: 1;
|
||||
margin: 0.5rem 0;
|
||||
&__title {
|
||||
margin: 0 0 2rem 0;
|
||||
font-size: 2rem;
|
||||
font-weight: 300;
|
||||
color: $text-color;
|
||||
line-height: 1;
|
||||
|
||||
@include mobile-only {
|
||||
font-size: 1.5rem;
|
||||
margin: 0 0 1rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__charts {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
|
||||
@include mobile-only {
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
&__top-content {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,27 +332,121 @@
|
||||
// }
|
||||
// }
|
||||
|
||||
.chart-section {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.chart-card {
|
||||
background: var(--background-ui);
|
||||
border-radius: 12px;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid var(--text-color-50);
|
||||
|
||||
.graph {
|
||||
@include mobile-only {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
&__title {
|
||||
margin: 0 0 1rem 0;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 500;
|
||||
color: $text-color;
|
||||
|
||||
@include mobile-only {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
&__graph {
|
||||
position: relative;
|
||||
height: 35vh;
|
||||
width: 90vw;
|
||||
margin-bottom: 2rem;
|
||||
min-height: 300px;
|
||||
|
||||
@include mobile-only {
|
||||
height: 30vh;
|
||||
min-height: 250px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
font-weight: 300;
|
||||
.section-title {
|
||||
margin: 0 0 1rem 0;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 500;
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: flex;
|
||||
gap: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@include mobile-only {
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.control-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
min-width: 200px;
|
||||
|
||||
@include mobile-only {
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.control-label {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
color: var(--text-color-60);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: var(--background-ui);
|
||||
border: 1px solid var(--text-color-50);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
transition: border-color 0.2s;
|
||||
|
||||
&:hover,
|
||||
&:focus-within {
|
||||
border-color: var(--text-color);
|
||||
}
|
||||
}
|
||||
|
||||
.days-input {
|
||||
flex: 1;
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0.75rem 1rem;
|
||||
font-size: 1rem;
|
||||
color: $text-color;
|
||||
outline: none;
|
||||
width: 80px;
|
||||
|
||||
&::-webkit-inner-spin-button,
|
||||
&::-webkit-outer-spin-button {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.input-suffix {
|
||||
padding: 0 1rem;
|
||||
font-size: 0.9rem;
|
||||
color: var(--text-color-60);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.stats-overview {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
gap: 1.5rem;
|
||||
margin: 2rem 0;
|
||||
margin-bottom: 2rem;
|
||||
|
||||
@include mobile-only {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
@@ -389,14 +493,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
.top-content-section {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.top-content-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 1rem;
|
||||
|
||||
@include mobile-only {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.top-content-item {
|
||||
@@ -406,10 +510,12 @@
|
||||
background: var(--background-ui);
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
transition: background 0.2s;
|
||||
border: 1px solid var(--text-color-50);
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: var(--background-40);
|
||||
border-color: var(--text-color);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user