Skip to content

Commit d78298e

Browse files
committed
perf(ui): render sidebar template icons via CSS mask
1 parent 72ac718 commit d78298e

3 files changed

Lines changed: 28 additions & 21 deletions

File tree

src/server/ui/App.vue

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
<script setup lang="ts">
22
import { ref, computed, onMounted, onUnmounted, watch, watchEffect } from 'vue'
33
import { RouterLink, RouterView, useRoute, useRouter } from 'vue-router'
4-
import { Monitor, CodeXml, Smartphone, ChevronDown, ArrowUp, ArrowDown, CornerDownLeft, Check, Search, FileCodeCorner, FileCode, FileText, Code, BookText, MailQuestion, Moon, Sun } from '@lucide/vue'
4+
import { Monitor, CodeXml, Smartphone, ChevronDown, ArrowUp, ArrowDown, CornerDownLeft, Check, Search, FileCode, FileText, Code, BookText, MailQuestion, Moon, Sun } from '@lucide/vue'
55
import SidebarClose from '@/components/SidebarClose.vue'
6-
import Markdown from '@/components/Markdown.vue'
76
import logoUrl from '@/logo.svg'
87
import logoGradientUrl from '@/logo-gradient.svg'
98
import { Kbd } from '@/components/ui/kbd'
@@ -340,7 +339,7 @@ onUnmounted(() => {
340339
:is-active="isActive(t.href)"
341340
>
342341
<RouterLink :to="t.href" class="truncate">
343-
<component :is="t.path.endsWith('.md') ? Markdown : FileCodeCorner" class="size-3 shrink-0 opacity-70" :stroke-width="1" />
342+
<span class="mz-tpl-icon size-4 shrink-0 opacity-70" :class="t.path.endsWith('.md') ? 'mz-tpl-icon-md' : 'mz-tpl-icon-vue'" />
344343
<span class="truncate">{{ t.name }}</span>
345344
</RouterLink>
346345
</SidebarMenuButton>
@@ -507,7 +506,7 @@ onUnmounted(() => {
507506
:value="t.path"
508507
@select="onCommandSelect(t.href)"
509508
>
510-
<component :is="t.path.endsWith('.md') ? Markdown : FileCodeCorner" class="size-3 shrink-0 opacity-70" :stroke-width="1" />
509+
<span class="mz-tpl-icon size-3 shrink-0 opacity-70" :class="t.path.endsWith('.md') ? 'mz-tpl-icon-md' : 'mz-tpl-icon-vue'" />
511510
<span>{{ getFileName(t.path) }}</span>
512511
<span class="sr-only">{{ ' ' + t.path.split('/').join(' ') }}</span>
513512
</CommandItem>

src/server/ui/components/Markdown.vue

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/server/ui/main.css

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,28 @@
127127
border-left: 2px solid #f59e0b;
128128
min-width: fit-content;
129129
}
130+
131+
/**
132+
* Template list icons, painted as a CSS mask so the sidebar can render
133+
* thousands of rows without a Vue component or inline <svg> per row. Each
134+
* icon SVG is decoded once and reused; background-color: currentColor keeps
135+
* the currentColor theming the old <svg> icons had.
136+
*/
137+
.mz-tpl-icon {
138+
display: inline-block;
139+
background-color: currentColor;
140+
-webkit-mask-position: center;
141+
mask-position: center;
142+
-webkit-mask-size: contain;
143+
mask-size: contain;
144+
-webkit-mask-repeat: no-repeat;
145+
mask-repeat: no-repeat;
146+
}
147+
.mz-tpl-icon-vue {
148+
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12.15V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-3.35'/%3E%3Cpath d='M14 2v5a1 1 0 0 0 1 1h5'/%3E%3Cpath d='m5 16-3 3 3 3'/%3E%3Cpath d='m9 22 3-3-3-3'/%3E%3C/svg%3E");
149+
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12.15V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-3.35'/%3E%3Cpath d='M14 2v5a1 1 0 0 0 1 1h5'/%3E%3Cpath d='m5 16-3 3 3 3'/%3E%3Cpath d='m9 22 3-3-3-3'/%3E%3C/svg%3E");
150+
}
151+
.mz-tpl-icon-md {
152+
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 22h6a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v6'/%3E%3Cpath d='M14 2v5a1 1 0 0 0 1 1h5'/%3E%3Cpath d='M3 22V14l4 4 4-4v8'/%3E%3C/svg%3E");
153+
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 22h6a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v6'/%3E%3Cpath d='M14 2v5a1 1 0 0 0 1 1h5'/%3E%3Cpath d='M3 22V14l4 4 4-4v8'/%3E%3C/svg%3E");
154+
}

0 commit comments

Comments
 (0)