mirror of
https://github.com/marktext/marktext.git
synced 2025-05-02 22:41:53 +08:00
feature: feedback via twitter
bugfix: can not save when there is no file edited optimization: Don't show welcome page when init App
This commit is contained in:
parent
fe6645e684
commit
8c392a7a5c
5786
package-lock.json
generated
5786
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -247,6 +247,10 @@ export const newTab = win => {
|
|||||||
win.webContents.send('AGANI::new-tab')
|
win.webContents.send('AGANI::new-tab')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const closeTab = win => {
|
||||||
|
win.webContents.send('AGANI::close-tab')
|
||||||
|
}
|
||||||
|
|
||||||
export const save = win => {
|
export const save = win => {
|
||||||
win.webContents.send('AGANI::ask-file-save')
|
win.webContents.send('AGANI::ask-file-save')
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
export const showAboutDialog = win => {
|
export const showAboutDialog = win => {
|
||||||
win.webContents.send('AGANI::about-dialog')
|
win.webContents.send('AGANI::about-dialog')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const showTweetDialog = (win, type) => {
|
||||||
|
win.webContents.send('AGANI::tweet', type)
|
||||||
|
}
|
||||||
|
@ -76,6 +76,14 @@ export default function (recentlyUsedFiles) {
|
|||||||
|
|
||||||
fileMenu.submenu.push({
|
fileMenu.submenu.push({
|
||||||
type: 'separator'
|
type: 'separator'
|
||||||
|
}, {
|
||||||
|
label: 'Close Tab',
|
||||||
|
accelerator: 'CmdOrCtrl+W',
|
||||||
|
click (menuItem, browserWindow) {
|
||||||
|
actions.closeTab(browserWindow)
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
type: 'separator'
|
||||||
}, {
|
}, {
|
||||||
label: 'Save',
|
label: 'Save',
|
||||||
accelerator: 'CmdOrCtrl+S',
|
accelerator: 'CmdOrCtrl+S',
|
||||||
|
@ -10,34 +10,41 @@ export default {
|
|||||||
role: 'help',
|
role: 'help',
|
||||||
submenu: [{
|
submenu: [{
|
||||||
label: 'Learn More',
|
label: 'Learn More',
|
||||||
click: function () {
|
click () {
|
||||||
shell.openExternal('https://github.com/marktext/marktext')
|
shell.openExternal('https://github.com/marktext/marktext')
|
||||||
}
|
}
|
||||||
}, {
|
|
||||||
label: 'Report Issue',
|
|
||||||
click: function () {
|
|
||||||
shell.openExternal('https://github.com/marktext/marktext/issues')
|
|
||||||
}
|
|
||||||
}, {
|
}, {
|
||||||
label: 'Source Code on GitHub',
|
label: 'Source Code on GitHub',
|
||||||
click: function () {
|
click () {
|
||||||
shell.openExternal('https://github.com/marktext/marktext')
|
shell.openExternal('https://github.com/marktext/marktext')
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
label: 'Changelog',
|
label: 'Changelog',
|
||||||
click: function () {
|
click () {
|
||||||
shell.openExternal('https://github.com/marktext/marktext/blob/master/.github/CHANGELOG.md')
|
shell.openExternal('https://github.com/marktext/marktext/blob/master/.github/CHANGELOG.md')
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
label: 'Markdown syntax',
|
label: 'Markdown syntax',
|
||||||
click: function () {
|
click () {
|
||||||
shell.openExternal('https://spec.commonmark.org/0.28/')
|
shell.openExternal('https://spec.commonmark.org/0.28/')
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
type: 'separator'
|
type: 'separator'
|
||||||
|
}, {
|
||||||
|
label: 'Feedback via Twitter',
|
||||||
|
click (item, win) {
|
||||||
|
actions.showTweetDialog(win, 'twitter')
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
label: 'Report Issue or Feature request',
|
||||||
|
click () {
|
||||||
|
shell.openExternal('https://github.com/marktext/marktext/issues')
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
type: 'separator'
|
||||||
}, {
|
}, {
|
||||||
label: 'Follow @Jocs on Github',
|
label: 'Follow @Jocs on Github',
|
||||||
click: function () {
|
click () {
|
||||||
shell.openExternal('https://github.com/Jocs')
|
shell.openExternal('https://github.com/Jocs')
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
|
@ -42,7 +42,7 @@ export default {
|
|||||||
}, {
|
}, {
|
||||||
type: 'separator'
|
type: 'separator'
|
||||||
}, {
|
}, {
|
||||||
label: 'Quit',
|
label: 'Quit Mark Text',
|
||||||
accelerator: 'Command+Q',
|
accelerator: 'Command+Q',
|
||||||
click: app.quit
|
click: app.quit
|
||||||
}]
|
}]
|
||||||
|
@ -38,7 +38,7 @@ let viewMenu = {
|
|||||||
}, {
|
}, {
|
||||||
id: 'typewriterModeMenuItem',
|
id: 'typewriterModeMenuItem',
|
||||||
label: 'Typewriter Mode',
|
label: 'Typewriter Mode',
|
||||||
accelerator: 'Option+CmdOrCtrl+T',
|
accelerator: 'Alt+CmdOrCtrl+T',
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
checked: false,
|
checked: false,
|
||||||
click (item, browserWindow) {
|
click (item, browserWindow) {
|
||||||
|
@ -6,8 +6,8 @@ export default {
|
|||||||
accelerator: 'CmdOrCtrl+M',
|
accelerator: 'CmdOrCtrl+M',
|
||||||
role: 'minimize'
|
role: 'minimize'
|
||||||
}, {
|
}, {
|
||||||
label: 'Close',
|
label: 'Close Window',
|
||||||
accelerator: 'CmdOrCtrl+W',
|
accelerator: 'Shift+CmdOrCtrl+W',
|
||||||
role: 'close'
|
role: 'close'
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
@ -12,10 +12,10 @@
|
|||||||
<div class="editor-middle">
|
<div class="editor-middle">
|
||||||
<side-bar></side-bar>
|
<side-bar></side-bar>
|
||||||
<recent
|
<recent
|
||||||
v-if="!hasCurrentFile"
|
v-if="!hasCurrentFile && init"
|
||||||
></recent>
|
></recent>
|
||||||
<editor-with-tabs
|
<editor-with-tabs
|
||||||
v-else
|
v-if="hasCurrentFile && init"
|
||||||
:markdown="markdown"
|
:markdown="markdown"
|
||||||
:cursor="cursor"
|
:cursor="cursor"
|
||||||
:theme="theme"
|
:theme="theme"
|
||||||
@ -32,6 +32,7 @@
|
|||||||
<about-dialog></about-dialog>
|
<about-dialog></about-dialog>
|
||||||
<font></font>
|
<font></font>
|
||||||
<rename></rename>
|
<rename></rename>
|
||||||
|
<tweet></tweet>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -46,6 +47,7 @@
|
|||||||
import AboutDialog from '@/components/about'
|
import AboutDialog from '@/components/about'
|
||||||
import Font from '@/components/font'
|
import Font from '@/components/font'
|
||||||
import Rename from '@/components/rename'
|
import Rename from '@/components/rename'
|
||||||
|
import Tweet from '@/components/tweet'
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -60,7 +62,8 @@
|
|||||||
UploadImage,
|
UploadImage,
|
||||||
AboutDialog,
|
AboutDialog,
|
||||||
Font,
|
Font,
|
||||||
Rename
|
Rename,
|
||||||
|
Tweet
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {}
|
return {}
|
||||||
@ -80,7 +83,7 @@
|
|||||||
'wordCount': state => state.editor.currentFile.wordCount
|
'wordCount': state => state.editor.currentFile.wordCount
|
||||||
}),
|
}),
|
||||||
...mapState([
|
...mapState([
|
||||||
'windowActive', 'platform'
|
'windowActive', 'platform', 'init'
|
||||||
]),
|
]),
|
||||||
hasCurrentFile () {
|
hasCurrentFile () {
|
||||||
return this.markdown !== undefined
|
return this.markdown !== undefined
|
||||||
@ -90,6 +93,8 @@
|
|||||||
const { dispatch } = this.$store
|
const { dispatch } = this.$store
|
||||||
// store/index.js
|
// store/index.js
|
||||||
dispatch('LINTEN_WIN_STATUS')
|
dispatch('LINTEN_WIN_STATUS')
|
||||||
|
// module: tweet
|
||||||
|
dispatch('LISTEN_FOR_TWEET')
|
||||||
// module: layout
|
// module: layout
|
||||||
dispatch('LISTEN_FOR_LAYOUT')
|
dispatch('LISTEN_FOR_LAYOUT')
|
||||||
dispatch('LISTEN_FOR_REQUEST_LAYOUT')
|
dispatch('LISTEN_FOR_REQUEST_LAYOUT')
|
||||||
@ -121,6 +126,7 @@
|
|||||||
dispatch('LISTEN_FOR_RENAME')
|
dispatch('LISTEN_FOR_RENAME')
|
||||||
dispatch('LINTEN_FOR_SET_LINE_ENDING')
|
dispatch('LINTEN_FOR_SET_LINE_ENDING')
|
||||||
dispatch('LISTEN_FOR_NEW_TAB')
|
dispatch('LISTEN_FOR_NEW_TAB')
|
||||||
|
dispatch('LISTEN_FOR_CLOSE_TAB')
|
||||||
// module: notification
|
// module: notification
|
||||||
dispatch('LISTEN_FOR_NOTIFICATION')
|
dispatch('LISTEN_FOR_NOTIFICATION')
|
||||||
}
|
}
|
||||||
|
File diff suppressed because one or more lines are too long
@ -236,6 +236,7 @@
|
|||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
.search-wrapper {
|
.search-wrapper {
|
||||||
|
margin: 0 auto;
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -243,7 +244,6 @@
|
|||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
width: 410px;
|
width: 410px;
|
||||||
margin: 0 auto;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
<li
|
<li
|
||||||
v-for="(icon, index) of sideBarBottomIcons"
|
v-for="(icon, index) of sideBarBottomIcons"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
@click="handleLeftBottomClick(icon.name)"
|
||||||
>
|
>
|
||||||
<svg class="icon" aria-hidden="true">
|
<svg class="icon" aria-hidden="true">
|
||||||
<use :xlink:href="'#' + icon.icon"></use>
|
<use :xlink:href="'#' + icon.icon"></use>
|
||||||
@ -50,6 +51,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { sideBarIcons, sideBarBottomIcons } from './help'
|
import { sideBarIcons, sideBarBottomIcons } from './help'
|
||||||
|
import bus from '../../bus'
|
||||||
import Tree from './tree.vue'
|
import Tree from './tree.vue'
|
||||||
import SideBarSearch from './search.vue'
|
import SideBarSearch from './search.vue'
|
||||||
import Toc from './toc.vue'
|
import Toc from './toc.vue'
|
||||||
@ -126,6 +128,11 @@
|
|||||||
this.$store.commit('SET_LAYOUT', { rightColumn: name })
|
this.$store.commit('SET_LAYOUT', { rightColumn: name })
|
||||||
this.sideBarViewWidth = +this.sideBarWidth
|
this.sideBarViewWidth = +this.sideBarWidth
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
handleLeftBottomClick (name) {
|
||||||
|
if (name === 'twitter') {
|
||||||
|
bus.$emit('tweetDialog')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,7 +142,6 @@
|
|||||||
.side-bar {
|
.side-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: calc(100vh - 22px);
|
height: calc(100vh - 22px);
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
color: var(--secondaryColor);
|
color: var(--secondaryColor);
|
||||||
}
|
}
|
||||||
@ -175,11 +181,20 @@
|
|||||||
& > svg {
|
& > svg {
|
||||||
width: 1em;
|
width: 1em;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
opacity: 0;
|
opacity: 1;
|
||||||
color: var(--secondaryColor);
|
color: var(--secondaryColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.left-column ul.bottom li {
|
||||||
|
& > svg {
|
||||||
|
transition: transform .25s ease-in-out;
|
||||||
|
}
|
||||||
|
&:hover > svg {
|
||||||
|
color: #1da1f2;
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
.side-bar:hover .left-column ul li svg {
|
.side-bar:hover .left-column ul li svg {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
200
src/renderer/components/tweet/index.vue
Normal file
200
src/renderer/components/tweet/index.vue
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
<template>
|
||||||
|
<div class="tweet-dialog" :class="theme">
|
||||||
|
<el-dialog
|
||||||
|
:visible.sync="showTweetDialog"
|
||||||
|
:show-close="false"
|
||||||
|
:modal="true"
|
||||||
|
custom-class="ag-dialog-table"
|
||||||
|
width="450px"
|
||||||
|
>
|
||||||
|
<div slot="title" class="title">
|
||||||
|
<span>Send us feedback via tweet</span>
|
||||||
|
</div>
|
||||||
|
<div class="body">
|
||||||
|
<div class="feeling">
|
||||||
|
<div>What's your experience feelings?</div>
|
||||||
|
<ul>
|
||||||
|
<li
|
||||||
|
:class="{ 'active': selectedFace === 'smile' }"
|
||||||
|
@click="faceClick('smile')"
|
||||||
|
>
|
||||||
|
<svg class="icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-smile"></use>
|
||||||
|
</svg>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
:class="{ 'active': selectedFace === 'sad' }"
|
||||||
|
@click="faceClick('sad')"
|
||||||
|
>
|
||||||
|
<svg class="icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-sad"></use>
|
||||||
|
</svg>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="feedback">
|
||||||
|
<div>Tell us your feedback?</div>
|
||||||
|
<textarea cols="30" rows="10" v-model="value" ref="textarea"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="button">
|
||||||
|
<a
|
||||||
|
href="javascript:;"
|
||||||
|
class="github"
|
||||||
|
@click="reportViaGithub"
|
||||||
|
>
|
||||||
|
Report bug or feature request via github
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="javascript:;"
|
||||||
|
class="twitter"
|
||||||
|
:class="{ 'active': value }"
|
||||||
|
@click="reportViaTwitter"
|
||||||
|
>
|
||||||
|
<svg class="icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-twitter"></use>
|
||||||
|
</svg>
|
||||||
|
Tweet
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { shell } from 'electron'
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
import bus from '../../bus'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
showTweetDialog: false,
|
||||||
|
value: '',
|
||||||
|
selectedFace: 'smile'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
'theme': state => state.preferences.theme
|
||||||
|
})
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
bus.$on('tweetDialog', this.showDialog)
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
bus.$off('tweetDialog', this.showDialog)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showDialog () {
|
||||||
|
this.showTweetDialog = true
|
||||||
|
this.value = ''
|
||||||
|
bus.$emit('editor-blur')
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.textarea.focus()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
faceClick (name) {
|
||||||
|
this.selectedFace = name
|
||||||
|
},
|
||||||
|
reportViaGithub () {
|
||||||
|
shell.openExternal('https://github.com/marktext/marktext/issues')
|
||||||
|
},
|
||||||
|
reportViaTwitter () {
|
||||||
|
const { value, selectedFace } = this
|
||||||
|
if (!value) return
|
||||||
|
const origin = 'https://twitter.com/intent/tweet'
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
via: 'marktextme',
|
||||||
|
url: encodeURI('https://github.com/marktext/marktext/'),
|
||||||
|
text: value
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedFace === 'smile') params.hashtags = 'happyMarkText'
|
||||||
|
|
||||||
|
shell.openExternal(`${origin}?${Object.keys(params).map(key => `${key}=${params[key]}`).join('&')}`)
|
||||||
|
this.showTweetDialog = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.tweet-dialog {
|
||||||
|
width: 450px;
|
||||||
|
& .title {
|
||||||
|
color: var(--regularColor);
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.feeling, .feedback {
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--secondaryColor);
|
||||||
|
}
|
||||||
|
.feeling {
|
||||||
|
& ul {
|
||||||
|
display: flex;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 45px;
|
||||||
|
& li {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& li > svg {
|
||||||
|
transition: color .25s ease-in-out;
|
||||||
|
width: 25px;
|
||||||
|
height: 25px;
|
||||||
|
}
|
||||||
|
& li:hover > svg, & li.active > svg {
|
||||||
|
color: rgb(255, 204, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.feedback {
|
||||||
|
& > textarea {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 15px 0;
|
||||||
|
padding: .5rem;
|
||||||
|
resize: none;
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--lightBorder);
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.button a.twitter {
|
||||||
|
color: var(--secondaryColor);
|
||||||
|
text-decoration: none;
|
||||||
|
width: auto;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
padding: 0 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-block;
|
||||||
|
background: #eee;
|
||||||
|
}
|
||||||
|
.button a.active, .button a.twitter:hover {
|
||||||
|
background: #1da1f2;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.button a.github {
|
||||||
|
color: var(--secondaryColor);
|
||||||
|
text-decoration: none;
|
||||||
|
&:hover {
|
||||||
|
color: #1da1f2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,6 +1,7 @@
|
|||||||
import { ipcRenderer } from 'electron'
|
import { ipcRenderer } from 'electron'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import bus from '../bus'
|
import bus from '../bus'
|
||||||
|
import { hasKeys } from '../util'
|
||||||
import { getOptionsFromState, getSingleFileState, getBlankFileState } from './help'
|
import { getOptionsFromState, getSingleFileState, getBlankFileState } from './help'
|
||||||
|
|
||||||
const toc = require('markdown-toc')
|
const toc = require('markdown-toc')
|
||||||
@ -62,7 +63,9 @@ const mutations = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
SET_SAVE_STATUS (state, status) {
|
SET_SAVE_STATUS (state, status) {
|
||||||
|
if (hasKeys(state.currentFile)) {
|
||||||
state.currentFile.isSaved = status
|
state.currentFile.isSaved = status
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SET_SAVE_STATUS_WHEN_REMOVE (state, { pathname }) {
|
SET_SAVE_STATUS_WHEN_REMOVE (state, { pathname }) {
|
||||||
state.tabs.forEach(f => {
|
state.tabs.forEach(f => {
|
||||||
@ -72,25 +75,39 @@ const mutations = {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
SET_MARKDOWN (state, markdown) {
|
SET_MARKDOWN (state, markdown) {
|
||||||
|
if (hasKeys(state.currentFile)) {
|
||||||
state.currentFile.markdown = markdown
|
state.currentFile.markdown = markdown
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SET_IS_UTF8_BOM_ENCODED (state, isUtf8BomEncoded) {
|
SET_IS_UTF8_BOM_ENCODED (state, isUtf8BomEncoded) {
|
||||||
|
if (hasKeys(state.currentFile)) {
|
||||||
state.currentFile.isUtf8BomEncoded = isUtf8BomEncoded
|
state.currentFile.isUtf8BomEncoded = isUtf8BomEncoded
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SET_LINE_ENDING (state, lineEnding) {
|
SET_LINE_ENDING (state, lineEnding) {
|
||||||
|
if (hasKeys(state.currentFile)) {
|
||||||
state.currentFile.lineEnding = lineEnding
|
state.currentFile.lineEnding = lineEnding
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SET_ADJUST_LINE_ENDING_ON_SAVE (state, adjustLineEndingOnSave) {
|
SET_ADJUST_LINE_ENDING_ON_SAVE (state, adjustLineEndingOnSave) {
|
||||||
|
if (hasKeys(state.currentFile)) {
|
||||||
state.currentFile.adjustLineEndingOnSave = adjustLineEndingOnSave
|
state.currentFile.adjustLineEndingOnSave = adjustLineEndingOnSave
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SET_WORD_COUNT (state, wordCount) {
|
SET_WORD_COUNT (state, wordCount) {
|
||||||
|
if (hasKeys(state.currentFile)) {
|
||||||
state.currentFile.wordCount = wordCount
|
state.currentFile.wordCount = wordCount
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SET_CURSOR (state, cursor) {
|
SET_CURSOR (state, cursor) {
|
||||||
|
if (hasKeys(state.currentFile)) {
|
||||||
state.currentFile.cursor = cursor
|
state.currentFile.cursor = cursor
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SET_HISTORY (state, history) {
|
SET_HISTORY (state, history) {
|
||||||
|
if (hasKeys(state.currentFile)) {
|
||||||
state.currentFile.history = history
|
state.currentFile.history = history
|
||||||
|
}
|
||||||
},
|
},
|
||||||
CLOSE_TABS (state, arr) {
|
CLOSE_TABS (state, arr) {
|
||||||
arr.forEach(id => {
|
arr.forEach(id => {
|
||||||
@ -147,13 +164,15 @@ const actions = {
|
|||||||
// need update line ending when change between tabs
|
// need update line ending when change between tabs
|
||||||
UPDATE_LINEENDING_MENU ({ commit, state }) {
|
UPDATE_LINEENDING_MENU ({ commit, state }) {
|
||||||
const { lineEnding } = state.currentFile
|
const { lineEnding } = state.currentFile
|
||||||
|
if (lineEnding) {
|
||||||
ipcRenderer.send('AGANI::update-line-ending-menu', lineEnding)
|
ipcRenderer.send('AGANI::update-line-ending-menu', lineEnding)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
CLOSE_SINGLE_FILE ({ commit, state }, file) {
|
CLOSE_SINGLE_FILE ({ commit, state }, file) {
|
||||||
const { id, pathname, markdown } = file
|
const { id, pathname, filename, markdown } = file
|
||||||
const options = getOptionsFromState(file)
|
const options = getOptionsFromState(file)
|
||||||
ipcRenderer.send('AGANI::save-close', [{ id, pathname, markdown, options }], true)
|
ipcRenderer.send('AGANI::save-close', [{ id, pathname, filename, markdown, options }], true)
|
||||||
},
|
},
|
||||||
|
|
||||||
// need pass some data to main process when `save` menu item clicked
|
// need pass some data to main process when `save` menu item clicked
|
||||||
@ -161,7 +180,9 @@ const actions = {
|
|||||||
ipcRenderer.on('AGANI::ask-file-save', () => {
|
ipcRenderer.on('AGANI::ask-file-save', () => {
|
||||||
const { id, pathname, markdown } = state.currentFile
|
const { id, pathname, markdown } = state.currentFile
|
||||||
const options = getOptionsFromState(state.currentFile)
|
const options = getOptionsFromState(state.currentFile)
|
||||||
|
if (id) {
|
||||||
ipcRenderer.send('AGANI::response-file-save', { id, pathname, markdown, options })
|
ipcRenderer.send('AGANI::response-file-save', { id, pathname, markdown, options })
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -170,7 +191,9 @@ const actions = {
|
|||||||
ipcRenderer.on('AGANI::ask-file-save-as', () => {
|
ipcRenderer.on('AGANI::ask-file-save-as', () => {
|
||||||
const { id, pathname, markdown } = state.currentFile
|
const { id, pathname, markdown } = state.currentFile
|
||||||
const options = getOptionsFromState(state.currentFile)
|
const options = getOptionsFromState(state.currentFile)
|
||||||
|
if (id) {
|
||||||
ipcRenderer.send('AGANI::response-file-save-as', { id, pathname, markdown, options })
|
ipcRenderer.send('AGANI::response-file-save-as', { id, pathname, markdown, options })
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -233,6 +256,7 @@ const actions = {
|
|||||||
ipcRenderer.on('AGANI::ask-file-move-to', () => {
|
ipcRenderer.on('AGANI::ask-file-move-to', () => {
|
||||||
const { id, pathname, markdown } = state.currentFile
|
const { id, pathname, markdown } = state.currentFile
|
||||||
const options = getOptionsFromState(state.currentFile)
|
const options = getOptionsFromState(state.currentFile)
|
||||||
|
if (!id) return
|
||||||
if (!pathname) {
|
if (!pathname) {
|
||||||
// if current file is a newly created file, just save it!
|
// if current file is a newly created file, just save it!
|
||||||
ipcRenderer.send('AGANI::response-file-save', { id, pathname, markdown, options })
|
ipcRenderer.send('AGANI::response-file-save', { id, pathname, markdown, options })
|
||||||
@ -252,6 +276,7 @@ const actions = {
|
|||||||
RESPONSE_FOR_RENAME ({ commit, state }) {
|
RESPONSE_FOR_RENAME ({ commit, state }) {
|
||||||
const { id, pathname, markdown } = state.currentFile
|
const { id, pathname, markdown } = state.currentFile
|
||||||
const options = getOptionsFromState(state.currentFile)
|
const options = getOptionsFromState(state.currentFile)
|
||||||
|
if (!id) return
|
||||||
if (!pathname) {
|
if (!pathname) {
|
||||||
// if current file is a newly created file, just save it!
|
// if current file is a newly created file, just save it!
|
||||||
ipcRenderer.send('AGANI::response-file-save', { id, pathname, markdown, options })
|
ipcRenderer.send('AGANI::response-file-save', { id, pathname, markdown, options })
|
||||||
@ -263,7 +288,7 @@ const actions = {
|
|||||||
// ask for main process to rename this file to a new name `newFilename`
|
// ask for main process to rename this file to a new name `newFilename`
|
||||||
RENAME ({ commit, state }, newFilename) {
|
RENAME ({ commit, state }, newFilename) {
|
||||||
const { id, pathname, filename } = state.currentFile
|
const { id, pathname, filename } = state.currentFile
|
||||||
if (filename !== newFilename) {
|
if (typeof filename === 'string' && filename !== newFilename) {
|
||||||
const newPathname = path.join(path.dirname(pathname), newFilename)
|
const newPathname = path.join(path.dirname(pathname), newFilename)
|
||||||
ipcRenderer.send('AGANI::rename', { id, pathname, newPathname })
|
ipcRenderer.send('AGANI::rename', { id, pathname, newPathname })
|
||||||
}
|
}
|
||||||
@ -282,6 +307,7 @@ const actions = {
|
|||||||
const fileState = getSingleFileState({ markdown, filename, pathname, options })
|
const fileState = getSingleFileState({ markdown, filename, pathname, options })
|
||||||
const { lineEnding } = options
|
const { lineEnding } = options
|
||||||
commit('SET_GLOBAL_LINE_ENDING', lineEnding)
|
commit('SET_GLOBAL_LINE_ENDING', lineEnding)
|
||||||
|
dispatch('INIT_STATUS', true)
|
||||||
dispatch('UPDATE_CURRENT_FILE', fileState)
|
dispatch('UPDATE_CURRENT_FILE', fileState)
|
||||||
bus.$emit('file-loaded', markdown)
|
bus.$emit('file-loaded', markdown)
|
||||||
commit('SET_LAYOUT', {
|
commit('SET_LAYOUT', {
|
||||||
@ -299,6 +325,19 @@ const actions = {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
LISTEN_FOR_CLOSE_TAB ({ commit, state, dispatch }) {
|
||||||
|
ipcRenderer.on('AGANI::close-tab', e => {
|
||||||
|
const file = state.currentFile
|
||||||
|
if (!hasKeys(file)) return
|
||||||
|
const { isSaved } = file
|
||||||
|
if (isSaved) {
|
||||||
|
dispatch('REMOVE_FILE_IN_TABS', file)
|
||||||
|
} else {
|
||||||
|
dispatch('CLOSE_SINGLE_FILE', file)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
NEW_BLANK_FILE ({ commit, state, dispatch }) {
|
NEW_BLANK_FILE ({ commit, state, dispatch }) {
|
||||||
const { tabs, lineEnding } = state
|
const { tabs, lineEnding } = state
|
||||||
const fileState = getBlankFileState(tabs, lineEnding)
|
const fileState = getBlankFileState(tabs, lineEnding)
|
||||||
@ -313,6 +352,7 @@ const actions = {
|
|||||||
const fileState = getBlankFileState(tabs, lineEnding)
|
const fileState = getBlankFileState(tabs, lineEnding)
|
||||||
const { markdown } = fileState
|
const { markdown } = fileState
|
||||||
commit('SET_GLOBAL_LINE_ENDING', lineEnding)
|
commit('SET_GLOBAL_LINE_ENDING', lineEnding)
|
||||||
|
dispatch('INIT_STATUS', true)
|
||||||
dispatch('UPDATE_CURRENT_FILE', fileState)
|
dispatch('UPDATE_CURRENT_FILE', fileState)
|
||||||
bus.$emit('file-loaded', markdown)
|
bus.$emit('file-loaded', markdown)
|
||||||
commit('SET_LAYOUT', {
|
commit('SET_LAYOUT', {
|
||||||
@ -385,12 +425,14 @@ const actions = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
EXPORT ({ commit, state }, { type, content }) {
|
EXPORT ({ commit, state }, { type, content }) {
|
||||||
|
if (!hasKeys(state.currentFile)) return
|
||||||
const { filename, pathname } = state.currentFile
|
const { filename, pathname } = state.currentFile
|
||||||
ipcRenderer.send('AGANI::response-export', { type, content, filename, pathname })
|
ipcRenderer.send('AGANI::response-export', { type, content, filename, pathname })
|
||||||
},
|
},
|
||||||
|
|
||||||
LISTEN_FOR_INSERT_IMAGE ({ commit, state }) {
|
LISTEN_FOR_INSERT_IMAGE ({ commit, state }) {
|
||||||
ipcRenderer.on('AGANI::INSERT_IMAGE', (e, { filename: imagePath, type }) => {
|
ipcRenderer.on('AGANI::INSERT_IMAGE', (e, { filename: imagePath, type }) => {
|
||||||
|
if (!hasKeys(state.currentFile)) return
|
||||||
if (type === 'absolute' || type === 'relative') {
|
if (type === 'absolute' || type === 'relative') {
|
||||||
const { pathname } = state.currentFile
|
const { pathname } = state.currentFile
|
||||||
if (type === 'relative' && pathname) {
|
if (type === 'relative' && pathname) {
|
||||||
|
@ -10,6 +10,7 @@ import layout from './layout'
|
|||||||
import preferences from './preferences'
|
import preferences from './preferences'
|
||||||
import autoUpdates from './autoUpdates'
|
import autoUpdates from './autoUpdates'
|
||||||
import notification from './notification'
|
import notification from './notification'
|
||||||
|
import tweet from './tweet'
|
||||||
|
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
|
|
||||||
@ -17,7 +18,8 @@ Vue.use(Vuex)
|
|||||||
const state = {
|
const state = {
|
||||||
platform: process.platform, // platform of system `darwin` | `win32` | `linux`
|
platform: process.platform, // platform of system `darwin` | `win32` | `linux`
|
||||||
appVersion: remote.app.getVersion(), // electron version in develop and Mark Text version in production
|
appVersion: remote.app.getVersion(), // electron version in develop and Mark Text version in production
|
||||||
windowActive: true // weather current window is active or focused
|
windowActive: true, // weather current window is active or focused
|
||||||
|
init: process.env.NODE_ENV === 'development' // weather Mark Text is inited
|
||||||
}
|
}
|
||||||
|
|
||||||
const getters = {}
|
const getters = {}
|
||||||
@ -25,6 +27,9 @@ const getters = {}
|
|||||||
const mutations = {
|
const mutations = {
|
||||||
SET_WIN_STATUS (state, status) {
|
SET_WIN_STATUS (state, status) {
|
||||||
state.windowActive = status
|
state.windowActive = status
|
||||||
|
},
|
||||||
|
SET_INIT_STATUS (state, status) {
|
||||||
|
state.init = status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,6 +38,9 @@ const actions = {
|
|||||||
ipcRenderer.on('AGANI::window-active-status', (e, { status }) => {
|
ipcRenderer.on('AGANI::window-active-status', (e, { status }) => {
|
||||||
commit('SET_WIN_STATUS', status)
|
commit('SET_WIN_STATUS', status)
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
INIT_STATUS ({ commit }, status) {
|
||||||
|
commit('SET_INIT_STATUS', status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,6 +54,7 @@ const store = new Vuex.Store({
|
|||||||
listenForMain,
|
listenForMain,
|
||||||
autoUpdates,
|
autoUpdates,
|
||||||
notification,
|
notification,
|
||||||
|
tweet,
|
||||||
// have states
|
// have states
|
||||||
project,
|
project,
|
||||||
aidou,
|
aidou,
|
||||||
|
@ -85,6 +85,7 @@ const mutations = {
|
|||||||
const actions = {
|
const actions = {
|
||||||
LISTEN_FOR_LOAD_PROJECT ({ commit, dispatch }) {
|
LISTEN_FOR_LOAD_PROJECT ({ commit, dispatch }) {
|
||||||
ipcRenderer.on('AGANI::open-project', (e, { pathname, name }) => {
|
ipcRenderer.on('AGANI::open-project', (e, { pathname, name }) => {
|
||||||
|
dispatch('INIT_STATUS', true)
|
||||||
commit('SET_PROJECT_TREE', { pathname, name })
|
commit('SET_PROJECT_TREE', { pathname, name })
|
||||||
commit('SET_LAYOUT', {
|
commit('SET_LAYOUT', {
|
||||||
rightColumn: 'files',
|
rightColumn: 'files',
|
||||||
|
20
src/renderer/store/tweet.js
Normal file
20
src/renderer/store/tweet.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { ipcRenderer } from 'electron'
|
||||||
|
import bus from '../bus'
|
||||||
|
|
||||||
|
const state = {}
|
||||||
|
|
||||||
|
const getters = {}
|
||||||
|
|
||||||
|
const mutations = {}
|
||||||
|
|
||||||
|
const actions = {
|
||||||
|
LISTEN_FOR_TWEET () {
|
||||||
|
ipcRenderer.on('AGANI::tweet', (e, type) => {
|
||||||
|
if (type === 'twitter') {
|
||||||
|
bus.$emit('tweetDialog')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default { state, getters, mutations, actions }
|
@ -174,3 +174,5 @@ export const animatedScrollTo = function (element, to, duration, callback) {
|
|||||||
export const getUniqueId = () => {
|
export const getUniqueId = () => {
|
||||||
return `${ID_PREFEX}${id++}`
|
return `${ID_PREFEX}${id++}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const hasKeys = obj => Object.keys(obj).length > 0
|
||||||
|
@ -81,8 +81,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.v-modal {
|
.v-modal {
|
||||||
background: #fff;
|
background: rgba(230, 230, 230, .9);
|
||||||
opacity: .8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body>*:first-child {
|
body>*:first-child {
|
||||||
|
Loading…
Reference in New Issue
Block a user