Improve mobile UX: condense torrent table and standardize page layouts

- TorrentTable: Condense to 2 columns on mobile (title+meta, actions)
  - Title shown on first line, size/seeders on second line
  - Hide separate seed/size columns on mobile (desktop only)
  - Improved spacing and readability for mobile screens

- Standardize page layouts to match ActivityPage:
  - TorrentsPage: Update header style, padding, and container structure
  - GenPasswordPage: Align header and content layout with other pages
  - Consistent 3rem desktop padding, 0.75rem mobile padding
  - Unified h1 styling: 2rem desktop, 1.5rem mobile, font-weight 300

- Minor improvements:
  - Remove console.log statements from usePlexApi
  - Fix duration unit handling in useTautulliStats
  - Adjust AdminStats label font sizing
  - Reduce Graph.vue point radius for cleaner charts
This commit is contained in:
2026-02-27 18:19:38 +01:00
parent 0c4c30d1a0
commit 64a833c9f8
7 changed files with 163 additions and 44 deletions

View File

@@ -106,6 +106,12 @@
const graphOptions = {
maintainAspectRatio: false,
elements: {
point: {
radius: 2,
}
},
plugins: {
tooltip: {
callbacks: {

View File

@@ -439,13 +439,12 @@
padding: 1rem 0;
@include mobile-only {
font-size: 1.25rem;
margin-bottom: 0.1rem;
}
}
&__label {
font-size: 0.75rem;
font-size: 0.8rem;
color: $text-color-70;
text-transform: uppercase;
letter-spacing: 0.4px;
@@ -455,7 +454,6 @@
line-height: 1.2;
@include mobile-only {
font-size: 0.65rem;
margin-bottom: 0.3rem;
letter-spacing: 0.2px;
}

View File

@@ -22,18 +22,26 @@
class="table__content"
>
<td
class="torrent-info"
@click="expand($event, torrent.name)"
@keydown.enter="expand($event, torrent.name)"
>
{{ torrent.name }}
<div class="torrent-title">{{ torrent.name }}</div>
<div class="torrent-meta">
<span class="meta-item">{{ torrent.size }}</span>
<span class="meta-separator"></span>
<span class="meta-item">{{ torrent.seed }} seeders</span>
</div>
</td>
<td
class="torrent-seed desktop-only"
@click="expand($event, torrent.name)"
@keydown.enter="expand($event, torrent.name)"
>
{{ torrent.seed }}
</td>
<td
class="torrent-size desktop-only"
@click="expand($event, torrent.name)"
@keydown.enter="expand($event, torrent.name)"
>
@@ -177,6 +185,13 @@
}
}
// Hide seed and size columns on mobile
.desktop-only {
@include mobile {
display: none;
}
}
thead {
position: relative;
user-select: none;
@@ -194,34 +209,81 @@
th:last-of-type {
padding-right: 0.4rem;
}
// Hide seed and size headers on mobile
@include mobile {
th:nth-child(2),
th:nth-child(3) {
display: none;
}
}
}
tbody {
// first column
tr td:first-of-type {
// first column - torrent info
.torrent-info {
position: relative;
padding: 0 0.3rem;
padding: 0.5rem 0.6rem;
cursor: default;
word-break: break-all;
word-break: break-word;
border-left: 1px solid var(--table-background-color);
@include mobile {
max-width: 40vw;
overflow-x: hidden;
width: 100%;
padding: 0.75rem 0.5rem;
}
.torrent-title {
font-weight: 500;
margin-bottom: 0.25rem;
line-height: 1.3;
@include mobile {
font-size: 0.95rem;
}
}
.torrent-meta {
display: none; // Hidden on desktop, shown on mobile
font-size: 0.85rem;
color: var(--text-color-60);
@include mobile {
display: flex;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
}
.meta-item {
white-space: nowrap;
}
.meta-separator {
color: var(--text-color-40);
}
}
}
// all columns except first
tr td:not(td:first-of-type) {
// seed and size columns (desktop only)
.torrent-seed,
.torrent-size {
text-align: center;
white-space: nowrap;
padding: 0.5rem;
}
// last column
// last column - action
tr td:last-of-type {
vertical-align: middle;
cursor: pointer;
border-right: 1px solid var(--table-background-color);
width: 60px;
text-align: center;
@include mobile {
width: 50px;
}
svg {
width: 21px;
@@ -229,6 +291,10 @@
margin: auto;
padding: 0.3rem 0;
fill: var(--text-color);
@include mobile {
width: 18px;
}
}
}

View File

@@ -26,7 +26,6 @@ export function usePlexApi() {
}
const data = await response.json();
console.log("[PlexAPI] Raw Plex API response:", data);
// Convert Unix timestamp to ISO date string if needed
let joinedDate = null;
@@ -62,7 +61,6 @@ export function usePlexApi() {
created_at: new Date().toISOString()
};
console.log("[PlexAPI] Processed user data:", userData);
localStorage.setItem("plex_user_data", JSON.stringify(userData));
return userData;
} catch (error) {

View File

@@ -108,7 +108,8 @@ export function useTautulliStats() {
.map(([date, stats]) => ({
date,
plays: stats.plays,
duration: Math.round(stats.duration / 60) // Convert to minutes
duration: stats.duration
// duration: Math.round(stats.duration / 60) // Convert to minutes
}))
.sort((a, b) => a.date.localeCompare(b.date));
}

View File

@@ -1,11 +1,11 @@
<template>
<section class="admin">
<h1 class="admin__title">Password gen</h1>
<div class="password">
<h1 class="password__title">Password Generator</h1>
<div class="form">
<div class="password__content">
<password-generator />
</div>
</section>
</div>
</template>
<script setup lang="ts">
@@ -17,9 +17,34 @@
</script>
<style lang="scss" scoped>
.form {
display: flex;
flex-direction: column;
gap: 0.65rem;
@import "scss/variables";
@import "scss/media-queries";
.password {
padding: 3rem;
max-width: 100%;
@include mobile-only {
padding: 0.75rem;
}
&__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;
}
}
&__content {
display: flex;
flex-direction: column;
gap: 0.65rem;
}
}
</style>

View File

@@ -1,28 +1,25 @@
<template>
<div>
<page-header title="Torrent search page" />
<div class="torrents">
<h1 class="torrents__title">Torrent Search</h1>
<section>
<div class="search-input-group">
<seasoned-input
v-model="query"
type="torrents"
placeholder="Search torrents"
@keydown.enter="setTorrentQuery"
/>
<seasoned-button @click="setTorrentQuery">Search</seasoned-button>
</div>
<div class="search-input-group">
<seasoned-input
v-model="query"
type="torrents"
placeholder="Search torrents"
@keydown.enter="setTorrentQuery"
/>
<seasoned-button @click="setTorrentQuery">Search</seasoned-button>
</div>
<active-torrents />
<active-torrents />
<TorrentList :query="torrentQuery" />
</section>
<TorrentList :query="torrentQuery" />
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import PageHeader from "@/components/PageHeader.vue";
import SeasonedInput from "@/components/ui/SeasonedInput.vue";
import SeasonedButton from "@/components/ui/SeasonedButton.vue";
import TorrentList from "@/components/torrent/TorrentSearchResults.vue";
@@ -42,16 +39,44 @@
</script>
<style lang="scss" scoped>
section {
padding: 1.25rem;
@import "scss/variables";
@import "scss/media-queries";
.torrents {
padding: 3rem;
max-width: 100%;
@include mobile-only {
padding: 0.75rem;
}
&__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;
}
}
.search-input-group {
display: flex;
gap: 0.5rem;
margin-bottom: 2rem;
@include mobile-only {
flex-direction: column;
gap: 0.75rem;
}
button {
margin-left: 0.5rem;
@include mobile-only {
width: 100%;
}
}
}
}