feat: display user public key after successful login

- Add userPublicKey state to App component
- Pass public key from Login to App to Bookmarks
- Display formatted public key in bookmarks header
- Show 'Logged in as: abc12345...xyz67890' format
- Update header layout to accommodate user info
- Add styling for user info display
- Improve login success feedback for users
This commit is contained in:
Gigi
2025-10-02 07:19:35 +02:00
parent f99c29ce78
commit fe35f45a42
7 changed files with 55 additions and 2116 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
:root{font-family:Inter,system-ui,Avenir,Helvetica,Arial,sans-serif;line-height:1.5;font-weight:400;color-scheme:light dark;color:#ffffffde;background-color:#242424;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-text-size-adjust:100%}body{margin:0;min-width:320px;min-height:100vh}#root{max-width:1280px;margin:0 auto;padding:2rem}.app{text-align:center}.app header{margin-bottom:2rem}.app header h1{font-size:2.5rem;margin:0;color:#646cff}.app header p{margin:.5rem 0 0;color:#888}.login-container{display:flex;justify-content:center;align-items:center;min-height:50vh}.login-card{background:#1a1a1a;padding:2rem;border-radius:8px;border:1px solid #333;max-width:400px;width:100%}.login-card h2{margin:0 0 1rem;color:#fff}.login-card p{margin:0 0 1.5rem;color:#ccc}.login-button{background:#646cff;color:#fff;border:none;padding:.75rem 1.5rem;border-radius:4px;font-size:1rem;cursor:pointer;transition:background-color .2s}.login-button:hover:not(:disabled){background:#535bf2}.login-button:disabled{opacity:.6;cursor:not-allowed}.bookmarks-container{text-align:left}.bookmarks-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:2rem;padding-bottom:1rem;border-bottom:1px solid #333}.bookmarks-header h2{margin:0;color:#fff}.logout-button{background:#dc3545;color:#fff;border:none;padding:.5rem 1rem;border-radius:4px;cursor:pointer;transition:background-color .2s}.logout-button:hover{background:#c82333}.loading{text-align:center;padding:2rem;color:#ccc}.empty-state{text-align:center;padding:3rem;color:#888}.empty-state p{margin:.5rem 0}.bookmarks-list{display:grid;gap:1rem}.bookmark-item{background:#1a1a1a;padding:1.5rem;border-radius:8px;border:1px solid #333;transition:border-color .2s}.bookmark-item:hover{border-color:#646cff}.bookmark-item h3{margin:0 0 .5rem;color:#fff;font-size:1.2rem}.bookmark-url{color:#646cff;text-decoration:none;display:block;margin-bottom:.5rem;word-break:break-all}.bookmark-url:hover{text-decoration:underline}.bookmark-content{color:#ccc;margin:.5rem 0;line-height:1.4}.bookmark-meta{color:#888;font-size:.9rem;margin-top:.5rem}@media (prefers-color-scheme: light){:root{color:#213547;background-color:#fff}.login-card,.bookmark-item{background:#f9f9f9;border-color:#ddd}.bookmarks-header{border-bottom-color:#ddd}.bookmark-item h3{color:#213547}.bookmark-content{color:#666}}

5
dist/index.html vendored
View File

@@ -5,10 +5,11 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Markr - Nostr Bookmarks</title>
<script type="module" crossorigin src="/assets/index-4FXhSRz4.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-FV8IYC7S.css">
<script type="module" crossorigin src="/assets/index-Cnm-Nmlg.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-D18sZheu.css">
</head>
<body>
<div id="root"></div>
</body>
</html>

View File

@@ -7,6 +7,7 @@ import Bookmarks from './components/Bookmarks'
function App() {
const [eventStore, setEventStore] = useState<EventStore | null>(null)
const [isAuthenticated, setIsAuthenticated] = useState(false)
const [userPublicKey, setUserPublicKey] = useState<string | null>(null)
useEffect(() => {
// Initialize event store
@@ -27,9 +28,18 @@ function App() {
</header>
{!isAuthenticated ? (
<Login onLogin={() => setIsAuthenticated(true)} />
<Login onLogin={(publicKey) => {
setIsAuthenticated(true)
setUserPublicKey(publicKey)
}} />
) : (
<Bookmarks onLogout={() => setIsAuthenticated(false)} />
<Bookmarks
userPublicKey={userPublicKey}
onLogout={() => {
setIsAuthenticated(false)
setUserPublicKey(null)
}}
/>
)}
</div>
</EventStoreProvider>

View File

@@ -12,39 +12,34 @@ interface Bookmark {
}
interface BookmarksProps {
userPublicKey: string | null
onLogout: () => void
}
const Bookmarks: React.FC<BookmarksProps> = ({ onLogout }) => {
const Bookmarks: React.FC<BookmarksProps> = ({ userPublicKey, onLogout }) => {
const [bookmarks, setBookmarks] = useState<Bookmark[]>([])
const [loading, setLoading] = useState(true)
const eventStore = useContext(EventStoreContext)
useEffect(() => {
if (eventStore) {
if (eventStore && userPublicKey) {
fetchBookmarks()
}
}, [eventStore])
}, [eventStore, userPublicKey])
const fetchBookmarks = async () => {
if (!eventStore) return
if (!eventStore || !userPublicKey) return
try {
setLoading(true)
// Get public key from nostr extension
const publicKey = await window.nostr?.getPublicKey()
if (!publicKey) {
throw new Error('No public key available')
}
// Fetch bookmarks according to NIP-51
// Kind 10003: bookmark lists
// Kind 30003: parameterized replaceable events (bookmark lists with d-tag)
const events = eventStore.getByFilters([
{
kinds: [10003, 30003],
authors: [publicKey]
authors: [userPublicKey]
}
])
@@ -109,11 +104,20 @@ const Bookmarks: React.FC<BookmarksProps> = ({ onLogout }) => {
return new Date(timestamp * 1000).toLocaleDateString()
}
const formatPublicKey = (publicKey: string) => {
return `${publicKey.slice(0, 8)}...${publicKey.slice(-8)}`
}
if (loading) {
return (
<div className="bookmarks-container">
<div className="bookmarks-header">
<h2>Your Bookmarks</h2>
<div>
<h2>Your Bookmarks</h2>
{userPublicKey && (
<p className="user-info">Logged in as: {formatPublicKey(userPublicKey)}</p>
)}
</div>
<button onClick={onLogout} className="logout-button">
Logout
</button>
@@ -126,7 +130,12 @@ const Bookmarks: React.FC<BookmarksProps> = ({ onLogout }) => {
return (
<div className="bookmarks-container">
<div className="bookmarks-header">
<h2>Your Bookmarks ({bookmarks.length})</h2>
<div>
<h2>Your Bookmarks ({bookmarks.length})</h2>
{userPublicKey && (
<p className="user-info">Logged in as: {formatPublicKey(userPublicKey)}</p>
)}
</div>
<button onClick={onLogout} className="logout-button">
Logout
</button>

View File

@@ -1,7 +1,7 @@
import { useState } from 'react'
interface LoginProps {
onLogin: () => void
onLogin: (publicKey: string) => void
}
const Login: React.FC<LoginProps> = ({ onLogin }) => {
@@ -20,7 +20,7 @@ const Login: React.FC<LoginProps> = ({ onLogin }) => {
const publicKey = await window.nostr.getPublicKey()
if (publicKey) {
onLogin()
onLogin(publicKey)
} else {
throw new Error('Failed to get public key')
}

View File

@@ -100,17 +100,28 @@ body {
.bookmarks-header {
display: flex;
justify-content: space-between;
align-items: center;
align-items: flex-start;
margin-bottom: 2rem;
padding-bottom: 1rem;
border-bottom: 1px solid #333;
}
.bookmarks-header > div {
flex: 1;
}
.bookmarks-header h2 {
margin: 0;
color: #fff;
}
.user-info {
margin: 0.5rem 0 0 0;
color: #888;
font-size: 0.9rem;
font-family: monospace;
}
.logout-button {
background: #dc3545;
color: white;
@@ -211,4 +222,8 @@ body {
.bookmark-content {
color: #666;
}
.user-info {
color: #666;
}
}