1
0
Fork 0

Migrate away from tailwind and move back to stores

This commit is contained in:
Leon Grünewald 2024-11-19 23:53:44 +01:00
parent 35a9b95c8e
commit 507ea37f74
20 changed files with 568 additions and 299 deletions

View file

@ -1,18 +0,0 @@
/* Write your global styles here, in PostCSS syntax */
@tailwind base;
@tailwind components;
@tailwind utilities;
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
}
img {
width: 100%;
margin: 0 auto;
}

View file

@ -1,88 +0,0 @@
<script>
import useSettings from '$lib/useSettings.svelte.js';
const settings = useSettings();
let tabPos = $state(0);
let showApikey = $state(false);
let apikey = $state('');
</script>
<div class="flex flex-col">
<h2 class="h2 mb-2 text-dark-token">Settings</h2>
<!--<TabGroup>
<Tab class="text-dark-token" bind:group={tabPos} name="tab1" value={0}>Display</Tab>
<Tab class="text-dark-token" bind:group={tabPos} name="tab2" value={1}>API</Tab>
<Tab class="text-dark-token" bind:group={tabPos} name="tab3" value={2}>User</Tab>
<Tab class="text-dark-token" bind:group={tabPos} name="tab4" value={3}>Chats</Tab>
{#snippet panel()}
{#if tabPos === 0}
<div class="flex flex-col gap-3">
<h3 class="h3 text-dark-token font-bold">Image</h3>
<SlideToggle name="image-limit-height" bind:checked={settings.limitImageHeight}><span class="text-dark-token">Limit image height</span></SlideToggle>
<h3 class="h3 text-dark-token font-bold">Grid</h3>
<div class="basis-1/2">
<RangeSlider accent="text-dark-token" name="grid-columns" min={1} max={12} bind:value={settings.imageGridColumns} ticked={true}>
<div class="flex flex-grow justify-between items-center dark">
<div class="text-dark-token font-bold mb-1">Grid Columns</div>
<div class="text-xs text-dark-token">{settings.imageGridColumns} / {12}</div>
</div>
</RangeSlider>
</div>
<div class="basis-1/2">
<label class="label">
<span class="text-dark-token font-bold">Preview type</span>
<select class="select" bind:value={settings.postGridPreviewQuality}>
<option value="preview">Preview</option>
<option value="sample">Sample</option>
</select>
</label>
</div>
</div>
{/if}
{#if tabPos === 1}
<div class="flex flex-col gap-3">
<div class="">
<label class="label">
<span class="text-dark-token font-bold">e621 Username</span>
<input class="input" />
</label>
</div>
<div class="">
<label class="label">
<span class="text-dark-token font-bold">e621 Apikey</span>
{#if showApikey}
<input class="input" type="text" bind:value={apikey} />
{:else}
<input class="input" type="password" bind:value={apikey} />
{/if}
</label>
<label class="label">
<span class="text-dark-token font-bold">Show apikey</span>
<input class="checkbox" type="checkbox" bind:checked={showApikey} />
</label>
</div>
</div>
{/if}
{#if tabPos === 2}
<div class="flex flex-col gap-3">
<div class="">
<p class="text-dark-token font-bold">Blacklist</p>
<InputChip name="blacklist" label="Blacklist" bind:value={settings.blacklist} />
</div>
</div>
{/if}
{#if tabPos === 3}
<div class="flex flex-col gap-3">
<div class="">
<p class="text-dark-token font-bold">Chats</p>
<InputChip name="blacklist" label="Blacklist" bind:value={settings.blacklist} />
</div>
</div>
{/if}
{/snippet}
</TabGroup>-->
</div>

View file

@ -2,6 +2,7 @@
import {faArrowLeft} from '@fortawesome/free-solid-svg-icons';
import {Fa} from 'svelte-fa';
import {onMount} from "svelte";
import Button from "$lib/components/Button.svelte";
let { popCount = 1 } = $props();
let href = $state();
@ -28,6 +29,6 @@
</script>
<a {href} class="flex flex-row aspect-square place-content-center justify-center items-center bg-gray-600 h-10">
<Button {href} >
<Fa color="white" size={'1.5x'} icon={faArrowLeft} />
</a>
</Button>

View file

@ -0,0 +1,30 @@
<script>
let { children, class: className, fill = false, type = 'button', onclick = null} = $props();
</script>
<button class={className}
style:width={fill ? '100%' : 'auto'}
{type}
onclick={() => onclick?.()}>
{@render children?.()}
</button>
<style>
button {
aspect-ratio: 1 / 1;
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
place-content: center;
height: 40px;
padding: 10px;
background-color: #4b5563;
color: #fff;
&:hover {
background-color: #434b58;
}
}
</style>

View file

@ -0,0 +1,58 @@
<script>
import { Button } from '$lib/components';
let { values = $bindable([]), onAdd = () => {} } = $props();
let newValue = $state('');
function onAddNewValue() {
onAdd?.(newValue);
newValue = '';
}
</script>
<div class="chips-container">
<form>
<input bind:value={newValue} type="text" />
<Button type="submit" onclick={onAddNewValue}>Add</Button>
</form>
<div class="chips">
{#if values}
{#each values as chip}
<div class="chip">
<Button onclick={() => {
values = values.filter(value => value !== chip);
}}>{chip}</Button>
</div>
{/each}
{/if}
</div>
</div>
<style>
.chips-container {
display: grid;
grid-gap: 10px;
}
.chips {
display: flex;
flex-flow: row wrap;
gap: 10px;
}
.chip {
color: white;
background-color: #4b5563;
border-radius: 10px;
&:hover {
background-color: #434b58;
}
}
form {
display: flex;
gap: 10px;
}
</style>

View file

@ -1,22 +1,29 @@
<script>
import useSettings from '$lib/useSettings.svelte.js';
import {loading} from "$lib/stores.js";
import {loading} from '$lib/stores.js';
import {Button} from '$lib/components';
import {lastSearch} from '$lib/stores.js';
const settings = useSettings();
let searchString = $state('');
const {onsubmit = null} = $props();
$effect(() => {
searchString = settings.lastSearch
searchString = $lastSearch
});
</script>
<form class="flex flex-row gap-2"
<form
onsubmit={(e) => {
e.preventDefault();
settings.lastSearch = searchString;
$lastSearch = searchString;
loading.set(true);
onsubmit?.(searchString, true);
}}>
<input class="h-10 p-2" type="text" placeholder="tags" bind:value={searchString} />
<button class="h-10 p-2 text-white bg-gray-600" type="submit">Search</button>
<input type="text" placeholder="tags" bind:value={searchString} />
<Button type="submit">Search</Button>
</form>
<style>
form {
display: flex;
gap: 10px;
}
</style>

View file

@ -1,11 +1,12 @@
<script>
import {BackButton, GlobalSearch} from "$lib/components";
import {faArrowLeft, faCogs} from "@fortawesome/free-solid-svg-icons";
import {BackButton, GlobalSearch, LinkButton} from "$lib/components";
import {faCogs} from "@fortawesome/free-solid-svg-icons";
import {Fa} from "svelte-fa";
let {onsubmit = null, back = null, class: className, showSearch = true} = $props();
let {onsubmit = null, back = null, class: className, showSearch = true, gridArea = ""} = $props();
</script>
<header class="absolute w-full top-0 flex bg-transparent py-2 px-4 gap-1 {className}">
<header class={className} style:grid-area={gridArea}>
<div class="left">
{#if back}
<BackButton popCount={back} />
{/if}
@ -14,7 +15,25 @@
onsubmit?.(val, explicitRefresh);
}} />
{/if}
<a href="/settings" class="flex flex-row aspect-square place-content-center justify-center items-center bg-gray-600 h-10">
</div>
<div class="right">
<LinkButton href="/settings/main">
<Fa color="white" size={'1.5x'} icon={faCogs} />
</a>
</LinkButton>
</div>
</header>
<style>
header {
margin: 10px 0;
display: flex;
justify-content: space-between;
grid-area: header;
width: 100%;
gap: 10px;
}
.right {
justify-content: flex-end;
}
</style>

View file

@ -1,25 +1,36 @@
<script>
import useSettings from "$lib/useSettings.svelte.js";
import { loading } from "$lib/stores.js";
import { loading, imageGridColumns, postGridPreviewQuality } from "$lib/stores.js";
let { posts = [] } = $props();
const settings = useSettings();
</script>
<div class="grid gap-3" style={`grid-template-columns: repeat(${settings.imageGridColumns}, minmax(0, 1fr))`}>
<div class="post-grid" style={`grid-template-columns: repeat(${$imageGridColumns}, minmax(0, 1fr))`}>
{#each posts as post}
<a href={`/posts/${post.id}`} class="card p-3 flex flex-col justify-end items-center" onclick={() => {
<a href={`/posts/${post.id}`} class="post-grid-item" onclick={() => {
loading.set(true);
}}>
<header class="card-header p-0"></header>
<section class="flex flex-col">
<img src={post[settings.postGridPreviewQuality].url}
<img src={post[$postGridPreviewQuality].url}
loading="lazy"
alt={`Post ${post.id}`} />
<div class="bg-black px-2 py-1">
<p class="text-center text-white">{post.id} {post.file.ext} {post.rating}</p>
</div>
</section>
<p class="post-info-bar">{post.id} {post.file.ext} {post.rating}</p>
</a>
{/each}
</div>
<style>
.post-grid {
display: grid;
gap: 1rem;
}
.post-grid-item {
display: flex;
flex-flow: column;
}
.post-info-bar {
color: white;
text-align: center;
background-color: #000;
}
</style>

View file

@ -0,0 +1,27 @@
<script>
let { children, class: className, href = $bindable(""), fill = false} = $props();
</script>
<a class={className} style:width={fill ? "100%" : "auto"} {href}>
{@render children?.()}
</a>
<style>
a {
aspect-ratio: 1 / 1;
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
place-content: center;
height: 40px;
padding: 10px;
background-color: #4b5563;
color: white;
&:hover {
background-color: #434b58;
}
}
</style>

View file

@ -1,6 +1,7 @@
<script>
import useSettings from '$lib/useSettings.svelte.js';
const settings = useSettings();
import {limitImageHeight} from '$lib/stores.js';
import {faCaretDown, faCaretUp, faCopy, faHeart, faStar} from "@fortawesome/free-solid-svg-icons";
import {Fa} from "svelte-fa";
/**
* @typedef {Object} Props
@ -13,7 +14,7 @@
</script>
{#if post?.preview?.has}
<img class:max-h-dvh={settings.limitImageHeight} class={className} src={post.preview.url} alt={`Post ${post.id}`} />
<img style:max-height={$limitImageHeight ? '100vh' : 'none'} class={className} src={post.preview.url} alt={`Post ${post.id}`} />
{:else}
{#if ['webm', 'mp4'].includes(post.file.ext)}
<video class={className} controls playsinline onclick={async e => {
@ -29,3 +30,72 @@
}}/>
{/if}
{/if}
<section class="post-info-bar">
<div class="post-info-bar-left">
<button class="btn-favorited">
<span class:accent-yellow-50={!post.is_favorited} class:accent-yellow-500={post.is_favorited}>
<Fa size={'1.5x'} icon={faHeart} />
</span>
&nbsp;
<span>
{post.fav_count}
</span>
</button>
<button class="btn-score">
<span class="text-secondary-500">
<Fa size={'1.5x'} icon={faStar} />
</span>
&nbsp;
{post.score.total}
</button>
<button class="btn-like">
<Fa size={'1.5x'} icon={faCaretUp} />
</button>
<button class="btn-dislike">
<Fa size={'1.5x'} icon={faCaretDown} />
</button>
</div>
<div class="post-info-bar-right">
<button class="btn-url"
onclick={async () => {await navigator.clipboard.writeText(`https://e621.net/posts/${post.id}`)}}>
<Fa size={'1.5x'} icon={faCopy} />
</button>
<button class="btn-id">
ID: {post.id}
</button>
</div>
</section>
<style>
video, img {
width: 100%;
}
.post-info-bar {
display: flex;
flex-flow: row;
justify-content: space-between;
color: white;
background-color: #000;
}
.btn-like, .btn-dislike, .btn-favorited, .btn-id, .btn-score, .btn-url {
padding: 10px;
display: flex;
gap: 2px;
background-color: black;
color: white;
&:hover {
color: black;
background-color: white;
}
}
.post-info-bar-left, .post-info-bar-right {
display: flex;
flex-flow: row;
gap: 2px;
}
</style>

View file

@ -1,15 +1,19 @@
import AppSettings from './AppSettings.svelte';
import BackButton from './BackButton.svelte';
import Button from './Button.svelte';
import Chips from './Chips.svelte';
import GlobalSearch from './GlobalSearch.svelte';
import ImageGrid from './ImageGrid.svelte';
import PostMedia from './PostMedia.svelte';
import Header from './Header.svelte';
import ImageGrid from './ImageGrid.svelte';
import LinkButton from './LinkButton.svelte';
import PostMedia from './PostMedia.svelte';
export {
AppSettings,
BackButton,
Button,
Chips,
GlobalSearch,
ImageGrid,
PostMedia,
Header,
ImageGrid,
LinkButton,
PostMedia,
}

View file

@ -1,4 +1,22 @@
import { writable } from 'svelte/store';
import { browser } from '$app/environment';
function localStorageStore(storageKey, defaultValue = null) {
if (!browser) return defaultValue;
let value = window.localStorage.getItem(storageKey);
if (value === null) {
if (defaultValue !== null) window.localStorage.setItem(storageKey, defaultValue);
value = defaultValue;
}
return writable(value)
}
export const postSearchResults = writable(null);
export const loading = writable(false);
export const lastSearch = localStorageStore('lastSearch', '');
export const showSearch = writable(true);
export const imageGridColumns = localStorageStore('gridColumns', 6);
export const postGridPreviewQuality = localStorageStore('gridPreviewQuality', 'preview');
export const blacklist = localStorageStore('blacklist', ['gore', 'scat'])
export const limitImageHeight = localStorageStore('limitImageHeight', false)

View file

@ -1,52 +0,0 @@
import {onMount} from "svelte";
export default function useSettings() {
let lastSearch = $state(null),
imageGridColumns = $state(6),
limitImageHeight = $state(true),
postGridPreviewQuality = $state('preview'),
blacklist = $state([
'gore',
'scat',
'watersports',
'young',
'loli',
'shota',
]);
onMount(() => {
lastSearch = localStorage.getItem('lastSearch') ?? lastSearch;
imageGridColumns = localStorage.getItem('gridColumns') ?? imageGridColumns;
limitImageHeight = localStorage.getItem('limitImageHeight') ?? limitImageHeight;
postGridPreviewQuality = localStorage.getItem('gridPreviewQuality') ?? postGridPreviewQuality;
blacklist = localStorage.getItem('blacklist') ?? blacklist;
})
return {
get lastSearch() {return lastSearch},
get imageGridColumns() {return imageGridColumns},
get postGridPreviewQuality() {return postGridPreviewQuality},
get blacklist() {return blacklist},
get limitImageHeight() {return limitImageHeight},
set lastSearch(val) {
lastSearch = val;
localStorage.setItem('lastSearch', val);
},
set imageGridColumns(val) {
imageGridColumns = val;
localStorage.setItem('gridColumns', val);
},
set postGridPreviewQuality(val) {
postGridPreviewQuality = val
localStorage.setItem('gridPreviewQuality', val);
},
set blacklist(val) {
blacklist = val
localStorage.setItem('blacklist', val);
},
set limitImageHeight(val) {
limitImageHeight = val
localStorage.setItem('limitImageHeight', val);
},
}
}

View file

@ -1,5 +1,4 @@
<script>
import '../app.pcss';
import { loading } from '$lib/stores.js';
import { Fa } from 'svelte-fa';
import { faSpinner } from '@fortawesome/free-solid-svg-icons';
@ -7,16 +6,59 @@
let { children } = $props();
</script>
<div class="bg-gray-200">
{@render children?.()}
{#if $loading}
<div class="absolute bottom-4 right-4 spin">
{@render children?.()}
{#if $loading}
<div class="loading spin">
<Fa size={'2x'} icon={faSpinner}></Fa>
</div>
{/if}
</div>
{/if}
<style lang="postcss">
:global(*) {
box-sizing: border-box;
}
:global(body) {
color: #fff;
margin: 0;
padding: 0;
background-color: #9ca3af;
}
:global(h1, h2, h3, h4, h5, h6) {
font: inherit;
font-weight: bold;
}
:global(p) {
font: inherit;
margin: 0;
padding: 0;
font-size: 1rem;
}
:global(h1) {
font-size: 2rem;
}
:global(input) {
border: none;
margin: 0;
padding: 0 4px;
min-height: 40px;
color: #000;
}
:global(button) {
border: none;
}
.loading {
position: absolute;
bottom: 10px;
right: 10px;
}
.spin {
animation: spin 2s infinite;
}

View file

@ -2,16 +2,14 @@
import { Header, ImageGrid } from '$lib/components';
import { invoke } from '@tauri-apps/api/core'
import PostList from '$lib/PostList';
import useSettings from "$lib/useSettings.svelte.js";
import {onMount} from "svelte";
import {loading, postSearchResults} from "$lib/stores.js";
import {onMount} from 'svelte';
import {loading, postSearchResults, blacklist, lastSearch} from '$lib/stores.js';
const settings = useSettings();
function onSearch(val = '', explicitRefresh = false) {
loading.set(true);
invoke('get_posts', { query: val }).then((resPosts) => {
postSearchResults.set(new PostList(resPosts).filterPosts(settings.blacklist).getPosts())
postSearchResults.set(new PostList(resPosts).filterPosts($blacklist).getPosts())
loading.set(false)
});
}
@ -24,18 +22,45 @@
}
if ($postSearchResults === null) {
onSearch(settings.lastSearch, true);
onSearch($lastSearch, true);
}
})
</script>
<div>
<Header onsubmit={(val = '', explicitRefresh = false) => {onSearch(val, explicitRefresh);}}></Header>
<div class="container">
<Header gridArea="header" onsubmit={(val = '', explicitRefresh = false) => {onSearch(val, explicitRefresh);}}></Header>
<main>
<div class="overflow-scroll p-2">
{#if $postSearchResults}
{#if !$loading}
{#if $postSearchResults && $postSearchResults.length > 0}
<ImageGrid posts={$postSearchResults} />
{:else}
<p>No search results found</p>
{/if}
{/if}
</div>
</main>
</div>
<style>
.container {
padding: 0 10px;
max-width: 1200px;
margin: 0 auto;
display: grid;
grid-template-areas: "header header header" "main main main";
}
aside {
grid-area: aside;
}
main {
grid-area: main;
}
@media (min-width: 1210px) {
.container {
padding: 0;
}
}
</style>

View file

@ -1,6 +1,4 @@
<script>
import { faStar, faCaretUp, faCaretDown, faHeart, faCopy } from '@fortawesome/free-solid-svg-icons';
import { Fa } from 'svelte-fa';
import { PostMedia, Header } from '$lib/components';
import { onMount } from 'svelte';
import { TAG_TYPES } from '$lib/Tags';
@ -19,77 +17,80 @@
});
</script>
<div class="grid [grid-template-areas:'header_header_header''main_main_aside']">
<Header class="[grid-area:header]" back={2} showSearch={false} onsubmit={(val = '') => {
<div class="container">
<Header back={2} showSearch={false} onsubmit={(val = '') => {
const queryParams = new URLSearchParams();
queryParams.set('search', val);
goto("/?" + queryParams.toString())
}}></Header>
<main class="[grid-area:main]">
<main id="container-main">
{#if post}
<div class="flex flex-col">
<PostMedia class="max-h-[95vh] w-auto" {post} />
<section class="flex flex-row justify-between bg-black">
<div class="flex flex-row px-2 gap-2">
<button class="py-2 px-3 flex flex-row place-items-center gap-1 text-white hover:text-black hover:bg-white">
<span class:accent-yellow-50={!post.is_favorited} class:accent-yellow-500={post.is_favorited}>
<Fa size={'1.5x'} icon={faHeart} />
</span>
&nbsp;
<span>
{post.fav_count}
</span>
</button>
<button class="py-2 px-3 flex flex-row place-items-center text-white hover:text-black hover:bg-white">
<span class="text-secondary-500">
<Fa size={'1.5x'} icon={faStar} />
</span>
&nbsp;
{post.score.total}
</button>
<button class="py-2 px-3 flex flex-row place-items-center text-white hover:text-black hover:bg-white">
<Fa size={'1.5x'} icon={faCaretUp} />
</button>
<button class="py-2 px-3 flex flex-row place-items-center text-white hover:text-black hover:bg-white">
<Fa size={'1.5x'} icon={faCaretDown} />
</button>
</div>
<div class="flex flex-row px-2 gap-2">
<button class="py-2 px-3 flex flex-row place-items-center text-white hover:text-black hover:bg-white"
onclick={async () => {await navigator.clipboard.writeText(`https://e621.net/posts/${post.id}`)}}>
<Fa size={'1.5x'} icon={faCopy} />
</button>
<button class="py-2 px-3 flex flex-row place-items-center text-white hover:text-black hover:bg-white">
ID: {post.id}
</button>
</div>
</section>
<footer class="card-footer py-4 px-2">
<h3 class="font-bold mb-2" class:line-through={post.description === ''} >Description</h3>
<p class="text-wrap">{post.description}</p>
<!--<pre>{JSON.stringify(post, null, 4)}</pre>-->
<div class="post-main">
<PostMedia {post} />
<footer id="post-footer">
<h3 style:text-decoration={post.description === '' ? 'strike-trough' : 'none' } >Description</h3>
<p>{post.description}</p>
</footer>
</div>
{/if}
</main>
<aside class="[grid-area:aside]">
<aside id="container-aside">
{#if post}
<div class="p-2">
{#each tagTypes as [name, label]}
{#if post.tags[name].length > 0}
<div class="mb-2">
<p class="font-bold">{label}</p>
<div class="tags-type-wrapper">
<p class="tag-type">{label}</p>
{#each post.tags[name] as tag}
<p>{tag}</p>
<p class="tag">{tag}</p>
{/each}
</div>
{/if}
{/each}
</div>
{/if}
</aside>
<footer id="container-footer">
</footer>
</div>
<style lang="postcss"></style>
<style>
.container {
max-width: 1200px;
margin: 0 auto;
display: grid;
grid-template-areas: "header header header" "aside main main" "footer footer footer";
grid-gap: 20px;
}
.tag-type {
font-weight: bold;
}
.post-main {
display: flex;
flex-flow: column;
}
#container-main {
grid-area: main;
}
#container-aside {
min-width: 300px;
grid-area: aside;
display: flex;
flex-flow: column;
gap: 10px;
}
#container-footer {
grid-area: footer;
}
#post-footer {
margin-top: 10px;
}
</style>

View file

@ -1,12 +0,0 @@
<script>
import {goto} from "$app/navigation";
import {Header} from "$lib/components/index.js";
</script>
<div class="grid [grid-template-areas:'header_header_header''main_main_aside']">
<Header class="[grid-area:header]" back={2} showSearch={false} onsubmit={(val = '') => {
const queryParams = new URLSearchParams();
queryParams.set('search', val);
goto("/?" + queryParams.toString())
}}></Header>
</div>

View file

@ -0,0 +1,35 @@
<script>
import {LinkButton} from "$lib/components";
</script>
<nav>
<ul>
<li>
<LinkButton href="/settings/main" fill={true}>
Main
</LinkButton>
</li>
<li>
<LinkButton href="/settings/display" fill={true}>
Display
</LinkButton>
</li>
<li>
<LinkButton href="/settings/blacklist" fill={true}>
Blacklist
</LinkButton>
</li>
</ul>
</nav>
<style>
ul {
display: flex;
flex-flow: column wrap;
gap: 10px;
}
li {
width: 100%;
}
</style>

View file

@ -0,0 +1,48 @@
<script>
import {goto} from '$app/navigation';
import {Chips, Header} from '$lib/components';
import SettingsNav from '../SettingsNav.svelte';
import {blacklist} from '$lib/stores.js';
</script>
<div class="container">
<Header gridArea="header" back={2} showSearch={false} onsubmit={(val = '') => {
const queryParams = new URLSearchParams();
queryParams.set('search', val);
goto("/?" + queryParams.toString());
}}></Header>
<aside>
<SettingsNav></SettingsNav>
</aside>
<main>
{JSON.stringify($blacklist)}
<!--<Chips bind:values={$blacklist} onAdd={val => {
$blacklist.push(val);
}}></Chips>-->
</main>
</div>
<style>
.container {
padding: 0 10px;
max-width: 1200px;
margin: 0 auto;
display: grid;
grid-template-areas: "header header header" "aside main main";
gap: 10px;
}
aside {
grid-area: aside;
}
main {
grid-area: main;
}
@media (min-width: 1210px) {
.container {
padding: 0;
}
}
</style>

View file

@ -0,0 +1,43 @@
<script>
import {goto} from "$app/navigation";
import {Header, Chips} from "$lib/components";
import SettingsNav from "../SettingsNav.svelte";
</script>
<div class="container">
<Header gridArea="header" back={2} showSearch={false} onsubmit={(val = '') => {
const queryParams = new URLSearchParams();
queryParams.set('search', val);
goto("/?" + queryParams.toString());
}}></Header>
<aside>
<SettingsNav></SettingsNav>
</aside>
<main>
</main>
</div>
<style>
.container {
padding: 0 10px;
max-width: 1200px;
margin: 0 auto;
display: grid;
grid-template-areas: "header header header" "aside main main";
gap: 10px;
}
aside {
grid-area: aside;
}
main {
grid-area: main;
}
@media (min-width: 1210px) {
.container {
padding: 0;
}
}
</style>