@bagelink/vue 1.2.111 → 1.2.119

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.
@@ -17,6 +17,7 @@ import {
17
17
  import { computed, reactive, ref, watch, watchEffect } from 'vue'
18
18
 
19
19
  import { useSchemaField } from '../composables/useSchemaField'
20
+ import TextInput from './form/inputs/TextInput.vue'
20
21
 
21
22
  // Add interface for schema items
22
23
  interface SchemaItem {
@@ -1512,21 +1513,23 @@ function getRelatedFieldWithDefaults(parentId: string, field: any) {
1512
1513
  <template>
1513
1514
  <Card class="upload-data-container h-100p grid overflow-hidden list-wrap ">
1514
1515
  <h2 class="line-height-1 m-0 pb-2 txt-center" v-text="props.title || 'Upload and Map Data'" />
1515
- <DragOver
1516
- v-if="!file"
1517
- accept=".csv,.xls,.xlsx"
1518
- @addFiles="addFile"
1519
- @click="browse(false)"
1520
- >
1521
- <Card class="flex flex-column items-center justify-center outline-dashed outline-3 bg-input hover h-100p justify-content-center">
1522
- <Icon name="upload" size="5" />
1523
- <p>Drag and drop an Excel or CSV file here</p>
1524
- <p>or click to select a file</p>
1525
- <p class="txt-12 color-gray">
1526
- Accepts .xlsx, .xls, and .csv files
1527
- </p>
1528
- </Card>
1529
- </DragOver>
1516
+ <div v-if="!file" class="h-100p flex column justify-content-center">
1517
+ <DragOver
1518
+ accept=".csv,.xls,.xlsx"
1519
+ class="max-h300px w-500px"
1520
+ @addFiles="addFile"
1521
+ @click="browse(false)"
1522
+ >
1523
+ <Card class="flex flex-column items-center justify-center outline-dashed outline-3 bg-input hover h-100p justify-content-center txt-center">
1524
+ <Icon name="upload" size="5" />
1525
+ <p>Drag and drop an Excel or CSV file here</p>
1526
+ <u>or click to select a file</u>
1527
+ <p class="txt-12 color-gray">
1528
+ Accepts .xlsx, .xls, and .csv files
1529
+ </p>
1530
+ </Card>
1531
+ </DragOver>
1532
+ </div>
1530
1533
 
1531
1534
  <!-- Loading indicator -->
1532
1535
  <div v-if="isLoading" class="loading-container">
@@ -1536,10 +1539,19 @@ function getRelatedFieldWithDefaults(parentId: string, field: any) {
1536
1539
 
1537
1540
  <!-- Step 2: Sheet selection and configuration -->
1538
1541
  <div class="overflow h-100p">
1539
- <div v-if="file && !isLoading && sheetNames.length > 0" class="config-section flex gap-05 pb-2">
1540
- <Btn v-tooltip="'Change File'" :value="file.name" thin round iconEnd="edit" @click="file = null" />
1542
+ <div v-if="file && !isLoading && sheetNames.length > 0" class="config-section flex gap-05 pb-2 m_flex-wrap">
1543
+ <Btn v-tooltip="'Change File'" class="px-1" color="gray" @click="file = null">
1544
+ <Icon icon="draft" size="1.5" weight="300" />
1545
+ <p>
1546
+ {{ file.name }}
1547
+ </p>
1548
+ <!-- <Icon icon="edit" size="0.75" /> -->
1549
+ </Btn>
1541
1550
  <SelectInput v-if="sheetNames.length > 1" v-model="selectedSheet" :options="sheetNames" label="Select Sheet" />
1542
- <CheckInput v-model="hasHeaders" label="Mark this if file has a header row" class="m-0" />
1551
+ <CheckInput
1552
+ v-model="hasHeaders" label="Mark this if file has a header row" class="m-0"
1553
+ style="--bgl-accent-color: var(--bgl-black); --bgl-primary: var(--bgl-black);"
1554
+ />
1543
1555
  </div>
1544
1556
 
1545
1557
  <!-- Step 3: Field Mapping -->
@@ -1552,7 +1564,7 @@ function getRelatedFieldWithDefaults(parentId: string, field: any) {
1552
1564
  </p>
1553
1565
 
1554
1566
  <div class="mapping-table">
1555
- <div class="grid grid-wrap-5 gap-1 bold pb-1">
1567
+ <div class="grid grid-wrap-5 gap-1 bold pb-1 m_none">
1556
1568
  <p>Schema Field</p>
1557
1569
  <p>Column from File</p>
1558
1570
  <p>Default Value</p>
@@ -1560,10 +1572,12 @@ function getRelatedFieldWithDefaults(parentId: string, field: any) {
1560
1572
  <p>Actions</p>
1561
1573
  </div>
1562
1574
 
1563
- <div v-for="field in schemaFields" :key="field.id" class="grid grid-wrap-5 gap-1" :class="{ 'array-field-row': field.isArrayField || field.$el === 'array' }">
1575
+ <div v-for="field in schemaFields" :key="field.id" class="grid grid-wrap-5 gap-1 m_gap-025 m_pb-1-5" :class="{ 'array-field-row': field.isArrayField || field.$el === 'array' }">
1564
1576
  <div>
1565
1577
  <div class="field-label">
1566
- {{ field.label }}
1578
+ <p class="grid-span-2 input-size line-height-1 inline-block">
1579
+ {{ field.label }}
1580
+ </p>
1567
1581
  <span v-if="field.isArrayField">↳</span>
1568
1582
  <Pill v-if="field.$el === 'array'" class="txt10 ms-05" round thin value="Array" />
1569
1583
  <!-- <span v-if="field.$el === 'array'" class="array-parent-indicator">[Array]</span> -->
@@ -1577,7 +1591,7 @@ function getRelatedFieldWithDefaults(parentId: string, field: any) {
1577
1591
  {{ getFieldDescription(field).description }}
1578
1592
  </div>
1579
1593
  </div>
1580
- <td class="fileColSelect">
1594
+ <div class="fileColSelect">
1581
1595
  <SelectInput
1582
1596
  v-model="fieldMapping[field.id]"
1583
1597
  icon="table_chart"
@@ -1586,7 +1600,7 @@ function getRelatedFieldWithDefaults(parentId: string, field: any) {
1586
1600
  :disabled="field.disabled"
1587
1601
  @change="handleSelectChange($event, field.id)"
1588
1602
  />
1589
- </td>
1603
+ </div>
1590
1604
  <div>
1591
1605
  <!-- Default Value Input -->
1592
1606
  <div class="default-value-container hideLabel">
@@ -1604,7 +1618,7 @@ function getRelatedFieldWithDefaults(parentId: string, field: any) {
1604
1618
  />
1605
1619
  </div>
1606
1620
  <div>
1607
- <div class="flex gap-05">
1621
+ <div class="flex gap-05 my-05">
1608
1622
  <Btn
1609
1623
  v-tooltip="'Transform'"
1610
1624
  thin
@@ -1634,34 +1648,40 @@ function getRelatedFieldWithDefaults(parentId: string, field: any) {
1634
1648
  <!-- Transformation Modal -->
1635
1649
  <Modal v-model:visible="showTransformDialog" title="Configure Transformations" width="800">
1636
1650
  <div v-if="selectedTransformField">
1637
- <div class="flex space-between gap-1 mb-1">
1651
+ <div class="flex space-between gap-1 mb-1 border-bottom pb-05 m_flex-wrap">
1638
1652
  <p>Create transformations for <strong>{{ selectedTransformField.label }}</strong></p>
1639
1653
  <Btn icon="auto_awesome" thin value="Autodetect" @click="autoPopulateTransformations(selectedTransformField.id)" />
1640
1654
  </div>
1641
- <table>
1642
- <thead>
1643
- <tr>
1644
- <th>Source Value</th>
1645
- <th>Target Value</th>
1646
- <th>Action</th>
1647
- </tr>
1648
- </thead>
1649
- <tbody>
1650
- <tr v-for="(transform, index) in transformations[selectedTransformField.id] || []" :key="index">
1651
- <td>{{ transform.sourceValue }}</td>
1652
- <td>{{ transform.targetValue }}</td>
1653
- <td>
1654
- <Btn
1655
- v-tooltip="'Remove'"
1656
- thin
1657
- icon="delete"
1658
- color="red"
1659
- @click="removeTransformation(selectedTransformField.id, index)"
1660
- />
1661
- </td>
1662
- </tr>
1663
- <tr>
1664
- <td>
1655
+
1656
+ <div>
1657
+ <div class="grid grid-wrap-7 gap-1 bold pb-05 m_none">
1658
+ <p class="grid-span-2">
1659
+ Source Value
1660
+ </p>
1661
+ <p class="grid-span-4">
1662
+ Target Value
1663
+ </p>
1664
+ <p>Action</p>
1665
+ </div>
1666
+ <div>
1667
+ <div v-for="(transform, index) in transformations[selectedTransformField.id] || []" :key="index" class="grid grid-wrap-7 gap-1 align-items-center m_gap-025 m_pb-1-5">
1668
+ <p class="grid-span-2 input-size line-height-1">
1669
+ {{ transform.sourceValue }}
1670
+ </p>
1671
+ <p class="grid-span-4 input-size line-height-1 ellipsis-1">
1672
+ {{ transform.targetValue }}
1673
+ </p>
1674
+ <Btn
1675
+ v-tooltip="'Remove'"
1676
+ class="mb-05"
1677
+ thin
1678
+ icon="delete"
1679
+ color="red"
1680
+ @click="removeTransformation(selectedTransformField.id, index)"
1681
+ />
1682
+ </div>
1683
+ <div class="grid grid-wrap-7 gap-1 align-items-center m_gap-025 m_pb-1-5">
1684
+ <div class="grid-span-2">
1665
1685
  <SelectInput
1666
1686
  v-if="fieldMapping[selectedTransformField.id]"
1667
1687
  v-model="selectedSourceValue"
@@ -1669,9 +1689,9 @@ function getRelatedFieldWithDefaults(parentId: string, field: any) {
1669
1689
  :options="sourceValueOptions"
1670
1690
  placeholder="Select source value"
1671
1691
  />
1672
- <input v-else v-model="selectedSourceValue" type="text" placeholder="Source value">
1673
- </td>
1674
- <td>
1692
+ <TextInput v-else v-model="selectedSourceValue" type="text" placeholder="Source value" />
1693
+ </div>
1694
+ <div class="grid-span-4">
1675
1695
  <SelectInput
1676
1696
  v-if="selectedTransformField.options && selectedTransformField.options.length > 0"
1677
1697
  v-model="selectedTargetValue"
@@ -1679,20 +1699,20 @@ function getRelatedFieldWithDefaults(parentId: string, field: any) {
1679
1699
  :options="selectedTransformField.options"
1680
1700
  placeholder="Select target value"
1681
1701
  />
1682
- <input v-else v-model="selectedTargetValue" type="text" placeholder="Target value">
1683
- </td>
1684
- <td>
1685
- <Btn
1686
- v-tooltip="'Add'"
1687
- thin
1688
- icon="add"
1689
- color="primary"
1690
- @click="addTransformation(selectedTransformField.id)"
1691
- />
1692
- </td>
1693
- </tr>
1694
- </tbody>
1695
- </table>
1702
+ <TextInput v-else v-model="selectedTargetValue" type="text" placeholder="Target value" />
1703
+ </div>
1704
+ <Btn
1705
+ v-tooltip="'Add'"
1706
+ class="mb-05"
1707
+ thin
1708
+ icon="add"
1709
+ color="primary"
1710
+ @click="addTransformation(selectedTransformField.id)"
1711
+ />
1712
+ </div>
1713
+ </div>
1714
+ </div>
1715
+
1696
1716
  <div class="flex pt-05">
1697
1717
  <Btn class="ms-auto" value="Close" @click="showTransformDialog = false" />
1698
1718
  </div>
@@ -1799,20 +1819,21 @@ function getRelatedFieldWithDefaults(parentId: string, field: any) {
1799
1819
  </Modal>
1800
1820
 
1801
1821
  <!-- Preview Modal -->
1802
- <Modal v-model:visible="showPreviewModal" title="Data Preview & Edit" width="1200">
1822
+ <Modal v-model:visible="showPreviewModal" title="Data Preview & Edit" width="90vw">
1803
1823
  <div>
1804
1824
  <Spreadsheet
1805
1825
  v-model="previewData"
1826
+ class="popupPreviewSpreadsheet"
1806
1827
  :column-config="spreadsheetColumns"
1807
1828
  allow-add-row
1808
1829
  />
1809
1830
  </div>
1810
1831
  <div>
1811
- <div>
1832
+ <p class="mt-1">
1812
1833
  Showing all {{ previewData.length }} records. You can edit values directly.
1813
- </div>
1814
- <div>
1815
- <Btn value="Cancel" @click="showPreviewModal = false" />
1834
+ </p>
1835
+ <div class="flex gap-1 mt-1 space-between">
1836
+ <Btn flat thin value="Cancel" @click="showPreviewModal = false" />
1816
1837
  <Btn value="Import Data" @click="processData()" />
1817
1838
  </div>
1818
1839
  </div>
@@ -1924,7 +1945,7 @@ function getRelatedFieldWithDefaults(parentId: string, field: any) {
1924
1945
  color: var(--bgl-green);
1925
1946
  line-height: 0;
1926
1947
  }
1927
- .hideLabel label{
1948
+ .hideLabel label, .hideLabel .label{
1928
1949
  font-size: 0 !important;
1929
1950
  }
1930
1951
  .mapping-table .selectinput-btn:disabled{
@@ -1934,4 +1955,8 @@ function getRelatedFieldWithDefaults(parentId: string, field: any) {
1934
1955
  .field-label{
1935
1956
  --pill-height: 20px;
1936
1957
  }
1958
+ .popupPreviewSpreadsheet .spreadsheet{
1959
+ width: 100%;
1960
+ overflow: auto;
1961
+ }
1937
1962
  </style>
@@ -1,11 +1,7 @@
1
- export interface HilightJS {
2
-
1
+ export interface HighlightJS {
3
2
  highlight: (code: string, options: { language: string, ignoreIllegals: boolean }) => { value: string }
4
-
5
3
  highlightAuto: (code: string) => { value: string }
6
-
7
- getLanguage: (lang: string) => boolean
8
-
4
+ getLanguage: (name: string) => any
9
5
  }
10
6
 
11
7
  export const codeLanguages = {
@@ -33,7 +29,7 @@ export const codeLanguages = {
33
29
  'brainfuck': 'Brainfuck',
34
30
  'c': 'C',
35
31
  'cal': 'C/AL',
36
- 'capnproto': 'Capn Proto',
32
+ 'capnproto': 'Cap\'n Proto',
37
33
  'ceylon': 'Ceylon',
38
34
  'clean': 'Clean',
39
35
  'clojure': 'Clojure',
@@ -203,4 +199,14 @@ export const codeLanguages = {
203
199
  'html': 'HTML',
204
200
  }
205
201
 
206
- export type Language = keyof typeof codeLanguages
202
+ export type Language = 'html' | 'css' | 'javascript' | 'typescript' | 'json' | 'markdown' | string
203
+
204
+ export interface CodeEditorProps {
205
+ language?: Language
206
+ readonly?: boolean
207
+ modelValue?: string
208
+ autodetect?: boolean
209
+ ignoreIllegals?: boolean
210
+ label?: string
211
+ height?: string
212
+ }
@@ -1,23 +1,8 @@
1
1
  <script setup lang="ts">
2
- import type { Language, HilightJS } from './CodeTypes'
3
-
4
- declare global {
5
- interface Window {
6
- hljs: HilightJS
7
- }
8
- }
9
- import { appendStyle, appendScript } from '@bagelink/vue'
2
+ import type { CodeEditorProps } from './CodeTypes'
10
3
  import { onMounted, ref, computed, watch } from 'vue'
4
+ import { useHighlight } from './useHighlight'
11
5
 
12
- interface CodeEditorProps {
13
- language?: Language
14
- readonly?: boolean
15
- modelValue?: string
16
- autodetect?: boolean
17
- ignoreIllegals?: boolean
18
- label?: string
19
- height?: string
20
- }
21
6
  // Props with default values
22
7
  const props = withDefaults(defineProps<CodeEditorProps>(), {
23
8
  language: 'html',
@@ -33,8 +18,8 @@ const emit = defineEmits(['update:modelValue'])
33
18
  // State
34
19
  const code = ref(props.modelValue || '')
35
20
  const editorRef = ref<HTMLDivElement>()
36
- const loaded = ref(false)
37
- const hljs = ref<HilightJS | null>(null)
21
+ const { loaded, loadHighlight, highlightCode } = useHighlight()
22
+
38
23
  // Computed
39
24
  const maxHeight = computed(() => {
40
25
  const h = props.height ?? '240px'
@@ -42,41 +27,14 @@ const maxHeight = computed(() => {
42
27
  })
43
28
 
44
29
  const formattedCode = computed(() => {
45
- if (!hljs.value) return escapeHtml(code.value)
46
-
47
- try {
48
- const lang = props.language || ''
49
-
50
- if (lang && !props.autodetect && !hljs.value.getLanguage(lang)) {
51
- console.warn(`The language "${lang}" is not available.`)
52
- return escapeHtml(code.value)
53
- }
54
-
55
- const result = props.autodetect
56
- ? hljs.value.highlightAuto(code.value)
57
- : hljs.value.highlight(code.value, { language: lang, ignoreIllegals: props.ignoreIllegals })
58
-
59
- return result.value || escapeHtml(code.value)
60
- } catch (error) {
61
- console.error('Highlighting error:', error)
62
- return escapeHtml(code.value)
63
- }
30
+ return highlightCode(
31
+ code.value,
32
+ props.language,
33
+ props.autodetect,
34
+ props.ignoreIllegals
35
+ )
64
36
  })
65
37
 
66
- // Methods
67
- function escapeHtml(unsafe: string) {
68
- return unsafe.replace(/[&<>"']/g, (m) => {
69
- const replacements: { [key: string]: string } = {
70
- '&': '&amp;',
71
- '<': '&lt;',
72
- '>': '&gt;',
73
- '"': '&quot;',
74
- '\'': '&#039;'
75
- }
76
- return replacements[m] || ''
77
- })
78
- }
79
-
80
38
  function handleInput(e: Event) {
81
39
  const target = e.target as HTMLTextAreaElement
82
40
  code.value = target.value
@@ -104,20 +62,7 @@ function handleTab(event: KeyboardEvent) {
104
62
 
105
63
  // Lifecycle
106
64
  onMounted(async () => {
107
- try {
108
- // Load highlight.js
109
- await appendScript('https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.0/highlight.min.js', { id: 'hljs-cdn' })
110
- await appendStyle('https://cdn.jsdelivr.net/npm/highlight.js/styles/atom-one-dark.min.css')
111
-
112
- if (window.hljs) {
113
- hljs.value = window.hljs
114
- loaded.value = true
115
- } else {
116
- console.error('Failed to load highlight.js')
117
- }
118
- } catch (error) {
119
- console.error('Error loading highlight.js:', error)
120
- }
65
+ await loadHighlight()
121
66
  })
122
67
 
123
68
  // Watch for external modelValue changes
@@ -0,0 +1,76 @@
1
+ import type { HighlightJS } from './CodeTypes'
2
+ import { appendStyle, appendScript } from '@bagelink/vue'
3
+ import { ref } from 'vue'
4
+
5
+ // Extend the Window interface
6
+ interface CustomWindow extends Window {
7
+ hljs: HighlightJS
8
+ }
9
+ declare const window: CustomWindow
10
+
11
+ export function useHighlight() {
12
+ const hljs = ref<HighlightJS | null>(null)
13
+ const loaded = ref(false)
14
+
15
+ const loadHighlight = async () => {
16
+ if (loaded.value) return
17
+
18
+ try {
19
+ // Load highlight.js
20
+ await appendScript('https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.0/highlight.min.js', { id: 'hljs-cdn' })
21
+ await appendStyle('https://cdn.jsdelivr.net/npm/highlight.js/styles/atom-one-dark.min.css')
22
+
23
+ if (window.hljs) {
24
+ hljs.value = window.hljs
25
+ loaded.value = true
26
+ } else {
27
+ console.error('Failed to load highlight.js')
28
+ }
29
+ } catch (error) {
30
+ console.error('Error loading highlight.js:', error)
31
+ }
32
+ }
33
+
34
+ const escapeHtml = (unsafe: string) => {
35
+ return unsafe.replace(/[&<>"']/g, (m) => {
36
+ const replacements: { [key: string]: string } = {
37
+ '&': '&amp;',
38
+ '<': '&lt;',
39
+ '>': '&gt;',
40
+ '"': '&quot;',
41
+ '\'': '&#039;'
42
+ }
43
+ return replacements[m] || ''
44
+ })
45
+ }
46
+
47
+ const highlightCode = (code: string, language?: string, autodetect = true, ignoreIllegals = true) => {
48
+ if (!hljs.value) return escapeHtml(code)
49
+
50
+ try {
51
+ const lang = language || ''
52
+
53
+ if (lang && !autodetect && !hljs.value.getLanguage(lang)) {
54
+ console.warn(`The language "${lang}" is not available.`)
55
+ return escapeHtml(code)
56
+ }
57
+
58
+ const result = autodetect
59
+ ? hljs.value.highlightAuto(code)
60
+ : hljs.value.highlight(code, { language: lang, ignoreIllegals })
61
+
62
+ return result.value || escapeHtml(code)
63
+ } catch (error) {
64
+ console.error('Highlighting error:', error)
65
+ return escapeHtml(code)
66
+ }
67
+ }
68
+
69
+ return {
70
+ hljs,
71
+ loaded,
72
+ loadHighlight,
73
+ escapeHtml,
74
+ highlightCode
75
+ }
76
+ }