rename blocks to widgets

This commit is contained in:
Ren Amamiya
2023-08-11 15:25:33 +07:00
parent 0cfc3a48d8
commit 36b2acba6a
22 changed files with 118 additions and 107 deletions

View File

@@ -0,0 +1,3 @@
-- Add migration script here
ALTER TABLE blocks
RENAME TO widgets;

View File

@@ -110,6 +110,12 @@ fn main() {
sql: include_str!("../migrations/20230808085847_add_relays_table.sql"), sql: include_str!("../migrations/20230808085847_add_relays_table.sql"),
kind: MigrationKind::Up, kind: MigrationKind::Up,
}, },
Migration {
version: 20230811074423,
description: "rename blocks to widgets",
sql: include_str!("../migrations/20230811074423_rename_blocks_to_widgets.sql"),
kind: MigrationKind::Up,
},
], ],
) )
.build(), .build(),

View File

@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { Link, useNavigate } from 'react-router-dom'; import { Link, useNavigate } from 'react-router-dom';
import { createBlock } from '@libs/storage'; import { createWidget } from '@libs/storage';
import { ArrowRightCircleIcon, CheckCircleIcon, LoaderIcon } from '@shared/icons'; import { ArrowRightCircleIcon, CheckCircleIcon, LoaderIcon } from '@shared/icons';
@@ -50,7 +50,7 @@ export function OnboardStep2Screen() {
setLoading(true); setLoading(true);
for (const tag of tags) { for (const tag of tags) {
await createBlock(BLOCK_KINDS.hashtag, tag, tag.replace('#', '')); await createWidget(BLOCK_KINDS.hashtag, tag, tag.replace('#', ''));
} }
setTimeout(() => navigate('/auth/onboarding/step-3', { replace: true }), 1000); setTimeout(() => navigate('/auth/onboarding/step-3', { replace: true }), 1000);

View File

@@ -9,11 +9,11 @@ import { NoteKindUnsupport } from '@shared/notes/kinds/unsupport';
import { NoteSkeleton } from '@shared/notes/skeleton'; import { NoteSkeleton } from '@shared/notes/skeleton';
import { TitleBar } from '@shared/titleBar'; import { TitleBar } from '@shared/titleBar';
import { Block, LumeEvent } from '@utils/types'; import { LumeEvent, Widget } from '@utils/types';
const ITEM_PER_PAGE = 10; const ITEM_PER_PAGE = 10;
export function FeedBlock({ params }: { params: Block }) { export function FeedBlock({ params }: { params: Widget }) {
const { status, data, fetchNextPage, hasNextPage, isFetchingNextPage } = const { status, data, fetchNextPage, hasNextPage, isFetchingNextPage } =
useInfiniteQuery({ useInfiniteQuery({
queryKey: ['newsfeed', params.content], queryKey: ['newsfeed', params.content],

View File

@@ -8,9 +8,9 @@ import { NoteKind_1, NoteSkeleton } from '@shared/notes';
import { TitleBar } from '@shared/titleBar'; import { TitleBar } from '@shared/titleBar';
import { nHoursAgo } from '@utils/date'; import { nHoursAgo } from '@utils/date';
import { Block, LumeEvent } from '@utils/types'; import { LumeEvent, Widget } from '@utils/types';
export function HashtagBlock({ params }: { params: Block }) { export function HashtagBlock({ params }: { params: Widget }) {
const { relayUrls, fetcher } = useNDK(); const { relayUrls, fetcher } = useNDK();
const { status, data } = useQuery(['hashtag', params.content], async () => { const { status, data } = useQuery(['hashtag', params.content], async () => {
const events = (await fetcher.fetchAllEvents( const events = (await fetcher.fetchAllEvents(

View File

@@ -1,13 +1,13 @@
import { CancelIcon } from '@shared/icons'; import { CancelIcon } from '@shared/icons';
import { Image } from '@shared/image'; import { Image } from '@shared/image';
import { useBlocks } from '@stores/blocks';
import { DEFAULT_AVATAR } from '@stores/constants'; import { DEFAULT_AVATAR } from '@stores/constants';
import { useWidgets } from '@stores/widgets';
import { Block } from '@utils/types'; import { Widget } from '@utils/types';
export function ImageBlock({ params }: { params: Block }) { export function ImageBlock({ params }: { params: Widget }) {
const removeBlock = useBlocks((state) => state.removeBlock); const remove = useWidgets((state) => state.removeWidget);
return ( return (
<div className="flex h-full w-[400px] shrink-0 flex-col justify-between"> <div className="flex h-full w-[400px] shrink-0 flex-col justify-between">
@@ -17,7 +17,7 @@ export function ImageBlock({ params }: { params: Block }) {
<h3 className="font-medium text-white drop-shadow-lg">{params.title}</h3> <h3 className="font-medium text-white drop-shadow-lg">{params.title}</h3>
<button <button
type="button" type="button"
onClick={() => removeBlock(params.id)} onClick={() => remove(params.id)}
className="inline-flex h-7 w-7 items-center justify-center rounded-md bg-white/30 backdrop-blur-lg" className="inline-flex h-7 w-7 items-center justify-center rounded-md bg-white/30 backdrop-blur-lg"
> >
<CancelIcon width={16} height={16} className="text-white" /> <CancelIcon width={16} height={16} className="text-white" />

View File

@@ -12,9 +12,9 @@ import { TitleBar } from '@shared/titleBar';
import { useAccount } from '@utils/hooks/useAccount'; import { useAccount } from '@utils/hooks/useAccount';
import { useEvent } from '@utils/hooks/useEvent'; import { useEvent } from '@utils/hooks/useEvent';
import { Block } from '@utils/types'; import { Widget } from '@utils/types';
export function ThreadBlock({ params }: { params: Block }) { export function ThreadBlock({ params }: { params: Widget }) {
const { status, data } = useEvent(params.content); const { status, data } = useEvent(params.content);
const { account } = useAccount(); const { account } = useAccount();

View File

@@ -9,9 +9,9 @@ import { TitleBar } from '@shared/titleBar';
import { UserProfile } from '@shared/userProfile'; import { UserProfile } from '@shared/userProfile';
import { nHoursAgo } from '@utils/date'; import { nHoursAgo } from '@utils/date';
import { Block, LumeEvent } from '@utils/types'; import { LumeEvent, Widget } from '@utils/types';
export function UserBlock({ params }: { params: Block }) { export function UserBlock({ params }: { params: Widget }) {
const parentRef = useRef<HTMLDivElement>(null); const parentRef = useRef<HTMLDivElement>(null);
const { fetcher, relayUrls } = useNDK(); const { fetcher, relayUrls } = useNDK();

View File

@@ -8,7 +8,7 @@ import { useHotkeys } from 'react-hotkeys-hook';
import { User } from '@app/auth/components/user'; import { User } from '@app/auth/components/user';
import { createBlock } from '@libs/storage'; import { createWidget } from '@libs/storage';
import { CancelIcon, CheckCircleIcon, CommandIcon, LoaderIcon } from '@shared/icons'; import { CancelIcon, CheckCircleIcon, CommandIcon, LoaderIcon } from '@shared/icons';
@@ -31,7 +31,7 @@ export function FeedModal() {
const block = useMutation({ const block = useMutation({
mutationFn: (data: { kind: number; title: string; content: string }) => { mutationFn: (data: { kind: number; title: string; content: string }) => {
return createBlock(data.kind, data.title, data.content); return createWidget(data.kind, data.title, data.content);
}, },
onSuccess: () => { onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['blocks'] }); queryClient.invalidateQueries({ queryKey: ['blocks'] });

View File

@@ -4,7 +4,7 @@ import { useState } from 'react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { createBlock } from '@libs/storage'; import { createWidget } from '@libs/storage';
import { CancelIcon, CommandIcon, LoaderIcon } from '@shared/icons'; import { CancelIcon, CommandIcon, LoaderIcon } from '@shared/icons';
@@ -28,7 +28,7 @@ export function HashtagModal() {
const block = useMutation({ const block = useMutation({
mutationFn: (data: { kind: number; title: string; content: string }) => { mutationFn: (data: { kind: number; title: string; content: string }) => {
return createBlock(data.kind, data.title, data.content); return createWidget(data.kind, data.title, data.content);
}, },
onSuccess: () => { onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['blocks'] }); queryClient.invalidateQueries({ queryKey: ['blocks'] });

View File

@@ -4,7 +4,7 @@ import { useEffect, useRef, useState } from 'react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { createBlock } from '@libs/storage'; import { createWidget } from '@libs/storage';
import { CancelIcon, CommandIcon, LoaderIcon } from '@shared/icons'; import { CancelIcon, CommandIcon, LoaderIcon } from '@shared/icons';
import { Image } from '@shared/image'; import { Image } from '@shared/image';
@@ -39,7 +39,7 @@ export function ImageModal() {
const block = useMutation({ const block = useMutation({
mutationFn: (data: { kind: number; title: string; content: string }) => { mutationFn: (data: { kind: number; title: string; content: string }) => {
return createBlock(data.kind, data.title, data.content); return createWidget(data.kind, data.title, data.content);
}, },
onSuccess: () => { onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['blocks'] }); queryClient.invalidateQueries({ queryKey: ['blocks'] });

View File

@@ -12,48 +12,51 @@ import { ImageModal } from '@app/space/components/modals/image';
import { LoaderIcon } from '@shared/icons'; import { LoaderIcon } from '@shared/icons';
import { useBlocks } from '@stores/blocks'; import { useWidgets } from '@stores/widgets';
import { Block } from '@utils/types'; import { Widget } from '@utils/types';
export function SpaceScreen() { export function SpaceScreen() {
const [blocks, fetchBlocks] = useBlocks((state) => [state.blocks, state.fetchBlocks]); const [widgets, fetchWidgets] = useWidgets((state) => [
state.widgets,
state.fetchWidgets,
]);
const renderBlock = useCallback( const renderItem = useCallback(
(block: Block) => { (widget: Widget) => {
switch (block.kind) { switch (widget.kind) {
case 0: case 0:
return <ImageBlock key={block.id} params={block} />; return <ImageBlock key={widget.id} params={widget} />;
case 1: case 1:
return <FeedBlock key={block.id} params={block} />; return <FeedBlock key={widget.id} params={widget} />;
case 2: case 2:
return <ThreadBlock key={block.id} params={block} />; return <ThreadBlock key={widget.id} params={widget} />;
case 3: case 3:
return <HashtagBlock key={block.id} params={block} />; return <HashtagBlock key={widget.id} params={widget} />;
case 5: case 5:
return <UserBlock key={block.id} params={block} />; return <UserBlock key={widget.id} params={widget} />;
default: default:
break; break;
} }
}, },
[blocks] [widgets]
); );
useEffect(() => { useEffect(() => {
fetchBlocks(); fetchWidgets();
}, [fetchBlocks]); }, [fetchWidgets]);
return ( return (
<div className="scrollbar-hide flex h-full w-full flex-nowrap divide-x divide-white/5 overflow-x-auto overflow-y-hidden"> <div className="scrollbar-hide flex h-full w-full flex-nowrap divide-x divide-white/5 overflow-x-auto overflow-y-hidden">
<NetworkBlock /> <NetworkBlock />
{!blocks ? ( {!widgets ? (
<div className="flex w-[350px] shrink-0 flex-col"> <div className="flex w-[350px] shrink-0 flex-col">
<div className="flex w-full flex-1 items-center justify-center p-3"> <div className="flex w-full flex-1 items-center justify-center p-3">
<LoaderIcon className="h-5 w-5 animate-spin text-white/10" /> <LoaderIcon className="h-5 w-5 animate-spin text-white/10" />
</div> </div>
</div> </div>
) : ( ) : (
blocks.map((block) => renderBlock(block)) widgets.map((widget) => renderItem(widget))
)} )}
<div className="flex w-[350px] shrink-0 flex-col"> <div className="flex w-[350px] shrink-0 flex-col">
<div className="inline-flex h-full w-full flex-col items-center justify-center gap-1"> <div className="inline-flex h-full w-full flex-col items-center justify-center gap-1">

View File

@@ -5,12 +5,12 @@ import { parser } from '@utils/parser';
import { getParentID } from '@utils/transform'; import { getParentID } from '@utils/transform';
import { import {
Account, Account,
Block,
Chats, Chats,
LumeEvent, LumeEvent,
Profile, Profile,
Relays, Relays,
Settings, Settings,
Widget,
} from '@utils/types'; } from '@utils/types';
let db: null | Database = null; let db: null | Database = null;
@@ -66,7 +66,7 @@ export async function createAccount(
[npub, pubkey, 'privkey is stored in secure storage', follows || '', is_active || 0] [npub, pubkey, 'privkey is stored in secure storage', follows || '', is_active || 0]
); );
if (res) { if (res) {
await createBlock( await createWidget(
0, 0,
'Have fun together!', 'Have fun together!',
'https://void.cat/d/N5KUHEQCVg7SywXUPiJ7yq.jpg' 'https://void.cat/d/N5KUHEQCVg7SywXUPiJ7yq.jpg'
@@ -417,18 +417,18 @@ export async function updateLastLogin(value: number) {
); );
} }
// get all blocks // get all widgets
export async function getBlocks() { export async function getWidgets() {
const db = await connect(); const db = await connect();
const account = await getActiveAccount(); const account = await getActiveAccount();
const result: Array<Block> = await db.select( const result: Array<Widget> = await db.select(
`SELECT * FROM blocks WHERE account_id = "${account.id}" ORDER BY created_at DESC;` `SELECT * FROM widgets WHERE account_id = "${account.id}" ORDER BY created_at DESC;`
); );
return result; return result;
} }
// create block // create block
export async function createBlock( export async function createWidget(
kind: number, kind: number,
title: string, title: string,
content: string | string[] content: string | string[]
@@ -436,13 +436,13 @@ export async function createBlock(
const db = await connect(); const db = await connect();
const activeAccount = await getActiveAccount(); const activeAccount = await getActiveAccount();
const insert = await db.execute( const insert = await db.execute(
'INSERT OR IGNORE INTO blocks (account_id, kind, title, content) VALUES (?, ?, ?, ?);', 'INSERT OR IGNORE INTO widgets (account_id, kind, title, content) VALUES (?, ?, ?, ?);',
[activeAccount.id, kind, title, content] [activeAccount.id, kind, title, content]
); );
if (insert) { if (insert) {
const record: Block = await db.select( const record: Widget = await db.select(
'SELECT * FROM blocks ORDER BY id DESC LIMIT 1;' 'SELECT * FROM widgets ORDER BY id DESC LIMIT 1;'
); );
return record[0]; return record[0];
} else { } else {
@@ -451,9 +451,9 @@ export async function createBlock(
} }
// remove block // remove block
export async function removeBlock(id: string) { export async function removeWidget(id: string) {
const db = await connect(); const db = await connect();
return await db.execute(`DELETE FROM blocks WHERE id = "${id}";`); return await db.execute(`DELETE FROM widgets WHERE id = "${id}";`);
} }
// logout // logout
@@ -462,8 +462,7 @@ export async function removeAll() {
await db.execute(`UPDATE settings SET value = "0" WHERE key = "last_login";`); await db.execute(`UPDATE settings SET value = "0" WHERE key = "last_login";`);
await db.execute('DELETE FROM replies;'); await db.execute('DELETE FROM replies;');
await db.execute('DELETE FROM notes;'); await db.execute('DELETE FROM notes;');
await db.execute('DELETE FROM blacklist;'); await db.execute('DELETE FROM widgets;');
await db.execute('DELETE FROM blocks;');
await db.execute('DELETE FROM chats;'); await db.execute('DELETE FROM chats;');
await db.execute('DELETE FROM accounts;'); await db.execute('DELETE FROM accounts;');
return true; return true;

View File

@@ -7,8 +7,8 @@ import { NoteReply } from '@shared/notes/actions/reply';
import { NoteRepost } from '@shared/notes/actions/repost'; import { NoteRepost } from '@shared/notes/actions/repost';
import { NoteZap } from '@shared/notes/actions/zap'; import { NoteZap } from '@shared/notes/actions/zap';
import { useBlocks } from '@stores/blocks';
import { BLOCK_KINDS } from '@stores/constants'; import { BLOCK_KINDS } from '@stores/constants';
import { useWidgets } from '@stores/widgets';
import { useAccount } from '@utils/hooks/useAccount'; import { useAccount } from '@utils/hooks/useAccount';
@@ -24,7 +24,7 @@ export function NoteActions({
root?: string; root?: string;
}) { }) {
const { account } = useAccount(); const { account } = useAccount();
const setBlock = useBlocks((state) => state.setBlock); const setWidget = useWidgets((state) => state.setWidget);
return ( return (
<Tooltip.Provider> <Tooltip.Provider>
@@ -43,7 +43,7 @@ export function NoteActions({
<button <button
type="button" type="button"
onClick={() => onClick={() =>
setBlock({ setWidget({
kind: BLOCK_KINDS.thread, kind: BLOCK_KINDS.thread,
title: 'Thread', title: 'Thread',
content: id, content: id,

View File

@@ -1,14 +1,14 @@
import { useBlocks } from '@stores/blocks';
import { BLOCK_KINDS } from '@stores/constants'; import { BLOCK_KINDS } from '@stores/constants';
import { useWidgets } from '@stores/widgets';
export function Hashtag({ tag }: { tag: string }) { export function Hashtag({ tag }: { tag: string }) {
const setBlock = useBlocks((state) => state.setBlock); const setWidget = useWidgets((state) => state.setWidget);
return ( return (
<button <button
type="button" type="button"
onClick={() => onClick={() =>
setBlock({ setWidget({
kind: BLOCK_KINDS.hashtag, kind: BLOCK_KINDS.hashtag,
title: tag, title: tag,
content: tag.replace('#', ''), content: tag.replace('#', ''),

View File

@@ -5,19 +5,19 @@ import remarkGfm from 'remark-gfm';
import { MentionUser, NoteSkeleton } from '@shared/notes'; import { MentionUser, NoteSkeleton } from '@shared/notes';
import { User } from '@shared/user'; import { User } from '@shared/user';
import { useBlocks } from '@stores/blocks';
import { BLOCK_KINDS } from '@stores/constants'; import { BLOCK_KINDS } from '@stores/constants';
import { useWidgets } from '@stores/widgets';
import { useEvent } from '@utils/hooks/useEvent'; import { useEvent } from '@utils/hooks/useEvent';
export const MentionNote = memo(function MentionNote({ id }: { id: string }) { export const MentionNote = memo(function MentionNote({ id }: { id: string }) {
const { status, data } = useEvent(id); const { status, data } = useEvent(id);
const setBlock = useBlocks((state) => state.setBlock); const setWidget = useWidgets((state) => state.setWidget);
const openThread = (event, thread: string) => { const openThread = (event, thread: string) => {
const selection = window.getSelection(); const selection = window.getSelection();
if (selection.toString().length === 0) { if (selection.toString().length === 0) {
setBlock({ kind: BLOCK_KINDS.thread, title: 'Thread', content: thread }); setWidget({ kind: BLOCK_KINDS.thread, title: 'Thread', content: thread });
} else { } else {
event.stopPropagation(); event.stopPropagation();
} }

View File

@@ -1,18 +1,18 @@
import { useBlocks } from '@stores/blocks';
import { BLOCK_KINDS } from '@stores/constants'; import { BLOCK_KINDS } from '@stores/constants';
import { useWidgets } from '@stores/widgets';
import { useProfile } from '@utils/hooks/useProfile'; import { useProfile } from '@utils/hooks/useProfile';
import { displayNpub } from '@utils/shortenKey'; import { displayNpub } from '@utils/shortenKey';
export function MentionUser({ pubkey }: { pubkey: string }) { export function MentionUser({ pubkey }: { pubkey: string }) {
const { user } = useProfile(pubkey); const { user } = useProfile(pubkey);
const setBlock = useBlocks((state) => state.setBlock); const setWidget = useWidgets((state) => state.setWidget);
return ( return (
<button <button
type="button" type="button"
onClick={() => onClick={() =>
setBlock({ setWidget({
kind: BLOCK_KINDS.user, kind: BLOCK_KINDS.user,
title: user?.nip05 || user?.name || user?.displayNam, title: user?.nip05 || user?.name || user?.displayNam,
content: pubkey, content: pubkey,

View File

@@ -8,13 +8,13 @@ import { createReplyNote } from '@libs/storage';
import { LoaderIcon } from '@shared/icons'; import { LoaderIcon } from '@shared/icons';
import { MiniUser } from '@shared/notes/users/mini'; import { MiniUser } from '@shared/notes/users/mini';
import { useBlocks } from '@stores/blocks';
import { BLOCK_KINDS } from '@stores/constants'; import { BLOCK_KINDS } from '@stores/constants';
import { useWidgets } from '@stores/widgets';
import { compactNumber } from '@utils/number'; import { compactNumber } from '@utils/number';
export function NoteMetadata({ id }: { id: string }) { export function NoteMetadata({ id }: { id: string }) {
const setBlock = useBlocks((state) => state.setBlock); const setWidget = useWidgets((state) => state.setWidget);
const { ndk } = useNDK(); const { ndk } = useNDK();
const { status, data } = useQuery( const { status, data } = useQuery(
@@ -96,7 +96,7 @@ export function NoteMetadata({ id }: { id: string }) {
<button <button
type="button" type="button"
onClick={() => onClick={() =>
setBlock({ kind: BLOCK_KINDS.thread, title: 'Thread', content: id }) setWidget({ kind: BLOCK_KINDS.thread, title: 'Thread', content: id })
} }
className="text-white/50" className="text-white/50"
> >

View File

@@ -1,9 +1,9 @@
import { CancelIcon } from '@shared/icons'; import { CancelIcon } from '@shared/icons';
import { useBlocks } from '@stores/blocks'; import { useWidgets } from '@stores/widgets';
export function TitleBar({ id, title }: { id?: string; title: string }) { export function TitleBar({ id, title }: { id?: string; title: string }) {
const removeBlock = useBlocks((state) => state.removeBlock); const remove = useWidgets((state) => state.removeWidget);
return ( return (
<div <div
@@ -15,7 +15,7 @@ export function TitleBar({ id, title }: { id?: string; title: string }) {
{id ? ( {id ? (
<button <button
type="button" type="button"
onClick={() => removeBlock(id)} onClick={() => remove(id)}
className="inline-flex h-6 w-6 shrink translate-y-8 transform items-center justify-center rounded transition-transform duration-150 ease-in-out hover:bg-white/10 group-hover:translate-y-0" className="inline-flex h-6 w-6 shrink translate-y-8 transform items-center justify-center rounded transition-transform duration-150 ease-in-out hover:bg-white/10 group-hover:translate-y-0"
> >
<CancelIcon className="h-3 w-3 text-white" /> <CancelIcon className="h-3 w-3 text-white" />

View File

@@ -1,37 +0,0 @@
import { create } from 'zustand';
import { createJSONStorage, persist } from 'zustand/middleware';
import { createBlock, getBlocks, removeBlock } from '@libs/storage';
import { Block } from '@utils/types';
interface BlockState {
blocks: null | Array<Block>;
fetchBlocks: () => void;
setBlock: ({ kind, title, content }: Block) => void;
removeBlock: (id: string) => void;
}
export const useBlocks = create<BlockState>()(
persist(
(set) => ({
blocks: null,
fetchBlocks: async () => {
const blocks = await getBlocks();
set({ blocks: blocks });
},
setBlock: async ({ kind, title, content }: Block) => {
const block: Block = await createBlock(kind, title, content);
set((state) => ({ blocks: [...state.blocks, block] }));
},
removeBlock: async (id: string) => {
await removeBlock(id);
set((state) => ({ blocks: state.blocks.filter((block) => block.id !== id) }));
},
}),
{
name: 'blocks',
storage: createJSONStorage(() => localStorage),
}
)
);

37
src/stores/widgets.tsx Normal file
View File

@@ -0,0 +1,37 @@
import { create } from 'zustand';
import { createJSONStorage, persist } from 'zustand/middleware';
import { createWidget, getWidgets, removeWidget } from '@libs/storage';
import { Widget } from '@utils/types';
interface WidgetState {
widgets: null | Array<Widget>;
fetchWidgets: () => void;
setWidget: ({ kind, title, content }: Widget) => void;
removeWidget: (id: string) => void;
}
export const useWidgets = create<WidgetState>()(
persist(
(set) => ({
widgets: null,
fetchWidgets: async () => {
const widgets = await getWidgets();
set({ widgets: widgets });
},
setWidget: async ({ kind, title, content }: Widget) => {
const widget: Widget = await createWidget(kind, title, content);
set((state) => ({ widgets: [...state.widgets, widget] }));
},
removeWidget: async (id: string) => {
await removeWidget(id);
set((state) => ({ widgets: state.widgets.filter((widget) => widget.id !== id) }));
},
}),
{
name: 'blocks',
storage: createJSONStorage(() => localStorage),
}
)
);

View File

@@ -31,7 +31,7 @@ export interface Profile extends NDKUserProfile {
pubkey?: string; pubkey?: string;
} }
export interface Block { export interface Widget {
id?: string; id?: string;
account_id?: number; account_id?: number;
kind: number; kind: number;