@meistrari/minuta-nuxt 0.1.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +97 -0
- package/dist/module.json +1 -1
- package/dist/runtime/components/MinutaAnnotationsGutter.vue +39 -11
- package/dist/runtime/components/MinutaDocumentViewer.vue +105 -47
- package/dist/runtime/components/MinutaDocxEditor.vue +211 -15
- package/dist/runtime/components/MinutaEmbed.vue +122 -22
- package/dist/runtime/components/MinutaIcon.vue +2 -0
- package/dist/runtime/components/MinutaTemplateEditor.vue +225 -0
- package/dist/runtime/components/MinutaVariablePicker.vue +149 -0
- package/dist/runtime/composables/annotationAnchors.d.ts +0 -1
- package/dist/runtime/composables/annotationAnchors.js +10 -3
- package/dist/runtime/composables/docxExport.js +14 -2
- package/dist/runtime/composables/editorExtensions.d.ts +38 -1
- package/dist/runtime/composables/editorExtensions.js +84 -2
- package/dist/runtime/composables/paginationPlugin.d.ts +13 -0
- package/dist/runtime/composables/paginationPlugin.js +88 -4
- package/dist/runtime/composables/useMinutaApi.d.ts +11 -2
- package/dist/runtime/composables/useMinutaApi.js +6 -1
- package/dist/runtime/utils/templateVariables.d.ts +49 -0
- package/dist/runtime/utils/templateVariables.js +36 -0
- package/package.json +97 -96
|
@@ -5,6 +5,8 @@ import { sanitizeRichHtml } from '../utils/sanitizeRichHtml'
|
|
|
5
5
|
import { vaultImageHtml } from '../composables/vaultImages'
|
|
6
6
|
import { sanitizeFootnoteHtml } from '../utils/footnoteHtml'
|
|
7
7
|
import MinutaIcon from './MinutaIcon.vue'
|
|
8
|
+
import MinutaVariablePicker from './MinutaVariablePicker.vue'
|
|
9
|
+
import type { MinutaVariableDef } from '../utils/templateVariables'
|
|
8
10
|
import type { Editor } from '@tiptap/core'
|
|
9
11
|
import type { PocPageConfig, PocPageNote } from '../composables/paginationPlugin'
|
|
10
12
|
import { POC_ASSET_SWAP, buildPocExtensions, renumberPocFootnotes } from '../composables/editorExtensions'
|
|
@@ -29,6 +31,13 @@ const props = defineProps<{
|
|
|
29
31
|
* falha), a imagem vira data-URI embutida no documento.
|
|
30
32
|
*/
|
|
31
33
|
uploadImage?: ((file: File) => Promise<{ src: string, vaultSrc: string } | null>) | null
|
|
34
|
+
/**
|
|
35
|
+
* Catálogo de variáveis do app hospedeiro. Com ele o editor vira editor de
|
|
36
|
+
* TEMPLATE: `/` e o botão da toolbar inserem placeholders. Vazio (o padrão),
|
|
37
|
+
* nada muda — placeholders já existentes no documento continuam sendo
|
|
38
|
+
* renderizados, só não há como inserir novos.
|
|
39
|
+
*/
|
|
40
|
+
variables?: MinutaVariableDef[]
|
|
32
41
|
}>()
|
|
33
42
|
|
|
34
43
|
const emit = defineEmits<{
|
|
@@ -141,7 +150,10 @@ onMounted(() => {
|
|
|
141
150
|
element: editorHost.value!,
|
|
142
151
|
content: props.initialHtml,
|
|
143
152
|
editable: props.editable,
|
|
144
|
-
extensions: buildPocExtensions(pageConfig
|
|
153
|
+
extensions: buildPocExtensions(pageConfig, {
|
|
154
|
+
variables: () => props.variables ?? [],
|
|
155
|
+
handleKeyDown: onEditorKeyDown,
|
|
156
|
+
}),
|
|
145
157
|
onCreate: ({ editor }) => {
|
|
146
158
|
emit('ready', editor as Editor)
|
|
147
159
|
nextTick(() => {
|
|
@@ -153,6 +165,7 @@ onMounted(() => {
|
|
|
153
165
|
},
|
|
154
166
|
onTransaction: ({ transaction }) => {
|
|
155
167
|
uiTick.value++
|
|
168
|
+
syncVariableTrigger(transaction.docChanged)
|
|
156
169
|
if (transaction.docChanged) {
|
|
157
170
|
// troca de imagem fria (load progressivo) não é edição do
|
|
158
171
|
// advogado: repagina, mas não marca o doc como sujo — senão
|
|
@@ -189,7 +202,10 @@ watch(containerRef, (el) => {
|
|
|
189
202
|
if (!el)
|
|
190
203
|
return
|
|
191
204
|
resizeObserver = new ResizeObserver(() => {
|
|
192
|
-
|
|
205
|
+
// respiro lateral da folha: 48px dá moldura no desktop, mas em tela de
|
|
206
|
+
// celular custa ~13% do zoom e o texto fica ilegível
|
|
207
|
+
const breathing = el.clientWidth < 640 ? 12 : 48
|
|
208
|
+
zoom.value = Math.min(1, (el.clientWidth - breathing) / A4_WIDTH_PX)
|
|
193
209
|
})
|
|
194
210
|
resizeObserver.observe(el)
|
|
195
211
|
}, { immediate: true })
|
|
@@ -658,6 +674,177 @@ function clearColor() {
|
|
|
658
674
|
editor.value?.chain().focus().unsetMark('inlineStyle').run()
|
|
659
675
|
}
|
|
660
676
|
|
|
677
|
+
// --- variáveis de template: gatilho `/`, botão da toolbar e seletor ---
|
|
678
|
+
|
|
679
|
+
const hasVariables = computed(() => (props.variables?.length ?? 0) > 0)
|
|
680
|
+
const variablePickerRef = ref<any>(null)
|
|
681
|
+
/**
|
|
682
|
+
* `from` = posição do `/` que abriu o seletor (apagado na inserção); `null`
|
|
683
|
+
* quando veio do botão da toolbar, que não digitou nada no documento.
|
|
684
|
+
* `query === undefined` faz o popover usar o próprio campo de busca.
|
|
685
|
+
*/
|
|
686
|
+
const variablePicker = ref<{ top: number, left: number, from: number | null, query: string | undefined } | null>(null)
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Coordenada do documento → coordenada dentro da folha.
|
|
690
|
+
*
|
|
691
|
+
* A folha tem `zoom` CSS: `coordsAtPos` devolve px de TELA e o `top`/`left` do
|
|
692
|
+
* popover é interpretado em px de LAYOUT lá dentro. Sem dividir pelo zoom o
|
|
693
|
+
* seletor desgruda do cursor em qualquer zoom diferente de 100%.
|
|
694
|
+
*/
|
|
695
|
+
function sheetCoords(pos: number): { top: number, left: number } | null {
|
|
696
|
+
const ed = editor.value
|
|
697
|
+
const sheet = sheetRef.value
|
|
698
|
+
if (!ed || ed.isDestroyed || !sheet)
|
|
699
|
+
return null
|
|
700
|
+
let coords
|
|
701
|
+
try {
|
|
702
|
+
coords = ed.view.coordsAtPos(pos)
|
|
703
|
+
}
|
|
704
|
+
catch {
|
|
705
|
+
return null
|
|
706
|
+
}
|
|
707
|
+
const rect = sheet.getBoundingClientRect()
|
|
708
|
+
const z = zoom.value || 1
|
|
709
|
+
return {
|
|
710
|
+
top: (coords.bottom - rect.top) / z + 6,
|
|
711
|
+
left: Math.max(8, Math.min((coords.left - rect.left) / z, A4_WIDTH_PX - 330)),
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* `/` no início de palavra abre o seletor; o que vem depois filtra.
|
|
717
|
+
*
|
|
718
|
+
* Exige delimitador à esquerda para não disparar dentro de uma data ("12/03")
|
|
719
|
+
* nem de uma referência de artigo ("art. 5º, II/CF") — onde a barra é conteúdo,
|
|
720
|
+
* não comando.
|
|
721
|
+
*/
|
|
722
|
+
const VARIABLE_TRIGGER_RE = /(?:^|[\s(\[«"'])\/([\p{L}\d_]*)$/u
|
|
723
|
+
/** acima disto não é mais busca, é texto — o gatilho desiste */
|
|
724
|
+
const VARIABLE_TRIGGER_MAX_QUERY = 24
|
|
725
|
+
|
|
726
|
+
function closeVariablePicker() {
|
|
727
|
+
variablePicker.value = null
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Reavalia o gatilho a cada transação. Só ABRE quando o documento mudou (foi
|
|
732
|
+
* alguém digitando); mover o cursor para perto de uma barra que já estava no
|
|
733
|
+
* texto não abre nada, mas fecha o que estiver aberto.
|
|
734
|
+
*/
|
|
735
|
+
function syncVariableTrigger(docChanged: boolean) {
|
|
736
|
+
const ed = editor.value
|
|
737
|
+
if (!ed || ed.isDestroyed || !hasVariables.value || !props.editable) {
|
|
738
|
+
if (variablePicker.value)
|
|
739
|
+
closeVariablePicker()
|
|
740
|
+
return
|
|
741
|
+
}
|
|
742
|
+
// seletor aberto pela toolbar não tem gatilho no texto para reavaliar
|
|
743
|
+
if (variablePicker.value && variablePicker.value.from === null)
|
|
744
|
+
return
|
|
745
|
+
|
|
746
|
+
const { from, empty } = ed.state.selection
|
|
747
|
+
if (!empty) {
|
|
748
|
+
closeVariablePicker()
|
|
749
|
+
return
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
const blockStart = ed.state.doc.resolve(from).start()
|
|
753
|
+
// '\ufffc' (object replacement) para nós atômicos: um chip antes do cursor
|
|
754
|
+
// conta como 1 caractere e não some do texto, senão o `^` casaria errado
|
|
755
|
+
const textBefore = ed.state.doc.textBetween(blockStart, from, '\n', '\uFFFC')
|
|
756
|
+
const match = textBefore.match(VARIABLE_TRIGGER_RE)
|
|
757
|
+
|
|
758
|
+
if (!match || (match[1]?.length ?? 0) > VARIABLE_TRIGGER_MAX_QUERY) {
|
|
759
|
+
closeVariablePicker()
|
|
760
|
+
return
|
|
761
|
+
}
|
|
762
|
+
if (!variablePicker.value && !docChanged)
|
|
763
|
+
return
|
|
764
|
+
|
|
765
|
+
const slashPos = from - match[0].length + match[0].indexOf('/')
|
|
766
|
+
const coords = sheetCoords(slashPos)
|
|
767
|
+
if (!coords) {
|
|
768
|
+
closeVariablePicker()
|
|
769
|
+
return
|
|
770
|
+
}
|
|
771
|
+
variablePicker.value = { ...coords, from: slashPos, query: match[1] ?? '' }
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* Botão da toolbar: mesmo seletor, ancorado no cursor, com campo de busca
|
|
776
|
+
* próprio.
|
|
777
|
+
*
|
|
778
|
+
* NÃO devolve o foco ao editor aqui. O `focus()` do Tiptap é adiado por um
|
|
779
|
+
* `requestAnimationFrame`, então ele chegava DEPOIS do popover montar e roubava
|
|
780
|
+
* o foco do campo de busca — o que a pessoa digitava virava texto do documento
|
|
781
|
+
* e o Enter inseria o primeiro item de uma lista que nunca chegou a ser
|
|
782
|
+
* filtrada. A posição do cursor não depende do foco: `state.selection`
|
|
783
|
+
* continua onde estava (ou no começo, se ninguém nunca clicou no documento).
|
|
784
|
+
*/
|
|
785
|
+
function openVariablePicker() {
|
|
786
|
+
const ed = editor.value
|
|
787
|
+
if (!ed || ed.isDestroyed || !hasVariables.value)
|
|
788
|
+
return
|
|
789
|
+
const coords = sheetCoords(ed.state.selection.from)
|
|
790
|
+
if (!coords)
|
|
791
|
+
return
|
|
792
|
+
variablePicker.value = { ...coords, from: null, query: undefined }
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
function insertVariable(variable: MinutaVariableDef) {
|
|
796
|
+
const ed = editor.value
|
|
797
|
+
if (!ed || ed.isDestroyed)
|
|
798
|
+
return
|
|
799
|
+
const trigger = variablePicker.value
|
|
800
|
+
const chain = ed.chain().focus()
|
|
801
|
+
// some com o `/consulta` que abriu o seletor — o placeholder toma o lugar dele
|
|
802
|
+
if (trigger?.from != null)
|
|
803
|
+
chain.deleteRange({ from: trigger.from, to: ed.state.selection.from })
|
|
804
|
+
chain.insertContent({
|
|
805
|
+
type: 'templateVariable',
|
|
806
|
+
attrs: { varKey: variable.key, label: variable.label },
|
|
807
|
+
}).run()
|
|
808
|
+
closeVariablePicker()
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
/**
|
|
812
|
+
* Com o seletor aberto o foco continua NO EDITOR (o usuário está digitando o
|
|
813
|
+
* texto do filtro), então as setas e o Enter têm que ser interceptados aqui —
|
|
814
|
+
* senão andam o cursor e quebram o parágrafo.
|
|
815
|
+
*/
|
|
816
|
+
function onEditorKeyDown(_view: unknown, event: KeyboardEvent): boolean {
|
|
817
|
+
const picker = variablePickerRef.value
|
|
818
|
+
if (!variablePicker.value || !picker)
|
|
819
|
+
return false
|
|
820
|
+
if (event.key === 'ArrowDown') {
|
|
821
|
+
picker.move(1)
|
|
822
|
+
return true
|
|
823
|
+
}
|
|
824
|
+
if (event.key === 'ArrowUp') {
|
|
825
|
+
picker.move(-1)
|
|
826
|
+
return true
|
|
827
|
+
}
|
|
828
|
+
if (event.key === 'Escape') {
|
|
829
|
+
closeVariablePicker()
|
|
830
|
+
return true
|
|
831
|
+
}
|
|
832
|
+
if (event.key === 'Enter' || event.key === 'Tab') {
|
|
833
|
+
// sem resultado o Enter é Enter: quebrar o parágrafo é o que a pessoa quis
|
|
834
|
+
if (!picker.hasResults())
|
|
835
|
+
return false
|
|
836
|
+
picker.choose()
|
|
837
|
+
return true
|
|
838
|
+
}
|
|
839
|
+
return false
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// catálogo esvaziado (ou editor virou read-only) com o seletor aberto
|
|
843
|
+
watch(() => [hasVariables.value, props.editable], () => {
|
|
844
|
+
if (variablePicker.value && (!hasVariables.value || !props.editable))
|
|
845
|
+
closeVariablePicker()
|
|
846
|
+
})
|
|
847
|
+
|
|
661
848
|
defineExpose({ editor, schedulePaginate, refreshChrome, containerRef })
|
|
662
849
|
</script>
|
|
663
850
|
|
|
@@ -759,6 +946,15 @@ defineExpose({ editor, schedulePaginate, refreshChrome, containerRef })
|
|
|
759
946
|
<MinutaIcon name="i-ph-image" />
|
|
760
947
|
</button>
|
|
761
948
|
<input ref="imageInput" type="file" accept="image/*" class="hidden" @change="onImageFile">
|
|
949
|
+
<button
|
|
950
|
+
v-if="hasVariables"
|
|
951
|
+
class="poc-tool"
|
|
952
|
+
:class="{ 'poc-tool--on': !!variablePicker }"
|
|
953
|
+
title="Inserir variável (ou digite / no texto)"
|
|
954
|
+
@click="openVariablePicker"
|
|
955
|
+
>
|
|
956
|
+
<MinutaIcon name="i-ph-brackets-curly" />
|
|
957
|
+
</button>
|
|
762
958
|
<button class="poc-tool" title="Inserir nota de rodapé" @click="insertFootnote">
|
|
763
959
|
<MinutaIcon name="i-ph-note" />
|
|
764
960
|
</button>
|
|
@@ -770,7 +966,7 @@ defineExpose({ editor, schedulePaginate, refreshChrome, containerRef })
|
|
|
770
966
|
</button>
|
|
771
967
|
</div>
|
|
772
968
|
|
|
773
|
-
<div ref="containerRef" class="relative min-h-0 w-full flex-1 overflow-y-auto bg-gray-120 py-24px" @click="openPalette = null">
|
|
969
|
+
<div ref="containerRef" class="relative min-h-0 w-full flex-1 overflow-y-auto bg-gray-120 py-24px" @click="openPalette = null; closeVariablePicker()">
|
|
774
970
|
<div ref="sheetRef" class="poc-sheet relative mx-auto bg-white shadow-md" :style="sheetStyle" @click="onNotesClick">
|
|
775
971
|
<!-- cabeçalho da 1ª página (na margem superior da folha) -->
|
|
776
972
|
<div class="poc-first-header" :style="firstHeaderStyle" title="Clique para editar o cabeçalho" @click="editChrome('header')">
|
|
@@ -817,6 +1013,17 @@ defineExpose({ editor, schedulePaginate, refreshChrome, containerRef })
|
|
|
817
1013
|
<div v-else class="poc-chrome-text" />
|
|
818
1014
|
<span v-if="chromeText.showPageNumber !== false" class="ml-auto">Página {{ totalPages }} de {{ totalPages }}</span>
|
|
819
1015
|
</div>
|
|
1016
|
+
<MinutaVariablePicker
|
|
1017
|
+
v-if="variablePicker"
|
|
1018
|
+
ref="variablePickerRef"
|
|
1019
|
+
:variables="props.variables ?? []"
|
|
1020
|
+
:top="variablePicker.top"
|
|
1021
|
+
:left="variablePicker.left"
|
|
1022
|
+
:query="variablePicker.query"
|
|
1023
|
+
@select="insertVariable"
|
|
1024
|
+
@close="closeVariablePicker"
|
|
1025
|
+
/>
|
|
1026
|
+
|
|
820
1027
|
<slot name="gutter" />
|
|
821
1028
|
|
|
822
1029
|
<!-- popover de edição da nota de rodapé (ancorado na chamada) -->
|
|
@@ -933,7 +1140,7 @@ defineExpose({ editor, schedulePaginate, refreshChrome, containerRef })
|
|
|
933
1140
|
</template>
|
|
934
1141
|
|
|
935
1142
|
<style scoped>
|
|
936
|
-
:deep(.poc-ins){background:rgba(34,197,94,.16);text-decoration:underline;text-decoration-color:#16a34a}:deep(.poc-del){background:rgba(239,68,68,.12);color:#b91c1c;text-decoration:line-through}.poc-bubble-btn{border-radius:6px;font-size:13px;padding:4px 8px;transition:all .15s;transition-timing-function:ease}.poc-toolbar{background:#fafbfc;border-bottom:.5px solid #dee3e7;flex-wrap:wrap;gap:2px;padding:4px 12px}.poc-
|
|
1143
|
+
:deep(.poc-ins){background:rgba(34,197,94,.16);text-decoration:underline;text-decoration-color:#16a34a}:deep(.poc-del){background:rgba(239,68,68,.12);color:#b91c1c;text-decoration:line-through}.poc-bubble-btn{border-radius:6px;font-size:13px;padding:4px 8px;transition:all .15s;transition-timing-function:ease}.poc-toolbar{align-items:center;background:#fafbfc;border-bottom:.5px solid #dee3e7;display:flex;flex-wrap:wrap;gap:2px;padding:4px 12px}@media (max-width:640px){.poc-toolbar{flex-wrap:nowrap;overflow-x:auto;padding:4px 8px;scrollbar-width:none}.poc-toolbar::-webkit-scrollbar{display:none}.poc-toolbar>*{flex:none}}.poc-tool{align-items:center;border-radius:6px;display:flex;font-size:13px;height:28px;justify-content:center;min-width:28px;padding-left:6px;padding-right:6px;position:relative;transition:all .15s;transition-timing-function:ease}.poc-tool-sep{background:#dee3e7;height:20px;margin:0 6px;width:1px}.poc-tool-select{background:#fff;border-radius:6px;font-size:12px;height:28px;padding-left:6px;padding-right:6px}.poc-color-underline{background:#dc2626;border-radius:1px;bottom:4px;height:3px;left:7px;position:absolute;right:7px}.poc-palette{background:#fff;border:.5px solid #dee3e7;border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.12);display:flex;flex-wrap:wrap;gap:2px;left:0;padding:8px;position:absolute;top:32px;width:230px;z-index:50}.poc-palette-swatch{border:1px solid rgba(0,0,0,.1);border-radius:3px;cursor:pointer;height:19px;width:19px}.poc-palette-swatch:hover{transform:scale(1.2)}.poc-palette-custom{align-items:center;color:#565d69;cursor:pointer;display:flex;font-size:12px;margin-top:6px;width:100%}.poc-color-swatch{border:1px solid rgba(0,0,0,.12);border-radius:4px;cursor:pointer;height:16px;margin:0 2px;width:16px}.poc-color-swatch:hover{transform:scale(1.15)}.poc-first-header{align-items:center;cursor:pointer;display:flex;gap:12px;position:absolute;top:0}.poc-first-header[style*=center]{justify-content:center}.poc-first-header[style*=right]{justify-content:flex-end}.poc-first-header:hover,.poc-last-footer:hover,:deep(.poc-page-footerarea:hover),:deep(.poc-page-headerarea:hover){background:rgba(99,102,241,.06);outline:1px dashed #c7d2fe}.poc-last-footer{align-items:center;bottom:0;color:#94a3b8;cursor:pointer;display:flex;font-size:11px;justify-content:space-between;position:absolute}.poc-chrome-text,:deep(.poc-chrome-text){color:#64748b;font-size:11px}.poc-chrome-text :deep(img),:deep(.poc-chrome-text img){display:inline-block;max-height:48px;max-width:200px;vertical-align:middle}:deep(.poc-pagebreak-marker){border-top:1px dashed #a5b4fc;font-size:0!important;height:16px;line-height:0!important;margin:6px 0!important;position:relative}:deep(.poc-pagebreak-marker):after{background:#fff;color:#818cf8;content:"quebra de página do template";font-size:10px;left:50%;line-height:16px;padding:0 8px;position:absolute;top:-8px;transform:translateX(-50%)}:deep(.poc-page-chrome){display:block;pointer-events:none;text-align:initial;text-indent:0;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}:deep(.poc-page-footerarea),:deep(.poc-page-headerarea){cursor:pointer;pointer-events:auto}:deep(.poc-page-footerarea){align-items:center;color:#94a3b8;display:flex;font-size:11px;justify-content:space-between}:deep(.poc-page-gapband){background:#eceef1;box-shadow:inset 0 6px 6px -6px rgba(0,0,0,.25),inset 0 -6px 6px -6px rgba(0,0,0,.25)}:deep(.poc-page-headerarea){align-items:center;display:flex}:deep(.poc-page-headerarea[style*=center]){justify-content:center}:deep(.poc-page-headerarea[style*=right]){justify-content:flex-end}:deep(.ProseMirror){outline:none;white-space:pre-wrap;word-wrap:break-word}:deep(h1){color:#0f172a;font-size:24px;font-weight:640;letter-spacing:-.3px;line-height:32px;margin:0 0 20px}:deep(h2){color:#0f172a;font-size:19px;font-weight:620;letter-spacing:-.2px;line-height:26px;margin:28px 0 14px}:deep(h3){color:#0f172a;font-size:17px;font-weight:600;letter-spacing:-.1px;line-height:24px;margin:24px 0 12px}:deep(h1):first-child,:deep(h2):first-child,:deep(h3):first-child{margin-top:0}:deep(strong){font-weight:540}:deep(p){color:#000;font-size:18px;font-weight:400;letter-spacing:-.4px;line-height:28px;line-height:1.7em;margin-bottom:.75em;text-align:justify}:deep(blockquote){font-size:18px;font-weight:400;letter-spacing:-.4px;line-height:28px;margin-bottom:2em;margin-left:35%}:deep(ol),:deep(ul){margin-bottom:2em}:deep(li){list-style-position:inside;margin-bottom:16px;margin-left:48px}:deep(ul)>li{list-style-type:disc}:deep(ol)>li{list-style-type:decimal}:deep(table){border:.5px solid #d4d9df;max-width:100%;table-layout:fixed;width:100%}:deep(th){color:inherit;font-size:inherit;font-weight:700;overflow-wrap:anywhere;padding:12px;text-align:left}:deep(td){color:inherit;font-size:inherit;line-height:inherit;overflow-wrap:anywhere;padding:12px;text-align:left}:deep(td p),:deep(th p){color:inherit;font-size:inherit;line-height:inherit;margin-bottom:0}:deep(img){display:block;max-width:100%}:deep(.poc-island--img>img),:deep(.poc-island>img:only-child){margin-left:auto;margin-right:auto}:deep(.poc-chrome-canvas){overflow:hidden}:deep(.poc-chrome-canvas [data-el]){position:absolute}:deep(.poc-chrome-canvas [data-el=text]){color:#64748b;font-size:11px;line-height:1.4;text-align:left;white-space:pre-wrap}:deep(img[data-vault-src]){animation:poc-img-loading 1.4s ease-in-out infinite}@keyframes poc-img-loading{0%,to{opacity:.5}50%{opacity:.9}}:deep(.poc-lone-row){justify-content:center!important}:deep(.poc-lone-row>:not(.poc-lone-cell)){flex:0 0 0!important;min-width:0!important;padding:0!important}:deep(.poc-lone-row>.poc-lone-cell){align-items:center!important;flex:0 0 auto!important;max-width:100%;min-width:0}:deep([data-horizontal-align=left] .poc-island--img>img),:deep([data-horizontal-align=left] .poc-island>img:only-child){margin-left:0}:deep([data-horizontal-align=right] .poc-island--img>img),:deep([data-horizontal-align=right] .poc-island>img:only-child){margin-right:0}.poc-review-cursor :deep(.poc-minuta-block){cursor:pointer}:deep(.poc-minuta-block){border-radius:4px;position:relative}:deep(.poc-minuta-block:hover){outline:1px dashed #c7d2fe;outline-offset:6px}.poc-no-block-origin :deep(.poc-minuta-block:hover){outline:none}.poc-no-block-origin :deep(.poc-minuta-block:hover):before{content:none}:deep(.poc-minuta-block:hover):before{background:#eef2ff;border:1px solid #c7d2fe;border-radius:4px;color:#6366f1;content:attr(data-block-title);font-size:10px;letter-spacing:.04em;padding:1px 8px;pointer-events:none;position:absolute;right:0;text-transform:uppercase;top:-22px;z-index:3}:deep(.poc-varchip){background:rgba(59,130,246,.06);border-radius:3px;box-shadow:inset 0 0 0 1px rgba(59,130,246,.25);cursor:pointer;transition:background .15s ease}:deep(.poc-varchip:hover){background:rgba(59,130,246,.16)}:deep(.poc-tplvar){background:rgba(251,191,36,.16);border-radius:3px;box-shadow:inset 0 0 0 1px rgba(180,83,9,.35);color:#78350f;display:inline;padding:0 2px;white-space:pre-wrap}:deep(.poc-tplvar--unknown){background:rgba(244,63,94,.12);box-shadow:inset 0 0 0 1px rgba(190,18,60,.45);color:#881337;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}:deep(.ProseMirror-selectednode.poc-tplvar){box-shadow:inset 0 0 0 2px rgba(180,83,9,.75)}:deep(.poc-missing-image .missing-image-warning:hover){background-color:rgba(254,174,0,.09);border-color:rgba(223,139,13,.85)}:deep(.poc-missing-image__remove){background:hsla(0,0%,100%,.75);border:none;border-radius:999px;color:#773613;cursor:pointer;font-size:16px;height:22px;line-height:1;opacity:0;position:absolute;right:4px;top:4px;transition:opacity .15s ease,background .15s ease;width:22px}:deep(.poc-missing-image:hover .poc-missing-image__remove){opacity:1}:deep(.poc-missing-image__remove:hover){background:rgba(254,174,0,.35)}:deep(.poc-missing-image.ProseMirror-selectednode .missing-image-warning){outline:2px solid rgba(223,139,13,.9);outline-offset:2px}.poc-page-notes,:deep(.poc-page-notes){color:#1c242d;font-size:10.67px;line-height:1.25;padding-top:6px}.poc-page-notes:before,:deep(.poc-page-notes):before{border-top:.5px solid #9aa4ae;content:"";display:block;margin-bottom:6px;width:30%}.poc-page-note,:deep(.poc-page-note){color:#1c242d;font-size:10.67px;font-weight:400;line-height:1.25;margin:0;text-align:justify}.poc-page-note sup,:deep(.poc-page-note sup){font-size:.8em;line-height:0;vertical-align:super}.poc-page-note a,:deep(.poc-page-note a){color:#0563c1;text-decoration:underline}:deep(.poc-footnote){color:#1d4ed8;cursor:help;font-size:.7em;line-height:0;vertical-align:super}:deep(.poc-island){position:relative}:deep(.poc-island--img){cursor:grab}:deep(.poc-img-handle){background:#3b82f6;border:2px solid #fff;border-radius:3px;bottom:-6px;box-shadow:0 1px 3px rgba(0,0,0,.3);cursor:nwse-resize;height:12px;opacity:0;position:absolute;right:-6px;transition:opacity .12s ease;width:12px}:deep(.poc-island--img.ProseMirror-selectednode .poc-img-handle),:deep(.poc-island--img:hover .poc-img-handle){opacity:1}:deep(.poc-island.ProseMirror-selectednode){outline:2px solid #93c5fd;outline-offset:2px}
|
|
937
1144
|
</style>
|
|
938
1145
|
|
|
939
1146
|
<style scoped>
|
|
@@ -1017,17 +1224,6 @@ defineExpose({ editor, schedulePaginate, refreshChrome, containerRef })
|
|
|
1017
1224
|
border: 0.5px solid #d4d9df;
|
|
1018
1225
|
}
|
|
1019
1226
|
|
|
1020
|
-
/* no CDB os tokens de heading vencem os overrides text-24px/text-20px — replica */
|
|
1021
|
-
.poc-editor-root :deep(h2) {
|
|
1022
|
-
font-size: 14px;
|
|
1023
|
-
line-height: 16px;
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
.poc-editor-root :deep(h3) {
|
|
1027
|
-
font-size: 12px;
|
|
1028
|
-
line-height: 14px;
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
1227
|
/* popover de nota de rodapé (ancorado na chamada, estilo comentário) */
|
|
1032
1228
|
.poc-footnote-pop {
|
|
1033
1229
|
position: absolute;
|
|
@@ -251,6 +251,12 @@ async function exportDocx() {
|
|
|
251
251
|
// ==========================================
|
|
252
252
|
|
|
253
253
|
const historyOpen = ref(false)
|
|
254
|
+
/**
|
|
255
|
+
* Painel de análise em tela estreita. Declarado aqui, e não junto do resto do
|
|
256
|
+
* layout responsivo, porque `toggleHistory` precisa fechá-lo: os dois painéis
|
|
257
|
+
* são mutuamente exclusivos.
|
|
258
|
+
*/
|
|
259
|
+
const showAnalysisPanel = ref(false)
|
|
254
260
|
const versions = ref<MinutaVersion[]>([])
|
|
255
261
|
const loadingVersions = ref(false)
|
|
256
262
|
const savingCheckpoint = ref(false)
|
|
@@ -296,6 +302,8 @@ function toggleHistory() {
|
|
|
296
302
|
closeHistory()
|
|
297
303
|
return
|
|
298
304
|
}
|
|
305
|
+
// só cabe um painel: dois de 320px lado a lado esmagam o documento
|
|
306
|
+
showAnalysisPanel.value = false
|
|
299
307
|
historyOpen.value = true
|
|
300
308
|
void loadVersions()
|
|
301
309
|
}
|
|
@@ -446,6 +454,44 @@ async function applyChrome({ html, scope, showPageNumber }: { html: string, scop
|
|
|
446
454
|
}
|
|
447
455
|
}
|
|
448
456
|
|
|
457
|
+
/**
|
|
458
|
+
* Comentários de margem só cabem quando há folha (≈794px) + coluna (264px) +
|
|
459
|
+
* respiro. Abaixo disso a margem fica fora da tela — então os cards viram um
|
|
460
|
+
* painel lateral que o usuário abre e fecha.
|
|
461
|
+
*/
|
|
462
|
+
const GUTTER_MIN_WIDTH = 1120
|
|
463
|
+
const bodyRef = ref<HTMLElement | null>(null)
|
|
464
|
+
const bodyWidth = ref(0)
|
|
465
|
+
let bodyResizeObserver: ResizeObserver | null = null
|
|
466
|
+
|
|
467
|
+
const narrowLayout = computed(() => bodyWidth.value > 0 && bodyWidth.value < GUTTER_MIN_WIDTH)
|
|
468
|
+
|
|
469
|
+
function openAnalysisPanel() {
|
|
470
|
+
// mutuamente exclusivo com o histórico (ver toggleHistory)
|
|
471
|
+
closeHistory()
|
|
472
|
+
showAnalysisPanel.value = true
|
|
473
|
+
}
|
|
474
|
+
const analysisCount = computed(() => {
|
|
475
|
+
const a = minuta.value?.analysis
|
|
476
|
+
if (!a)
|
|
477
|
+
return 0
|
|
478
|
+
return (a.teses?.length ?? 0) + (a.jurisprudencias?.length ?? 0) + (a.citacoes?.length ?? 0) + (a.fatos?.length ?? 0)
|
|
479
|
+
})
|
|
480
|
+
|
|
481
|
+
watch(bodyRef, (el) => {
|
|
482
|
+
bodyResizeObserver?.disconnect()
|
|
483
|
+
bodyResizeObserver = null
|
|
484
|
+
if (!el || typeof ResizeObserver === 'undefined')
|
|
485
|
+
return
|
|
486
|
+
bodyWidth.value = el.clientWidth
|
|
487
|
+
bodyResizeObserver = new ResizeObserver(() => {
|
|
488
|
+
bodyWidth.value = el.clientWidth
|
|
489
|
+
})
|
|
490
|
+
bodyResizeObserver.observe(el)
|
|
491
|
+
}, { immediate: true })
|
|
492
|
+
|
|
493
|
+
onUnmounted(() => bodyResizeObserver?.disconnect())
|
|
494
|
+
|
|
449
495
|
onMounted(() => window.addEventListener('poc:edit-chrome', onEditChrome))
|
|
450
496
|
onUnmounted(() => window.removeEventListener('poc:edit-chrome', onEditChrome))
|
|
451
497
|
|
|
@@ -523,10 +569,22 @@ const editorCompRef = ref<any>(null)
|
|
|
523
569
|
const docPreviewOpen = ref(false)
|
|
524
570
|
const docPreviewUrl = ref<string | null>(null)
|
|
525
571
|
const docPreviewPage = ref<number | null>(null)
|
|
526
|
-
|
|
527
|
-
|
|
572
|
+
/** trecho que o card de fato pediu para destacar no documento-fonte */
|
|
573
|
+
const docPreviewHighlight = ref<string | null>(null)
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* `fromCard` separa os dois chamadores: o botão Documentos abre a lista limpa,
|
|
577
|
+
* e o card de fato extraído mantém página e destaque mesmo quando o documento
|
|
578
|
+
* que ele nomeia não casa com nenhum anexo (aí abre o primeiro arquivo, mas a
|
|
579
|
+
* localização que o card pediu continua valendo).
|
|
580
|
+
*/
|
|
581
|
+
function openDocPreview(url?: string | null, fromCard = false) {
|
|
528
582
|
if (!minuta.value?.files.length)
|
|
529
583
|
return
|
|
584
|
+
if (!fromCard) {
|
|
585
|
+
docPreviewPage.value = null
|
|
586
|
+
docPreviewHighlight.value = null
|
|
587
|
+
}
|
|
530
588
|
docPreviewUrl.value = url ?? minuta.value.files[0].url
|
|
531
589
|
docPreviewOpen.value = true
|
|
532
590
|
}
|
|
@@ -555,7 +613,8 @@ function onOpenDocument(payload: { documento: string, pagina?: number, highlight
|
|
|
555
613
|
const file = minuta.value?.files.find(f => f.name === payload.documento)
|
|
556
614
|
?? minuta.value?.files.find(f => f.name.includes(payload.documento) || payload.documento.includes(f.name))
|
|
557
615
|
docPreviewPage.value = payload.pagina ?? null
|
|
558
|
-
|
|
616
|
+
docPreviewHighlight.value = payload.highlight ?? null
|
|
617
|
+
openDocPreview(file?.url, true)
|
|
559
618
|
}
|
|
560
619
|
|
|
561
620
|
const hasAnalysis = computed(() => {
|
|
@@ -592,32 +651,41 @@ defineExpose({ saveNow, exportDocx, editor })
|
|
|
592
651
|
>
|
|
593
652
|
<span v-else class="minuta-embed__name">{{ minuta.name }}</span>
|
|
594
653
|
<span class="minuta-embed__save-state">{{ SAVE_LABEL[saveState] }}</span>
|
|
595
|
-
<
|
|
654
|
+
<TelaButton
|
|
596
655
|
v-if="minuta.status === 'READY' && minuta.files.length"
|
|
597
|
-
|
|
598
|
-
|
|
656
|
+
variant="ghost"
|
|
657
|
+
size="sm"
|
|
658
|
+
icon="i-ph-files"
|
|
659
|
+
leading
|
|
660
|
+
class="minuta-embed__toolbar-btn"
|
|
599
661
|
@click="openDocPreview()"
|
|
600
662
|
>
|
|
601
|
-
Documentos
|
|
602
|
-
</
|
|
603
|
-
<
|
|
663
|
+
<span class="minuta-embed__btn-label">Documentos</span>
|
|
664
|
+
</TelaButton>
|
|
665
|
+
<TelaButton
|
|
604
666
|
v-if="minuta.status === 'READY'"
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
667
|
+
:variant="historyOpen ? 'secondary' : 'ghost'"
|
|
668
|
+
size="sm"
|
|
669
|
+
icon="i-ph-clock-counter-clockwise"
|
|
670
|
+
leading
|
|
671
|
+
class="minuta-embed__toolbar-btn"
|
|
608
672
|
@click="toggleHistory"
|
|
609
673
|
>
|
|
610
|
-
Histórico
|
|
611
|
-
</
|
|
612
|
-
<
|
|
674
|
+
<span class="minuta-embed__btn-label">Histórico</span>
|
|
675
|
+
</TelaButton>
|
|
676
|
+
<TelaButton
|
|
613
677
|
v-if="minuta.status === 'READY'"
|
|
614
|
-
|
|
678
|
+
variant="primary"
|
|
679
|
+
size="sm"
|
|
680
|
+
icon="i-ph-download-simple"
|
|
681
|
+
leading
|
|
682
|
+
:loading="isExporting"
|
|
615
683
|
:disabled="isExporting || !!versionPreview"
|
|
616
|
-
|
|
684
|
+
class="minuta-embed__toolbar-btn"
|
|
617
685
|
@click="exportDocx"
|
|
618
686
|
>
|
|
619
|
-
{{ isExporting ? 'Exportando…' : 'Baixar DOCX' }}
|
|
620
|
-
</
|
|
687
|
+
<span class="minuta-embed__btn-label">{{ isExporting ? 'Exportando…' : 'Baixar DOCX' }}</span>
|
|
688
|
+
</TelaButton>
|
|
621
689
|
</div>
|
|
622
690
|
|
|
623
691
|
<div v-if="isLoading" class="minuta-embed__status">
|
|
@@ -636,7 +704,7 @@ defineExpose({ saveNow, exportDocx, editor })
|
|
|
636
704
|
A geração falhou: {{ minuta.error || 'erro desconhecido' }}
|
|
637
705
|
</div>
|
|
638
706
|
|
|
639
|
-
<div v-else-if="minuta" class="minuta-embed__body">
|
|
707
|
+
<div v-else-if="minuta" ref="bodyRef" class="minuta-embed__body">
|
|
640
708
|
<div class="minuta-embed__document">
|
|
641
709
|
<MinutaDocxEditor
|
|
642
710
|
ref="editorCompRef"
|
|
@@ -652,7 +720,7 @@ defineExpose({ saveNow, exportDocx, editor })
|
|
|
652
720
|
>
|
|
653
721
|
<template #gutter>
|
|
654
722
|
<MinutaAnnotationsGutter
|
|
655
|
-
v-if="hasAnalysis && minuta.analysis"
|
|
723
|
+
v-if="hasAnalysis && minuta.analysis && !narrowLayout"
|
|
656
724
|
:editor="editor"
|
|
657
725
|
:analysis="minuta.analysis"
|
|
658
726
|
:scroll-container="editorCompRef?.containerRef ?? null"
|
|
@@ -662,6 +730,17 @@ defineExpose({ saveNow, exportDocx, editor })
|
|
|
662
730
|
</template>
|
|
663
731
|
</MinutaDocxEditor>
|
|
664
732
|
|
|
733
|
+
<!-- tela estreita: os comentários viram painel lateral -->
|
|
734
|
+
<button
|
|
735
|
+
v-if="hasAnalysis && narrowLayout && !showAnalysisPanel"
|
|
736
|
+
type="button"
|
|
737
|
+
class="minuta-embed__analysis-toggle"
|
|
738
|
+
@click="openAnalysisPanel"
|
|
739
|
+
>
|
|
740
|
+
Análise
|
|
741
|
+
<span class="minuta-embed__analysis-count">{{ analysisCount }}</span>
|
|
742
|
+
</button>
|
|
743
|
+
|
|
665
744
|
<!-- edição de cabeçalho/rodapé (canvas estilo Word) -->
|
|
666
745
|
<div v-if="chromeEditor" class="minuta-embed__chrome-overlay">
|
|
667
746
|
<MinutaChromeEditor
|
|
@@ -703,6 +782,26 @@ defineExpose({ saveNow, exportDocx, editor })
|
|
|
703
782
|
</div>
|
|
704
783
|
</div>
|
|
705
784
|
|
|
785
|
+
<!-- painel: análise (tela estreita — sem margem para ancorar os cards) -->
|
|
786
|
+
<aside v-if="hasAnalysis && narrowLayout && showAnalysisPanel && minuta.analysis" class="minuta-embed__panel minuta-embed__panel--analysis">
|
|
787
|
+
<div class="minuta-embed__panel-head">
|
|
788
|
+
<span>Análise da peça</span>
|
|
789
|
+
<button type="button" @click="showAnalysisPanel = false">
|
|
790
|
+
×
|
|
791
|
+
</button>
|
|
792
|
+
</div>
|
|
793
|
+
<div class="minuta-embed__panel-scroll">
|
|
794
|
+
<MinutaAnnotationsGutter
|
|
795
|
+
:editor="editor"
|
|
796
|
+
:analysis="minuta.analysis"
|
|
797
|
+
:scroll-container="editorCompRef?.containerRef ?? null"
|
|
798
|
+
compact
|
|
799
|
+
@open-document="onOpenDocument"
|
|
800
|
+
@update-analysis="onAnalysisUpdate"
|
|
801
|
+
/>
|
|
802
|
+
</div>
|
|
803
|
+
</aside>
|
|
804
|
+
|
|
706
805
|
<!-- painel: histórico -->
|
|
707
806
|
<aside v-if="historyOpen" class="minuta-embed__panel">
|
|
708
807
|
<div class="minuta-embed__panel-head">
|
|
@@ -771,6 +870,7 @@ defineExpose({ saveNow, exportDocx, editor })
|
|
|
771
870
|
:files="minuta.files"
|
|
772
871
|
:initial-url="docPreviewUrl"
|
|
773
872
|
:initial-page="docPreviewPage"
|
|
873
|
+
:highlight="docPreviewHighlight"
|
|
774
874
|
@close="docPreviewOpen = false"
|
|
775
875
|
@error="msg => emit('error', msg)"
|
|
776
876
|
/>
|
|
@@ -779,5 +879,5 @@ defineExpose({ saveNow, exportDocx, editor })
|
|
|
779
879
|
</template>
|
|
780
880
|
|
|
781
881
|
<style scoped>
|
|
782
|
-
.minuta-embed{background:#f7f7f8;display:flex;flex-direction:column;height:100%}.minuta-embed__toolbar{align-items:center;background:#fff;border-bottom:1px solid #e5e7eb;display:flex;gap:8px;padding:8px 16px}.minuta-embed__name--input{background:transparent;border:0;font-family:inherit;outline:none}.minuta-embed__name--input:focus{text-decoration:underline}.minuta-embed__name{color:#111827;flex:1;font-size:15px;font-weight:500;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.minuta-embed__save-state{color:#9ca3af;font-size:12px;margin-right:4px}.minuta-
|
|
882
|
+
.minuta-embed{background:#f7f7f8;display:flex;flex-direction:column;height:100%}.minuta-embed__toolbar{align-items:center;background:#fff;border-bottom:1px solid #e5e7eb;display:flex;gap:8px;padding:8px 16px}@media (max-width:640px){.minuta-embed__toolbar{gap:4px;padding:6px 10px}.minuta-embed__btn-label{clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}.minuta-embed__save-state{display:none}}.minuta-embed__name--input{background:transparent;border:0;font-family:inherit;outline:none}.minuta-embed__name--input:focus{text-decoration:underline}.minuta-embed__name{color:#111827;flex:1;font-size:15px;font-weight:500;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.minuta-embed__save-state{color:#9ca3af;font-size:12px;margin-right:4px}.minuta-embed__chrome-overlay{bottom:16px;position:absolute;right:16px;z-index:30}.minuta-embed__status{color:#6b7280;font-size:14px;padding:48px 24px;text-align:center}.minuta-embed__status--error{color:#b91c1c}.minuta-embed__body,.minuta-embed__document{display:flex;flex:1;min-height:0}.minuta-embed__document{min-width:0;position:relative}.minuta-embed__banner{align-items:center;background:#fffbeb;border:1px solid #fcd34d;border-radius:16px;bottom:16px;box-shadow:0 4px 6px -1px rgba(0,0,0,.1);display:flex;flex-wrap:wrap;gap:8px 12px;justify-content:center;left:50%;max-width:calc(100% - 32px);padding:8px 16px;position:absolute;transform:translateX(-50%);width:-moz-max-content;width:max-content;z-index:30}.minuta-embed__banner-text{color:#92400e;font-size:12px;font-weight:500}.minuta-embed__banner-actions{display:flex;gap:8px}.minuta-embed__banner-actions button{background:#fff;border:1px solid #fcd34d;border-radius:6px;color:#92400e;cursor:pointer;font-size:12px;padding:4px 10px;white-space:nowrap}.minuta-embed__banner-actions button:disabled{cursor:default;opacity:.6}.minuta-embed__analysis-toggle{align-items:center;background:#fff;border:1px solid #d4d9df;border-radius:999px;bottom:16px;box-shadow:0 2px 10px rgba(15,23,42,.12);color:#334155;cursor:pointer;display:inline-flex;font-size:13px;font-weight:540;gap:8px;padding:8px 14px;position:absolute;right:16px;z-index:20}.minuta-embed__analysis-toggle:hover{border-color:#b8bfc9;color:#0f172a}.minuta-embed__analysis-count{background:#eef1f5;border-radius:999px;color:#64748b;font-size:11px;font-variant-numeric:tabular-nums;padding:1px 7px}.minuta-embed__panel--analysis .minuta-embed__panel-scroll{flex:1;min-height:0;overflow-y:auto;padding:12px}.minuta-embed__panel{background:#fff;border-left:1px solid #e5e7eb;display:flex;flex-direction:column;flex-shrink:0;max-width:55%;width:320px}.minuta-embed__panel-head{align-items:center;border-bottom:1px solid #e5e7eb;color:#111827;display:flex;font-size:14px;font-weight:600;justify-content:space-between;padding:10px 16px}.minuta-embed__panel-head button{background:none;border:none;color:#6b7280;cursor:pointer;font-size:18px;line-height:1}.minuta-embed__checkpoint{border-bottom:1px solid #e5e7eb;display:flex;flex-direction:column;gap:8px;padding:12px}.minuta-embed__checkpoint input{border:1px solid #e5e7eb;border-radius:6px;font-size:13px;padding:6px 10px}.minuta-embed__checkpoint button{background:#fff;border:1px solid #e5e7eb;border-radius:6px;cursor:pointer;font-size:13px;padding:6px 12px}.minuta-embed__versions{flex:1;min-height:0;overflow-y:auto;padding:8px}.minuta-embed__versions-empty{color:#6b7280;font-size:12px;margin:0;padding:8px 12px}.minuta-embed__version{background:#fff;border:1px solid #e5e7eb;border-radius:10px;cursor:pointer;display:block;margin-bottom:6px;padding:10px;text-align:left;width:100%}.minuta-embed__version:hover{background:#faf5ff;border-color:#c4b5fd}.minuta-embed__version--active{background:#f5f3ff;border-color:#a78bfa}.minuta-embed__version:disabled{cursor:wait;opacity:.7}.minuta-embed__version-row{align-items:center;color:#111827;display:flex;font-size:12px;gap:6px}.minuta-embed__version-type{background:#f3f4f6;border-radius:999px;color:#4b5563;font-size:11px;font-style:normal;padding:1px 8px}.minuta-embed__version-type[data-type=auto]{background:#f5f3ff;color:#6d28d9}.minuta-embed__version-type[data-type=manual]{background:#eff6ff;color:#1d4ed8}.minuta-embed__version-date{color:#9ca3af;font-size:11px;margin-left:auto}.minuta-embed__version-comment{color:#111827;display:block;font-size:12px;margin-top:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.minuta-embed__version-author{color:#9ca3af;display:block;font-size:11px;margin-top:2px}
|
|
783
883
|
</style>
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
PhArrowUUpRight,
|
|
6
6
|
PhArrowsOutLineHorizontal,
|
|
7
7
|
PhArrowsOutLineVertical,
|
|
8
|
+
PhBracketsCurly,
|
|
8
9
|
PhEraser,
|
|
9
10
|
PhHighlighter,
|
|
10
11
|
PhImage,
|
|
@@ -29,6 +30,7 @@ const ICONS: Record<string, unknown> = {
|
|
|
29
30
|
'i-ph-arrow-u-up-right': PhArrowUUpRight,
|
|
30
31
|
'i-ph-arrows-out-line-horizontal': PhArrowsOutLineHorizontal,
|
|
31
32
|
'i-ph-arrows-out-line-vertical': PhArrowsOutLineVertical,
|
|
33
|
+
'i-ph-brackets-curly': PhBracketsCurly,
|
|
32
34
|
'i-ph-eraser': PhEraser,
|
|
33
35
|
'i-ph-highlighter': PhHighlighter,
|
|
34
36
|
'i-ph-image': PhImage,
|