Skip to content

Commit

Permalink
Merge branch 'release/v0.21.16'
Browse files Browse the repository at this point in the history
  • Loading branch information
holtwick committed Jul 4, 2024
2 parents 46d214a + 1dc51a9 commit 2bf7cbc
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 22 deletions.
4 changes: 3 additions & 1 deletion lib/basic/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './_types'
export * from './directives'
export * from './formatters'
export * from './log'

export { default as OuiButton } from './oui-button.vue'
export { default as OuiCard } from './oui-card.vue'
Expand All @@ -15,16 +16,17 @@ export { default as OuiFormItem } from './oui-form-item.vue'
export { default as OuiInput } from './oui-input.vue'
export { default as OuiInputGroup } from './oui-input-group.vue'
export { default as OuiInputNumber } from './oui-input-number.vue'
export { default as OuiLog } from './oui-log.vue'
export { default as OuiNotice } from './oui-notice.vue'
export { default as OuiPassword } from './oui-password.vue'
export { default as OuiPasswordMeter } from './oui-password-meter.vue'
export { default as OuiResizeable } from './oui-resizeable.vue'
export { default as OuiSelect } from './oui-select.vue'
export { default as OuiSeparator } from './oui-separator.vue'
export { default as OuiStars } from './oui-stars.vue'
export { default as OuiTabs } from './oui-tabs.vue'
export { default as OuiTable } from './oui-table.vue'
export { default as OuiTableview } from './oui-tableview.vue'
export { default as OuiTabs } from './oui-tabs.vue'
export { default as OuiText } from './oui-text.vue'
export { default as OuiTextarea } from './oui-textarea.vue'
export { default as OuiVirtualList } from './oui-virtual-list.vue'
Expand Down
22 changes: 22 additions & 0 deletions lib/basic/log.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { reactive } from 'vue'
import type { LogMessage, LoggerInterface } from 'zeed'
import { LogLevelAll, LoggerContext, LoggerMemoryHandler } from 'zeed'

export type LogOui = LoggerInterface & {
messages: LogMessage[]
}

export function useLog(name: string): LogOui {
const messages: LogMessage[] = reactive([])
const logger = LoggerContext()
logger.setHandlers([
LoggerMemoryHandler({
level: LogLevelAll,
filter: '*',
messages,
}),
])
const log = logger(name) as any
log.messages = messages
return log
}
28 changes: 28 additions & 0 deletions lib/basic/oui-log.demo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script lang="ts" setup>
import { useIntervalFn, useTimeoutFn } from '@vueuse/core'
import { uuid } from 'zeed'
import OuiText from './oui-text.vue'
import { OuiLog, useLog } from '@/lib'
const log = useLog('test')
log('Hello World')
log.info('Info')
log.warn('Warning')
log.error('Error')
log('Some binary data', new Uint8Array([1, 2, 3, 99, 100, 101]))
useIntervalFn(() => {
log(`interval ${uuid()}`)
}, 1000)
</script>

<template>
<OuiText>
<h2>Virtual List</h2>
<div>
<OuiLog :log="log" />
</div>
</OuiText>
</template>
14 changes: 14 additions & 0 deletions lib/basic/oui-log.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@require "../../stylus/index.styl";

.oui-log {
border: 1px solid var(--s2-fg);
border-radius: 4;
font-family: "Jetbrains Mono", monospace;
font-size: 12;
line-height: 1.2;
height: 200;

._active {
background: var(--p1-200) !important;
}
}
150 changes: 150 additions & 0 deletions lib/basic/oui-log.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
<script lang="ts" setup>
import { ref, watch } from 'vue'
import type { LogMessage } from 'zeed'
import { Uint8ArrayToHexDump, browserSelectColorByName, formatMilliseconds, isArray, isString, logMessageFromCompact } from 'zeed'
import type { OuiTableColumn } from './_types'
import type { LogOui } from './log'
import OuiTableview from './oui-tableview.vue'
import './oui-log.styl'
const props = defineProps<{
log: LogOui
}>()
const selected = ref<number>()
interface RenderMessagesOptions {
trace?: boolean // = true
pretty?: boolean // = true
}
function formatMessages(
messages: any[],
opt: RenderMessagesOptions = {},
): any[] {
const { trace = true, pretty = true } = opt
return messages.map((obj) => {
if (obj && typeof obj === 'object') {
if (pretty && (obj instanceof Uint8Array || obj instanceof ArrayBuffer))
return `\n${Uint8ArrayToHexDump(obj)}\n`
if (obj instanceof Error) {
if (!trace)
return `${obj.name || 'Error'}: ${obj.message}`
return `${obj.name || 'Error'}: ${obj.message}\n${obj.stack}`
}
return obj
}
return String(obj)
})
}
function renderMessages(
messages: any[],
opt: RenderMessagesOptions = {},
): any[] {
return formatMessages(messages, opt)
}
function handlerLogInfo(msg: LogMessage) {
const name = msg.name || ''
const color = browserSelectColorByName(name)
const message = renderMessages(isArray(msg.messages) ? msg.messages : [msg.messages], { pretty: true })
// const message = msg.messages
return {
...msg,
name,
color,
background: {
1: '#d4f4ff',
2: '#ffedbd',
3: '#ffaab0',
4: '#ffbbe9',
}[msg.level] ?? 'transparent',
message,
}
}
const logs = ref<any>([])
function updateLogs() {
const ll: LogMessage[] = [...props.log.messages] ?? []
const first = ll[0]
const compact = isArray(first)
let timestamp = (compact ? first[0] : first?.timestamp) ?? 0
// const date = new Date(timestamp).toLocaleString()
logs.value = ll.map((_info: any) => {
const info = compact ? logMessageFromCompact(_info) : _info
const { name, message, color, background } = handlerLogInfo(info)
const diff = Math.abs(timestamp - (info.timestamp ?? 0))
timestamp = (info.timestamp ?? 0)
const timeDiffString = diff && `+${formatMilliseconds(diff)}`
const datetime = new Date(info.timestamp).toLocaleString('de')
return {
...info,
diff,
datetime,
timeDiffString,
name,
message,
color,
background,
}
})
}
watch(() => props.log.messages.length, updateLogs)
updateLogs()
const columns: OuiTableColumn[] = [
{ title: 'Time', name: 'time', sortable: false, width: 96, align: 'right' },
// { title: 'Tag', name: 'tag', sortable: false },
{ title: 'Message', name: 'message', sortable: false },
]
// const selectedItem = computed(() => list.value[selected.value ?? -1])
</script>

<template>
<OuiTableview
v-model="selected"
class="oui-log"
name="log-table"
selectable
:data="logs"
:columns="columns"
:row-height="23"
:row-attrs="(item: any) => ({ style: `background: ${item.background}` })"
:header="false"
:scroll-to-end="true"
:resizeable="false"
>
<template #col-time="{ item }">
<span style="color: #888; white-space:pre">
{{ item.diff ? item.timeDiffString : '' }}
</span>
</template>
<template #col-tag="{ item }">
<span :style="{ color: item.color, whiteSpace: 'pre', fontWeight: 600 }">
{{ item.name }}
</span>
</template>
<template #col-message="{ item }">
<span>
<template v-for="(o, i) in item.message" :key="o">
<template v-if="isString(o)">
<b v-if="i % 2 !== 0" style="font-weight:600;">{{ o.slice(0, 255) }}</b>
<span v-else>{{ o.slice(0, 255) }}</span>
</template>
<template v-else>
<!-- <b>{{ JSON.stringify(o) }}</b> -->
<span class="code">&lt;{{ o?.__class ?? typeof o }}&gt;</span>
<!-- <OuiObject :value="o" /> -->
</template>
{{ ' ' }}
</template>
</span>
</template>
</OuiTableview>
</template>
22 changes: 13 additions & 9 deletions lib/basic/oui-tableview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ const props = withDefaults(defineProps<{
scrollToEnd?: boolean
rowAttrs?: (item: T, index: number) => any // Record<string, string>
name?: string
resizeable?: boolean
}>(), {
rowHeight: 44,
header: true,
footer: false,
selectable: true,
fillLast: true,
scrollToEnd: false,
resizeable: true,
rowAttrs: () => ({}),
})
Expand All @@ -42,7 +44,7 @@ const sortName = computed(() => parseOrderby(modelSort.value).field)
const sortAsc = computed(() => parseOrderby(modelSort.value).asc)
const widthsPlain = props.columns.map(c => c.width ?? 120)
const widths = props.name ? useLocalStorage<number[]>(`oui.tableview.${props.name}.widths`, widthsPlain) : ref(widthsPlain)
const widths = props.name && props.resizeable ? useLocalStorage<number[]>(`oui.tableview.${props.name}.widths`, widthsPlain) : ref(widthsPlain)
watch(() => [props.data, props.fillLast], () => {
let values = props.columns.map((c, i) => widths.value[i] ?? c.width ?? 120)
Expand Down Expand Up @@ -163,14 +165,16 @@ function scrollX(x: number) {
</template>
</div>
</div>
<template v-for="w, i in widths" :key="i">
<OuiSeparator
v-model="widths[i]"
side="right"
:min-size="columns[i].minWidth ?? 80"
:max-size="columns[i].maxWidth ?? 300"
:style="{ left: px(arraySum(widths.slice(0, i + 1)) - 1 - marginLeft) }"
/>
<template v-if="resizeable">
<template v-for="w, i in widths" :key="i">
<OuiSeparator
v-model="widths[i]"
side="right"
:min-size="columns[i].minWidth ?? 80"
:max-size="columns[i].maxWidth ?? 300"
:style="{ left: px(arraySum(widths.slice(0, i + 1)) - 1 - marginLeft) }"
/>
</template>
</template>
</div>
</template>
33 changes: 22 additions & 11 deletions lib/basic/oui-virtual-list.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const paddingTop = ref(margin)
let containerSize = 0
let isScrollBusy = false
let lastScrollX = 0
let didUserScroll = false
function handleScroll() {
if (!root.value)
Expand Down Expand Up @@ -69,19 +70,14 @@ function handleScroll() {
paddingTop.value = range[0] * rowHeight.value + margin
emit('scrollX', root.value.scrollLeft)
// Scroll to end
if (props.scrollToEnd && !isScrollBusy && !didUserScroll) {
root.value.scrollTop = scrollHeight.value
}
})
}
watch(data, (cData) => {
scrollHeight.value = cData.length * rowHeight.value
})
watch(rowHeight, (cRowHeight) => {
scrollHeight.value = data.value.length * cRowHeight
})
watch(() => data.value.length, handleScroll)
// useOnBus('listScrollTop', () => {
// if (root.value)
// root.value.scrollTop = 0
Expand All @@ -99,6 +95,21 @@ function scrollToEnd() {
watch(() => props.scrollToEnd, scrollToEnd)
watch(() => data.value.length, (l) => {
scrollHeight.value = l * rowHeight.value
handleScroll()
})
watch(rowHeight, (cRowHeight) => {
scrollHeight.value = data.value.length * cRowHeight
})
function handleUserScroll() {
const bottomScroll = root.value ? root.value.scrollTop + root.value.clientHeight + 1 : 0
handleScroll()
didUserScroll = scrollHeight.value > bottomScroll
}
onMounted(() => {
if (!root.value)
return
Expand All @@ -113,7 +124,7 @@ onMounted(() => {
</script>

<template>
<div ref="root" class="oui-virtual-list" @scroll.passive="handleScroll">
<div ref="root" class="oui-virtual-list" @scroll.passive="handleUserScroll">
<div :style="`height: ${px(scrollHeight)}; padding-top: ${px(paddingTop)}`">
<template v-for="(item, index) in data.slice(indexFirst, indexLast)" :key="indexFirst + index">
<div :style="{ height: `${px(rowHeight)}` }">
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "oui-kit",
"type": "module",
"version": "0.21.15",
"version": "0.21.16",
"author": {
"email": "dirk.holtwick@gmail.com",
"name": "Dirk Holtwick",
Expand Down

0 comments on commit 2bf7cbc

Please sign in to comment.