rename blocks to widgets
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
-- Add migration script here
|
||||||
|
ALTER TABLE blocks
|
||||||
|
RENAME TO widgets;
|
||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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],
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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'] });
|
||||||
|
|||||||
@@ -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'] });
|
||||||
|
|||||||
@@ -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'] });
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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('#', ''),
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
@@ -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
37
src/stores/widgets.tsx
Normal 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),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
2
src/utils/types.d.ts
vendored
2
src/utils/types.d.ts
vendored
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user