mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-30 12:15:51 +00:00
UBERF-9371, UBERF-9274: Apply redesign for link preview (#7893)
Some checks are pending
CI / build (push) Waiting to run
CI / svelte-check (push) Blocked by required conditions
CI / formatting (push) Blocked by required conditions
CI / test (push) Blocked by required conditions
CI / uitest (push) Waiting to run
CI / uitest-pg (push) Waiting to run
CI / uitest-qms (push) Waiting to run
CI / docker-build (push) Blocked by required conditions
CI / dist-build (push) Blocked by required conditions
Some checks are pending
CI / build (push) Waiting to run
CI / svelte-check (push) Blocked by required conditions
CI / formatting (push) Blocked by required conditions
CI / test (push) Blocked by required conditions
CI / uitest (push) Waiting to run
CI / uitest-pg (push) Waiting to run
CI / uitest-qms (push) Waiting to run
CI / docker-build (push) Blocked by required conditions
CI / dist-build (push) Blocked by required conditions
This commit is contained in:
parent
65e7195e10
commit
1dd22f85c5
@ -348,6 +348,10 @@
|
||||
--theme-clockface-arrows-holder: radial-gradient(at top center, #2F2F3A, #555555);
|
||||
--theme-clockface-arrows-shadow: 0 0 1px white;
|
||||
|
||||
--theme-link-preview-bg-color: #2B2D41;
|
||||
--theme-link-preview-description-color: #C1C9D6;
|
||||
--theme-link-preview-text-color:#FFFFFF;
|
||||
|
||||
--theme-dialog-border-color: rgba(255, 255, 255, 0.1);
|
||||
--theme-dialog-background-color: #2a2938;
|
||||
--theme-dialog-back-color: #848484;
|
||||
@ -431,6 +435,10 @@
|
||||
--theme-mention-bg-color: rgba(55, 122, 230, 0.1);
|
||||
--theme-mention-focused-bg-color: rgba(55, 122, 230, 0.2);
|
||||
|
||||
--theme-link-preview-bg-color: #E5E8F0;
|
||||
--theme-link-preview-description-color: #5A667E;
|
||||
--theme-link-preview-text-color:#0F121A;
|
||||
|
||||
--theme-trans-color: rgba(0, 0, 0, .3);
|
||||
--theme-darker-color: rgba(0, 0, 0, .4);
|
||||
--theme-halfcontent-color: rgba(0, 0, 0, .5);
|
||||
|
@ -25,6 +25,7 @@
|
||||
export let attachments: Attachment[] | undefined = undefined
|
||||
export let imageSize: AttachmentImageSize = 'auto'
|
||||
export let videoPreload = true
|
||||
export let isOwn = false
|
||||
|
||||
const query = createQuery()
|
||||
const savedAttachmentsQuery = createQuery()
|
||||
@ -62,4 +63,4 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<AttachmentGroup attachments={resAttachments} {savedAttachmentsIds} {imageSize} {videoPreload} />
|
||||
<AttachmentGroup attachments={resAttachments} {savedAttachmentsIds} {imageSize} {videoPreload} {isOwn} />
|
||||
|
@ -24,6 +24,7 @@
|
||||
export let savedAttachmentsIds: Ref<Attachment>[] = []
|
||||
export let imageSize: AttachmentImageSize = 'auto'
|
||||
export let videoPreload = true
|
||||
export let isOwn = false
|
||||
|
||||
let otherAttachments: WithLookup<Attachment>[]
|
||||
let linkPreviewAttachments: WithLookup<Attachment>[]
|
||||
@ -47,5 +48,5 @@
|
||||
|
||||
<div class="gapV-2">
|
||||
<AttachmentList attachments={otherAttachments} {savedAttachmentsIds} {imageSize} {videoPreload} />
|
||||
<LinkPreviewList attachments={linkPreviewAttachments} />
|
||||
<LinkPreviewList attachments={linkPreviewAttachments} {isOwn} />
|
||||
</div>
|
||||
|
@ -128,21 +128,8 @@
|
||||
return url.protocol.startsWith('http')
|
||||
}
|
||||
|
||||
function longestSegment (s: string): string {
|
||||
const segments = s.split('.')
|
||||
let maxLen = segments[0].length
|
||||
let result = segments[0]
|
||||
for (const segment of segments) {
|
||||
if (segment.length > maxLen) {
|
||||
result = segment
|
||||
maxLen = segment.length
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
function getUrlKey (s: string): string {
|
||||
const url = new URL(s)
|
||||
return longestSegment(url.host) + url.pathname
|
||||
return s
|
||||
}
|
||||
|
||||
$: objectId && updateAttachments(objectId)
|
||||
|
@ -19,12 +19,13 @@
|
||||
import { type Attachment } from '@hcengineering/attachment'
|
||||
import { Scroller } from '@hcengineering/ui'
|
||||
export let attachments: WithLookup<Attachment>[] = []
|
||||
export let isOwn = false
|
||||
</script>
|
||||
|
||||
<div class="gapV-2">
|
||||
{#each attachments as attachment}
|
||||
<Scroller contentDirection={'horizontal'} horizontal scrollSnap>
|
||||
<LinkPreviewPresenter {attachment} />
|
||||
<LinkPreviewPresenter {attachment} {isOwn} />
|
||||
</Scroller>
|
||||
{/each}
|
||||
</div>
|
||||
|
@ -13,14 +13,17 @@
|
||||
// limitations under the License.
|
||||
// -->
|
||||
<script lang="ts">
|
||||
import { getJsonOrEmpty, type LinkPreviewDetails } from '@hcengineering/presentation'
|
||||
import { getJsonOrEmpty, getClient, type LinkPreviewDetails } from '@hcengineering/presentation'
|
||||
import { type Attachment } from '@hcengineering/attachment'
|
||||
import { type WithLookup } from '@hcengineering/core'
|
||||
import { Spinner } from '@hcengineering/ui'
|
||||
import WebIcon from './icons/Web.svelte'
|
||||
import { onMount } from 'svelte'
|
||||
import TrashIcon from './icons/Trash.svelte'
|
||||
|
||||
export let attachment: WithLookup<Attachment>
|
||||
export let isOwn = false
|
||||
|
||||
let useDefaultIcon = false
|
||||
let retryCount = 0
|
||||
let viewModel: LinkPreviewDetails
|
||||
@ -37,7 +40,18 @@
|
||||
retryCount++
|
||||
previewImageSrc = `${viewModel.image}#${Date.now()}`
|
||||
}
|
||||
const client = getClient()
|
||||
|
||||
async function onDelete (): Promise<void> {
|
||||
await client.removeCollection(
|
||||
attachment._class,
|
||||
attachment.space,
|
||||
attachment._id,
|
||||
attachment.attachedTo,
|
||||
attachment.attachedToClass,
|
||||
'attachments'
|
||||
)
|
||||
}
|
||||
onMount(() => {
|
||||
void getJsonOrEmpty(attachment.file, attachment.name)
|
||||
.then((res) => {
|
||||
@ -50,49 +64,61 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="quote content">
|
||||
<div class="content">
|
||||
{#if viewModel}
|
||||
<div class="gapV-2">
|
||||
<div class="flex-row-center gap-1">
|
||||
{#if viewModel.icon !== undefined && !useDefaultIcon}
|
||||
<div class="title">
|
||||
{#if viewModel.icon !== undefined && !useDefaultIcon}
|
||||
<img
|
||||
src={viewModel.icon}
|
||||
class="preview-icon"
|
||||
alt="link-preview-icon"
|
||||
on:error={() => {
|
||||
useDefaultIcon = true
|
||||
}}
|
||||
/>
|
||||
{:else}
|
||||
<WebIcon size="small" />
|
||||
{/if}
|
||||
<b><a class="link" target="_blank" href={viewModel.host}>{viewModel.hostname}</a></b>
|
||||
{#if isOwn}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<span
|
||||
class="delete-button"
|
||||
tabindex="0"
|
||||
role="button"
|
||||
on:click={() => {
|
||||
void onDelete()
|
||||
}}><TrashIcon size="small" /></span
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="description">
|
||||
{#if viewModel.title?.toLowerCase() !== viewModel.hostname?.toLowerCase()}
|
||||
<div>
|
||||
<b><a class="link" target="_blank" href={viewModel.url}>{viewModel.title}</a></b>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if viewModel.description}
|
||||
<div>
|
||||
{viewModel.description}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if previewImageSrc}
|
||||
<div>
|
||||
<a target="_blank" href={viewModel.url}>
|
||||
<img
|
||||
src={viewModel.icon}
|
||||
class="preview-icon"
|
||||
alt="link-preview-icon"
|
||||
src={previewImageSrc}
|
||||
class="round-image"
|
||||
alt="link-preview"
|
||||
on:error={() => {
|
||||
useDefaultIcon = true
|
||||
refreshPreviewImage()
|
||||
}}
|
||||
/>
|
||||
{:else}
|
||||
<WebIcon size="medium" />
|
||||
{/if}
|
||||
<b><a target="_blank" href={viewModel.host}>{viewModel.hostname}</a></b>
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
{#if viewModel.title?.toLowerCase() !== viewModel.hostname?.toLowerCase()}
|
||||
<b><a target="_blank" href={viewModel.url}>{viewModel.title}</a></b>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
{#if viewModel.description}
|
||||
{viewModel.description}
|
||||
{/if}
|
||||
{#if previewImageSrc}
|
||||
<a target="_blank" href={viewModel.url}>
|
||||
<img
|
||||
src={previewImageSrc}
|
||||
class="round-image"
|
||||
alt="link-preview"
|
||||
on:error={() => {
|
||||
refreshPreviewImage()
|
||||
}}
|
||||
/>
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="centered">
|
||||
<Spinner size="medium" />
|
||||
@ -101,23 +127,52 @@
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.delete-button {
|
||||
margin-left: auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
.delete-button:not(:hover) {
|
||||
color: var(--theme-link-preview-description-color);
|
||||
}
|
||||
.round-image {
|
||||
border: 0.5px solid;
|
||||
border-radius: 7px;
|
||||
max-width: 25rem;
|
||||
max-height: 25rem;
|
||||
margin-top: 0.5rem;
|
||||
border-radius: 0.375rem;
|
||||
max-width: 24.5rem;
|
||||
max-height: 15rem;
|
||||
}
|
||||
.preview-icon {
|
||||
max-width: 16px;
|
||||
max-height: 16px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.quote {
|
||||
border-left: 0.25rem solid;
|
||||
padding-left: 0.75rem;
|
||||
.link {
|
||||
color: var(--theme-link-preview-text-color);
|
||||
}
|
||||
.title {
|
||||
gap: 0.375rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
.description {
|
||||
color: var(--theme-link-preview-description-color);
|
||||
}
|
||||
.content span {
|
||||
display: none;
|
||||
}
|
||||
.content:hover span {
|
||||
display: block;
|
||||
}
|
||||
.content {
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
line-height: 150%;
|
||||
gap: 0.188rem;
|
||||
padding: 0.75rem;
|
||||
background-color: var(--theme-link-preview-bg-color);
|
||||
border-radius: 0.75rem;
|
||||
scroll-snap-align: start;
|
||||
max-width: 35rem;
|
||||
max-height: 35rem;
|
||||
max-width: 26rem;
|
||||
max-height: 28rem;
|
||||
font-family: var(--font-family);
|
||||
}
|
||||
</style>
|
||||
|
@ -0,0 +1,32 @@
|
||||
<!--
|
||||
// Copyright © 2025 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 size: 'tiny' | 'x-small' | 'small' | 'medium' | 'large' | 'full'
|
||||
export let fill: string = 'currentColor'
|
||||
</script>
|
||||
|
||||
<svg class="svg-{size}" {fill} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12 23C12 23.5523 12.4477 24 13 24C13.5523 24 14 23.5523 14 23V13C14 12.4477 13.5523 12 13 12C12.4477 12 12 12.4477 12 13V23Z"
|
||||
/>
|
||||
<path
|
||||
d="M20 23C20 23.5523 19.5523 24 19 24C18.4477 24 18 23.5523 18 23V13C18 12.4477 18.4477 12 19 12C19.5523 12 20 12.4477 20 13V23Z"
|
||||
/>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M15 2C13.3431 2 12 3.34315 12 5V6H5C4.44772 6 4 6.44772 4 7C4 7.55228 4.44772 8 5 8H6V26C6 28.2091 7.79086 30 10 30H22C24.2091 30 26 28.2091 26 26V8H27C27.5523 8 28 7.55228 28 7C28 6.44772 27.5523 6 27 6H20V5C20 3.34315 18.6569 2 17 2H15ZM18 6V5C18 4.44772 17.5523 4 17 4H15C14.4477 4 14 4.44772 14 5V6H18ZM8 26V8H24V26C24 27.1046 23.1046 28 22 28H10C8.89543 28 8 27.1046 8 26Z"
|
||||
/>
|
||||
</svg>
|
@ -265,7 +265,7 @@
|
||||
{#if (value.attachments ?? 0) > 0 || (value.inlineButtons ?? 0) > 0}
|
||||
<div class="mt-2" />
|
||||
{/if}
|
||||
<AttachmentDocList {value} {attachments} imageSize={attachmentImageSize} {videoPreload} />
|
||||
<AttachmentDocList {value} {attachments} imageSize={attachmentImageSize} {videoPreload} {isOwn} />
|
||||
<InlineButtons {value} {inlineButtons} />
|
||||
</div>
|
||||
</ShowMore>
|
||||
@ -275,7 +275,7 @@
|
||||
{#if (value.attachments ?? 0) > 0 || (value.inlineButtons ?? 0) > 0}
|
||||
<div class="mt-2" />
|
||||
{/if}
|
||||
<AttachmentDocList {value} {attachments} imageSize={attachmentImageSize} {videoPreload} />
|
||||
<AttachmentDocList {value} {attachments} imageSize={attachmentImageSize} {videoPreload} {isOwn} />
|
||||
<InlineButtons {value} {inlineButtons} />
|
||||
</div>
|
||||
{/if}
|
||||
|
Loading…
Reference in New Issue
Block a user