Skip to content

Commit 574271f

Browse files
committed
feat: add document download popover
1 parent a7be6ee commit 574271f

File tree

12 files changed

+267
-32
lines changed

12 files changed

+267
-32
lines changed

components.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ declare module 'vue' {
6464
ColumnFilterBadge: typeof import('./src/components/ColumnFilterBadge.vue')['default']
6565
ColumnFilterDropdown: typeof import('./src/components/ColumnFilterDropdown.vue')['default']
6666
ContentTypeBadge: typeof import('./src/components/ContentTypeBadge.vue')['default']
67-
copy: typeof import('./src/components/PageTable/PageTableTh copy.vue')['default']
67+
copy: typeof import('./src/components/Document/DocumentDownloadPopover copy.vue')['default']
6868
DismissableAlert: typeof import('./src/components/Dismissable/DismissableAlert.vue')['default']
6969
DismissableToastBody: typeof import('./src/components/Dismissable/DismissableToastBody.vue')['default']
7070
DisplayContentLength: typeof import('./src/components/Display/DisplayContentLength.vue')['default']
@@ -104,6 +104,8 @@ declare module 'vue' {
104104
DocumentContentSlice: typeof import('./src/components/DocumentContentSlice.vue')['default']
105105
DocumentContentSlicePlaceholder: typeof import('./src/components/DocumentContentSlicePlaceholder.vue')['default']
106106
DocumentContentSlices: typeof import('./src/components/DocumentContentSlices.vue')['default']
107+
DocumentDownloadPopover: typeof import('./src/components/Document/DocumentDownloadPopover/DocumentDownloadPopover.vue')['default']
108+
DocumentDownloadPopoverSection: typeof import('./src/components/Document/DocumentDownloadPopover/DocumentDownloadPopoverSection.vue')['default']
107109
DocumentGlobalSearchTermsTags: typeof import('./src/components/DocumentGlobalSearchTermsTags.vue')['default']
108110
DocumentInModal: typeof import('./src/components/DocumentInModal.vue')['default']
109111
DocumentLocalSearch: typeof import('./src/components/Document/DocumentLocalSearch/DocumentLocalSearch.vue')['default']

src/components/Document/DocumentActionsGroup/DocumentActionsGroup.vue

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@
2222
@click="clickShare"
2323
/>
2424
<document-actions-group-entry
25+
ref="downloadButton"
2526
icon="download"
2627
:label="$t('documentActionsGroup.download')"
27-
:disabled="isDownloadAllowed"
28-
:tooltip-placement="tooltipPlacement"
28+
:disabled="!isDownloadAllowed"
29+
hide-tooltip
2930
@click="clickDownload"
3031
/>
3132
<document-actions-group-entry
@@ -34,12 +35,19 @@
3435
:tooltip-placement="tooltipPlacement"
3536
@click="clickExpand"
3637
/>
38+
<document-download-popover :target="downloadButton" :document="document" :placement="tooltipPlacement" />
3739
</slot>
3840
</div>
3941
</template>
4042

4143
<script setup>
42-
import DocumentActionsGroupEntry from '@/components/Document/DocumentActionsGroup/DocumentActionsGroupEntry'
44+
import { ref } from 'vue'
45+
46+
import DocumentActionsGroupEntry from './DocumentActionsGroupEntry'
47+
48+
import DocumentDownloadPopover from '@/components/Document/DocumentDownloadPopover/DocumentDownloadPopover'
49+
50+
const downloadButton = ref(null)
4351
4452
defineProps({
4553
/**

src/components/Document/DocumentActionsGroup/DocumentActionsGroupEntry.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
:icon-left-hover-weight="iconHoverWeight"
77
:label="label"
88
hide-label
9+
:hide-tooltip="hideTooltip"
910
:tooltip-placement="tooltipPlacement"
1011
square
1112
variant="outline-tertiary"
@@ -50,6 +51,12 @@ const props = defineProps({
5051
fill: {
5152
type: Boolean
5253
},
54+
/**
55+
* Hide the button tooltip
56+
*/
57+
hideTooltip: {
58+
type: Boolean
59+
},
5360
/**
5461
* Class to apply to the action button when document is fill
5562
*/
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
<script setup>
2+
import { computed } from 'vue'
3+
import { PhosphorIcon } from '@icij/murmur-next'
4+
import { useI18n } from 'vue-i18n'
5+
6+
import DocumentDownloadPopoverSection from './DocumentDownloadPopoverSection'
7+
8+
import DisplayContentType from '@/components/Display/DisplayContentType'
9+
10+
const props = defineProps({
11+
/**
12+
* The selected document
13+
*/
14+
document: {
15+
type: Object
16+
},
17+
/**
18+
* The target element
19+
*/
20+
target: {
21+
type: Object
22+
},
23+
/**
24+
* Toggle value when the popover is open
25+
*/
26+
modelValue: {
27+
type: Boolean
28+
},
29+
/**
30+
* True if the popover is open manually
31+
*/
32+
manual: {
33+
type: Boolean
34+
},
35+
/**
36+
* Disable auto close
37+
*/
38+
noAutoClose: {
39+
type: Boolean
40+
},
41+
/**
42+
* The placement of the popover
43+
*/
44+
placement: {
45+
type: String
46+
}
47+
})
48+
49+
const { locale, t } = useI18n()
50+
51+
const extensionWarning = computed(() => {
52+
const { standardExtension: extension } = props.document
53+
return t('documentDownloadPopover.extensionWarning', { extension })
54+
})
55+
56+
const description = computed(() => {
57+
const descriptions = props.document.contentTypeDescription ?? {}
58+
const description = descriptions[locale.value] || descriptions.en
59+
return props.document.hasStandardExtension ? description : `${description} <strong>${extensionWarning.value}</strong>`
60+
})
61+
62+
const executionWarning = computed(() => {
63+
const warnings = props.document.contentTypeWarning ?? {}
64+
return warnings[locale.value] || warnings.en
65+
})
66+
</script>
67+
68+
<template>
69+
<b-popover
70+
teleport-to="body"
71+
:target="target"
72+
:manual="manual"
73+
:model-value="modelValue"
74+
:no-auto-close="noAutoClose"
75+
:placement="placement"
76+
custom-class="document-download-popover"
77+
@update:modelValue="$emit('update:modelValue')"
78+
>
79+
<div class="document-download-popover__body">
80+
<icon-button icon-left="download-simple" label="Download" class="document-download-popover__body__button" />
81+
<icon-button
82+
icon-left="download-simple"
83+
label="Download without metadata"
84+
variant="outline-primary"
85+
class="document-download-popover__body__button"
86+
/>
87+
<icon-button
88+
icon-left="download-simple"
89+
label="Download extract text"
90+
variant="outline-primary"
91+
class="document-download-popover__body__button"
92+
/>
93+
<div class="document-download-popover__body__sections pt-3">
94+
<document-download-popover-section title="What's the document's title?" :value="document.title" />
95+
<document-download-popover-section title="What's the document's type">
96+
<phosphor-icon :name="document.contentTypeIcon" class="me-2" />
97+
<display-content-type :value="document.contentType" />
98+
</document-download-popover-section>
99+
<document-download-popover-section
100+
v-if="description"
101+
title="Once downloaded, how do I open it ?"
102+
:value="description"
103+
/>
104+
</div>
105+
</div>
106+
</b-popover>
107+
</template>
108+
109+
<style lang="scss">
110+
.document-download-popover {
111+
width: 100%;
112+
113+
&__body {
114+
display: flex;
115+
flex-direction: column;
116+
gap: $spacer-sm;
117+
118+
&__button {
119+
white-space: nowrap;
120+
align-self: flex-start;
121+
}
122+
123+
&__sections {
124+
margin-top: $spacer;
125+
display: flex;
126+
flex-direction: column;
127+
gap: $spacer-xl;
128+
}
129+
}
130+
}
131+
</style>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<script setup>
2+
defineProps({
3+
title: {
4+
type: String
5+
},
6+
value: {
7+
type: String
8+
}
9+
})
10+
</script>
11+
12+
<template>
13+
<section class="document-download-popover-section">
14+
<div class="document-download-popover-section__title pb-2 text-tertiary-emphasis fst-italic">
15+
{{ title }}
16+
</div>
17+
<div class="document-download-popover-section__value text-primary-emphasis">
18+
<slot><span v-html="value"></span></slot>
19+
</div>
20+
</section>
21+
</template>

src/components/PageTable/PageTable.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const classList = computed(() => {
3737

3838
<style lang="scss" scoped>
3939
.page-table {
40+
vertical-align: middle;
4041
font-size: math.div(14, 16) * 1rem;
4142
4243
&__select {

src/components/PageTable/PageTableTh.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ const labelClassList = computed(() => {
7070

7171
<style lang="scss" scoped>
7272
.page-table-th {
73-
vertical-align: $table-cell-vertical-align;
73+
vertical-align: middle;
7474
7575
&--compact {
7676
width: 2rem;

src/lang/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242
"private": "Private to you",
4343
"public": "Public to project members"
4444
},
45+
"documentDownloadPopover": {
46+
"extensionWarning": "This document has the wrong file extension for its type. You might need to add the extension <code>{extension}</code> before you can open it."
47+
},
4548
"error": {
4649
"title": "Something's wrong here",
4750
"description": "An error has occurred. Please try again later or contact your administrator if the problem persists.",

src/main.scss

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,11 +218,6 @@ $value in $theme-colors {
218218
border-radius: inherit;
219219
overflow: hidden;
220220
}
221-
222-
&.bs-popover-bottom > .popover-arrow::after,
223-
&.bs-popover-auto[data-popper-placement^="bottom"] > .popover-arrow::after {
224-
border-bottom-color: $popover-header-bg;
225-
}
226221
}
227222

228223
html[data-bs-theme] body .Toastify {
Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,44 @@
1-
import IconButton from '@/components/IconButton'
1+
import { markRaw } from 'vue'
2+
import { PhFilePdf } from '@phosphor-icons/vue'
3+
4+
import types from '@/utils/types.json'
25
import DocumentActionsGroup from '@/components/Document/DocumentActionsGroup/DocumentActionsGroup'
36

47
export default {
58
components: { DocumentActionsGroup },
69
title: 'Components/Document/DocumentActionsGroup',
7-
component: IconButton,
10+
component: DocumentActionsGroup,
811
tags: ['autodocs'],
9-
render: (args) => ({
10-
components: {
11-
DocumentActionsGroup
12-
},
13-
setup() {
14-
return {
15-
args
16-
}
17-
},
18-
template: `
19-
<document-actions-group v-bind="args" >
20-
</document-actions-group>
21-
`
22-
})
23-
}
24-
25-
export const Default = {
2612
args: {
2713
document: {
28-
id: 'test'
14+
id: '5f5b3b3b-7b3b-4b3b-8b3b-3b3b3b3b3b3b',
15+
title: 'Inter IKEA Investment S.à r.l._cover letter 2010-2011 tax returns.pdf',
16+
extractionLevel: 0,
17+
project: 'banana-papers',
18+
creationDate: new Date(),
19+
inlineFullUrl: 'https://i.imgur.com/ns9ThQx.jpeg',
20+
path: '/vault/ns9ThQx.jpeg',
21+
tags: ['foo', 'bar', 'baz'],
22+
language: 'ENGLISH',
23+
contentLength: 23e4,
24+
contentTextLength: 14e3,
25+
isSupportedImage: true,
26+
highlights: [
27+
'Lorem ispum dolor sit <mark>IKEA</mark> amet.',
28+
'Consectetur <mark>IKEA</mark> adipiscing elit.',
29+
'Sed do eiusmod tempor incididunt ut labore et <mark>IKEA</mark> dolore magna aliqua.'
30+
],
31+
contentType: 'application/pdf',
32+
contentTypeDescription: types['application/pdf'].description,
33+
contentTypeIcon: markRaw(PhFilePdf)
2934
},
3035
vertical: false,
31-
tooltipPlacement: 'top',
36+
tooltipPlacement: 'bottom',
3237
isStarred: false,
33-
isDownloadAllowed: false,
38+
isDownloadAllowed: true,
3439
selectMode: true,
3540
selected: false
3641
}
3742
}
43+
44+
export const Default = {}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { markRaw } from 'vue'
2+
import { PhFile, PhFilePdf } from '@phosphor-icons/vue'
3+
4+
import DocumentDownloadPopover from '@/components/Document/DocumentDownloadPopover/DocumentDownloadPopover'
5+
import types from '@/utils/types.json'
6+
7+
export default {
8+
component: DocumentDownloadPopover,
9+
title: 'Components/Document/DocumentDownloadPopover/DocumentDownloadPopover',
10+
tags: ['autodocs'],
11+
args: {
12+
document: {
13+
id: 'foo',
14+
title: 'Inter IKEA Investment S.à r.l._cover letter 2010-2011 tax returns.pdf',
15+
standardExtension: 'pdf',
16+
hasStandardExtension: true,
17+
contentType: 'application/pdf',
18+
contentTypeDescription: types['application/pdf'].description,
19+
contentTypeIcon: markRaw(PhFilePdf)
20+
}
21+
},
22+
render: (args) => ({
23+
components: {
24+
DocumentDownloadPopover
25+
},
26+
setup: () => ({ args }),
27+
computed: {
28+
trigger() {
29+
return `btn-${this.$.uid}`
30+
}
31+
},
32+
template: `
33+
<div class="p-sm-5 p-3 text-center">
34+
<button type="button" class="btn btn-outline-secondary" :id="trigger">
35+
Hover me
36+
</button>
37+
<document-download-popover v-bind="args" :target="trigger" />
38+
</div>
39+
`
40+
})
41+
}
42+
43+
export const Default = {}
44+
45+
export const WithWarning = {
46+
args: {
47+
document: {
48+
id: 'bar',
49+
title: 'Inter IKEA Investment S.à r.l._cover letter 2010-2011 tax returns.txt',
50+
contentType: 'text/html',
51+
standardExtension: 'html',
52+
hasStandardExtension: false,
53+
contentTypeDescription: types['text/html'].description,
54+
contentTypeWarning: types['text/html'].warning,
55+
contentTypeIcon: markRaw(PhFile)
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)