diff --git a/src/app.css b/src/app.css index 8e48a78e..fcf4b0cd 100644 --- a/src/app.css +++ b/src/app.css @@ -1438,6 +1438,7 @@ body:has(.media-modal-container + .status-deck) .media-post-link { display: inline-block; margin: 4px; align-self: center; + text-align: center; &.clickable { cursor: pointer; diff --git a/src/components/account-info.css b/src/components/account-info.css index 43b70526..0cd656ff 100644 --- a/src/components/account-info.css +++ b/src/components/account-info.css @@ -165,6 +165,76 @@ animation: fade-in 0.3s both ease-in-out 0.2s; } +.private-note-tag { + z-index: 1; + appearance: none; + display: inline-block; + color: var(--private-note-text-color); + background-color: var(--private-note-bg-color); + border: 1px solid var(--private-note-border-color); + padding: 4px; + line-height: normal; + font-size: smaller; + border-radius: 0; + align-self: center !important; + /* clip a dog ear on top right */ + clip-path: polygon(0 0, calc(100% - 4px) 0, 100% 4px, 100% 100%, 0 100%); + /* 4x4px square on top right */ + background-size: 4px 4px; + background-repeat: no-repeat; + background-position: top right; + background-image: linear-gradient( + to bottom, + var(--private-note-border-color), + var(--private-note-border-color) + ); + transition: transform 0.15s ease-in-out; + + span { + color: inherit; + opacity: 0.75; + text-overflow: ellipsis; + overflow: hidden; + display: -webkit-box; + display: box; + -webkit-box-orient: vertical; + box-orient: vertical; + -webkit-line-clamp: 2; + line-clamp: 2; + text-align: left; + } + + &:hover:not(:active) { + filter: none !important; + transform: rotate(-0.5deg) scale(1.05); + + span { + opacity: 1; + } + } +} +.account-container .private-note { + font-size: 90%; + color: var(--text-insignificant-color); + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + padding: 12px; + background-color: var(--bg-faded-color); + display: flex; + gap: 0.5em; + align-items: center; + + b { + font-size: 90%; + text-transform: uppercase; + } + p { + margin: 0; + padding: 0; + } +} + .account-container .note { font-size: 95%; line-height: 1.4; @@ -228,10 +298,11 @@ align-items: center; } .account-container .actions button { - align-self: flex-end; + /* align-self: flex-end; */ } .account-container .actions .buttons { display: flex; + align-items: center; } .account-container .account-metadata-box { @@ -571,3 +642,30 @@ drop-shadow(8px 0 8px var(--header-color-4, --bg-color)); } } + +#private-note-container { + textarea { + margin-top: 8px; + width: 100%; + resize: vertical; + height: 33vh; + min-height: 25vh; + max-height: 50vh; + color: var(--private-note-text-color); + background-color: var(--private-note-bg-color); + border: 1px solid var(--private-note-border-color); + box-shadow: 0 2px 8px var(--drop-shadow-color); + border-radius: 0; + padding: 16px; + } + + footer { + display: flex; + justify-content: space-between; + padding: 8px 0; + + * { + vertical-align: middle; + } + } +} diff --git a/src/components/account-info.jsx b/src/components/account-info.jsx index d5ac62c4..b97e9762 100644 --- a/src/components/account-info.jsx +++ b/src/components/account-info.jsx @@ -772,6 +772,7 @@ function RelatedActions({ requested, domainBlocking, endorsed, + note: privateNote, } = relationship || {}; const [currentInfo, setCurrentInfo] = useState(null); @@ -853,6 +854,7 @@ function RelatedActions({ const [showTranslatedBio, setShowTranslatedBio] = useState(false); const [showAddRemoveLists, setShowAddRemoveLists] = useState(false); + const [showPrivateNoteModal, setShowPrivateNoteModal] = useState(false); return ( <> @@ -863,9 +865,11 @@ function RelatedActions({ ) : !!lastStatusAt ? ( Last post:{' '} - {niceDateTime(lastStatusAt, { - hideTime: true, - })} + + {niceDateTime(lastStatusAt, { + hideTime: true, + })} + ) : ( @@ -874,6 +878,19 @@ function RelatedActions({ {blocking && Blocked} {' '} + {!!privateNote && ( + + )} Translate bio + { + setShowPrivateNoteModal(true); + }} + > + + + {privateNote ? 'Edit private note' : 'Add private note'} + + {/* Add/remove from lists is only possible if following the account */} {following && ( )} + {!!showPrivateNoteModal && ( + { + setShowPrivateNoteModal(false); + }} + > + { + setRelationship(relationship); + // onRelationshipChange({ relationship, currentID: accountID.current }); + }} + onClose={() => setShowPrivateNoteModal(false)} + /> + + )} ); } @@ -1434,4 +1479,95 @@ function AddRemoveListsSheet({ accountID, onClose }) { ); } +function PrivateNoteSheet({ + account, + note: initialNote, + onRelationshipChange = () => {}, + onClose = () => {}, +}) { + const { masto } = api(); + const [uiState, setUIState] = useState('default'); + const textareaRef = useRef(null); + + useEffect(() => { + let timer; + if (textareaRef.current && !initialNote) { + timer = setTimeout(() => { + textareaRef.current.focus?.(); + }, 100); + } + return () => { + clearTimeout(timer); + }; + }, []); + + return ( +
+ {!!onClose && ( + + )} +
+ Private note for @{account?.acct} +
+
+
{ + e.preventDefault(); + const formData = new FormData(e.target); + const note = formData.get('note'); + if (note?.trim() !== initialNote?.trim()) { + setUIState('loading'); + (async () => { + try { + const newRelationship = await masto.v1.accounts + .$select(account?.id) + .note.create({ + comment: note, + }); + console.log('updated relationship', newRelationship); + setUIState('default'); + onRelationshipChange(newRelationship); + onClose(); + } catch (e) { + console.error(e); + setUIState('error'); + alert(e?.message || 'Unable to update private note.'); + } + })(); + } + }} + > + + +
+
+
+ ); +} + export default AccountInfo; diff --git a/src/index.css b/src/index.css index 98a1ce08..8508da46 100644 --- a/src/index.css +++ b/src/index.css @@ -62,6 +62,9 @@ --close-button-bg-active-color: rgba(0, 0, 0, 0.2); --close-button-color: rgba(0, 0, 0, 0.5); --close-button-hover-color: rgba(0, 0, 0, 1); + --private-note-text-color: var(--text-color); + --private-note-bg-color: color-mix(in srgb, yellow 20%, var(--bg-color)); + --private-note-border-color: rgba(0, 0, 0, 0.2); /* Video colors won't change based on color scheme */ --media-fg-color: #f0f2f5; @@ -111,6 +114,7 @@ --close-button-bg-active-color: rgba(255, 255, 255, 0.15); --close-button-color: rgba(255, 255, 255, 0.5); --close-button-hover-color: rgba(255, 255, 255, 1); + --private-note-border-color: rgba(255, 255, 255, 0.2); } }