feat(ui): Networking Profits dashboard + card-action consistency sweep #96

Merged
lfg2025 merged 4 commits from networking-profits-dashboard into main 2026-07-17 02:08:03 +00:00
2 changed files with 35 additions and 40 deletions
Showing only changes of commit f08f34ca10 - Show all commits

View File

@ -79,7 +79,9 @@ select:focus-visible {
border-color: rgba(251, 146, 60, 0.4);
}
/* Card action placement: keep compact header buttons for genuinely wide layouts. */
/* Card action placement: actions always live at the bottom of the card as
full-width buttons same layout on every screen size. The compact header
variants are permanently retired for consistency (desktop == mobile). */
.responsive-card-actions-top,
.web5-card-actions-top {
display: none;
@ -109,20 +111,6 @@ select:focus-visible {
white-space: nowrap;
}
@media (min-width: 1800px) {
.responsive-card-actions-top,
.web5-card-actions-top {
display: flex;
}
.responsive-card-actions-bottom,
.responsive-card-actions-bottom-grid,
.web5-card-actions-bottom,
.web5-card-actions-bottom-grid {
display: none;
}
}
/* Mobile touch targets — ensure tappable elements meet 44px minimum */
@media (max-width: 767px) {
button:not(.mode-switcher-btn):not(.sidebar-nav-item):not([class*="w-9"]):not([class*="w-8"]):not([class*="w-7"]):not([class*="w-10"]):not([class*="w-11"]):not([class*="w-12"]) {

View File

@ -30,40 +30,47 @@
</svg>
Refreshing Tor services...
</div>
<div v-for="svc in torServices" :key="svc.name" class="bg-black/20 rounded-xl border border-white/10 p-3 flex items-center justify-between gap-3">
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2">
<p class="text-white text-sm font-medium">{{ svc.name }}</p>
<span class="text-white/30 text-xs">:{{ svc.local_port }}</span>
<span v-if="svc.protocol" class="text-xs px-1.5 py-0.5 rounded bg-blue-500/20 text-blue-400">protocol</span>
<span v-else-if="!svc.unauthenticated" class="text-xs px-1.5 py-0.5 rounded bg-green-500/20 text-green-400">auth</span>
<span v-else class="text-xs px-1.5 py-0.5 rounded bg-amber-500/20 text-amber-400">open</span>
<div v-for="svc in torServices" :key="svc.name" class="bg-black/20 rounded-xl border border-white/10 p-3">
<div class="flex items-center justify-between gap-3">
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2">
<p class="text-white text-sm font-medium">{{ svc.name }}</p>
<span class="text-white/30 text-xs">:{{ svc.local_port }}</span>
<span v-if="svc.protocol" class="text-xs px-1.5 py-0.5 rounded bg-blue-500/20 text-blue-400">protocol</span>
<span v-else-if="!svc.unauthenticated" class="text-xs px-1.5 py-0.5 rounded bg-green-500/20 text-green-400">auth</span>
<span v-else class="text-xs px-1.5 py-0.5 rounded bg-amber-500/20 text-amber-400">open</span>
</div>
<p v-if="svc.onion_address" class="text-amber-300/80 text-xs font-mono truncate cursor-pointer" :title="svc.onion_address" @click="$emit('copyAddress', svc.onion_address)">{{ svc.onion_address }}</p>
<p v-else-if="svc.enabled" class="text-white/30 text-xs">Waiting for .onion address...</p>
<p v-else class="text-white/30 text-xs">Disabled</p>
</div>
<p v-if="svc.onion_address" class="text-amber-300/80 text-xs font-mono truncate cursor-pointer" :title="svc.onion_address" @click="$emit('copyAddress', svc.onion_address)">{{ svc.onion_address }}</p>
<p v-else-if="svc.enabled" class="text-white/30 text-xs">Waiting for .onion address...</p>
<p v-else class="text-white/30 text-xs">Disabled</p>
<ToggleSwitch class="shrink-0" :model-value="svc.enabled" @update:model-value="$emit('toggleApp', svc.name, $event)" />
</div>
<div class="flex items-center gap-2 shrink-0">
<button
v-if="svc.onion_address && svc.enabled"
@click="$emit('rotateService', svc.name)"
:disabled="torRotating === svc.name"
class="glass-button px-3 py-1.5 rounded-lg text-xs"
>
{{ torRotating === svc.name ? 'Rotating...' : 'Rotate' }}
</button>
<!-- Actions in their own 50/50 row: Delete on the LEFT, far from the
toggle above, so a rushed thumb can't hit the wrong control. -->
<div
v-if="svc.name !== 'archipelago' || (svc.onion_address && svc.enabled)"
class="grid grid-cols-2 gap-2 mt-3"
>
<button
v-if="svc.name !== 'archipelago'"
@click="$emit('deleteService', svc.name)"
:disabled="torDeleting === svc.name"
class="glass-button px-2 py-1.5 rounded-lg text-xs text-red-400 hover:text-red-300"
class="glass-button py-2 rounded-lg text-xs text-red-400 hover:text-red-300 disabled:opacity-50"
:class="{ 'col-span-2': !(svc.onion_address && svc.enabled) }"
:title="'Delete ' + svc.name + ' hidden service'"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
{{ torDeleting === svc.name ? 'Deleting...' : 'Delete' }}
</button>
<button
v-if="svc.onion_address && svc.enabled"
@click="$emit('rotateService', svc.name)"
:disabled="torRotating === svc.name"
class="glass-button py-2 rounded-lg text-xs disabled:opacity-50"
:class="{ 'col-span-2': svc.name === 'archipelago' }"
>
{{ torRotating === svc.name ? 'Rotating...' : 'Rotate' }}
</button>
<ToggleSwitch :model-value="svc.enabled" @update:model-value="$emit('toggleApp', svc.name, $event)" />
</div>
</div>
</div>