summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-11-18 09:43:16 +0700
committerpolwex <polwex@sortug.com>2025-11-18 09:43:16 +0700
commita465c73178dc621578d10312f263355f0f2d5309 (patch)
tree08a0b655835d4c08d45e8e3e8f52601f7911044b
parent7706acaafa89691dba33c216e6287a8405c4c302 (diff)
fixes to profile handling and rendering
-rw-r--r--app/app/nostrill.hoon12
-rw-r--r--app/lib/json/nostr.hoon5
-rw-r--r--app/lib/nostr/client.hoon12
-rw-r--r--app/lib/websockets.hoon5
-rw-r--r--gui/devenv.nix8
-rw-r--r--gui/src/components/Avatar.tsx9
-rw-r--r--gui/src/components/modals/UserModal.tsx256
-rw-r--r--gui/src/components/post/Post.tsx4
-rw-r--r--gui/src/logic/nostr.ts10
-rw-r--r--gui/src/styles/UserModal.css316
-rw-r--r--gui/src/styles/styles.css10
11 files changed, 608 insertions, 39 deletions
diff --git a/app/app/nostrill.hoon b/app/app/nostrill.hoon
index 9d67dea..230f72f 100644
--- a/app/app/nostrill.hoon
+++ b/app/app/nostrill.hoon
@@ -234,6 +234,11 @@
:_ this
:~ (connect:ws endpoint bowl)
==
+ %wscancel
+ =/ wid 1
+ :_ this
+ :~ (cancel-connect:ws wid)
+ ==
%wstest
:: =/ url 'ws://localhost:8888'
=/ url 'wss://nos.lol'
@@ -313,6 +318,13 @@
$(pfs t.pfs)
`this
+ [%prof @]
+ =/ pubkey=(unit @ux) (slaw:sr %ux +.noun)
+ ~& pubkey=pubkey
+ ?~ pubkey ~& "pubkey not valid hex. take out the 0x maybe" !!
+ =^ cs state (get-profile:nclient u.pubkey)
+ [cs this]
+
%wtf
=/ lol=(unit @) ~
=/ l ~| "wtf" (need lol)
diff --git a/app/lib/json/nostr.hoon b/app/lib/json/nostr.hoon
index 3c42f0b..ca4ed43 100644
--- a/app/lib/json/nostr.hoon
+++ b/app/lib/json/nostr.hoon
@@ -276,10 +276,13 @@
?~ crd $(fields t.fields) $(fields t.fields, um um(name u.crd))
%'about'
=/ crd (so jn)
- ?~ crd $(fields t.fields) $(fields t.fields, um um(picture u.crd))
+ ?~ crd $(fields t.fields) $(fields t.fields, um um(about u.crd))
%'picture'
=/ crd (so jn)
?~ crd $(fields t.fields) $(fields t.fields, um um(picture u.crd))
+ %'image'
+ =/ crd (so jn)
+ ?~ crd $(fields t.fields) $(fields t.fields, um um(picture u.crd))
==
--
--
diff --git a/app/lib/nostr/client.hoon b/app/lib/nostr/client.hoon
index 741c51e..9c732bb 100644
--- a/app/lib/nostr/client.hoon
+++ b/app/lib/nostr/client.hoon
@@ -69,6 +69,13 @@
=/ =filter:nsur [~ `pubkeys `kinds ~ ~ ~ ~]
(send-req ~[filter] .y ~)
+++ get-profile |= pubkey=@ux
+ =/ kinds (silt ~[0])
+ :: =/ since (to-unix-secs:jikan:sr last-week)
+ =/ pubkeys (silt ~[pubkey])
+ =/ =filter:nsur [~ `pubkeys `kinds ~ ~ ~ ~]
+ (send-req ~[filter] .n ~)
+
++ get-profiles
^- (quip card _state)
=/ npoasts (tap:norm:sur nostr-feed.state)
@@ -80,11 +87,12 @@
=. missing-profs ?: have missing-profs (~(put in missing-profs) pubkey.poast)
$(npoasts t.npoasts)
=/ kinds (silt ~[0])
- ?. (gth ~(wyt in pubkeys) 300)
+ =/ chunk-size 300
+ ?. (gth ~(wyt in pubkeys) chunk-size)
=/ =filter:nsur [~ `pubkeys `kinds ~ ~ ~ ~]
(send-req ~[filter] .n ~)
::
- =/ chunks=(list (list @ux)) (chunk-by-size:seq ~(tap in pubkeys) 300)
+ =/ chunks=(list (list @ux)) (chunk-by-size:seq ~(tap in pubkeys) chunk-size)
?~ chunks ~& >>> "error chunking pubkeys" `state
=/ queue=(list filter:nsur)
%+ turn t.chunks |= l=(list @ux) ^- filter:nsur
diff --git a/app/lib/websockets.hoon b/app/lib/websockets.hoon
index ae48775..a87f2a1 100644
--- a/app/lib/websockets.hoon
+++ b/app/lib/websockets.hoon
@@ -4,6 +4,11 @@
=/ =task:iris [%websocket-connect dap.bowl endpoint]
[%pass /ws-connect %arvo %i task]
+ ++ cancel-connect |= wid=@ud
+ ^- card:agent:gall
+ =/ =task:iris [%cancel-websocket wid]
+ [%pass /ws-connect %arvo %i task]
+
++ disconnect |= wid=@ud
^- card:agent:gall
=/ =path /websocket-client/(scot %ud wid)
diff --git a/gui/devenv.nix b/gui/devenv.nix
index e4e3748..af7c11f 100644
--- a/gui/devenv.nix
+++ b/gui/devenv.nix
@@ -8,6 +8,14 @@
# https://devenv.sh/basics/
env.GREET = "devenv";
+ env.ANTHROPIC_BASE_URL = "https://api.moonshot.ai/anthropic";
+ env.ANTHROPIC_AUTH_TOKEN = "sk-el9tYLoqFmDrauY293aUpMUvgncoYjCtofRjKsdgrrI9NrP2";
+ env.ANTHROPIC_MODEL = "kimi-k2-thinking-turbo";
+ env.ANTHROPIC_DEFAULT_OPUS_MODEL = "kimi-k2-thinking-turbo";
+ env.ANTHROPIC_DEFAULT_SONNET_MODEL = "kimi-k2-thinking-turbo";
+ env.ANTHROPIC_DEFAULT_HAIKU_MODEL = "kimi-k2-thinking-turbo";
+ env.CLAUDE_CODE_SUBAGENT_MODEL = "kimi-k2-thinking-turbo ";
+
# https://devenv.sh/packages/
packages = with pkgs; [
git
diff --git a/gui/src/components/Avatar.tsx b/gui/src/components/Avatar.tsx
index a071655..2b38848 100644
--- a/gui/src/components/Avatar.tsx
+++ b/gui/src/components/Avatar.tsx
@@ -43,7 +43,7 @@ export default function ({
function openModal(e: React.MouseEvent) {
if (noClickOnName) return;
e.stopPropagation();
- setModal(<UserModal user={user} userString={userString} />);
+ setModal(<UserModal userString={userString} />);
}
const name = (
<div className="name cp" role="link" onMouseUp={openModal}>
@@ -58,5 +58,10 @@ export default function ({
)}
</div>
);
- return <div className="ship-avatar">{name}</div>;
+ return (
+ <div className="ship-avatar">
+ {avatar}
+ {name}
+ </div>
+ );
}
diff --git a/gui/src/components/modals/UserModal.tsx b/gui/src/components/modals/UserModal.tsx
index 6e3089d..0694f1e 100644
--- a/gui/src/components/modals/UserModal.tsx
+++ b/gui/src/components/modals/UserModal.tsx
@@ -4,59 +4,259 @@ import Icon from "@/components/Icon";
import useLocalState from "@/state/state";
import { useLocation } from "wouter";
import toast from "react-hot-toast";
-import type { UserType } from "@/types/nostrill";
-
-export default function ({
- user,
- userString,
-}: {
- user: UserType;
- userString: string;
-}) {
- const { setModal, api, pubkey } = useLocalState((s) => ({
+import { isValidPatp } from "urbit-ob";
+import { isValidNostrPubkey } from "@/logic/nostrill";
+import { generateNprofile } from "@/logic/nostr";
+import { useState } from "react";
+
+export default function ({ userString }: { userString: string }) {
+ const { setModal, api, pubkey, profiles, following, followers } = useLocalState((s) => ({
setModal: s.setModal,
api: s.api,
pubkey: s.pubkey,
+ profiles: s.profiles,
+ following: s.following,
+ followers: s.followers,
}));
const [_, navigate] = useLocation();
+ const [loading, setLoading] = useState(false);
+
function close() {
setModal(null);
}
+
+ const user = isValidPatp(userString)
+ ? { urbit: userString }
+ : isValidNostrPubkey(userString)
+ ? { nostr: userString }
+ : { error: "" };
+
+ if ("error" in user) {
+ return (
+ <Modal close={close}>
+ <div className="user-modal-error">
+ <Icon name="comet" size={48} />
+ <p>Invalid user identifier</p>
+ </div>
+ </Modal>
+ );
+ }
+
const itsMe =
"urbit" in user
? user.urbit === api?.airlock.our
: "nostr" in user
? user.nostr === pubkey
: false;
+
+ const profile = profiles.get(userString);
+ const isFollowing = following.has(userString);
+ const isFollower = followers.includes(userString);
+
+ // Get follower/following counts from the user's feed if available
+ const userFeed = following.get(userString);
+ const postCount = userFeed ? Object.keys(userFeed.feed).length : 0;
+
async function copy(e: React.MouseEvent) {
e.stopPropagation();
await navigator.clipboard.writeText(userString);
toast.success("Copied to clipboard");
}
+
+ async function handleFollow(e: React.MouseEvent) {
+ e.stopPropagation();
+ if (!api) return;
+
+ setLoading(true);
+ try {
+ if (isFollowing) {
+ const result = await api.unfollow(userString);
+ if ("ok" in result) {
+ toast.success(`Unfollowed ${profile?.name || userString}`);
+ } else {
+ toast.error(result.error);
+ }
+ } else {
+ const result = await api.follow(userString);
+ if ("ok" in result) {
+ toast.success(`Following ${profile?.name || userString}`);
+ } else {
+ toast.error(result.error);
+ }
+ }
+ } catch (err) {
+ toast.error("Action failed");
+ } finally {
+ setLoading(false);
+ }
+ }
+
+ async function handleAvatarClick(e: React.MouseEvent) {
+ e.stopPropagation();
+ if ("nostr" in user) {
+ const nprof = generateNprofile(userString);
+ const href = `https://primal.net/p/${nprof}`;
+ window.open(href, "_blank");
+ }
+ }
+
+ const displayName = profile?.name || ("urbit" in user ? user.urbit : "Anon");
+ const truncatedId = userString.length > 20
+ ? `${userString.slice(0, 10)}...${userString.slice(-8)}`
+ : userString;
+
+ // Check if a string is a URL
+ const isURL = (str: string): boolean => {
+ try {
+ new URL(str);
+ return true;
+ } catch {
+ return str.startsWith('http://') || str.startsWith('https://');
+ }
+ };
+
+ // Get banner image from profile.other
+ const bannerImage = profile?.other?.banner || profile?.other?.Banner;
+
+ // Filter out banner from other fields since we display it separately
+ const otherFields = profile?.other
+ ? Object.entries(profile.other).filter(
+ ([key]) => key.toLowerCase() !== 'banner'
+ )
+ : [];
+
return (
<Modal close={close}>
- <div id="ship-modal">
- <div className="flex">
- <Avatar user={user} userString={userString} size={60} />
- <Icon
- name="copy"
- size={20}
- className="copy-icon cp"
- onClick={copy}
- title="Copy ship name"
- />
+ <div className="user-modal">
+ {/* Banner Image */}
+ {bannerImage && (
+ <div className="user-modal-banner">
+ <img src={bannerImage} alt="Profile banner" />
+ </div>
+ )}
+
+ {/* Header with Avatar and Basic Info */}
+ <div className="user-modal-header">
+ <div
+ className="user-modal-avatar-wrapper"
+ onClick={handleAvatarClick}
+ style={{ cursor: "nostr" in user ? "pointer" : "default" }}
+ >
+ <Avatar
+ user={user}
+ userString={userString}
+ profile={profile}
+ size={80}
+ picOnly
+ />
+ </div>
+
+ <div className="user-modal-info">
+ <h2 className="user-modal-name">{displayName}</h2>
+ <div className="user-modal-id-row">
+ <span className="user-modal-id" title={userString}>
+ {"urbit" in user ? user.urbit : truncatedId}
+ </span>
+ <Icon
+ name="copy"
+ size={16}
+ className="user-modal-copy-icon cp"
+ onClick={copy}
+ title="Copy to clipboard"
+ />
+ </div>
+
+ {/* User type badge */}
+ <div className="user-modal-badge">
+ {"urbit" in user ? (
+ <span className="badge badge-urbit">Urbit</span>
+ ) : (
+ <span className="badge badge-nostr">Nostr</span>
+ )}
+ {itsMe && <span className="badge badge-me">You</span>}
+ {isFollower && !itsMe && <span className="badge badge-follows">Follows you</span>}
+ </div>
+ </div>
</div>
- <div className="buttons f1">
- <button onClick={() => navigate(`/feed/${userString}`)}>Feed</button>
- <button onClick={() => navigate(`/pals/${userString}`)}>
- Profile
- </button>
- {itsMe && (
+
+ {/* Profile About Section */}
+ {profile?.about && (
+ <div className="user-modal-about">
+ <p>{profile.about}</p>
+ </div>
+ )}
+
+ {/* Stats */}
+ <div className="user-modal-stats">
+ {postCount > 0 && (
+ <div className="stat">
+ <span className="stat-value">{postCount}</span>
+ <span className="stat-label">Posts</span>
+ </div>
+ )}
+ {/* Additional stats could go here */}
+ </div>
+
+ {/* Custom Fields */}
+ {otherFields.length > 0 && (
+ <div className="user-modal-custom-fields">
+ <h4>Additional Info</h4>
+ {otherFields.map(([key, value]) => (
+ <div key={key} className="custom-field-item">
+ <span className="field-key">{key}:</span>
+ {isURL(value) ? (
+ <a
+ href={value}
+ target="_blank"
+ rel="noopener noreferrer"
+ className="field-value field-link"
+ onClick={(e) => e.stopPropagation()}
+ >
+ {value}
+ <Icon name="nostr" size={12} className="external-link-icon" />
+ </a>
+ ) : (
+ <span className="field-value">{value}</span>
+ )}
+ </div>
+ ))}
+ </div>
+ )}
+
+ {/* Action Buttons */}
+ <div className="user-modal-actions">
+ {!itsMe && (
+ <button
+ className={`action-btn ${isFollowing ? "following" : "follow"}`}
+ onClick={handleFollow}
+ disabled={loading}
+ >
+ <Icon name="pals" size={16} />
+ {loading ? "..." : isFollowing ? "Following" : "Follow"}
+ </button>
+ )}
+
+ {"urbit" in user ? (
<>
- <button onClick={() => navigate(`/chat/dm/${userString}`)}>
- DM
+ <button
+ className="action-btn secondary"
+ onClick={() => {
+ navigate(`/feed/${userString}`);
+ close();
+ }}
+ >
+ <Icon name="home" size={16} />
+ View Feed
</button>
</>
+ ) : (
+ <button
+ className="action-btn secondary"
+ onClick={handleAvatarClick}
+ >
+ <Icon name="nostr" size={16} />
+ View on Primal
+ </button>
)}
</div>
</div>
diff --git a/gui/src/components/post/Post.tsx b/gui/src/components/post/Post.tsx
index 2d9a09a..7413e70 100644
--- a/gui/src/components/post/Post.tsx
+++ b/gui/src/components/post/Post.tsx
@@ -6,7 +6,7 @@ import Footer from "./Footer";
import { useLocation } from "wouter";
import useLocalState from "@/state/state";
import RP from "./RP";
-import ShipModal from "../modals/ShipModal";
+import UserModal from "../modals/UserModal";
import type { Ship } from "@/types/urbit";
import Sigil from "../Sigil";
import type { UserProfile } from "@/types/nostrill";
@@ -57,7 +57,7 @@ function TrillPost(props: PostProps) {
function openModal(e: React.MouseEvent) {
e.stopPropagation();
- setModal(<ShipModal ship={poast.author} />);
+ setModal(<UserModal userString={poast.author} />);
}
const avatar = profile ? (
<div className="avatar sigil cp" role="link" onMouseUp={openModal}>
diff --git a/gui/src/logic/nostr.ts b/gui/src/logic/nostr.ts
index b85047f..7da9b91 100644
--- a/gui/src/logic/nostr.ts
+++ b/gui/src/logic/nostr.ts
@@ -12,6 +12,16 @@ export function generateNevent(event: Event) {
return nev;
}
+export function generateNpub(pubkey: string) {
+ const npub = nip19.npubEncode(pubkey);
+ return npub;
+}
+export function generateNprofile(pubkey: string) {
+ const prof = { pubkey };
+ const nprofile = nip19.nprofileEncode(prof);
+ return nprofile;
+}
+
// let sk = generateSecretKey()
// let nsec = nip19.nsecEncode(sk)
// let { type, data } = nip19.decode(nsec)
diff --git a/gui/src/styles/UserModal.css b/gui/src/styles/UserModal.css
new file mode 100644
index 0000000..bf4ff56
--- /dev/null
+++ b/gui/src/styles/UserModal.css
@@ -0,0 +1,316 @@
+/* User Modal Styles */
+
+.user-modal {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ min-width: 400px;
+ max-width: 500px;
+ padding: 24px;
+}
+
+.user-modal-error {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 16px;
+ padding: 40px;
+ text-align: center;
+ color: var(--color-text-secondary);
+}
+
+/* Header Section */
+.user-modal-header {
+ display: flex;
+ gap: 16px;
+ align-items: flex-start;
+}
+
+.user-modal-avatar-wrapper {
+ flex-shrink: 0;
+}
+
+.user-modal-avatar-wrapper .avatar {
+ width: 80px;
+ height: 80px;
+ border-radius: 50%;
+ overflow: hidden;
+ border: 3px solid var(--color-border);
+ transition: transform 0.2s ease, border-color 0.2s ease;
+}
+
+.user-modal-avatar-wrapper .avatar:hover {
+ transform: scale(1.05);
+ border-color: var(--color-primary);
+}
+
+.user-modal-avatar-wrapper .avatar img,
+.user-modal-avatar-wrapper .avatar canvas {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+
+.user-modal-info {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ min-width: 0;
+}
+
+.user-modal-name {
+ margin: 0;
+ font-size: 24px;
+ font-weight: 600;
+ color: var(--color-text);
+ word-wrap: break-word;
+}
+
+.user-modal-id-row {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.user-modal-id {
+ font-size: 14px;
+ color: var(--color-text-secondary);
+ font-family: "Source Code Pro", monospace;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.user-modal-copy-icon {
+ flex-shrink: 0;
+ color: var(--color-text-secondary);
+ transition: color 0.2s ease;
+}
+
+.user-modal-copy-icon:hover {
+ color: var(--color-primary);
+}
+
+/* Badges */
+.user-modal-badge {
+ display: flex;
+ gap: 6px;
+ flex-wrap: wrap;
+}
+
+.badge {
+ display: inline-flex;
+ align-items: center;
+ padding: 4px 10px;
+ font-size: 12px;
+ font-weight: 500;
+ border-radius: 12px;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+.badge-urbit {
+ background: var(--color-primary);
+ color: white;
+}
+
+.badge-nostr {
+ background: #8e44ad;
+ color: white;
+}
+
+.badge-me {
+ background: var(--color-accent);
+ color: white;
+}
+
+.badge-follows {
+ background: var(--color-surface);
+ color: var(--color-text-secondary);
+ border: 1px solid var(--color-border);
+}
+
+/* About Section */
+.user-modal-about {
+ padding: 16px;
+ background: var(--color-surface);
+ border-radius: 8px;
+ border-left: 3px solid var(--color-primary);
+}
+
+.user-modal-about p {
+ margin: 0;
+ color: var(--color-text);
+ line-height: 1.6;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+/* Stats */
+.user-modal-stats {
+ display: flex;
+ gap: 24px;
+ padding: 16px;
+ background: var(--color-surface);
+ border-radius: 8px;
+}
+
+.stat {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 4px;
+}
+
+.stat-value {
+ font-size: 20px;
+ font-weight: 600;
+ color: var(--color-text);
+}
+
+.stat-label {
+ font-size: 12px;
+ color: var(--color-text-secondary);
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+/* Custom Fields */
+.user-modal-custom-fields {
+ padding: 16px;
+ background: var(--color-surface);
+ border-radius: 8px;
+}
+
+.user-modal-custom-fields h4 {
+ margin: 0 0 12px 0;
+ font-size: 14px;
+ font-weight: 600;
+ color: var(--color-text);
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+.custom-field-item {
+ display: flex;
+ gap: 8px;
+ margin-bottom: 8px;
+ font-size: 14px;
+}
+
+.custom-field-item:last-child {
+ margin-bottom: 0;
+}
+
+.custom-field-item .field-key {
+ font-weight: 500;
+ color: var(--color-text);
+ min-width: 100px;
+}
+
+.custom-field-item .field-value {
+ color: var(--color-text-secondary);
+ word-wrap: break-word;
+ flex: 1;
+}
+
+/* Action Buttons */
+.user-modal-actions {
+ display: flex;
+ gap: 12px;
+ padding-top: 8px;
+ border-top: 1px solid var(--color-border);
+}
+
+.user-modal-actions .action-btn {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ padding: 12px 20px;
+ border: 2px solid;
+ border-radius: 8px;
+ font-size: 14px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ background: transparent;
+}
+
+.user-modal-actions .action-btn:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+.user-modal-actions .action-btn.follow {
+ border-color: var(--color-primary);
+ color: var(--color-primary);
+}
+
+.user-modal-actions .action-btn.follow:hover:not(:disabled) {
+ background: var(--color-primary);
+ color: white;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+}
+
+.user-modal-actions .action-btn.following {
+ border-color: var(--color-success);
+ background: var(--color-success);
+ color: white;
+}
+
+.user-modal-actions .action-btn.following:hover:not(:disabled) {
+ background: var(--color-error);
+ border-color: var(--color-error);
+ transform: translateY(-1px);
+}
+
+.user-modal-actions .action-btn.secondary {
+ border-color: var(--color-border);
+ color: var(--color-text);
+}
+
+.user-modal-actions .action-btn.secondary:hover:not(:disabled) {
+ border-color: var(--color-text-secondary);
+ background: var(--color-surface);
+ transform: translateY(-1px);
+}
+
+/* Responsive adjustments */
+@media (max-width: 480px) {
+ .user-modal {
+ min-width: 320px;
+ max-width: 100%;
+ padding: 16px;
+ }
+
+ .user-modal-name {
+ font-size: 20px;
+ }
+
+ .user-modal-actions {
+ flex-direction: column;
+ }
+
+ .user-modal-actions .action-btn {
+ width: 100%;
+ }
+}
+
+/* Modal background improvements for user modal */
+#modal-background {
+ background: rgba(0, 0, 0, 0.6);
+ backdrop-filter: blur(4px);
+}
+
+#modal {
+ background: var(--color-background);
+ border-radius: 16px;
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
+ max-height: 90vh;
+ overflow-y: auto;
+}
diff --git a/gui/src/styles/styles.css b/gui/src/styles/styles.css
index ac3c71b..5772c40 100644
--- a/gui/src/styles/styles.css
+++ b/gui/src/styles/styles.css
@@ -1,4 +1,5 @@
@import "tailwindcss";
+@import "./UserModal.css";
/* assets */
/* fonts */
@@ -573,10 +574,6 @@ h6 {
}
}
- post-body {
- max-height: 300px;
- overflow-y: auto;
- }
& .date {
color: grey;
@@ -584,6 +581,11 @@ h6 {
}
+ .body {
+ max-height: 300px;
+ overflow-y: auto;
+ }
+
& footer {
justify-content: left;
margin: unset;