Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sidebar attachments preview #6797

Merged
merged 3 commits into from
Oct 3, 2024
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
3 changes: 2 additions & 1 deletion models/attachment/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@hcengineering/ui": "^0.6.15",
"@hcengineering/view": "^0.6.13",
"@hcengineering/model-presentation": "^0.6.0",
"@hcengineering/model-uploader": "^0.6.0"
"@hcengineering/model-uploader": "^0.6.0",
"@hcengineering/workbench": "^0.6.16"
}
}
20 changes: 20 additions & 0 deletions models/attachment/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import {
import core, { TAttachedDoc } from '@hcengineering/model-core'
import preference, { TPreference } from '@hcengineering/model-preference'
import view, { createAction } from '@hcengineering/model-view'
import workbench, { WidgetType } from '@hcengineering/workbench'
import presentation from '@hcengineering/model-presentation'

import attachment from './plugin'

Expand Down Expand Up @@ -97,6 +99,24 @@ export function createModel (builder: Builder): void {
editor: attachment.component.Photos
})

builder.createDoc(
workbench.class.Widget,
core.space.Model,
{
label: attachment.string.Files,
type: WidgetType.Flexible,
icon: attachment.icon.Attachment,
component: attachment.component.PreviewWidget,
closeIfNoTabs: true
},
attachment.ids.PreviewWidget
)

builder.createDoc(presentation.class.ComponentPointExtension, core.space.Model, {
extension: presentation.extension.FilePreviewPopupActions,
component: attachment.component.PreviewPopupActions
})

builder.createDoc(
activity.class.DocUpdateMessageViewlet,
core.space.Model,
Expand Down
4 changes: 3 additions & 1 deletion models/attachment/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ import type { ActionCategory } from '@hcengineering/view'

export default mergeIds(attachmentId, attachment, {
component: {
AttachmentPresenter: '' as AnyComponent
AttachmentPresenter: '' as AnyComponent,
PreviewWidget: '' as AnyComponent,
PreviewPopupActions: '' as AnyComponent
},
string: {
AddAttachment: '' as IntlString,
Expand Down
43 changes: 43 additions & 0 deletions packages/presentation/src/components/DownloadFileButton.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!--
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import type { Ref, Blob } from '@hcengineering/core'
import { Button } from '@hcengineering/ui'

import { getFileUrl } from '../file'
import Download from './icons/Download.svelte'
import presentation from '../plugin'

export let file: Ref<Blob> | undefined
export let name: string

let download: HTMLAnchorElement
$: srcRef = file !== undefined ? getFileUrl(file, name) : undefined
</script>

{#await srcRef then src}
{#if src !== ''}
<a class="no-line" href={src} download={name} bind:this={download}>
<Button
icon={Download}
kind={'icon'}
on:click={() => {
download.click()
}}
showTooltip={{ label: presentation.string.Download }}
/>
</a>
{/if}
{/await}
64 changes: 16 additions & 48 deletions packages/presentation/src/components/FilePreviewPopup.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@
<script lang="ts">
import { type Blob, type Ref } from '@hcengineering/core'
import { getEmbeddedLabel } from '@hcengineering/platform'
import { Button, Dialog, tooltip } from '@hcengineering/ui'
import { Dialog, tooltip } from '@hcengineering/ui'
import { createEventDispatcher, onMount } from 'svelte'

import presentation from '../plugin'

import { getFileUrl } from '../file'
import { BlobMetadata } from '../types'

import ActionContext from './ActionContext.svelte'
import FilePreview from './FilePreview.svelte'
import Download from './icons/Download.svelte'
import DownloadFileButton from './DownloadFileButton.svelte'
import { ComponentExtensions } from '../index'
import presentation from '../plugin'
import FileTypeIcon from './FileTypeIcon.svelte'

export let file: Ref<Blob> | undefined
export let name: string
Expand All @@ -38,21 +38,11 @@

const dispatch = createEventDispatcher()

let download: HTMLAnchorElement

onMount(() => {
if (fullSize) {
dispatch('fullsize')
}
})

function iconLabel (name: string): string {
const parts = `${name}`.split('.')
const ext = parts[parts.length - 1]
return ext.substring(0, 4).toUpperCase()
}

$: srcRef = file !== undefined ? getFileUrl(file, name) : undefined
</script>

<ActionContext context={{ mode: 'browser' }} />
Expand All @@ -67,49 +57,27 @@
<div class="antiTitle icon-wrapper">
{#if showIcon}
<div class="wrapped-icon">
<div class="flex-center icon">
{iconLabel(name)}
</div>
<FileTypeIcon {name} />
</div>
{/if}
<span class="wrapped-title" use:tooltip={{ label: getEmbeddedLabel(name) }}>{name}</span>
</div>
</svelte:fragment>

<svelte:fragment slot="utils">
{#await srcRef then src}
{#if src !== ''}
<a class="no-line" href={src} download={name} bind:this={download}>
<Button
icon={Download}
kind={'ghost'}
on:click={() => {
download.click()
}}
showTooltip={{ label: presentation.string.Download }}
/>
</a>
{/if}
{/await}
<DownloadFileButton {name} {file} />
<ComponentExtensions
extension={presentation.extension.FilePreviewPopupActions}
props={{
file,
name,
contentType,
metadata
}}
/>
</svelte:fragment>

{#if file}
<FilePreview {file} {contentType} {name} {metadata} {props} fit />
{/if}
</Dialog>

<style lang="scss">
.icon {
position: relative;
flex-shrink: 0;
width: 2rem;
height: 2rem;
font-weight: 500;
font-size: 0.625rem;
color: var(--primary-button-color);
background-color: var(--primary-button-default);
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 0.5rem;
cursor: pointer;
}
</style>
42 changes: 42 additions & 0 deletions packages/presentation/src/components/FileTypeIcon.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!--
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
export let name: string

function iconLabel (name: string): string {
const parts = `${name}`.split('.')
const ext = parts[parts.length - 1]
return ext.substring(0, 4).toUpperCase()
}
</script>

<div class="flex-center icon">
{iconLabel(name)}
</div>

<style lang="scss">
.icon {
position: relative;
flex-shrink: 0;
width: 2rem;
height: 2rem;
font-weight: 500;
font-size: 0.625rem;
color: var(--primary-button-color);
background-color: var(--primary-button-default);
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 0.5rem;
}
</style>
2 changes: 2 additions & 0 deletions packages/presentation/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ export { default as BreadcrumbsElement } from './components/breadcrumbs/Breadcru
export { default as ComponentExtensions } from './components/extensions/ComponentExtensions.svelte'
export { default as DocCreateExtComponent } from './components/extensions/DocCreateExtComponent.svelte'
export { default as SearchResult } from './components/SearchResult.svelte'
export { default as DownloadFileButton } from './components/DownloadFileButton.svelte'
export { default as FileTypeIcon } from './components/FileTypeIcon.svelte'
export { default } from './plugin'
export * from './types'
export * from './utils'
Expand Down
3 changes: 2 additions & 1 deletion packages/presentation/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ export default plugin(presentationId, {
ContentTypeNotSupported: '' as IntlString
},
extension: {
FilePreviewExtension: '' as ComponentExtensionId
FilePreviewExtension: '' as ComponentExtensionId,
FilePreviewPopupActions: '' as ComponentExtensionId
},
metadata: {
ModelVersion: '' as Metadata<string>,
Expand Down
8 changes: 7 additions & 1 deletion packages/ui/src/components/Breadcrumb.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
export let icon: Asset | AnySvelteComponent | ComponentType | undefined = undefined
export let iconProps: any | undefined = undefined
export let iconWidth: string | undefined = undefined
export let iconMargin: string | undefined = undefined
export let withoutIconBackground = false
export let label: IntlString | undefined = undefined
export let title: string | undefined = undefined
Expand All @@ -31,7 +32,12 @@

<button class="hulyBreadcrumb-container {size}" class:current={isCurrent} on:click>
{#if size === 'large' && icon}
<div class="hulyBreadcrumb-avatar" style:width={iconWidth ?? null} class:withoutIconBackground>
<div
class="hulyBreadcrumb-avatar"
style:width={iconWidth ?? null}
style:margin={iconMargin}
class:withoutIconBackground
>
<Icon {icon} size={'small'} {iconProps} />
</div>
{/if}
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ export interface BreadcrumbItem {
icon?: Asset | AnySvelteComponent | ComponentType
iconProps?: any
iconWidth?: string
iconMargin?: string
withoutIconBackground?: boolean
label?: IntlString
title?: string
Expand Down
3 changes: 2 additions & 1 deletion plugins/attachment-assets/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"UnPinAttachment": "Mark less important",
"FilterAttachments": "Attachments",
"RemovedAttachment": "Removed attachment",
"ContentType": "Content type"
"ContentType": "Content type",
"OpenInWindow": "Open in window"
}
}
3 changes: 2 additions & 1 deletion plugins/attachment-assets/lang/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"UnPinAttachment": "Marcar como menos importante",
"FilterAttachments": "Adjuntos",
"RemovedAttachment": "Adjunto eliminado",
"ContentType": "Tipo de contenido"
"ContentType": "Tipo de contenido",
"OpenInWindow": "Abrir en ventana"
}
}
3 changes: 2 additions & 1 deletion plugins/attachment-assets/lang/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"UnPinAttachment": "Marquer comme moins important",
"FilterAttachments": "Pièces jointes",
"RemovedAttachment": "Pièce jointe supprimée",
"ContentType": "Type de contenu"
"ContentType": "Type de contenu",
"OpenInWindow": "Ouvrir dans une fenêtre"
}
}
3 changes: 2 additions & 1 deletion plugins/attachment-assets/lang/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"UnPinAttachment": "Marcar como menos importante",
"FilterAttachments": "Anexos",
"RemovedAttachment": "Anexo removido",
"ContentType": "Tipo de conteúdo"
"ContentType": "Tipo de conteúdo",
"OpenInWindow": "Abrir numa janela"
}
}
3 changes: 2 additions & 1 deletion plugins/attachment-assets/lang/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"UnPinAttachment": "Убрать пометку важное",
"FilterAttachments": "Вложения",
"RemovedAttachment": "Удалил(а) вложение",
"ContentType": "Тип контента"
"ContentType": "Тип контента",
"OpenInWindow": "Открыть в окне"
}
}
3 changes: 2 additions & 1 deletion plugins/attachment-assets/lang/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"UnPinAttachment": "标记为不重要",
"FilterAttachments": "附件",
"RemovedAttachment": "移除附件",
"ContentType": "内容类型"
"ContentType": "内容类型",
"OpenInWindow": "在新窗口中打开"
}
}
3 changes: 2 additions & 1 deletion plugins/attachment-resources/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
"typescript": "^5.3.3"
},
"dependencies": {
"@hcengineering/analytics": "^0.6.0",
"@hcengineering/activity": "^0.6.0",
"@hcengineering/analytics": "^0.6.0",
"@hcengineering/attachment": "^0.6.14",
"@hcengineering/contact": "^0.6.24",
"@hcengineering/core": "^0.6.32",
Expand All @@ -55,6 +55,7 @@
"@hcengineering/uploader": "^0.6.0",
"@hcengineering/view": "^0.6.13",
"@hcengineering/view-resources": "^0.6.0",
"@hcengineering/workbench": "^0.6.16",
"filesize": "^8.0.3",
"svelte": "^4.2.12"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
} from '@hcengineering/presentation'
import { IconMoreH, Menu, Action as UIAction, closeTooltip, showPopup, tooltip } from '@hcengineering/ui'
import view, { Action } from '@hcengineering/view'
import workbench from '@hcengineering/workbench'

import AttachmentAction from './AttachmentAction.svelte'
import FileDownload from './icons/FileDownload.svelte'
import attachmentPlugin from '../plugin'
import { openAttachmentInSidebar } from '../utils'

export let attachment: WithLookup<Attachment>
export let isSaved = false
Expand Down Expand Up @@ -95,6 +97,13 @@
if (canPreview) {
actions.push(openAction)
}
actions.push({
icon: view.icon.DetailsFilled,
label: workbench.string.OpenInSidebar,
action: async () => {
await openAttachmentInSidebar(attachment)
}
})
actions.push({
label: saveAttachmentAction.label,
icon: saveAttachmentAction.icon,
Expand Down
Loading
Loading