Skip to content
This repository has been archived by the owner on Jan 2, 2025. It is now read-only.

Commit

Permalink
frontend(editor): rendering publication embeds
Browse files Browse the repository at this point in the history
  • Loading branch information
horacioh committed Oct 17, 2023
1 parent 8009add commit 239a3f5
Show file tree
Hide file tree
Showing 8 changed files with 854 additions and 739 deletions.
151 changes: 151 additions & 0 deletions frontend/packages/app/components/static-embeds.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import {
Account,
DefaultStaticBlockUnknown,
Group,
StaticBlockNode,
StaticEmbedProps,
StaticGroup,
blockStyles,
createHmId,
getBlockNodeById,
} from '@mintter/shared'
import {SizableText, UIAvatar, XStack, YStack} from '@mintter/ui'
import {Book} from '@tamagui/lucide-icons'
import {useMemo} from 'react'
import {useAccount} from '../models/accounts'
import {usePublication} from '../models/documents'
import {useGroup} from '../models/groups'
import {getAvatarUrl} from '../utils/account-url'
import {NavRoute} from '../utils/navigation'

export function StaticBlockPublication(props: StaticEmbedProps) {
const docId = props.type == 'd' ? createHmId('d', props.eid) : undefined
const pub = usePublication({
id: docId,
version: props.version || undefined,
enabled: !!docId,
})

let embedData = useMemo(() => {
const {data} = pub

const selectedBlock =
props.blockRef && data?.document?.children
? getBlockNodeById(data.document.children, props.blockRef)
: null

const embedBlocks = selectedBlock
? [selectedBlock]
: data?.document?.children

return {
...pub,
data: {
publication: pub.data,
embedBlocks,
},
}
}, [props.blockRef, pub])

return (
<YStack
{...blockStyles}
className="block-static block-embed"
backgroundColor="$color5"
hoverStyle={{
backgroundColor: '$color6',
}}
overflow="hidden"
borderRadius="$3"
>
{embedData.data.embedBlocks?.length ? (
<StaticGroup childrenType="group">
{embedData.data.embedBlocks.map((bn, idx) => (
<StaticBlockNode
key={bn.block?.id}
depth={1}
blockNode={bn}
childrenType="group"
index={idx}
/>
))}
</StaticGroup>
) : (
<DefaultStaticBlockUnknown {...props} />
)}
</YStack>
)
}

export function StaticBlockGroup(props: StaticEmbedProps) {
const groupId = props.type == 'g' ? createHmId('d', props.eid) : undefined
const groupQuery = useGroup(groupId, props.version || undefined)

if (groupQuery.status == 'success') {
return <GroupCard group={groupQuery.data} />
}

return null
}

export function StaticBlockAccount(props: StaticEmbedProps) {
const accountId = props.type == 'a' ? props.eid : undefined
const accountQuery = useAccount(accountId)

if (accountQuery.status == 'success') {
return <AccountCard account={accountQuery.data} />
}

return null
}

function EntityCard({
title,
icon,
description,
route,
}: {
title?: string
icon?: React.ReactNode
description?: string
route: NavRoute
}) {
return (
<XStack gap="$3">
{icon}
<YStack>
<SizableText size="$5" fontWeight="bold" fontFamily="$body">
{title}
</SizableText>
<SizableText fontFamily="$body">{description}</SizableText>
</YStack>
</XStack>
)
}
function GroupCard({group}: {group: Group}) {
return (
<EntityCard
title={group.title}
description={group.description}
route={{key: 'group', groupId: group.id}}
icon={<Book />}
/>
)
}
function AccountCard({account}: {account: Account}) {
return (
<EntityCard
title={account.profile?.alias}
description={account.profile?.bio}
route={{key: 'account', accountId: account.id}}
icon={
<UIAvatar
id={account.id}
size={24}
label={account.profile?.alias}
url={getAvatarUrl(account.profile?.avatar)}
/>
}
/>
)
}
3 changes: 3 additions & 0 deletions frontend/packages/app/pages/draft.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export default function DraftPage() {
onEditorState: setDebugValue,
})

console.log(`== ~ DraftPage ~ query:`, query)

let isDaemonReady = useDaemonReady()

if (editor && query.data) {
Expand All @@ -45,6 +47,7 @@ export default function DraftPage() {
>
<MainWrapper>
{!isDaemonReady ? <NotSavingBanner /> : null}

<HMEditorContainer>
{editor && <HyperMediaEditorView editor={editor} />}
{debugValue && <DebugData data={debugValue} />}
Expand Down
9 changes: 8 additions & 1 deletion frontend/packages/app/pages/group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,14 @@ function PublicationDisplay({urlWithVersion}: {urlWithVersion: string}) {
})

return pub.status == 'success' && pub.data ? (
<StaticPublication publication={pub.data} />
<YStack
width="100%"
maxWidth="calc(90ch + 20vw)"
paddingHorizontal="$5"
alignSelf="center"
>
<StaticPublication publication={pub.data} />
</YStack>
) : null
}

Expand Down
37 changes: 32 additions & 5 deletions frontend/packages/app/pages/publication.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,24 @@ import {useDocChanges} from '@mintter/app/models/changes'
import {useDocCitations} from '@mintter/app/models/content-graph'
import {useNavRoute} from '@mintter/app/utils/navigation'
import {useNavigate} from '@mintter/app/utils/useNavigate'
import {MttLink, StaticPublication, pluralS, unpackDocId} from '@mintter/shared'
import {
MttLink,
StaticPublication,
StaticPublicationProvider,
pluralS,
unpackDocId,
} from '@mintter/shared'
import {Button, Link, MainWrapper, Text, XStack, YStack} from '@mintter/ui'
import {History} from '@tamagui/lucide-icons'
import {Allotment} from 'allotment'
import 'allotment/dist/style.css'
import {ErrorBoundary} from 'react-error-boundary'
import {EntityVersionsAccessory} from '../components/changes-list'
import {
StaticBlockAccount,
StaticBlockGroup,
StaticBlockPublication,
} from '../components/static-embeds'
import {VersionChangesInfo} from '../components/version-changes-info'
import {usePublicationInContext} from '../models/publication'
import {DocumentPlaceholder} from './document-placeholder'
Expand Down Expand Up @@ -64,10 +75,26 @@ export default function PublicationPage() {
<Allotment.Pane>
<YStack height="100%">
<MainWrapper>
<StaticPublication publication={publication.data} />
{route.versionId ? (
<OutOfDateBanner docId={docId} version={route.versionId} />
) : null}
<YStack
paddingVertical={80}
width="100%"
maxWidth="calc(90ch + 20vw)"
paddingHorizontal="10vw"
alignSelf="center"
>
<StaticPublicationProvider
entityComponents={{
StaticAccount: StaticBlockAccount,
StaticGroup: StaticBlockGroup,
StaticPublication: StaticBlockPublication,
}}
>
<StaticPublication publication={publication.data} />
</StaticPublicationProvider>
</YStack>
{version && (
<OutOfDateBanner docId={docId} version={version} />
)}
</MainWrapper>
</YStack>
</Allotment.Pane>
Expand Down
31 changes: 14 additions & 17 deletions frontend/packages/editor/src/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,23 @@ import {
import './blocknote/core/style.css'
import './editor.css'
import {useOpenUrl} from '@mintter/app/open-url'
import {
DefaultStaticBlockAccount,
DefaultStaticBlockGroup,
DefaultStaticBlockPublication,
StaticPublicationProvider,
} from '@mintter/shared'

export function HyperMediaEditorView({editor}: {editor: HyperDocsEditor}) {
const openUrl = useOpenUrl()
if (editor.isEditable) {
return (
<BlockNoteView editor={editor}>
<FormattingToolbarPositioner editor={editor} />
<HyperlinkToolbarPositioner editor={editor} openUrl={openUrl} />
<SlashMenuPositioner editor={editor} />
<SideMenuPositioner editor={editor} placement="left" />
</BlockNoteView>
)
} else {
return (
<BlockNoteView editor={editor}>
{/* This is needed so no elements will be rendered for non-editable publications */}
<YStack opacity={0} pointerEvents="none" />
</BlockNoteView>
)
}
return (
<BlockNoteView editor={editor}>
<FormattingToolbarPositioner editor={editor} />
<HyperlinkToolbarPositioner editor={editor} openUrl={openUrl} />
<SlashMenuPositioner editor={editor} />
<SideMenuPositioner editor={editor} placement="left" />
</BlockNoteView>
)
}

export function HMEditorContainer({children}: {children: React.ReactNode}) {
Expand Down
Loading

0 comments on commit 239a3f5

Please sign in to comment.