SquidSpirit 3cb69f6e7c
All checks were successful
Frontend CI / build (push) Successful in 1m8s
BLOG-45 Post content page (#67)
### Description

- Implement the content page
  - Parse markdown formant content to html by `markdown-it`
  - Use `sanitize-html` to prevent from XSS attack
  - Style the html with `tailwindcss-typography`
- Fix the issue when backend parse the password to url
- Fix and make the post info list from backend always sorted by id

### Package Changes

### Rust

```toml
percent-encoding = "2.3.1"
```

### Node

```json
{
  "@types/markdown-it": "^14.1.2",
  "@types/sanitize-html": "^2.16.0",
  "markdown-it": "^14.1.0",
  "sanitize-html": "^2.17.0"
}
```

### Screenshots

|Desktop|Mobile|
|-|-|
|![image.png](/attachments/0ec5718a-f804-432f-8e4b-e9dc22c080d2)|![beta.squidspirit.com_post(iPhone 12 Pro) (1).png](/attachments/b30d1b96-d4a4-4b2b-b9bd-90fd2592ab52)|

### Reference

Resolves #45

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #67
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-07-24 22:20:58 +08:00

63 lines
1.5 KiB
TypeScript

import { StatusType, type AsyncState } from '$lib/common/adapter/presenter/asyncState';
import { PostViewModel } from '$lib/post/adapter/presenter/postViewModel';
import type { GetPostUseCase } from '$lib/post/application/useCase/getPostUseCase';
import { get, writable } from 'svelte/store';
export type PostState = AsyncState<PostViewModel>;
export type PostEvent = PostLoadedEvent;
export class PostBloc {
private readonly state = writable<PostState>({
status: StatusType.Idle
});
constructor(
private readonly getPostUseCase: GetPostUseCase,
initialData?: PostViewModel
) {
this.state.set({
status: StatusType.Idle,
data: initialData
});
}
get subscribe() {
return this.state.subscribe;
}
async dispatch(event: PostEvent): Promise<PostState> {
switch (event.event) {
case PostEventType.PostLoadedEvent:
return this.loadPost(event.id);
}
}
private async loadPost(id: number): Promise<PostState> {
this.state.set({ status: StatusType.Loading, data: get(this.state).data });
const post = await this.getPostUseCase.execute(id);
if (!post) {
this.state.set({ status: StatusType.Error, error: new Error('Post not found') });
return get(this.state);
}
const postViewModel = PostViewModel.fromEntity(post);
const result: PostState = {
status: StatusType.Success,
data: postViewModel
};
this.state.set(result);
return result;
}
}
export enum PostEventType {
PostLoadedEvent
}
export interface PostLoadedEvent {
event: PostEventType.PostLoadedEvent;
id: number;
}