Skip to content
Merged
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
122 changes: 122 additions & 0 deletions src/cloud/components/Views/EditableDocItemContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { lngKeys } from '../../lib/i18n/types'
import { mdiDotsVertical, mdiPencilOutline, mdiTrashCanOutline } from '@mdi/js'
import React, { useCallback, useState } from 'react'
import { SerializedDocWithSupplemental } from '../../interfaces/db/doc'
import { useCloudApi } from '../../lib/hooks/useCloudApi'
import { useI18n } from '../../lib/hooks/useI18n'
import {
MenuItem,
MenuTypes,
useContextMenu,
} from '../../../design/lib/stores/contextMenu'
import Icon from '../../../design/components/atoms/Icon'
import styled from '../../../design/lib/styled'
import EditableInput from '../../../design/components/atoms/EditableInput'

interface ItemProps {
doc: SerializedDocWithSupplemental
children?: React.ReactNode
}

const EditableDocItemContainer = ({ doc, children }: ItemProps) => {
const [editingItemTitle, setEditingItemTitle] = useState<boolean>(false)
const [showingContextMenuActions, setShowingContextMenuActions] = useState<
boolean
>(false)

const { updateDoc, deleteDocApi, sendingMap } = useCloudApi()
const { translate } = useI18n()
const { popup } = useContextMenu()

const updateDocTitle = useCallback(
async (doc, newTitle) => {
await updateDoc(doc, {
workspaceId: doc.workspaceId,
parentFolderId: doc.parentFolderId,
title: newTitle,
})
setEditingItemTitle(false)
},
[updateDoc]
)

const openActionMenu: (
event: React.MouseEvent<HTMLDivElement>,
doc: SerializedDocWithSupplemental
) => void = useCallback(
(
event: React.MouseEvent<HTMLDivElement>,
doc: SerializedDocWithSupplemental
) => {
const editTitleAction: MenuItem = {
icon: <Icon path={mdiPencilOutline} />,
type: MenuTypes.Normal,
label: translate(lngKeys.GeneralEditTitle),
onClick: () => setEditingItemTitle(true),
}
const deleteDocAction: MenuItem = {
icon: <Icon path={mdiTrashCanOutline} />,
type: MenuTypes.Normal,
label: translate(lngKeys.GeneralDelete),
onClick: () => deleteDocApi({ id: doc.id, teamId: doc.teamId }),
}
const actions: MenuItem[] = [editTitleAction, deleteDocAction]

event.preventDefault()
event.stopPropagation()
popup(event, actions)
},
[deleteDocApi, popup, translate]
)

const showInput = !sendingMap.has(doc.id) && editingItemTitle
return (
<ItemContainer
onMouseEnter={() => setShowingContextMenuActions(true)}
onMouseLeave={() => setShowingContextMenuActions(false)}
>
{showInput && (
<EditableInput
editOnStart={true}
placeholder={'Title...'}
text={doc.title}
onTextChange={(newText) => updateDocTitle(doc, newText)}
onBlur={() => setEditingItemTitle(false)}
/>
)}

{!showInput && <>{children}</>}

{showingContextMenuActions && (
<div className={'item__container__item__actions'}>
<div
onClick={(event) => openActionMenu(event, doc)}
className='doc__action'
>
<Icon size={20} path={mdiDotsVertical} />
</div>
</div>
)}
</ItemContainer>
)
}

const ItemContainer = styled.div`
position: relative;

.item__container__item__actions {
position: absolute;
right: 5px;
z-index: 1;
margin: 0;
top: 50%;
transform: translate(-50%, -50%);

.doc__action {
width: 20px;
height: 20px;
}
}
`

export default EditableDocItemContainer
84 changes: 45 additions & 39 deletions src/cloud/components/Views/Kanban/Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { SerializedDocWithSupplemental } from '../../../interfaces/db/doc'
import { getDocTitle } from '../../../lib/utils/patterns'
import { isKanbanStaticProp, KanbanViewProp } from '../../../lib/views/kanban'
import PropPicker from '../../Props/PropPicker'
import EditableDocItemContainer from '../EditableDocItemContainer'

interface ItemProps {
doc: SerializedDocWithSupplemental
Expand All @@ -19,48 +20,53 @@ interface ItemProps {

const Item = ({ doc, displayedProps, onClick }: ItemProps) => {
return (
<Container
labelClick={() => onClick && onClick(doc)}
label={
<Flexbox direction='column'>
<Flexbox className='kanban__label__wrapper'>
<div className='kanban__label__icon'>
{doc.emoji != null ? (
<Emoji emoji={doc.emoji} set='apple' size={16} />
) : (
<Icon path={mdiFileDocumentOutline} size={16} />
)}
</div>
<span className='kanban__label'>
{getDocTitle(doc, 'Untitled')}
</span>
</Flexbox>
{Object.values(displayedProps).map((prop, i) => {
const docProp = doc.props[prop.name]
<EditableDocItemContainer doc={doc}>
<Container
labelClick={() => onClick && onClick(doc)}
label={
<Flexbox direction='column'>
<Flexbox className='kanban__label__wrapper'>
<div className='kanban__label__icon'>
{doc.emoji != null ? (
<Emoji emoji={doc.emoji} set='apple' size={16} />
) : (
<Icon path={mdiFileDocumentOutline} size={16} />
)}
</div>
<span className='kanban__label'>
{getDocTitle(doc, 'Untitled')}
</span>
</Flexbox>
{Object.values(displayedProps).map((prop, i) => {
const docProp = doc.props[prop.name]

if (isKanbanStaticProp(prop)) {
return
}
if (isKanbanStaticProp(prop)) {
return
}

if (docProp == null || docProp.data == null) {
return null
}
if (docProp == null || docProp.data == null) {
return null
}

return (
<div key={`kanban-${doc.id}-prop-${i}`} className='kanban__prop'>
<PropPicker
parent={{ type: 'doc', target: doc }}
propName={prop.name}
propData={docProp}
readOnly={true}
showIcon={true}
/>
</div>
)
})}
</Flexbox>
}
/>
return (
<div
key={`kanban-${doc.id}-prop-${i}`}
className='kanban__prop'
>
<PropPicker
parent={{ type: 'doc', target: doc }}
propName={prop.name}
propData={docProp}
readOnly={true}
showIcon={true}
/>
</div>
)
})}
</Flexbox>
}
/>
</EditableDocItemContainer>
)
}

Expand Down
48 changes: 25 additions & 23 deletions src/cloud/components/Views/List/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { getDocLinkHref } from '../../Link/DocLink'
import ListViewPropertiesContext from './ListViewPropertiesContext'
import { useListView } from '../../../lib/hooks/views/listView'
import ListDocProperties from './ListDocProperties'
import EditableDocItemContainer from '../EditableDocItemContainer'

type ListViewProps = {
view: SerializedView<ViewListData>
Expand Down Expand Up @@ -229,29 +230,30 @@ const ListView = ({
const { id } = doc
const href = getDocLinkHref(doc, team, 'index')
return (
<ListViewItem
key={id}
id={id}
checked={hasDocInSelection(doc.id)}
onSelect={() => toggleDocInSelection(doc.id)}
showCheckbox={currentUserIsCoreMember}
label={doc.title}
defaultIcon={mdiFileDocumentOutline}
emoji={doc.emoji}
labelHref={href}
labelOnclick={() => push(href)}
onDragStart={(event: any) => saveDocTransferData(event, doc)}
onDragEnd={(event: any) => clearDragTransferData(event)}
onDrop={(event: any) => onDropDoc(event, doc)}
hideOrderingHandle={true}
>
<ListDocProperties
doc={doc}
props={orderedViewProps}
team={team}
currentUserIsCoreMember={currentUserIsCoreMember}
/>
</ListViewItem>
<EditableDocItemContainer key={id} doc={doc}>
<ListViewItem
id={id}
checked={hasDocInSelection(doc.id)}
onSelect={() => toggleDocInSelection(doc.id)}
showCheckbox={currentUserIsCoreMember}
label={doc.title}
defaultIcon={mdiFileDocumentOutline}
emoji={doc.emoji}
labelHref={href}
labelOnclick={() => push(href)}
onDragStart={(event: any) => saveDocTransferData(event, doc)}
onDragEnd={(event: any) => clearDragTransferData(event)}
onDrop={(event: any) => onDropDoc(event, doc)}
hideOrderingHandle={true}
>
<ListDocProperties
doc={doc}
props={orderedViewProps}
team={team}
currentUserIsCoreMember={currentUserIsCoreMember}
/>
</ListViewItem>
</EditableDocItemContainer>
)
})}
{currentWorkspaceId != null && (
Expand Down
30 changes: 17 additions & 13 deletions src/cloud/components/Views/Table/TableView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import { DraggedTo } from '../../../../design/lib/dnd'
import { StyledContentManagerList } from '../../ContentManager/styled'
import Flexbox from '../../../../design/components/atoms/Flexbox'
import ColumnSettingsContext from './ColSettingsContext'
import { getDocLinkHref } from '../../Link/DocLink'
import NavigationItem from '../../../../design/components/molecules/Navigation/NavigationItem'
import { mdiFileDocumentOutline, mdiPlus } from '@mdi/js'
import DocTagsList from '../../DocPage/DocTagsList'
import { getFormattedBoosthubDateTime } from '../../../lib/date'
Expand All @@ -41,6 +39,9 @@ import Button from '../../../../design/components/atoms/Button'
import TableViewPropertiesContext from './TableViewPropertiesContext'
import TitleColumnSettingsContext from './TitleColumnSettingsContext'
import { usePage } from '../../../lib/stores/pageStore'
import EditableDocItemContainer from '../EditableDocItemContainer'
import NavigationItem from '../../../../design/components/molecules/Navigation/NavigationItem'
import { getDocLinkHref } from '../../Link/DocLink'
import { useCloudResourceModals } from '../../../lib/hooks/useCloudResourceModals'

type TableViewProps = {
Expand Down Expand Up @@ -72,14 +73,15 @@ const TableView = ({
toggleDocInSelection,
resetDocsInSelection,
}: TableViewProps) => {
const { goToDocPreview } = useCloudResourceModals()

const currentStateRef = useRef(view.data)
const [state, setState] = useState<ViewTableData>(
Object.assign({}, view.data as ViewTableData)
)
const { translate } = useI18n()
const { createDoc } = useCloudApi()
const { openContextModal, closeLastModal } = useModal()
const { goToDocPreview } = useCloudResourceModals()
const { permissions = [] } = usePage()

const {
Expand Down Expand Up @@ -268,16 +270,18 @@ const TableView = ({
cells: [
{
children: (
<NavigationItem
labelHref={docLink}
labelClick={() => goToDocPreview(doc)}
label={getDocTitle(doc, 'Untitled')}
icon={
doc.emoji != null
? { type: 'emoji', path: doc.emoji }
: { type: 'icon', path: mdiFileDocumentOutline }
}
/>
<EditableDocItemContainer doc={doc}>
<NavigationItem
labelHref={docLink}
labelClick={() => goToDocPreview(doc)}
label={getDocTitle(doc, 'Untitled')}
icon={
doc.emoji != null
? { type: 'emoji', path: doc.emoji }
: { type: 'icon', path: mdiFileDocumentOutline }
}
/>
</EditableDocItemContainer>
),
},
...orderedColumns.map((col) => {
Expand Down
1 change: 1 addition & 0 deletions src/cloud/lib/i18n/enUS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ const enTranslation: TranslationSource = {
[lngKeys.GeneralContinueVerb]: 'Continue',
[lngKeys.GeneralShared]: 'Shared',
[lngKeys.GeneralRenameVerb]: 'Rename',
[lngKeys.GeneralEditTitle]: 'Edit title',
[lngKeys.GeneralEditVerb]: 'Settings',
[lngKeys.GeneralBookmarks]: 'Bookmarks',
[lngKeys.GeneralUnbookmarkVerb]: 'Remove from Bookmarks',
Expand Down
1 change: 1 addition & 0 deletions src/cloud/lib/i18n/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ const frTranslation: TranslationSource = {
[lngKeys.GeneralMoveVerb]: 'Déplacer',
[lngKeys.GeneralShared]: 'Partagé',
[lngKeys.GeneralRenameVerb]: 'Renommer',
[lngKeys.GeneralEditTitle]: 'Modifier le titre',
[lngKeys.GeneralEditVerb]: 'Editer',
[lngKeys.GeneralDashboards]: 'Dashboards',
[lngKeys.GeneralBookmarks]: 'Favoris',
Expand Down
1 change: 1 addition & 0 deletions src/cloud/lib/i18n/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ const jpTranslation: TranslationSource = {
[lngKeys.GeneralContinueVerb]: '次に進む',
[lngKeys.GeneralShared]: 'シェア済',
[lngKeys.GeneralRenameVerb]: '名前変更',
[lngKeys.GeneralEditTitle]: 'タイトルを編集',
[lngKeys.GeneralEditVerb]: '編集',
[lngKeys.GeneralBookmarks]: 'ブックマーク',
[lngKeys.GeneralUnbookmarkVerb]: 'ブックマーク削除',
Expand Down
1 change: 1 addition & 0 deletions src/cloud/lib/i18n/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export enum lngKeys {
GeneralLabels = 'general.Labels',
GeneralMore = 'general.More',
GeneralStatus = 'general.Status',
GeneralEditTitle = 'general.EditTitle',
GeneralRenameVerb = 'general.Renameverb',
GeneralEditVerb = 'general.Editverb',
GeneralSettings = 'general.Settings',
Expand Down
1 change: 1 addition & 0 deletions src/cloud/lib/i18n/zhCN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ const zhTranslation: TranslationSource = {
[lngKeys.GeneralContinueVerb]: '跳过',
[lngKeys.GeneralShared]: '分享',
[lngKeys.GeneralRenameVerb]: '重命名',
[lngKeys.GeneralEditTitle]: '编辑标题',
[lngKeys.GeneralEditVerb]: '编辑',
[lngKeys.GeneralBookmarks]: '书签',
[lngKeys.GeneralUnbookmarkVerb]: '移除书签',
Expand Down
Loading