BLOG-44 Post overall page #64
@ -25,7 +25,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@apply bg-white font-sans text-base font-normal text-gray-600;
|
@apply bg-white font-sans text-base font-normal text-gray-800;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre,
|
pre,
|
||||||
|
@ -34,9 +34,9 @@
|
|||||||
|
|
||||||
<span
|
<span
|
||||||
bind:this={element}
|
bind:this={element}
|
||||||
class="rounded-md bg-blue-600 px-1 py-0.5 text-white transition-transform delay-500 duration-1000 md:rounded-lg md:px-2.5 md:py-2 {origin} {isReady
|
class="rounded-md bg-blue-600 px-1 py-0.5 text-white transition-transform delay-500 duration-1000 md:rounded-lg md:px-2.5 md:py-2
|
||||||
? 'scale-x-100'
|
{origin}
|
||||||
: 'scale-x-0'}"
|
{isReady ? 'scale-x-100' : 'scale-x-0'}"
|
||||||
>
|
>
|
||||||
<span class="scale-x-100">{text}</span>
|
<span class="scale-x-100">{text}</span>
|
||||||
</span>
|
</span>
|
||||||
|
@ -57,7 +57,7 @@
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
bind:this={element}
|
bind:this={element}
|
||||||
class="flex w-full flex-col gap-y-1.5 rounded-2xl border-4 border-true-gray-800 bg-true-gray-700 p-4 pb-28 font-mono font-medium text-gray-50 shadow-lg transition-opacity duration-300 md:gap-y-2.5 md:rounded-3xl md:border-8 md:p-8 md:pb-32 md:text-xl md:shadow-xl {isReady
|
class="flex w-full flex-col gap-y-1.5 rounded-2xl border-4 border-true-gray-800 bg-true-gray-700 p-4 pb-28 font-mono font-medium text-gray-50 shadow-lg transition-opacity duration-300 md:gap-y-2.5 md:rounded-3xl md:border-8 md:p-8 md:pb-32 md:text-lg md:shadow-xl {isReady
|
||||||
? 'opacity-100'
|
? 'opacity-100'
|
||||||
: 'opacity-0'}"
|
: 'opacity-0'}"
|
||||||
>
|
>
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
const tagsCollection = [
|
const tagsCollection = [
|
||||||
'APP',
|
'APP',
|
||||||
'C++',
|
'C++',
|
||||||
|
'Clean Architecture',
|
||||||
'Design Pattern',
|
'Design Pattern',
|
||||||
'Docker',
|
'Docker',
|
||||||
'Flutter',
|
'Flutter',
|
||||||
@ -12,7 +13,10 @@
|
|||||||
'LINER',
|
'LINER',
|
||||||
'Linux',
|
'Linux',
|
||||||
'Python',
|
'Python',
|
||||||
|
'React',
|
||||||
|
'Rust',
|
||||||
'Squid',
|
'Squid',
|
||||||
|
'Svelte',
|
||||||
'TypeScript',
|
'TypeScript',
|
||||||
'中央大學',
|
'中央大學',
|
||||||
'全端',
|
'全端',
|
||||||
@ -20,9 +24,7 @@
|
|||||||
'前端',
|
'前端',
|
||||||
'後端',
|
'後端',
|
||||||
'教學',
|
'教學',
|
||||||
'暴肝',
|
|
||||||
'知識',
|
'知識',
|
||||||
'碼農',
|
|
||||||
'科技',
|
'科技',
|
||||||
'科普',
|
'科普',
|
||||||
'程式設計',
|
'程式設計',
|
||||||
@ -64,7 +66,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class={`relative w-full max-w-screen-md transition-opacity duration-500 ${isTagsVisible ? 'opacity-100' : 'opacity-0'}`}
|
class="relative w-full max-w-screen-md transition-opacity duration-500
|
||||||
|
{isTagsVisible ? 'opacity-100' : 'opacity-0'}"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="absolute inset-0 bg-gradient-to-r from-transparent via-transparent via-60% to-white"
|
class="absolute inset-0 bg-gradient-to-r from-transparent via-transparent via-60% to-white"
|
||||||
|
42
frontend/src/lib/post/adapter/gateway/colorResponseDto.ts
Normal file
42
frontend/src/lib/post/adapter/gateway/colorResponseDto.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { Color } from '$lib/post/domain/entity/color';
|
||||||
|
import z from 'zod';
|
||||||
|
|
||||||
|
export const ColorResponseSchema = z.object({
|
||||||
|
red: z.number().int().min(0).max(255),
|
||||||
|
green: z.number().int().min(0).max(255),
|
||||||
|
blue: z.number().int().min(0).max(255),
|
||||||
|
alpha: z.number().int().min(0).max(255)
|
||||||
|
});
|
||||||
|
|
||||||
|
export class ColorResponseDto {
|
||||||
|
readonly red: number;
|
||||||
|
readonly green: number;
|
||||||
|
readonly blue: number;
|
||||||
|
readonly alpha: number;
|
||||||
|
|
||||||
|
private constructor(props: { red: number; green: number; blue: number; alpha: number }) {
|
||||||
|
this.red = props.red;
|
||||||
|
this.green = props.green;
|
||||||
|
this.blue = props.blue;
|
||||||
|
this.alpha = props.alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJson(json: unknown): ColorResponseDto {
|
||||||
|
const parsedJson = ColorResponseSchema.parse(json);
|
||||||
|
return new ColorResponseDto({
|
||||||
|
red: parsedJson.red,
|
||||||
|
green: parsedJson.green,
|
||||||
|
blue: parsedJson.blue,
|
||||||
|
alpha: parsedJson.alpha
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toEntity(): Color {
|
||||||
|
return new Color({
|
||||||
|
red: this.red,
|
||||||
|
green: this.green,
|
||||||
|
blue: this.blue,
|
||||||
|
alpha: this.alpha
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,19 @@
|
|||||||
|
import { ColorResponseDto, ColorResponseSchema } from '$lib/post/adapter/gateway/colorResponseDto';
|
||||||
import { Label } from '$lib/post/domain/entity/label';
|
import { Label } from '$lib/post/domain/entity/label';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const LabelResponseSchema = z.object({
|
export const LabelResponseSchema = z.object({
|
||||||
id: z.int32(),
|
id: z.int32(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
color: z.string().startsWith('#').length(9)
|
color: ColorResponseSchema
|
||||||
});
|
});
|
||||||
|
|
||||||
export class LabelResponseDto {
|
export class LabelResponseDto {
|
||||||
readonly id: number;
|
readonly id: number;
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
readonly color: string;
|
readonly color: ColorResponseDto;
|
||||||
|
|
||||||
private constructor(props: { id: number; name: string; color: string }) {
|
private constructor(props: { id: number; name: string; color: ColorResponseDto }) {
|
||||||
this.id = props.id;
|
this.id = props.id;
|
||||||
this.name = props.name;
|
this.name = props.name;
|
||||||
this.color = props.color;
|
this.color = props.color;
|
||||||
@ -23,7 +24,7 @@ export class LabelResponseDto {
|
|||||||
return new LabelResponseDto({
|
return new LabelResponseDto({
|
||||||
id: parsedJson.id,
|
id: parsedJson.id,
|
||||||
name: parsedJson.name,
|
name: parsedJson.name,
|
||||||
color: parsedJson.color
|
color: ColorResponseDto.fromJson(parsedJson.color)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ export const PostInfoResponseSchema = z.object({
|
|||||||
description: z.string(),
|
description: z.string(),
|
||||||
preview_image_url: z.url(),
|
preview_image_url: z.url(),
|
||||||
labels: z.array(LabelResponseSchema),
|
labels: z.array(LabelResponseSchema),
|
||||||
published_time: z.number().int(),
|
published_time: z.number().int()
|
||||||
});
|
});
|
||||||
|
|
||||||
export class PostInfoResponseDto {
|
export class PostInfoResponseDto {
|
||||||
@ -42,8 +42,8 @@ export class PostInfoResponseDto {
|
|||||||
title: parsedJson.title,
|
title: parsedJson.title,
|
||||||
description: parsedJson.description,
|
description: parsedJson.description,
|
||||||
previewImageUrl: new URL(parsedJson.preview_image_url),
|
previewImageUrl: new URL(parsedJson.preview_image_url),
|
||||||
labels: parsedJson.labels.map((label) => LabelResponseDto.fromJson(JSON.stringify(label))),
|
labels: parsedJson.labels.map((label) => LabelResponseDto.fromJson(label)),
|
||||||
publishedTime: new Date(parsedJson.published_time / 1000),
|
publishedTime: new Date(parsedJson.published_time / 1000)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ export class PostInfoResponseDto {
|
|||||||
description: this.description,
|
description: this.description,
|
||||||
previewImageUrl: this.previewImageUrl,
|
previewImageUrl: this.previewImageUrl,
|
||||||
labels: this.labels.map((label) => label.toEntity()),
|
labels: this.labels.map((label) => label.toEntity()),
|
||||||
publishedTime: this.publishedTime,
|
publishedTime: this.publishedTime
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
114
frontend/src/lib/post/adapter/presenter/colorViewModel.ts
Normal file
114
frontend/src/lib/post/adapter/presenter/colorViewModel.ts
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import type { Color } from '$lib/post/domain/entity/color';
|
||||||
|
|
||||||
|
export class ColorViewModel {
|
||||||
|
readonly red: number;
|
||||||
|
readonly green: number;
|
||||||
|
readonly blue: number;
|
||||||
|
readonly alpha: number;
|
||||||
|
|
||||||
|
private constructor(props: { red: number; green: number; blue: number; alpha: number }) {
|
||||||
|
this.red = props.red;
|
||||||
|
this.green = props.green;
|
||||||
|
this.blue = props.blue;
|
||||||
|
this.alpha = props.alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static fromHsl(hsl: Hsl): ColorViewModel {
|
||||||
|
const { h, s, l } = hsl;
|
||||||
|
let r, g, b;
|
||||||
|
|
||||||
|
if (s === 0) {
|
||||||
|
// achromatic (grayscale)
|
||||||
|
r = g = b = l;
|
||||||
|
} else {
|
||||||
|
const hue2rgb = (p: number, q: number, t: number) => {
|
||||||
|
if (t < 0) t += 1;
|
||||||
|
if (t > 1) t -= 1;
|
||||||
|
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
||||||
|
if (t < 1 / 2) return q;
|
||||||
|
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
||||||
|
return p;
|
||||||
|
};
|
||||||
|
|
||||||
|
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||||
|
const p = 2 * l - q;
|
||||||
|
const h_norm = h / 360;
|
||||||
|
|
||||||
|
r = hue2rgb(p, q, h_norm + 1 / 3);
|
||||||
|
g = hue2rgb(p, q, h_norm);
|
||||||
|
b = hue2rgb(p, q, h_norm - 1 / 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ColorViewModel({
|
||||||
|
red: Math.round(r * 255),
|
||||||
|
green: Math.round(g * 255),
|
||||||
|
blue: Math.round(b * 255),
|
||||||
|
alpha: 255
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromEntity(color: Color): ColorViewModel {
|
||||||
|
return new ColorViewModel({
|
||||||
|
red: color.red,
|
||||||
|
green: color.green,
|
||||||
|
blue: color.blue,
|
||||||
|
alpha: color.alpha
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get hex(): string {
|
||||||
|
const toHex = (value: number) => value.toString(16).padStart(2, '0');
|
||||||
|
return `#${toHex(this.red)}${toHex(this.green)}${toHex(this.blue)}${toHex(this.alpha)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private toHsl(): Hsl {
|
||||||
|
const r = this.red / 255;
|
||||||
|
const g = this.green / 255;
|
||||||
|
const b = this.blue / 255;
|
||||||
|
|
||||||
|
const max = Math.max(r, g, b);
|
||||||
|
const min = Math.min(r, g, b);
|
||||||
|
let h = 0,
|
||||||
|
s = 0;
|
||||||
|
const l = (max + min) / 2;
|
||||||
|
|
||||||
|
if (max === min) {
|
||||||
|
// achromatic (grayscale)
|
||||||
|
h = s = 0;
|
||||||
|
} else {
|
||||||
|
const d = max - min;
|
||||||
|
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||||
|
switch (max) {
|
||||||
|
case r:
|
||||||
|
h = (g - b) / d + (g < b ? 6 : 0);
|
||||||
|
break;
|
||||||
|
case g:
|
||||||
|
h = (b - r) / d + 2;
|
||||||
|
break;
|
||||||
|
case b:
|
||||||
|
h = (r - g) / d + 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
h /= 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { h: h * 360, s: s, l: l };
|
||||||
|
}
|
||||||
|
|
||||||
|
lighten(amount: number): ColorViewModel {
|
||||||
|
const hsl = this.toHsl();
|
||||||
|
hsl.l += amount;
|
||||||
|
hsl.l = Math.max(0, Math.min(1, hsl.l));
|
||||||
|
return ColorViewModel.fromHsl(hsl);
|
||||||
|
}
|
||||||
|
|
||||||
|
darken(amount: number): ColorViewModel {
|
||||||
|
return this.lighten(-amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Hsl {
|
||||||
|
h: number;
|
||||||
|
s: number;
|
||||||
|
l: number;
|
||||||
|
}
|
@ -1,19 +1,22 @@
|
|||||||
|
import { ColorViewModel } from '$lib/post/adapter/presenter/colorViewModel';
|
||||||
|
import type { Label } from '$lib/post/domain/entity/label';
|
||||||
|
|
||||||
export class LabelViewModel {
|
export class LabelViewModel {
|
||||||
readonly id: number;
|
readonly id: number;
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
readonly color: string;
|
readonly color: ColorViewModel;
|
||||||
|
|
||||||
private constructor(props: { id: number; name: string; color: string }) {
|
private constructor(props: { id: number; name: string; color: ColorViewModel }) {
|
||||||
this.id = props.id;
|
this.id = props.id;
|
||||||
this.name = props.name;
|
this.name = props.name;
|
||||||
this.color = props.color;
|
this.color = props.color;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromEntity(label: { id: number; name: string; color: string }): LabelViewModel {
|
static fromEntity(label: Label): LabelViewModel {
|
||||||
return new LabelViewModel({
|
return new LabelViewModel({
|
||||||
id: label.id,
|
id: label.id,
|
||||||
name: label.name,
|
name: label.name,
|
||||||
color: label.color
|
color: ColorViewModel.fromEntity(label.color)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
frontend/src/lib/post/domain/entity/color.ts
Normal file
13
frontend/src/lib/post/domain/entity/color.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export class Color {
|
||||||
|
readonly red: number;
|
||||||
|
readonly green: number;
|
||||||
|
readonly blue: number;
|
||||||
|
readonly alpha: number;
|
||||||
|
|
||||||
|
constructor(props: { red: number; green: number; blue: number; alpha: number }) {
|
||||||
|
this.red = props.red;
|
||||||
|
this.green = props.green;
|
||||||
|
this.blue = props.blue;
|
||||||
|
this.alpha = props.alpha;
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
|
import type { Color } from '$lib/post/domain/entity/color';
|
||||||
|
|
||||||
export class Label {
|
export class Label {
|
||||||
readonly id: number;
|
readonly id: number;
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
readonly color: string;
|
readonly color: Color;
|
||||||
|
|
||||||
constructor(props: { id: number; name: string; color: string }) {
|
constructor(props: { id: number; name: string; color: Color }) {
|
||||||
this.id = props.id;
|
this.id = props.id;
|
||||||
this.name = props.name;
|
this.name = props.name;
|
||||||
this.color = props.color;
|
this.color = props.color;
|
||||||
|
@ -1,23 +1,22 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { StatusType } from '$lib/common/adapter/presenter/asyncState';
|
import { StatusType } from '$lib/common/adapter/presenter/asyncState';
|
||||||
import { PostListBloc, PostListEventType } from '$lib/post/adapter/presenter/postListBloc';
|
import { PostListBloc, PostListEventType } from '$lib/post/adapter/presenter/postListBloc';
|
||||||
|
import PostPreview from '$lib/post/framework/ui/PostPreview.svelte';
|
||||||
import { getContext, onMount } from 'svelte';
|
import { getContext, onMount } from 'svelte';
|
||||||
|
|
||||||
const postListBloc = getContext<PostListBloc>(PostListBloc.name);
|
const postListBloc = getContext<PostListBloc>(PostListBloc.name);
|
||||||
let state = $derived($postListBloc);
|
const state = $derived($postListBloc);
|
||||||
|
|
||||||
$inspect(state, 'PostListBloc State');
|
|
||||||
|
|
||||||
onMount(() => postListBloc.dispatch({ event: PostListEventType.PostListLoadedEvent }));
|
onMount(() => postListBloc.dispatch({ event: PostListEventType.PostListLoadedEvent }));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="py-9 text-center text-3xl font-bold text-gray-800 md:py-20 md:text-5xl">文章</div>
|
<div class="py-9 text-center text-3xl font-bold text-gray-800 md:py-20 md:text-5xl">文章</div>
|
||||||
{#if state.status === StatusType.Loading || state.status === StatusType.Idle}
|
{#if state.status === StatusType.Success}
|
||||||
<div>Loading</div>
|
<div class="grid grid-cols-1 gap-6 md:grid-cols-2 md:gap-y-8 lg:grid-cols-3">
|
||||||
{:else if state.status === StatusType.Success}
|
{#each state.data as postInfo (postInfo.id)}
|
||||||
<div>{JSON.stringify(state.data)}</div>
|
<PostPreview {postInfo} />
|
||||||
{:else}
|
{/each}
|
||||||
<div class="text-red-500">Error loading posts</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
41
frontend/src/lib/post/framework/ui/PostPreview.svelte
Normal file
41
frontend/src/lib/post/framework/ui/PostPreview.svelte
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { PostInfoViewModel } from '$lib/post/adapter/presenter/postInfoViewModel';
|
||||||
|
import PostPreviewLabels from '$lib/post/framework/ui/PostPreviewLabels.svelte';
|
||||||
|
|
||||||
|
const { postInfo }: { postInfo: PostInfoViewModel } = $props();
|
||||||
|
|
||||||
|
let isImageLoading = $state(true);
|
||||||
|
let isImageError = $state(false);
|
||||||
|
|
||||||
|
function handleImageLoad() {
|
||||||
|
isImageLoading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleImageError() {
|
||||||
|
isImageLoading = false;
|
||||||
|
isImageError = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<a class="flex cursor-pointer flex-col gap-y-4" href="/post/{postInfo.id}">
|
||||||
|
<div class="relative aspect-video overflow-hidden rounded-2xl bg-gray-200">
|
||||||
|
<img
|
||||||
|
class="rounded-2xl object-cover transition-opacity duration-300
|
||||||
|
{isImageLoading ? 'opacity-0' : 'opacity-100'}
|
||||||
|
{isImageError ? 'hidden' : ''}"
|
||||||
|
src={postInfo.previewImageUrl.href}
|
||||||
|
alt={postInfo.title}
|
||||||
|
onload={handleImageLoad}
|
||||||
|
onerror={handleImageError}
|
||||||
|
/>
|
||||||
|
{#if isImageLoading || isImageError}
|
||||||
|
<div class="absolute inset-0 flex items-center justify-center bg-gray-200"></div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-1.5">
|
||||||
|
<PostPreviewLabels labels={postInfo.labels} />
|
||||||
|
<span class="line-clamp-1 font-bold">{postInfo.title}</span>
|
||||||
|
<span class="line-clamp-3 text-justify text-sm">{postInfo.description}</span>
|
||||||
|
<span class="text-sm text-gray-500">查看更多 ⭢</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
25
frontend/src/lib/post/framework/ui/PostPreviewLabels.svelte
Normal file
25
frontend/src/lib/post/framework/ui/PostPreviewLabels.svelte
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { LabelViewModel } from '$lib/post/adapter/presenter/labelViewModel';
|
||||||
|
|
||||||
|
const { labels }: { labels: readonly LabelViewModel[] } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex flex-row gap-x-2 text-xs">
|
||||||
|
{#each labels.slice(0, 2) as label (label.id)}
|
||||||
|
<div
|
||||||
|
class="flex flex-row items-center gap-x-1 rounded-full px-2 py-0.5"
|
||||||
|
style="background-color: {label.color.hex};"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="size-2 rounded-full"
|
||||||
|
style="background-color: {label.color.darken(0.2).hex};"
|
||||||
|
></div>
|
||||||
|
<span>{label.name}</span>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{#if labels.length > 2}
|
||||||
|
<div class="rounded-full bg-gray-200 px-2 py-0.5">
|
||||||
|
<span>+{labels.length - 2}</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
@ -3,7 +3,7 @@
|
|||||||
import { PostListBloc } from '$lib/post/adapter/presenter/postListBloc';
|
import { PostListBloc } from '$lib/post/adapter/presenter/postListBloc';
|
||||||
import { GetAllPostUseCase } from '$lib/post/application/useCase/getAllPostsUseCase';
|
import { GetAllPostUseCase } from '$lib/post/application/useCase/getAllPostsUseCase';
|
||||||
import { PostApiServiceImpl } from '$lib/post/framework/api/postApiServiceImpl';
|
import { PostApiServiceImpl } from '$lib/post/framework/api/postApiServiceImpl';
|
||||||
import PostListPage from '$lib/post/framework/ui/PostListPage.svelte';
|
import PostOverallPage from '$lib/post/framework/ui/PostOverallPage.svelte';
|
||||||
import { setContext } from 'svelte';
|
import { setContext } from 'svelte';
|
||||||
|
|
||||||
const postApiService = new PostApiServiceImpl();
|
const postApiService = new PostApiServiceImpl();
|
||||||
@ -14,4 +14,4 @@
|
|||||||
setContext(PostListBloc.name, postListBloc);
|
setContext(PostListBloc.name, postListBloc);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<PostListPage />
|
<PostOverallPage />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user