add search, improve SLayout
This commit is contained in:
parent
ddb07a651e
commit
1dc5768640
11 changed files with 153 additions and 15 deletions
15
src/app.d.ts
vendored
15
src/app.d.ts
vendored
|
|
@ -1,10 +1,21 @@
|
|||
// See https://svelte.dev/docs/kit/types#app.d.ts
|
||||
|
||||
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
interface Locals {
|
||||
results?: object[],
|
||||
query?: string,
|
||||
me: UserEntry | null
|
||||
}
|
||||
interface PageData {
|
||||
site: ServerHealth | null,
|
||||
me: UserEntry | null,
|
||||
results?: object[],
|
||||
query?: string
|
||||
}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
|
|
|
|||
9
src/hooks.server.ts
Normal file
9
src/hooks.server.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { getMe } from "$lib/globals.svelte";
|
||||
import type { Handle } from "@sveltejs/kit";
|
||||
|
||||
|
||||
export const handle: Handle = async ({event, resolve }) => {
|
||||
event.locals.me = getMe();
|
||||
|
||||
return resolve(event);
|
||||
}
|
||||
13
src/lib/BigSearchInput.svelte
Normal file
13
src/lib/BigSearchInput.svelte
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<script lang="ts">
|
||||
|
||||
let { query = $bindable<string>() }: {query?: string} = $props();
|
||||
</script>
|
||||
|
||||
<input value={query} type="search" name="query" class="bigsearch" />
|
||||
|
||||
<style>
|
||||
.bigsearch {
|
||||
width: 100%;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
|
||||
let { user } : {user: UserEntry} = $props();
|
||||
let enable_search = $state(false);
|
||||
let enable_search = $derived(user !== null);
|
||||
|
||||
</script>
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ let enable_search = $state(false);
|
|||
method="POST"
|
||||
class="mini-search-bar nomobile">
|
||||
<!-- csrf_token() -->
|
||||
<input type="search" disabled={true} name="q" placeholder="Search among {activePostCount()} posts" />
|
||||
<input type="search" name="q" placeholder="Search among {activePostCount()} posts" />
|
||||
<button type="submit">Search</button>
|
||||
</form>
|
||||
<a href="/search" aria-label="Search" title="Search" class="mobileonly">
|
||||
|
|
@ -98,7 +98,7 @@ let enable_search = $state(false);
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mini-search-bar + a {display: none}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,18 +2,21 @@
|
|||
import { RiInformationLine, RiMenu3Line, RiShieldLine } from "svelte-remixicon";
|
||||
|
||||
let { children, title, left, right } = $props();
|
||||
|
||||
let mobiLeftActive = $state(false);
|
||||
let mobiRightActive = $state(false);
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div class="layout">
|
||||
<div class="layout-title">{title}</div>
|
||||
<div class="layout-left">{@render left()}</div>
|
||||
<div class="layout-left" class:active={mobiLeftActive}>{@render left()}</div>
|
||||
<div class="layout-content">{@render children()}</div>
|
||||
<div class="layout-right">{@render right()}</div>
|
||||
<div class="layout-right" class:active={mobiRightActive}>{@render right()}</div>
|
||||
|
||||
<div class="layout-licon" onclick={() => {}}><RiMenu3Line /></div>
|
||||
<div class="layout-ricon" onclick={() => {}}><RiInformationLine /></div>
|
||||
<div class="layout-licon" onclick={() => {mobiLeftActive = !mobiLeftActive;}}><RiMenu3Line /></div>
|
||||
<div class="layout-ricon" onclick={() => {mobiRightActive = !mobiRightActive;}}><RiInformationLine /></div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
|
@ -26,15 +29,31 @@ let { children, title, left, right } = $props();
|
|||
". title ."
|
||||
"left center right";
|
||||
margin: 1em 2em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.layout-left { grid-area: left; }
|
||||
.layout-right { grid-area: right; }
|
||||
.layout-left { grid-area: left; padding-right: 1em; }
|
||||
.layout-right { grid-area: right; padding-left: 1em; }
|
||||
.layout-content { grid-area: center; }
|
||||
.layout-title { grid-area: title; text-align: center; font-size: 1.4em; }
|
||||
|
||||
|
||||
@media (min-width: 800px) {
|
||||
.layout {
|
||||
grid-template-columns: 180px auto 180px;
|
||||
}
|
||||
|
||||
.layout-licon, .layout-ricon { display: none; }
|
||||
|
||||
}
|
||||
@media (min-width: 800px) and (max-width: 919px) {
|
||||
.layout-left, .layout-right {
|
||||
font-size: smaller;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (min-width: 920px) {
|
||||
.layout {
|
||||
grid-template-columns: 240px auto 240px;
|
||||
}
|
||||
|
|
@ -42,7 +61,7 @@ let { children, title, left, right } = $props();
|
|||
.layout-licon, .layout-ricon { display: none; }
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
@media (min-width: 1000px) {
|
||||
.layout {
|
||||
grid-template-columns: 270px auto 270px;
|
||||
}
|
||||
|
|
@ -70,6 +89,24 @@ let { children, title, left, right } = $props();
|
|||
}
|
||||
|
||||
.layout-left, .layout-right { display: none; }
|
||||
|
||||
.layout-left.active, .layout-right.active {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 2.5em;
|
||||
width: 80%;
|
||||
min-height: calc(100vh - 6em);
|
||||
background-color: var(--canvas);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.layout-left.active {
|
||||
left: 0;
|
||||
}
|
||||
.layout-right.active {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ async function loadMe(event: LoadEvent, me?: string): Promise<UserEntry | null>
|
|||
}
|
||||
|
||||
|
||||
export async function load(event): Promise<{site: ServerHealth | null, me: UserEntry | null} > {
|
||||
export async function load(event) {
|
||||
let site = await loadSite(event);
|
||||
let me = await loadMe (event, site?.me || void 0);
|
||||
return { site, me };
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { backend } from '$lib/backend.js';
|
||||
import { backend } from '$lib/backend';
|
||||
import { error } from '@sveltejs/kit';
|
||||
|
||||
export async function load(event) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export async function load (event) {
|
|||
redirect(303, next);
|
||||
}
|
||||
|
||||
// cookies managed by backend
|
||||
const resp = await backend.withEvent(event).fetch("logout", {method: 'POST'});
|
||||
|
||||
if ([200, 204].indexOf(resp.status) >= 0) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
import { backend } from '$lib/backend';
|
||||
import type { Action, Actions } from '@sveltejs/kit';
|
||||
|
||||
|
||||
|
||||
export const actions = {
|
||||
default: async (event) => {
|
||||
const { request } = event;
|
||||
const data = await request.formData()
|
||||
|
||||
const query = data.get("query");
|
||||
if ("string" !== typeof query) {
|
||||
console.log("query is", query);
|
||||
return;
|
||||
}
|
||||
|
||||
const client = await backend.withEvent(event).oath();
|
||||
const resp = await client.submitJson('search/top', { query });
|
||||
|
||||
const { status } = resp;
|
||||
const respData = await resp.json();
|
||||
|
||||
if (status !== 200) {
|
||||
event.locals.results = [];
|
||||
event.locals.query = query;
|
||||
console.log({ query, status })
|
||||
return;
|
||||
}
|
||||
|
||||
const { has: results } = respData;
|
||||
|
||||
event.locals.results = results;
|
||||
event.locals.query = query;
|
||||
console.log(event.locals);
|
||||
return
|
||||
}
|
||||
} satisfies Actions;
|
||||
|
||||
export async function load (event) {
|
||||
const { results, query } = event.locals;
|
||||
|
||||
console.log({ results, query });
|
||||
return { results, query };
|
||||
}
|
||||
|
||||
22
src/routes/search/+page.svelte
Normal file
22
src/routes/search/+page.svelte
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<script lang="ts">
|
||||
import { enhance } from "$app/forms";
|
||||
import BigSearchInput from "$lib/BigSearchInput.svelte";
|
||||
import Feed from "$lib/Feed.svelte";
|
||||
import { RiSearchLine } from "svelte-remixicon";
|
||||
import type { PageProps } from "./$types";
|
||||
|
||||
let { data }: PageProps = $props();
|
||||
let { query, results } = $derived(data);
|
||||
</script>
|
||||
|
||||
<form method="POST" use:enhance>
|
||||
<ul class="row">
|
||||
<BigSearchInput bind:query />
|
||||
<button class="inline"><RiSearchLine /></button>
|
||||
</ul>
|
||||
</form>
|
||||
{#if query}
|
||||
<Feed posts={results} />
|
||||
{/if}
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue