Skip to content

Commit 2ab2e6a

Browse files
authored
Presentation mode (#57)
* presentation mode * fix attrs * add distraction-free mode aka hide footer in normal window and hide header and footer in full-screen * add indicator * tweaks * extract presentation control panel as a component * enable arrow keys in preview mode * extract writing modes control panel support using ctrl/cmd + shift + \ to switch mode * fix lint * fix typo * update print result for presentation * add more animations * fix lint
1 parent 2693d85 commit 2ab2e6a

17 files changed

+399
-88
lines changed

app/eme/menu.js

+7
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,13 @@ module.exports = cb => {
205205
{
206206
type: 'separator'
207207
},
208+
{
209+
label: 'Toggle Distraction Free mode',
210+
accelerator: 'CmdOrCtrl+J',
211+
click(item, focusedWindow) {
212+
if (focusedWindow) focusedWindow.webContents.send('toggle-distraction-free-mode')
213+
}
214+
},
208215
{
209216
label: 'Toggle Focus Mode',
210217
accelerator: 'CmdOrCtrl+\\',

app/eme/window.js

+8
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ class Window {
4747
web.send('win-focus')
4848
})
4949

50+
win.on('enter-full-screen', () => {
51+
web.send('enter-full-screen')
52+
})
53+
54+
win.on('leave-full-screen', () => {
55+
web.send('leave-full-screen')
56+
})
57+
5058
if (isDev) {
5159
const installExtension = require('electron-devtools-installer')
5260
installExtension.default(installExtension.VUEJS_DEVTOOLS)

app/vendor/css/print.css

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.slide:not(:last-child) {
2+
margin-bottom: 30px;
3+
}

app/welcome-guide.md

+33-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,36 @@ EME is trying to give you the best experience of writing in Markdown.
66

77
Markdown shines ✨
88

9-
![shiny](http://ww4.sinaimg.cn/large/a15b4afegw1f6499jo5ruj20iw0anmxv.jpg)
9+
![shiny](http://ww4.sinaimg.cn/large/a15b4afegw1f6499jo5ruj20iw0anmxv.jpg)
10+
11+
## Focus Mode
12+
13+
The first feature that most markdown editors do not have is, focus the paragraph you are actually writing. It reduces a lot of distractions when you are working on a long post. Use <kbd>Ctrl/CMD + \</kbd> to toggle it.
14+
15+
## Distraction Free Mode
16+
17+
One step further, you may want to hide the header and footer when you are writing in full-screen. Use <kbd>Ctrl/CMD + J</kbd> to toggle it.
18+
19+
## Vim Mode
20+
21+
For developers, you may miss the vim key binding, here it is. Use <kbd>Ctrl/CMD + I</kbd> to toggle it.
22+
23+
## Presentation Mode
24+
25+
You can event write markdown and render then in slides! Here's a example:
26+
27+
```markdown
28+
# title
29+
# subtitle
30+
31+
---
32+
33+
# another title
34+
## another subtitle
35+
```
36+
37+
Use <kbd>Ctrl/CMD + K</kbd> to toggle it!
38+
39+
## Shortcuts
40+
41+
Please view: https://github.com/egoist/eme/wiki/Key-bindings

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"editor"
2727
],
2828
"devDependencies": {
29+
"autoprefixer": "^6.4.0",
2930
"babel-eslint": "^6.1.2",
3031
"babel-loader": "^6.2.4",
3132
"babel-plugin-transform-runtime": "^6.9.0",
@@ -64,6 +65,7 @@
6465
"webpack-visualizer-plugin": "^0.1.5"
6566
},
6667
"dependencies": {
68+
"animate.css": "^3.5.1",
6769
"babel-runtime": "^6.9.2",
6870
"codemirror": "^5.17.0",
6971
"highlight.js": "^9.5.0",

scripts/webpack.config.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ module.exports = {
5555
require('postcss-nested'),
5656
require('postcss-simple-vars'),
5757
require('postcss-import')(),
58-
require('postcss-mixins')
58+
require('postcss-mixins'),
59+
require('autoprefixer')({
60+
browsers: ['last 2 Chrome versions']
61+
})
5962
],
6063
loaders: {
6164
css: ExtractTextPlugin.extract(

src/app.vue

+44-3
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,66 @@
11
<style src="hint.css/hint.css"></style>
2+
<style src="animate.css/animate.css"></style>
23
<style src="./css/reset"></style>
34
<style src="./css/editor-reset"></style>
45

56
<template>
6-
<div id="app">
7-
<app-header></app-header>
7+
<div id="app"
8+
:class="{
9+
'distraction-free': isDistractionFreeMode,
10+
'full-screen': isFullScreen
11+
}">
12+
<app-header v-if="!isDistractionFreeMode || (isDistractionFreeMode && !isFullScreen)"></app-header>
813
<app-main></app-main>
9-
<app-footer></app-footer>
14+
<app-footer v-if="showFooter()"></app-footer>
1015
</div>
1116
</template>
1217

1318
<script>
19+
import {ipcRenderer, remote} from 'electron'
20+
1421
import appHeader from './components/header'
1522
import appMain from './components/main'
1623
import appFooter from './components/footer'
24+
import {$} from 'utils/dom'
25+
26+
const currentWindow = remote.getCurrentWindow()
1727
1828
export default {
29+
data() {
30+
return {
31+
isDistractionFreeMode: false,
32+
isFullScreen: currentWindow.isFullScreen()
33+
}
34+
},
35+
vuex: {
36+
getters: {
37+
tabsAmount: state => state.editor.tabs.length,
38+
}
39+
},
1940
components: {
2041
appHeader,
2142
appMain,
2243
appFooter
44+
},
45+
ready() {
46+
ipcRenderer.on('toggle-distraction-free-mode', () => {
47+
this.isDistractionFreeMode = !this.isDistractionFreeMode
48+
})
49+
ipcRenderer.on('enter-full-screen', () => {
50+
this.isFullScreen = true
51+
})
52+
ipcRenderer.on('leave-full-screen', () => {
53+
this.isFullScreen = false
54+
})
55+
},
56+
methods: {
57+
showFooter() {
58+
return this.tabsAmount > 0 &&
59+
(
60+
!this.isDistractionFreeMode ||
61+
(this.isDistractionFreeMode && !this.isFullScreen)
62+
)
63+
}
2364
}
2465
}
2566
</script>

src/components/footer.vue

+19-55
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@
8181
path {
8282
fill: #666;
8383
}
84+
.disabled & path {
85+
fill: #ccc;
86+
}
8487
}
8588
.presentation-footer-control,
8689
.writing-modes {
@@ -94,51 +97,21 @@
9497
</style>
9598

9699
<template>
97-
<footer class="footer" v-if="showFooter" :class="{'mac-footer': isMac}">
100+
<footer class="footer" :class="{'mac-footer': isMac}">
98101
<span class="file-path" v-if="status.filePath">{{ status.filePath }}</span>
99102
<span class="word-count">{{ status.wordCount }} words</span>
100103
<span class="pdf-link clickable-link" v-if="status.pdf" @click="openPDF(status.pdf)">PDF</span>
101104
<div class="footer-right">
102-
<div class="footer-icon-group presentation-footer-control" v-if="status.isPresentationMode">
103-
<span
104-
aria-label="Previous Slide"
105-
class="footer-icon-item hint--top-left hint--rounded"
106-
@click="moveSlide('left')">
107-
<svg-icon name="arrowLeft" class="footer-icon"></svg-icon>
108-
</span>
109-
<span class="footer-icon-item">
110-
{{ status.slides.current + 1 }}/{{ status.slides.total }}
111-
</span>
112-
<span
113-
aria-label="Next Slide"
114-
class="footer-icon-item hint--top-right hint--rounded"
115-
@click="moveSlide('right')">
116-
<svg-icon name="arrowRight" class="footer-icon"></svg-icon>
117-
</span>
118-
</div>
119-
<div class="footer-icon-group writing-modes" v-if="status.writingMode">
120-
<span
121-
aria-label="Editor only"
122-
class="footer-icon-item writing-mode hint--top-left hint--rounded"
123-
:class="{active: status.writingMode === 'writing'}"
124-
@click="setWritingMode('writing')">
125-
<svg-icon name="pencil" class="footer-icon"></svg-icon>
126-
</span>
127-
<span
128-
aria-label="Editor and Preview"
129-
class="footer-icon-item writing-mode hint--top-left hint--rounded"
130-
:class="{active: status.writingMode === 'default'}"
131-
@click="setWritingMode('default')">
132-
<svg-icon name="alignHorizontalMiddle" class="footer-icon"></svg-icon>
133-
</span>
134-
<span
135-
aria-label="Preview only"
136-
class="footer-icon-item writing-mode hint--top-left hint--rounded"
137-
:class="{active: status.writingMode === 'preview'}"
138-
@click="setWritingMode('preview')">
139-
<svg-icon name="eye" class="footer-icon"></svg-icon>
140-
</span>
141-
</div>
105+
<presentation-control
106+
:slides="status.slides"
107+
:writing-mode="status.writingMode"
108+
v-if="status.isPresentationMode">
109+
</presentation-control>
110+
<writing-modes
111+
:writing-mode="status.writingMode"
112+
:current-tab-index="currentTabIndex"
113+
v-if="status.writingMode">
114+
</writing-modes>
142115
</div>
143116
</footer>
144117
</template>
@@ -147,12 +120,13 @@
147120
import tildify from 'tildify'
148121
import {isMac} from 'utils/os'
149122
import {shell} from 'electron'
150-
import SvgIcon from 'components/svg-icon'
123+
124+
import PresentationControl from 'components/presentation-control'
125+
import WritingModes from 'components/writing-modes'
151126
152127
export default {
153128
vuex: {
154129
getters: {
155-
showFooter: state => state.editor.tabs.length > 0,
156130
currentTabIndex: state => state.editor.currentTabIndex,
157131
status: state => {
158132
const editor = state.editor.tabs[state.editor.currentTabIndex] || {}
@@ -170,17 +144,6 @@
170144
}
171145
}
172146
}
173-
},
174-
actions: {
175-
setWritingMode({dispatch}, mode) {
176-
dispatch('SET_WRITING_MODE', {
177-
index: this.currentTabIndex,
178-
mode
179-
})
180-
},
181-
moveSlide({dispatch}, direction) {
182-
dispatch('MOVE_SLIDE', direction)
183-
}
184147
}
185148
},
186149
data() {
@@ -194,7 +157,8 @@
194157
}
195158
},
196159
components: {
197-
SvgIcon
160+
PresentationControl,
161+
WritingModes
198162
}
199163
}
200164
</script>

src/components/header.vue

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
-webkit-app-region: drag;
1010
&.is-mac {
1111
padding-left: 80px;
12+
.full-screen & {
13+
padding-left: 0;
14+
}
1215
}
1316
.tab {
1417
height: $header-height;

src/components/main.vue

+20-4
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55

66
<style>
77
.main {
8+
/* total - header - footer */
89
height: calc(100% - 36px - 25px);
10+
.distraction-free.full-screen & {
11+
height: 100%;
12+
}
913
}
1014
.tab-body {
11-
/* total - header - footer */
1215
height: 100%;
1316
display: flex;
1417
&.resizing {
@@ -55,6 +58,10 @@
5558
}
5659
.preview {
5760
padding: 10px;
61+
overflow-x: hidden;
62+
&.preview-presentation {
63+
padding: 0;
64+
}
5865
&::-webkit-scrollbar {
5966
width: 0;
6067
}
@@ -105,7 +112,13 @@
105112
<div class="resize-bar" @mousedown="resizeStart($event, $index)"></div>
106113
</div>
107114
<div
108-
:class="'preview preview-' + $index"
115+
:class="[
116+
'preview',
117+
'preview-' + $index,
118+
{
119+
'preview-presentation': tab.isPresentationMode
120+
}
121+
]"
109122
:style="{ width: (100 - tab.split) + '%' }"
110123
v-show="currentTab && currentTab.writingMode !== 'writing'">
111124
<presentation :slides="tab.html" v-if="tab.isPresentationMode"></presentation>
@@ -531,10 +544,13 @@
531544
})
532545
if (filePath) {
533546
const html = makeHTML({
534-
html: `<div class="markdown-body">${this.currentTab.html}</div>`,
547+
html: Array.isArray(this.currentTab.html) ?
548+
this.currentTab.html.map(html => `<div class="slide markdown-body">${html}</div>`).join('') :
549+
`<div class="markdown-body">${this.currentTab.html}</div>`,
535550
css: [
536551
appPath('vendor/github-markdown-css/github-markdown.css'),
537-
appPath('vendor/katex/katex.min.css')
552+
appPath('vendor/katex/katex.min.css'),
553+
appPath('vendor/css/print.css')
538554
]
539555
})
540556
ipcRenderer.send('print-to-pdf', html, filePath)

0 commit comments

Comments
 (0)