Skip to content

Commit

Permalink
Clean up parsing of rows
Browse files Browse the repository at this point in the history
  • Loading branch information
xingrz committed Mar 31, 2024
1 parent 3296ab1 commit 2f7ea65
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 81 deletions.
14 changes: 4 additions & 10 deletions src/components/BSMap.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div :class="$style.map" :style="style">
<BSRow v-for="(row, index) in rows" :key="index" :content="row" :row="index" />
<BSRow v-for="(row, index) in rows" :key="index" :src="row" :row="index" />
</div>
</template>

Expand All @@ -11,6 +11,8 @@ import {
defineProps,
} from 'vue';
import { max } from 'radash';
import BSRow from './BSMap/BSRow.vue';
const props = defineProps<{
Expand All @@ -19,15 +21,7 @@ const props = defineProps<{
}>();
const rows = computed(() => props.content.split('\n'));
const cols = computed(() => {
let cols = 0;
for (const row of rows.value) {
const c = Math.max(cols, row.split('\\').length);
if (c > cols) cols = c;
}
return cols;
});
const cols = computed(() => max(rows.value.map((row) => row.split('\\').length)) || 1);
const style = computed(() => ({
'--bs-map-size': props.size,
Expand Down
16 changes: 7 additions & 9 deletions src/components/BSMap/BSCell.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<BSSelectable v-slot="{ selectable }" :row="props.row" :offset="props.offset" :length="props.content.length">
<div :class="[selectable, $style.cell]" :title="content" @click="handleClick" :style="style">
<BSIcon v-for="(icon, index) in (parts?.icons || [])" :key="index" :content="icon" :stacked="stacked"
<BSSelectable v-slot="{ selectable }" :row="props.row" :offset="props.offset" :length="props.src.length">
<div :class="[selectable, $style.cell]" :title="props.src" @click="handleClick" :style="style">
<BSIcon v-for="(icon, index) in (parts?.icons || [])" :key="index" :src="icon"
@ratio="(ratio: number) => updateRatio(index, ratio)" />
</div>
</BSSelectable>
Expand All @@ -22,7 +22,7 @@ import BSSelectable from './BSSelectable.vue';
import BSIcon from './BSIcon.vue';
const props = defineProps<{
content: string;
src: string;
row: number;
offset: number;
}>();
Expand All @@ -32,17 +32,15 @@ const editorStore = useEditorStore();
const ratio = ref(1);
const parts = computed(() => {
if (!props.content) return;
if (!props.src) return;
const [nonParam, ...params] = props.content.split('!_');
const [nonParam, ...params] = props.src.split('!_');
const [nonLink, ...links] = nonParam.split('!@');
const icons = nonLink.split('!~').filter((icon) => !!icon);
return { icons, links, params };
});
const stacked = computed(() => !!parts.value && parts.value.icons.length > 1);
const style = computed(() => ({
...styleFromParams(parts.value?.params?.[0], true),
'--bs-map-cell-ratio': (ratio.value == 1 ? undefined : ratio.value),
Expand All @@ -52,7 +50,7 @@ function handleClick(): void {
editorStore.selection = {
row: props.row,
offset: props.offset,
length: props.content.length,
length: props.src.length,
from: 'preview',
};
}
Expand Down
47 changes: 18 additions & 29 deletions src/components/BSMap/BSIcon.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<div v-if="text" :class="$style.text" :style="style">
<span>{{ text.data }}</span>
<div v-if="parts.type == 'text'" :class="$style.text" :style="style">
<span>{{ parts.data }}</span>
</div>
<img v-else :class="$style.icon" :style="style" :src="icon?.data" />
<img v-else :class="$style.icon" :style="style" :src="parts.data" />
</template>

<script lang="ts" setup>
Expand All @@ -18,8 +18,7 @@ import { useIconStore } from '@/stores/icon';
import styleFromParams from '@/utils/styleFromParams';
const props = defineProps<{
content: string;
stacked: boolean;
src: string;
}>();
const emit = defineEmits<{
Expand All @@ -28,39 +27,29 @@ const emit = defineEmits<{
const iconStore = useIconStore();
const content = computed<string>(() => {
return props.stacked ? props.content.split('__')[0] : props.content;
});
const parts = computed(() => {
const [src, params] = props.src.split('__') as [string, string | undefined];
const type = src.includes('*') ? 'text' : 'icon';
const params = computed<string | undefined>(() => {
// available only for stacked icons
return props.stacked ? props.content.split('__')[1] : undefined;
});
const res = type == 'text' ? (() => {
const [prefix, data] = src.split('*');
return { data, ratio: selectTextWidth(prefix) };
})() : iconStore.icons[src];
const text = computed(() => {
let match: RegExpMatchArray | null = null;
if (content.value && (match = content.value.match(/^(.*)\*([^_]+)$/))) {
const ratio = selectTextWidth(match[1]) as number;
const data = match[2];
return { data, ratio };
} else {
return undefined;
}
return { src, params, type, ...res };
});
const icon = computed(() => text.value ? undefined : iconStore.icons[content.value]);
watch(content, (content) => {
if (content && !text.value) {
iconStore.resolve(content);
watch(parts, ({ type, src }) => {
if (type == 'icon') {
iconStore.resolve(src);
}
}, { immediate: true });
const ratio = computed(() => (text.value ?? icon.value)?.ratio ?? 1);
const ratio = computed(() => parts.value.ratio ?? 1);
watch(ratio, (ratio) => emit('ratio', ratio), { immediate: true });
const style = computed(() => ({
...styleFromParams(params.value, true),
...styleFromParams(parts.value.params, true),
'--bs-map-icon-ratio': (ratio.value == 1 ? undefined : ratio.value),
}) as CSSProperties);
Expand Down Expand Up @@ -106,7 +95,7 @@ function selectTextWidth(flag: string): number | undefined {
span {
line-height: 1;
vertical-align: var(--bs-map-cell-valign, center);
vertical-align: var(--bs-map-cell-valign, middle);
}
}
</style>
41 changes: 12 additions & 29 deletions src/components/BSMap/BSRow.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<template>
<div :class="$style.row">
<div :class="$style.cells" :style="rowStyle">
<BSCell v-for="({ cell, offset }, index) in cells" :key="index" :content="cell" :row="row" :offset="offset" />
<BSCell v-for="({ part, offset }, index) in cells" :key="index" :src="part" :row="row" :offset="offset" />
</div>
<div :class="$style.texts">
<BSText v-for="({ text, offset, align }, index) in texts" :key="index" :content="text" :align="align" :row="row"
<BSText v-for="({ part, offset, align }, index) in texts" :key="index" :src="part" :align="align" :row="row"
:offset="offset" />
</div>
</div>
Expand All @@ -13,47 +13,30 @@
<script lang="ts" setup>
import { computed, defineProps } from 'vue';
import splitWithOffset from '@/utils/splitWithOffset';
import styleFromParams from '@/utils/styleFromParams';
import BSCell from './BSCell.vue';
import BSText from './BSText.vue';
const props = defineProps<{
content: string;
src: string;
row: number;
}>();
const parts = computed(() => {
let offset = 0;
return props.content.split('~~').map((part) => {
const o = offset;
offset += part.length + 2;
return { part, offset: o };
});
const [cells, ...texts] = splitWithOffset(props.src, '~~');
return { cells, texts };
});
const cells = computed(() => {
let offset = 0;
return parts.value[0].part.split('\\').map((cell) => {
const o = offset;
offset += cell.length + 1;
return { cell, offset: o };
});
});
const texts = computed(() => {
const texts = parts.value.slice(1, 5)
.map(({ part, offset }, i) => ({ text: part, offset, align: i + 1 }));
const cells = computed(() => splitWithOffset(parts.value.cells.part, '\\'));
// Shorthand that the only text is treated as the main (the 2nd) text
if (texts.length == 1) {
texts[0].align = 2;
}
return texts.filter(({ text }) => text != '' && text != ' ');
});
const texts = computed(() => parts.value.texts
.slice(0, 4)
.map((part, index, { length }) => ({ ...part, align: length == 1 ? 2 : index + 1 }))
.filter(({ part }) => !!part));
const rowStyle = computed(() => styleFromParams(parts.value[5]?.part));
const rowStyle = computed(() => styleFromParams(parts.value.texts[4]?.part));
</script>

<style lang="scss" module>
Expand Down
9 changes: 5 additions & 4 deletions src/components/BSMap/BSText.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<BSSelectable v-slot="{ selectable }" :row="props.row" :offset="props.offset" :length="props.content.length">
<div :class="[selectable, $style.text]" :data-align="align" :title="content" @click="handleClick">{{ content }}
<BSSelectable v-slot="{ selectable }" :row="props.row" :offset="props.offset" :length="props.src.length">
<div :class="[selectable, $style.text]" :data-align="align" :title="props.src" @click="handleClick">
{{ props.src }}
</div>
</BSSelectable>
</template>
Expand All @@ -13,7 +14,7 @@ import { useEditorStore } from '@/stores/editor';
import BSSelectable from './BSSelectable.vue';
const props = defineProps<{
content: string;
src: string;
align: number;
row: number;
offset: number;
Expand All @@ -25,7 +26,7 @@ function handleClick(): void {
editorStore.selection = {
row: props.row,
offset: props.offset,
length: props.content.length,
length: props.src.length,
from: 'preview',
};
}
Expand Down
8 changes: 8 additions & 0 deletions src/utils/splitWithOffset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default function splitWithOffset(str: string, splitter: string, initialOffset = 0) {
let offset = initialOffset;
return str.split(splitter).map((part) => {
const o = offset;
offset += part.length + splitter.length;
return { part, offset: o };
});
}

0 comments on commit 2f7ea65

Please sign in to comment.