Skip to content

feat: added example #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions examples/user-page/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
16 changes: 16 additions & 0 deletions examples/user-page/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!doctype html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tsky - User Page Example</title>
</head>

<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>

</html>
28 changes: 28 additions & 0 deletions examples/user-page/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "examples-user-page",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"preview": "vite preview"
},
"dependencies": {
"@tsky/client": "workspace:*",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@tailwindcss/vite": "^4.0.12",
"@tsky/lexicons": "workspace:*",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@vitejs/plugin-react": "^4.3.4",
"globals": "^15.15.0",
"tailwindcss": "^4.0.12",
"typescript": "~5.7.2",
"typescript-eslint": "^8.24.1",
"vite": "^6.2.0"
}
}
Binary file added examples/user-page/public/tsky-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
172 changes: 172 additions & 0 deletions examples/user-page/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import { type ActorProfile, createAgent } from '@tsky/client';
import type { At } from '@tsky/lexicons';
import { useEffect, useState } from 'react';

async function getUserProfile(identity: string) {
try {
const agent = await createAgent({
options: {
service: 'https://public.api.bsky.app',
},
});

let did = identity;

if (!did.startsWith('did:')) {
const _id = await agent.resolveDIDFromHandle(identity);
did = _id.did;
}

const actor = await agent.actor(did as At.DID);

return actor.profile();
} catch (err) {
console.error(err);
}
}

function App() {
const [search, setSearch] = useState<string>();
const [user, setUser] = useState<ActorProfile>();

useEffect(() => {
if (search) {
getUserProfile(search).then(setUser);
}
}, [search]);

return (
<main className="w-full h-screen bg-white text-black dark:bg-zinc-950 dark:text-white">
<div className="max-w-lg mx-auto w-full py-6 space-y-6">
<form
action={(values) => {
const value = values.get('search');

if (value) {
setSearch(value.toString());
}
}}
className="flex gap-3 items-center"
>
<a
href="https://github.com/tsky-dev/tsky"
target="_blank"
rel="noreferrer"
>
<img
src="/examples/user-profile/tsky-logo.png"
alt="tsky logo"
className="size-9 min-w-9 rounded"
/>
</a>
<input
name="search"
type="search"
placeholder="Search Profile"
className="w-full border appearance-none outline-none dark:text-zinc-100 transition-all placeholder:text-zinc-400 dark:placeholder:text-zinc-500 py-1.5 text-base hover:border-blue-500 dark:hover:border-blue-300 border-zinc-300 dark:border-zinc-700 focus-visible:ring-2 ring-offset-2 ring-offset-white dark:ring-offset-zinc-950 focus:border-blue-500 dark:focus:border-blue-300 ring-blue-300 dark:ring-blue-100 bg-transparent rounded-l-md rounded-r-md px-3"
/>
<button
type="submit"
className="cursor-pointer whitespace-nowrap font-semibold h-max transition-all border select-none outline-none px-3 py-2 text-sm flex items-center justify-center rounded-md text-white dark:text-black focus-visible:ring-2 ring-offset-2 ring-offset-white dark:ring-offset-zinc-950 border-transparent bg-blue-500 hover:bg-blue-600 dark:bg-blue-300/90 dark:hover:bg-blue-400/80 ring-blue-300 dark:ring-blue-100"
>
Search
</button>
</form>
{user && (
<div className="w-full rounded-xl ring-1 ring-transparent dark:ring-white/5 overflow-hidden drop-shadow-lg dark:drop-shadow-none">
<img
src={user.banner}
alt="banner"
className="h-36 w-full object-cover"
/>
<div className="bg-white dark:bg-zinc-900 p-4">
<div className="flex items-end justify-between -mt-16">
<div className="rounded-full size-28 border-[3px] border-white dark:border-zinc-900 overflow-hidden">
<img
src={user.avatar}
alt="profile-pic"
className="size-full object-cover"
/>
</div>
<a
href={`https://bsky.app/profile/${user.handle}`}
target="_blank"
rel="noreferrer"
className="rounded-full"
>
<button
type="button"
className="whitespace-nowrap cursor-pointer font-semibold h-max transition-all border select-none outline-none px-3 py-2 text-sm flex items-center justify-center rounded-full text-white dark:text-black focus-visible:ring-2 ring-offset-2 ring-offset-white dark:ring-offset-zinc-950 border-transparent bg-blue-500 hover:bg-blue-600 dark:bg-blue-300/90 dark:hover:bg-blue-400/80 ring-blue-300 dark:ring-blue-100"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="3"
stroke="currentColor"
className="size-3.5 mr-1"
>
<title>Plus Icon</title>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M12 4.5v15m7.5-7.5h-15"
/>
</svg>
Follow
</button>
</a>
</div>
<h1 className="text-lg font-semibold mt-2">{user.displayName}</h1>
<p className="text-sm text-zinc-500 dark:text-zinc-400">
@{user.handle}
</p>
<div className="mt-3 flex items-center gap-3 text-sm font-semibold">
<p>
{user.followersCount}
<span className="font-normal text-zinc-500 dark:text-zinc-400">
{' '}
Followers
</span>
</p>
<p>
{user.followsCount}
<span className="font-normal text-zinc-500 dark:text-zinc-400">
{' '}
Following
</span>
</p>
</div>
<p className="mt-4">{user.description}</p>
<div className="flex items-end justify-between">
<p className="text-sm text-zinc-400 dark:text-zinc-500">
Made with Tsky
</p>
<a
href="https://github.com/tsky-dev/tsky"
target="_blank"
rel="noreferrer"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 320 286"
className="size-8"
>
<title>Bluesky Icon</title>
<path
fill="rgb(10,122,255)"
d="M69.364 19.146c36.687 27.806 76.147 84.186 90.636 114.439 14.489-30.253 53.948-86.633 90.636-114.439C277.107-.917 320-16.44 320 32.957c0 9.865-5.603 82.875-8.889 94.729-11.423 41.208-53.045 51.719-90.071 45.357 64.719 11.12 81.182 47.953 45.627 84.785-80 82.874-106.667-44.333-106.667-44.333s-26.667 127.207-106.667 44.333c-35.555-36.832-19.092-73.665 45.627-84.785-37.026 6.362-78.648-4.149-90.071-45.357C5.603 115.832 0 42.822 0 32.957 0-16.44 42.893-.917 69.364 19.147Z"
/>
</svg>
</a>
</div>
</div>
</div>
)}
</div>
</main>
);
}

export default App;
1 change: 1 addition & 0 deletions examples/user-page/src/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import "tailwindcss";
16 changes: 16 additions & 0 deletions examples/user-page/src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App.tsx';

const root = document.getElementById('root');

if (!root) {
throw new Error('No root element found');
}

createRoot(root).render(
<StrictMode>
<App />
</StrictMode>,
);
1 change: 1 addition & 0 deletions examples/user-page/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
22 changes: 22 additions & 0 deletions examples/user-page/tsconfig.app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src"]
}
7 changes: 7 additions & 0 deletions examples/user-page/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}
20 changes: 20 additions & 0 deletions examples/user-page/tsconfig.node.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}
9 changes: 9 additions & 0 deletions examples/user-page/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';

// https://vite.dev/config/
export default defineConfig({
plugins: [react(), tailwindcss()],
base: '/examples/user-page/',
});
Loading