42 Commits

Author SHA1 Message Date
peterlu14 a1e1dd0c72 - fix EIS channel select wrong 2023-04-28 10:26:48 +08:00
peterlu14 556fd0697f - fix reset
- update find with range
2023-04-27 11:56:51 +08:00
peterlu14 47f5da9efc - disable zoom in when max min boundry is given
- file info add working mode & date
- filter size 0 data
- format code
2023-03-23 12:53:38 +08:00
peterlu14 9bf9db5263 - add right click context menu 2023-03-20 17:40:34 +08:00
peterlu14 8070da4270 - echarts series sampling with lttb
- echarts add color support
- support line in batch mode
- create canvas class
- add find meta files api
- auto import boundry from interactive mode
2023-03-17 17:09:16 +08:00
peterlu14 e666d75772 - support time channel
- support none filter mode
2023-03-14 10:36:57 +08:00
peterlu14 4507ee1c35 - file loading 2 second
- default channel [1,2]
2023-03-07 17:44:49 +08:00
peterlu14 6537664c04 - let to const 2023-03-07 16:48:30 +08:00
peterlu14 ab2b3b2fa4 -remove import defineExpose & defineEmit 2023-03-07 16:47:22 +08:00
peterlu14 8c6f551a35 -remove useless files 2023-03-07 16:41:43 +08:00
peterlu14 3c835eec6a - upgrade modules in package.json (-ionicons) 2023-03-07 16:30:15 +08:00
peterlu14 c3570d1259 - add canvas class and store
- add data-analysis store to save batchMode
- channel store to save generate x & y axis
- data-analysis page display can be switch to display chart
2023-03-06 17:17:41 +08:00
peterlu14 1230a5ffa6 [update] remove useless sidebar 2023-03-02 15:22:57 +08:00
peterlu14 2fd179b73d -file slider loading
-change message format
-disable console
-add console time
-callback func data format change
-remove time limit
-grid show remove
2023-02-13 09:59:42 +08:00
peterlu14 feeb423e24 - get file data onMounted 2023-02-04 18:01:43 +08:00
peterlu14 a1c202fc5c - add chartAPI to series markLine formatter
- rename XAxis & YAxis class
2023-02-04 18:01:03 +08:00
peterlu14 1a5bcf0a58 - chart reset function to fix series not render problem 2023-02-04 15:57:03 +08:00
peterlu14 6b7e5015e7 - let series & markLine tooltip follow unit & scale 2023-02-04 15:55:33 +08:00
peterlu14 d2ccfc63a4 - chart grid height 80% to 75% 2023-02-03 18:27:12 +08:00
peterlu14 c94d4360e6 -add yAxisManager setting in click start button
-replace x-axis setting with axis-setting can both use by x&y axis
-remove chart watch select files
2023-02-03 18:23:25 +08:00
peterlu14 62f62ef5e5 [update] add y-axis manager 2023-02-03 17:02:39 +08:00
peterlu14 aadbb6c482 [update] legend locate bottom & x-axis default name remove 2023-02-03 16:50:10 +08:00
peterlu14 69dc2a718f [update] x-axis fixed & interval follow the unit 2023-02-03 16:49:11 +08:00
peterlu14 4fc46ca4ea [update] x-axis change unit 2023-02-03 15:04:25 +08:00
peterlu14 840f0af14b [update] chart build timing from select file to press start button 2023-02-03 11:07:58 +08:00
peterlu14 53d131376d [update] add Grid & tooltip 2023-02-03 10:12:54 +08:00
peterlu14 f83f8eb8f8 [update] folder rename 2023-02-03 10:10:05 +08:00
peterlu14 68356fbd04 [update] add xAxisManager & giveup setOption & appendData api 2023-02-02 11:20:07 +08:00
peterlu14 a357102e82 [update] restruct again 2023-02-01 11:19:57 +08:00
peterlu14 6ac8e8cd4a [update] resturct data-analysis files struct 2023-02-01 11:16:06 +08:00
peterlu14 3cbc572592 test 2023-01-31 17:50:28 +08:00
peterlu14 ef8ce2a0c4 [update] add chart series 2023-01-31 10:37:06 +08:00
peterlu14 9000fabdea [update] chart init & series data api init 2023-01-18 17:29:48 +08:00
peterlu14 06afc2e1a3 [update] fix render problem 2023-01-13 11:51:25 +08:00
peterlu14 3dfef28777 [update] filetable update 2023-01-12 17:37:54 +08:00
peterlu14 4d48e82997 [update] add new slideout & table 2023-01-12 16:06:51 +08:00
peterlu14 5af4215562 Merge remote-tracking branch 'origin/10-test' into dev/file_modal 2023-01-06 13:41:44 +08:00
peterlu14 4f94fcf541 [update] temp get all files 2023-01-06 13:40:59 +08:00
peterlu14 22afbab8ff [update] fix vue-router deploy apache problem 2023-01-06 13:40:16 +08:00
peterlu14 99f401bac0 [update] router default page direct to data-analysis 2023-01-06 11:13:42 +08:00
peterlu14 3d751f746b [debug] temp fix typescript error 2023-01-06 11:12:49 +08:00
peterlu14 2df4ccf13c [update] fix channel 2023-01-06 10:42:20 +08:00
165 changed files with 6029 additions and 17328 deletions
+1
View File
@@ -22,6 +22,7 @@ module.exports = {
],
rules: {
'@typescript-eslint/no-empty-interface': 0,
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'prettier/prettier': ['warn', {}, { usePrettierrc: true }],
+3345 -1043
View File
File diff suppressed because it is too large Load Diff
+44 -40
View File
@@ -18,55 +18,59 @@
]
},
"dependencies": {
"@amcharts/amcharts5": "^5.2.19",
"@amcharts/amcharts5-geodata": "^5.0.3",
"@fortawesome/fontawesome-free": "^6.1.1",
"@gtm-support/vue-gtm": "^1.6.0",
"axios": "^0.27.2",
"chart.js": "^3.8.0",
"@amcharts/amcharts5": "^5.3.6",
"@amcharts/amcharts5-geodata": "^5.1.0",
"@fortawesome/fontawesome-free": "^6.3.0",
"@gtm-support/vue-gtm": "^2.0.0",
"@hyjiacan/vue-slideout": "^3.0.2",
"axios": "^1.3.4",
"chart.js": "^4.2.1",
"epic-spinners": "^2.0.0",
"flag-icons": "^6.6.4",
"flag-icons": "^6.6.6",
"ionicons": "^4.6.3",
"leaflet": "^1.8.0",
"leaflet": "^1.9.3",
"leaflet-map": "^0.2.1",
"maplibre-gl": "^2.1.9",
"maplibre-gl": "^2.4.0",
"medium-editor": "^5.23.3",
"pinia": "^2.0.16",
"register-service-worker": "^1.7.1",
"sass": "^1.53.0",
"vue": "^3.2.25",
"vue-chartjs": "^4.1.1",
"vue-i18n": "^9.1.10",
"vue-router": "^4.0.14",
"npm-check-updates": "^16.7.10",
"pinia": "^2.0.33",
"register-service-worker": "^1.7.2",
"sass": "^1.58.3",
"v-contextmenu": "^3.0.0",
"vue": "^3.2.47",
"vue-chartjs": "^5.2.0",
"vue-good-table-next": "^0.2.1",
"vue-i18n": "^9.2.2",
"vue-router": "^4.1.6",
"vue-yandex-maps": "^0.12.3",
"vuestic-ui": "^1.5.0"
"vuestic-ui": "^1.6.1"
},
"devDependencies": {
"@intlify/vite-plugin-vue-i18n": "^5.0.1",
"@types/leaflet": "^1.7.11",
"@intlify/vite-plugin-vue-i18n": "^6.0.3",
"@types/leaflet": "^1.9.1",
"@types/medium-editor": "^5.0.5",
"@types/node": "^17.0.25",
"@typescript-eslint/eslint-plugin": "^5.20.0",
"@typescript-eslint/parser": "^5.20.0",
"@vitejs/plugin-vue": "^2.3.3",
"@vue/eslint-config-prettier": "^7.0.0",
"@vue/eslint-config-typescript": "^10.0.0",
"autoprefixer": "^10.4.4",
"echarts": "^5.4.0",
"eslint": "^8.13.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.7.0",
"husky": "^8.0.1",
"lint-staged": "^13.0.1",
"@types/node": "^18.14.6",
"@typescript-eslint/eslint-plugin": "^5.54.1",
"@typescript-eslint/parser": "^5.54.1",
"@vitejs/plugin-vue": "^4.0.0",
"@vue/eslint-config-prettier": "^7.1.0",
"@vue/eslint-config-typescript": "^11.0.2",
"autoprefixer": "^10.4.13",
"echarts": "^5.4.1",
"eslint": "^8.35.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.9.0",
"husky": "^8.0.3",
"lint-staged": "^13.1.2",
"mqtt": "^4.3.7",
"postcss": "^8.4.12",
"prettier": "^2.6.2",
"typescript": "^4.5.4",
"vite": "^2.9.9",
"vite-plugin-windicss": "^1.8.8",
"vue-echarts": "^6.2.3",
"vue-eslint-parser": "^8.3.0",
"vue-tsc": "^1.0.10",
"postcss": "^8.4.21",
"prettier": "^2.8.4",
"typescript": "^4.9.5",
"vite": "^4.1.4",
"vite-plugin-windicss": "^1.8.10",
"vue-echarts": "^6.5.4",
"vue-eslint-parser": "^9.1.0",
"vue-tsc": "^1.2.0",
"windicss": "^3.5.6"
}
}
@@ -1,96 +0,0 @@
<template>
<div>
<va-card class="h-full">
<va-card-content>
<va-select
v-model="simpleSelectModel"
:label="'Filter Mode'"
text-by="description"
track-by="id"
:options="simpleOptions"
/>
<va-card-content>
<div v-if="simpleSelectModel.id === 1">
<va-slider v-model="VTModeModel" label="percentage(%)" track-label-visible :min="0" :max="50" />
</div>
<div v-else-if="simpleSelectModel.id === 2">
<va-slider v-model="slopModeModel" label="1D window" track-label-visible :min="1" :max="50" />
</div>
<div v-else></div>
<div>
<p>{{ channel.xAxis }}</p>
<p>{{ channel.yAxis }}</p>
<p>{{ fileView.filesSelected }}</p>
</div>
</va-card-content>
<va-button class="mt-2" @click="filterData">Start</va-button>
<!-- <div v-if="simpleSelectModel.id === 1">
<va-button>test</va-button>
<va-input></va-input>
</div> -->
</va-card-content>
</va-card>
</div>
</template>
<script setup lang="ts">
import { useChannelStore } from '@/stores/data-analysis/channel'
import { useFileViewStore } from '@/stores/data-analysis/file-view'
import { Ref, ref, defineEmits, defineExpose } from 'vue'
// define emit
// const emit = defineEmits({
// 'filter-data': ({ mode, data_id, data_channel, data }) => {
// return { mode, data_id, data_channel, data }
// },
// })
const emit = defineEmits(['filter-data'])
const channel = useChannelStore()
const fileView = useFileViewStore()
const VTModeModel = ref(10)
const slopModeModel = ref(20)
const simpleSelectModel: Ref<{ id: number; description: string } | Record<string, never>> = ref({})
const simpleOptions = ref([
{
id: 1,
description: 'V-T Mode',
},
{
id: 2,
description: '1st Order Differential',
},
{
id: 3,
description: 'Third option',
},
])
const filterData = function () {
console.log(VTModeModel.value)
const a = 0
console.log(a)
// switch(simpleSelectModel.value.id) {
// case 1:
// const return_data = { mode: 1, data_id: 166, data: { persentage: 0 } };
// case 2:
// const return_data = { mode: 2, data_id: 166, data: { persentage: 0 } };
// default:
// }
// console.log(return_data)
emit('filter-data', {
mode: simpleSelectModel.value.id,
data_id: fileView.filesSelected,
data_channel: [channel.xAxis.id, channel.yAxis.id],
data: { persentage: VTModeModel.value, window: slopModeModel.value },
})
}
defineExpose({
simpleSelectModel,
simpleOptions,
VTModeModel,
slopModeModel,
filterData,
})
</script>
<style lang=""></style>
@@ -1,31 +0,0 @@
<template>
<va-card class="">
<div class="h-200px">
<va-button @click="showModal">FILE</va-button>
<p>Meta: {{ fileView.filesSelected }}</p>
<p>X: {{ channel.xAxis }}</p>
<p>Y: {{ channel.yAxis }}</p>
<Suspense>
<FileModal ref="file_modal_ref"></FileModal>
</Suspense>
</div>
</va-card>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useChannelStore } from '@/stores/data-analysis/channel'
import { useFileViewStore } from '@/stores/data-analysis/file-view'
import FileModal from '@/components/data-analysis/FileModal.vue'
const channel = useChannelStore()
const fileView = useFileViewStore()
/* File Modal Handling */
let file_modal_ref = ref<InstanceType<typeof FileModal> | null>(null)
const showModal = function () {
file_modal_ref.value?.showModal()
}
defineExpose({ file_modal_ref, showModal })
</script>
-212
View File
@@ -1,212 +0,0 @@
<template>
<div>
<va-modal v-model="show" :fixed-layout="true" size="large" @before-open="initLoad">
<!-- File Container-->
<div class="h-[75vh] w-[50vw]">
<!-- Control Bar -->
<div class="d-flex align-center">
<va-input v-model="filter" placeholder="Filter..." class="mr-3" style="flex: 0 200px" clearable />
<va-checkbox v-model="isFilterCaseSensitive" class="mr-3" label="Case sensitive" />
<va-button-group class="mr-3">
<va-button @click="changeFileView('time')">Time</va-button>
<va-button @click="changeFileView('folder')">Folder</va-button>
<va-button @click="changeFileView('project')">Project</va-button>
</va-button-group>
<va-button-group>
<va-button @click="expandAll(true)">Expand</va-button>
<va-button @click="expandAll(false)">Close</va-button>
</va-button-group>
</div>
<!-- File Window-->
<div class="grid grid-cols-4 gap-6">
<!-- File View-->
<div class="h-full col-span-3">
<va-tree-view
v-model:checked="selectedNodes"
v-model:expanded="expanedNodes"
:nodes="treeNodes"
class="customizable-content"
:filter="filter"
:filter-method="customFilterMethod"
:track-by="'idType'"
:value-by="'idType'"
selectable
>
<template #content="node">
<div class="align-center">
<va-icon v-if="node.type === 'Folder' && node.expanded === false" class="fas fa-folder mr-2" />
<va-icon v-if="node.type === 'Folder' && node.expanded === true" class="fas fa-folder-open mr-2" />
<va-icon v-if="node.type === 'MetaFile'" class="fas fa-file mr-2" />
<template v-if="node.type !== 'MetaFile'">{{ node.name }}</template>
<template v-if="node.type === 'MetaFile'">
{{ node.name }}
</template>
</div>
</template>
</va-tree-view>
</div>
<!-- Channel & Group setting-->
<div class="h-full col-span-1">
<div>
X-Axis
<va-select v-model="channel.xAxis" :text-by="'name'" :options="options"></va-select>
</div>
<div>
Y-Axis
<va-select v-model="channel.yAxis" :text-by="'name'" :options="options"></va-select>
</div>
</div>
</div>
</div>
</va-modal>
</div>
</template>
<script setup lang="ts">
import { Ref, ref, computed, watch } from 'vue'
import { FileView, Project, MetaFile, Folder, Time } from '@/utils/file'
import configTable from '@/data/config-table/index'
import { useChannelStore } from '@/stores/data-analysis/channel'
import { useFileViewStore } from '@/stores/data-analysis/file-view'
// emit
const emit = defineEmits({
filesSelected: ({ metas, channel }) => {
return { metas, channel }
},
})
function emitFilesSelected(meta: string[], channel: { x: object; y: object }) {
emit('filesSelected', { meta, channel })
}
// filter function
const customFilterMethod = computed(() => {
return (node: Project | MetaFile, filterText: string) => {
// console.log('customFilterMethod', node, filterText, key, node.name.includes(filterText))
return node.name.includes(filterText)
}
})
// handling show modal
let show = ref(false)
const showModal = function () {
show.value = !show.value
}
// handling fileView
const fileViewStore = useFileViewStore()
const fileView = new FileView()
// handling tree-view
const filter = ref('')
const isFilterCaseSensitive = ref(false)
const selectedNodes: Ref<(never | string)[]> = ref([])
const expanedNodes: Ref<(never | string)[]> = ref([])
const treeNodes: Ref<(never | Project | Folder | Time | MetaFile)[]> = ref([])
const initLoad = async function () {
if (treeNodes.value.length === 0) {
await initLoadFileView()
initLoadNodes()
}
}
const initLoadFileView = async function () {
await fileView.appendChildren(1)
}
const initLoadNodes = function () {
const files = fileView.getChildren()
if (files.length > 0) {
treeNodes.value.push(...files)
expanedNodes.value.push(treeNodes.value[0].idType)
}
}
const reset = function () {
resetFileView()
resetNodes()
}
const resetFileView = function () {
fileView.reset()
}
const resetNodes = function () {
selectedNodes.value.length = 0
expanedNodes.value.length = 0
treeNodes.value.length = 0
}
// handling modal header
const changeFileView = async function (view: string) {
// reset fileView
fileView.changeView(view)
await fileView.appendChildren(1)
// reset treeNodes & expandedNodes & selectedNodes
treeNodes.value.length = 0
treeNodes.value.push(...fileView.getChildren())
expanedNodes.value.length = 0
expanedNodes.value.push(treeNodes.value[0].idType)
// selectedNodes.value.length = 0
}
const expandAll = function (expandOrNot: boolean) {
expanedNodes.value.length = 0
if (!expandOrNot) return
for (const node of treeNodes.value) {
expanedNodes.value.push(node.idType)
}
}
// handling channel options
const channel = useChannelStore()
let options: any[] = []
// watch selectedNodes to decide axis options
watch(selectedNodes, (newSelectedNodes, oldSelectedNodes) => {
// update fileViewStore.filesSelected
fileViewStore.filesSelected.length = 0
fileViewStore.filesSelected.push(...newSelectedNodes.filter((x) => x.includes('MetaFile')))
// 新的要filter掉舊的沒有的
const newNodes = newSelectedNodes.filter((x) => x.includes('MetaFile') && !oldSelectedNodes.includes(x))
const MetFileList = []
for (const node of newNodes) {
const meta = fileView.getMetaFile(node)
MetFileList.push(meta)
}
console.log('MetFileList', MetFileList)
if (MetFileList[0]) {
// console.log(MetFileList[0].device.library_name, MetFileList[0].parameter.MODE)
// console.log(configTable.getConfig(MetFileList[0].device.library_name))
const config = configTable.getModeConfig(MetFileList[0].device.library_name, MetFileList[0].parameter.MODE)
const channel = Object.values(config.channels)
const channelOptions = channel.map((v: any, idx) => {
v.id = idx
return v
})
console.log('channelOptions', channelOptions)
options.length = 0
options.push(...channelOptions)
}
})
defineExpose({
emitFilesSelected,
show,
showModal,
changeFileView,
expandAll,
reset,
initLoad,
treeNodes,
expanedNodes,
selectedNodes,
})
</script>
<style lang="scss"></style>
@@ -1,63 +0,0 @@
<template>
<div>
<va-card class="h-full">
<va-card-content class="h-full w-full">
<EChart ref="chart_ref" :option="option" :autoresize="true" :loading="loading" />
</va-card-content>
</va-card>
</div>
</template>
<script setup lang="ts">
import LineChart from '@/data/echart/composables/LineChart'
import { EChartsCoreOption } from 'echarts'
import { ref } from 'vue'
const loading = ref(false)
const { chart_ref, option } = LineChart()
const setOption = function (option: EChartsCoreOption) {
chart_ref.value?.setOption(option)
}
const appendData = function (seriesIndex: number, data: Array<number | string>) {
chart_ref.value?.appendData({
seriesIndex: seriesIndex,
data: data,
})
chart_ref.value?.resize()
}
const markLine = function (
seriesIndex: number,
markLineIndex: number,
header: string,
value: number | Array<number> | string,
) {
chart_ref.value?.setOption({
series: [
{
markLine: {
data: [{ name: header, yAxis: value }],
},
},
],
})
}
const startLoading = function () {
loading.value = true
}
const stopLoading = function () {
loading.value = false
}
defineExpose({
startLoading,
stopLoading,
setOption,
appendData,
markLine,
})
</script>
<style lang=""></style>
@@ -0,0 +1,196 @@
<template>
<div>
<div class="mt-2 mx-1 grid grid-cols-6 items-center">
<div>
<p>Unit ({{ unitObj.text }})</p>
</div>
<va-button-toggle
v-model="unitObj.text"
:options="unitOption"
@update:model-value="changeUnit"
></va-button-toggle>
</div>
<va-divider />
<div class="mt-2 mx-1 grid grid-cols-6 items-center">
<div class="col-span-1">
<p>Space</p>
</div>
<va-input
v-model="leftBoundryInput"
:label="axis === 'x' ? 'Left' : 'Bottom'"
placeholder="10%"
class="col-span-2"
@keyup.enter="setBoundry"
@blur="setBoundry"
/>
<va-input
v-model="rightBoundryInput"
:label="axis === 'x' ? 'Right' : 'Top'"
placeholder="10%"
class="px-1 col-span-2"
@keyup.enter="setBoundry"
@blur="setBoundry"
/>
<div class="mx-2 col-span-1 justify-self-end">
<button @click="resetBoundry">Reset</button>
</div>
</div>
<va-divider />
<div class="mt-2 mx-1 grid grid-cols-6 items-center">
<div class="col-span-1">
<p>Fixed</p>
</div>
<va-input
v-model="minInput"
class="col-span-2"
label="Min"
@keyup.enter="setMin(minInput)"
@blur="setMin(minInput)"
>
<template #appendInner>{{ unitObj.text }}</template>
</va-input>
<va-input
v-model="maxInput"
class="px-1 col-span-2"
label="Max"
@keyup.enter="setMax(maxInput)"
@blur="setMax(maxInput)"
>
<template #appendInner>{{ unitObj.text }}</template>
</va-input>
<div class="mx-2 col-span-1 justify-self-end">
<button small @click="resetMinMax">Reset</button>
</div>
</div>
<va-divider />
<div class="mt-2 mx-1 grid grid-cols-6 items-center">
<div>
<p>Interval</p>
</div>
<va-input
v-model="intervalInput"
class="col-span-2"
@keyup.enter="setInterval(Number(intervalInput))"
@blur="setInterval(Number(intervalInput))"
>
<template #appendInner>{{ unitObj.text }}</template>
</va-input>
<div class="mx-2 col-span-3 justify-self-end">
<button small @click="resetInterval">Reset</button>
</div>
</div>
<!-- <va-divider />
<div class="mt-2 mx-1 grid grid-cols-6 items-center">
<div>
<p>SplitLine</p>
</div>
<va-counter v-model="splitNumber" class="col-span-2" @update:model-value="setSplitNumber" />
</div> -->
</div>
<va-divider />
</template>
<script setup lang="ts">
import { ref, computed, toRef, defineProps } from 'vue'
import { XAxisManager } from '@/utils/chart/x-axis/xAxisManager'
import { YAxisManager } from '@/utils/chart/y-axis/yAxisManager'
/* init definition */
const props = defineProps<{
axis: string
axisManager: XAxisManager | YAxisManager
axisIndex: number
dataZoom: object
}>()
const axisManager = toRef(props, 'axisManager')
const dataZoom = toRef(props, 'dataZoom')
/** axis setting */
/* unit */
const unitObj = computed(() => axisManager.value.getUnit())
const unitOption = computed(() =>
Object.keys(unitObj.value.option).map((ele) => {
return { label: ele, value: ele }
}),
)
const changeUnit = function (_unit: string) {
/* caculate the ratio */
const oldScale = unitObj.value.scale
const newScale = unitObj.value.option[_unit]
const ratio = newScale / oldScale
/* correct the input value with ratio */
if (maxInput.value !== '') maxInput.value = String(Number(maxInput.value) / ratio)
if (minInput.value !== '') minInput.value = String(Number(minInput.value) / ratio)
if (intervalInput.value !== '') intervalInput.value = String(Number(intervalInput.value) / ratio)
/* change the scale */
unitObj.value.scale = unitObj.value.option[_unit]
}
/* boundry */
const leftBoundryInput = ref('')
const rightBoundryInput = ref('')
const setBoundry = function () {
if (leftBoundryInput.value === '') leftBoundryInput.value = '0'
if (rightBoundryInput.value === '') rightBoundryInput.value = '0'
axisManager.value.setBoundry([leftBoundryInput.value, rightBoundryInput.value])
dataZoom.value[0].disabled = true
}
const resetBoundry = function () {
leftBoundryInput.value = ''
rightBoundryInput.value = ''
axisManager.value.resetBoundry()
dataZoom.value[0].disabled = false
}
/* max & min */
const maxInput = ref('')
const minInput = ref('')
const setMax = function (max: string) {
if (max === '') return
/* adjust max with scale */
max = String(Number(max) * unitObj.value.scale)
/* set max */
axisManager.value.setMax(max)
dataZoom.value[0].disabled = true
}
const setMin = function (min: string) {
if (min === '') return
/* adjust min with scale */
min = String(Number(min) * unitObj.value.scale)
/* set min */
axisManager.value.setMin(min)
dataZoom.value[0].disabled = true
}
const resetMinMax = function () {
maxInput.value = ''
minInput.value = ''
axisManager.value.resetMinMax()
dataZoom.value[0].disabled = false
}
/* interval */
const intervalInput = ref('')
const setInterval = function (interval: number) {
if (interval <= 0) return
interval = Number(interval) * unitObj.value.scale
axisManager.value.setInterval(interval)
}
const resetInterval = function () {
intervalInput.value = ''
axisManager.value.resetInterval()
}
/* splitLine */
const splitNumber = ref(5)
const setSplitNumber = function (splitNumber: number) {
axisManager.value.setSplitNumber(splitNumber)
}
</script>
<style></style>
@@ -0,0 +1,46 @@
<template>
<slideout v-model="show" :show-mask="false" :arrow-button="false" :title="title" :size="'30%'" dock="left" resizable>
<div class="grid justify-items-center self-center text-lg">
<span>X-Axis</span>
</div>
<va-divider />
<AxisSetting
axis="x"
:axis-manager="chartStore.chartManager.children[chartIndex].xAxisManager"
:data-zoom="chartStore.chartManager.children[chartIndex].dataZoom"
:axis-index="0"
></AxisSetting>
<div class="grid justify-items-center self-center text-lg">
<span>Y-Axis</span>
</div>
<va-divider />
<AxisSetting
axis="y"
:axis-manager="chartStore.chartManager.children[chartIndex].yAxisManager"
:data-zoom="chartStore.chartManager.children[chartIndex].dataZoom"
:axis-index="0"
></AxisSetting>
</slideout>
</template>
<script setup lang="ts">
import AxisSetting from './AxisSetting.vue'
import { ref, computed } from 'vue'
import { useChartStore } from '@/stores/data-analysis/chart'
const title = 'Axis Settings'
const chartStore = useChartStore()
const chartIndex = ref(0)
/* slideout show */
const show = computed({
// getter
get() {
return chartStore.xAxisSlider
},
// setter
set(newValue) {
chartStore.xAxisSlider = newValue
},
})
</script>
@@ -0,0 +1,428 @@
<template>
<div class="">
<v-contextmenu ref="contextmenu">
<v-contextmenu-item @click="changeAxisPointer">pointer</v-contextmenu-item>
<v-contextmenu-item v-if="canvasInstance.format === 'line'" @click="changeFormat('scatter')"
>scatter</v-contextmenu-item
>
<v-contextmenu-item v-if="canvasInstance.format === 'scatter'" @click="changeFormat('line')"
>line</v-contextmenu-item
>
<v-contextmenu-item @click="deleteSelected">clear</v-contextmenu-item>
<v-contextmenu-item @click="download">download</v-contextmenu-item>
</v-contextmenu>
<va-card v-contextmenu:contextmenu class="h-full">
<va-card-content class="h-full">
<div style="position: relative" class="h-full">
<canvas
id="lineCanvas"
class="myCanvas"
:width="width"
:height="height"
style="position: absolute; top: 0; left: 0"
></canvas>
<canvas
id="scatterCanvas"
class="myCanvas displayNone"
:width="width"
:height="height"
style="position: absolute; top: 0; left: 0"
></canvas>
<canvas
id="axisCanvas"
class="myCanvas"
:width="width"
:height="height"
style="position: absolute; top: 0; left: 0"
></canvas>
</div>
</va-card-content>
</va-card>
</div>
</template>
<script setup lang="ts">
import { ref, watch, computed, onMounted } from 'vue'
import { useCanvasStore } from '@/stores/data-analysis/canvas'
import api from '@/data/server-api'
import { useToast } from 'vuestic-ui'
const { init } = useToast()
const canvasStore = useCanvasStore()
const { width, height, numTicks, innerWidth, innerHeight, start, end, xTickPixels, yTickPixels, x, y } =
canvasStore.canvas
// monitor screen height
const screenHeight = computed(() => canvasStore.canvas.screenHeight)
// monitor screen width
const screenWidth = computed(() => canvasStore.canvas.screenWidth)
// monitor screen inner height
const screenInnerHeight = computed(() => canvasStore.canvas.screenInnerHeight)
// monitor screen inner width
const screenInnerWidth = computed(() => canvasStore.canvas.screenInnerWidth)
// line or scatter
const format = computed(() => canvasStore.canvas.format)
// canvas instance
const canvasInstance = canvasStore.canvas
// show axis pointer
const showAxisPointer = ref(false)
let axisCanvas: HTMLCanvasElement
let axisCtx: CanvasRenderingContext2D
let lineCanvas: HTMLCanvasElement
let lineCtx: CanvasRenderingContext2D
let scatterCanvas: HTMLCanvasElement
let scatterCtx: CanvasRenderingContext2D
// show axis pointer or not
const changeAxisPointer = function () {
showAxisPointer.value = !showAxisPointer.value
reDraw()
}
// change line or scatter
const changeFormat = function (format: string) {
canvasInstance.format = format
}
// delect select rect
const deleteSelected = function () {
canvasInstance.resetSelected()
reDraw()
}
const download = function () {
// create combined canvas
const combinedCanvas = document.createElement('canvas')
const combinedCtx = combinedCanvas.getContext('2d')
// if the source canvas is exist
if (combinedCtx && lineCanvas && scatterCanvas) {
// define height & width
combinedCanvas.width = axisCanvas.width
combinedCanvas.height = axisCanvas.height
// make background white
combinedCtx.fillStyle = '#FFFFFF'
combinedCtx.fillRect(0, 0, combinedCanvas.width, combinedCanvas.height)
// draw axis
combinedCtx.drawImage(axisCanvas, 0, 0)
combinedCtx.globalCompositeOperation = 'multiply'
// draw line
if (format.value === 'line') combinedCtx.drawImage(lineCanvas, 0, 0)
// draw scatter
if (format.value === 'scatter') combinedCtx.drawImage(scatterCanvas, 0, 0)
// create download link
const link = document.createElement('a')
link.download = 'canvas.png'
link.href = combinedCanvas.toDataURL()
link.click()
}
}
// mouse down position
let mouseStartX = -1
let mouseStartY = -1
// mouse moving temp position
let mouseTempX = -1
let mouseTempY = -1
// mouse up position
let mouseEndX = -1
let mouseEndY = -1
// dragging flag
let isDragging = false
// color code
let colorIndex = 0
const generatorColor = function () {
const colorCode = [
'#054A91',
'#5FA8D3',
'#16697A',
'#2A9D8F',
'#746C68',
'#E9C46A',
'#F78514',
'#D14958',
'#4C4DC8',
'#9E2A2B',
'#F87575',
]
const ret = colorCode[colorIndex]
colorIndex = colorIndex === colorCode.length ? 0 : colorIndex + 1
return ret
}
const calcPositionX = function (xPos: number) {
const diffX = xPos - x.range[0]
let ratioX = Math.abs(diffX / (x.range[1] - x.range[0]))
if (ratioX > 1) ratioX = 1
return Math.trunc(ratioX * innerWidth) + start.x
}
const calcPositionY = function (yPoint: number) {
const diffY = y.range[1] - yPoint
let ratioY = Math.abs(diffY / (y.range[1] - y.range[0]))
if (ratioY > 1) ratioY = 1
return Math.trunc(ratioY * innerHeight) + end.y
}
const drawPoint = function (posX: number, posY: number, color: string, ctx: CanvasRenderingContext2D) {
// draw circle & fill color
ctx.beginPath()
ctx.arc(posX, posY, 2, 0, 2 * Math.PI)
ctx.fillStyle = color
ctx.fill()
}
// Helper function to draw the x axis with tick marks
function drawXAxis(xMin: number, xMax: number, tickPixels: number[], ctx: CanvasRenderingContext2D) {
// draw axis line
ctx.beginPath()
ctx.moveTo(start.x, start.y)
ctx.lineTo(end.x, start.y)
ctx.fillStyle = 'black'
ctx.lineWidth = 1
ctx.font = '40px sans-serif'
ctx.textAlign = 'center'
// draw axis tickle
for (let i = 0; i < tickPixels.length; i++) {
const x = tickPixels[i]
ctx.moveTo(start.x + x, start.y)
ctx.lineTo(start.x + x, start.y + 15)
const text = canvasInstance.getXText(xMin + (i / numTicks) * (xMax - xMin))
ctx.fillText(text, start.x + x, start.y + 75)
}
ctx.strokeStyle = 'black'
ctx.stroke()
}
function drawYAxis(yMin: number, yMax: number, tickPixels: number[], ctx: CanvasRenderingContext2D) {
// draw axis line
ctx.beginPath()
ctx.moveTo(start.x, start.y)
ctx.lineTo(start.x, end.y)
ctx.fillStyle = 'black'
ctx.font = '40px sans-serif'
ctx.textAlign = 'right'
ctx.lineWidth = 1
// draw axis tickle
for (let i = 0; i < tickPixels.length; i++) {
const y = tickPixels[i]
ctx.moveTo(start.x, start.y - y)
ctx.lineTo(start.x - 25, start.y - y)
const text = canvasInstance.getYText(yMin + (i / numTicks) * (yMax - yMin))
ctx.fillText(text, start.x - 30, start.y - y + 15)
}
ctx.strokeStyle = 'black'
ctx.stroke()
}
const drawXAxisPointer = function (mouseX: number, ctx: CanvasRenderingContext2D) {
const x = (mouseX * width) / screenWidth.value
ctx.moveTo(x, start.y)
ctx.lineTo(x, end.y)
ctx.strokeStyle = 'black'
ctx.stroke()
const value = canvasInstance.mouseXToValue(mouseX)
const text = canvasInstance.getXText(value)
ctx.textAlign = 'center'
ctx.fillText(text, x, start.y + 50)
}
const drawYAxisPointer = function (mouseY: number, ctx: CanvasRenderingContext2D) {
const y = (mouseY * height) / screenHeight.value
ctx.moveTo(start.x, y)
ctx.lineTo(end.x, y)
ctx.strokeStyle = 'black'
ctx.stroke()
const value = canvasInstance.mouseYToValue(mouseY)
const text = canvasInstance.getYText(value)
ctx.textAlign = 'right'
ctx.fillText(text, start.x, y)
}
const drawInputData = function (x: string | any[], y: number[]) {
const color = generatorColor()
// draw line
lineCtx.beginPath()
lineCtx.moveTo(calcPositionX(x[0]), calcPositionY(y[0]))
for (let i = 0; i < x.length; i++) {
const X = calcPositionX(x[i])
const Y = calcPositionY(y[i])
lineCtx.lineTo(X, Y)
// draw point
drawPoint(X, Y, color, scatterCtx)
}
lineCtx.lineWidth = 2
lineCtx.strokeStyle = color
lineCtx.stroke()
}
const generateAxis = function () {
drawXAxis(Number(x.range[0]), Number(x.range[1]), xTickPixels, axisCtx)
drawYAxis(Number(y.range[0]), Number(y.range[1]), yTickPixels, axisCtx)
}
const resetCanvas = function () {
axisCtx.clearRect(0, 0, width, height)
lineCtx?.clearRect(0, 0, width, height)
scatterCtx?.clearRect(0, 0, width, height)
}
const outOfBoundry = function (mouseX: number, mouseY: number) {
if (mouseX < canvasInstance.getBoundryInScreen(3) || mouseX > canvasInstance.getBoundryInScreen(1)) return true
if (mouseY < canvasInstance.getBoundryInScreen(0) || mouseY > canvasInstance.getBoundryInScreen(2)) return true
return false
}
const reDraw = function () {
const rect = axisCanvas.getBoundingClientRect()
// Clear the canvas
axisCtx.clearRect(0, 0, width, height)
// Draw the x and y axes with tick marks
generateAxis()
// Draw the x and y axis pointers
if (showAxisPointer.value === true) {
drawXAxisPointer(mouseTempX, axisCtx)
drawYAxisPointer(mouseTempY, axisCtx)
}
for (const selectionRect of canvasInstance.selectedSave) {
axisCtx.lineWidth = 5
axisCtx.strokeRect(
(selectionRect[0] / rect.width) * width,
(selectionRect[1] / rect.height) * height,
((selectionRect[2] - selectionRect[0]) / rect.width) * width,
((selectionRect[3] - selectionRect[1]) / rect.height) * height,
)
}
if (isDragging || (mouseEndX !== -1 && mouseEndY !== -1)) {
if (isDragging === true) {
mouseEndX = mouseTempX
mouseEndY = mouseTempY
}
axisCtx.lineWidth = 5
axisCtx.strokeRect(
(mouseStartX / rect.width) * width,
(mouseStartY / rect.height) * height,
((mouseEndX - mouseStartX) / rect.width) * width,
((mouseEndY - mouseStartY) / rect.height) * height,
)
}
}
onMounted(() => {
axisCanvas = document.getElementById('axisCanvas') as HTMLCanvasElement
axisCtx = axisCanvas?.getContext('2d')
lineCanvas = document.getElementById('lineCanvas') as HTMLCanvasElement
lineCtx = lineCanvas?.getContext('2d')
scatterCanvas = document.getElementById('scatterCanvas') as HTMLCanvasElement
scatterCtx = scatterCanvas?.getContext('2d')
const rect = axisCanvas?.getBoundingClientRect()
if (rect) {
canvasInstance.setScreenSize(rect.width, rect.height)
}
// resize
window.addEventListener('resize', () => {
const rect = axisCanvas?.getBoundingClientRect()
if (rect) canvasInstance.setScreenSize(rect.width, rect.height)
})
// listen for mouse down event
axisCanvas?.addEventListener('mousedown', (event) => {
if (event.button === 0) {
const rect = axisCanvas.getBoundingClientRect()
// reset mouse up
mouseEndX = -1
mouseEndY = -1
// set starting coordinates of square
mouseStartX = event.clientX - rect.left
mouseStartY = event.clientY - rect.top
if (outOfBoundry(mouseStartX, mouseStartY) === true) return
isDragging = true
}
})
// listen for mouse up event
axisCanvas?.addEventListener('mouseup', async () => {
const rect = axisCanvas.getBoundingClientRect()
if (mouseEndX === -1 || mouseEndY === -1) return
canvasInstance.selectedSave.push([mouseStartX, mouseStartY, mouseEndX, mouseEndY])
// update ending coordinates of square
const dataStartX =
((mouseStartX - rect.width * 0.1) * (x.range[1] - x.range[0])) / screenInnerWidth.value + Number(x.range[0])
const dataEndX =
((mouseEndX - rect.width * 0.1) * (x.range[1] - x.range[0])) / screenInnerWidth.value + Number(x.range[0])
const dataStartY =
((rect.height - mouseStartY - rect.height * 0.1) * (y.range[1] - y.range[0])) / screenInnerHeight.value +
Number(y.range[0])
const dataEndY =
((rect.height - mouseEndY - rect.height * 0.1) * (y.range[1] - y.range[0])) / screenInnerHeight.value +
Number(y.range[0])
const xInfo = [canvasInstance.x.channel.id, dataStartX, dataEndX]
const yInfo = [canvasInstance.y.channel.id, dataStartY, dataEndY]
const ret = await api.meta.findMeta(canvasStore.canvas.metaIds, [xInfo, yInfo])
console.log('ret', ret)
for (const mes of ret.data) {
init(mes[1])
}
// reset mouse position
mouseStartX = mouseStartY = mouseEndX = mouseEndY = -1
// reset isDraggable flag
isDragging = false
})
axisCanvas?.addEventListener('mousemove', function (event) {
const rect = axisCanvas.getBoundingClientRect()
// get mouse current pos
mouseTempX = event.clientX - rect.left
mouseTempY = event.clientY - rect.top
if (outOfBoundry(mouseTempX, mouseTempY) === true) return
reDraw()
})
})
watch(format, (newVal: string) => {
if (newVal === 'line') {
lineCanvas?.classList.remove('displayNone')
scatterCanvas?.classList.add('displayNone')
}
if (newVal === 'scatter') {
lineCanvas?.classList.add('displayNone')
scatterCanvas?.classList.remove('displayNone')
}
})
defineExpose({ reDraw, generateAxis, drawInputData, resetCanvas })
</script>
<style>
.myCanvas {
width: 100%;
height: 100%;
}
.displayNone {
display: none;
}
</style>
@@ -0,0 +1,106 @@
<template>
<div>
<va-card class="h-full">
<va-card-content class="h-full w-full">
<EChart ref="chart_ref" :option="chart" :autoresize="true" :loading="loading" />
</va-card-content>
</va-card>
<AxisSettingSlider></AxisSettingSlider>
</div>
</template>
<script setup lang="ts">
import { ECharts, EChartsCoreOption } from 'echarts'
import { ref, onMounted } from 'vue'
import { useChartStore } from '@/stores/data-analysis/chart'
import { useCanvasStore } from '@/stores/data-analysis/canvas'
import AxisSettingSlider from './AxisSettingSlider.vue'
import Chart from '@/utils/chart/chart'
const chartStore = useChartStore()
const canvasStore = useCanvasStore()
const chartIndex = 0
interface Props {
chart: Chart
}
const props = defineProps<Props>()
const chart_ref = ref<ECharts | null>(null)
const setOption = function (option: EChartsCoreOption, notMerge = false) {
chart_ref.value?.setOption(option, notMerge)
}
const appendData = function (seriesIndex: number, data: Array<number | string>) {
if (data.length <= 5e4) {
chartStore.chartManager.children[chartIndex].series[seriesIndex].data.push(...data)
} else {
for (const _data of data) {
chartStore.chartManager.children[chartIndex].series[seriesIndex].data.push(_data)
}
}
// chart_ref.value?.appendData({
// seriesIndex: seriesIndex,
// data: data,
// })
// chart_ref.value?.resize()
setTimeout(() => {
const chartXRange = chart_ref.value.chart.getModel().getComponent('xAxis').axis.scale._extent
const chartYRange = chart_ref.value.chart.getModel().getComponent('yAxis').axis.scale._extent
canvasStore.canvas.x.range = chartXRange.map((val: number) => String(val))
canvasStore.canvas.y.range = chartYRange.map((val: number) => String(val))
})
}
const markLine = function (value: number | Array<number> | string, seriesIndex = 0) {
chartStore.chartManager.children[chartIndex].series[seriesIndex].markLine.data = value
// chart_ref.value?.setOption({
// series: [
// {
// markLine: {
// data: [{ name: header, yAxis: value }],
// },
// },
// ],
// })
}
/* refresh */
const reset = function () {
setOption({}, true)
}
/* Loading */
const loading = ref(false)
const startLoading = function () {
loading.value = true
}
const stopLoading = function () {
loading.value = false
}
onMounted(() => {
const newTool = {
show: true,
title: 'custom icon1',
icon: 'path://M432.45,595.444c0,2.177-4.661,6.82-11.305,6.82c-6.475,0-11.306-4.567-11.306-6.82s4.852-6.812,11.306-6.812C427.841,588.632,432.452,593.191,432.45,595.444L432.45,595.444z M421.155,589.876c-3.009,0-5.448,2.495-5.448,5.572s2.439,5.572,5.448,5.572c3.01,0,5.449-2.495,5.449-5.572C426.604,592.371,424.165,589.876,421.155,589.876L421.155,589.876z M421.146,591.891c-1.916,0-3.47,1.589-3.47,3.549c0,1.959,1.554,3.548,3.47,3.548s3.469-1.589,3.469-3.548C424.614,593.479,423.062,591.891,421.146,591.891L421.146,591.891zM421.146,591.891',
onclick: function () {
chartStore.xAxisSlider = !chartStore.xAxisSlider
},
}
for (const chart of chartStore.chartManager.children) {
chart.toolbox.feature['myTool1'] = newTool
}
})
defineExpose({
startLoading,
stopLoading,
setOption,
appendData,
markLine,
reset,
})
</script>
<style lang=""></style>
@@ -0,0 +1,54 @@
<template>
<div>
<div>
X-Axis
<va-select
v-model="channelStore.xAxisSelected"
:text-by="'name'"
:options="xOption"
:no-options-text="'Select a file first.'"
></va-select>
</div>
<div>
Y-Axis
<va-select
v-model="channelStore.yAxisSelected"
:text-by="'name'"
:options="yOption"
:no-options-text="'Select a file first.'"
></va-select>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, watch } from 'vue'
import { useChannelStore } from '@/stores/data-analysis/channel'
const channelStore = useChannelStore()
const xOption = computed(() => channelStore.xAxisOptions)
const yOption = computed(() => channelStore.yAxisOptions)
watch(
xOption,
() => {
if (Object.keys(channelStore.xAxisSelected).length === 0) {
channelStore.xAxisSelected = xOption.value[1]
}
},
{
deep: true,
},
)
watch(
yOption,
() => {
if (Object.keys(channelStore.yAxisSelected).length === 0) {
channelStore.yAxisSelected = yOption.value[2]
}
},
{
deep: true,
},
)
</script>
@@ -0,0 +1,44 @@
<template>
<va-card>
<va-card-content>
<va-button @click="showModal">FILE</va-button>
<p>X: {{ channelStore.xAxisSelected.name }} Y: {{ channelStore.yAxisSelected.name }}</p>
<va-list class="py-2" fit>
<va-list-label> </va-list-label>
<template v-for="(file, i) in selectedFiles" :key="'item' + file.id">
<va-list-item>
<va-list-item-section>
<va-list-item-label>
{{ file.name }}
</va-list-item-label>
</va-list-item-section>
</va-list-item>
<va-list-separator v-if="i < selectedFiles.length - 1" :key="'separator' + i" class="my-1" fit />
</template>
</va-list>
<Suspense>
<FileSlide ref="file_modal_ref"></FileSlide>
</Suspense>
</va-card-content>
</va-card>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { useChannelStore } from '@/stores/data-analysis/channel'
import { useFileViewStore } from '@/stores/data-analysis/file-view'
import FileSlide from './FileSlider.vue'
const channelStore = useChannelStore()
const fileViewStore = useFileViewStore()
const selectedFiles = reactive(fileViewStore.selectedFiles)
/* File Modal Handling */
const file_modal_ref = ref<InstanceType<typeof FileSlide> | null>(null)
const showModal = function () {
file_modal_ref.value?.showModal()
}
defineExpose({ file_modal_ref, showModal })
</script>
@@ -0,0 +1,147 @@
<template>
<slideout v-model="showSlideOut" title="The title" :size="'120%'" dock="left" resizable>
<ChannelSelector></ChannelSelector>
<div class="pa-1 d-flex align-center">
<va-button-group class="mr-1">
<va-button @click="changeViewFormat(0)">Table</va-button>
<va-button disabled @click="changeViewFormat(1)">Tree</va-button>
</va-button-group>
<va-button-group class="mr-3">
<va-button @click="changeFileView('time')">Time</va-button>
<va-button @click="changeFileView('folder')">Folder</va-button>
<va-button @click="changeFileView('project')">Project</va-button>
</va-button-group>
<va-button-group>
<va-button @click="expandAll(true)">Expand</va-button>
<va-button @click="expandAll(false)">Close</va-button>
</va-button-group>
</div>
<va-inner-loading :loading="loading">
<div>
<TableFormat
v-if="viewFormat === 0"
ref="table_format_ref"
:columns="columns"
:rows="rows"
@on-select="onSelect"
></TableFormat>
<TreeFormat v-if="viewFormat === 1" ref="table_format_ref" :columns="columns" :rows="rows"></TreeFormat>
</div>
</va-inner-loading>
</slideout>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { useFileViewStore } from '@/stores/data-analysis/file-view'
import { useChannelStore } from '@/stores/data-analysis/channel'
import { MetaFile } from '@/utils/file'
import TableFormat from './TableFormat.vue'
import TreeFormat from './TreeFormat.vue'
import ChannelSelector from './ChannelSelector.vue'
import configTable from '@/data/config-table'
const table_format_ref = ref<InstanceType<typeof TableFormat> | null>(null)
const getWorkingMode = function (rowObj) {
if (rowObj.parameter) return configTable.getModeConfig(rowObj.parameter._LIBRARY_, rowObj.parameter.MODE).name
return
}
const getDate = function (rowObj) {
if (rowObj.created_at) {
return rowObj.created_at.replace('Z', '').replace('T', ' ')
}
return
}
const fileViewStore = useFileViewStore()
const channelStore = useChannelStore()
const fileView = reactive(fileViewStore.fileView)
const rows: any = fileView.children
const columns = reactive([
{
label: 'Name',
field: 'name',
},
{
label: 'Working Mode',
field: getWorkingMode,
},
{
label: 'TotalTime',
field: 'time',
type: 'number',
},
{
label: 'Size',
field: 'size',
type: 'number',
},
{
label: 'Created At',
field: getDate,
},
])
const loading = ref(true)
const showSlideOut = ref(false)
const showModal = function () {
showSlideOut.value = !showSlideOut.value
setTimeout(() => {
loading.value = false
}, 2000)
}
const viewFormat = ref(0)
const changeViewFormat = function (view: number) {
viewFormat.value = view
}
const changeFileView = async function (view: string) {
loading.value = true
fileView.changeView(view)
await fileView.appendChildren(1)
loading.value = false
}
const expandAll = function (expandOrNot: boolean) {
if (expandOrNot === true) table_format_ref.value?.expandAll()
if (expandOrNot === false) table_format_ref.value?.collapseAll()
}
const onSelect = function (selectedFile: MetaFile[]) {
fileViewStore.selectedFiles.length = 0
fileViewStore.selectedFiles.push(...selectedFile)
if (fileViewStore.selectedFiles.length > 0) {
// TODO get all selected library
const config: any = configTable.getModeConfig(
fileViewStore.selectedFiles[0].device.library_name,
fileViewStore.selectedFiles[0].parameter.MODE,
)
const channelKey = Object.keys(config.channels)
const channel = Object.values(config.channels)
const channelOptions = channel.map((v: any, idx) => {
v.id = channelKey[idx]
if (v.name === 'Time') {
v.id = 'Time'
}
return v
})
channelStore.xAxisOptions.length = 0
channelStore.xAxisOptions.push(...channelOptions)
channelStore.yAxisOptions.length = 0
channelStore.yAxisOptions.push(...channelOptions)
}
}
onMounted(() => {
fileView.appendChildren()
})
defineExpose({
showModal,
})
</script>
<style lang="scss"></style>
@@ -0,0 +1,64 @@
<template>
<VueGoodTable
ref="vue_good_table_refs"
:columns="columns"
:rows="rows"
:select-options="{ enabled: true, selectAllByGroup: true }"
:search-options="{ enabled: true }"
:group-options="{
enabled: true,
collapsable: true,
rowKey: 'id',
}"
@selected-rows-change="select"
>
</VueGoodTable>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { MetaFile } from '@/utils/file'
// emit
const emit = defineEmits(['onSelect'])
// props
defineProps({
columns: {
type: Array,
default: () => {
return []
},
},
rows: {
type: Array,
default: () => {
return []
},
},
})
// ref
const vue_good_table_refs = ref()
const expandAll = function () {
vue_good_table_refs.value.expandAll()
}
const collapseAll = function () {
vue_good_table_refs.value.collapseAll()
}
const select = function (params: { selectedRows: MetaFile[] }) {
emit('onSelect', params.selectedRows)
}
onMounted(() => {
// Due to "vue_good_table" package error, need to fix group select by reassign function
vue_good_table_refs.value.toggleSelectGroup = function (event: { checked: any }, headerRow: { children: any[] }) {
headerRow.children.forEach((row: { [x: string]: any }) => {
row['vgtSelected'] = event.checked
})
}
})
defineExpose({ expandAll, collapseAll })
</script>
<style></style>
@@ -0,0 +1,55 @@
<template>
<va-tree-view
v-model:checked="selectedNodes"
v-model:expanded="expanedNodes"
:nodes="rows"
class="customizable-content"
:filter="filter"
:filter-method="customFilterMethod"
:track-by="'idType'"
:value-by="'idType'"
selectable
>
<template #content="node">
<div class="align-center">
<va-icon v-if="node.type === 'Folder' && node.expanded === false" class="fas fa-folder mr-2" />
<va-icon v-if="node.type === 'Folder' && node.expanded === true" class="fas fa-folder-open mr-2" />
<va-icon v-if="node.type === 'MetaFile'" class="fas fa-file mr-2" />
<template v-if="node.type !== 'MetaFile'">{{ node.name }}</template>
<template v-if="node.type === 'MetaFile'">
{{ node.name }}
</template>
</div>
</template>
</va-tree-view>
</template>
<script setup lang="ts">
import { Ref, ref, computed } from 'vue'
defineProps({
columns: {
type: Array,
default: () => {
return []
},
},
rows: {
type: Array,
default: () => {
return []
},
},
})
const filter = ref('')
const selectedNodes: Ref<(never | string)[]> = ref([])
const expanedNodes: Ref<(never | string)[]> = ref([])
// filter function
const customFilterMethod = computed(() => {
return (node: any, filterText: string) => {
// console.log('customFilterMethod', node, filterText, key, node.name.includes(filterText))
return node.name.includes(filterText)
}
})
</script>
@@ -0,0 +1,178 @@
<template>
<div>
<va-card class="h-full">
<va-card-content>
<va-switch
v-model="daSettingStore.batchMode"
class="mb-1"
size="small"
true-label="Batch Mode"
false-label="InterActive Mode"
></va-switch>
<va-select
v-model="simpleSelectModel"
class="my-1"
:label="'Filter Mode'"
text-by="description"
track-by="id"
:options="simpleOptions"
/>
<div class="my-2">
<div v-if="simpleSelectModel.id === 1">
<va-slider v-model="VTModeModel" label="percentage(%)" track-label-visible :min="0" :max="50" />
</div>
<div v-else-if="simpleSelectModel.id === 2">
<va-slider v-model="slopModeModel" label="1D window" track-label-visible :min="1" :max="50" />
</div>
<div v-else></div>
</div>
<div v-if="daSettingStore.batchMode" class="my-2">
<va-switch
v-model="lineOrScatter"
class="mb-1"
size="small"
true-label="Scatter"
false-label="Line"
></va-switch>
<div>
<h1>Fixed Boundry</h1>
<va-divider></va-divider>
<div class="my-1 grid grid-cols-12 items-center">
<span>x</span>
<va-input v-model="canvasStore.canvas.x.range[0]" class="col-span-5">
<template #appendInner> </template>
</va-input>
<br />
<va-input v-model="canvasStore.canvas.x.range[1]" class="col-span-5"></va-input>
</div>
<div class="my-1 grid grid-cols-12 items-center">
<span>y</span>
<va-input v-model="canvasStore.canvas.y.range[0]" class="col-span-5"></va-input>
<br />
<va-input v-model="canvasStore.canvas.y.range[1]" class="col-span-5"></va-input>
</div>
</div>
</div>
<div>
<va-button class="mt-2" @click="filterData">Start</va-button>
</div>
</va-card-content>
</va-card>
</div>
</template>
<script setup lang="ts">
import { useChannelStore } from '@/stores/data-analysis/channel'
import { useChartStore } from '@/stores/data-analysis/chart'
import { useCanvasStore } from '@/stores/data-analysis/canvas'
import { useDASettingStore } from '@/stores/data-analysis/data-analysis'
import { useFileViewStore } from '@/stores/data-analysis/file-view'
import { Ref, ref, computed } from 'vue'
const emit = defineEmits(['filter-data'])
// chart index
const chartIndex = 0
// create stores
const chartStore = useChartStore()
const channelStore = useChannelStore()
const fileView = useFileViewStore()
const canvasStore = useCanvasStore()
const daSettingStore = useDASettingStore()
// setting
const VTModeModel = ref(10)
const slopModeModel = ref(20)
const simpleOptions = ref([
{ id: 0, description: 'None' },
{
id: 1,
description: 'V-T Mode',
},
{
id: 2,
description: '1st Order Differential',
},
{
id: 3,
description: 'Third option',
},
])
const simpleSelectModel: Ref<{ id: number; description: string }> = ref(simpleOptions.value[0])
const lineOrScatter = ref(false)
// const xOption = computed(() => channelStore.xAxisOptions)
// const yOption = computed(() => channelStore.yAxisOptions)
/* Start */
const filterData = function () {
/* reset specify chart */
const chart = chartStore.chartManager.children[chartIndex]
chart.reset()
/* reset specify canvas */
canvasStore.canvas.reset()
canvasStore.canvas.format = lineOrScatter.value === false ? 'line' : 'scatter'
/* assign mode & library and create series*/
for (const meta of fileView.selectedFiles) {
/* append info to chart */
chart.addLibraryMode(meta.parameter._LIBRARY_, meta.parameter.MODE)
/* append series */
chart.seriesManager.addSeries({ id: meta.id, name: meta.name })
canvasStore.canvas.metaIds.push(meta.id)
}
/* set x-axis name */
chart.xAxisManager.setName(channelStore.xAxisSelected.name)
/* set y-axis name */
chart.yAxisManager.setName(channelStore.yAxisSelected.name)
/* set x-axis label */
chart.xAxisManager.setAxisLabel({
text: channelStore.xAxisSelected.defaultUnit,
scale: channelStore.xAxisSelected.unit[channelStore.xAxisSelected.defaultUnit],
option: channelStore.xAxisSelected.unit,
})
const xChannel = JSON.parse(JSON.stringify(channelStore.xAxisSelected))
canvasStore.canvas.x.channel = xChannel
canvasStore.canvas.x.selectUnit = xChannel.defaultUnit
canvasStore.canvas.x.unit = xChannel.unit
/* set y-axis label */
chart.yAxisManager.setAxisLabel({
text: channelStore.yAxisSelected.defaultUnit,
scale: channelStore.yAxisSelected.unit[channelStore.yAxisSelected.defaultUnit],
option: channelStore.yAxisSelected.unit,
})
const yChannel = JSON.parse(JSON.stringify(channelStore.yAxisSelected))
canvasStore.canvas.y.channel = yChannel
canvasStore.canvas.y.selectUnit = yChannel.defaultUnit
canvasStore.canvas.y.unit = yChannel.unit
emit('filter-data', {
pattern: {
id: simpleSelectModel.value.id,
name: simpleSelectModel.value.description,
parameter: { percentage: VTModeModel.value, window: slopModeModel.value },
},
data: {
id: fileView.selectedFiles.map((ele: any) => ele.id),
channel: [channelStore.xAxisSelected.id, channelStore.yAxisSelected.id],
},
})
}
defineExpose({
simpleSelectModel,
simpleOptions,
VTModeModel,
slopModeModel,
filterData,
})
</script>
<style lang=""></style>
+211 -211
View File
@@ -12,220 +12,220 @@ export default {
},
routes: [
{
name: 'dashboard',
displayName: 'menu.dashboard',
name: 'data-analysis',
displayName: 'Analysis',
meta: {
icon: 'vuestic-iconset-dashboard',
},
},
{
name: 'statistics',
displayName: 'menu.statistics',
meta: {
icon: 'vuestic-iconset-statistics',
},
disabled: true,
children: [
{
name: 'charts',
displayName: 'menu.charts',
},
{
name: 'progress-bars',
displayName: 'menu.progressBars',
},
],
},
{
name: 'forms',
displayName: 'menu.forms',
meta: {
icon: 'vuestic-iconset-forms',
},
disabled: true,
children: [
{
name: 'form-elements',
displayName: 'menu.formElements',
},
{
name: 'medium-editor',
displayName: 'menu.mediumEditor',
},
],
},
{
name: 'tables',
displayName: 'menu.tables',
meta: {
icon: 'vuestic-iconset-tables',
},
children: [
{
name: 'markup',
displayName: 'menu.markupTables',
},
// {
// name: 'data',
// displayName: 'menu.dataTables',
// },
],
},
{
name: 'ui',
displayName: 'menu.uiElements',
meta: {
icon: 'vuestic-iconset-ui-elements',
},
disabled: true,
children: [
{
name: 'buttons',
displayName: 'menu.buttons',
},
{
name: 'cards',
displayName: 'menu.cards',
},
{
name: 'chat',
displayName: 'menu.chat',
},
{
name: 'chips',
displayName: 'menu.chips',
},
{
name: 'collapses',
displayName: 'menu.collapses',
},
{
name: 'colors',
displayName: 'menu.colors',
},
// {
// name: 'color-pickers',
// displayName: 'menu.colorPickers',
// },
{
name: 'file-upload',
displayName: 'menu.fileUpload',
},
{
name: 'grid',
displayName: 'menu.grid',
},
{
name: 'icon-sets',
displayName: 'menu.icons',
children: [
{
displayName: 'concrete',
name: 'icon-set',
},
],
},
{
name: 'lists',
displayName: 'menu.lists',
},
{
name: 'modals',
displayName: 'menu.modals',
},
{
name: 'notifications',
displayName: 'menu.notifications',
},
{
name: 'popovers',
displayName: 'menu.popovers',
},
{
name: 'rating',
displayName: 'menu.rating',
},
{
name: 'sliders',
displayName: 'menu.sliders',
},
{
name: 'spacing',
displayName: 'menu.spacing',
},
{
name: 'spinners',
displayName: 'menu.spinners',
},
{
name: 'tabs',
displayName: 'menu.tabs',
},
// {
// name: "timelines",
// displayName: "menu.timelines",
// },
{
name: 'tree-view',
displayName: 'menu.treeView',
},
{
name: 'typography',
displayName: 'menu.typography',
},
],
},
{
name: 'maps',
displayName: 'menu.maps',
meta: {
icon: 'vuestic-iconset-maps',
},
disabled: true,
children: [
{
name: 'maplibre-maps',
displayName: 'menu.maplibre-maps',
},
{
name: 'yandex-maps',
displayName: 'menu.yandex-maps',
},
{
name: 'leaflet-maps',
displayName: 'menu.leaflet-maps',
},
{
name: 'bubble-maps',
displayName: 'menu.bubble-maps',
},
{
name: 'line-maps',
displayName: 'menu.line-maps',
},
],
},
{
name: 'pages',
displayName: 'menu.pages',
meta: {
icon: 'vuestic-iconset-files',
},
disabled: true,
children: [
{
name: 'login',
displayName: 'menu.login-singup',
},
{
name: '404-pages',
displayName: 'menu.404-pages',
},
{
name: 'faq',
displayName: 'menu.faq',
},
],
},
// {
// name: 'statistics',
// displayName: 'menu.statistics',
// meta: {
// icon: 'vuestic-iconset-statistics',
// },
// disabled: true,
// children: [
// {
// name: 'charts',
// displayName: 'menu.charts',
// },
// {
// name: 'progress-bars',
// displayName: 'menu.progressBars',
// },
// ],
// },
// {
// name: 'forms',
// displayName: 'menu.forms',
// meta: {
// icon: 'vuestic-iconset-forms',
// },
// disabled: true,
// children: [
// {
// name: 'form-elements',
// displayName: 'menu.formElements',
// },
// {
// name: 'medium-editor',
// displayName: 'menu.mediumEditor',
// },
// ],
// },
// {
// name: 'tables',
// displayName: 'menu.tables',
// meta: {
// icon: 'vuestic-iconset-tables',
// },
// children: [
// {
// name: 'markup',
// displayName: 'menu.markupTables',
// },
// // {
// // name: 'data',
// // displayName: 'menu.dataTables',
// // },
// ],
// },
// {
// name: 'ui',
// displayName: 'menu.uiElements',
// meta: {
// icon: 'vuestic-iconset-ui-elements',
// },
// disabled: true,
// children: [
// {
// name: 'buttons',
// displayName: 'menu.buttons',
// },
// {
// name: 'cards',
// displayName: 'menu.cards',
// },
// {
// name: 'chat',
// displayName: 'menu.chat',
// },
// {
// name: 'chips',
// displayName: 'menu.chips',
// },
// {
// name: 'collapses',
// displayName: 'menu.collapses',
// },
// {
// name: 'colors',
// displayName: 'menu.colors',
// },
// // {
// // name: 'color-pickers',
// // displayName: 'menu.colorPickers',
// // },
// {
// name: 'file-upload',
// displayName: 'menu.fileUpload',
// },
// {
// name: 'grid',
// displayName: 'menu.grid',
// },
// {
// name: 'icon-sets',
// displayName: 'menu.icons',
// children: [
// {
// displayName: 'concrete',
// name: 'icon-set',
// },
// ],
// },
// {
// name: 'lists',
// displayName: 'menu.lists',
// },
// {
// name: 'modals',
// displayName: 'menu.modals',
// },
// {
// name: 'notifications',
// displayName: 'menu.notifications',
// },
// {
// name: 'popovers',
// displayName: 'menu.popovers',
// },
// {
// name: 'rating',
// displayName: 'menu.rating',
// },
// {
// name: 'sliders',
// displayName: 'menu.sliders',
// },
// {
// name: 'spacing',
// displayName: 'menu.spacing',
// },
// {
// name: 'spinners',
// displayName: 'menu.spinners',
// },
// {
// name: 'tabs',
// displayName: 'menu.tabs',
// },
// // {
// // name: "timelines",
// // displayName: "menu.timelines",
// // },
// {
// name: 'tree-view',
// displayName: 'menu.treeView',
// },
// {
// name: 'typography',
// displayName: 'menu.typography',
// },
// ],
// },
// {
// name: 'maps',
// displayName: 'menu.maps',
// meta: {
// icon: 'vuestic-iconset-maps',
// },
// disabled: true,
// children: [
// {
// name: 'maplibre-maps',
// displayName: 'menu.maplibre-maps',
// },
// {
// name: 'yandex-maps',
// displayName: 'menu.yandex-maps',
// },
// {
// name: 'leaflet-maps',
// displayName: 'menu.leaflet-maps',
// },
// {
// name: 'bubble-maps',
// displayName: 'menu.bubble-maps',
// },
// {
// name: 'line-maps',
// displayName: 'menu.line-maps',
// },
// ],
// },
// {
// name: 'pages',
// displayName: 'menu.pages',
// meta: {
// icon: 'vuestic-iconset-files',
// },
// disabled: true,
// children: [
// {
// name: 'login',
// displayName: 'menu.login-singup',
// },
// {
// name: '404-pages',
// displayName: 'menu.404-pages',
// },
// {
// name: 'faq',
// displayName: 'menu.faq',
// },
// ],
// },
] as INavigationRoute[],
}
-46
View File
@@ -1,46 +0,0 @@
<template>
<component :is="chartComponent" ref="chart" class="va-chart" :chart-options="chartOptions" :chart-data="data" />
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import type { TChartOptions } from 'vue-chartjs/dist/types'
import { defaultConfig, chartTypesMap } from './vaChartConfigs'
import { TChartData } from '../../data/types'
const props = defineProps<{
data: TChartData
options?: TChartOptions<'line' | 'bar' | 'bubble' | 'doughnut' | 'pie'>
type: keyof typeof chartTypesMap
}>()
const chart = ref()
const chartComponent = computed(() => chartTypesMap[props.type])
const chartOptions = computed(() => ({
...defaultConfig,
...props.options,
}))
</script>
<style lang="scss">
.va-chart {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
> * {
height: 100%;
width: 100%;
}
canvas {
width: 100%;
height: auto;
min-height: 320px;
}
}
</style>
@@ -1,17 +0,0 @@
<template>
<Bar :chart-options="chartOptions" :chart-data="props.chartData" />
</template>
<script setup lang="ts">
import { Bar } from 'vue-chartjs'
import type { TChartOptions } from 'vue-chartjs/dist/types'
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, LinearScale, CategoryScale } from 'chart.js'
import { TBarChartData } from '../../../data/types'
ChartJS.register(Title, Tooltip, Legend, BarElement, LinearScale, CategoryScale)
const props = defineProps<{
chartData: TBarChartData
chartOptions?: TChartOptions<'bar'>
}>()
</script>
@@ -1,17 +0,0 @@
<template>
<Bubble :chart-options="chartOptions" :chart-data="props.chartData" />
</template>
<script setup lang="ts">
import { Bubble } from 'vue-chartjs'
import type { TChartOptions } from 'vue-chartjs/dist/types'
import { Chart as ChartJS, Title, Tooltip, Legend, PointElement, LinearScale } from 'chart.js'
import { TBubbleChartData } from '../../../data/types'
ChartJS.register(Title, Tooltip, Legend, PointElement, LinearScale)
const props = defineProps<{
chartData: TBubbleChartData
chartOptions?: TChartOptions<'bubble'>
}>()
</script>
@@ -1,17 +0,0 @@
<template>
<Doughnut :chart-options="chartOptions" :chart-data="props.chartData" />
</template>
<script setup lang="ts">
import { Doughnut } from 'vue-chartjs'
import type { TChartOptions } from 'vue-chartjs/dist/types'
import { Chart as ChartJS, Title, Tooltip, Legend, ArcElement, CategoryScale } from 'chart.js'
import { TDoughnutChartData } from '../../../data/types'
ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale)
const props = defineProps<{
chartData: TDoughnutChartData
chartOptions?: TChartOptions<'doughnut'>
}>()
</script>
@@ -1,26 +0,0 @@
<template>
<Bar :chart-options="{ ...chartOptions, ...horizontalBarOptions }" :chart-data="props.chartData" />
</template>
<script setup lang="ts">
import { Bar } from 'vue-chartjs'
import type { TChartOptions } from 'vue-chartjs/dist/types'
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, LinearScale, CategoryScale } from 'chart.js'
import { TBarChartData } from '../../../data/types'
ChartJS.register(Title, Tooltip, Legend, BarElement, LinearScale, CategoryScale)
const horizontalBarOptions = {
indexAxis: 'y' as 'x' | 'y',
elements: {
bar: {
borderWidth: 1,
},
},
}
const props = defineProps<{
chartData: TBarChartData
chartOptions?: TChartOptions<'bar'>
}>()
</script>
@@ -1,27 +0,0 @@
<template>
<Line :chart-options="chartOptions" :chart-data="props.chartData" />
</template>
<script setup lang="ts">
import { Line } from 'vue-chartjs'
import type { TChartOptions } from 'vue-chartjs/dist/types'
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
LineElement,
LinearScale,
PointElement,
CategoryScale,
Filler,
} from 'chart.js'
import { TLineChartData } from '../../../data/types'
ChartJS.register(Title, Tooltip, Legend, LineElement, LinearScale, PointElement, CategoryScale, Filler)
const props = defineProps<{
chartData: TLineChartData
chartOptions?: TChartOptions<'line'>
}>()
</script>
@@ -1,17 +0,0 @@
<template>
<Pie :chart-options="chartOptions" :chart-data="props.chartData" />
</template>
<script setup lang="ts">
import { Pie } from 'vue-chartjs'
import type { TChartOptions } from 'vue-chartjs/dist/types'
import { Chart as ChartJS, Title, Tooltip, Legend, ArcElement, CategoryScale } from 'chart.js'
import { TPieChartData } from '../../../data/types'
ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale)
const props = defineProps<{
chartData: TPieChartData
chartOptions?: TChartOptions<'pie'>
}>()
</script>
@@ -1,48 +0,0 @@
import { defineAsyncComponent } from 'vue'
export const defaultConfig = {
plugins: {
legend: {
position: 'bottom',
labels: {
font: {
color: '#34495e',
family: 'sans-serif',
size: 14,
},
usePointStyle: true,
},
},
tooltip: {
bodyFont: {
size: 14,
family: 'sans-serif',
},
boxPadding: 4,
},
},
datasets: {
line: {
fill: 'origin',
tension: 0.3,
borderColor: 'transparent',
},
bubble: {
borderColor: 'transparent',
},
bar: {
borderColor: 'transparent',
},
},
maintainAspectRatio: false,
animation: true,
}
export const chartTypesMap = {
pie: defineAsyncComponent(() => import('./chart-types/PieChart.vue')),
doughnut: defineAsyncComponent(() => import('./chart-types/DoughnutChart.vue')),
bubble: defineAsyncComponent(() => import('./chart-types/BubbleChart.vue')),
line: defineAsyncComponent(() => import('./chart-types/LineChart.vue')),
bar: defineAsyncComponent(() => import('./chart-types/BarChart.vue')),
'horizontal-bar': defineAsyncComponent(() => import('./chart-types/HorizontalBarChart.vue')),
}
@@ -1,189 +0,0 @@
<template>
<div ref="editorElement" class="va-medium-editor content">
<slot />
</div>
</template>
<script setup lang="ts">
import { ref, Ref, onMounted, onBeforeUnmount } from 'vue'
import MediumEditor from 'medium-editor'
const props = withDefaults(
defineProps<{
editorOptions?: {
buttonLabels: string
autoLink: boolean
toolbar: {
buttons: string[]
}
}
}>(),
{
editorOptions: () => ({
buttonLabels: 'fontawesome',
autoLink: true,
toolbar: {
buttons: ['bold', 'italic', 'underline', 'anchor', 'h1', 'h2', 'h3'],
},
}),
},
)
const emit = defineEmits<{
(e: 'initialized', editor: typeof MediumEditor): void
}>()
const editorElement: Ref<null | HTMLElement> = ref(null)
let editor: typeof MediumEditor | null = null
onMounted(() => {
if (!editorElement.value) {
return
}
editor = new MediumEditor(editorElement.value, props.editorOptions)
emit('initialized', editor)
})
onBeforeUnmount(() => {
if (editor) {
editor.destroy()
}
})
</script>
<style lang="scss">
@import 'medium-editor/src/sass/medium-editor';
@import 'variables';
$medium-editor-shadow: var(--va-box-shadow);
$medium-editor-background-color: var(--va-divider);
$medium-editor-text-color: var(--va-dark);
$medium-editor-active-background-color: var(--va-primary);
$medium-editor-active-text-color: var(--va-white);
.va-medium-editor {
margin-bottom: var(--va-medium-editor-margin-bottom);
min-width: var(--va-medium-editor-min-width);
max-width: var(--va-medium-editor-max-width);
&:focus {
outline: none;
}
&.content {
i {
font-style: italic;
}
}
}
// isn't a part of the .va-medium-editor, so can't be places inside it
.medium-editor-toolbar,
.medium-editor-toolbar-form,
.medium-editor-toolbar-actions,
.medium-editor-toolbar-anchor-preview {
box-shadow: $medium-editor-shadow;
background-color: $medium-editor-background-color;
border-radius: 1.5rem;
height: 44px;
line-height: 42px;
}
.medium-editor-toolbar-anchor-preview {
a {
padding: 0 2rem;
margin: 0;
line-height: 44px;
}
}
.medium-editor-toolbar {
box-shadow: $medium-editor-shadow;
.medium-editor-toolbar-actions {
overflow: hidden;
height: 44px;
}
.medium-editor-action {
margin: 0;
border: 0;
padding: 0.375rem 1rem;
height: 44px;
background-color: $medium-editor-background-color;
box-shadow: none;
border-radius: 0;
i {
color: $medium-editor-text-color;
}
&.medium-editor-button-active {
background-color: $medium-editor-active-background-color;
color: $medium-editor-active-text-color;
i {
color: $medium-editor-active-text-color;
}
}
}
& > .medium-editor-action:not(:last-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-right: 0;
}
& > .medium-editor-action + .medium-editor-action {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-left: 0;
}
}
.medium-editor-toolbar-form {
color: $medium-editor-text-color;
overflow: hidden;
a {
color: $medium-editor-text-color;
transform: translateY(1px);
}
input {
margin-left: 4px !important;
transform: translateY(-2px);
border-radius: 13px;
}
.medium-editor-toolbar-close {
margin-right: 1rem;
}
}
.medium-toolbar-arrow-under::after {
border-color: $medium-editor-background-color transparent transparent transparent;
top: 100%;
}
.medium-toolbar-arrow-over::before {
border-color: transparent transparent var(--va-primary) transparent;
}
.medium-editor-toolbar-anchor-preview {
// @include va-button($btn-padding-y-nrm, $btn-padding-x-nrm, $btn-font-size-nrm, $btn-line-height-nrm, $btn-border-radius-nrm);
.medium-editor-toolbar-anchor-preview {
margin: 0;
}
}
.medium-editor-anchor-preview {
max-width: 50%;
a {
color: $medium-editor-text-color;
text-decoration: none;
}
}
</style>
@@ -1,9 +0,0 @@
:root {
--va-medium-editor-margin-bottom: 2.25rem;
--va-medium-editor-min-width: 6rem;
--va-medium-editor-max-width: 600px;
/* Toolbar */
--va-medium-editor-toolbar-max-width: 90%;
--va-medium-editor-toolbar-box-shadow: none;
}
-243
View File
@@ -1,243 +0,0 @@
export default [
'Afghanistan',
'Albania',
'Algeria',
'American Samoa',
'Andorra',
'Angola',
'Anguilla',
'Antarctica',
'Antigua and Barbuda',
'Argentina',
'Armenia',
'Aruba',
'Australia',
'Austria',
'Azerbaijan',
'Bahamas',
'Bahrain',
'Bangladesh',
'Barbados',
'Belarus',
'Belgium',
'Belize',
'Benin',
'Bermuda',
'Bhutan',
'Bolivia',
'Bosnia and Herzegowina',
'Botswana',
'Bouvet Island',
'Brazil',
'British Indian Ocean Territory',
'Brunei Darussalam',
'Bulgaria',
'Burkina Faso',
'Burundi',
'Cambodia',
'Cameroon',
'Canada',
'Cape Verde',
'Cayman Islands',
'Central African Republic',
'Chad',
'Chile',
'China',
'Christmas Island',
'Cocos (Keeling) Islands',
'Colombia',
'Comoros',
'Congo',
'Congo, the Democratic Republic of the',
'Cook Islands',
'Costa Rica',
"Cote d'Ivoire",
'Croatia (Hrvatska)',
'Cuba',
'Cyprus',
'Czech Republic',
'Denmark',
'Djibouti',
'Dominica',
'Dominican Republic',
'East Timor',
'Ecuador',
'Egypt',
'El Salvador',
'Equatorial Guinea',
'Eritrea',
'Estonia',
'Ethiopia',
'Falkland Islands (Malvinas)',
'Faroe Islands',
'Fiji',
'Finland',
'France',
'France Metropolitan',
'French Guiana',
'French Polynesia',
'French Southern Territories',
'Gabon',
'Gambia',
'Georgia',
'Germany',
'Ghana',
'Gibraltar',
'Greece',
'Greenland',
'Grenada',
'Guadeloupe',
'Guam',
'Guatemala',
'Guinea',
'Guinea-Bissau',
'Guyana',
'Haiti',
'Heard and Mc Donald Islands',
'Holy See (Vatican City State)',
'Honduras',
'Hong Kong',
'Hungary',
'Iceland',
'India',
'Indonesia',
'Iran (Islamic Republic of)',
'Iraq',
'Ireland',
'Israel',
'Italy',
'Jamaica',
'Japan',
'Jordan',
'Kazakhstan',
'Kenya',
'Kiribati',
"Korea, Democratic People's Republic of",
'Korea, Republic of',
'Kuwait',
'Kyrgyzstan',
"Lao, People's Democratic Republic",
'Latvia',
'Lebanon',
'Lesotho',
'Liberia',
'Libyan Arab Jamahiriya',
'Liechtenstein',
'Lithuania',
'Luxembourg',
'Macau',
'Macedonia, The Former Yugoslav Republic of',
'Madagascar',
'Malawi',
'Malaysia',
'Maldives',
'Mali',
'Malta',
'Marshall Islands',
'Martinique',
'Mauritania',
'Mauritius',
'Mayotte',
'Mexico',
'Micronesia, Federated States of',
'Moldova, Republic of',
'Monaco',
'Mongolia',
'Montserrat',
'Morocco',
'Mozambique',
'Myanmar',
'Namibia',
'Nauru',
'Nepal',
'Netherlands',
'Netherlands Antilles',
'New Caledonia',
'New Zealand',
'Nicaragua',
'Niger',
'Nigeria',
'Niue',
'Norfolk Island',
'Northern Mariana Islands',
'Norway',
'Oman',
'Pakistan',
'Palau',
'Panama',
'Papua New Guinea',
'Paraguay',
'Peru',
'Philippines',
'Pitcairn',
'Poland',
'Portugal',
'Puerto Rico',
'Qatar',
'Reunion',
'Romania',
'Russian Federation',
'Rwanda',
'Saint Kitts and Nevis',
'Saint Lucia',
'Saint Vincent and the Grenadines',
'Samoa',
'San Marino',
'Sao Tome and Principe',
'Saudi Arabia',
'Senegal',
'Serbia',
'Seychelles',
'Sierra Leone',
'Singapore',
'Slovakia (Slovak Republic)',
'Slovenia',
'Solomon Islands',
'Somalia',
'South Africa',
'South Georgia and the South Sandwich Islands',
'Spain',
'Sri Lanka',
'St. Helena',
'St. Pierre and Miquelon',
'Sudan',
'Suriname',
'Svalbard and Jan Mayen Islands',
'Swaziland',
'Sweden',
'Switzerland',
'Syrian Arab Republic',
'Taiwan, Province of China',
'Tajikistan',
'Tanzania, United Republic of',
'United States of America',
'Thailand',
'Togo',
'Tokelau',
'Tonga',
'Trinidad and Tobago',
'Tunisia',
'Turkey',
'Turkmenistan',
'Turks and Caicos Islands',
'Tuvalu',
'Uganda',
'Ukraine',
'United Arab Emirates',
'United Kingdom',
'United States',
'United States Minor Outlying Islands',
'Uruguay',
'Uzbekistan',
'Vanuatu',
'Venezuela',
'Vietnam',
'Virgin Islands (British)',
'Virgin Islands (U.S.)',
'Wallis and Futuna Islands',
'Western Sahara',
'Yemen',
'Yugoslavia',
'Zambia',
'Zimbabwe',
]
-30
View File
@@ -1,30 +0,0 @@
import { TBarChartData } from '../types'
export const barChartData: TBarChartData = {
labels: [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
],
datasets: [
{
label: 'Last year',
backgroundColor: 'primary',
data: [50, 20, 12, 39, 10, 40, 39, 80, 40, 20, 12, 11],
},
{
label: 'Current year',
backgroundColor: 'info',
data: [50, 10, 22, 39, 15, 20, 85, 32, 60, 50, 20, 30],
},
],
}
-231
View File
@@ -1,231 +0,0 @@
import { TBubbleChartData } from '../types'
export const bubbleChartData: TBubbleChartData = {
datasets: [
{
label: 'USA',
backgroundColor: 'danger',
data: [
{
x: 23,
y: 25,
r: 15,
},
{
x: 40,
y: 10,
r: 10,
},
{
x: 30,
y: 22,
r: 30,
},
{
x: 7,
y: 43,
r: 40,
},
{
x: 23,
y: 27,
r: 12,
},
{
x: 20,
y: 15,
r: 11,
},
{
x: 7,
y: 10,
r: 35,
},
{
x: 10,
y: 20,
r: 40,
},
],
},
{
label: 'Russia',
backgroundColor: 'primary',
data: [
{
x: 0,
y: 30,
r: 15,
},
{
x: 20,
y: 20,
r: 20,
},
{
x: 15,
y: 15,
r: 50,
},
{
x: 31,
y: 46,
r: 30,
},
{
x: 20,
y: 14,
r: 25,
},
{
x: 34,
y: 17,
r: 30,
},
{
x: 44,
y: 44,
r: 10,
},
{
x: 39,
y: 25,
r: 35,
},
],
},
{
label: 'Canada',
backgroundColor: 'warning',
data: [
{
x: 10,
y: 30,
r: 45,
},
{
x: 10,
y: 50,
r: 20,
},
{
x: 5,
y: 5,
r: 30,
},
{
x: 40,
y: 30,
r: 20,
},
{
x: 33,
y: 15,
r: 18,
},
{
x: 40,
y: 20,
r: 40,
},
{
x: 33,
y: 33,
r: 40,
},
],
},
{
label: 'Belarus',
backgroundColor: 'info',
data: [
{
x: 35,
y: 30,
r: 45,
},
{
x: 25,
y: 40,
r: 35,
},
{
x: 5,
y: 5,
r: 30,
},
{
x: 5,
y: 20,
r: 40,
},
{
x: 10,
y: 40,
r: 15,
},
{
x: 3,
y: 10,
r: 10,
},
{
x: 15,
y: 40,
r: 40,
},
{
x: 7,
y: 15,
r: 10,
},
],
},
{
label: 'Ukraine',
backgroundColor: 'success',
data: [
{
x: 25,
y: 10,
r: 40,
},
{
x: 17,
y: 40,
r: 40,
},
{
x: 35,
y: 10,
r: 20,
},
{
x: 3,
y: 40,
r: 10,
},
{
x: 40,
y: 40,
r: 40,
},
{
x: 20,
y: 10,
r: 10,
},
{
x: 10,
y: 27,
r: 35,
},
{
x: 7,
y: 26,
r: 40,
},
],
},
],
}
@@ -1,35 +0,0 @@
import { computed, ref } from '@vue/reactivity'
import { watch } from 'vue'
import { useColors, useGlobalConfig } from 'vuestic-ui'
type chartColors = string | string[]
export function useChartColors(chartColors = [] as chartColors, alfa = 0.6) {
const { getGlobalConfig } = useGlobalConfig()
const { setHSLAColor, getColor } = useColors()
const generateHSLAColors = (colors: chartColors) =>
typeof colors === 'string'
? setHSLAColor(getColor(colors), { a: alfa })
: colors.map((color) => setHSLAColor(getColor(color), { a: alfa }))
const generateColors = (colors: chartColors) =>
typeof colors === 'string' ? getColor(colors) : colors.map((color) => getColor(color))
const generatedHSLAColors = ref(generateHSLAColors(chartColors))
const generatedColors = ref(generateColors(chartColors))
const theme = computed(() => getGlobalConfig().colors!)
watch(theme, () => {
generatedHSLAColors.value = generateHSLAColors(chartColors)
generatedColors.value = generateColors(chartColors)
})
return {
generateHSLAColors,
generateColors,
generatedColors,
generatedHSLAColors,
}
}
@@ -1,20 +0,0 @@
import { computed, ComputedRef } from '@vue/reactivity'
import { useChartColors } from './useChartColors'
import { TChartData } from '../../types'
export function useChartData<T extends TChartData>(data: T, alfa?: number): ComputedRef<T> {
const datasetsColors = data.datasets.map((dataset) => dataset.backgroundColor as string)
const datasetsThemesColors = datasetsColors.map(
(colors) => useChartColors(colors, alfa)[alfa ? 'generatedHSLAColors' : 'generatedColors'],
)
return computed(() => {
const datasets = data.datasets.map((dataset, idx) => ({
...dataset,
backgroundColor: datasetsThemesColors[idx].value,
}))
return { ...data, datasets } as T
})
}
-12
View File
@@ -1,12 +0,0 @@
import { TDoughnutChartData } from '../types'
export const doughnutChartData: TDoughnutChartData = {
labels: ['North America', 'South America', 'Australia'],
datasets: [
{
label: 'Population (millions)',
backgroundColor: ['danger', 'info', 'primary'],
data: [2478, 5267, 734],
},
],
}
-30
View File
@@ -1,30 +0,0 @@
import { TBarChartData } from '../types'
export const horizontalBarChartData: TBarChartData = {
labels: [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
],
datasets: [
{
label: 'Vuestic Satisfaction Score',
backgroundColor: 'primary',
data: [80, 90, 50, 70, 60, 90, 50, 90, 80, 40, 72, 93],
},
{
label: 'Bulma Satisfaction Score',
backgroundColor: 'danger',
data: [20, 30, 20, 40, 50, 40, 15, 60, 30, 20, 42, 53],
},
],
}
-6
View File
@@ -1,6 +0,0 @@
export { bubbleChartData } from './bubbleChartData'
export { doughnutChartData } from './doughnutChartData'
export { barChartData } from './barChartData'
export { horizontalBarChartData } from './horizontalBarChartData'
export { lineChartData } from './lineChartData'
export { pieChartData } from './pieChartData'
-44
View File
@@ -1,44 +0,0 @@
import { TLineChartData } from '../types'
const months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
]
const getSize = (minSize = 5) => Math.max(minSize, new Date().getMonth())
const size = getSize()
const generateValue = () => Math.floor(Math.random() * 100)
const generateArray = (length: number) => Array.from(Array(length), generateValue)
const generateYLabels = () => {
const flip = !!Math.floor(Math.random() * 2)
return flip ? ['Debit', 'Credit'] : ['Credit', 'Debit']
}
const yLabels = generateYLabels()
export const lineChartData: TLineChartData = {
labels: months.slice(0, size),
datasets: [
{
label: yLabels[0],
backgroundColor: 'primary',
data: generateArray(size),
},
{
label: yLabels[1],
backgroundColor: 'secondary',
data: generateArray(size),
},
],
}
-12
View File
@@ -1,12 +0,0 @@
import { TLineChartData } from '../types'
export const pieChartData: TLineChartData = {
labels: ['Africa', 'Asia', 'Europe'],
datasets: [
{
label: 'Population (millions)',
backgroundColor: ['primary', 'warning', 'danger'],
data: [2478, 5267, 734],
},
],
}
+1 -1
View File
@@ -1,5 +1,5 @@
import { TooltipComponentFormatterCallbackParams } from 'echarts'
export const generateFormatter = function (params: TooltipComponentFormatterCallbackParams): string {
export const generateFormatter = function (params: any): string {
return String(params[0].value)
}
File diff suppressed because it is too large Load Diff
-342
View File
@@ -1,342 +0,0 @@
import { computed, ComputedRef, Ref } from '@vue/reactivity'
import { useColors } from 'vuestic-ui'
type GeoBounds = {
bottom: number
left: number
right: number
top: number
}
export type PointGeoCoord = {
latitude: number
longitude: number
}
export type DataGeometry = {
geometry: {
type: string
coordinates: [number, number][]
}
}
export type CityItem = {
id?: string
title: string
country: string
latitude: number
longitude: number
svgPath: string
color: string
flights?: PointGeoCoord[]
}
const targetSVG =
'M9,0C4.029,0,0,4.029,0,9s4.029,9,9,9s9-4.029,9-9S13.971,0,9,0z M9,15.93 c-3.83,0-6.93-3.1-6.93-6.93S5.17,2.07,9,2.07s6.93,3.1,6.93,6.93S12.83,15.93,9,15.93 M12.5,9c0,1.933-1.567,3.5-3.5,3.5S5.5,10.933,5.5,9S7.067,5.5,9,5.5 S12.5,7.067,12.5,9z'
export const planeSVG =
'M19.671,8.11l-2.777,2.777l-3.837-0.861c0.362-0.505,0.916-1.683,0.464-2.135c-0.518-0.517-1.979,0.278-2.305,0.604l-0.913,0.913L7.614,8.804l-2.021,2.021l2.232,1.061l-0.082,0.082l1.701,1.701l0.688-0.687l3.164,1.504L9.571,18.21H6.413l-1.137,1.138l3.6,0.948l1.83,1.83l0.947,3.598l1.137-1.137V21.43l3.725-3.725l1.504,3.164l-0.687,0.687l1.702,1.701l0.081-0.081l1.062,2.231l2.02-2.02l-0.604-2.689l0.912-0.912c0.326-0.326,1.121-1.789,0.604-2.306c-0.452-0.452-1.63,0.101-2.135,0.464l-0.861-3.838l2.777-2.777c0.947-0.947,3.599-4.862,2.62-5.839C24.533,4.512,20.618,7.163,19.671,8.11z'
const london = {
id: 'london',
color: 'info',
svgPath: targetSVG,
title: 'London',
country: 'United Kingdom',
latitude: 51.5002,
longitude: -0.1262,
flights: [
{
latitude: 50.4422,
longitude: 30.5367,
},
{
latitude: 46.948,
longitude: 7.4481,
},
{
latitude: 59.3328,
longitude: 18.0645,
},
{
latitude: 40.4167,
longitude: -3.7033,
},
{
latitude: 46.0514,
longitude: 14.506,
},
{
latitude: 48.2116,
longitude: 17.1547,
},
{
latitude: 44.8048,
longitude: 20.4781,
},
{
latitude: 55.7558,
longitude: 37.6176,
},
{
latitude: 38.7072,
longitude: -9.1355,
},
{
latitude: 54.6896,
longitude: 25.2799,
},
{
latitude: 64.1353,
longitude: -21.8952,
},
{
latitude: 40.43,
longitude: -74.0,
},
],
}
const vilnius = {
id: 'vilnius',
color: 'info',
svgPath: targetSVG,
title: 'Vilnius',
country: 'Lithuania',
latitude: 54.6896,
longitude: 25.2799,
flights: [
{
latitude: 50.8371,
longitude: 4.3676,
},
{
latitude: 59.9138,
longitude: 10.7387,
},
{
latitude: 40.4167,
longitude: -3.7033,
},
{
latitude: 50.0878,
longitude: 14.4205,
},
{
latitude: 48.2116,
longitude: 17.1547,
},
{
latitude: 44.8048,
longitude: 20.4781,
},
{
latitude: 55.7558,
longitude: 37.6176,
},
{
latitude: 37.9792,
longitude: 23.7166,
},
{
latitude: 51.5002,
longitude: -0.1262,
},
{
latitude: 53.3441,
longitude: -6.2675,
},
],
}
const cities: CityItem[] = [
london,
vilnius,
{
svgPath: targetSVG,
color: 'info',
title: 'Brussels',
country: 'Belgium',
latitude: 50.8371,
longitude: 4.3676,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Prague',
country: 'Czech Republic',
latitude: 50.0878,
longitude: 14.4205,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Athens',
country: 'Greece',
latitude: 37.9792,
longitude: 23.7166,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Reykjavik',
country: 'Iceland',
latitude: 64.1353,
longitude: -21.8952,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Dublin',
country: 'Ireland',
latitude: 53.3441,
longitude: -6.2675,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Oslo',
country: 'Norway',
latitude: 59.9138,
longitude: 10.7387,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Lisbon',
country: 'Portugal',
latitude: 38.7072,
longitude: -9.1355,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Moscow',
country: 'Russia',
latitude: 55.7558,
longitude: 37.6176,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Belgrade',
country: 'Serbia',
latitude: 44.8048,
longitude: 20.4781,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Bratislava',
country: 'Slovakia',
latitude: 48.2116,
longitude: 17.1547,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Ljubljana',
country: 'Slovenia',
latitude: 46.0514,
longitude: 14.506,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Madrid',
country: 'Spain',
latitude: 40.4167,
longitude: -3.7033,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Stockholm',
country: 'Sweden',
latitude: 59.3328,
longitude: 18.0645,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Bern',
country: 'Switzerland',
latitude: 46.948,
longitude: 7.4481,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Kiev',
country: 'Ukraine',
latitude: 50.4422,
longitude: 30.5367,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Paris',
country: 'France',
latitude: 48.8567,
longitude: 2.351,
},
{
svgPath: targetSVG,
color: 'info',
title: 'New York',
country: 'United States of America',
latitude: 40.43,
longitude: -74,
},
]
export const lineMapData = {
cities,
mainCity: london.title,
homeCity: london.title,
}
export const useMapData = (data: Ref<CityItem[]>): ComputedRef<CityItem[]> => {
const { getColor } = useColors()
return computed(() =>
data.value.map((item) => ({
...item,
color: getColor(item.color),
})),
)
}
export const getGeoBounds = (item?: CityItem): GeoBounds | undefined => {
if (!item || !item.flights || !item.flights.length) {
return
}
const latitudes = [...item.flights.map(({ latitude }) => latitude), item.latitude]
const longitudes = [...item.flights.map(({ longitude }) => longitude), item.longitude]
return {
bottom: Math.min(...latitudes),
left: Math.min(...longitudes),
right: Math.max(...longitudes),
top: Math.max(...latitudes),
}
}
export const generateLineSeriesData = (item?: CityItem): DataGeometry[] | undefined => {
if (!item || !item.flights || !item.flights.length) {
return
}
return item.flights.map((point) => ({
geometry: {
type: 'LineString',
coordinates: [
[item.longitude, item.latitude],
[point.longitude, point.latitude],
],
},
}))
}
export const compareStrings = (first: string, second: string) => first.toLowerCase() === second.toLowerCase()
+30 -9
View File
@@ -7,9 +7,9 @@ const axios = getAxios()
const getMetaWithTypeFolder = async function (
parent: number,
offset: number,
limit: number,
order: Array<string>,
offset?: number,
limit?: number,
order?: Array<string>,
): Promise<AxiosResponse<any, any>> {
let url = `api/file/meta/get?type=${FOLDER_TYPE}&`
if (parent) url += `parent=${parent}&`
@@ -23,20 +23,40 @@ const getMetaWithTypeFolder = async function (
return result
}
const getMetaByTime = async function (time: string): Promise<AxiosResponse<any, any>> {
const url = `api/file/meta/get?time=${time}`
const getMetaByTime = async function (time: string, offset?: number, limit?: number): Promise<AxiosResponse<any, any>> {
let url = `api/file/meta/get?time=${time}`
if (offset !== undefined) url += `&offset=${offset}`
if (limit !== undefined) url += `&limit=${limit}`
// console.log('url', url)
const result = await axios.get(url)
return result
}
const getMetaGroupByTime = async function (): Promise<AxiosResponse<any, any>> {
const url = `api/file/meta/get?group=time`
const getMetaGroupByTime = async function (offset?: number, limit?: number): Promise<AxiosResponse<any, any>> {
let url = `api/file/meta/get?group=time`
if (offset !== undefined) url += `&offset=${offset}`
if (limit !== undefined) url += `&limit=${limit}`
const result = await axios.get(url)
return result
}
const getMetaByProject = async function (
uuid: string,
offset?: number,
limit?: number,
): Promise<AxiosResponse<any, any>> {
let url = `api/file/meta/get?type=project&project=${uuid}`
if (offset !== undefined) url += `&offset=${offset}`
if (limit !== undefined) url += `&limit=${limit}`
const result = await axios.get(url)
return result
}
const getMetaByProject = async function (uuid: string): Promise<AxiosResponse<any, any>> {
const url = `api/file/meta/get?type=project&project=${uuid}`
const findMeta = async function (id, range) {
let url = `api/file/meta/find?`
if (id !== undefined) url += `id=${JSON.stringify(id)}`
if (range !== undefined) url += `&range=${JSON.stringify(range)}`
const result = await axios.get(url)
return result
}
@@ -46,6 +66,7 @@ const meta = {
getMetaByTime,
getMetaByProject,
getMetaGroupByTime,
findMeta,
}
export default meta
-402
View File
@@ -1,402 +0,0 @@
[
{
"id": "5d3026a3a4c8c8f35689104b",
"name": "Mcguire Prince",
"email": "mcguireprince@glasstep.com",
"country": "Swaziland",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a3e1579c30d1703632",
"name": "Dean Jennings",
"email": "deanjennings@glasstep.com",
"country": "Korea (North)",
"starred": true,
"status": "rejected"
},
{
"id": "5d3026a38023a44a3b5e934d",
"name": "Cotton Weber",
"email": "cottonweber@glasstep.com",
"country": "Mozambique",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a31c6b23082419e5f4",
"name": "Osborne Foster",
"email": "osbornefoster@glasstep.com",
"country": "US Minor Outlying Islands",
"starred": true,
"status": "paid"
},
{
"id": "5d3026a3b2cca1fd45746dbf",
"name": "William Dillard",
"email": "williamdillard@glasstep.com",
"country": "Cayman Islands",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a3486badb41f9f18b5",
"name": "Anna Meyers",
"email": "annameyers@glasstep.com",
"country": "Viet Nam",
"starred": false,
"status": "paid"
},
{
"id": "5d3026a3c614901a53477e5c",
"name": "Ana Barrett",
"email": "anabarrett@glasstep.com",
"country": "Rwanda",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a3fcff2a76b73e6016",
"name": "Pam Ward",
"email": "pamward@glasstep.com",
"country": "Kuwait",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a3b54fc3e9a2570ce8",
"name": "Hannah Holloway",
"email": "hannahholloway@glasstep.com",
"country": "Gibraltar",
"starred": false,
"status": "paid"
},
{
"id": "5d3026a3e2303324ae9d823f",
"name": "Allison Cobb",
"email": "allisoncobb@glasstep.com",
"country": "East Timor",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a3f22a52e3706ed868",
"name": "Terrie Hawkins",
"email": "terriehawkins@glasstep.com",
"country": "Greenland",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a32bad267623e706ec",
"name": "Peck Ryan",
"email": "peckryan@glasstep.com",
"country": "Belgium",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a37a50452a85d01cbb",
"name": "Candace Powell",
"email": "candacepowell@glasstep.com",
"country": "Yugoslavia",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a3ce9f5acf20065037",
"name": "Wolfe Pitts",
"email": "wolfepitts@glasstep.com",
"country": "Bouvet Island",
"starred": true,
"status": "rejected"
},
{
"id": "5d3026a3e3a5afe09338eca5",
"name": "Marietta Robbins",
"email": "mariettarobbins@glasstep.com",
"country": "Martinique",
"starred": true,
"status": "paid"
},
{
"id": "5d3026a33fc3196e598bdc7b",
"name": "Michelle Wolfe",
"email": "michellewolfe@glasstep.com",
"country": "French Guiana",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a3364f517d8f5dbf16",
"name": "Katina Lindsay",
"email": "katinalindsay@glasstep.com",
"country": "Guyana",
"starred": true,
"status": "rejected"
},
{
"id": "5d3026a313dedc3cf25404ba",
"name": "Bridgett Lloyd",
"email": "bridgettlloyd@glasstep.com",
"country": "Niger",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a3a72281322b845f6a",
"name": "Letha Hamilton",
"email": "lethahamilton@glasstep.com",
"country": "Zimbabwe",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a3bd037e491b76f097",
"name": "Mcclain Doyle",
"email": "mcclaindoyle@glasstep.com",
"country": "Switzerland",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a36aa5b7fda077d6ef",
"name": "Giles Lucas",
"email": "gileslucas@glasstep.com",
"country": "Bhutan",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a381c974954ce9ab94",
"name": "Figueroa Lowery",
"email": "figueroalowery@glasstep.com",
"country": "Netherlands Antilles",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a3c0af2698fcd2a750",
"name": "Valeria Justice",
"email": "valeriajustice@glasstep.com",
"country": "Moldova",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a301d5e7c957e6d864",
"name": "Louise Ayala",
"email": "louiseayala@glasstep.com",
"country": "India",
"starred": true,
"status": "rejected"
},
{
"id": "5d3026a31f6f1fd6399aeee6",
"name": "Kathrine Kirby",
"email": "kathrinekirby@glasstep.com",
"country": "Cook Islands",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a3e8cb16cd2afa41dd",
"name": "Brandi Morris",
"email": "brandimorris@glasstep.com",
"country": "Honduras",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a3c52ac7ffb85c892d",
"name": "Margaret Mckenzie",
"email": "margaretmckenzie@glasstep.com",
"country": "Jordan",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a3c66670f258790358",
"name": "Janie Collier",
"email": "janiecollier@glasstep.com",
"country": "Samoa",
"starred": true,
"status": "rejected"
},
{
"id": "5d3026a3108b6b1d543fb117",
"name": "Catherine Vance",
"email": "catherinevance@glasstep.com",
"country": "Sierra Leone",
"starred": false,
"status": "paid"
},
{
"id": "5d3026a325d727b6d9b85d84",
"name": "Kate Allen",
"email": "kateallen@glasstep.com",
"country": "France",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a32be6debb7532cc75",
"name": "Jeanne Cross",
"email": "jeannecross@glasstep.com",
"country": "Anguilla",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a3cc16b4cd36e3a7b4",
"name": "Stewart Hanson",
"email": "stewarthanson@glasstep.com",
"country": "Western Sahara",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a3d3496dd200d5f6af",
"name": "Beulah Castaneda",
"email": "beulahcastaneda@glasstep.com",
"country": "Malaysia",
"starred": true,
"status": "rejected"
},
{
"id": "5d3026a3187e74fcd18a7918",
"name": "Carissa Taylor",
"email": "carissataylor@glasstep.com",
"country": "Burkina Faso",
"starred": false,
"status": "paid"
},
{
"id": "5d3026a32db20d8ce9111367",
"name": "Muriel Butler",
"email": "murielbutler@glasstep.com",
"country": "Pitcairn",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a35b04715a89693024",
"name": "Janna Anthony",
"email": "jannaanthony@glasstep.com",
"country": "Nigeria",
"starred": false,
"status": "paid"
},
{
"id": "5d3026a3a40b0f908cf0b831",
"name": "Cortez Singleton",
"email": "cortezsingleton@glasstep.com",
"country": "Morocco",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a30ab099fe57fe76ad",
"name": "Acevedo Blevins",
"email": "acevedoblevins@glasstep.com",
"country": "Turkmenistan",
"starred": false,
"status": "paid"
},
{
"id": "5d3026a39f9244d7f7d7fe80",
"name": "Hamilton Lewis",
"email": "hamiltonlewis@glasstep.com",
"country": "Marshall Islands",
"starred": true,
"status": "paid"
},
{
"id": "5d3026a3637724139b82f9bc",
"name": "Marylou Wright",
"email": "marylouwright@glasstep.com",
"country": "Iraq",
"starred": true,
"status": "paid"
},
{
"id": "5d3026a3e5cda49e94e1f0de",
"name": "Lenore Bullock",
"email": "lenorebullock@glasstep.com",
"country": "El Salvador",
"starred": true,
"status": "paid"
},
{
"id": "5d3026a30bcb1168afa7bb26",
"name": "Enid Stephens",
"email": "enidstephens@glasstep.com",
"country": "Greece",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a34b33074f1ee12e73",
"name": "Oneill Joyner",
"email": "oneilljoyner@glasstep.com",
"country": "Micronesia",
"starred": false,
"status": "paid"
},
{
"id": "5d3026a3f3f5a4121051c6bc",
"name": "Kristine Finley",
"email": "kristinefinley@glasstep.com",
"country": "Uganda",
"starred": false,
"status": "paid"
},
{
"id": "5d3026a341bb45b14a38d0ec",
"name": "York Carson",
"email": "yorkcarson@glasstep.com",
"country": "Cyprus",
"starred": true,
"status": "paid"
},
{
"id": "5d3026a32ed6a9a296e01c71",
"name": "Nikki Conway",
"email": "nikkiconway@glasstep.com",
"country": "Tuvalu",
"starred": true,
"status": "paid"
},
{
"id": "5d3026a32b3f710cb8b73bca",
"name": "Lindsey Burgess",
"email": "lindseyburgess@glasstep.com",
"country": "Mali",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a3fbfadf6c0b971769",
"name": "Love Christian",
"email": "lovechristian@glasstep.com",
"country": "Andorra",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a35c48c5e49f1930e0",
"name": "Julia Sawyer",
"email": "juliasawyer@glasstep.com",
"country": "Hungary",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a3fc275278bd752b31",
"name": "Mayer Warren",
"email": "mayerwarren@glasstep.com",
"country": "Latvia",
"starred": false,
"status": "rejected"
}
]
-13
View File
@@ -1,13 +0,0 @@
import type { TChartData as ChartData } from 'vue-chartjs/dist/types'
export type ColorThemes = {
[key: string]: string
}
export type TLineChartData = ChartData<'line'>
export type TBarChartData = ChartData<'bar'>
export type TBubbleChartData = ChartData<'bubble'>
export type TDoughnutChartData = ChartData<'doughnut'>
export type TPieChartData = ChartData<'pie'>
export type TChartData = TLineChartData | TBarChartData | TBubbleChartData | TDoughnutChartData | TPieChartData
-386
View File
@@ -1,386 +0,0 @@
[
{
"id": "5d2c865e9a0bae79a6ef7cfa",
"firstName": "Ashley",
"lastName": "Mcdaniel",
"fullName": "Ashley Mcdaniel",
"email": "ashleymcdaniel@nebulean.com",
"country": "Cayman Islands",
"starred": true,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "warning",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865ec73341e16e5f2251",
"firstName": "Sellers",
"lastName": "Todd",
"fullName": "Todd Sellers",
"email": "sellerstodd@nebulean.com",
"country": "Togo",
"starred": false,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "none",
"color": "primary",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e38800c5ce28f2f6b",
"firstName": "Sherman",
"lastName": "Knowles",
"fullName": "Sherman Knowles",
"email": "shermanknowles@nebulean.com",
"country": "Central African Republic",
"starred": true,
"hasReport": true,
"status": "warning",
"checked": false,
"trend": "none",
"color": "warning",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e957cd150b82e17a6",
"firstName": "Vasquez",
"lastName": "Lawson",
"fullName": "Vasquez Lawson",
"email": "vasquezlawson@nebulean.com",
"country": "Bouvet Island",
"starred": true,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "down",
"color": "warning",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e9194dbe2faf99227",
"firstName": "April",
"lastName": "Sykes",
"fullName": "April Sykes",
"email": "aprilsykes@nebulean.com",
"country": "Saint Vincent and The Grenadines",
"starred": false,
"hasReport": true,
"status": "warning",
"checked": false,
"trend": "down",
"color": "primary",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e1ed74d83f6b26934",
"firstName": "Hodges",
"lastName": "Garrison",
"fullName": "Hodges Garrison",
"email": "hodgesgarrison@nebulean.com",
"country": "Zimbabwe",
"starred": true,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "none",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e0ef31380880c3de5",
"firstName": "Therese",
"lastName": "Stokes",
"fullName": "Therese Stokes",
"email": "theresestokes@nebulean.com",
"country": "Mali",
"starred": true,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "up",
"color": "warning",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e4b5ab4727e5c8b69",
"firstName": "Goodwin",
"lastName": "Brewer",
"fullName": "Goodwin Brewer",
"email": "goodwinbrewer@nebulean.com",
"country": "Iraq",
"starred": true,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "none",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e4c4d675787cfe1c0",
"firstName": "Gomez",
"lastName": "Wise",
"fullName": "Gomez Wise",
"email": "gomezwise@nebulean.com",
"country": "Portugal",
"starred": true,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "none",
"color": "primary",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e1017c3229017fc68",
"firstName": "Laverne",
"lastName": "Ayers",
"fullName": "Laverne Ayers",
"email": "laverneayers@nebulean.com",
"country": "Micronesia",
"starred": false,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "info",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865ee66676fd7464f8b9",
"firstName": "Stewart",
"lastName": "Leon",
"fullName": "Stewart Leon",
"email": "stewartleon@nebulean.com",
"country": "Seychelles",
"starred": true,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "up",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e644d8acbed1e0e97",
"firstName": "Lindsey",
"lastName": "Hopkins",
"fullName": "Lindsey Hopkins",
"email": "lindseyhopkins@nebulean.com",
"country": "Costa Rica",
"starred": false,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "up",
"color": "primary",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865ef2b732c74dc3d6a2",
"firstName": "Head",
"lastName": "Lloyd",
"fullName": "Head Lloyd",
"email": "headlloyd@nebulean.com",
"country": "Turkey",
"starred": true,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e4ee4f09e92ead2e7",
"firstName": "Fisher",
"lastName": "Bradford",
"fullName": "Fisher Bradford",
"email": "fisherbradford@nebulean.com",
"country": "Ethiopia",
"starred": true,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "up",
"color": "info",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e88d46a9e9049a549",
"firstName": "Aurora",
"lastName": "Bird",
"fullName": "Aurora Bird",
"email": "aurorabird@nebulean.com",
"country": "Burkina Faso",
"starred": false,
"hasReport": true,
"status": "warning",
"checked": false,
"trend": "up",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e44bf14ea96d6e752",
"firstName": "Bonita",
"lastName": "Shields",
"fullName": "Bonita Shields",
"email": "bonitashields@nebulean.com",
"country": "Cote D'Ivoire (Ivory Coast)",
"starred": true,
"hasReport": true,
"status": "warning",
"checked": false,
"trend": "down",
"color": "primary",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e2a8be26f6ac4369c",
"firstName": "Ethel",
"lastName": "Underwood",
"fullName": "Ethel Underwood",
"email": "ethelunderwood@nebulean.com",
"country": "Vanuatu",
"starred": false,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e5e0aea40111c37f8",
"firstName": "Parker",
"lastName": "May",
"fullName": "Parker May",
"email": "parkermay@nebulean.com",
"country": "Pakistan",
"starred": true,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "warning",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e7e0c05ecc2d0c186",
"firstName": "Hillary",
"lastName": "Waters",
"fullName": "Hillary Waters",
"email": "hillarywaters@nebulean.com",
"country": "Comoros",
"starred": true,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "down",
"color": "primary",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e80a72eeda016b169",
"firstName": "Raquel",
"lastName": "Ferrell",
"fullName": "Raquel Ferrell",
"email": "raquelferrell@nebulean.com",
"country": "China",
"starred": false,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "info",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865eafacadd378add679",
"firstName": "Pickett",
"lastName": "Page",
"fullName": "Pickett Page",
"email": "pickettpage@nebulean.com",
"country": "Bermuda",
"starred": true,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "up",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e772b1a75bb0a07b5",
"firstName": "Alyson",
"lastName": "Bailey",
"fullName": "Alyson Bailey",
"email": "alysonbailey@nebulean.com",
"country": "United Arab Emirates",
"starred": false,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "up",
"color": "warning",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e137c19a76b56210c",
"firstName": "Farley",
"lastName": "Meyers",
"fullName": "Farley Meyers",
"email": "farleymeyers@nebulean.com",
"country": "Christmas Island",
"starred": false,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "up",
"color": "warning",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865eb0ba37a27aa9afe0",
"firstName": "Hinton",
"lastName": "Avery",
"fullName": "Hinton Avery",
"email": "hintonavery@nebulean.com",
"country": "Liechtenstein",
"starred": false,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "up",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
}
]
+12
View File
@@ -43,12 +43,24 @@ use([
import serverApi from '@/data/server-api'
import Slideout from '@hyjiacan/vue-slideout'
import '@hyjiacan/vue-slideout/dist/slideout.css'
import VueGoodTable from 'vue-good-table-next'
import 'vue-good-table-next/dist/vue-good-table-next.css'
import contextmenu from 'v-contextmenu'
import 'v-contextmenu/dist/themes/default.css'
const app = createApp(App)
app.use(stores)
app.use(router)
app.use(i18n)
app.use(createVuestic({ config: vuesticGlobalConfig }))
app.use(Slideout)
app.use(VueGoodTable)
app.use(contextmenu)
app.component('EChart', ECharts)
-50
View File
@@ -1,50 +0,0 @@
<template>
<div class="dashboard">
<dashboard-charts />
<dashboard-info-block />
<div class="row row-equal">
<div class="flex xs12 lg6">
<dashboard-tabs @submit="addAddressToMap" />
</div>
<div class="flex xs12 lg6">
<DashboardMap ref="dashboardMap" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import DashboardCharts from './DashboardCharts.vue'
import DashboardInfoBlock from './DashboardInfoBlock.vue'
import DashboardTabs from './DashboardTabs.vue'
import DashboardMap from './DashboardMap.vue'
const dashboardMap = ref()
function addAddressToMap({ city, country }: { city: { text: string }; country: string }) {
dashboardMap.value.addAddress({ city: city.text, country })
}
</script>
<style lang="scss">
.row-equal .flex {
.va-card {
height: 100%;
}
}
.dashboard {
.va-card {
margin-bottom: 0 !important;
&__title {
display: flex;
justify-content: space-between;
}
}
}
</style>
@@ -1,101 +0,0 @@
<template>
<div class="row row-equal">
<div class="flex xs12 lg6 xl6">
<va-card v-if="lineChartDataGenerated">
<va-card-title>
<h1>{{ t('dashboard.charts.trendyTrends') }}</h1>
<div>
<va-button
class="ma-1"
size="small"
color="danger"
:disabled="datasetIndex === minIndex"
@click="setDatasetIndex(datasetIndex - 1)"
>
{{ t('dashboard.charts.showInLessDetail') }}
</va-button>
<va-button
class="ma-1"
size="small"
color="danger"
:disabled="datasetIndex === maxIndex - 1"
@click="setDatasetIndex(datasetIndex + 1)"
>
{{ t('dashboard.charts.showInMoreDetail') }}
</va-button>
</div>
</va-card-title>
<va-card-content>
<va-chart class="chart" :data="lineChartDataGenerated" type="line" />
</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md6 lg3 xl3">
<va-card class="d-flex">
<va-card-title>
<h1>{{ t('dashboard.charts.loadingSpeed') }}</h1>
<va-button icon="print" plain @click="printChart" />
</va-card-title>
<va-card-content v-if="doughnutChartDataGenerated">
<va-chart ref="doughnutChart" class="chart chart--donut" :data="doughnutChartDataGenerated" type="doughnut" />
</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md6 lg3 xl3">
<dashboard-contributors-chart />
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { doughnutChartData, lineChartData } from '../../../data/charts'
import { useChartData } from '../../../data/charts/composables/useChartData'
import { usePartOfChartData } from './composables/usePartOfChartData'
import VaChart from '../../../components/va-charts/VaChart.vue'
import DashboardContributorsChart from './DashboardContributorsList.vue'
const { t } = useI18n()
const doughnutChart = ref()
const dataGenerated = useChartData(lineChartData, 0.7)
const doughnutChartDataGenerated = useChartData(doughnutChartData)
const {
dataComputed: lineChartDataGenerated,
minIndex,
maxIndex,
datasetIndex,
setDatasetIndex,
} = usePartOfChartData(dataGenerated)
function printChart() {
const windowObjectReference = window.open('', 'Print', 'height=600,width=800') as Window
const img = windowObjectReference.document.createElement('img')
img.src = `${(document.querySelector('.chart--donut canvas') as HTMLCanvasElement | undefined)?.toDataURL(
'image/png',
)}`
img.onload = () => {
windowObjectReference?.document.body.appendChild(img)
}
windowObjectReference.print()
windowObjectReference.onafterprint = () => {
windowObjectReference?.close()
}
}
</script>
<style scoped>
.chart {
height: 400px;
}
</style>
@@ -1,95 +0,0 @@
<template>
<va-card class="d-flex dashboard-contributors-list">
<va-card-title>
<h1>{{ t('dashboard.charts.topContributors') }}</h1>
<div class="mr-0 va-text-right">
<a class="mr-0 va-link" :disabled="contributors.length <= step" @click="showNext">
{{ t('dashboard.charts.showNextFive') }}
</a>
</div>
</va-card-title>
<va-card-content>
<va-inner-loading :loading="loading" style="width: 100%">
<div v-for="(contributor, idx) in visibleList" :key="idx" class="mb-3">
<va-progress-bar :model-value="getPercent(contributor.contributions)" :color="getProgressBarColor(idx)">
{{ contributor.contributions }} {{ t('dashboard.charts.commits') }}
</va-progress-bar>
<p class="mt-2">{{ contributor.login }}</p>
</div>
</va-inner-loading>
</va-card-content>
</va-card>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import axios from 'axios'
const { t } = useI18n()
interface IContributor {
contributions: number
login: string
}
const contributors = ref<IContributor[]>([])
const loading = ref(false)
const progressMax = ref(392)
const visibleList = ref<IContributor[]>([])
const step = ref(5)
const page = ref(0)
onMounted(() => {
loadContributorsList()
})
async function loadContributorsList() {
loading.value = true
const { data } = await axios.get<IContributor[]>(
'https://api.github.com/repos/epicmaxco/vuestic-admin/contributors',
)
contributors.value = data
progressMax.value = Math.max(...contributors.value.map(({ contributions }) => contributions))
showNext()
loading.value = false
}
function getPercent(val: number) {
return (val / progressMax.value) * 100
}
function showNext() {
visibleList.value = contributors.value.slice(page.value * step.value, page.value * step.value + step.value)
page.value += 1
const maxPages = (contributors.value.length - 1) / step.value
if (page.value > maxPages) {
page.value = 0
}
}
function getProgressBarColor(idx: number) {
const themeColors = ['primary', 'success', 'info', 'danger', 'warning']
if (idx < themeColors.length) {
return themeColors[idx]
}
// Get random color if idx out of colors array
const keys = Object.keys(themeColors)
return themeColors[keys[(keys.length * Math.random()) << 0] as unknown as number]
}
</script>
<style scoped lang="scss">
.dashboard-contributors-list {
flex-direction: column;
.inner-loading {
height: 100%;
}
}
</style>
@@ -1,145 +0,0 @@
<template>
<div class="row row-equal">
<div class="flex xl6 xs12 lg6">
<div class="row">
<div v-for="(info, idx) in infoTiles" :key="idx" class="flex xs12 sm4">
<va-card class="mb-4" :color="info.color">
<va-card-content>
<h2 class="va-h2 ma-0" style="color: white">{{ info.value }}</h2>
<p style="color: white">{{ t('dashboard.info.' + info.text) }}</p>
</va-card-content>
</va-card>
</div>
</div>
<div class="row">
<div class="flex xs12 sm6 md6">
<va-card>
<va-card-content>
<h2 class="va-h2 ma-0" :style="{ color: colors.primary }">291</h2>
<p class="no-wrap">{{ t('dashboard.info.completedPullRequests') }}</p>
</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md6">
<va-card>
<va-card-content>
<div class="row row-separated">
<div class="flex xs4">
<h2 class="va-h2 ma-0 va-text-center" :style="{ color: colors.primary }">3</h2>
<p class="va-text-center">{{ t('dashboard.info.users') }}</p>
</div>
<div class="flex xs4">
<h2 class="va-h2 ma-0 va-text-center" :style="{ color: colors.info }">24</h2>
<p class="va-text-center no-wrap">{{ t('dashboard.info.points') }}</p>
</div>
<div class="flex xs4">
<h2 class="va-h2 ma-0 va-text-center" :style="{ color: colors.warning }">91</h2>
<p class="va-text-center">{{ t('dashboard.info.units') }}</p>
</div>
</div>
</va-card-content>
</va-card>
</div>
</div>
</div>
<div class="flex xs12 sm6 md6 xl3 lg3">
<va-card stripe stripe-color="info">
<va-card-title>
{{ t('dashboard.info.componentRichTheme') }}
</va-card-title>
<va-card-content>
<p class="rich-theme-card-text">
Buying the right telescope to take your love of astronomy to the next level is a big next step.
</p>
<div class="mt-3">
<va-button color="primary" target="_blank" href="https://github.com/epicmaxco/vuestic-ui">
{{ t('dashboard.info.viewLibrary') }}
</va-button>
</div>
</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md6 xl3 lg3">
<va-card>
<va-image :src="images[currentImageIndex]" style="height: 200px" />
<va-card-title>
<va-button preset="plain" icon-right="fa-arrow-circle-right" @click="showModal">
{{ t('dashboard.info.exploreGallery') }}
</va-button>
</va-card-title>
</va-card>
</div>
<va-modal v-model="modal">
<va-carousel v-model="currentImageIndex" :items="images" class="gallery-carousel" />
</va-modal>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { VaCarousel, VaModal, VaCard, VaCardContent, VaCardTitle, VaButton, VaImage, useColors } from 'vuestic-ui'
const { t } = useI18n()
const { colors } = useColors()
const infoTiles = ref([
{
color: 'success',
value: '803',
text: 'commits',
icon: '',
},
{
color: 'danger',
value: '57',
text: 'components',
icon: '',
},
{
color: 'info',
value: '5',
text: 'teamMembers',
icon: '',
},
])
const modal = ref(false)
const currentImageIndex = ref(0)
const images = ref([
'https://i.imgur.com/qSykGko.jpg',
'https://i.imgur.com/jYwT08D.png',
'https://i.imgur.com/9930myH.jpg',
'https://i.imgur.com/2JxhWD6.jpg',
'https://i.imgur.com/MpiOWbM.jpg',
])
function showModal() {
modal.value = true
}
</script>
<style lang="scss" scoped>
.row-separated {
.flex + .flex {
border-left: 1px solid var(--va-background-primary);
}
}
.rich-theme-card-text {
line-height: 1.5;
}
.gallery-carousel {
width: 80vw;
max-width: 100%;
@media all and (max-width: 576px) {
width: 100%;
}
}
</style>
@@ -1,38 +0,0 @@
<template>
<va-card>
<va-card-title>
{{ t('dashboard.currentVisitors') }}
</va-card-title>
<line-map v-model="mainCity" :map-data="cities" :home-city="homeCity" class="dashboard-map" />
</va-card>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import LineMap from '../../../components/maps/LineMap.vue'
import { lineMapData, compareStrings } from '../../../data/maps/lineMapData'
const { t } = useI18n()
const cities = ref(lineMapData.cities)
const mainCity = ref('Vilnius')
const homeCity = ref('Vilnius')
function addAddress(address: { city: string; country: string }) {
cities.value = cities.value.map((mapItem) =>
compareStrings(mapItem.title, address.city) && compareStrings(mapItem.country, address.country)
? { ...mapItem, color: 'success' }
: mapItem,
)
}
defineExpose({ addAddress })
</script>
<style>
.dashboard-map {
height: 380px;
}
</style>
@@ -1,53 +0,0 @@
<template>
<va-card>
<va-card-title>
{{ t('dashboard.setupRemoteConnections') }}
</va-card-title>
<va-card-content>
<va-tabs v-model="activeTabName" grow>
<template #tabs>
<va-tab name="OverviewTab">
{{ t('dashboard.tabs.overview.title') }}
</va-tab>
<va-tab name="BillingAddressTab">
{{ t('dashboard.tabs.billingAddress.title') }}
</va-tab>
<va-tab name="BankDetailsTab">
{{ t('dashboard.tabs.bankDetails.title') }}
</va-tab>
</template>
</va-tabs>
<va-separator />
<component :is="tabs[activeTabName]" @submit="submit" />
</va-card-content>
</va-card>
</template>
<script setup lang="ts">
import { defineAsyncComponent, ref } from 'vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const tabs = {
OverviewTab: defineAsyncComponent(() => import('./dashboard-tabs/OverviewTab.vue')),
BillingAddressTab: defineAsyncComponent(() => import('./dashboard-tabs/BillingAddressTab.vue')),
BankDetailsTab: defineAsyncComponent(() => import('./dashboard-tabs/BankDetailsTab.vue')),
}
const emit = defineEmits<{
(e: 'submit', data: any): void
}>()
const activeTabName = ref<keyof typeof tabs>('BillingAddressTab')
function submit(data: any) {
emit('submit', data)
}
</script>
<style lang="scss">
.va-tabs__tabs {
height: 100%;
}
</style>
@@ -1,27 +0,0 @@
import { computed, ref, ComputedRef } from '@vue/reactivity'
import { TChartData } from '../../../../data/types'
export function usePartOfChartData<T extends TChartData>(data: ComputedRef<T>) {
const datasetIndex = ref(0)
const setDatasetIndex = (index: number) => {
datasetIndex.value = index
}
const dataComputed = computed<T>(() => ({
...data.value,
labels: data.value.labels?.slice(datasetIndex.value),
datasets: data.value.datasets.map((dataset) => ({
...dataset,
data: dataset.data.slice(datasetIndex.value),
})),
}))
return {
datasetIndex,
minIndex: 0,
maxIndex: (data.value.labels?.length ?? 0) - 1,
dataComputed,
setDatasetIndex,
}
}
@@ -1,46 +0,0 @@
<template>
<div class="pt-2">
<div class="title text-dark">
{{ t('dashboard.tabs.bankDetails.detailsFields') }}
</div>
<div class="row">
<div class="flex xs12 md6">
<va-input v-model="form.bankName" class="mb-3" :label="t('dashboard.tabs.bankDetails.bankName')" />
<va-input v-model="form.accountName" class="mb-3" :label="t('dashboard.tabs.bankDetails.accountName')" />
<va-input v-model="form.sortCode" class="mb-3" :label="t('dashboard.tabs.bankDetails.sortCode')" />
</div>
<div class="flex xs12 md6">
<va-input v-model="form.accountNumber" class="mb-3" :label="t('dashboard.tabs.bankDetails.accountNumber')" />
<va-input v-model="form.notes" class="mb-3" :label="t('dashboard.tabs.bankDetails.notes')" />
</div>
</div>
<div class="row justify-center">
<va-button @click="sendDetails">
{{ t('dashboard.tabs.bankDetails.sendDetails') }}
</va-button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useColors, useToast } from 'vuestic-ui'
const { colors } = useColors()
const { t } = useI18n()
const { init: initToast } = useToast()
const form = ref({
bankName: 'Raiffeisen Bank',
accountName: 'GoalSaver',
sortCode: '6558912',
accountNumber: '000876432',
notes: '',
})
function sendDetails() {
const color = colors.primary
initToast({ message: `Details sent!`, color })
}
</script>
@@ -1,102 +0,0 @@
<template>
<div class="pt-2">
<div class="row">
<div class="flex sm12 md6">
<div class="title mb-3" :style="computedStylesTitle">
{{ t('dashboard.tabs.billingAddress.personalInfo') }}
</div>
<va-input v-model="form.name" :label="t('dashboard.tabs.billingAddress.firstName')" />
<va-input v-model="form.email" :label="t('dashboard.tabs.billingAddress.email')" />
<va-input v-model="form.address" :label="t('dashboard.tabs.billingAddress.address')" />
</div>
<div class="flex sm12 md6">
<div class="title mb-3" :style="computedStylesTitle">
{{ t('dashboard.tabs.billingAddress.companyInfo') }}
</div>
<va-select
v-model="form.country"
:options="countriesList"
:label="t('dashboard.tabs.billingAddress.country')"
searchable
clearable
class="mb-3"
/>
<va-select
v-model="form.city"
:label="t('dashboard.tabs.billingAddress.city')"
:options="allowedCitiesList"
key-by="text"
track-by="text"
class="mb-3"
/>
<va-checkbox v-model="form.connection" :label="t('dashboard.tabs.billingAddress.infiniteConnections')" />
</div>
</div>
<div class="row justify-center mb-3">
<va-button @click="submit">
{{ t('dashboard.tabs.billingAddress.addConnection') }}
</va-button>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, reactive, ref, watch } from 'vue'
import { useColors } from 'vuestic-ui'
import { useI18n } from 'vue-i18n'
import { lineMapData } from '../../../../data/maps/lineMapData'
import CountriesList from '../../../../data/CountriesList'
const { colors } = useColors()
const { t } = useI18n()
const emit = defineEmits<{
(e: 'submit', data: typeof form): void
}>()
const form = reactive({
name: 'John Smith',
email: 'smith@gmail.com',
address: '93 Guild Street',
city: { text: 'London' },
country: 'United Kingdom',
connection: true,
})
const countriesList = computed(() => {
return CountriesList.filter((item) => citiesList.value.filter(({ country }) => country === item).length)
})
const citiesList = computed(() => {
return lineMapData.cities.map(({ title, country }) => ({ text: title, country }))
})
const allowedCitiesList = ref<typeof citiesList['value']>([])
const computedStylesTitle = computed(() => ({ color: colors.dark }))
watch(
() => form.country,
(newCountry, oldCountry) => {
allowedCitiesList.value = form.country
? citiesList.value.filter(({ country }) => country === form.country)
: [...citiesList.value]
if (newCountry !== oldCountry) {
const city = allowedCitiesList.value.find(({ country }) => country === newCountry)?.text || ''
form.city = { text: city }
}
},
{ immediate: true },
)
function submit() {
emit('submit', form)
}
</script>
<style lang="scss" scoped>
.va-input-wrapper {
margin-bottom: 1rem;
}
</style>
@@ -1,89 +0,0 @@
<template>
<div class="overview-tab pt-2 layout">
<div class="mb-2"></div>
<div class="row">
<div class="flex xs12 xl6 mb-5">
<div class="overview-tab__item d-flex align--center">
<div class="overview-tab__item-icon fill-height mr-2">
<va-icon-vue />
</div>
<div class="text--bold">{{ t('dashboard.tabs.overview.built') }}</div>
</div>
</div>
<div class="flex xs12 xl6 mb-5">
<div class="overview-tab__item d-flex align--center">
<div class="overview-tab__item-icon fill-height mr-2">
<va-icon-responsive />
</div>
<div class="text--bold">{{ t('dashboard.tabs.overview.mobile') }}</div>
</div>
</div>
</div>
<div class="row">
<div class="flex xs12 xl6 mb-5">
<div class="overview-tab__item d-flex align--center">
<div class="overview-tab__item-icon fill-height mr-2">
<va-icon-free />
</div>
<div class="text--bold">{{ t('dashboard.tabs.overview.free') }}</div>
</div>
</div>
<div class="flex xs12 xl6 mb-5">
<div class="overview-tab__item d-flex align--center">
<div class="overview-tab__item-icon fill-height mr-2">
<va-icon-rich />
</div>
<div class="text--bold">{{ t('dashboard.tabs.overview.components') }}</div>
</div>
</div>
</div>
<div class="row">
<div class="flex xs12 xl6 mb-5">
<div class="overview-tab__item d-flex align--center">
<div class="overview-tab__item-icon fill-height mr-2">
<va-icon-fresh />
</div>
<div class="text--bold">{{ t('dashboard.tabs.overview.fresh') }}</div>
</div>
</div>
<div class="flex xs12 xl6">
<div class="overview-tab__item d-flex align--center">
<div class="overview-tab__item-icon fill-height mr-2">
<va-icon-clean-code />
</div>
<div class="text--bold">{{ t('dashboard.tabs.overview.nojQuery') }}</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import VaIconVue from '../../../../components/icons/VaIconVue.vue'
import VaIconFree from '../../../../components/icons/VaIconFree.vue'
import VaIconFresh from '../../../../components/icons/VaIconFresh.vue'
import VaIconResponsive from '../../../../components/icons/VaIconResponsive.vue'
import VaIconRich from '../../../../components/icons/VaIconRich.vue'
import VaIconCleanCode from '../../../../components/icons/VaIconCleanCode.vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
</script>
<style lang="scss">
.overview-tab {
&__item {
height: 55px;
&-icon {
min-width: 65px;
max-width: 65px;
}
}
}
</style>
+96 -56
View File
@@ -1,87 +1,127 @@
<template>
<div class="h-[88vh] grid grid-cols-3 gap-6">
<div class="h-[86vh] grid grid-cols-4 gap-3">
<div class="h-full col-span-1">
<div class="h-1/3">
<FileContainer class="h-9/10"></FileContainer>
<FileContainer class="h-200px overflow-auto"></FileContainer>
</div>
<div class="h-2/3">
<ControlPanel class="h-9/10" @filter-data="filterData"></ControlPanel>
<div class="h-2/3 pt-1">
<ControlPanel class="h-[100%]" @filter-data="filterData"></ControlPanel>
</div>
</div>
<LineChartContainer ref="linechart_ref" class="h-[50%] col-span-2"></LineChartContainer>
<template v-for="chart in chartManager.children" :key="chart.id">
<template v-if="dataAnalysisSettitngStore.batchMode">
<CanvasContainer ref="canvas_ref" class="h-[100%] col-span-3"></CanvasContainer>
</template>
<template v-else>
<ChartContainer ref="chart_ref" :chart="chart" class="h-[100%] col-span-3"></ChartContainer>
</template>
</template>
</div>
</template>
<script setup lang="ts">
import useMqtt from '@/composables/utils/useMqtt'
import FileContainer from '@/components/data-analysis/FileContainer.vue'
import ControlPanel from '@/components/data-analysis/ControlPanel.vue'
import LineChartContainer from '@/components/data-analysis/LineChartContainer.vue'
import { onMounted, ref } from 'vue'
import FileContainer from '@/components/data-analysis/file-container/FileContainer.vue'
import ControlPanel from '@/components/data-analysis/setting-container/SettingContainer.vue'
import ChartContainer from '@/components/data-analysis/chart-container/ChartContainer.vue'
import CanvasContainer from '@/components/data-analysis/chart-container/CanvasContainer.vue'
import { useDASettingStore } from '@/stores/data-analysis/data-analysis'
import { useChartStore } from '@/stores/data-analysis/chart'
import { ref, reactive, onMounted } from 'vue'
// reference
const chart_ref = ref()
const canvas_ref = ref()
const chartStore = useChartStore()
const chartManager = reactive(chartStore.chartManager)
onMounted(() => {
if (chartManager.children.length === 0) {
chartManager.addChart()
}
})
const dataAnalysisSettitngStore = useDASettingStore()
// mqtt init
const { startMqtt, publish } = useMqtt()
const controllerID = 'dc:a6:32:0f:56:9d'
const controllerID = 'b8:27:eb:14:55:ef'
// define subscribe and callback
startMqtt(`${controllerID}/data_analysis/#`, (topic: string, message: ArrayBuffer) => {
// [data, data, ceiling, ground]
console.timeEnd('analysising')
console.time('painting')
// [metaID, xData, yData, horizontalLine, twoPointLine]
const msg = JSON.parse(message.toString())
const name = 'test'
const url = `http://192.168.2.1:3000/api/analysis/get/csv?name=${name}`
const a = document.createElement('a')
a.href = url
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
// try draw line
// msg.push(1500000, -1500000)
console.log('msg', msg)
// reformat data
const _msg = []
for (let i = 0; i < msg[0].length; i++) {
_msg.push([msg[0][i], msg[1][i]])
// for (const info of msg) {
const metaID = msg[0]
const xData = msg[1]
const yData = msg[2]
const horizontal = msg[3]
const line = msg[4]
const groupData: number | string[][] = []
if (dataAnalysisSettitngStore.batchMode === true) {
canvas_ref.value[0].reDraw()
canvas_ref.value[0].drawInputData(xData, yData)
} else {
for (let i = 0; i < xData.length; i++) {
groupData.push([xData[i], yData[i]])
}
chartManager.children.forEach((chart, index) => {
const seriesIndex = chart.seriesManager.findSeries({ id: metaID })
// append Data
if (seriesIndex !== -1) {
chart_ref.value[index]?.appendData(seriesIndex, groupData)
}
// draw line
if (horizontal !== undefined) {
const yAxis_list = horizontal.map((x: any) => ({ yAxis: x }))
const coord_list = [{ coord: [line[0][0], line[0][1]] }, { coord: [line[1][0], line[1][1]] }]
yAxis_list.push(coord_list)
chart_ref.value[index]?.markLine(yAxis_list)
chart_ref.value[0].setOption({
series: [
{
markLine: {
data: yAxis_list,
},
},
],
})
}
// stop loading
chart_ref.value[index]?.stopLoading()
})
}
// append Data
linechart_ref.value?.appendData(0, _msg)
// stop loading
linechart_ref.value?.stopLoading()
// draw line
// draw line
if (msg.length < 3) return true
let yAxis_list = msg[2].map((x) => ({ yAxis: x }))
let coord_list = [{ coord: [msg[3][0][0], msg[3][0][1]] }, { coord: [msg[3][1][0], msg[3][1][1]] }]
// yAxis_list.append([{ coord:[ msg[3][0][0],msg[3][0][1]]},{ coord:[ msg[3][1][0], msg[3][1][1]]}])
yAxis_list.push(coord_list)
console.log('yAxis_list', yAxis_list)
linechart_ref.value.setOption({
series: [
{
markLine: {
data: yAxis_list,
},
},
],
})
// download file
// const name = 'test'
// const url = `http://192.168.2.1:3000/api/analysis/get/csv?name=${name}`
// const a = document.createElement('a')
// a.href = url
// a.target = '_blank'
// document.body.appendChild(a)
// a.click()
// document.body.removeChild(a)
})
// reference
const linechart_ref = ref()
// ControlPanel handling
const filterData = function (e: any) {
linechart_ref.value?.startLoading()
console.log(linechart_ref)
console.log(e)
publish(`${controllerID}_data_analysis/get_analysis_data`, JSON.stringify({ e }))
if (dataAnalysisSettitngStore.batchMode === true) {
canvas_ref.value[0].resetCanvas()
} else {
chart_ref.value[0]?.reset()
chart_ref.value[0]?.startLoading()
}
publish(`${controllerID}_data_analysis/get_analysis_data`, JSON.stringify(e))
}
defineExpose({ linechart_ref, filterData })
defineExpose({ chart_ref, filterData })
</script>
<style></style>
-243
View File
@@ -1,243 +0,0 @@
export default [
'Afghanistan',
'Albania',
'Algeria',
'American Samoa',
'Andorra',
'Angola',
'Anguilla',
'Antarctica',
'Antigua and Barbuda',
'Argentina',
'Armenia',
'Aruba',
'Australia',
'Austria',
'Azerbaijan',
'Bahamas',
'Bahrain',
'Bangladesh',
'Barbados',
'Belarus',
'Belgium',
'Belize',
'Benin',
'Bermuda',
'Bhutan',
'Bolivia',
'Bosnia and Herzegowina',
'Botswana',
'Bouvet Island',
'Brazil',
'British Indian Ocean Territory',
'Brunei Darussalam',
'Bulgaria',
'Burkina Faso',
'Burundi',
'Cambodia',
'Cameroon',
'Canada',
'Cape Verde',
'Cayman Islands',
'Central African Republic',
'Chad',
'Chile',
'China',
'Christmas Island',
'Cocos (Keeling) Islands',
'Colombia',
'Comoros',
'Congo',
'Congo, the Democratic Republic of the',
'Cook Islands',
'Costa Rica',
"Cote d'Ivoire",
'Croatia (Hrvatska)',
'Cuba',
'Cyprus',
'Czech Republic',
'Denmark',
'Djibouti',
'Dominica',
'Dominican Republic',
'East Timor',
'Ecuador',
'Egypt',
'El Salvador',
'Equatorial Guinea',
'Eritrea',
'Estonia',
'Ethiopia',
'Falkland Islands (Malvinas)',
'Faroe Islands',
'Fiji',
'Finland',
'France',
'France Metropolitan',
'French Guiana',
'French Polynesia',
'French Southern Territories',
'Gabon',
'Gambia',
'Georgia',
'Germany',
'Ghana',
'Gibraltar',
'Greece',
'Greenland',
'Grenada',
'Guadeloupe',
'Guam',
'Guatemala',
'Guinea',
'Guinea-Bissau',
'Guyana',
'Haiti',
'Heard and Mc Donald Islands',
'Holy See (Vatican City State)',
'Honduras',
'Hong Kong',
'Hungary',
'Iceland',
'India',
'Indonesia',
'Iran (Islamic Republic of)',
'Iraq',
'Ireland',
'Israel',
'Italy',
'Jamaica',
'Japan',
'Jordan',
'Kazakhstan',
'Kenya',
'Kiribati',
"Korea, Democratic People's Republic of",
'Korea, Republic of',
'Kuwait',
'Kyrgyzstan',
"Lao, People's Democratic Republic",
'Latvia',
'Lebanon',
'Lesotho',
'Liberia',
'Libyan Arab Jamahiriya',
'Liechtenstein',
'Lithuania',
'Luxembourg',
'Macau',
'Macedonia, The Former Yugoslav Republic of',
'Madagascar',
'Malawi',
'Malaysia',
'Maldives',
'Mali',
'Malta',
'Marshall Islands',
'Martinique',
'Mauritania',
'Mauritius',
'Mayotte',
'Mexico',
'Micronesia, Federated States of',
'Moldova, Republic of',
'Monaco',
'Mongolia',
'Montserrat',
'Morocco',
'Mozambique',
'Myanmar',
'Namibia',
'Nauru',
'Nepal',
'Netherlands',
'Netherlands Antilles',
'New Caledonia',
'New Zealand',
'Nicaragua',
'Niger',
'Nigeria',
'Niue',
'Norfolk Island',
'Northern Mariana Islands',
'Norway',
'Oman',
'Pakistan',
'Palau',
'Panama',
'Papua New Guinea',
'Paraguay',
'Peru',
'Philippines',
'Pitcairn',
'Poland',
'Portugal',
'Puerto Rico',
'Qatar',
'Reunion',
'Romania',
'Russian Federation',
'Rwanda',
'Saint Kitts and Nevis',
'Saint Lucia',
'Saint Vincent and the Grenadines',
'Samoa',
'San Marino',
'Sao Tome and Principe',
'Saudi Arabia',
'Senegal',
'Serbia',
'Seychelles',
'Sierra Leone',
'Singapore',
'Slovakia (Slovak Republic)',
'Slovenia',
'Solomon Islands',
'Somalia',
'South Africa',
'South Georgia and the South Sandwich Islands',
'Spain',
'Sri Lanka',
'St. Helena',
'St. Pierre and Miquelon',
'Sudan',
'Suriname',
'Svalbard and Jan Mayen Islands',
'Swaziland',
'Sweden',
'Switzerland',
'Syrian Arab Republic',
'Taiwan, Province of China',
'Tajikistan',
'Tanzania, United Republic of',
'United States of America',
'Thailand',
'Togo',
'Tokelau',
'Tonga',
'Trinidad and Tobago',
'Tunisia',
'Turkey',
'Turkmenistan',
'Turks and Caicos Islands',
'Tuvalu',
'Uganda',
'Ukraine',
'United Arab Emirates',
'United Kingdom',
'United States',
'United States Minor Outlying Islands',
'Uruguay',
'Uzbekistan',
'Vanuatu',
'Venezuela',
'Vietnam',
'Virgin Islands (British)',
'Virgin Islands (U.S.)',
'Wallis and Futuna Islands',
'Western Sahara',
'Yemen',
'Yugoslavia',
'Zambia',
'Zimbabwe',
]
@@ -1,330 +0,0 @@
<template>
<div class="form-elements">
<div class="row">
<div class="flex xs12">
<va-card>
<va-card-title>{{ t('forms.inputs.title') }}</va-card-title>
<va-card-content>
<form>
<div class="row">
<div class="flex md4 sm6 xs12">
<va-input v-model="simple" placeholder="Text Input" />
</div>
<div class="flex md4 sm6 xs12">
<va-input v-model="withIcon" placeholder="Input With Icon">
<template #prepend>
<va-icon color="gray" name="envelope" />
</template>
</va-input>
</div>
<div class="flex md4 sm6 xs12">
<va-input v-model="withButton" placeholder="Input With Button">
<template #append>
<va-button style="margin-right: 0" small> UPLOAD </va-button>
</template>
</va-input>
</div>
<div class="flex md4 sm6 xs12">
<va-input v-model="successfulEmail" type="email" label="Email (Validated with success)" success>
</va-input>
</div>
<div class="flex md4 sm6 xs12">
<va-input v-model="clearableText" placeholder="Input With Clear Button" clearable />
</div>
<div class="flex md4 sm6 xs12">
<va-input
v-model="wrongEmail"
type="email"
label="Email (Validated)"
error
:error-messages="errorMessages"
>
</va-input>
</div>
<div class="flex md4 sm6 xs12">
<va-input
v-model="withDescription"
placeholder="Text Input (with description)"
:messages="messages"
/>
</div>
</div>
</form>
</va-card-content>
</va-card>
</div>
<div class="flex xs12">
<va-card>
<va-card-title>{{ t('forms.dateTimePicker.title') }}</va-card-title>
<va-card-content>
<form>
<div class="row">
<div class="flex md4 sm6 xs12">
<va-date-input v-model="dateInput.simple" :label="t('forms.dateTimePicker.basic')" />
</div>
<div class="flex md4 sm6 xs12">
<va-date-input
v-model="dateInput.simple"
:label="t('forms.dateTimePicker.manualInput')"
manual-input
/>
</div>
<div class="flex md4 sm6 xs12">
<va-date-input v-model="dateInput.disabled" :label="t('forms.dateTimePicker.disabled')" disabled />
</div>
<div class="flex md4 sm6 xs12">
<va-date-input
v-model="dateInput.multiple"
:label="t('forms.dateTimePicker.multiple')"
mode="multiple"
clearable
/>
</div>
<div class="flex md4 sm6 xs12">
<va-date-input
v-model="dateInput.range"
:label="t('forms.dateTimePicker.range')"
mode="range"
clearable
/>
</div>
<div class="flex md4 sm6 xs12">
<va-date-input
v-model="dateInput.simple"
:label="t('forms.dateTimePicker.customFirstDay')"
first-weekday="Monday"
highlight-weekend
/>
</div>
</div>
</form>
</va-card-content>
<va-divider />
<va-card-content>
<form>
<div class="row">
<div class="flex md4 sm6 xs12">
<va-time-input v-model="dateInput.simple" :label="t('forms.dateTimePicker.basic')" />
</div>
<div class="flex md4 sm6 xs12">
<va-time-input
v-model="dateInput.simple"
:label="t('forms.dateTimePicker.manualInput')"
manual-input
/>
</div>
<div class="flex md4 sm6 xs12">
<va-time-input v-model="dateInput.simple" :label="t('forms.dateTimePicker.disabled')" disabled />
</div>
</div>
</form>
</va-card-content>
</va-card>
</div>
<div class="flex xs12">
<va-card>
<va-card-title>{{ t('forms.selects.title') }}</va-card-title>
<va-card-content>
<form>
<div class="row">
<div class="flex md6 xs12">
<va-select
v-model="simpleSelectModel"
:label="t('forms.selects.simple')"
text-by="description"
track-by="id"
:options="simpleOptions"
/>
</div>
<div class="flex md6 xs12">
<va-select
v-model="multiSelectModel"
:label="t('forms.selects.multi')"
text-by="description"
track-by="id"
multiple
:options="simpleOptions"
/>
</div>
<div class="flex md6 xs12">
<va-select v-model="chosenCountry" :label="t('forms.selects.country')" :options="countriesList" />
</div>
<div class="flex md6 xs12">
<va-select
v-model="multiSelectCountriesModel"
:label="t('forms.selects.countryMulti')"
multiple
:options="countriesList"
/>
</div>
<div class="flex md6 xs12">
<va-select
v-model="searchableSelectModel"
:label="t('forms.selects.searchable')"
searchable
text-by="description"
track-by="id"
:options="simpleOptions"
/>
</div>
<div class="flex md6 xs12">
<va-select
v-model="multiSearchableSelectModel"
:label="t('forms.selects.searchableMulti')"
text-by="description"
searchable
multiple
:options="countriesList"
/>
</div>
</div>
</form>
</va-card-content>
</va-card>
</div>
<div class="flex xs12">
<va-card>
<va-card-title>{{ t('forms.controls.title') }}</va-card-title>
<va-card-content>
<form>
<div class="row">
<div class="flex md6 xs12">
<fieldset>
<va-checkbox v-model="checkbox.unselected" :label="t('forms.controls.unselected')" class="mb-2" />
<va-checkbox v-model="checkbox.selected" :label="t('forms.controls.selected')" class="mb-2" />
<va-checkbox
v-model="checkbox.readonly"
:label="t('forms.controls.readonly')"
readonly
class="mb-2"
/>
<va-checkbox
v-model="checkbox.disabled"
:label="t('forms.controls.disabled')"
disabled
class="mb-2"
/>
<va-checkbox v-model="checkbox.error" :label="t('forms.controls.error')" error class="mb-2" />
<va-checkbox
v-model="checkbox.errorMessages"
:label="t('forms.controls.errorMessage')"
error
:error-messages="errorMessages"
:error-count="2"
/>
</fieldset>
</div>
<div class="flex md6 xs12">
<fieldset>
<va-radio v-model="radioSelectedOption" option="option1" label="Radio-1" />
<va-radio v-model="radioSelectedOption" option="option2" label="Radio-2" />
</fieldset>
<fieldset>
<va-radio v-model="radioSelectedDisableOption" option="option1" disabled label="Disabled Radio-1" />
<va-radio v-model="radioSelectedDisableOption" option="option2" disabled label="Disabled Radio-2" />
</fieldset>
</div>
<div class="flex">
<fieldset>
<va-switch v-model="toggles.selected" label="Selected toggle" class="mr-4 mb-2" />
<va-switch v-model="toggles.unselected" label="Unselected toggle" class="mr-4 mb-2" />
</fieldset>
<fieldset>
<va-switch v-model="toggles.disabled" disabled label="Disabled toggle" class="mr-4 mb-2" />
<va-switch v-model="toggles.disabled" readonly label="Readonly toggle" class="mr-4 mb-2" />
</fieldset>
<fieldset>
<va-switch v-model="toggles.small" size="small" label="Small toggle" class="mr-4 mb-2" />
<va-switch v-model="toggles.large" size="large" label="Large toggle" class="mr-4 mb-2" />
</fieldset>
</div>
</div>
</form>
</va-card-content>
</va-card>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import CountriesList from '../data/CountriesList'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const countriesList = ref(CountriesList)
const chosenCountry = ref('')
const simple = ref('')
const withIcon = ref('')
const withButton = ref('')
const withDescription = ref('')
const clearableText = ref('Vasili Savitski')
const successfulEmail = ref('andrei@dreamsupport.io')
const wrongEmail = ref('andrei@dreamsupport')
const messages = ref([
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor ' +
'incididunt ut labore et dolore magna aliqua.',
])
const errorMessages = ref(['Field should contain a valid email'])
const simpleOptions = ref([
{
id: 1,
description: 'First option',
},
{
id: 2,
description: 'Second option',
},
{
id: 3,
description: 'Third option',
},
])
const simpleSelectModel = ref('')
const multiSelectModel = ref([])
const multiSelectCountriesModel = ref([])
const searchableSelectModel = ref('')
const multiSearchableSelectModel = ref([])
const radioSelectedOption = ref('option1')
const radioSelectedDisableOption = ref('option1')
const checkbox = ref({
unselected: false,
selected: true,
readonly: true,
disabled: true,
error: false,
errorMessages: true,
})
const toggles = ref({
unselected: false,
selected: true,
disabled: true,
small: false,
large: false,
})
const datePlusDay = (date: Date, days: number) => {
const d = new Date(date)
d.setDate(d.getDate() + days)
return d
}
const dateInput = ref({
simple: new Date(),
disabled: '2018-05-09',
range: { start: new Date(), end: datePlusDay(new Date(), 7) },
multiple: ['2018-04-25', '2018-04-27'],
})
</script>
<style lang="scss" scoped>
fieldset {
margin-bottom: 0.5rem;
}
</style>
@@ -1,48 +0,0 @@
<template>
<div class="medium-editor">
<div class="row">
<div class="flex md12">
<va-card>
<va-card-title>{{ t('forms.mediumEditor.title') }}</va-card-title>
<va-card-content class="d-flex justify-center">
<va-medium-editor @initialized="handleEditorInitialization">
<h1>Select Text To Open Editor</h1>
<p>
You enter into your favorite local bar looking
<span class="default-selection"><b>good</b></span> as hell, but you know the only heads you want to
turnspicy & stylish alpha bitches are heavily fixated on the D. The hot girl talks to you, but she
only wants to be your best friend. Her nonthreatening and attentive best friend. Receiver of sexy
selfies, listener of stories. Meanwhile, you attract unwanted attention from straight men, pudgy and
greasy moths to your emotionally distant flame.
</p>
<p>
Read the full article on
<a href="https://medium.com/@dorn.anna/girl-no-you-dont-2e21e826c62c">Medium</a>
</p>
</va-medium-editor>
</va-card-content>
</va-card>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { nextTick } from 'vue'
import { useI18n } from 'vue-i18n'
import type MediumEditor from 'medium-editor'
import VaMediumEditor from '../../../../components/va-medium-editor/VaMediumEditor.vue'
const { t } = useI18n()
function handleEditorInitialization(editor: typeof MediumEditor) {
nextTick(() => highlightSampleText(editor))
}
function highlightSampleText(editor: typeof MediumEditor) {
const sampleText = document.getElementsByClassName('default-selection')[0] as HTMLElement
editor.selectElement(sampleText)
}
</script>
@@ -1,162 +0,0 @@
<template>
<div ref="mapRef" class="bubble-map" />
</template>
<script setup lang="ts">
import { computed, onMounted, onUpdated, onBeforeUnmount, ref, shallowRef, watch } from 'vue'
import * as am5 from '@amcharts/amcharts5'
import * as am5map from '@amcharts/amcharts5/map'
import am5geodata_worldLow from '@amcharts/amcharts5-geodata/worldLow'
import am5themes_Animated from '@amcharts/amcharts5/themes/Animated'
import { useColors } from 'vuestic-ui'
import { PointGeoCoord, CountryItem, getValueBounds, getItemRadius } from '../../../../data/maps/bubbleMapData'
const bulletSizes = { min: 3, max: 30 }
const titleHTML = `
<div style="text-align: center">
<h2 style="font-size: 16px; margin-bottom: 8px">Population of the World in 2011</h2>
<p style="font-size: 12px">source: Gapminder</p>
<div>`
const props = defineProps<{
mapData: {
latLng: Record<string, PointGeoCoord>
data: CountryItem[]
}
}>()
const { getColor, colors } = useColors()
const mapRef = ref()
const mapRoot = shallowRef()
const mapChart = shallowRef()
const mapPolygonSeries = shallowRef()
const mapPointSeries = shallowRef()
const mapZoomControl = shallowRef()
const pointData = computed(() =>
props.mapData.data.map((country) => ({
...country,
...props.mapData.latLng[country.code],
})),
)
const bulletBounds = computed(() => ({
min: (Math.PI * bulletSizes.min ** 2) / 4,
max: (Math.PI * bulletSizes.max ** 2) / 4,
}))
const valueBounds = computed(() => getValueBounds(pointData.value))
const createMap = () => {
const root = am5.Root.new(mapRef.value)
root.setThemes([am5themes_Animated.new(root)])
const chart = root.container.children.push(
am5map.MapChart.new(root, {
minZoomLevel: 1,
maxZoomLevel: 10,
}),
)
const zoomControl = chart.set('zoomControl', am5map.ZoomControl.new(root, {}))
// polygon series
const polygonSeries = chart.series.push(
am5map.MapPolygonSeries.new(root, {
geoJSON: am5geodata_worldLow,
exclude: ['AQ'],
}),
)
polygonSeries.mapPolygons.template.setAll({
fill: am5.color(getColor(colors.secondary)),
fillOpacity: 0.2,
strokeWidth: 0.5,
})
// title
chart.children.push(
am5.Label.new(root, {
html: titleHTML,
y: 15,
x: am5.percent(50),
centerX: am5.percent(50),
}),
)
// point series
const pointSeries = chart.series.push(
am5map.MapPointSeries.new(root, {
latitudeField: 'latitude',
longitudeField: 'longitude',
}),
)
pointSeries.bullets.push((root, series, dataItem) => {
const itemData = dataItem.dataContext as CountryItem
return am5.Bullet.new(root, {
sprite: am5.Circle.new(root, {
radius: getItemRadius(itemData, valueBounds.value, bulletBounds.value),
fill: am5.color(itemData.color),
opacity: 0.6,
tooltipText: '{name}: {value}',
}),
})
})
// set map data
pointSeries.data.setAll(pointData.value)
// assign objects to refs
mapRoot.value = root
mapChart.value = chart
mapZoomControl.value = zoomControl
mapPointSeries.value = pointSeries
mapPolygonSeries.value = polygonSeries
}
const setPointSeriesData = () => {
mapPointSeries.value.data.setAll(pointData.value)
}
const updateChartDataOnChangeTheme = () => {
if (mapRoot.value) {
mapPolygonSeries.value.mapPolygons.template.setAll({
fill: am5.color(getColor(colors.secondary)),
})
}
}
const updateChartDataOnUpdateProps = () => {
if (mapRoot.value) {
setPointSeriesData()
}
}
const disposeMap = () => {
if (mapRoot.value) {
mapRoot.value.dispose()
}
}
onMounted(createMap)
onUpdated(updateChartDataOnUpdateProps)
watch(colors, updateChartDataOnChangeTheme)
onBeforeUnmount(disposeMap)
</script>
<style lang="scss" scoped>
.bubble-map {
border-radius: inherit;
:deep(div),
:deep(canvas) {
border-radius: inherit;
}
}
</style>
@@ -1,24 +0,0 @@
<template>
<div class="bubble-maps-page">
<div class="row">
<div class="flex md12 xs12">
<va-card class="bubble-maps-page__widget" title="Bubble Maps">
<bubble-map :map-data="bubbleMapData" style="height: 75vh" />
</va-card>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import BubbleMap from './BubbleMap.vue'
import { bubbleMapData } from '../../../../data/maps/bubbleMapData'
</script>
<style lang="scss">
.line-maps-page__widget {
.va-card__inner {
border-radius: inherit;
}
}
</style>
@@ -1,25 +0,0 @@
<template>
<div ref="mapRef" class="leaflet-map fill-height" />
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import 'leaflet-map'
import 'leaflet/dist/leaflet.css'
import * as Leaflet from 'leaflet'
Leaflet.Icon.Default.imagePath = '/vendor/leaflet/'
const mapRef = ref()
onMounted(() => {
const map = Leaflet.map(mapRef.value).setView([51.505, -0.09], 13)
Leaflet.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://osm.org/copyright">OpenStreetMap</a> contributors',
}).addTo(map)
Leaflet.marker([51.5, -0.09]).addTo(map).bindPopup('A pretty CSS3 popup.<br> Easily customizable.').openPopup()
})
</script>
@@ -1,15 +0,0 @@
<template>
<div class="leaflet-maps-page">
<div class="row">
<div class="flex md12 xs12">
<va-card class="leaflet-maps-page__widget" title="Leaflet Maps">
<leaflet-map style="height: 65vh" />
</va-card>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import LeafletMap from './LeafletMap.vue'
</script>
@@ -1,30 +0,0 @@
<template>
<div class="line-maps-page">
<div class="row">
<div class="flex md12 xs12">
<va-card class="line-maps-page__widget" title="Line Maps">
<line-map v-model="mainCity" :map-data="cities" :home-city="homeCity" style="height: 75vh" />
</va-card>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import LineMap from '../../../../components/maps/LineMap.vue'
import { lineMapData } from '../../../../data/maps/lineMapData'
const mainCity = ref(lineMapData.mainCity)
const homeCity = ref(lineMapData.homeCity)
const cities = ref(lineMapData.cities)
</script>
<style lang="scss">
.line-maps-page__widget {
.va-card__inner {
border-radius: inherit;
}
}
</style>
@@ -1,20 +0,0 @@
<template>
<div ref="mapRef" class="maplibre-map fill-height" />
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import maplibregl from 'maplibre-gl'
import 'maplibre-gl/dist/maplibre-gl.css'
const mapRef = ref()
onMounted(() => {
const map = new maplibregl.Map({
container: mapRef.value,
style: 'https://demotiles.maplibre.org/style.json',
})
map.addControl(new maplibregl.NavigationControl({}))
})
</script>
@@ -1,15 +0,0 @@
<template>
<div class="maplibre-maps-page">
<div class="row">
<div class="flex md12 xs12">
<va-card class="maplibre-maps-page__widget" title="MapLibre Maps">
<map-libre-map style="height: 65vh" />
</va-card>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import MapLibreMap from './MapLibreMap.vue'
</script>
@@ -1,37 +0,0 @@
<template>
<div class="yandex-maps-page">
<div class="row">
<div class="flex md12 xs12">
<va-card class="yandex-maps-page__widget" title="Yandex Maps">
<yandex-map
map-type="hybrid"
:coords="[55.2, 38.8]"
:zoom="8"
:controls="['trafficControl', 'zoomControl', 'geolocationControl', 'fullscreenControl', 'searchControl']"
style="width: 100%; height: 65vh"
>
<yandex-map-marker v-for="marker in markers" :key="marker['marker-id']" v-bind="marker" />
</yandex-map>
</va-card>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
// No TS declarations are provided - ignoring the error
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import { yandexMap as YandexMap, ymapMarker as YandexMapMarker } from 'vue-yandex-maps'
const markers = ref([
{
'marker-id': 0,
coords: [54.8, 38.9],
clusterName: '1',
balloonTemplate: '<div>"Your custom template"</div>',
},
])
</script>
-46
View File
@@ -1,46 +0,0 @@
<template>
<div class="not-found-pages">
<div class="row">
<div v-for="(item, index) in items" :key="index" class="flex xs12 sm6 lg4 xl3">
<va-card class="not-found-pages__cards va-text-center">
<va-image :src="item.imageUrl" style="max-height: 200px" />
<va-card-content>
{{ item.label }}
<div class="not-found-pages__button-container pt-3 mb-0">
<va-button :to="{ name: item.buttonTo }">
{{ 'View Example' }}
</va-button>
</div>
</va-card-content>
</va-card>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const items = ref([
{
imageUrl: 'https://i.imgur.com/GzUR0Wz.png',
label: 'Advanced layouts',
buttonTo: 'not-found-advanced',
},
{
imageUrl: 'https://i.imgur.com/HttcXPi.png',
label: 'Simple',
buttonTo: 'not-found-simple',
},
{
imageUrl: 'https://i.imgur.com/dlcZMiG.png',
label: 'Custom image',
buttonTo: 'not-found-custom',
},
{
imageUrl: 'https://i.imgur.com/qcOlDz7.png',
label: 'Large text heading',
buttonTo: 'not-found-large-text',
},
])
</script>
-55
View File
@@ -1,55 +0,0 @@
<template>
<div class="not-found-pages">
<div class="row mb-4">
<va-card class="flex xs12">
<va-card-title> Do you have any questions? </va-card-title>
<va-card-content>
<va-input>
<template #prepend>
<va-icon name="search" />
</template>
</va-input>
</va-card-content>
</va-card>
</div>
<div class="row">
<va-card class="flex xs12">
<va-card-title> Frequently Asked Questions </va-card-title>
<va-card-content>
<va-accordion>
<va-collapse header="First question">
<div class="pa-3">
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nemo veniam provident voluptates consequuntur
nostrum cumque possimus unde asperiores magnam rem.
</div>
</va-collapse>
<va-collapse header="Second question">
<div class="pa-3">
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nemo veniam provident voluptates consequuntur
nostrum cumque possimus unde asperiores magnam rem.
</div>
</va-collapse>
<va-collapse header="Third question">
<div class="pa-3">
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nemo veniam provident voluptates consequuntur
nostrum cumque possimus unde asperiores magnam rem.
</div>
</va-collapse>
<va-collapse header="Fourth question">
<div class="pa-3">
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nemo veniam provident voluptates consequuntur
nostrum cumque possimus unde asperiores magnam rem.
</div>
</va-collapse>
<va-collapse header="Fifth question">
<div class="pa-3">
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nemo veniam provident voluptates consequuntur
nostrum cumque possimus unde asperiores magnam rem.
</div>
</va-collapse>
</va-accordion>
</va-card-content>
</va-card>
</div>
</div>
</template>
@@ -1,96 +0,0 @@
<template>
<div class="charts">
<div class="row">
<div class="flex md6 xs12">
<va-card v-if="barChartDataGenerated" class="chart-widget">
<va-card-title>{{ t('charts.verticalBarChart') }}</va-card-title>
<va-card-content>
<va-chart :data="barChartDataGenerated" type="bar" />
</va-card-content>
</va-card>
</div>
<div class="flex md6 xs12">
<va-card v-if="horizontalBarChartDataGenerated" class="chart-widget">
<va-card-title>{{ t('charts.horizontalBarChart') }}</va-card-title>
<va-card-content>
<va-chart :data="horizontalBarChartDataGenerated" type="horizontal-bar" />
</va-card-content>
</va-card>
</div>
</div>
<div class="row">
<div class="flex md12 xs12">
<va-card v-if="lineChartDataGenerated" class="chart-widget">
<va-card-title>{{ t('charts.lineChart') }}</va-card-title>
<va-card-content>
<va-chart :data="lineChartDataGenerated" type="line" />
</va-card-content>
</va-card>
</div>
</div>
<div class="row">
<div class="flex md6 xs12">
<va-card v-if="pieChartDataGenerated" class="chart-widget">
<va-card-title>{{ t('charts.pieChart') }}</va-card-title>
<va-card-content>
<va-chart :data="pieChartDataGenerated" type="pie" />
</va-card-content>
</va-card>
</div>
<div class="flex md6 xs12">
<va-card v-if="doughnutChartDataGenerated" class="chart-widget">
<va-card-title>{{ t('charts.donutChart') }}</va-card-title>
<va-card-content>
<va-chart :data="doughnutChartDataGenerated" type="doughnut" />
</va-card-content>
</va-card>
</div>
</div>
<div class="row">
<div class="flex md12 xs12">
<va-card v-if="bubbleChartDataGenerated" class="chart-widget">
<va-card-title>{{ t('charts.bubbleChart') }}</va-card-title>
<va-card-content>
<va-chart :data="bubbleChartDataGenerated" type="bubble" />
</va-card-content>
</va-card>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import { useChartData } from '../../../../data/charts/composables/useChartData'
import {
lineChartData,
doughnutChartData,
bubbleChartData,
pieChartData,
barChartData,
horizontalBarChartData,
} from '../../../../data/charts'
import VaChart from '../../../../components/va-charts/VaChart.vue'
const lineChartDataGenerated = useChartData(lineChartData, 0.7)
const doughnutChartDataGenerated = useChartData(doughnutChartData)
const bubbleChartDataGenerated = useChartData(bubbleChartData, 0.9)
const pieChartDataGenerated = useChartData(pieChartData)
const barChartDataGenerated = useChartData(barChartData)
const horizontalBarChartDataGenerated = useChartData(horizontalBarChartData)
const { t } = useI18n()
</script>
<style lang="scss">
.chart-widget {
.va-card__content {
height: 450px;
}
}
</style>
@@ -1,31 +0,0 @@
<template>
<div class="progress-bars">
<div class="row mb-4">
<div class="flex xs12 mb-12">
<horizontal-bars />
</div>
</div>
<div class="row mb-4">
<div class="flex xs12">
<bars-state />
</div>
</div>
<div class="row mb-4">
<div class="flex xs12">
<circle-bars />
</div>
</div>
<div class="row">
<div class="flex xs12">
<colorful-bars />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import HorizontalBars from './Widgets/HorizontalBars.vue'
import CircleBars from './Widgets/CircleBars.vue'
import BarsState from './Widgets/BarsState.vue'
import ColorfulBars from './Widgets/ColorfulBars.vue'
</script>
@@ -1,60 +0,0 @@
<template>
<va-card class="bars-state">
<va-card-title>
{{ t('progressBars.state') }}
</va-card-title>
<va-card-content class="row">
<div class="flex md4 xs12">
<va-progress-bar :model-value="value2">66%</va-progress-bar>
</div>
<div class="flex md4 xs12">
<va-progress-bar :model-value="bufferValues.value" :buffer="bufferValues.buffer">Buffering </va-progress-bar>
</div>
<div class="flex md4 xs12">
<va-progress-bar indeterminate>Loading</va-progress-bar>
</div>
</va-card-content>
</va-card>
</template>
<script>
import { useI18n } from 'vue-i18n'
export default {
name: 'BarsState',
setup() {
const { t } = useI18n()
return { t }
},
data() {
return {
value2: 66,
bufferValues: {
value: 0,
buffer: 0,
},
}
},
mounted() {
this.animateValue()
this.animateBufferValues()
},
methods: {
animateValue() {
setTimeout(() => {
this.value = 100
})
},
animateBufferValues() {
const interval = setInterval(() => {
this.bufferValues.value += 2 + Math.floor(Math.random() * 2)
this.bufferValues.buffer += 2 + Math.floor(Math.random() * 4)
if (this.bufferValues.value >= 100) {
clearInterval(interval)
}
}, 400)
},
},
}
</script>
@@ -1,40 +0,0 @@
<template>
<va-card class="circle-bars">
<va-card-title>
{{ t('progressBars.circle') }}
</va-card-title>
<va-card-content class="row">
<div v-for="n in 10" :key="n" class="flex xs4 sm2 lg1">
<div class="d-flex justify-center">
<div>
<va-progress-circle :model-value="(value * n) / 10">{{ (value * n) / 10 }}%</va-progress-circle>
</div>
</div>
</div>
<div class="flex xs4 sm2 lg1">
<div class="d-flex justify-center">
<div>
<va-progress-circle indeterminate />
</div>
</div>
</div>
</va-card-content>
</va-card>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const value = ref(0)
onMounted(animateValue)
function animateValue() {
setTimeout(() => {
value.value = 100
})
}
</script>
@@ -1,35 +0,0 @@
<template>
<va-card class="colorful-bars progress-bar-widget">
<va-card-title> {{ t('progressBars.colors') }} </va-card-title>
<va-card-content class="row">
<div v-for="n in 6" :key="`pb-${n}`" class="flex md4 xs12">
<va-progress-bar :model-value="(value * n) / 6" :color="colors[n - 1]">
{{ colors[n - 1] }}
</va-progress-bar>
</div>
<div v-for="n in 6" :key="`pc-${n}`" class="flex md2 xs6">
<va-progress-circle class="ma-auto" :model-value="(value * n) / 6" :color="colors[n - 1]">
<span style="font-size: 0.625rem">
{{ colors[n - 1] }}
</span>
</va-progress-circle>
</div>
</va-card-content>
</va-card>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const value = ref(0)
const colors = ref(['danger', 'success', 'info', 'secondary', 'warning', 'textDark'])
onMounted(animateValue)
function animateValue() {
setTimeout(() => (value.value = 100))
}
</script>
@@ -1,29 +0,0 @@
<template>
<va-card class="horizontal-bars">
<va-card-title>
{{ t('progressBars.horizontal') }}
</va-card-title>
<va-card-content class="row">
<div class="flex md4 xs12">
<va-progress-bar :model-value="value / 3" />
</div>
<div class="flex md4 xs12">
<va-progress-bar :model-value="value2" />
</div>
<div class="flex md4 xs12">
<va-progress-bar :model-value="value3" />
</div>
</va-card-content>
</va-card>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const value = ref(0)
const value2 = ref(66)
const value3 = ref(100)
</script>
@@ -1,38 +0,0 @@
<template>
<div>
<data-table-actions class="mb-4" />
<data-table-sorting-pagination class="mb-4" />
<data-table-filter class="mb-4" />
<data-table-infinite-scroll class="mb-4" />
<data-table-select class="mb-4" />
<data-table-server-pagination class="mb-4" />
<data-table-empty class="mb-4" />
<data-table-loading />
</div>
</template>
<script>
import DataTableActions from './scenarios/DataTableActions.vue'
import DataTableSortingPagination from './scenarios/DataTableSortingPagination.vue'
import DataTableFilter from './scenarios/DataTableFilter.vue'
import DataTableInfiniteScroll from './scenarios/DataTableInfiniteScroll.vue'
import DataTableSelect from './scenarios/DataTableSelect.vue'
import DataTableServerPagination from './scenarios/DataTableServerPagination.vue'
import DataTableEmpty from './scenarios/DataTableEmpty.vue'
import DataTableLoading from './scenarios/DataTableLoading.vue'
export default {
components: {
DataTableActions,
DataTableSortingPagination,
DataTableFilter,
DataTableInfiniteScroll,
DataTableSelect,
DataTableServerPagination,
DataTableEmpty,
DataTableLoading,
},
}
</script>
<style lang="scss"></style>
@@ -1,386 +0,0 @@
[
{
"id": "5d2c865e9a0bae79a6ef7cfa",
"firstName": "Ashley",
"lastName": "Mcdaniel",
"fullName": "Ashley Mcdaniel",
"email": "ashleymcdaniel@nebulean.com",
"country": "Cayman Islands",
"starred": true,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "warning",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865ec73341e16e5f2251",
"firstName": "Sellers",
"lastName": "Todd",
"fullName": "Todd Sellers",
"email": "sellerstodd@nebulean.com",
"country": "Togo",
"starred": false,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "none",
"color": "primary",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e38800c5ce28f2f6b",
"firstName": "Sherman",
"lastName": "Knowles",
"fullName": "Sherman Knowles",
"email": "shermanknowles@nebulean.com",
"country": "Central African Republic",
"starred": true,
"hasReport": true,
"status": "warning",
"checked": false,
"trend": "none",
"color": "warning",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e957cd150b82e17a6",
"firstName": "Vasquez",
"lastName": "Lawson",
"fullName": "Vasquez Lawson",
"email": "vasquezlawson@nebulean.com",
"country": "Bouvet Island",
"starred": true,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "down",
"color": "warning",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e9194dbe2faf99227",
"firstName": "April",
"lastName": "Sykes",
"fullName": "April Sykes",
"email": "aprilsykes@nebulean.com",
"country": "Saint Vincent and The Grenadines",
"starred": false,
"hasReport": true,
"status": "warning",
"checked": false,
"trend": "down",
"color": "primary",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e1ed74d83f6b26934",
"firstName": "Hodges",
"lastName": "Garrison",
"fullName": "Hodges Garrison",
"email": "hodgesgarrison@nebulean.com",
"country": "Zimbabwe",
"starred": true,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "none",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e0ef31380880c3de5",
"firstName": "Therese",
"lastName": "Stokes",
"fullName": "Therese Stokes",
"email": "theresestokes@nebulean.com",
"country": "Mali",
"starred": true,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "up",
"color": "warning",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e4b5ab4727e5c8b69",
"firstName": "Goodwin",
"lastName": "Brewer",
"fullName": "Goodwin Brewer",
"email": "goodwinbrewer@nebulean.com",
"country": "Iraq",
"starred": true,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "none",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e4c4d675787cfe1c0",
"firstName": "Gomez",
"lastName": "Wise",
"fullName": "Gomez Wise",
"email": "gomezwise@nebulean.com",
"country": "Portugal",
"starred": true,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "none",
"color": "primary",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e1017c3229017fc68",
"firstName": "Laverne",
"lastName": "Ayers",
"fullName": "Laverne Ayers",
"email": "laverneayers@nebulean.com",
"country": "Micronesia",
"starred": false,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "info",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865ee66676fd7464f8b9",
"firstName": "Stewart",
"lastName": "Leon",
"fullName": "Stewart Leon",
"email": "stewartleon@nebulean.com",
"country": "Seychelles",
"starred": true,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "up",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e644d8acbed1e0e97",
"firstName": "Lindsey",
"lastName": "Hopkins",
"fullName": "Lindsey Hopkins",
"email": "lindseyhopkins@nebulean.com",
"country": "Costa Rica",
"starred": false,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "up",
"color": "primary",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865ef2b732c74dc3d6a2",
"firstName": "Head",
"lastName": "Lloyd",
"fullName": "Head Lloyd",
"email": "headlloyd@nebulean.com",
"country": "Turkey",
"starred": true,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e4ee4f09e92ead2e7",
"firstName": "Fisher",
"lastName": "Bradford",
"fullName": "Fisher Bradford",
"email": "fisherbradford@nebulean.com",
"country": "Ethiopia",
"starred": true,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "up",
"color": "info",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e88d46a9e9049a549",
"firstName": "Aurora",
"lastName": "Bird",
"fullName": "Aurora Bird",
"email": "aurorabird@nebulean.com",
"country": "Burkina Faso",
"starred": false,
"hasReport": true,
"status": "warning",
"checked": false,
"trend": "up",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e44bf14ea96d6e752",
"firstName": "Bonita",
"lastName": "Shields",
"fullName": "Bonita Shields",
"email": "bonitashields@nebulean.com",
"country": "Cote D'Ivoire (Ivory Coast)",
"starred": true,
"hasReport": true,
"status": "warning",
"checked": false,
"trend": "down",
"color": "primary",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e2a8be26f6ac4369c",
"firstName": "Ethel",
"lastName": "Underwood",
"fullName": "Ethel Underwood",
"email": "ethelunderwood@nebulean.com",
"country": "Vanuatu",
"starred": false,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e5e0aea40111c37f8",
"firstName": "Parker",
"lastName": "May",
"fullName": "Parker May",
"email": "parkermay@nebulean.com",
"country": "Pakistan",
"starred": true,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "warning",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e7e0c05ecc2d0c186",
"firstName": "Hillary",
"lastName": "Waters",
"fullName": "Hillary Waters",
"email": "hillarywaters@nebulean.com",
"country": "Comoros",
"starred": true,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "down",
"color": "primary",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e80a72eeda016b169",
"firstName": "Raquel",
"lastName": "Ferrell",
"fullName": "Raquel Ferrell",
"email": "raquelferrell@nebulean.com",
"country": "China",
"starred": false,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "info",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865eafacadd378add679",
"firstName": "Pickett",
"lastName": "Page",
"fullName": "Pickett Page",
"email": "pickettpage@nebulean.com",
"country": "Bermuda",
"starred": true,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "up",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e772b1a75bb0a07b5",
"firstName": "Alyson",
"lastName": "Bailey",
"fullName": "Alyson Bailey",
"email": "alysonbailey@nebulean.com",
"country": "United Arab Emirates",
"starred": false,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "up",
"color": "warning",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e137c19a76b56210c",
"firstName": "Farley",
"lastName": "Meyers",
"fullName": "Farley Meyers",
"email": "farleymeyers@nebulean.com",
"country": "Christmas Island",
"starred": false,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "up",
"color": "warning",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865eb0ba37a27aa9afe0",
"firstName": "Hinton",
"lastName": "Avery",
"fullName": "Hinton Avery",
"email": "hintonavery@nebulean.com",
"country": "Liechtenstein",
"starred": false,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "up",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
}
]
@@ -1,69 +0,0 @@
<template>
<va-card :title="t('tables.labelsActions')">
<va-data-table :fields="fields" :data="users" no-pagination>
<template #marker="props">
<va-icon name="fa fa-circle" :color="props.rowData.color" size="8px" />
</template>
<template #actions="props">
<va-button preset="plain" small color="gray" class="ma-0" @click="edit(props.rowData)">
{{ t('tables.edit') }}
</va-button>
<va-button preset="plain" small color="danger" class="ma-0" @click="remove(props.rowData)">
{{ t('tables.delete') }}
</va-button>
</template>
</va-data-table>
</va-card>
</template>
<script>
import users from '../data/users.json'
export default {
data() {
return {
users: users.slice(0, 6),
}
},
computed: {
fields() {
return [
{
name: '__slot:marker',
width: '30px',
dataClass: 'text-center',
},
{
name: 'fullName',
title: this.t('tables.headings.name'),
},
{
name: 'email',
title: this.t('tables.headings.email'),
},
{
name: 'country',
title: this.t('tables.headings.country'),
},
{
name: '__slot:actions',
dataClass: 'va-text-right',
},
]
},
},
methods: {
edit(user) {
alert('Edit User: ' + JSON.stringify(user))
},
remove(user) {
const idx = this.users.findIndex((u) => u.id === user.id)
this.users.splice(idx, 1)
},
},
}
</script>
<style lang="scss"></style>
@@ -1,35 +0,0 @@
<template>
<va-card :title="t('tables.emptyTable')">
<va-data-table :fields="fields" :data="data" :no-data-label="t('tables.noReport')" no-pagination />
</va-card>
</template>
<script>
export default {
data() {
return {
data: [],
}
},
computed: {
fields() {
return [
{
name: 'fullName',
title: this.t('tables.headings.name'),
},
{
name: 'email',
title: this.t('tables.headings.email'),
},
{
name: 'country',
title: this.t('tables.headings.country'),
},
]
},
},
}
</script>
<style lang="scss"></style>
@@ -1,127 +0,0 @@
<template>
<va-card :title="t('tables.searchTrendsBadges')">
<div class="row align--center">
<div class="flex xs12 md6">
<va-input :value="term" :placeholder="t('tables.searchByName')" removable @input="search">
<template #prepend>
<va-icon name="search" />
</template>
</va-input>
</div>
<div class="flex xs12 md3 offset--md3">
<va-select v-model="perPage" :label="t('tables.perPage')" :options="perPageOptions" no-clear />
</div>
</div>
<va-data-table
:fields="fields"
:data="filteredData"
:per-page="parseInt(perPage)"
clickable
@row-clicked="showUser"
>
<template #trend="props">
<va-icon :name="getTrendIcon(props.rowData)" :color="getTrendColor(props.rowData)" />
</template>
<template #status="props">
<va-badge :color="props.rowData.color">
{{ props.rowData.status }}
</va-badge>
</template>
<template #actions="props">
<va-button v-if="props.rowData.hasReport" small color="danger" class="ma-0">
{{ t('tables.report') }}
</va-button>
</template>
</va-data-table>
</va-card>
</template>
<script>
import { debounce } from 'lodash'
import users from '../data/users.json'
export default {
data() {
return {
term: null,
perPage: '6',
perPageOptions: ['4', '6', '10', '20'],
users: users,
}
},
computed: {
fields() {
return [
{
name: '__slot:trend',
width: '30px',
height: '45px',
dataClass: 'text-center',
},
{
name: 'fullName',
title: this.t('tables.headings.name'),
width: '30%',
},
{
name: '__slot:status',
title: this.t('tables.headings.status'),
width: '20%',
},
{
name: 'email',
title: this.t('tables.headings.email'),
width: '30%',
},
{
name: '__slot:actions',
dataClass: 'va-text-right',
},
]
},
filteredData() {
if (!this.term || this.term.length < 1) {
return this.users
}
return this.users.filter((item) => {
return item.fullName.toLowerCase().startsWith(this.term.toLowerCase())
})
},
},
methods: {
getTrendIcon(user) {
if (user.trend === 'up') {
return 'fa fa-caret-up'
}
if (user.trend === 'down') {
return 'fa fa-caret-down'
}
return 'fa fa-minus'
},
getTrendColor(user) {
if (user.trend === 'up') {
return 'primary'
}
if (user.trend === 'down') {
return 'danger'
}
return 'gray'
},
showUser(user) {
alert(JSON.stringify(user))
},
search: debounce(function (term) {
this.term = term
}, 400),
},
}
</script>
@@ -1,99 +0,0 @@
<!--<template>-->
<!-- <va-card :title="t('tables.infiniteScroll')">-->
<!-- <div ref="scrollable" class="data-table-infinite-scroll&#45;&#45;container" @scroll="onScroll">-->
<!-- <va-data-table :fields="fields" :data="users" api-mode no-pagination>-->
<!-- <template #marker="props">-->
<!-- <va-icon name="fa fa-circle" :color="props.rowData.color" size="8px" />-->
<!-- </template>-->
<!-- </va-data-table>-->
<!-- <div class="justify-center ma-3">-->
<!-- <spring-spinner v-if="loading" :animation-duration="2000" :size="60" :color="theme.variables.primary" />-->
<!-- </div>-->
<!-- </div>-->
<!-- </va-card>-->
<!--</template>-->
<!--<script>-->
<!-- // import { SpringSpinner } from 'epic-spinners'-->
<!-- import users from '../data/users.json'-->
<!-- import { useGlobalConfig } from 'vuestic-ui'-->
<!-- import { defineComponent } from 'vue'-->
<!-- export default {-->
<!-- components: {-->
<!-- SpringSpinner: defineComponent({ template: '<div>LOADER PLACEHOLDER</div>' }),-->
<!-- },-->
<!-- data() {-->
<!-- return {-->
<!-- users: [],-->
<!-- loading: false,-->
<!-- offset: 0,-->
<!-- }-->
<!-- },-->
<!-- computed: {-->
<!-- theme() {-->
<!-- return useGlobalConfig().getGlobalConfig().colors-->
<!-- },-->
<!-- fields() {-->
<!-- return [-->
<!-- {-->
<!-- name: '__slot:marker',-->
<!-- width: '30px',-->
<!-- dataClass: 'text-center',-->
<!-- },-->
<!-- {-->
<!-- name: 'fullName',-->
<!-- title: this.t('tables.headings.name'),-->
<!-- },-->
<!-- {-->
<!-- name: 'email',-->
<!-- title: this.t('tables.headings.email'),-->
<!-- },-->
<!-- {-->
<!-- name: 'country',-->
<!-- title: this.t('tables.headings.country'),-->
<!-- },-->
<!-- ]-->
<!-- },-->
<!-- },-->
<!-- created() {-->
<!-- this.loadMore()-->
<!-- },-->
<!-- methods: {-->
<!-- loadMore() {-->
<!-- this.loading = true-->
<!-- this.readUsers().then((users) => {-->
<!-- this.users = this.users.concat(users)-->
<!-- this.loading = false-->
<!-- })-->
<!-- },-->
<!-- readUsers() {-->
<!-- return new Promise((resolve) => {-->
<!-- setTimeout(() => {-->
<!-- resolve(users.slice(0, 10))-->
<!-- }, 600)-->
<!-- })-->
<!-- },-->
<!-- onScroll(e) {-->
<!-- if (this.loading) {-->
<!-- return-->
<!-- }-->
<!-- const { target } = e-->
<!-- if (target.offsetHeight + target.scrollTop === target.scrollHeight) {-->
<!-- this.loadMore()-->
<!-- }-->
<!-- },-->
<!-- },-->
<!-- }-->
<!--</script>-->
<!--<style lang="scss">-->
<!-- .data-table-infinite-scroll&#45;&#45;container {-->
<!-- height: 300px;-->
<!-- overflow-y: auto;-->
<!-- }-->
<!--</style>-->
@@ -1,37 +0,0 @@
<template>
<va-card :title="t('tables.loading')">
<va-data-table :fields="fields" :data="users" loading />
</va-card>
</template>
<script>
import users from '../data/users.json'
export default {
data() {
return {
users: users,
}
},
computed: {
fields() {
return [
{
name: 'fullName',
title: this.t('tables.headings.name'),
},
{
name: 'email',
title: this.t('tables.headings.email'),
},
{
name: 'country',
title: this.t('tables.headings.country'),
},
]
},
},
}
</script>
<style lang="scss"></style>
@@ -1,66 +0,0 @@
<template>
<va-card :title="t('tables.selectable')">
<va-data-table :fields="fields" :data="users" :per-page="5">
<template #select="props">
<va-checkbox :value="props.rowData.checked" @input="select(props.rowData)" />
</template>
<template #graph="props">
<svg width="100" height="40" xmlns="http://www.w3.org/2000/svg">
<path :d="props.rowData.graph" :stroke="props.rowData.graphColor" fill="transparent" />
</svg>
</template>
</va-data-table>
<p v-if="selected.length">{{ t('tables.selected') }}: {{ selected.map((user) => user.fullName).join(', ') }}.</p>
</va-card>
</template>
<script>
import users from '../data/users.json'
export default {
data() {
return {
users: users.slice(),
}
},
computed: {
fields() {
return [
{
name: '__slot:select',
},
{
name: 'fullName',
title: this.t('tables.headings.name'),
width: '20%',
},
{
name: 'email',
title: this.t('tables.headings.email'),
width: '30%',
},
{
name: 'country',
title: this.t('tables.headings.country'),
width: '30%',
},
{
name: '__slot:graph',
dataClass: 'va-text-right',
},
]
},
selected() {
return this.users.filter((user) => user.checked)
},
},
methods: {
select(user) {
const idx = this.users.findIndex((u) => u.id === user.id)
this.users[idx].checked = !this.users[idx].checked
},
},
}
</script>
@@ -1,82 +0,0 @@
<template>
<va-card :title="t('tables.serverSidePagination')">
<va-data-table
:fields="fields"
:data="items"
:loading="loading"
:total-pages="totalPages"
api-mode
@page-selected="readItems"
>
<template #avatar="props">
<img :src="props.rowData.avatar" class="data-table-server-pagination---avatar" />
</template>
</va-data-table>
</va-card>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
perPage: 3,
totalPages: 0,
items: [],
loading: false,
}
},
computed: {
fields() {
return [
{
name: '__slot:avatar',
width: '60px',
},
{
name: 'first_name',
title: this.t('tables.headings.firstName'),
width: '20%',
},
{
name: 'last_name',
title: this.t('tables.headings.lastName'),
width: '20%',
},
{
name: 'email',
title: this.t('tables.headings.email'),
},
]
},
},
created() {
this.readItems()
},
methods: {
readItems(page = 0) {
this.loading = true
const params = {
per_page: this.perPage,
page: page,
}
axios.get('https://reqres.in/api/users', { params }).then((response) => {
this.items = response.data.data
this.totalPages = response.data.total_pages
this.loading = false
})
},
},
}
</script>
<style lang="scss">
.data-table-server-pagination---avatar {
width: 40px;
height: 40px;
border-radius: 50%;
}
</style>
@@ -1,79 +0,0 @@
<template>
<va-card :title="t('tables.sortingPaginationActionsAsIcons')">
<va-data-table :fields="fields" :data="users" :per-page="5">
<template #actions="props">
<va-popover :message="getStarMessage(props.rowData)" placement="top">
<va-button
preset="plain"
small
:color="getStarColor(props.rowData)"
icon="fa fa-star"
@click="star(props.rowData)"
/>
</va-popover>
<va-popover :message="`${t('tables.edit')} ${props.rowData.fullName}`" placement="top">
<va-button preset="plain" small color="gray" icon="fa fa-pencil" />
</va-popover>
<va-popover :message="`${t('tables.delete')} ${props.rowData.fullName}`" placement="top">
<va-button preset="plain" small color="gray" icon="fa fa-trash" />
</va-popover>
</template>
</va-data-table>
</va-card>
</template>
<script>
import users from '../data/users.json'
export default {
data() {
return {
users: users.slice(),
}
},
computed: {
fields() {
return [
{
name: 'fullName',
title: this.t('tables.headings.name'),
sortField: 'fullName',
width: '25%',
},
{
name: 'email',
title: this.t('tables.headings.email'),
width: '30%',
},
{
name: 'country',
title: this.t('tables.headings.country'),
sortField: 'country',
width: '25%',
},
{
name: '__slot:actions',
dataClass: 'va-text-right',
},
]
},
},
methods: {
getStarMessage(user) {
const actionName = user.starred ? this.t('tables.unstar') : this.t('tables.star')
return `${actionName} ${user.fullName}`
},
getStarColor(user) {
return user.starred ? 'primary' : 'gray'
},
star({ id }) {
const i = this.users.findIndex((user) => user.id === id)
this.users[i].starred = !this.users[i].starred
},
},
}
</script>
<style lang="scss"></style>
@@ -1,95 +0,0 @@
<template>
<div class="markup-tables flex">
<va-card class="flex mb-4">
<va-card-title>{{ t('tables.basic') }}</va-card-title>
<va-card-content>
<div class="table-wrapper">
<table class="va-table">
<thead>
<tr>
<th>{{ t('tables.headings.name') }}</th>
<th>{{ t('tables.headings.email') }}</th>
<th>{{ t('tables.headings.country') }}</th>
<th>{{ t('tables.headings.status') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="user in users" :key="user.id">
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
<td>{{ user.country }}</td>
<td>
<va-badge :text="user.status" :color="getStatusColor(user.status)" />
</td>
</tr>
</tbody>
</table>
</div>
</va-card-content>
</va-card>
<va-card>
<va-card-title>{{ t('tables.stripedHoverable') }}</va-card-title>
<va-card-content>
<div class="table-wrapper">
<table class="va-table va-table--striped va-table--hoverable">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Country</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr v-for="user in users" :key="user.id">
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
<td>{{ user.country }}</td>
<td>
<va-badge :text="user.status" :color="getStatusColor(user.status)" />
</td>
</tr>
</tbody>
</table>
</div>
</va-card-content>
</va-card>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import data from '../../../../data/tables/markup-table/data.json'
const { t } = useI18n()
const users = ref(data.slice(0, 8))
function getStatusColor(status: string) {
if (status === 'paid') {
return 'success'
}
if (status === 'processing') {
return 'info'
}
return 'danger'
}
</script>
<style lang="scss">
.markup-tables {
.table-wrapper {
overflow: auto;
}
.va-table {
width: 100%;
}
}
</style>
-303
View File
@@ -1,303 +0,0 @@
<template>
<div class="buttons">
<div class="row">
<div class="flex xs12">
<va-card class="larger-padding">
<va-card-title>{{ t('buttons.types') }}</va-card-title>
<va-card-content class="row">
<div class="flex">
<va-button class="mr-2 mb-2"> {{ t('buttons.default') }}</va-button>
<va-button class="mr-2 mb-2" disabled> {{ t('buttons.disabled') }}</va-button>
<va-button class="mr-2 mb-2" preset="outline" border-color="primary" color="primary">
{{ t('buttons.outline') }}</va-button
>
<va-button class="mr-2 mb-2" preset="outline" border-color="primary" color="primary" disabled>
{{ t('buttons.disabled') }}</va-button
>
<va-button class="mr-2 mb-2" preset="plain"> {{ t('buttons.flat') }}</va-button>
<va-button class="mr-2 mb-2" preset="plain" disabled> {{ t('buttons.disabled') }}</va-button>
</div>
</va-card-content>
</va-card>
</div>
<div class="flex xs12">
<va-card class="larger-padding">
<va-card-title>{{ t('buttons.size') }}</va-card-title>
<va-card-content class="row">
<div class="flex">
<va-button class="mr-2 mb-2" size="small"> {{ t('buttons.small') }}</va-button>
<va-button class="mr-2 mb-2"> {{ t('buttons.normal') }}</va-button>
<va-button class="mr-2 mb-2" size="large"> {{ t('buttons.large') }}</va-button>
</div>
</va-card-content>
</va-card>
</div>
<div class="flex xs12">
<va-card class="larger-padding">
<va-card-title>{{ t('buttons.tags') }}</va-card-title>
<va-card-content class="row">
<div class="flex">
<va-button class="mr-2 mb-2"> {{ t('buttons.button') }}</va-button>
<va-button class="mr-2 mb-2" href="http://epic-spinners.epicmax.co/">
{{ t('buttons.a-link') }}
</va-button>
<va-button class="mr-2 mb-2" :to="{ name: 'charts' }">
{{ t('buttons.router-link') }}
</va-button>
</div>
</va-card-content>
</va-card>
</div>
<div class="flex xs12">
<va-card class="larger-padding">
<va-card-title>{{ t('buttons.advanced') }}</va-card-title>
<va-card-content class="row">
<div class="flex">
<va-button class="mr-2 mb-2" icon="md_close"> {{ t('buttons.button') }}</va-button>
<va-button class="mr-2 mb-2" icon-right="expand_more"> {{ t('buttons.button') }}</va-button>
<va-button class="mr-2 mb-2" icon="md_close" icon-right="expand_more">
{{ t('buttons.button') }}
</va-button>
<va-button class="mr-2 mb-2" icon="md_close" />
</div>
</va-card-content>
</va-card>
</div>
<div class="flex xs12">
<va-card class="larger-padding">
<va-card-title>{{ t('buttons.colors') }}</va-card-title>
<va-card-content>
<div class="row">
<div class="flex">
<va-button class="mr-2 mb-2" color="danger"> {{ t('buttons.danger') }}</va-button>
<va-button class="mr-2 mb-2" color="info"> {{ t('buttons.info') }}</va-button>
<va-button class="mr-2 mb-2" color="dark"> {{ t('buttons.dark') }}</va-button>
<va-button class="mr-2 mb-2" color="warning"> {{ t('buttons.warning') }}</va-button>
<va-button class="mr-2 mb-2" color="success"> {{ t('buttons.success') }}</va-button>
<va-button class="mr-2 mb-2" color="gray"> {{ t('buttons.gray') }}</va-button>
</div>
</div>
<div class="row">
<div class="flex">
<va-button class="mr-2 mb-2" preset="outline" border-color="danger" color="danger">
{{ t('buttons.danger') }}</va-button
>
<va-button class="mr-2 mb-2" preset="outline" border-color="info" color="info">
{{ t('buttons.info') }}</va-button
>
<va-button class="mr-2 mb-2" preset="outline" border-color="dark" color="dark">
{{ t('buttons.dark') }}</va-button
>
<va-button class="mr-2 mb-2" preset="outline" border-color="warning" color="warning">
{{ t('buttons.warning') }}</va-button
>
<va-button class="mr-2 mb-2" preset="outline" border-color="success" color="success">
{{ t('buttons.success') }}</va-button
>
<va-button class="mr-2 mb-2" preset="outline" border-color="gray" color="gray">
{{ t('buttons.gray') }}</va-button
>
</div>
</div>
<div class="row">
<div class="flex">
<va-button class="mr-2 mb-2" preset="plain" color="danger"> {{ t('buttons.danger') }}</va-button>
<va-button class="mr-2 mb-2" preset="plain" color="info"> {{ t('buttons.info') }}</va-button>
<va-button class="mr-2 mb-2" preset="plain" color="dark"> {{ t('buttons.dark') }}</va-button>
<va-button class="mr-2 mb-2" preset="plain" color="warning"> {{ t('buttons.warning') }}</va-button>
<va-button class="mr-2 mb-2" preset="plain" color="success"> {{ t('buttons.success') }}</va-button>
<va-button class="mr-2 mb-2" preset="plain" color="gray"> {{ t('buttons.gray') }}</va-button>
</div>
</div>
</va-card-content>
</va-card>
</div>
<div class="flex xs12">
<va-card class="larger-padding">
<va-card-title>{{ t('buttons.buttonGroups') }}</va-card-title>
<va-card-content>
<div class="row">
<div class="flex xs12 xl6">
<va-button-group color="secondary">
<va-button size="large"> One</va-button>
<va-button size="large"> Two</va-button>
<va-button size="large"> Three</va-button>
</va-button-group>
</div>
<div class="flex xs12 xl6">
<va-button-group preset="outline" border-color="danger" color="danger">
<va-button icon="maki-art-gallery">One</va-button>
<va-button>Two</va-button>
<va-button>Three</va-button>
</va-button-group>
</div>
<div class="flex xs12 xl6">
<va-button-group preset="plain" color="gray">
<va-button icon="ion-ios-mail">One</va-button>
<va-button icon="entypo-user">Two</va-button>
<va-button icon="ion-ios-alarm">Three</va-button>
</va-button-group>
</div>
<div class="flex xs12 xl6">
<va-button-group color="dark">
<va-button> One</va-button>
<va-button> Two</va-button>
<va-button> Three</va-button>
<va-button icon="ion-ios-arrow-down" />
</va-button-group>
</div>
<div class="flex xs12 xl6">
<va-button-group preset="outline" border-color="primary" color="primary" size="large">
<va-button>First</va-button>
<va-button icon-right="glyphicon-pencil">Second</va-button>
<va-button>Third</va-button>
</va-button-group>
</div>
<div class="flex xs12 xl6">
<va-button-group preset="plain" size="small" color="warning">
<va-button icon="glyphicon-envelope" />
<va-button icon="entypo-user" />
<va-button icon="ion-ios-alarm" />
</va-button-group>
</div>
</div>
</va-card-content>
</va-card>
</div>
<div class="flex xs12">
<va-card class="larger-padding">
<va-card-title>{{ t('buttons.buttonToggles') }}</va-card-title>
<va-card-content>
<div class="row">
<div class="flex xs12 lg6">
<va-button-toggle v-model="model" :options="options" />
</div>
<div class="flex xs12 lg6">
<va-button-toggle
v-model="model"
preset="outline"
:options="options"
border-color="danger"
color="danger"
/>
</div>
<div class="flex xs12 lg6">
<va-button-toggle v-model="model" preset="plain" :options="options" color="gray" />
</div>
<div class="flex xs12 lg6">
<va-button-toggle v-model="model" :options="options" color="dark" />
</div>
<div class="flex xs12 lg6">
<va-button-toggle
v-model="model"
preset="outline"
:options="options"
border-color="info"
color="info"
/>
</div>
<div class="flex xs12 lg6">
<va-button-toggle v-model="model" preset="plain" :options="options" color="warning" />
</div>
</div>
</va-card-content>
</va-card>
</div>
<div class="flex xs12">
<va-card class="larger-padding">
<va-card-title>{{ t('buttons.pagination') }}</va-card-title>
<va-card-content>
<div class="row">
<div class="flex xs12 xl6">
<va-pagination v-model="activePage" :visible-pages="3" :pages="20" />
</div>
<div class="flex xs12 xl6">
<va-pagination v-model="activePage" :visible-pages="4" :pages="15" color="danger" />
</div>
<div class="flex xs12 xl6">
<va-pagination v-model="activePage" :pages="5" disabled />
</div>
<div class="flex xs12 xl6">
<va-pagination
v-model="activePage"
:pages="10"
:visible-pages="3"
:icon="{ boundary: 'bell_slash', direction: 'volume_off' }"
:icon-right="{ boundary: 'bell', direction: 'volume_up' }"
color="success"
/>
</div>
</div>
</va-card-content>
</va-card>
</div>
<div class="flex xs12">
<va-card class="larger-padding">
<va-card-title>{{ t('buttons.buttonsDropdown') }}</va-card-title>
<va-card-content>
<div class="row">
<div class="flex">
<va-button-dropdown class="mr-2 mb-2" :label="t('buttons.default')">
{{ t('buttons.content') }}</va-button-dropdown
>
<va-button-dropdown class="mr-2 mb-2" split :label="t('buttons.split')">
{{ t('buttons.content') }}</va-button-dropdown
>
<va-button-dropdown class="mr-2 mb-2" split split-to="/" :label="t('buttons.splitTo')">
{{ t('buttons.content') }}</va-button-dropdown
>
<va-button-dropdown
class="mr-2 mb-2"
:label="t('buttons.customIcon')"
icon="info"
opened-icon="bell_slash"
>
{{ t('buttons.content') }}
</va-button-dropdown>
<va-button-dropdown class="mr-2 mb-2" disabled :label="t('buttons.disabled')">
{{ t('buttons.content') }}</va-button-dropdown
>
<va-button-dropdown class="mr-2 mb-2" color="warning" :label="t('buttons.warning')">
{{ t('buttons.content') }}</va-button-dropdown
>
</div>
</div>
</va-card-content>
</va-card>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const options = ref([
{ label: 'One', value: 'one' },
{ label: 'Two', value: 'two' },
{ label: 'Three', value: 'three' },
])
const model = ref('three')
const activePage = ref(4)
</script>
<style lang="scss">
.va-card__content {
& > .row {
overflow-x: auto;
}
}
.va-button-dropdown {
display: inline-block;
}
</style>
-138
View File
@@ -1,138 +0,0 @@
<template>
<div class="cards">
<div class="cards-container row d-flex wrap align--start">
<template v-for="loop in listLoops" :key="loop + '-0'">
<div class="flex xs12 sm6 md6 xl6">
<va-card>
<va-card-title>{{ t('cards.title.default') }}</va-card-title>
<va-card-content>{{ t('cards.contentTextLong') }}</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md6 xl6">
<va-card>
<va-card-title>
{{ t('cards.title.withControls') }}
<va-spacer />
<va-button class="mr-1" size="small" icon="refresh" />
<va-button size="small" icon="gear" />
</va-card-title>
<va-card-content>{{ t('cards.contentTextLong') }}</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md6 xl6">
<va-card>
<va-card-title>
<va-icon class="mr-3" name="cogs" />
{{ t('cards.title.customHeader') }}
</va-card-title>
<va-card-content>{{ t('cards.contentTextLong') }}</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md6 xl6">
<va-card>
<va-card-content>
<p>{{ t('cards.title.withoutHeader') }}</p>
{{ t('cards.contentTextLong') }}
</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md3 xl3 lg3 xl3">
<va-card>
<va-image src="https://picsum.photos/300/200/?image=1043" style="height: 200px" />
<va-card-title>{{ t('cards.title.withImage') }}</va-card-title>
<va-card-content>{{ t('cards.contentText') }}</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md3 xl3 lg3 xl3">
<va-card>
<va-image src="https://picsum.photos/300/200/?image=898" style="height: 200px">
<va-card-title text-color="#fff">{{ t('cards.title.withTitleOnImage') }}</va-card-title>
</va-image>
<va-card-content>{{ t('cards.contentText') }}</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md3 xl3 lg3 xl3">
<va-card>
<va-image src="https://picsum.photos/300/200/?image=898" style="height: 200px">
<va-button class="ma-0">
{{ t('cards.button.readMore') }}
</va-button>
</va-image>
</va-card>
</div>
<div class="flex xs12 sm6 md3 xl3 lg3 xl3">
<va-card stripe stripe-color="danger">
<va-card-title>{{ t('cards.title.withStripe') }}</va-card-title>
<va-card-content>{{ t('cards.contentTextLong') }}</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md3 xl3 lg3 xl3">
<va-card color="success">
<va-card-content>{{ t('cards.contentTextLong') }}</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md3 xl3 lg3 xl3">
<va-card color="danger">
<va-card-content>{{ t('cards.contentTextLong') }}</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md3 xl3 lg3 xl3">
<va-card stripe stripe-color="info">
<va-card-title>{{ t('cards.title.withStripe') }}</va-card-title>
<va-card-content>{{ t('cards.contentTextLong') }}</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md3 xl3 lg3 xl3">
<va-card>
<va-image src="https://picsum.photos/300/200/?image=1067" style="height: 200px">
<va-card-title text-color="#fff">{{ t('cards.title.withTitleOnImage') }}</va-card-title>
</va-image>
<va-card-content>{{ t('cards.contentText') }}</va-card-content>
</va-card>
</div>
</template>
</div>
<va-inner-loading class="justify-center py-3" style="width: 100%" :loading="isLoading">
<va-button @click="addCards()">
{{ t('cards.button.showMore') }}
</va-button>
</va-inner-loading>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const listLoops = ref(1)
const isLoading = ref(false)
function addCards() {
isLoading.value = true
setTimeout(() => {
isLoading.value = false
++listLoops.value
}, 1000)
}
</script>
<style lang="scss">
.cards-container {
.va-card {
margin: 0;
}
}
</style>
-158
View File
@@ -1,158 +0,0 @@
<template>
<div class="va-chat">
<div
v-sticky-scroll="{
animate: true,
duration: 500,
}"
class="va-chat__body"
:style="{ height: height }"
>
<div
v-for="(message, index) in modelValue"
:key="index"
class="va-chat__message"
:style="{
backgroundColor: message.yours ? colors.primary : undefined,
}"
:class="{ 'va-chat__message--yours': message.yours }"
>
<span class="va-chat__message-text">
{{ message.text }}
</span>
</div>
</div>
<div class="va-chat__controls">
<va-input
v-model="inputMessage"
placeholder="Type your message..."
class="va-chat__input mr-2"
@keypress.enter="sendMessage"
/>
<va-button @click="sendMessage()">
{{ t('chat.sendButton') }}
</va-button>
</div>
</div>
</template>
<script setup lang="ts">
import vStickyScroll from './StickyScroll'
import { useColors } from 'vuestic-ui'
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
const { colors } = useColors()
const { t } = useI18n()
const props = withDefaults(
defineProps<{
modelValue?: { text: string; yours: boolean }[]
height?: string
}>(),
{
modelValue: () => [
{
text: 'Hello! So glad you liked my work. Do you want me to shoot you?',
yours: false,
},
{
text: 'Yeah, that would be cool. Maybe this Sunday at 3 pm?',
yours: true,
},
{
text: 'Sounds great! See you later!',
yours: false,
},
{
text: 'Should I bring a lightbox with me?',
yours: true,
},
{
text: 'No, thanks. There is no need. Can we set up a meeting earlier?',
yours: false,
},
{
text: "I'm working on Vuestic, so let's meet at 3pm. Thanks!",
yours: true,
},
],
height: '20rem',
},
)
const emit = defineEmits<{
(e: 'update:modelValue', payload: { text: string; yours: boolean }[]): void
}>()
const inputMessage = ref('')
function sendMessage() {
if (!inputMessage.value) {
return
}
emit('update:modelValue', props.modelValue.concat({ text: inputMessage.value, yours: true }))
inputMessage.value = ''
}
</script>
<style lang="scss" scoped>
// .chat {
// &__content {
// @include va-justify-center();
// }
// }
$chat-message-br: 0.875rem;
.va-chat {
width: 100%;
&__body {
min-height: 18.75rem;
display: flex;
flex-direction: column;
margin-bottom: 1.5rem;
overflow-y: auto;
}
&__message {
position: relative;
padding: 0.657rem 1.375rem;
margin-bottom: 0.625rem;
max-width: 70%;
overflow-wrap: break-word;
border-radius: 0.5rem;
border-top-left-radius: 0;
align-self: flex-start;
// background-color: $light-gray2;
&-text {
display: block;
transform: translateY(-2px);
}
&:last-child {
margin-bottom: 0;
}
&--yours {
color: white;
align-self: flex-end;
border-top-right-radius: 0;
border-top-left-radius: 0.5rem;
}
}
&__controls {
display: flex;
align-items: center;
}
&__input {
flex-grow: 1;
margin-bottom: 0;
}
}
</style>
-50
View File
@@ -1,50 +0,0 @@
<template>
<div class="chat">
<div class="row">
<div class="flex xs12 md12">
<va-card>
<va-card-title>{{ t('chat.title') }}</va-card-title>
<va-card-content>
<chat v-model="chatMessages" />
</va-card-content>
</va-card>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import Chat from './Chat.vue'
import { useI18n } from 'vue-i18n'
import { ref } from 'vue'
const { t } = useI18n()
const chatMessages = ref([
{
text: 'Hello! So glad you liked my work. Do you want me to shoot you?',
yours: false,
},
{
text: 'Yeah, that would be cool. Maybe this Sunday at 3 pm?',
yours: true,
},
{
text: 'Sounds great! See you later!',
yours: false,
},
{
text: 'Should I bring a lightbox with me?',
yours: true,
},
{
text: 'No, thanks. There is no need. Can we set up a meeting earlier?',
yours: false,
},
{
text: "I'm working on Vuestic, so let's meet at 3pm. Thanks!",
yours: true,
},
])
</script>
<style lang="scss"></style>
-52
View File
@@ -1,52 +0,0 @@
import { Directive, DirectiveBinding } from '@vue/runtime-core'
const directive: Directive = {
mounted: (el: HTMLElement, binding: DirectiveBinding) => {
const duration = binding.value.duration || 500
const isAnimated = binding.value.animate
const animateScroll = (duration: number) => {
const start = el.scrollTop
const end = el.scrollHeight
const change = end - start
const increment = 20
function easeInOut(currentTime: number, start: number, change: number, duration: number) {
currentTime /= duration / 2
if (currentTime < 1) {
return (change / 2) * currentTime * currentTime + start
}
currentTime -= 1
return (-change / 2) * (currentTime * (currentTime - 2) - 1) + start
}
function animate(elapsedTime: number) {
elapsedTime += increment
const position = easeInOut(elapsedTime, start, change, duration)
el.scrollTop = position
if (elapsedTime < duration) {
setTimeout(() => {
animate(elapsedTime)
}, increment)
}
}
animate(0)
}
const scrollToBottom = () => {
if (isAnimated) {
animateScroll(duration)
} else {
el.scrollTop = el.scrollHeight
}
}
const observer = new MutationObserver(scrollToBottom)
const config = { childList: true }
observer.observe(el, config)
},
}
export default directive
-76
View File
@@ -1,76 +0,0 @@
<template>
<div class="row">
<div class="flex xs12">
<va-card>
<va-card-title>{{ t('chips.chips.title') }}</va-card-title>
<va-card-content class="row">
<div class="flex xs12">
<div class="row">
<div class="flex xs12">
<va-chip shadow class="mb-2 mr-2" color="primary">{{ t('chips.chips.primary') }}</va-chip>
<va-chip shadow class="mb-2 mr-2" color="secondary">{{ t('chips.chips.secondary') }}</va-chip>
<va-chip shadow class="mb-2 mr-2" color="success">{{ t('chips.chips.success') }}</va-chip>
<va-chip shadow class="mb-2 mr-2" color="info">{{ t('chips.chips.info') }}</va-chip>
<va-chip shadow class="mb-2 mr-2" color="danger">{{ t('chips.chips.danger') }}</va-chip>
<va-chip shadow class="mb-2 mr-2" color="warning">{{ t('chips.chips.warning') }}</va-chip>
<va-chip shadow class="mb-2 mr-2" color="gray">{{ t('chips.chips.gray') }}</va-chip>
<va-chip shadow class="mb-2 mr-2" color="dark">{{ t('chips.chips.dark') }}</va-chip>
</div>
</div>
<div class="row">
<div class="flex xs12">
<va-chip outline class="mb-2 mr-2" color="primary">{{ t('chips.chips.primary') }}</va-chip>
<va-chip outline class="mb-2 mr-2" color="secondary">{{ t('chips.chips.secondary') }}</va-chip>
<va-chip outline class="mb-2 mr-2" color="success">{{ t('chips.chips.success') }}</va-chip>
<va-chip outline class="mb-2 mr-2" color="info">{{ t('chips.chips.info') }}</va-chip>
<va-chip outline class="mb-2 mr-2" color="danger">{{ t('chips.chips.danger') }}</va-chip>
<va-chip outline class="mb-2 mr-2" color="warning">{{ t('chips.chips.warning') }}</va-chip>
<va-chip outline class="mb-2 mr-2" color="gray">{{ t('chips.chips.gray') }}</va-chip>
<va-chip outline class="mb-2 mr-2" color="dark">{{ t('chips.chips.dark') }}</va-chip>
</div>
</div>
</div>
</va-card-content>
</va-card>
</div>
<div class="flex xs12">
<va-card>
<va-card-title>{{ t('chips.badges.title') }}</va-card-title>
<va-card-content class="row">
<div class="flex xs12">
<div class="row">
<div class="flex xs12">
<va-badge class="mb-2 mr-2" color="primary" :text="t('chips.badges.primary')" />
<va-badge class="mb-2 mr-2" color="secondary" :text="t('chips.badges.secondary')" />
<va-badge class="mb-2 mr-2" color="success" :text="t('chips.badges.success')" />
<va-badge class="mb-2 mr-2" color="info" :text="t('chips.badges.info')" />
<va-badge class="mb-2 mr-2" color="danger" :text="t('chips.badges.danger')" />
<va-badge class="mb-2 mr-2" color="warning" :text="t('chips.badges.warning')" />
<va-badge class="mb-2 mr-2" color="gray" :text="t('chips.badges.gray')" />
<va-badge class="mb-2 mr-2" color="dark" :text="t('chips.badges.dark')" />
</div>
</div>
<div class="row">
<div class="flex xs12">
<va-badge class="mb-2 mr-2" color="primary" :text="t('chips.badges.primary')" transparent />
<va-badge class="mb-2 mr-2" color="secondary" :text="t('chips.badges.secondary')" transparent />
<va-badge class="mb-2 mr-2" color="success" :text="t('chips.badges.success')" transparent />
<va-badge class="mb-2 mr-2" color="info" :text="t('chips.badges.info')" transparent />
<va-badge class="mb-2 mr-2" color="danger" :text="t('chips.badges.danger')" transparent />
<va-badge class="mb-2 mr-2" color="warning" :text="t('chips.badges.warning')" transparent />
<va-badge class="mb-2 mr-2" color="gray" :text="t('chips.badges.gray')" transparent />
<va-badge class="mb-2 mr-2" color="dark" :text="t('chips.badges.dark')" transparent />
</div>
</div>
</div>
</va-card-content>
</va-card>
</div>
</div>
</template>
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
</script>
-104
View File
@@ -1,104 +0,0 @@
<template>
<div class="collapse-page">
<div class="row">
<div class="flex xs12">
<va-card>
<va-card-title>{{ t('collapse.basic') }}</va-card-title>
<va-card-content>
<va-accordion v-model="basicAccordionValue">
<va-collapse :header="t('collapse.firstHeader')">
<div class="pa-3">
<p class="va-h3">{{ t('collapse.content.title') }}</p>
<div>
{{ t('collapse.content.text') }}
</div>
</div>
</va-collapse>
<va-collapse :header="t('collapse.secondHeader')">
<div class="pa-3">
<p class="va-h3">{{ t('collapse.content.title') }}</p>
<div>
{{ t('collapse.content.text') }}
</div>
</div>
</va-collapse>
</va-accordion>
</va-card-content>
</va-card>
</div>
<div class="flex xs12">
<va-card>
<va-card-title>{{ t('collapse.collapseWithBackground') }}</va-card-title>
<va-card-content>
<va-accordion v-model="colorAccordionValue">
<va-collapse :header="t('collapse.firstHeader')" color="success" color-all>
<div class="pa-3">
<p class="va-h3">{{ t('collapse.content.title') }}</p>
<div>
{{ t('collapse.content.text') }}
</div>
</div>
</va-collapse>
<va-collapse :header="t('collapse.secondHeader')" color="warning" color-all>
<div class="pa-3">
<p class="va-h3">{{ t('collapse.content.title') }}</p>
<div>
{{ t('collapse.content.text') }}
</div>
</div>
</va-collapse>
</va-accordion>
</va-card-content>
</va-card>
</div>
<div class="flex xs12">
<va-card>
<va-card-title>{{ t('collapse.collapseWithCustomHeader') }}</va-card-title>
<va-card-content>
<va-accordion v-model="customHeaderAccordionValue">
<va-collapse class="mb-4">
<template #header>
<va-button style="width: 100%">
{{ t('collapse.firstHeader') }}
</va-button>
</template>
<div class="pa-3">
<p class="va-h3">{{ t('collapse.content.title') }}</p>
<div>
{{ t('collapse.content.text') }}
</div>
</div>
</va-collapse>
<va-collapse>
<template #header>
<va-button style="width: 100%">
{{ t('collapse.secondHeader') }}
</va-button>
</template>
<div>
<p class="va-h3">{{ t('collapse.content.title') }}</p>
<div class="pa-3">
{{ t('collapse.content.text') }}
</div>
</div>
</va-collapse>
</va-accordion>
</va-card-content>
</va-card>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const basicAccordionValue = ref([false, false])
const colorAccordionValue = ref([false, false])
const customHeaderAccordionValue = ref([false, false])
</script>
@@ -1,95 +0,0 @@
<template>
<div class="color-pickers vuestic-color-picker-page">
<div class="row">
<div class="flex md12 xs12">
<va-card>
<va-card-title>{{ t('menu.colorPickers') }}</va-card-title>
<va-card-content class="row">
<div class="flex xs4 md2">
<div class="vuestic-color-picker-page__top-square">
<span class="title no-wrap" :style="{ color: colors.primary }">
{{ t('colorPickers.simple') }}
</span>
<va-color-picker v-model="topSimpleSquareColor" :palette="palette" />
</div>
</div>
<div class="flex xs4 md2">
<div class="vuestic-color-picker-page__top-square">
<span class="title no-wrap" :style="{ color: colors.primary }">
{{ t('colorPickers.slider') }}
</span>
<va-color-picker v-model="topSliderSquareColor" mode="slider" />
</div>
</div>
<div class="flex xs4 md2">
<div class="vuestic-color-picker-page__top-square">
<span class="title no-wrap" :style="{ color: colors.primary }">
{{ t('colorPickers.advanced') }}
</span>
<va-color-input v-model="topAdvancedSquareColor" mode="advanced" />
</div>
</div>
</va-card-content>
</va-card>
</div>
</div>
<div class="row">
<div class="flex md12 xs12">
<va-card>
<va-card-title>Simple Inline</va-card-title>
<va-card-content class="row">
<div class="flex md1">
<va-color-square :value="simpleColor" />
</div>
<div class="flex md2">
<va-color-palette v-model="simpleColor" :palette="palette" />
</div>
</va-card-content>
</va-card>
</div>
</div>
<div class="row">
<div class="flex md12 xs12">
<va-card>
<va-card-title>Slider</va-card-title>
<va-card-content class="row">
<div class="flex xs12 md1">
<va-color-square :value="sliderColor" />
</div>
<div class="flex md6 xs12">
<va-color-slider v-model="sliderColor" />
</div>
</va-card-content>
</va-card>
</div>
</div>
<div class="row">
<div class="flex md12 xs12">
<va-card>
<va-card-title>Advanced</va-card-title>
<va-card-content class="row">
<div class="flex md1">
<va-color-square :value="advancedColor" />
</div>
<div class="flex md7">
<va-color-picker v-model="advancedColor" />
</div>
</va-card-content>
</va-card>
</div>
</div>
</div>
</template>
<script setup>
import { useColors } from 'vuestic-ui'
const topSimpleSquareColor = '#f81953'
const topSliderSquareColor = '#34495e'
const topAdvancedSquareColor = '#ffd50a'
const sliderColor = '#2e5e2a'
const advancedColor = '#ffd50a'
const simpleColor = '#f81953'
const palette = []
const { colors } = useColors()
</script>
-95
View File
@@ -1,95 +0,0 @@
<template>
<div class="row">
<div class="flex xs12 sm6">
<va-card>
<va-card-title>{{ t('colors.themeColors') }}</va-card-title>
<va-card-content>
<div v-for="(themeColor, index) in themeColors" :key="index">
<color-presentation
:color="themeColor.color"
:name="themeColor.name"
:description="themeColor.description"
/>
</div>
</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6">
<va-card>
<va-card-title>{{ t('colors.extraColors') }}</va-card-title>
<va-card-content>
<div v-for="(extraColor, index) in extraColors" :key="index">
<color-presentation
:color="extraColor.color"
:name="extraColor.name"
:description="extraColor.description"
/>
</div>
</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 lg4">
<va-card>
<va-card-title>{{ t('colors.gradients.basic.title') }}</va-card-title>
<va-card-content>
<div v-for="(buttonGradient, index) in buttonGradients" :key="index">
<color-presentation
:color="buttonGradient.color"
:variant="['gradient']"
:name="buttonGradient.name"
:description="buttonGradient.description"
/>
</div>
</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 lg4">
<va-card>
<va-card-title>{{ t('colors.gradients.hovered.title') }}</va-card-title>
<va-card-content>
<p class="mt-0 mb-2">
{{ t('colors.gradients.hovered.text') }}
</p>
<div v-for="(buttonGradient, index) in buttonGradients" :key="index">
<color-presentation
:color="buttonGradient.color"
:variant="['gradient', 'hovered']"
:name="buttonGradient.name"
:description="buttonGradient.description"
/>
</div>
</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 lg4">
<va-card>
<va-card-title>{{ t('colors.gradients.pressed.title') }}</va-card-title>
<va-card-content>
<p class="mt-0 mb-2">
{{ t('colors.gradients.pressed.text') }}
</p>
<div v-for="(buttonGradient, index) in buttonGradients" :key="index">
<color-presentation
:color="buttonGradient.color"
:variant="['gradient', 'pressed']"
:name="buttonGradient.name"
:description="buttonGradient.description"
/>
</div>
</va-card-content>
</va-card>
</div>
</div>
</template>
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import ColorPresentation from './color-presentation/ColorPresentation.vue'
import { themeColors, extraColors, buttonGradients } from './color-presentation/colorsData'
const { t } = useI18n()
</script>
@@ -1,133 +0,0 @@
<template>
<div class="color-presentation">
<va-popover color="info" :placement="popoverOptions.placement" :message="popoverOptions.content">
<div class="color-presentation__color" :style="computedStyle" @click="colorCopy()"></div>
</va-popover>
<div v-if="name || description" class="color-presentation__description">
<div class="color-presentation__name">{{ name }}</div>
<div class="color-presentation__text">{{ description }}</div>
</div>
<input ref="hiddenInput" :value="computedBackground" class="hidden-input" />
</div>
</template>
<script setup lang="ts">
import { useColors, useToast } from 'vuestic-ui'
import { computed, ref } from 'vue'
const props = withDefaults(
defineProps<{
color?: string
variant?: string[]
width?: number
name?: string
description?: string
}>(),
{
color: '',
variant: () => [],
width: 0,
name: '',
description: '',
},
)
const popoverOptions = ref({
content: 'Click to copy the color to clipboard',
placement: 'right',
})
const { getColor, getGradientBackground } = useColors()
const computedBackground = computed(() => {
const color = getColor(props.color)
if (props.variant.includes('gradient')) {
return getGradientBackground(color)
}
return color
})
const computedStyle = computed(() => {
const calcFilter = () => {
if (props.variant.includes('hovered')) {
return 'brightness(115%)'
}
if (props.variant.includes('pressed')) {
return 'brightness(85%)'
}
}
return {
background: computedBackground.value,
filter: calcFilter(),
width: props.width ? `${props.width}px` : '',
}
})
const hiddenInput = ref()
function colorCopy() {
navigator.clipboard?.writeText?.(hiddenInput.value.value).then(notify)
}
const { init } = useToast()
function notify() {
init({
message: "The color's copied to your clipboard",
position: 'bottom-right',
color: getColor(props.color),
})
}
</script>
<style lang="scss">
.color-presentation {
display: flex;
align-items: center;
margin-bottom: 1.125rem;
.v-popover {
width: 80px;
height: 40px;
span {
outline: none !important;
}
}
&__color {
height: 40px;
width: 80px;
margin-right: 0.25rem;
cursor: pointer;
border-radius: 4px;
overflow: hidden;
}
&__description {
margin-left: 1rem;
min-width: 100px;
}
&__name {
color: var(--va-dark);
padding-bottom: 4px;
}
&__text {
color: var(--va-secondary);
}
.hidden-input {
width: 0;
padding: 0;
opacity: 0;
user-select: none;
}
}
</style>
@@ -1,96 +0,0 @@
export const themeColors = [
{
color: 'primary',
name: 'Primary',
description: 'Buttons, labels, graphs.',
},
{
color: 'secondary',
name: 'Secondary',
description: 'Light text, buttons, labels, graphs.',
},
{
color: 'success',
name: 'Success',
description: 'Buttons, labels, graphs.',
},
{
color: 'info',
name: 'Info',
description: 'Buttons, labels, graphs.',
},
{
color: 'danger',
name: 'Danger',
description: 'Buttons, labels, graphs.',
},
{
color: 'warning',
name: 'Warning',
description: 'Buttons, labels, graphs.',
},
{
color: 'gray',
name: 'Gray',
description: 'Buttons, labels, graphs.',
},
{
color: 'dark',
name: 'Dark',
description: 'Buttons, labels, graphs.',
},
]
export const extraColors = [
{
color: '#36e9f6',
name: 'Teal',
description: 'Graphs, tables, labels, etc.',
},
{
color: '#ed34b8',
name: 'Violet',
description: 'Graphs, tables, labels, etc.',
},
{
color: '#8f4ed6',
name: 'Purple',
description: 'Graphs, tables, labels, etc.',
},
{
color: '#d40d52',
name: 'Ruby',
description: 'Graphs, tables, labels, etc.',
},
{
color: '#ff842b',
name: 'Orrange',
description: 'Graphs, tables, labels, etc.',
},
{
color: '#1b9a7c',
name: 'Dark Green',
description: 'Graphs, tables, labels, etc.',
},
{
color: '#d3ff00',
name: 'Toxic',
description: 'Graphs, tables, labels, etc.',
},
{
color: '#81513e',
name: 'Brown',
description: 'Graphs, tables, labels, etc.',
},
]
export const buttonGradients = [
{ color: 'primary', name: 'primary', description: 'Buttons, chips, badges...' },
{ color: 'secondary', name: 'secondary', description: 'Buttons, chips, badges...' },
{ color: 'success', name: 'success', description: 'Buttons, chips, badges...' },
{ color: 'info', name: 'info', description: 'Buttons, chips, badges...' },
{ color: 'danger', name: 'danger', description: 'Buttons, chips, badges...' },
{ color: 'warning', name: 'warning', description: 'Buttons, chips, badges...' },
{ color: 'gray', name: 'gray', description: 'Buttons, chips, badges...' },
{ color: 'dark', name: 'dark', description: 'Buttons, chips, badges...' },
]

Some files were not shown because too many files have changed in this diff Show More