mirror of
https://github.com/marktext/marktext.git
synced 2025-05-02 08:51:36 +08:00
add tab scrolling and drag&drop (#953)
* add tab scrolling and drag&drop * fix tab maximal width without side bar * use dragula instead of vue-draggable * Update changelog * fix issues with maximal side bar width If the side bar is resized more than 50vw then issues occur because the commited width is not limited to 50vw or if the window is resized. * reordered tabs after dropping and some improvements
This commit is contained in:
parent
3b9c16779d
commit
620df2ee69
2
.github/CHANGELOG.md
vendored
2
.github/CHANGELOG.md
vendored
@ -5,6 +5,8 @@
|
||||
**:cactus:Feature**
|
||||
|
||||
- The cursor jump to the end of format or to the next brackets when press `tab`(#976)
|
||||
- Tab drag & drop inside the window
|
||||
- Scrollable tabs
|
||||
|
||||
**:butterfly:Optimization**
|
||||
|
||||
|
@ -170,7 +170,9 @@
|
||||
"codemirror": "^5.46.0",
|
||||
"command-exists": "^1.2.8",
|
||||
"dayjs": "^1.8.13",
|
||||
"dom-autoscroller": "^2.3.4",
|
||||
"dompurify": "^1.0.10",
|
||||
"dragula": "^3.7.2",
|
||||
"electron-is-accelerator": "^0.1.2",
|
||||
"element-resize-detector": "^1.2.0",
|
||||
"element-ui": "^2.8.2",
|
||||
|
@ -152,6 +152,9 @@
|
||||
|
||||
// prevent Chromium's default behavior and try to open the first file
|
||||
window.addEventListener('dragover', e => {
|
||||
// Cancel to allow tab drag&drop.
|
||||
if (!e.dataTransfer.types.length) return
|
||||
|
||||
e.preventDefault()
|
||||
if (e.dataTransfer.types.indexOf('Files') >= 0) {
|
||||
if (e.dataTransfer.items.length === 1 && /png|jpg|jpeg|gif/.test(e.dataTransfer.items[0].type)) {
|
||||
@ -201,6 +204,7 @@
|
||||
}
|
||||
.editor-middle {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
|
@ -48,9 +48,27 @@
|
||||
}
|
||||
|
||||
.editor-tabs {
|
||||
border-bottom: 1px solid #1d1d1d;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.editor-tabs:after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
border-bottom: 1px solid #1d1d1d;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
.editor-tabs ul.tabs-container:after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
border-bottom: 1px solid #1d1d1d;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.tabs-container > li,
|
||||
.tabs-container > li.active {
|
||||
background: var(--editorBgColor) !important;
|
||||
|
@ -27,15 +27,32 @@
|
||||
--editorAreaWidth: 700px;
|
||||
}
|
||||
|
||||
.title-bar.tabs-visible {
|
||||
.editor-tabs {
|
||||
background: #f3f3f3 !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.editor-tabs:after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
border-bottom: 1px solid #dddddd;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
.editor-tabs ul.tabs-container:after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
border-bottom: 1px solid #dddddd;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
.title-bar-editor-bg.tabs-visible {
|
||||
background: #f3f3f3 !important;
|
||||
}
|
||||
|
||||
.editor-tabs {
|
||||
background: #f3f3f3 !important;
|
||||
border-bottom: 1px solid #dddddd !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.tabs-container > li {
|
||||
background: none !important;
|
||||
}
|
||||
@ -45,7 +62,7 @@
|
||||
border-bottom: none;
|
||||
background: var(--floatBgColor) !important;
|
||||
}
|
||||
.tabs-container > li.active:not(:last-child):after {
|
||||
.tabs-container > li.active:after {
|
||||
top: 0 !important;
|
||||
bottom: auto !important;
|
||||
background: var(--themeColor) !important;
|
||||
|
@ -110,9 +110,27 @@
|
||||
}
|
||||
|
||||
.editor-tabs {
|
||||
border-bottom: 1px solid #181a1f;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.editor-tabs:after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
border-bottom: 1px solid #181a1f;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
.editor-tabs ul.tabs-container:after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
border-bottom: 1px solid #181a1f;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.tabs-container > li,
|
||||
.tabs-container > li.active {
|
||||
background: var(--editorBgColor) !important;
|
||||
@ -121,7 +139,7 @@
|
||||
border: 1px solid #181a1f;
|
||||
border-bottom: none;
|
||||
}
|
||||
.tabs-container > li.active:not(:last-child):after {
|
||||
.tabs-container > li.active:after {
|
||||
top: 0 !important;
|
||||
right: auto !important;
|
||||
width: 2px !important;
|
||||
|
@ -31,7 +31,7 @@
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.tabs-container > li:not(:last-child) {
|
||||
.tabs-container > li {
|
||||
border-right: 1px solid #e5e5e5 !important;
|
||||
background: var(--editorBgColor) !important;
|
||||
}
|
||||
|
@ -68,13 +68,12 @@
|
||||
|
||||
<style scoped>
|
||||
.editor-with-tabs {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
padding-top: var(--titleBarHeight);
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
|
||||
overflow: hidden;
|
||||
background: var(--editorBgColor);
|
||||
& > .container {
|
||||
|
@ -1,13 +1,22 @@
|
||||
<template>
|
||||
<div
|
||||
class="editor-tabs"
|
||||
:style="{'max-width': showSideBar ? `calc(100vw - ${sideBarWidth}px` : '100vw' }"
|
||||
>
|
||||
<div
|
||||
class="editor-tabs"
|
||||
class="scrollable-tabs"
|
||||
ref="tabContainer"
|
||||
>
|
||||
<ul class="tabs-container">
|
||||
<ul
|
||||
ref="tabDropContainer"
|
||||
class="tabs-container"
|
||||
>
|
||||
<li
|
||||
:title="file.pathname"
|
||||
:class="{'active': currentFile.id === file.id, 'unsaved': !file.isSaved }"
|
||||
v-for="(file, index) of tabs"
|
||||
:key="index"
|
||||
v-for="file of tabs"
|
||||
:key="file.id"
|
||||
:data-id="file.id"
|
||||
@click.stop="selectFile(file)"
|
||||
>
|
||||
<span>{{ file.filename }}</span>
|
||||
@ -18,32 +27,112 @@
|
||||
<use id="default-close-icon" xlink:href="#icon-close-small"></use>
|
||||
</svg>
|
||||
</li>
|
||||
<li class="new-file">
|
||||
<svg class="icon" aria-hidden="true"
|
||||
@click.stop="newFile()"
|
||||
>
|
||||
<use xlink:href="#icon-plus"></use>
|
||||
</svg>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
class="new-file"
|
||||
>
|
||||
<svg class="icon" aria-hidden="true"
|
||||
@click.stop="newFile()"
|
||||
>
|
||||
<use xlink:href="#icon-plus"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import autoScroll from 'dom-autoscroller'
|
||||
import dragula from 'dragula'
|
||||
import { tabsMixins } from '../../mixins'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
this.autoScroller = null
|
||||
this.drake = null
|
||||
return {}
|
||||
},
|
||||
mixins: [tabsMixins],
|
||||
computed: {
|
||||
...mapState({
|
||||
currentFile: state => state.editor.currentFile,
|
||||
tabs: state => state.editor.tabs
|
||||
'currentFile': state => state.editor.currentFile,
|
||||
'tabs': state => state.editor.tabs,
|
||||
'showSideBar': state => state.layout.showSideBar,
|
||||
'sideBarWidth': state => state.layout.sideBarWidth
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
newFile () {
|
||||
this.$store.dispatch('NEW_BLANK_FILE')
|
||||
},
|
||||
handleTabScroll (event) {
|
||||
// Use mouse wheel value first but prioritize X value more (e.g. touchpad input).
|
||||
let delta = event.deltaY
|
||||
if (event.deltaX !== 0) {
|
||||
delta = event.deltaX
|
||||
}
|
||||
|
||||
const tabs = this.$refs.tabContainer
|
||||
const newLeft = Math.max(0, Math.min(tabs.scrollLeft + delta, tabs.scrollWidth ))
|
||||
tabs.scrollLeft = newLeft
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
const tabs = this.$refs.tabContainer
|
||||
|
||||
// Allow to scroll through the tabs by mouse wheel or touchpad.
|
||||
tabs.addEventListener('wheel', this.handleTabScroll)
|
||||
|
||||
// Allow tab drag and drop to reorder tabs.
|
||||
const drake = this.drake = dragula([ this.$refs.tabDropContainer ], {
|
||||
direction: 'horizontal',
|
||||
revertOnSpill: true,
|
||||
mirrorContainer: this.$refs.tabDropContainer,
|
||||
ignoreInputTextSelection: false
|
||||
}).on('drop', (el, target, source, sibling) => {
|
||||
// Current tab that was dropped and need to be reordered.
|
||||
const droppedId = el.getAttribute('data-id')
|
||||
// This should be the next tab (tab | ... | el | sibling | tab | ...) but may be
|
||||
// the mirror image or null (tab | ... | el | sibling or null) if last tab.
|
||||
const nextTabId = sibling && sibling.getAttribute('data-id')
|
||||
const isLastTab = !sibling || sibling.classList.contains('gu-mirror')
|
||||
if (!droppedId || (sibling && !nextTabId)) {
|
||||
throw new Error('Cannot reorder tabs: invalid tab id.')
|
||||
}
|
||||
|
||||
this.$store.dispatch('EXCHANGE_TABS_BY_ID', {
|
||||
fromId: droppedId,
|
||||
toId: isLastTab ? null : nextTabId
|
||||
})
|
||||
})
|
||||
|
||||
// TODO(perf): Create a copy of dom-autoscroller and just hook tabs-container to
|
||||
// improve performance. Currently autoScroll is triggered when the mouse is moved
|
||||
// in Mark Text window.
|
||||
|
||||
// Scroll when dragging a tab to the beginning or end of the tab container.
|
||||
this.autoScroller = autoScroll([ tabs ], {
|
||||
margin: 20,
|
||||
maxSpeed: 6,
|
||||
scrollWhenOutside: false,
|
||||
autoScroll: () => {
|
||||
return this.autoScroller.down && drake.dragging
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
beforeDestroy () {
|
||||
const tabs = this.$refs.tabContainer
|
||||
tabs.removeEventListener('wheel', this.handleTabScroll)
|
||||
|
||||
if (this.autoScroller) {
|
||||
// Force destroy
|
||||
this.autoScroller.destroy(true)
|
||||
}
|
||||
if (this.drake) {
|
||||
this.drake.destroy()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -54,18 +143,33 @@
|
||||
fill: var(--themeColor);
|
||||
}
|
||||
.editor-tabs {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 35px;
|
||||
user-select: none;
|
||||
box-shadow: 0px 0px 9px 2px rgba(0, 0, 0, .1);
|
||||
overflow: hidden;
|
||||
&:hover > .new-file {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
}
|
||||
.scrollable-tabs {
|
||||
flex: 0 1 auto;
|
||||
height: 35px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.tabs-container {
|
||||
min-width: min-content;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 35px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: auto;
|
||||
overflow-y: hidden;
|
||||
z-index: 2;
|
||||
&::-webkit-scrollbar:horizontal {
|
||||
display: none;
|
||||
}
|
||||
@ -80,9 +184,15 @@
|
||||
background: var(--floatBgColor);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&[aria-grabbed="true"] {
|
||||
color: var(--editorColor30) !important;
|
||||
}
|
||||
& > svg {
|
||||
opacity: 0;
|
||||
}
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
&:hover > svg {
|
||||
opacity: 1;
|
||||
}
|
||||
@ -112,7 +222,8 @@
|
||||
}
|
||||
& > li.active {
|
||||
background: var(--itemBgColor);
|
||||
&:not(:last-child):after {
|
||||
z-index: 3;
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
@ -128,16 +239,39 @@
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
& > li.new-file {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
border-right: none;
|
||||
background: transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
cursor: pointer;
|
||||
}
|
||||
.editor-tabs > .new-file {
|
||||
flex: 0 0 35px;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
border-right: none;
|
||||
background: transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
cursor: pointer;
|
||||
color: var(--editorColor50);
|
||||
opacity: 0;
|
||||
&.always-visible {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* dragula effects */
|
||||
.gu-mirror {
|
||||
position: fixed !important;
|
||||
margin: 0 !important;
|
||||
z-index: 9999 !important;
|
||||
opacity: 0.8;
|
||||
cursor: grabbing;
|
||||
}
|
||||
.gu-hide {
|
||||
display: none !important;
|
||||
}
|
||||
.gu-unselectable {
|
||||
user-select: none !important;
|
||||
}
|
||||
.gu-transit {
|
||||
opacity: 0.2;
|
||||
}
|
||||
</style>
|
||||
|
@ -77,7 +77,7 @@
|
||||
'rightColumn': state => state.layout.rightColumn,
|
||||
'showSideBar': state => state.layout.showSideBar,
|
||||
'projectTree': state => state.project.projectTree,
|
||||
'sideBarWidth': state => state.project.sideBarWidth,
|
||||
'sideBarWidth': state => state.layout.sideBarWidth,
|
||||
'tabs': state => state.editor.tabs
|
||||
}),
|
||||
...mapGetters(['fileList']),
|
||||
@ -101,7 +101,7 @@
|
||||
const mouseUpHandler = event => {
|
||||
document.removeEventListener('mousemove', mouseMoveHandler, false)
|
||||
document.removeEventListener('mouseup', mouseUpHandler, false)
|
||||
this.$store.dispatch('CHANGE_SIDE_BAR_WIDTH', sideBarWidth)
|
||||
this.$store.dispatch('CHANGE_SIDE_BAR_WIDTH', sideBarWidth < 180 ? 180 : sideBarWidth)
|
||||
}
|
||||
|
||||
const mouseMoveHandler = event => {
|
||||
@ -141,7 +141,11 @@
|
||||
<style scoped>
|
||||
.side-bar {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
widows: 280px;
|
||||
height: 100vh;
|
||||
min-width: 180px;
|
||||
position: relative;
|
||||
color: var(--sideBarColor);
|
||||
user-select: none;
|
||||
|
@ -1,24 +1,7 @@
|
||||
<template>
|
||||
<div class="tree-view">
|
||||
<div class="title">
|
||||
<a
|
||||
href="javascript:;"
|
||||
:class="{'active': active === 'tree'}"
|
||||
title="Tree View"
|
||||
>
|
||||
<svg class="icon" aria-hidden="true" @click="active = 'tree'">
|
||||
<use xlink:href="#icon-tree"></use>
|
||||
</svg>
|
||||
</a>
|
||||
<a
|
||||
href="javascript:;"
|
||||
:class="{'active': active === 'list'}"
|
||||
title="List View"
|
||||
>
|
||||
<svg class="icon" aria-hidden="true" @click="active = 'list'">
|
||||
<use xlink:href="#icon-list"></use>
|
||||
</svg>
|
||||
</a>
|
||||
<!-- Placeholder -->
|
||||
</div>
|
||||
<!-- opened files -->
|
||||
<div class="opened-files">
|
||||
@ -50,7 +33,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- project tree view -->
|
||||
<div
|
||||
<div
|
||||
class="project-tree" v-if="projectTree"
|
||||
>
|
||||
<div class="title">
|
||||
@ -58,6 +41,24 @@
|
||||
<use xlink:href="#icon-arrow"></use>
|
||||
</svg>
|
||||
<span class="default-cursor text-overflow" @click.stop="toggleDirectories()">{{ projectTree.name }}</span>
|
||||
<a
|
||||
href="javascript:;"
|
||||
:class="{'active': active === 'tree'}"
|
||||
title="Tree View"
|
||||
>
|
||||
<svg class="icon" aria-hidden="true" @click="active = 'tree'">
|
||||
<use xlink:href="#icon-tree"></use>
|
||||
</svg>
|
||||
</a>
|
||||
<a
|
||||
href="javascript:;"
|
||||
:class="{'active': active === 'list'}"
|
||||
title="List View"
|
||||
>
|
||||
<svg class="icon" aria-hidden="true" @click="active = 'list'">
|
||||
<use xlink:href="#icon-list"></use>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div class="tree-wrapper" v-show="showDirectories && active === 'tree'">
|
||||
<folder
|
||||
@ -226,26 +227,6 @@
|
||||
padding: 0 15px;
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
& > span {
|
||||
flex: 1;
|
||||
user-select: none;
|
||||
}
|
||||
& > a {
|
||||
pointer-events: auto;
|
||||
cursor: pointer;
|
||||
margin-left: 8px;
|
||||
color: var(--iconColor);
|
||||
opacity: 0;
|
||||
}
|
||||
& > a:hover {
|
||||
color: var(--themeColor);
|
||||
}
|
||||
& > a.active {
|
||||
color: var(--themeColor);
|
||||
}
|
||||
}
|
||||
.tree-view:hover .title a {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.icon-arrow {
|
||||
@ -309,8 +290,26 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
& > .title {
|
||||
padding-right: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
& > span {
|
||||
flex: 1;
|
||||
user-select: none;
|
||||
}
|
||||
& > a {
|
||||
pointer-events: auto;
|
||||
cursor: pointer;
|
||||
margin-left: 8px;
|
||||
color: var(--iconColor);
|
||||
opacity: 0;
|
||||
}
|
||||
& > a:hover {
|
||||
color: var(--themeColor);
|
||||
}
|
||||
& > a.active {
|
||||
color: var(--themeColor);
|
||||
}
|
||||
}
|
||||
& > .tree-wrapper,
|
||||
& > .list-wrapper {
|
||||
@ -322,6 +321,9 @@
|
||||
}
|
||||
flex: 1;
|
||||
}
|
||||
.project-tree div.title:hover > a {
|
||||
opacity: 1;
|
||||
}
|
||||
.open-project {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
|
@ -1,86 +1,96 @@
|
||||
<template>
|
||||
<div
|
||||
class="title-bar"
|
||||
:class="[{ 'active': active }, { 'tabs-visible': showTabBar }, { 'frameless': titleBarStyle === 'custom' }, { 'isOsx': platform === 'darwin' }]"
|
||||
>
|
||||
<div class="title">
|
||||
<span v-if="!filename">Mark Text</span>
|
||||
<span v-else>
|
||||
<span
|
||||
v-for="(path, index) of paths"
|
||||
:key="index"
|
||||
>
|
||||
{{ path }}
|
||||
<svg class="icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-arrow-right"></use>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="filename"
|
||||
:class="{'isOsx': platform === 'darwin'}"
|
||||
@click="rename"
|
||||
>
|
||||
{{ filename }}
|
||||
</span>
|
||||
<span class="save-dot" :class="{'show': !isSaved}"></span>
|
||||
</span>
|
||||
</div>
|
||||
<div :class="titleBarStyle === 'custom' ? 'left-toolbar title-no-drag' : 'right-toolbar'">
|
||||
<div
|
||||
v-if="titleBarStyle === 'custom'"
|
||||
class="frameless-titlebar-menu title-no-drag"
|
||||
@click.stop="handleMenuClick"
|
||||
>☰</div>
|
||||
<el-tooltip
|
||||
v-if="wordCount"
|
||||
class="item"
|
||||
:content="`${wordCount[show]} ${HASH[show].full + (wordCount[show] > 1 ? 's' : '')}`"
|
||||
placement="bottom-end"
|
||||
>
|
||||
<div slot="content">
|
||||
<div class="title-item">
|
||||
<span class="front">Words:</span><span class="text">{{wordCount['word']}}</span>
|
||||
</div>
|
||||
<div class="title-item">
|
||||
<span class="front">Characters:</span><span class="text">{{wordCount['character']}}</span>
|
||||
</div>
|
||||
<div class="title-item">
|
||||
<span class="front">Paragraph:</span><span class="text">{{wordCount['paragraph']}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="wordCount"
|
||||
class="word-count"
|
||||
:class="[{ 'title-no-drag': platform !== 'darwin' }]"
|
||||
@click.stop="handleWordClick"
|
||||
>{{ `${HASH[show].short} ${wordCount[show]}` }}</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
v-if="titleBarStyle === 'custom' && !isFullScreen"
|
||||
class="right-toolbar"
|
||||
:class="[{ 'title-no-drag': titleBarStyle === 'custom' }]"
|
||||
class="title-bar-editor-bg"
|
||||
:class="{ 'tabs-visible': showTabBar }"
|
||||
></div>
|
||||
<div
|
||||
class="title-bar"
|
||||
:class="[{ 'active': active }, { 'tabs-visible': showTabBar }, { 'frameless': titleBarStyle === 'custom' }, { 'isOsx': platform === 'darwin' }]"
|
||||
>
|
||||
<div class="frameless-titlebar-button frameless-titlebar-close" @click.stop="handleCloseClick">
|
||||
<div>
|
||||
<svg width="10" height="10">
|
||||
<path :d="windowIconClose" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="title">
|
||||
<span v-if="!filename">Mark Text</span>
|
||||
<span v-else>
|
||||
<span
|
||||
v-for="(path, index) of paths"
|
||||
:key="index"
|
||||
>
|
||||
{{ path }}
|
||||
<svg class="icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-arrow-right"></use>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="filename"
|
||||
:class="{'isOsx': platform === 'darwin'}"
|
||||
@click="rename"
|
||||
>
|
||||
{{ filename }}
|
||||
</span>
|
||||
<span class="save-dot" :class="{'show': !isSaved}"></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="frameless-titlebar-button frameless-titlebar-toggle" @click.stop="handleMaximizeClick">
|
||||
<div>
|
||||
<svg width="10" height="10">
|
||||
<path v-show="!isMaximized" :d="windowIconMaximize" />
|
||||
<path v-show="isMaximized" :d="windowIconRestore" />
|
||||
</svg>
|
||||
<div :class="titleBarStyle === 'custom' ? 'left-toolbar title-no-drag' : 'right-toolbar'">
|
||||
<div
|
||||
v-if="titleBarStyle === 'custom'"
|
||||
class="frameless-titlebar-menu title-no-drag"
|
||||
@click.stop="handleMenuClick"
|
||||
>
|
||||
<span class="text-center-vertical">☰</span>
|
||||
</div>
|
||||
<el-tooltip
|
||||
v-if="wordCount"
|
||||
class="item"
|
||||
:content="`${wordCount[show]} ${HASH[show].full + (wordCount[show] > 1 ? 's' : '')}`"
|
||||
placement="bottom-end"
|
||||
>
|
||||
<div slot="content">
|
||||
<div class="title-item">
|
||||
<span class="front">Words:</span><span class="text">{{wordCount['word']}}</span>
|
||||
</div>
|
||||
<div class="title-item">
|
||||
<span class="front">Characters:</span><span class="text">{{wordCount['character']}}</span>
|
||||
</div>
|
||||
<div class="title-item">
|
||||
<span class="front">Paragraph:</span><span class="text">{{wordCount['paragraph']}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="wordCount"
|
||||
class="word-count"
|
||||
:class="[{ 'title-no-drag': platform !== 'darwin' }]"
|
||||
@click.stop="handleWordClick"
|
||||
>
|
||||
<span class="text-center-vertical">{{ `${HASH[show].short} ${wordCount[show]}` }}</span>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="frameless-titlebar-button frameless-titlebar-minimize" @click.stop="handleMinimizeClick">
|
||||
<div>
|
||||
<svg width="10" height="10">
|
||||
<path :d="windowIconMinimize" />
|
||||
</svg>
|
||||
<div
|
||||
v-if="titleBarStyle === 'custom' && !isFullScreen"
|
||||
class="right-toolbar"
|
||||
:class="[{ 'title-no-drag': titleBarStyle === 'custom' }]"
|
||||
>
|
||||
<div class="frameless-titlebar-button frameless-titlebar-close" @click.stop="handleCloseClick">
|
||||
<div>
|
||||
<svg width="10" height="10">
|
||||
<path :d="windowIconClose" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="frameless-titlebar-button frameless-titlebar-toggle" @click.stop="handleMaximizeClick">
|
||||
<div>
|
||||
<svg width="10" height="10">
|
||||
<path v-show="!isMaximized" :d="windowIconMaximize" />
|
||||
<path v-show="isMaximized" :d="windowIconRestore" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="frameless-titlebar-button frameless-titlebar-minimize" @click.stop="handleMinimizeClick">
|
||||
<div>
|
||||
<svg width="10" height="10">
|
||||
<path :d="windowIconMinimize" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -186,17 +196,11 @@
|
||||
},
|
||||
|
||||
handleMenuClick () {
|
||||
let offsetX = 23
|
||||
const elems = document.getElementsByClassName('side-bar')
|
||||
if (elems) {
|
||||
offsetX += elems[0].clientWidth
|
||||
}
|
||||
|
||||
const win = remote.getCurrentWindow()
|
||||
remote
|
||||
.Menu
|
||||
.getApplicationMenu()
|
||||
.popup({ window: win, x: offsetX, y: 20 })
|
||||
.popup({ window: win, x: 23, y: 20 })
|
||||
},
|
||||
|
||||
handleWindowStateChanged () {
|
||||
@ -220,15 +224,23 @@
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.title-bar-editor-bg {
|
||||
height: var(--titleBarHeight);
|
||||
background: var(--editorBgColor);
|
||||
position: relative;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
.title-bar {
|
||||
-webkit-app-region: drag;
|
||||
user-select: none;
|
||||
background: var(--editorBgColor);
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
height: var(--titleBarHeight);
|
||||
box-sizing: border-box;
|
||||
color: var(--editorColor50);
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
@ -244,7 +256,7 @@
|
||||
vertical-align: top;
|
||||
}
|
||||
.title {
|
||||
padding: 0 100px;
|
||||
padding: 0 142px;
|
||||
height: 100%;
|
||||
line-height: var(--titleBarHeight);
|
||||
font-size: 14px;
|
||||
@ -293,27 +305,27 @@
|
||||
color: var(sideBarTitleColor);
|
||||
}
|
||||
|
||||
.right-toolbar {
|
||||
padding: 0 10px;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 100px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
.left-toolbar {
|
||||
padding: 0 10px;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100px;
|
||||
width: 118px; /* + 2*10px padding*/
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.right-toolbar {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 138px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.word-count {
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
@ -326,11 +338,11 @@
|
||||
border-radius: 4px;
|
||||
transition: all .25s ease-in-out;
|
||||
}
|
||||
|
||||
.word-count:hover {
|
||||
background: var(--sideBarBgColor);
|
||||
color: var(--sideBarTitleColor);
|
||||
}
|
||||
|
||||
.title-no-drag {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
@ -338,7 +350,7 @@
|
||||
.frameless-titlebar-button {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: var(--titleBarHeight);
|
||||
width: 46px;
|
||||
height: var(--titleBarHeight);
|
||||
}
|
||||
.frameless-titlebar-button > div {
|
||||
@ -364,6 +376,12 @@
|
||||
.frameless-titlebar-close:hover svg {
|
||||
fill: #ffffff
|
||||
}
|
||||
|
||||
.text-center-vertical {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
line-height: normal;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
|
@ -51,6 +51,31 @@ const mutations = {
|
||||
}
|
||||
}
|
||||
},
|
||||
// Exchange from with to and move from to the end if to is null or empty.
|
||||
EXCHANGE_TABS_BY_ID (state, tabIDs) {
|
||||
const { fromId } = tabIDs
|
||||
const toId = tabIDs.toId // may be null
|
||||
|
||||
const { tabs } = state
|
||||
const moveItem = (arr, from, to) => {
|
||||
if (from === to) return true
|
||||
const len = arr.length
|
||||
const item = arr.splice(from, 1)
|
||||
if (item.length === 0) return false
|
||||
|
||||
arr.splice(to, 0, item[0])
|
||||
return arr.length === len
|
||||
}
|
||||
|
||||
const fromIndex = tabs.findIndex(t => t.id === fromId)
|
||||
if (!toId) {
|
||||
moveItem(tabs, fromIndex, tabs.length - 1)
|
||||
} else {
|
||||
const toIndex = tabs.findIndex(t => t.id === toId)
|
||||
const realToIndex = fromIndex < toIndex ? toIndex - 1 : toIndex
|
||||
moveItem(tabs, fromIndex, realToIndex)
|
||||
}
|
||||
},
|
||||
LOAD_CHANGE (state, change) {
|
||||
const { tabs, currentFile } = state
|
||||
const { data, pathname } = change
|
||||
@ -233,6 +258,10 @@ const actions = {
|
||||
dispatch('ASK_FILE_WATCH', { pathname, watch: false })
|
||||
},
|
||||
|
||||
EXCHANGE_TABS_BY_ID ({ commit }, tabIDs) {
|
||||
commit('EXCHANGE_TABS_BY_ID', tabIDs)
|
||||
},
|
||||
|
||||
// need update line ending when change between windows.
|
||||
LISTEN_FOR_LINEENDING_MENU ({ commit, state, dispatch }) {
|
||||
ipcRenderer.on('AGANI::req-update-line-ending-menu', e => {
|
||||
|
@ -1,10 +1,14 @@
|
||||
import { ipcRenderer } from 'electron'
|
||||
|
||||
const width = localStorage.getItem('side-bar-width')
|
||||
const sideBarWidth = typeof +width === 'number' ? Math.max(+width, 180) : 280
|
||||
|
||||
// messages from main process, and do not change the state
|
||||
const state = {
|
||||
rightColumn: 'files',
|
||||
showSideBar: false,
|
||||
showTabBar: false
|
||||
showTabBar: false,
|
||||
sideBarWidth
|
||||
}
|
||||
|
||||
const getters = {}
|
||||
@ -12,6 +16,11 @@ const getters = {}
|
||||
const mutations = {
|
||||
SET_LAYOUT (state, layout) {
|
||||
Object.assign(state, layout)
|
||||
},
|
||||
SET_SIDE_BAR_WIDTH (state, width) {
|
||||
// TODO: Add side bar with to session (GH#732).
|
||||
localStorage.setItem('side-bar-width', Math.max(+width, 180))
|
||||
state.sideBarWidth = width
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,6 +38,9 @@ const actions = {
|
||||
SET_LAYOUT_MENU_ITEM ({ commit, state }) {
|
||||
const { showTabBar, showSideBar } = state
|
||||
ipcRenderer.send('AGANI::set-view-layout', { showTabBar, showSideBar })
|
||||
},
|
||||
CHANGE_SIDE_BAR_WIDTH ({ commit }, width) {
|
||||
commit('SET_SIDE_BAR_WIDTH', width)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,11 +7,7 @@ import { PATH_SEPARATOR } from '../config'
|
||||
import notice from '../services/notification'
|
||||
import { getFileStateFromData } from './help'
|
||||
|
||||
const width = localStorage.getItem('side-bar-width')
|
||||
const sideBarWidth = typeof +width === 'number' ? Math.max(+width, 180) : 280
|
||||
|
||||
const state = {
|
||||
sideBarWidth,
|
||||
activeItem: {},
|
||||
createCache: {},
|
||||
// Use to cache newly created filename, for open iimmediately.
|
||||
@ -56,10 +52,6 @@ const mutations = {
|
||||
files: []
|
||||
}
|
||||
},
|
||||
SET_SIDE_BAR_WIDTH (state, width) {
|
||||
localStorage.setItem('side-bar-width', Math.max(+width, 180))
|
||||
state.sideBarWidth = width
|
||||
},
|
||||
SET_NEWFILENAME (state, name) {
|
||||
state.newFileNameCache = name
|
||||
},
|
||||
@ -162,9 +154,6 @@ const actions = {
|
||||
}
|
||||
})
|
||||
},
|
||||
CHANGE_SIDE_BAR_WIDTH ({ commit }, width) {
|
||||
commit('SET_SIDE_BAR_WIDTH', width)
|
||||
},
|
||||
CHANGE_ACTIVE_ITEM ({ commit }, activeItem) {
|
||||
commit('SET_ACTIVE_ITEM', activeItem)
|
||||
},
|
||||
|
113
yarn.lock
113
yarn.lock
@ -446,6 +446,11 @@ amdefine@>=0.0.4:
|
||||
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
|
||||
integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=
|
||||
|
||||
animation-frame-polyfill@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/animation-frame-polyfill/-/animation-frame-polyfill-1.0.1.tgz#5f5ad993a78794bd176acde5b6dce62867410c9d"
|
||||
integrity sha1-X1rZk6eHlL0Xas3lttzmKGdBDJ0=
|
||||
|
||||
ansi-align@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
|
||||
@ -634,6 +639,11 @@ array-flatten@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099"
|
||||
integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==
|
||||
|
||||
array-from@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/array-from/-/array-from-2.1.1.tgz#cfe9d8c26628b9dc5aecc62a9f5d8f1f352c1195"
|
||||
integrity sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=
|
||||
|
||||
array-includes@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d"
|
||||
@ -761,6 +771,11 @@ asynckit@^0.4.0:
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
|
||||
|
||||
atoa@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/atoa/-/atoa-1.0.0.tgz#0cc0e91a480e738f923ebc103676471779b34a49"
|
||||
integrity sha1-DMDpGkgOc4+SPrwQNnZHF3mzSkk=
|
||||
|
||||
atob@^2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
||||
@ -2604,6 +2619,14 @@ content-type@~1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
||||
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
|
||||
|
||||
contra@1.9.4:
|
||||
version "1.9.4"
|
||||
resolved "https://registry.yarnpkg.com/contra/-/contra-1.9.4.tgz#f53bde42d7e5b5985cae4d99a8d610526de8f28d"
|
||||
integrity sha1-9TveQtfltZhcrk2ZqNYQUm3o8o0=
|
||||
dependencies:
|
||||
atoa "1.0.0"
|
||||
ticky "1.0.1"
|
||||
|
||||
convert-source-map@^1.5.1:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20"
|
||||
@ -2739,6 +2762,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
|
||||
safe-buffer "^5.0.1"
|
||||
sha.js "^2.4.8"
|
||||
|
||||
create-point-cb@^1.0.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/create-point-cb/-/create-point-cb-1.2.0.tgz#1bce47fc4fc01855ee12138d676b0cb2a7cbce71"
|
||||
integrity sha1-G85H/E/AGFXuEhONZ2sMsqfLznE=
|
||||
dependencies:
|
||||
type-func "^1.0.1"
|
||||
|
||||
cross-env@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.2.0.tgz#6ecd4c015d5773e614039ee529076669b9d126f2"
|
||||
@ -2772,6 +2802,13 @@ cross-unzip@0.0.2:
|
||||
resolved "https://registry.yarnpkg.com/cross-unzip/-/cross-unzip-0.0.2.tgz#5183bc47a09559befcf98cc4657964999359372f"
|
||||
integrity sha1-UYO8R6CVWb78+YzEZXlkmZNZNy8=
|
||||
|
||||
crossvent@1.5.4:
|
||||
version "1.5.4"
|
||||
resolved "https://registry.yarnpkg.com/crossvent/-/crossvent-1.5.4.tgz#da2c4f8f40c94782517bf2beec1044148194ab92"
|
||||
integrity sha1-2ixPj0DJR4JRe/K+7BBEFIGUq5I=
|
||||
dependencies:
|
||||
custom-event "1.0.0"
|
||||
|
||||
crypto-browserify@^3.11.0:
|
||||
version "3.12.0"
|
||||
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
|
||||
@ -2947,6 +2984,11 @@ currently-unhandled@^0.4.1:
|
||||
dependencies:
|
||||
array-find-index "^1.0.1"
|
||||
|
||||
custom-event@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.0.tgz#2e4628be19dc4b214b5c02630c5971e811618062"
|
||||
integrity sha1-LkYovhncSyFLXAJjDFlx6BFhgGI=
|
||||
|
||||
custom-event@~1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425"
|
||||
@ -3590,6 +3632,18 @@ doctrine@^3.0.0:
|
||||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
|
||||
dom-autoscroller@^2.3.4:
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/dom-autoscroller/-/dom-autoscroller-2.3.4.tgz#1ed25cbde2bdf3bf3eb762937089b20ecef190bd"
|
||||
integrity sha512-HcAdt/2Dq9x4CG6LWXc2x9Iq0MJPAu8fuzHncclq7byufqYEYVtx9sZ/dyzR+gdj4qwEC9p27Lw1G2HRRYX6jQ==
|
||||
dependencies:
|
||||
animation-frame-polyfill "^1.0.0"
|
||||
create-point-cb "^1.0.0"
|
||||
dom-mousemove-dispatcher "^1.0.1"
|
||||
dom-plane "^1.0.1"
|
||||
dom-set "^1.0.1"
|
||||
type-func "^1.0.1"
|
||||
|
||||
dom-converter@^0.2:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768"
|
||||
@ -3597,6 +3651,18 @@ dom-converter@^0.2:
|
||||
dependencies:
|
||||
utila "~0.4"
|
||||
|
||||
dom-mousemove-dispatcher@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/dom-mousemove-dispatcher/-/dom-mousemove-dispatcher-1.0.1.tgz#a24a6ddf93b27bb3694f72087546a57fc7e9140f"
|
||||
integrity sha1-okpt35Oye7NpT3IIdUalf8fpFA8=
|
||||
|
||||
dom-plane@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/dom-plane/-/dom-plane-1.0.2.tgz#f8c85e697c587f147e8fc2fac1de078c1fe4172c"
|
||||
integrity sha1-+MheaXxYfxR+j8L6wd4HjB/kFyw=
|
||||
dependencies:
|
||||
create-point-cb "^1.0.0"
|
||||
|
||||
dom-serialize@^2.2.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b"
|
||||
@ -3615,6 +3681,15 @@ dom-serializer@0, dom-serializer@~0.1.1:
|
||||
domelementtype "^1.3.0"
|
||||
entities "^1.1.1"
|
||||
|
||||
dom-set@^1.0.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/dom-set/-/dom-set-1.1.1.tgz#5c2c610ee4839b520ed5f98ddbcbe314c0fa954a"
|
||||
integrity sha1-XCxhDuSDm1IO1fmN28vjFMD6lUo=
|
||||
dependencies:
|
||||
array-from "^2.1.1"
|
||||
is-array "^1.0.1"
|
||||
iselement "^1.1.4"
|
||||
|
||||
domain-browser@^1.1.1:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
|
||||
@ -3694,6 +3769,14 @@ dotenv@^7.0.0:
|
||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c"
|
||||
integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==
|
||||
|
||||
dragula@^3.7.2:
|
||||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/dragula/-/dragula-3.7.2.tgz#4a35c9d3981ffac1a949c29ca7285058e87393ce"
|
||||
integrity sha1-SjXJ05gf+sGpScKcpyhQWOhzk84=
|
||||
dependencies:
|
||||
contra "1.9.4"
|
||||
crossvent "1.5.4"
|
||||
|
||||
duplexer3@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
|
||||
@ -5743,6 +5826,11 @@ is-accessor-descriptor@^1.0.0:
|
||||
dependencies:
|
||||
kind-of "^6.0.0"
|
||||
|
||||
is-array@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-array/-/is-array-1.0.1.tgz#e9850cc2cc860c3bc0977e84ccf0dd464584279a"
|
||||
integrity sha1-6YUMwsyGDDvAl36EzPDdRkWEJ5o=
|
||||
|
||||
is-arrayish@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
|
||||
@ -6039,6 +6127,11 @@ isbinaryfile@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.0.tgz#07d1061c21598b41292b0f5c68add5eab601ad8e"
|
||||
integrity sha512-RBtmso6l2mCaEsUvXngMTIjg3oheXo0MgYzzfT6sk44RYggPnm9fT+cQJAmzRnJIxPHXg9FZglqDJGW28dvcqA==
|
||||
|
||||
iselement@^1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/iselement/-/iselement-1.1.4.tgz#7e55b52a8ebca50a7e2e80e5b8d2840f32353146"
|
||||
integrity sha1-flW1Ko68pQp+LoDluNKEDzI1MUY=
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
@ -10324,6 +10417,11 @@ thunky@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826"
|
||||
integrity sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==
|
||||
|
||||
ticky@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ticky/-/ticky-1.0.1.tgz#b7cfa71e768f1c9000c497b9151b30947c50e46d"
|
||||
integrity sha1-t8+nHnaPHJAAxJe5FRswlHxQ5G0=
|
||||
|
||||
timed-out@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
|
||||
@ -10531,7 +10629,20 @@ type-detect@^4.0.0, type-detect@^4.0.5:
|
||||
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
|
||||
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
|
||||
|
||||
type-is@~1.6.16, type-is@~1.6.17:
|
||||
type-func@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/type-func/-/type-func-1.0.3.tgz#ab184234ae80d8d50057cefeff3b2d97d08ae9b0"
|
||||
integrity sha1-qxhCNK6A2NUAV87+/zstl9CK6bA=
|
||||
|
||||
type-is@~1.6.16:
|
||||
version "1.6.16"
|
||||
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194"
|
||||
integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==
|
||||
dependencies:
|
||||
media-typer "0.3.0"
|
||||
mime-types "~2.1.18"
|
||||
|
||||
type-is@~1.6.17:
|
||||
version "1.6.18"
|
||||
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
|
||||
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
|
||||
|
Loading…
Reference in New Issue
Block a user