updated prettier config & run linted

This commit is contained in:
Ren Amamiya 2023-03-04 21:00:43 +07:00
parent 416243706c
commit 63dbfba391
29 changed files with 1737 additions and 870 deletions

View File

@ -5,7 +5,7 @@
"next/core-web-vitals", "next/core-web-vitals",
"plugin:react/recommended", "plugin:react/recommended",
"plugin:react/jsx-runtime", "plugin:react/jsx-runtime",
"plugin:react-hooks/recommended", "plugin:react-hooks/recommended",
"plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended",
"prettier" "prettier"
], ],

View File

@ -3,12 +3,19 @@
"trailingComma": "es5", "trailingComma": "es5",
"singleQuote": true, "singleQuote": true,
"tabWidth": 2, "tabWidth": 2,
"printWidth": 150, "printWidth": 120,
"useTabs": false, "useTabs": false,
"endOfLine": "lf", "endOfLine": "lf",
"bracketSpacing": true, "bracketSpacing": true,
"bracketSameLine": true, "bracketSameLine": false,
"importOrder": ["^@layouts/(.*)$", "^@pages/(.*)$", "^@components/(.*)$", "^@utils/(.*)$", "^@stores/(.*)$", "<THIRD_PARTY_MODULES>", "^[./]"], "importOrder": [
"^@layouts/(.*)$",
"^@pages/(.*)$",
"^@components/(.*)$",
"^@utils/(.*)$",
"<THIRD_PARTY_MODULES>",
"^[./]"
],
"importOrderSeparation": true, "importOrderSeparation": true,
"importOrderSortSpecifiers": true, "importOrderSortSpecifiers": true,
"plugins": ["@trivago/prettier-plugin-sort-imports", "prettier-plugin-tailwindcss"], "plugins": ["@trivago/prettier-plugin-sort-imports", "prettier-plugin-tailwindcss"],

View File

@ -24,14 +24,14 @@
"framer-motion": "^9.1.7", "framer-motion": "^9.1.7",
"moment": "^2.29.4", "moment": "^2.29.4",
"nanostores": "^0.7.4", "nanostores": "^0.7.4",
"next": "^13.2.1", "next": "^13.2.3",
"next-remove-imports": "^1.0.10", "next-remove-imports": "^1.0.10",
"nostr-relaypool": "^0.5.3", "nostr-relaypool": "^0.5.3",
"nostr-tools": "^1.7.1", "nostr-tools": "^1.7.4",
"qrcode.react": "^3.1.0", "qrcode.react": "^3.1.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-hook-form": "^7.43.2", "react-hook-form": "^7.43.4",
"react-moment": "^1.1.3", "react-moment": "^1.1.3",
"react-player": "^2.11.2", "react-player": "^2.11.2",
"react-virtuoso": "^4.1.0", "react-virtuoso": "^4.1.0",
@ -43,7 +43,7 @@
"@tailwindcss/typography": "^0.5.9", "@tailwindcss/typography": "^0.5.9",
"@tauri-apps/cli": "^1.2.3", "@tauri-apps/cli": "^1.2.3",
"@trivago/prettier-plugin-sort-imports": "^4.1.1", "@trivago/prettier-plugin-sort-imports": "^4.1.1",
"@types/node": "^18.14.2", "@types/node": "^18.14.6",
"@types/react": "^18.0.28", "@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11", "@types/react-dom": "^18.0.11",
"@typescript-eslint/eslint-plugin": "^5.54.0", "@typescript-eslint/eslint-plugin": "^5.54.0",
@ -51,7 +51,7 @@
"autoprefixer": "^10.4.13", "autoprefixer": "^10.4.13",
"csstype": "^3.1.1", "csstype": "^3.1.1",
"eslint": "^8.35.0", "eslint": "^8.35.0",
"eslint-config-next": "^13.2.1", "eslint-config-next": "^13.2.3",
"eslint-config-prettier": "^8.6.0", "eslint-config-prettier": "^8.6.0",
"eslint-plugin-react": "^7.32.2", "eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
@ -59,7 +59,7 @@
"lint-staged": "^13.1.2", "lint-staged": "^13.1.2",
"postcss": "^8.4.21", "postcss": "^8.4.21",
"prettier": "^2.8.4", "prettier": "^2.8.4",
"prettier-plugin-tailwindcss": "^0.2.3", "prettier-plugin-tailwindcss": "^0.2.4",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"tailwindcss": "^3.2.7", "tailwindcss": "^3.2.7",
"typescript": "^4.9.5" "typescript": "^4.9.5"

File diff suppressed because it is too large Load Diff

View File

@ -145,8 +145,8 @@
.w-md-editor-toolbar-child { .w-md-editor-toolbar-child {
position: absolute; position: absolute;
border-radius: 3px; border-radius: 3px;
box-shadow: 0 0 0 1px var(--color-border-default), box-shadow: 0 0 0 1px var(--color-border-default), 0 0 0 var(--color-border-default),
0 0 0 var(--color-border-default), 0 1px 1px var(--color-border-default); 0 1px 1px var(--color-border-default);
background-color: var(--color-canvas-default); background-color: var(--color-canvas-default);
z-index: 1; z-index: 1;
display: none; display: none;

View File

@ -14,7 +14,8 @@ export const Account = memo(function Account({ user, current }: { user: any; cur
onClick={() => setCurrentUser()} onClick={() => setCurrentUser()}
className={`relative h-11 w-11 shrink overflow-hidden rounded-full ${ className={`relative h-11 w-11 shrink overflow-hidden rounded-full ${
current === user.pubkey ? 'ring-1 ring-fuchsia-500 ring-offset-4 ring-offset-black' : '' current === user.pubkey ? 'ring-1 ring-fuchsia-500 ring-offset-4 ring-offset-black' : ''
}`}> }`}
>
{userData?.picture !== undefined ? ( {userData?.picture !== undefined ? (
<Image src={userData.picture} alt="user's avatar" fill={true} className="rounded-full object-cover" /> <Image src={userData.picture} alt="user's avatar" fill={true} className="rounded-full object-cover" />
) : ( ) : (

View File

@ -31,7 +31,8 @@ export default function AccountBar() {
))} ))}
<Link <Link
href="/onboarding" href="/onboarding"
className="group relative flex h-11 w-11 shrink cursor-pointer items-center justify-center overflow-hidden rounded-full border-2 border-dashed border-zinc-600 hover:border-zinc-400"> className="group relative flex h-11 w-11 shrink cursor-pointer items-center justify-center overflow-hidden rounded-full border-2 border-dashed border-zinc-600 hover:border-zinc-400"
>
<PlusIcon className="h-4 w-4 text-zinc-400 group-hover:text-zinc-200" /> <PlusIcon className="h-4 w-4 text-zinc-400 group-hover:text-zinc-200" />
</Link> </Link>
</div> </div>

View File

@ -7,12 +7,7 @@ type ActiveLinkProps = LinkProps & {
activeClassName: string; activeClassName: string;
}; };
const ActiveLink = ({ const ActiveLink = ({ children, activeClassName, className, ...props }: PropsWithChildren<ActiveLinkProps>) => {
children,
activeClassName,
className,
...props
}: PropsWithChildren<ActiveLinkProps>) => {
const { asPath, isReady } = useRouter(); const { asPath, isReady } = useRouter();
const [computedClassName, setComputedClassName] = useState(className); const [computedClassName, setComputedClassName] = useState(className);
@ -26,8 +21,7 @@ const ActiveLink = ({
// Using URL().pathname to get rid of query and hash // Using URL().pathname to get rid of query and hash
const activePathname = new URL(asPath, location.href).pathname; const activePathname = new URL(asPath, location.href).pathname;
const newClassName = const newClassName = linkPathname === activePathname ? `${className} ${activeClassName}`.trim() : className;
linkPathname === activePathname ? `${className} ${activeClassName}`.trim() : className;
if (newClassName !== computedClassName) { if (newClassName !== computedClassName) {
setComputedClassName(newClassName); setComputedClassName(newClassName);

View File

@ -29,19 +29,19 @@ export default function Empty() {
fill="none" fill="none"
stroke="currentColor" stroke="currentColor"
viewBox="0 0 48 48" viewBox="0 0 48 48"
aria-hidden="true"> aria-hidden="true"
>
<path <path
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
strokeWidth={2} strokeWidth={2}
d="M34 40h10v-4a6 6 0 00-10.712-3.714M34 40H14m20 0v-4a9.971 9.971 0 00-.712-3.714M14 40H4v-4a6 6 0 0110.713-3.714M14 40v-4c0-1.313.253-2.566.713-3.714m0 0A10.003 10.003 0 0124 26c4.21 0 7.813 2.602 9.288 6.286M30 14a6 6 0 11-12 0 6 6 0 0112 0zm12 6a4 4 0 11-8 0 4 4 0 018 0zm-28 0a4 4 0 11-8 0 4 4 0 018 0z"></path> d="M34 40h10v-4a6 6 0 00-10.712-3.714M34 40H14m20 0v-4a9.971 9.971 0 00-.712-3.714M14 40H4v-4a6 6 0 0110.713-3.714M14 40v-4c0-1.313.253-2.566.713-3.714m0 0A10.003 10.003 0 0124 26c4.21 0 7.813 2.602 9.288 6.286M30 14a6 6 0 11-12 0 6 6 0 0112 0zm12 6a4 4 0 11-8 0 4 4 0 018 0zm-28 0a4 4 0 11-8 0 4 4 0 018 0z"
></path>
</svg> </svg>
<h2 className="mt-2 text-lg font-medium text-zinc-100"> <h2 className="mt-2 text-lg font-medium text-zinc-100">You haven&apos;t followed anyone yet</h2>
You haven&apos;t followed anyone yet
</h2>
<p className="mt-1 text-sm text-zinc-500"> <p className="mt-1 text-sm text-zinc-500">
You can send invite via email to your friend and lume will onboard them into nostr or You can send invite via email to your friend and lume will onboard them into nostr or follow some people in
follow some people in suggested below suggested below
</p> </p>
</div> </div>
<form action="#" className="relative mt-6"> <form action="#" className="relative mt-6">
@ -68,12 +68,7 @@ export default function Empty() {
<li key={index} className="flex items-center justify-between space-x-3 py-4"> <li key={index} className="flex items-center justify-between space-x-3 py-4">
<div className="flex min-w-0 flex-1 items-center space-x-3"> <div className="flex min-w-0 flex-1 items-center space-x-3">
<div className="relative h-10 w-10 flex-shrink-0"> <div className="relative h-10 w-10 flex-shrink-0">
<Image <Image className="rounded-full object-cover" src={person.imageUrl} alt={person.name} fill={true} />
className="rounded-full object-cover"
src={person.imageUrl}
alt={person.name}
fill={true}
/>
</div> </div>
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<p className="truncate text-sm font-medium text-zinc-200">{person.name}</p> <p className="truncate text-sm font-medium text-zinc-200">{person.name}</p>
@ -83,7 +78,8 @@ export default function Empty() {
<div className="flex-shrink-0"> <div className="flex-shrink-0">
<button <button
type="button" type="button"
className="inline-flex items-center rounded-full border border-zinc-700 bg-zinc-800 px-3 py-1 text-xs font-medium text-zinc-400 shadow-sm hover:bg-zinc-800 focus:outline-none focus:ring-2 focus:ring-fuchsia-600 focus:ring-offset-2"> className="inline-flex items-center rounded-full border border-zinc-700 bg-zinc-800 px-3 py-1 text-xs font-medium text-zinc-400 shadow-sm hover:bg-zinc-800 focus:outline-none focus:ring-2 focus:ring-fuchsia-600 focus:ring-offset-2"
>
<PlusIcon className="-ml-1 h-5 w-5" /> <PlusIcon className="-ml-1 h-5 w-5" />
<span className="text-sm font-medium text-zinc-300">Follow</span> <span className="text-sm font-medium text-zinc-300">Follow</span>
</button> </button>

View File

@ -30,7 +30,9 @@ export default function CreatePost() {
buttonProps: { className: 'cta-btn', 'aria-label': 'Post a message' }, buttonProps: { className: 'cta-btn', 'aria-label': 'Post a message' },
icon: ( icon: (
<div className="relative inline-flex h-10 w-16 transform cursor-pointer overflow-hidden rounded bg-zinc-900 px-2.5 ring-zinc-500/50 ring-offset-zinc-900 will-change-transform focus:outline-none focus:ring-1 focus:ring-offset-2 active:translate-y-1"> <div className="relative inline-flex h-10 w-16 transform cursor-pointer overflow-hidden rounded bg-zinc-900 px-2.5 ring-zinc-500/50 ring-offset-zinc-900 will-change-transform focus:outline-none focus:ring-1 focus:ring-offset-2 active:translate-y-1">
<span className="absolute inset-px z-10 inline-flex items-center justify-center rounded bg-zinc-900 text-zinc-200">Post</span> <span className="absolute inset-px z-10 inline-flex items-center justify-center rounded bg-zinc-900 text-zinc-200">
Post
</span>
<span className="absolute inset-0 z-0 scale-x-[2.0] blur before:absolute before:inset-0 before:top-1/2 before:aspect-square before:animate-disco before:bg-gradient-conic before:from-gray-300 before:via-fuchsia-600 before:to-orange-600"></span> <span className="absolute inset-0 z-0 scale-x-[2.0] blur before:absolute before:inset-0 before:top-1/2 before:aspect-square before:animate-disco before:bg-gradient-conic before:from-gray-300 before:via-fuchsia-600 before:to-orange-600"></span>
</div> </div>
), ),

View File

@ -30,7 +30,10 @@ export default function NavigatorBar() {
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<div className="flex items-center justify-between px-2"> <div className="flex items-center justify-between px-2">
<h3 className="text-sm font-bold text-zinc-400">Newsfeed</h3> <h3 className="text-sm font-bold text-zinc-400">Newsfeed</h3>
<button type="button" className="group flex h-6 w-6 items-center justify-center rounded-full hover:bg-zinc-900"> <button
type="button"
className="group flex h-6 w-6 items-center justify-center rounded-full hover:bg-zinc-900"
>
<PlusIcon className="h-3 w-3 text-zinc-400 group-hover:text-zinc-100" /> <PlusIcon className="h-3 w-3 text-zinc-400 group-hover:text-zinc-100" />
</button> </button>
</div> </div>
@ -38,14 +41,16 @@ export default function NavigatorBar() {
<ActiveLink <ActiveLink
href={`/feed/following`} href={`/feed/following`}
activeClassName="ring-1 ring-white/10 dark:bg-zinc-900 dark:text-white" activeClassName="ring-1 ring-white/10 dark:bg-zinc-900 dark:text-white"
className="flex h-10 items-center gap-1 rounded-lg px-2.5 text-sm font-medium hover:bg-zinc-900"> className="flex h-10 items-center gap-1 rounded-lg px-2.5 text-sm font-medium hover:bg-zinc-900"
>
<span>#</span> <span>#</span>
<span>following</span> <span>following</span>
</ActiveLink> </ActiveLink>
<ActiveLink <ActiveLink
href={`/feed/global`} href={`/feed/global`}
activeClassName="ring-1 ring-white/10 dark:bg-zinc-900 dark:text-white" activeClassName="ring-1 ring-white/10 dark:bg-zinc-900 dark:text-white"
className="flex h-10 items-center gap-1 rounded-lg px-2.5 text-sm font-medium hover:bg-zinc-900"> className="flex h-10 items-center gap-1 rounded-lg px-2.5 text-sm font-medium hover:bg-zinc-900"
>
<span>#</span> <span>#</span>
<span>global</span> <span>global</span>
</ActiveLink> </ActiveLink>
@ -55,7 +60,10 @@ export default function NavigatorBar() {
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<div className="flex items-center justify-between px-2"> <div className="flex items-center justify-between px-2">
<h3 className="text-sm font-bold text-zinc-400">Direct Messages</h3> <h3 className="text-sm font-bold text-zinc-400">Direct Messages</h3>
<button type="button" className="group flex h-6 w-6 items-center justify-center rounded-full hover:bg-zinc-900"> <button
type="button"
className="group flex h-6 w-6 items-center justify-center rounded-full hover:bg-zinc-900"
>
<PlusIcon className="h-3 w-3 text-zinc-400 group-hover:text-zinc-100" /> <PlusIcon className="h-3 w-3 text-zinc-400 group-hover:text-zinc-100" />
</button> </button>
</div> </div>

View File

@ -31,20 +31,24 @@ export const ProfileMenu = memo(function ProfileMenu({ pubkey }: { pubkey: strin
<DropdownMenu.Portal> <DropdownMenu.Portal>
<DropdownMenu.Content <DropdownMenu.Content
className="min-w-[220px] rounded-md border border-white/20 bg-zinc-800 p-1 shadow-lg shadow-black/30 will-change-[opacity,transform] data-[side=top]:animate-slideDownAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade data-[side=left]:animate-slideRightAndFade" className="min-w-[220px] rounded-md border border-white/20 bg-zinc-800 p-1 shadow-lg shadow-black/30 will-change-[opacity,transform] data-[side=top]:animate-slideDownAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade data-[side=left]:animate-slideRightAndFade"
sideOffset={2}> sideOffset={2}
>
<DropdownMenu.Item <DropdownMenu.Item
onClick={() => viewProfile()} onClick={() => viewProfile()}
className="group relative flex h-[30px] select-none items-center rounded px-1 pl-6 text-sm leading-none text-zinc-100 outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-zinc-700 data-[highlighted]:text-fuchsia-400 data-[disabled]:text-zinc-400"> className="group relative flex h-[30px] select-none items-center rounded px-1 pl-6 text-sm leading-none text-zinc-100 outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-zinc-700 data-[highlighted]:text-fuchsia-400 data-[disabled]:text-zinc-400"
>
View profile View profile
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Item <DropdownMenu.Item
onClick={() => updateProfile()} onClick={() => updateProfile()}
className="group relative flex h-[30px] select-none items-center rounded px-1 pl-6 text-sm leading-none text-zinc-100 outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-zinc-700 data-[highlighted]:text-fuchsia-400 data-[disabled]:text-zinc-400"> className="group relative flex h-[30px] select-none items-center rounded px-1 pl-6 text-sm leading-none text-zinc-100 outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-zinc-700 data-[highlighted]:text-fuchsia-400 data-[disabled]:text-zinc-400"
>
Update profile Update profile
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Item <DropdownMenu.Item
onClick={() => copyPubkey()} onClick={() => copyPubkey()}
className="group relative flex h-[30px] select-none items-center rounded px-1 pl-6 text-sm leading-none text-zinc-100 outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-zinc-700 data-[highlighted]:text-fuchsia-400 data-[disabled]:text-zinc-400"> className="group relative flex h-[30px] select-none items-center rounded px-1 pl-6 text-sm leading-none text-zinc-100 outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-zinc-700 data-[highlighted]:text-fuchsia-400 data-[disabled]:text-zinc-400"
>
Copy public key Copy public key
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Item className="group relative flex h-[30px] select-none items-center rounded px-1 pl-6 text-sm leading-none text-zinc-100 outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-zinc-700 data-[highlighted]:text-fuchsia-400 data-[disabled]:text-zinc-400"> <DropdownMenu.Item className="group relative flex h-[30px] select-none items-center rounded px-1 pl-6 text-sm leading-none text-zinc-100 outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-zinc-700 data-[highlighted]:text-fuchsia-400 data-[disabled]:text-zinc-400">

View File

@ -67,7 +67,11 @@ export default function Reaction({ eventID, eventPubkey }: { eventID: string; ev
return ( return (
<button onClick={(e) => handleReaction(e)} className="group flex w-16 items-center gap-1.5 text-sm text-zinc-500"> <button onClick={(e) => handleReaction(e)} className="group flex w-16 items-center gap-1.5 text-sm text-zinc-500">
<div className="rounded-lg p-1 group-hover:bg-zinc-600"> <div className="rounded-lg p-1 group-hover:bg-zinc-600">
{isReact ? <HeartFilledIcon className="h-4 w-4 group-hover:text-red-400" /> : <HeartIcon className="h-4 w-4 text-zinc-500" />} {isReact ? (
<HeartFilledIcon className="h-4 w-4 group-hover:text-red-400" />
) : (
<HeartIcon className="h-4 w-4 text-zinc-500" />
)}
</div> </div>
<span>{reaction}</span> <span>{reaction}</span>
</button> </button>

View File

@ -17,7 +17,9 @@ export const User = memo(function User({ pubkey, time }: { pubkey: string; time:
async (event) => { async (event) => {
const metadata: any = JSON.parse(event.content); const metadata: any = JSON.parse(event.content);
await db.execute(`INSERT OR IGNORE INTO cache_profiles (id, metadata) VALUES ("${pubkey}", '${JSON.stringify(metadata)}')`); await db.execute(
`INSERT OR IGNORE INTO cache_profiles (id, metadata) VALUES ("${pubkey}", '${JSON.stringify(metadata)}')`
);
setProfile(metadata); setProfile(metadata);
}, },
[db, pubkey] [db, pubkey]
@ -53,13 +55,20 @@ export const User = memo(function User({ pubkey, time }: { pubkey: string; time:
{profile.picture ? ( {profile.picture ? (
<ImageWithFallback src={profile.picture} alt={pubkey} fill={true} className="rounded-full object-cover" /> <ImageWithFallback src={profile.picture} alt={pubkey} fill={true} className="rounded-full object-cover" />
) : ( ) : (
<Avatar size={44} name={pubkey} variant="beam" colors={['#FEE2E2', '#FEF3C7', '#F59E0B', '#EC4899', '#D946EF', '#8B5CF6']} /> <Avatar
size={44}
name={pubkey}
variant="beam"
colors={['#FEE2E2', '#FEF3C7', '#F59E0B', '#EC4899', '#D946EF', '#8B5CF6']}
/>
)} )}
</div> </div>
<div className="flex w-full flex-1 items-start justify-between"> <div className="flex w-full flex-1 items-start justify-between">
<div className="flex w-full justify-between"> <div className="flex w-full justify-between">
<div className="flex items-baseline gap-2 text-sm"> <div className="flex items-baseline gap-2 text-sm">
<span className="font-bold leading-tight">{profile.name ? profile.name : truncate(pubkey, 16, ' .... ')}</span> <span className="font-bold leading-tight">
{profile.name ? profile.name : truncate(pubkey, 16, ' .... ')}
</span>
<span className="leading-tight text-zinc-500">·</span> <span className="leading-tight text-zinc-500">·</span>
<Moment fromNow unix className="text-zinc-500"> <Moment fromNow unix className="text-zinc-500">
{time} {time}

View File

@ -25,14 +25,23 @@ export const UserWithUsername = memo(function UserWithUsername({ pubkey }: { pub
{profile.picture ? ( {profile.picture ? (
<ImageWithFallback src={profile.picture} alt={pubkey} fill={true} className="rounded-full object-cover" /> <ImageWithFallback src={profile.picture} alt={pubkey} fill={true} className="rounded-full object-cover" />
) : ( ) : (
<Avatar size={44} name={pubkey} variant="beam" colors={['#FEE2E2', '#FEF3C7', '#F59E0B', '#EC4899', '#D946EF', '#8B5CF6']} /> <Avatar
size={44}
name={pubkey}
variant="beam"
colors={['#FEE2E2', '#FEF3C7', '#F59E0B', '#EC4899', '#D946EF', '#8B5CF6']}
/>
)} )}
</div> </div>
<div className="flex w-full flex-1 items-start justify-between"> <div className="flex w-full flex-1 items-start justify-between">
<div className="flex w-full justify-between"> <div className="flex w-full justify-between">
<div className="flex flex-col gap-1 text-sm"> <div className="flex flex-col gap-1 text-sm">
<span className="font-bold leading-tight">{profile.name ? profile.name : truncate(pubkey, 16, ' .... ')}</span> <span className="font-bold leading-tight">
<span className="text-zinc-500">{profile.username ? profile.username : truncate(pubkey, 16, ' .... ')}</span> {profile.name ? profile.name : truncate(pubkey, 16, ' .... ')}
</span>
<span className="text-zinc-500">
{profile.username ? profile.username : truncate(pubkey, 16, ' .... ')}
</span>
</div> </div>
<div> <div>
<DotsHorizontalIcon className="h-4 w-4 text-zinc-500" /> <DotsHorizontalIcon className="h-4 w-4 text-zinc-500" />

View File

@ -40,7 +40,14 @@ export const NoteConnector = memo(function NoteConnector({
`INSERT OR IGNORE INTO `INSERT OR IGNORE INTO
cache_notes cache_notes
(id, pubkey, created_at, kind, tags, content) VALUES (id, pubkey, created_at, kind, tags, content) VALUES
("${event.id}", "${event.pubkey}", "${event.created_at}", "${event.kind}", '${JSON.stringify(event.tags)}', "${event.content}");` (
"${event.id}",
"${event.pubkey}",
"${event.created_at}",
"${event.kind}",
'${JSON.stringify(event.tags)}',
"${event.content}"
);`
); );
}, },
[db] [db]
@ -85,7 +92,10 @@ export const NoteConnector = memo(function NoteConnector({
<h3 className="text-sm font-semibold text-zinc-500"># following</h3> <h3 className="text-sm font-semibold text-zinc-500"># following</h3>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<button onClick={() => reloadNewsfeed()} className={`${reload ? 'animate-spin' : ''} rounded-full p-1 hover:bg-zinc-800`}> <button
onClick={() => reloadNewsfeed()}
className={`${reload ? 'animate-spin' : ''} rounded-full p-1 hover:bg-zinc-800`}
>
<ReloadIcon className="h-3.5 w-3.5 text-zinc-500" /> <ReloadIcon className="h-3.5 w-3.5 text-zinc-500" />
</button> </button>
<div className="inline-flex items-center gap-1 rounded-full border border-zinc-700 bg-zinc-800 px-2.5 py-1"> <div className="inline-flex items-center gap-1 rounded-full border border-zinc-700 bg-zinc-800 px-2.5 py-1">

View File

@ -7,7 +7,8 @@ export default function LinkCard({ data }: { data: object }) {
<Link <Link
href={data['url']} href={data['url']}
target={'_blank'} target={'_blank'}
className="relative mt-2 flex flex-col overflow-hidden rounded-xl border border-zinc-700"> className="relative mt-2 flex flex-col overflow-hidden rounded-xl border border-zinc-700"
>
<div className="relative aspect-video h-auto w-full"> <div className="relative aspect-video h-auto w-full">
<Image src={data['image']} alt="image preview" fill={true} className="object-cover" /> <Image src={data['image']} alt="image preview" fill={true} className="object-cover" />
</div> </div>

View File

@ -1,7 +1,3 @@
export default function BaseLayout({ children }: { children: React.ReactNode }) { export default function BaseLayout({ children }: { children: React.ReactNode }) {
return ( return <div className="h-screen w-screen bg-white text-zinc-900 dark:bg-near-black dark:text-white">{children}</div>;
<div className="h-screen w-screen bg-white text-zinc-900 dark:bg-near-black dark:text-white">
{children}
</div>
);
} }

View File

@ -2,10 +2,7 @@ export default function FullLayout({ children }: { children: React.ReactNode })
return ( return (
<div className="bg-gradient-radial-page relative h-full overflow-hidden"> <div className="bg-gradient-radial-page relative h-full overflow-hidden">
{/* dragging area */} {/* dragging area */}
<div <div data-tauri-drag-region className="absolute top-0 left-0 z-20 h-16 w-full bg-transparent" />
data-tauri-drag-region
className="absolute top-0 left-0 z-20 h-16 w-full bg-transparent"
/>
{/* end dragging area */} {/* end dragging area */}
{/* content */} {/* content */}
<div className="relative z-10 h-full">{children}</div> <div className="relative z-10 h-full">{children}</div>

View File

@ -27,13 +27,15 @@ export default function UserLayout({ children }: { children: React.ReactNode })
<ActiveLink <ActiveLink
href={`/profile/${currentUser.pubkey}`} href={`/profile/${currentUser.pubkey}`}
activeClassName="ring-1 ring-white/10 dark:bg-zinc-900 dark:text-white" activeClassName="ring-1 ring-white/10 dark:bg-zinc-900 dark:text-white"
className="flex h-10 items-center gap-1 rounded-lg px-2.5 text-sm font-medium hover:bg-zinc-900"> className="flex h-10 items-center gap-1 rounded-lg px-2.5 text-sm font-medium hover:bg-zinc-900"
>
<span>Personal Page</span> <span>Personal Page</span>
</ActiveLink> </ActiveLink>
<ActiveLink <ActiveLink
href={`/profile/update?pubkey=${currentUser.pubkey}`} href={`/profile/update?pubkey=${currentUser.pubkey}`}
activeClassName="ring-1 ring-white/10 dark:bg-zinc-900 dark:text-white" activeClassName="ring-1 ring-white/10 dark:bg-zinc-900 dark:text-white"
className="flex h-10 items-center gap-1 rounded-lg px-2.5 text-sm font-medium hover:bg-zinc-900"> className="flex h-10 items-center gap-1 rounded-lg px-2.5 text-sm font-medium hover:bg-zinc-900"
>
<span>Update Profile</span> <span>Update Profile</span>
</ActiveLink> </ActiveLink>
</div> </div>

View File

@ -69,7 +69,9 @@ export default function Page() {
useEffect(() => { useEffect(() => {
const getData = async () => { const getData = async () => {
const result = await db.select( const result = await db.select(
`SELECT * FROM cache_notes WHERE created_at <= ${dateToUnix(now.current)} ORDER BY created_at DESC LIMIT ${limit.current}` `SELECT * FROM cache_notes WHERE created_at <= ${dateToUnix(now.current)} ORDER BY created_at DESC LIMIT ${
limit.current
}`
); );
if (result) { if (result) {
setData(result); setData(result);
@ -94,7 +96,8 @@ export default function Page() {
<div className="absolute top-16 left-1/2 z-50 -translate-x-1/2 transform"> <div className="absolute top-16 left-1/2 z-50 -translate-x-1/2 transform">
<button <button
onClick={() => loadNewest()} onClick={() => loadNewest()}
className="inline-flex h-8 transform items-center justify-center gap-1 rounded-full bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-gray-300 via-fuchsia-600 to-orange-600 pl-3 pr-3.5 text-sm shadow-lg active:translate-y-1"> className="inline-flex h-8 transform items-center justify-center gap-1 rounded-full bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-gray-300 via-fuchsia-600 to-orange-600 pl-3 pr-3.5 text-sm shadow-lg active:translate-y-1"
>
<ArrowUpIcon className="h-4 w-4" /> <ArrowUpIcon className="h-4 w-4" />
<span className="drop-shadow-md">Load newest</span> <span className="drop-shadow-md">Load newest</span>
</button> </button>
@ -125,7 +128,13 @@ export default function Page() {
} }
Page.getLayout = function getLayout( Page.getLayout = function getLayout(
page: string | number | boolean | ReactElement<unknown, string | JSXElementConstructor<unknown>> | ReactFragment | ReactPortal page:
| string
| number
| boolean
| ReactElement<unknown, string | JSXElementConstructor<unknown>>
| ReactFragment
| ReactPortal
) { ) {
return ( return (
<BaseLayout> <BaseLayout>

View File

@ -12,7 +12,13 @@ export default function Page() {
} }
Page.getLayout = function getLayout( Page.getLayout = function getLayout(
page: string | number | boolean | ReactElement<unknown, string | JSXElementConstructor<unknown>> | ReactFragment | ReactPortal page:
| string
| number
| boolean
| ReactElement<unknown, string | JSXElementConstructor<unknown>>
| ReactFragment
| ReactPortal
) { ) {
return ( return (
<BaseLayout> <BaseLayout>

View File

@ -36,12 +36,16 @@ export default function Page() {
<LumeSymbol className="h-16 w-16 text-white" /> <LumeSymbol className="h-16 w-16 text-white" />
</motion.div> </motion.div>
<div className="flex flex-col items-center gap-0.5"> <div className="flex flex-col items-center gap-0.5">
<motion.h2 layoutId="subtitle" className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-4xl font-medium text-transparent"> <motion.h2
layoutId="subtitle"
className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-4xl font-medium text-transparent"
>
A censorship-resistant social network A censorship-resistant social network
</motion.h2> </motion.h2>
<motion.h1 <motion.h1
layoutId="title" layoutId="title"
className="bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-gray-300 via-fuchsia-600 to-orange-600 bg-clip-text text-5xl font-bold text-transparent"> className="bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-gray-300 via-fuchsia-600 to-orange-600 bg-clip-text text-5xl font-bold text-transparent"
>
built on nostr built on nostr
</motion.h1> </motion.h1>
</div> </div>
@ -49,12 +53,18 @@ export default function Page() {
<div className="flex items-center gap-2 pb-16"> <div className="flex items-center gap-2 pb-16">
<div className="h-10"> <div className="h-10">
{loading ? ( {loading ? (
<svg className="h-5 w-5 animate-spin text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <svg
className="h-5 w-5 animate-spin text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle> <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path <path
className="opacity-75" className="opacity-75"
fill="currentColor" fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg> </svg>
) : ( ) : (
<></> <></>
@ -65,7 +75,8 @@ export default function Page() {
<div className="absolute inset-0 bg-gradient-to-r from-fuchsia-400/10 to-orange-100/10 opacity-100 [mask-image:radial-gradient(farthest-side_at_top,white,transparent)]"> <div className="absolute inset-0 bg-gradient-to-r from-fuchsia-400/10 to-orange-100/10 opacity-100 [mask-image:radial-gradient(farthest-side_at_top,white,transparent)]">
<svg <svg
aria-hidden="true" aria-hidden="true"
className="dark:fill-white/2.5 absolute inset-x-0 inset-y-[-50%] h-[200%] w-full skew-y-[-18deg] fill-black/40 stroke-black/50 mix-blend-overlay dark:stroke-white/5"> className="dark:fill-white/2.5 absolute inset-x-0 inset-y-[-50%] h-[200%] w-full skew-y-[-18deg] fill-black/40 stroke-black/50 mix-blend-overlay dark:stroke-white/5"
>
<defs> <defs>
<pattern id=":R11d6:" width="72" height="56" patternUnits="userSpaceOnUse" x="-12" y="4"> <pattern id=":R11d6:" width="72" height="56" patternUnits="userSpaceOnUse" x="-12" y="4">
<path d="M.5 56V.5H72" fill="none"></path> <path d="M.5 56V.5H72" fill="none"></path>
@ -86,7 +97,13 @@ export default function Page() {
} }
Page.getLayout = function getLayout( Page.getLayout = function getLayout(
page: string | number | boolean | ReactElement<unknown, string | JSXElementConstructor<unknown>> | ReactFragment | ReactPortal page:
| string
| number
| boolean
| ReactElement<unknown, string | JSXElementConstructor<unknown>>
| ReactFragment
| ReactPortal
) { ) {
return ( return (
<BaseLayout> <BaseLayout>

View File

@ -11,7 +11,16 @@ import { motion } from 'framer-motion';
import Image from 'next/image'; import Image from 'next/image';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { generatePrivateKey, getEventHash, getPublicKey, nip19, signEvent } from 'nostr-tools'; import { generatePrivateKey, getEventHash, getPublicKey, nip19, signEvent } from 'nostr-tools';
import { JSXElementConstructor, ReactElement, ReactFragment, ReactPortal, useCallback, useContext, useMemo, useState } from 'react'; import {
JSXElementConstructor,
ReactElement,
ReactFragment,
ReactPortal,
useCallback,
useContext,
useMemo,
useState,
} from 'react';
import { Config, names, uniqueNamesGenerator } from 'unique-names-generator'; import { Config, names, uniqueNamesGenerator } from 'unique-names-generator';
const config: Config = { const config: Config = {
@ -58,7 +67,9 @@ export default function Page() {
const insertDB = useCallback(async () => { const insertDB = useCallback(async () => {
await db.execute( await db.execute(
`INSERT INTO accounts (id, privkey, npub, nsec, metadata) VALUES ("${pubKey}", "${privKey}", "${npub}", "${nsec}", '${JSON.stringify(data)}')` `INSERT INTO accounts (id, privkey, npub, nsec, metadata) VALUES ("${pubKey}", "${privKey}", "${npub}", "${nsec}", '${JSON.stringify(
data
)}')`
); );
}, [data, db, npub, nsec, privKey, pubKey]); }, [data, db, npub, nsec, privKey, pubKey]);
@ -101,12 +112,15 @@ export default function Page() {
<div>{/* spacer */}</div> <div>{/* spacer */}</div>
<motion.div layoutId="form"> <motion.div layoutId="form">
<div className="mb-8 flex flex-col gap-3"> <div className="mb-8 flex flex-col gap-3">
<motion.h1 layoutId="title" className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-3xl font-medium text-transparent"> <motion.h1
layoutId="title"
className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-3xl font-medium text-transparent"
>
Create new key Create new key
</motion.h1> </motion.h1>
<motion.h2 layoutId="subtitle" className="w-3/4 text-zinc-400"> <motion.h2 layoutId="subtitle" className="w-3/4 text-zinc-400">
Lume will generate key with default profile for you, you can edit it later, and please store your key safely so you can restore your Lume will generate key with default profile for you, you can edit it later, and please store your key safely
account or use other client so you can restore your account or use other client
</motion.h2> </motion.h2>
</div> </div>
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
@ -131,7 +145,8 @@ export default function Page() {
/> />
<button <button
onClick={() => showPrivateKey()} onClick={() => showPrivateKey()}
className="group absolute right-2 top-1/2 -translate-y-1/2 transform rounded p-1 hover:bg-zinc-700"> className="group absolute right-2 top-1/2 -translate-y-1/2 transform rounded p-1 hover:bg-zinc-700"
>
{type === 'password' ? ( {type === 'password' ? (
<EyeClosedIcon className="h-5 w-5 text-zinc-500 group-hover:text-zinc-200" /> <EyeClosedIcon className="h-5 w-5 text-zinc-500 group-hover:text-zinc-200" />
) : ( ) : (
@ -170,18 +185,25 @@ export default function Page() {
<motion.div layoutId="action" className="pb-5"> <motion.div layoutId="action" className="pb-5">
<div className="flex h-10 items-center"> <div className="flex h-10 items-center">
{loading === true ? ( {loading === true ? (
<svg className="h-5 w-5 animate-spin text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <svg
className="h-5 w-5 animate-spin text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle> <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path <path
className="opacity-75" className="opacity-75"
fill="currentColor" fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg> </svg>
) : ( ) : (
<div className="relative shrink-0 before:pointer-events-none before:absolute before:-inset-1 before:rounded-[11px] before:border before:border-blue-500 before:opacity-0 before:ring-2 before:ring-blue-500/20 before:transition after:pointer-events-none after:absolute after:inset-px after:rounded-[7px] after:shadow-highlight after:shadow-white/5 after:transition focus-within:before:opacity-100 focus-within:after:shadow-blue-500/100 dark:focus-within:after:shadow-blue-500/20"> <div className="relative shrink-0 before:pointer-events-none before:absolute before:-inset-1 before:rounded-[11px] before:border before:border-blue-500 before:opacity-0 before:ring-2 before:ring-blue-500/20 before:transition after:pointer-events-none after:absolute after:inset-px after:rounded-[7px] after:shadow-highlight after:shadow-white/5 after:transition focus-within:before:opacity-100 focus-within:after:shadow-blue-500/100 dark:focus-within:after:shadow-blue-500/20">
<button <button
onClick={() => createAccount()} onClick={() => createAccount()}
className="transform rounded-lg border border-white/10 bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-gray-300 via-fuchsia-600 to-orange-600 px-3.5 py-2 font-medium shadow-input shadow-black/5 active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-50 dark:shadow-black/10"> className="transform rounded-lg border border-white/10 bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-gray-300 via-fuchsia-600 to-orange-600 px-3.5 py-2 font-medium shadow-input shadow-black/5 active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-50 dark:shadow-black/10"
>
<span className="drop-shadow-lg">Continue </span> <span className="drop-shadow-lg">Continue </span>
</button> </button>
</div> </div>
@ -193,7 +215,13 @@ export default function Page() {
} }
Page.getLayout = function getLayout( Page.getLayout = function getLayout(
page: string | number | boolean | ReactElement<unknown, string | JSXElementConstructor<unknown>> | ReactFragment | ReactPortal page:
| string
| number
| boolean
| ReactElement<unknown, string | JSXElementConstructor<unknown>>
| ReactFragment
| ReactPortal
) { ) {
return ( return (
<BaseLayout> <BaseLayout>

View File

@ -33,7 +33,9 @@ export default function Page() {
const insertDB = async () => { const insertDB = async () => {
// self follow // self follow
await db.execute(`INSERT INTO follows (pubkey, account, kind) VALUES ("${currentUser.pubkey}", "${currentUser.pubkey}", "0")`); await db.execute(
`INSERT INTO follows (pubkey, account, kind) VALUES ("${currentUser.pubkey}", "${currentUser.pubkey}", "0")`
);
// follow selected // follow selected
follow.forEach(async (npub) => { follow.forEach(async (npub) => {
const { data } = nip19.decode(npub); const { data } = nip19.decode(npub);
@ -57,11 +59,15 @@ export default function Page() {
<div>{/* spacer */}</div> <div>{/* spacer */}</div>
<motion.div layoutId="form" className="flex flex-col"> <motion.div layoutId="form" className="flex flex-col">
<div className="mb-8 flex flex-col gap-3"> <div className="mb-8 flex flex-col gap-3">
<motion.h1 layoutId="title" className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-3xl font-medium text-transparent"> <motion.h1
layoutId="title"
className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-3xl font-medium text-transparent"
>
Choose 10 people you want to following Choose 10 people you want to following
</motion.h1> </motion.h1>
<motion.h2 layoutId="subtitle" className="w-3/4 text-zinc-400"> <motion.h2 layoutId="subtitle" className="w-3/4 text-zinc-400">
For better experiences, you should follow the people you care about to personalize your newsfeed, otherwise you will be very bored For better experiences, you should follow the people you care about to personalize your newsfeed, otherwise
you will be very bored
</motion.h2> </motion.h2>
</div> </div>
<div className="h-full w-full shrink"> <div className="h-full w-full shrink">
@ -73,7 +79,8 @@ export default function Page() {
data-npub={item.npub} data-npub={item.npub}
className={`col-span-1 inline-flex cursor-pointer items-center gap-3 rounded-lg p-2 hover:bg-zinc-700 ${ className={`col-span-1 inline-flex cursor-pointer items-center gap-3 rounded-lg p-2 hover:bg-zinc-700 ${
follow.includes(item.npub) ? 'bg-zinc-800' : '' follow.includes(item.npub) ? 'bg-zinc-800' : ''
}`}> }`}
>
<div className="relative h-10 w-10 flex-shrink-0"> <div className="relative h-10 w-10 flex-shrink-0">
<Image className="rounded-full object-cover" src={item.avatar} alt={item.name} fill={true} /> <Image className="rounded-full object-cover" src={item.avatar} alt={item.name} fill={true} />
</div> </div>
@ -82,7 +89,9 @@ export default function Page() {
<p className="truncate text-sm font-medium text-zinc-200">{item.name}</p> <p className="truncate text-sm font-medium text-zinc-200">{item.name}</p>
<p className="text-sm leading-tight text-zinc-500">{truncate(item.npub, 16, ' .... ')}</p> <p className="text-sm leading-tight text-zinc-500">{truncate(item.npub, 16, ' .... ')}</p>
</div> </div>
<div>{follow.includes(item.npub) ? <CheckCircledIcon className="h-4 w-4 text-green-500" /> : <></>}</div> <div>
{follow.includes(item.npub) ? <CheckCircledIcon className="h-4 w-4 text-green-500" /> : <></>}
</div>
</div> </div>
</div> </div>
))} ))}
@ -92,19 +101,26 @@ export default function Page() {
<motion.div layoutId="action" className="pb-5"> <motion.div layoutId="action" className="pb-5">
<div className="flex h-10 items-center"> <div className="flex h-10 items-center">
{loading === true ? ( {loading === true ? (
<svg className="h-5 w-5 animate-spin text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <svg
className="h-5 w-5 animate-spin text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle> <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path <path
className="opacity-75" className="opacity-75"
fill="currentColor" fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg> </svg>
) : ( ) : (
<div className="relative shrink-0 before:pointer-events-none before:absolute before:-inset-1 before:rounded-[11px] before:border before:border-blue-500 before:opacity-0 before:ring-2 before:ring-blue-500/20 before:transition after:pointer-events-none after:absolute after:inset-px after:rounded-[7px] after:shadow-highlight after:shadow-white/5 after:transition focus-within:before:opacity-100 focus-within:after:shadow-blue-500/100 dark:focus-within:after:shadow-blue-500/20"> <div className="relative shrink-0 before:pointer-events-none before:absolute before:-inset-1 before:rounded-[11px] before:border before:border-blue-500 before:opacity-0 before:ring-2 before:ring-blue-500/20 before:transition after:pointer-events-none after:absolute after:inset-px after:rounded-[7px] after:shadow-highlight after:shadow-white/5 after:transition focus-within:before:opacity-100 focus-within:after:shadow-blue-500/100 dark:focus-within:after:shadow-blue-500/20">
<button <button
onClick={() => createFollowing()} onClick={() => createFollowing()}
disabled={follow.length < 10 ? true : false} disabled={follow.length < 10 ? true : false}
className="transform rounded-lg border border-white/10 bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-gray-300 via-fuchsia-600 to-orange-600 px-3.5 py-2 font-medium shadow-input shadow-black/5 active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-50 dark:shadow-black/10"> className="transform rounded-lg border border-white/10 bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-gray-300 via-fuchsia-600 to-orange-600 px-3.5 py-2 font-medium shadow-input shadow-black/5 active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-50 dark:shadow-black/10"
>
<span className="drop-shadow-lg">Finish </span> <span className="drop-shadow-lg">Finish </span>
</button> </button>
</div> </div>
@ -116,7 +132,13 @@ export default function Page() {
} }
Page.getLayout = function getLayout( Page.getLayout = function getLayout(
page: string | number | boolean | ReactElement<unknown, string | JSXElementConstructor<unknown>> | ReactFragment | ReactPortal page:
| string
| number
| boolean
| ReactElement<unknown, string | JSXElementConstructor<unknown>>
| ReactFragment
| ReactPortal
) { ) {
return ( return (
<BaseLayout> <BaseLayout>

View File

@ -10,7 +10,10 @@ export default function Page() {
<div className="flex h-full flex-col justify-between px-8"> <div className="flex h-full flex-col justify-between px-8">
<div>{/* spacer */}</div> <div>{/* spacer */}</div>
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
<motion.h1 layoutId="title" className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-3xl font-medium text-transparent"> <motion.h1
layoutId="title"
className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-3xl font-medium text-transparent"
>
Other social network require email/password Other social network require email/password
<br /> <br />
nostr use{' '} nostr use{' '}
@ -19,19 +22,21 @@ export default function Page() {
</span> </span>
</motion.h1> </motion.h1>
<motion.h2 layoutId="subtitle" className="w-3/4 text-zinc-400"> <motion.h2 layoutId="subtitle" className="w-3/4 text-zinc-400">
If you have used nostr before, you can import your own private key. Otherwise, you can create a new key or use auto-generated account If you have used nostr before, you can import your own private key. Otherwise, you can create a new key or use
created by system. auto-generated account created by system.
</motion.h2> </motion.h2>
<motion.div layoutId="form"></motion.div> <motion.div layoutId="form"></motion.div>
<motion.div layoutId="action" className="mt-4 flex gap-2"> <motion.div layoutId="action" className="mt-4 flex gap-2">
<Link <Link
href="/onboarding/create" href="/onboarding/create"
className="hover:bg-zinc-900/2.5 transform rounded-lg border border-black/5 bg-zinc-800 px-3.5 py-2 font-medium ring-1 ring-inset ring-zinc-900/10 hover:text-zinc-900 active:translate-y-1 dark:text-zinc-300 dark:ring-white/10 dark:hover:bg-zinc-700 dark:hover:text-white"> className="hover:bg-zinc-900/2.5 transform rounded-lg border border-black/5 bg-zinc-800 px-3.5 py-2 font-medium ring-1 ring-inset ring-zinc-900/10 hover:text-zinc-900 active:translate-y-1 dark:text-zinc-300 dark:ring-white/10 dark:hover:bg-zinc-700 dark:hover:text-white"
>
Create new key Create new key
</Link> </Link>
<Link <Link
href="/onboarding/login" href="/onboarding/login"
className="hover:bg-zinc-900/2.5 transform rounded-lg border border-black/5 bg-zinc-800 px-3.5 py-2 font-medium ring-1 ring-inset ring-zinc-900/10 hover:text-zinc-900 active:translate-y-1 dark:text-zinc-300 dark:ring-white/10 dark:hover:bg-zinc-700 dark:hover:text-white"> className="hover:bg-zinc-900/2.5 transform rounded-lg border border-black/5 bg-zinc-800 px-3.5 py-2 font-medium ring-1 ring-inset ring-zinc-900/10 hover:text-zinc-900 active:translate-y-1 dark:text-zinc-300 dark:ring-white/10 dark:hover:bg-zinc-700 dark:hover:text-white"
>
Login with private key Login with private key
</Link> </Link>
</motion.div> </motion.div>
@ -42,7 +47,13 @@ export default function Page() {
} }
Page.getLayout = function getLayout( Page.getLayout = function getLayout(
page: string | number | boolean | ReactElement<unknown, string | JSXElementConstructor<unknown>> | ReactFragment | ReactPortal page:
| string
| number
| boolean
| ReactElement<unknown, string | JSXElementConstructor<unknown>>
| ReactFragment
| ReactPortal
) { ) {
return ( return (
<BaseLayout> <BaseLayout>

View File

@ -10,7 +10,16 @@ import { motion } from 'framer-motion';
import Link from 'next/link'; import Link from 'next/link';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { getPublicKey, nip19 } from 'nostr-tools'; import { getPublicKey, nip19 } from 'nostr-tools';
import { JSXElementConstructor, ReactElement, ReactFragment, ReactPortal, useCallback, useContext, useMemo, useState } from 'react'; import {
JSXElementConstructor,
ReactElement,
ReactFragment,
ReactPortal,
useCallback,
useContext,
useMemo,
useState,
} from 'react';
export default function Page() { export default function Page() {
const { db }: any = useContext(DatabaseContext); const { db }: any = useContext(DatabaseContext);
@ -44,7 +53,9 @@ export default function Page() {
async (follows) => { async (follows) => {
follows.forEach(async (item) => { follows.forEach(async (item) => {
if (item) { if (item) {
await db.execute(`INSERT OR IGNORE INTO follows (pubkey, account, kind) VALUES ("${item[1]}", "${pubkey}", "0")`); await db.execute(
`INSERT OR IGNORE INTO follows (pubkey, account, kind) VALUES ("${item[1]}", "${pubkey}", "0")`
);
} }
}); });
}, },
@ -80,28 +91,39 @@ export default function Page() {
<div>{/* spacer */}</div> <div>{/* spacer */}</div>
<motion.div layoutId="form"> <motion.div layoutId="form">
<div className="mb-8 flex flex-col gap-3"> <div className="mb-8 flex flex-col gap-3">
<motion.h1 layoutId="title" className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-3xl font-medium text-transparent"> <motion.h1
layoutId="title"
className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-3xl font-medium text-transparent"
>
Fetching your profile... Fetching your profile...
</motion.h1> </motion.h1>
<motion.h2 layoutId="subtitle" className="w-3/4 text-zinc-400"> <motion.h2 layoutId="subtitle" className="w-3/4 text-zinc-400">
As long as you have private key, you alway can sync your profile and follows list on every nostr client, so please keep your key safely As long as you have private key, you alway can sync your profile and follows list on every nostr client, so
please keep your key safely
</motion.h2> </motion.h2>
</div> </div>
</motion.div> </motion.div>
<motion.div layoutId="action" className="pb-5"> <motion.div layoutId="action" className="pb-5">
<div className="flex h-10 items-center"> <div className="flex h-10 items-center">
{loading === true ? ( {loading === true ? (
<svg className="h-5 w-5 animate-spin text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <svg
className="h-5 w-5 animate-spin text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle> <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path <path
className="opacity-75" className="opacity-75"
fill="currentColor" fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg> </svg>
) : ( ) : (
<Link <Link
href="/" href="/"
className="transform rounded-lg bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-gray-300 via-fuchsia-600 to-orange-600 px-3.5 py-2 font-medium active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-30"> className="transform rounded-lg bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-gray-300 via-fuchsia-600 to-orange-600 px-3.5 py-2 font-medium active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-30"
>
<span className="drop-shadow-lg">Finish</span> <span className="drop-shadow-lg">Finish</span>
</Link> </Link>
)} )}
@ -112,7 +134,13 @@ export default function Page() {
} }
Page.getLayout = function getLayout( Page.getLayout = function getLayout(
page: string | number | boolean | ReactElement<unknown, string | JSXElementConstructor<unknown>> | ReactFragment | ReactPortal page:
| string
| number
| boolean
| ReactElement<unknown, string | JSXElementConstructor<unknown>>
| ReactFragment
| ReactPortal
) { ) {
return ( return (
<BaseLayout> <BaseLayout>

View File

@ -60,12 +60,15 @@ export default function Page() {
<div>{/* spacer */}</div> <div>{/* spacer */}</div>
<motion.div layoutId="form"> <motion.div layoutId="form">
<div className="mb-8 flex flex-col gap-3"> <div className="mb-8 flex flex-col gap-3">
<motion.h1 layoutId="title" className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-3xl font-medium text-transparent"> <motion.h1
layoutId="title"
className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-3xl font-medium text-transparent"
>
Import your private key Import your private key
</motion.h1> </motion.h1>
<motion.h2 layoutId="subtitle" className="w-3/4 text-zinc-400"> <motion.h2 layoutId="subtitle" className="w-3/4 text-zinc-400">
You can import private key format as hex string or nsec. If you have installed Nostr Connect compality wallet in your mobile, you can You can import private key format as hex string or nsec. If you have installed Nostr Connect compality
connect by scan QR Code below wallet in your mobile, you can connect by scan QR Code below
</motion.h2> </motion.h2>
</div> </div>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
@ -83,18 +86,25 @@ export default function Page() {
<motion.div layoutId="action" className="pb-5"> <motion.div layoutId="action" className="pb-5">
<div className="flex h-10 items-center"> <div className="flex h-10 items-center">
{isSubmitting ? ( {isSubmitting ? (
<svg className="h-5 w-5 animate-spin text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <svg
className="h-5 w-5 animate-spin text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle> <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path <path
className="opacity-75" className="opacity-75"
fill="currentColor" fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg> </svg>
) : ( ) : (
<button <button
type="submit" type="submit"
disabled={!isDirty || !isValid} disabled={!isDirty || !isValid}
className="transform rounded-lg bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-gray-300 via-fuchsia-600 to-orange-600 px-3.5 py-2 font-medium active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-30"> className="transform rounded-lg bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-gray-300 via-fuchsia-600 to-orange-600 px-3.5 py-2 font-medium active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-30"
>
<span className="drop-shadow-lg">Continue </span> <span className="drop-shadow-lg">Continue </span>
</button> </button>
)} )}
@ -105,7 +115,13 @@ export default function Page() {
} }
Page.getLayout = function getLayout( Page.getLayout = function getLayout(
page: string | number | boolean | ReactElement<unknown, string | JSXElementConstructor<unknown>> | ReactFragment | ReactPortal page:
| string
| number
| boolean
| ReactElement<unknown, string | JSXElementConstructor<unknown>>
| ReactFragment
| ReactPortal
) { ) {
return ( return (
<BaseLayout> <BaseLayout>

View File

@ -32,7 +32,8 @@ export default function Page() {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [currentUser]: any = useLocalStorage('current-user'); const [currentUser]: any = useLocalStorage('current-user');
const profile = currentUser.metadata !== undefined ? JSON.parse(currentUser.metadata) : { display_name: null, username: null }; const profile =
currentUser.metadata !== undefined ? JSON.parse(currentUser.metadata) : { display_name: null, username: null };
const { const {
register, register,
@ -79,9 +80,12 @@ export default function Page() {
return ( return (
<form onSubmit={handleSubmit(onSubmit)} className="flex h-full w-full flex-col justify-between px-6"> <form onSubmit={handleSubmit(onSubmit)} className="flex h-full w-full flex-col justify-between px-6">
<div className="mb-8 flex flex-col gap-3 pt-8"> <div className="mb-8 flex flex-col gap-3 pt-8">
<h1 className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-3xl font-medium text-transparent">Update profile</h1> <h1 className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-3xl font-medium text-transparent">
Update profile
</h1>
<h2 className="w-3/4 text-zinc-400"> <h2 className="w-3/4 text-zinc-400">
Your profile will be published to all relays, as long as you have the private key, you always can recover your profile in any client Your profile will be published to all relays, as long as you have the private key, you always can recover your
profile in any client
</h2> </h2>
</div> </div>
<fieldset className="flex flex-col gap-2"> <fieldset className="flex flex-col gap-2">
@ -179,18 +183,25 @@ export default function Page() {
<div className="pb-5"> <div className="pb-5">
<div className="flex h-10 items-center"> <div className="flex h-10 items-center">
{loading === true ? ( {loading === true ? (
<svg className="h-5 w-5 animate-spin text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <svg
className="h-5 w-5 animate-spin text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle> <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path <path
className="opacity-75" className="opacity-75"
fill="currentColor" fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg> </svg>
) : ( ) : (
<button <button
type="submit" type="submit"
disabled={!isDirty || !isValid} disabled={!isDirty || !isValid}
className="transform rounded-lg bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-gray-300 via-fuchsia-600 to-orange-600 px-3.5 py-2 font-medium active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-30"> className="transform rounded-lg bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-gray-300 via-fuchsia-600 to-orange-600 px-3.5 py-2 font-medium active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-30"
>
<span className="drop-shadow-lg">Update</span> <span className="drop-shadow-lg">Update</span>
</button> </button>
)} )}
@ -201,7 +212,13 @@ export default function Page() {
} }
Page.getLayout = function getLayout( Page.getLayout = function getLayout(
page: string | number | boolean | ReactElement<unknown, string | JSXElementConstructor<unknown>> | ReactFragment | ReactPortal page:
| string
| number
| boolean
| ReactElement<unknown, string | JSXElementConstructor<unknown>>
| ReactFragment
| ReactPortal
) { ) {
return ( return (
<BaseLayout> <BaseLayout>