Skip to content

Commit 21828e6

Browse files
feat(snippets): add html & css renderer to snippets preview (#126)
1 parent 551ac8a commit 21828e6

File tree

15 files changed

+205
-6
lines changed

15 files changed

+205
-6
lines changed

config/vite.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,16 @@ export default defineConfig({
3333
resolvers: [
3434
IconsResolver({
3535
prefix: '',
36-
customCollections: ['unicons']
36+
customCollections: ['unicons', 'svg']
3737
})
3838
]
3939
}),
4040
Icons({
4141
customCollections: {
4242
unicons: FileSystemIconLoader(
4343
'./node_modules/@iconscout/unicons/svg/line'
44-
)
44+
),
45+
svg: FileSystemIconLoader(pathSrc + '/assets/svg')
4546
}
4647
})
4748
],

src/main/menu/main.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,15 @@ const editorMenu: MenuItemConstructorOptions[] = [
341341
'main-menu:preview-markdown'
342342
)
343343
}
344+
},
345+
{
346+
label: 'Preview Code',
347+
accelerator: 'Shift+CommandOrControl+P',
348+
click: () => {
349+
BrowserWindow.getFocusedWindow()?.webContents.send(
350+
'main-menu:preview-code'
351+
)
352+
}
344353
}
345354
]
346355

src/renderer/App.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ ipc.on('main-menu:preview-markdown', async () => {
197197
}
198198
})
199199
200+
ipc.on('main-menu:preview-code', () => {
201+
snippetStore.isCodePreview = !snippetStore.isCodePreview
202+
})
203+
200204
ipc.on('main-menu:copy-snippet', () => {
201205
onCopySnippet()
202206
})

src/renderer/assets/scss/base.scss

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,25 @@ h6 {
7070
z-index: 10;
7171
}
7272
}
73+
.gutter-line-horizontal {
74+
position: absolute;
75+
top: 0;
76+
left: 0;
77+
right: 0;
78+
width: 100%;
79+
height: 1px;
80+
background-color: var(--color-border);
81+
cursor: row-resize;
82+
&::after {
83+
content: '';
84+
display: block;
85+
height: 8px;
86+
width: 100%;
87+
position: absolute;
88+
top: -2px;
89+
z-index: 10;
90+
}
91+
}
7392

7493
.desc {
7594
font-size: var(--text-sm);
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<template>
2+
<div
3+
ref="previewRef"
4+
class="editor-preview"
5+
>
6+
<div class="tools">
7+
<div class="left">
8+
<AppCheckbox
9+
v-model="appStore.codePreview.darkMode"
10+
name="Dark mode"
11+
label="Dark mode"
12+
/>
13+
</div>
14+
<div class="right">
15+
<AppActionButton @click="onSaveToHtml">
16+
<UniconsFileDownload />
17+
</AppActionButton>
18+
</div>
19+
</div>
20+
<div class="body">
21+
<iframe
22+
:srcDoc="srcDoc"
23+
frameborder="0"
24+
height="100%"
25+
width="100%"
26+
/>
27+
</div>
28+
<div
29+
ref="gutterRef"
30+
class="gutter-line-horizontal"
31+
/>
32+
</div>
33+
</template>
34+
35+
<script setup lang="ts">
36+
import { useSnippetStore } from '@/store/snippets'
37+
import { computed, ref, onMounted, watch } from 'vue'
38+
import interact from 'interactjs'
39+
import { useAppStore } from '@/store/app'
40+
41+
const snippetStore = useSnippetStore()
42+
const appStore = useAppStore()
43+
const srcDoc = ref()
44+
const height = computed(() => appStore.sizes.codePreviewHeight + 'px')
45+
46+
const previewRef = ref()
47+
const gutterRef = ref()
48+
49+
snippetStore.$subscribe(() => {
50+
setSrcDoc()
51+
})
52+
53+
watch(
54+
() => appStore.codePreview.darkMode,
55+
() => {
56+
setSrcDoc()
57+
}
58+
)
59+
60+
const setSrcDoc = () => {
61+
const html = snippetStore.selected?.content.find(
62+
i => i.language === 'html'
63+
)?.value
64+
const css = snippetStore.selected?.content.find(
65+
i => i.language === 'css'
66+
)?.value
67+
68+
const htmlDefault =
69+
'<div>Add fragments with HTML & CSS languages to view result.</div>'
70+
const bg = appStore.codePreview.darkMode ? 'background: #263238;' : ''
71+
const cssDefault = `
72+
body {
73+
display: flex;
74+
align-items: center;
75+
justify-content: center;
76+
height: 100vh;
77+
margin: 0;
78+
${bg}
79+
}
80+
`
81+
82+
srcDoc.value = `<html>
83+
<body>${html || htmlDefault}<body>
84+
<style>${cssDefault + css}<style>
85+
</html>
86+
`
87+
}
88+
setSrcDoc()
89+
90+
const onSaveToHtml = () => {
91+
const a = document.createElement('a')
92+
93+
a.href = `data:text/plain;charset=utf-8, ${encodeURIComponent(srcDoc.value)}`
94+
console.log(a)
95+
a.download = `${snippetStore.selected?.name}.html`
96+
a.click()
97+
}
98+
99+
onMounted(() => {
100+
interact(previewRef.value).resizable({
101+
edges: { top: true },
102+
onmove: e => {
103+
const { pageY } = e
104+
appStore.sizes.codePreviewHeight = Math.floor(window.innerHeight - pageY)
105+
}
106+
})
107+
})
108+
</script>
109+
110+
<style lang="scss" scoped>
111+
.editor-preview {
112+
position: relative;
113+
.body {
114+
height: calc(v-bind(height) - 34px);
115+
}
116+
.tools {
117+
height: 34px;
118+
display: flex;
119+
justify-content: space-between;
120+
align-items: center;
121+
padding: 4px var(--spacing-xs);
122+
border-bottom: 1px solid var(--color-border);
123+
}
124+
iframe {
125+
background-color: #fff;
126+
}
127+
}
128+
</style>

src/renderer/components/editor/TheEditor.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ const editorHeight = computed(() => {
8383
forceRefresh.value
8484
8585
let result =
86-
appStore.sizes.editor.titleHeight +
8786
appStore.sizes.titlebar +
87+
appStore.sizes.editor.titleHeight +
8888
appStore.sizes.editor.footerHeight
8989
9090
if (snippetStore.isFragmentsShow) {
@@ -99,6 +99,10 @@ const editorHeight = computed(() => {
9999
result += appStore.sizes.editor.descriptionHeight
100100
}
101101
102+
if (snippetStore.isCodePreview) {
103+
result += appStore.sizes.codePreviewHeight
104+
}
105+
102106
return window.innerHeight - result + 'px'
103107
})
104108

src/renderer/components/snippets/SnippetHeader.vue

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@
2121
<UniconsCamera v-if="!snippetStore.isScreenshotPreview" />
2222
<UniconsCameraSlash v-else />
2323
</AppActionButton>
24-
<AppActionButton @click="onCopySnippet">
25-
<UniconsArrow />
24+
<AppActionButton @click="onCodePreview">
25+
<SvgArrowSlash v-if="snippetStore.isCodePreview" />
26+
<UniconsArrow v-else />
2627
</AppActionButton>
2728
<AppActionButton @click="onAddDescription">
2829
<UniconsText />
@@ -53,6 +54,7 @@ import { useSnippetStore } from '@/store/snippets'
5354
import { useDebounceFn } from '@vueuse/core'
5455
import { computed, onUnmounted, ref } from 'vue'
5556
import { useAppStore } from '@/store/app'
57+
import { track } from '@/electron'
5658
5759
const snippetStore = useSnippetStore()
5860
const appStore = useAppStore()
@@ -77,6 +79,10 @@ const onClickMarkdownPreview = () => {
7779
const onClickScreenshotPreview = () => {
7880
snippetStore.isScreenshotPreview = !snippetStore.isScreenshotPreview
7981
}
82+
const onCodePreview = () => {
83+
snippetStore.isCodePreview = !snippetStore.isCodePreview
84+
track('snippets/code-preview')
85+
}
8086
8187
emitter.on('snippet:focus-name', () => {
8288
inputRef.value?.select()

src/renderer/components/snippets/SnippetsView.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
>
88
<template v-if="snippetStore.selected">
99
<SnippetHeader />
10+
<!-- TODO: упростить условия отображения -->
1011
<TheEditor
1112
v-if="
1213
!snippetStore.isMarkdownPreview && !snippetStore.isScreenshotPreview
@@ -18,6 +19,13 @@
1819
:is-search-mode="isSearchMode"
1920
:fragments="snippetStore.isFragmentsShow"
2021
/>
22+
<EditorPreview
23+
v-if="
24+
snippetStore.isCodePreview &&
25+
!snippetStore.isScreenshotPreview &&
26+
!snippetStore.isMarkdownPreview
27+
"
28+
/>
2129
<TheMarkdown
2230
v-if="
2331
snippetStore.isMarkdownPreview && !snippetStore.isScreenshotPreview

src/renderer/store/app.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { platform, store } from '@/electron'
22
import type {
3+
CodePreviewSettings,
34
EditorSettings,
45
ScreenshotSettings,
56
State,
@@ -29,6 +30,10 @@ const SCREENSHOT_DEFAULTS: ScreenshotSettings = {
2930
width: 600
3031
}
3132

33+
const CODE_PREVIEW_DEFAULTS: CodePreviewSettings = {
34+
darkMode: false
35+
}
36+
3237
export const useAppStore = defineStore('app', {
3338
state: (): State => ({
3439
isInit: false,
@@ -38,6 +43,7 @@ export const useAppStore = defineStore('app', {
3843
titlebar: 15,
3944
sidebar: 180,
4045
snippetList: 250,
46+
codePreviewHeight: 200,
4147
editor: {
4248
titleHeight: 34,
4349
fragmentsHeight: 25,
@@ -48,6 +54,7 @@ export const useAppStore = defineStore('app', {
4854
},
4955
editor: EDITOR_DEFAULTS,
5056
screenshot: SCREENSHOT_DEFAULTS,
57+
codePreview: CODE_PREVIEW_DEFAULTS,
5158
selectedPreferencesMenu: 'storage',
5259
version,
5360
platform: platform()

0 commit comments

Comments
 (0)