21 changed files with 387 additions and 219 deletions
@ -0,0 +1,155 @@
@@ -0,0 +1,155 @@
|
||||
<script lang="ts"> |
||||
import Icon from '../ui/Icon.svelte'; |
||||
import { goto } from '$app/navigation'; |
||||
import { page } from '$app/stores'; |
||||
|
||||
interface Props { |
||||
title: string; |
||||
onRefresh?: () => void | Promise<void>; |
||||
refreshLoading?: boolean; |
||||
} |
||||
|
||||
let { title, onRefresh, refreshLoading = false }: Props = $props(); |
||||
|
||||
function handleBack() { |
||||
if (typeof window !== 'undefined' && window.history.length > 1) { |
||||
window.history.back(); |
||||
} else { |
||||
goto('/discussions'); |
||||
} |
||||
} |
||||
|
||||
async function handleRefresh() { |
||||
if (onRefresh) { |
||||
await onRefresh(); |
||||
} else { |
||||
// Default: reload the page |
||||
window.location.reload(); |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<div class="page-header"> |
||||
<div class="page-header-left"> |
||||
<button |
||||
class="page-header-button back-button" |
||||
onclick={handleBack} |
||||
aria-label="Go back" |
||||
title="Go back" |
||||
> |
||||
<Icon name="arrow-left" size={20} /> |
||||
</button> |
||||
<h1 class="page-header-title">{title}</h1> |
||||
</div> |
||||
<button |
||||
class="page-header-button refresh-button" |
||||
class:loading={refreshLoading} |
||||
onclick={handleRefresh} |
||||
disabled={refreshLoading} |
||||
aria-label="Refresh" |
||||
title="Refresh" |
||||
> |
||||
<Icon name="refresh" size={20} /> |
||||
</button> |
||||
</div> |
||||
|
||||
<style> |
||||
.page-header { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
gap: 1rem; |
||||
padding: 0 1rem; |
||||
margin-bottom: 1.5rem; |
||||
} |
||||
|
||||
.page-header-left { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 0.75rem; |
||||
flex: 1; |
||||
min-width: 0; |
||||
} |
||||
|
||||
.page-header-title { |
||||
font-size: 1.5em; |
||||
font-weight: bold; |
||||
color: var(--fog-text, #1f2937); |
||||
margin: 0; |
||||
font-family: monospace; |
||||
flex: 1; |
||||
min-width: 0; |
||||
word-break: break-word; |
||||
} |
||||
|
||||
:global(.dark) .page-header-title { |
||||
color: var(--fog-dark-text, #f9fafb); |
||||
} |
||||
|
||||
.page-header-button { |
||||
display: inline-flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
padding: 0.5rem; |
||||
border: 1px solid var(--fog-border, #e5e7eb); |
||||
border-radius: 0.375rem; |
||||
background: var(--fog-post, #ffffff); |
||||
color: var(--fog-text, #1f2937); |
||||
cursor: pointer; |
||||
transition: all 0.2s; |
||||
flex-shrink: 0; |
||||
width: 2.5rem; |
||||
height: 2.5rem; |
||||
} |
||||
|
||||
:global(.dark) .page-header-button { |
||||
border-color: var(--fog-dark-border, #374151); |
||||
background: var(--fog-dark-post, #1f2937); |
||||
color: var(--fog-dark-text, #f9fafb); |
||||
} |
||||
|
||||
.page-header-button:hover:not(:disabled) { |
||||
background: var(--fog-highlight, #f3f4f6); |
||||
border-color: var(--fog-accent, #64748b); |
||||
} |
||||
|
||||
:global(.dark) .page-header-button:hover:not(:disabled) { |
||||
background: var(--fog-dark-highlight, #475569); |
||||
border-color: var(--fog-dark-accent, #94a3b8); |
||||
} |
||||
|
||||
.page-header-button:disabled { |
||||
opacity: 0.5; |
||||
cursor: not-allowed; |
||||
} |
||||
|
||||
.page-header-button.loading { |
||||
animation: spin 1s linear infinite; |
||||
} |
||||
|
||||
@keyframes spin { |
||||
from { |
||||
transform: rotate(0deg); |
||||
} |
||||
to { |
||||
transform: rotate(360deg); |
||||
} |
||||
} |
||||
|
||||
@media (max-width: 640px) { |
||||
.page-header { |
||||
padding: 0 0.5rem; |
||||
margin-bottom: 1rem; |
||||
} |
||||
|
||||
.page-header-title { |
||||
font-size: 1.25em; |
||||
} |
||||
|
||||
.page-header-button { |
||||
width: 2.25rem; |
||||
height: 2.25rem; |
||||
padding: 0.375rem; |
||||
} |
||||
} |
||||
</style> |
||||
Loading…
Reference in new issue