mirror of
https://github.com/zoriya/vex.git
synced 2026-08-16 02:44:55 +00:00
Imported timelineItem in the codebase
This commit is contained in:
@@ -42,6 +42,8 @@ services:
|
||||
- 5173:5173
|
||||
environment:
|
||||
- API_URL=http://api:1597
|
||||
depends_on:
|
||||
- api
|
||||
|
||||
volumes:
|
||||
db:
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
|
||||
<article>
|
||||
<div>
|
||||
<img src={feed.faviconUrl} alt={feed.title} />
|
||||
<h3>{feed.title}</h3>
|
||||
<img src={feed.faviconUrl} alt={feed.name} />
|
||||
<h3>{feed.name}</h3>
|
||||
</div>
|
||||
<div>
|
||||
<span>{feed.url}</span>
|
||||
<span>{feed.link}</span>
|
||||
</div>
|
||||
{#if feed.submitter}
|
||||
<div>
|
||||
|
||||
@@ -14,14 +14,16 @@
|
||||
>
|
||||
<article>
|
||||
<div class="origin">
|
||||
<img src={post.feed.faviconUrl} alt={post.feed.title} />
|
||||
<span>{post.feed.title}</span> |
|
||||
{#if post.author}
|
||||
<div class="author">
|
||||
<QuillPenLine />
|
||||
<span>{post.author}</span>
|
||||
</div>
|
||||
|
|
||||
<img src={post.feed.faviconUrl} alt={post.feed.name} />
|
||||
<span>{post.feed.name}</span> |
|
||||
{#if post.authors?.length}
|
||||
{#each post.authors as author}
|
||||
<div class="author">
|
||||
<QuillPenLine />
|
||||
<span>{author}</span>
|
||||
</div>
|
||||
|
|
||||
{/each}
|
||||
{/if}
|
||||
<Time
|
||||
timestamp={post.date}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
<script lang="ts">
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { getContext } from "svelte";
|
||||
import Time, { dayjs } from "svelte-time";
|
||||
import { P } from "flowbite-svelte";
|
||||
import QuillPenLine from "virtual:icons/mingcute/quill-pen-line";
|
||||
import type { Post } from "$lib/types";
|
||||
export let title: string = "";
|
||||
export let date: string = "";
|
||||
export let post: Post;
|
||||
export let svgClass: string =
|
||||
"w-3 h-3 text-primary-600 dark:text-primary-400";
|
||||
|
||||
let order: "default" | "vertical" | "horizontal" | "activity" | "group" =
|
||||
"default";
|
||||
order = getContext("order");
|
||||
const liClasses = {
|
||||
default: "mb-10 ms-4",
|
||||
vertical: "mb-10 ms-6",
|
||||
horizontal: "relative mb-6 sm:mb-0",
|
||||
activity: "mb-10 ms-6",
|
||||
group: "",
|
||||
};
|
||||
|
||||
const divClasses = {
|
||||
default:
|
||||
"absolute w-3 h-3 bg-gray-200 rounded-full mt-1.5 -start-1.5 border border-white dark:border-gray-900 dark:bg-gray-700",
|
||||
vertical:
|
||||
"flex absolute -start-3 justify-center items-center w-6 h-6 bg-primary-200 rounded-full ring-8 ring-white dark:ring-gray-900 dark:bg-primary-900",
|
||||
horizontal: "flex items-center",
|
||||
activity:
|
||||
"flex absolute -start-3 justify-center items-center w-6 h-6 bg-primary-200 rounded-full ring-8 ring-white dark:ring-gray-900 dark:bg-primary-900",
|
||||
group:
|
||||
"p-5 mb-4 bg-gray-50 rounded-lg border border-gray-100 dark:bg-gray-800 dark:border-gray-700",
|
||||
};
|
||||
|
||||
const timeClasses = {
|
||||
default:
|
||||
"mb-1 text-sm font-normal leading-none text-gray-400 dark:text-gray-500",
|
||||
vertical:
|
||||
"block mb-2 text-sm font-normal leading-none text-gray-400 dark:text-gray-500",
|
||||
horizontal:
|
||||
"block mb-2 text-sm font-normal leading-none text-gray-400 dark:text-gray-500",
|
||||
activity: "mb-1 text-xs font-normal text-gray-400 sm:order-last sm:mb-0",
|
||||
group: "text-lg font-semibold text-gray-900 dark:text-white",
|
||||
};
|
||||
|
||||
let liCls: string = twMerge(liClasses[order], $$props.classLi);
|
||||
let divCls: string = twMerge(divClasses[order], $$props.classDiv);
|
||||
let timeCls: string = twMerge(timeClasses[order], $$props.classTime);
|
||||
const h3Cls = twMerge(
|
||||
order === "vertical"
|
||||
? "flex items-center mb-1 text-lg font-semibold text-gray-900 dark:text-white"
|
||||
: "text-lg font-semibold text-gray-900 dark:text-white",
|
||||
$$props.classH3,
|
||||
);
|
||||
</script>
|
||||
|
||||
<li class={liCls}>
|
||||
<div class={divCls} />
|
||||
{#if order !== "default"}
|
||||
<slot name="icon">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class={svgClass}
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</slot>
|
||||
{:else if date}
|
||||
<time class={timeCls}>{date}</time>
|
||||
{/if}
|
||||
|
||||
{#if title}
|
||||
<a href={post.link} target="_blank">
|
||||
<h3 class={h3Cls}>
|
||||
{title}
|
||||
</h3>
|
||||
</a>
|
||||
{/if}
|
||||
|
||||
{#if order !== "default"}
|
||||
<div class="font-light text-sm text-slate-500">
|
||||
<span>{post.feed.name}</span> |
|
||||
{#if post.authors?.length}
|
||||
{#each post.authors as author}
|
||||
<div class="author">
|
||||
<QuillPenLine />
|
||||
<span>{author}</span>
|
||||
</div>
|
||||
|
|
||||
{/each}
|
||||
{/if}
|
||||
<Time
|
||||
timestamp={post.date}
|
||||
relative={true}
|
||||
title={dayjs(post.date).locale("en").toString()}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<slot />
|
||||
</li>
|
||||
@@ -33,5 +33,6 @@ export async function getPosts(token?: string) {
|
||||
}
|
||||
const r = await fetch(env.API_URL + '/entries', token ? opts : undefined);
|
||||
const j = await r.json();
|
||||
return j.posts as Post[];
|
||||
console.log(j);
|
||||
return j as Post[];
|
||||
}
|
||||
@@ -2,8 +2,8 @@ import type { User } from "./user.type";
|
||||
|
||||
export type Feed = {
|
||||
id: string;
|
||||
title: string;
|
||||
url: string;
|
||||
name: string;
|
||||
link: string;
|
||||
faviconUrl: string;
|
||||
tags: string[];
|
||||
submitterId: string;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<slot></slot>
|
||||
|
||||
<footer>
|
||||
<!-- <footer>
|
||||
<BottomNav position="absolute" classInner="grid-cols-2">
|
||||
<BottomNavItem btnName="Posts">
|
||||
<HomeSolid
|
||||
@@ -20,4 +20,4 @@
|
||||
/>
|
||||
</BottomNavItem>
|
||||
</BottomNav>
|
||||
</footer>
|
||||
</footer> -->
|
||||
|
||||
@@ -5,8 +5,8 @@ import { get } from "svelte/store";
|
||||
const feeds: Feed[] = [
|
||||
{
|
||||
id: "1",
|
||||
title: "The first feed",
|
||||
url: "https://example.com/feed",
|
||||
name: "The first feed",
|
||||
link: "https://example.com/feed",
|
||||
faviconUrl: "https://kit.svelte.dev/favicon.png",
|
||||
tags: ["tag1", "tag2"],
|
||||
submitterId: "1",
|
||||
@@ -14,8 +14,8 @@ const feeds: Feed[] = [
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
title: "Phoronix",
|
||||
url: "https://www.phoronix.com",
|
||||
name: "Phoronix",
|
||||
link: "https://www.phoronix.com",
|
||||
faviconUrl: "https://www.phoronix.com/favicon.ico",
|
||||
tags: ["linux", "kernel", "gnu", "gnu/linux", "gnu+linux", "gnu linux"],
|
||||
submitterId: "1",
|
||||
@@ -23,8 +23,8 @@ const feeds: Feed[] = [
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
title: "LWN.net",
|
||||
url: "https://lwn.net",
|
||||
name: "LWN.net",
|
||||
link: "https://lwn.net",
|
||||
faviconUrl: "https://lwn.net/favicon.ico",
|
||||
tags: ["linux", "kernel", "gnu", "gnu/linux", "gnu+linux", "gnu linux"],
|
||||
submitterId: "1",
|
||||
@@ -60,9 +60,9 @@ const posts: Post[] = [
|
||||
}
|
||||
];
|
||||
|
||||
export function load() {
|
||||
export async function load() {
|
||||
return {
|
||||
posts: getPosts(),
|
||||
posts: await getPosts(),
|
||||
feeds
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,23 +5,69 @@
|
||||
BottomNavItem,
|
||||
Skeleton,
|
||||
ImagePlaceholder,
|
||||
Avatar,
|
||||
P,
|
||||
} from "flowbite-svelte";
|
||||
import List from "$lib/posts/list.svelte";
|
||||
import { CalendarWeekSolid } from "flowbite-svelte-icons";
|
||||
import TimelineItem from "$lib/posts/timeline-item.svelte";
|
||||
import { Timeline, TimelineItem as TI } from "flowbite-svelte";
|
||||
import {
|
||||
HomeSolid,
|
||||
WalletSolid,
|
||||
AdjustmentsVerticalOutline,
|
||||
UserCircleSolid,
|
||||
} from "flowbite-svelte-icons";
|
||||
|
||||
$: displayPosts = (data?.posts || []).map((post) => {
|
||||
let dateStr = post.feed.name + " - ";
|
||||
dateStr += new Date(post.date).toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
});
|
||||
|
||||
if (post.authors && post.authors.length > 0) {
|
||||
dateStr += ` by ${post.authors.join(", ")}`;
|
||||
}
|
||||
return {
|
||||
...post,
|
||||
dateStr,
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<List posts={data.posts} />
|
||||
<Timeline order="vertical" class="max-w-3xl">
|
||||
{#each displayPosts as post}
|
||||
<TimelineItem title={post.title} date={post.dateStr} post={post}>
|
||||
<svelte:fragment slot="icon">
|
||||
<span
|
||||
class="flex absolute -start-3 justify-center items-center w-6 h-6 bg-primary-200 rounded-full ring-8 ring-white dark:ring-gray-900 dark:bg-primary-900"
|
||||
>
|
||||
<Avatar
|
||||
src={post.feed.faviconUrl}
|
||||
alt={post.feed.name}
|
||||
class="w-4 h-4 -start-2 -top-2"
|
||||
/>
|
||||
</span>
|
||||
</svelte:fragment>
|
||||
<p
|
||||
class="mb-4 text-base font-normal text-gray-500 dark:text-gray-400 line-clamp-2"
|
||||
>
|
||||
{#if post.content}
|
||||
{post.content}
|
||||
{/if}
|
||||
</p>
|
||||
</TimelineItem>
|
||||
{/each}
|
||||
</Timeline>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
main {
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { fail } from '@sveltejs/kit';
|
||||
import { fail, redirect } from '@sveltejs/kit';
|
||||
import { login, register } from '$lib/server/api.js';
|
||||
|
||||
|
||||
@@ -8,9 +8,8 @@ export const actions = {
|
||||
const email = data.get('email');
|
||||
const password = data.get('password');
|
||||
const token = await login(email as any, password as any);
|
||||
return {
|
||||
token
|
||||
};
|
||||
cookies.set('token', token, { path: '/', maxAge: 60 * 60 * 24 * 365 * 2 });
|
||||
throw redirect(303, '/');
|
||||
},
|
||||
register: async ({ cookies, request }) => {
|
||||
const data = await request.formData();
|
||||
@@ -30,8 +29,7 @@ export const actions = {
|
||||
})
|
||||
}
|
||||
const token = await register(email as any, username as any, password as any);
|
||||
return {
|
||||
token
|
||||
};
|
||||
cookies.set('token', token, { path: '/', maxAge: 60 * 60 * 24 * 365 * 2 });
|
||||
throw redirect(303, '/');
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user