Stackedit/src/components/Modal.vue

442 lines
11 KiB
Vue
Raw Normal View History

<template>
2018-06-21 19:16:33 +00:00
<div class="modal" v-if="config" @keydown.esc="onEscape" @keydown.tab="onTab" @focusin="onFocusInOut" @focusout="onFocusInOut">
2018-09-19 08:59:22 +00:00
<div class="modal__sponsor-banner" v-if="!isSponsor">
StackEdit is <a class="not-tabbable" target="_blank" href="https://github.com/benweet/stackedit/">open source</a>, please consider
<a class="not-tabbable" href="javascript:void(0)" @click="sponsor">sponsoring</a> for just $5.
</div>
2018-03-14 00:42:26 +00:00
<component v-if="currentModalComponent" :is="currentModalComponent"></component>
<modal-inner v-else aria-label="Dialog">
2018-06-07 23:56:11 +00:00
<div class="modal__content" v-html="simpleModal.contentHtml(config)"></div>
<div class="modal__button-bar">
2018-06-07 23:56:11 +00:00
<button class="button" v-if="simpleModal.rejectText" @click="config.reject()">{{simpleModal.rejectText}}</button>
<button class="button button--resolve" v-if="simpleModal.resolveText" @click="config.resolve()">{{simpleModal.resolveText}}</button>
</div>
</modal-inner>
</div>
</template>
<script>
2017-09-23 19:01:50 +00:00
import { mapGetters } from 'vuex';
2018-06-07 23:56:11 +00:00
import simpleModals from '../data/simpleModals';
import editorSvc from '../services/editorSvc';
2018-09-19 08:59:22 +00:00
import syncSvc from '../services/syncSvc';
import googleHelper from '../services/providers/helpers/googleHelper';
import store from '../store';
import ModalInner from './modals/common/ModalInner';
2017-09-23 19:01:50 +00:00
import FilePropertiesModal from './modals/FilePropertiesModal';
import SettingsModal from './modals/SettingsModal';
import TemplatesModal from './modals/TemplatesModal';
2017-10-02 00:34:48 +00:00
import AboutModal from './modals/AboutModal';
2017-09-23 19:01:50 +00:00
import HtmlExportModal from './modals/HtmlExportModal';
import PdfExportModal from './modals/PdfExportModal';
import PandocExportModal from './modals/PandocExportModal';
2017-09-23 19:01:50 +00:00
import LinkModal from './modals/LinkModal';
import ImageModal from './modals/ImageModal';
import SyncManagementModal from './modals/SyncManagementModal';
import PublishManagementModal from './modals/PublishManagementModal';
2017-12-10 23:49:20 +00:00
import WorkspaceManagementModal from './modals/WorkspaceManagementModal';
import SponsorModal from './modals/SponsorModal';
// Providers
import GooglePhotoModal from './modals/providers/GooglePhotoModal';
2017-12-23 18:25:14 +00:00
import GoogleDriveAccountModal from './modals/providers/GoogleDriveAccountModal';
import GoogleDriveSaveModal from './modals/providers/GoogleDriveSaveModal';
2017-12-10 23:49:20 +00:00
import GoogleDriveWorkspaceModal from './modals/providers/GoogleDriveWorkspaceModal';
import GoogleDrivePublishModal from './modals/providers/GoogleDrivePublishModal';
import DropboxAccountModal from './modals/providers/DropboxAccountModal';
import DropboxSaveModal from './modals/providers/DropboxSaveModal';
import DropboxPublishModal from './modals/providers/DropboxPublishModal';
import GithubAccountModal from './modals/providers/GithubAccountModal';
import GithubOpenModal from './modals/providers/GithubOpenModal';
import GithubSaveModal from './modals/providers/GithubSaveModal';
2018-04-27 14:37:05 +00:00
import GithubWorkspaceModal from './modals/providers/GithubWorkspaceModal';
import GithubPublishModal from './modals/providers/GithubPublishModal';
import GistSyncModal from './modals/providers/GistSyncModal';
import GistPublishModal from './modals/providers/GistPublishModal';
2018-09-19 08:59:22 +00:00
import GitlabAccountModal from './modals/providers/GitlabAccountModal';
import GitlabOpenModal from './modals/providers/GitlabOpenModal';
import GitlabPublishModal from './modals/providers/GitlabPublishModal';
import GitlabSaveModal from './modals/providers/GitlabSaveModal';
import GitlabWorkspaceModal from './modals/providers/GitlabWorkspaceModal';
import WordpressPublishModal from './modals/providers/WordpressPublishModal';
import BloggerPublishModal from './modals/providers/BloggerPublishModal';
import BloggerPagePublishModal from './modals/providers/BloggerPagePublishModal';
import ZendeskAccountModal from './modals/providers/ZendeskAccountModal';
import ZendeskPublishModal from './modals/providers/ZendeskPublishModal';
2018-01-24 07:31:54 +00:00
import CouchdbWorkspaceModal from './modals/providers/CouchdbWorkspaceModal';
import CouchdbCredentialsModal from './modals/providers/CouchdbCredentialsModal';
2018-09-19 08:59:22 +00:00
const getTabbables = container => container.querySelectorAll('a[href], button, .textfield, input[type=checkbox]')
2017-10-07 11:22:24 +00:00
// Filter enabled and visible element
.cl_filter(el => !el.disabled && el.offsetParent !== null && !el.classList.contains('not-tabbable'));
2017-10-07 11:22:24 +00:00
export default {
components: {
ModalInner,
FilePropertiesModal,
SettingsModal,
TemplatesModal,
2017-10-02 00:34:48 +00:00
AboutModal,
2017-09-23 19:01:50 +00:00
HtmlExportModal,
PdfExportModal,
PandocExportModal,
LinkModal,
ImageModal,
2017-09-23 19:01:50 +00:00
SyncManagementModal,
PublishManagementModal,
2017-12-10 23:49:20 +00:00
WorkspaceManagementModal,
SponsorModal,
// Providers
GooglePhotoModal,
2017-12-23 18:25:14 +00:00
GoogleDriveAccountModal,
GoogleDriveSaveModal,
2017-12-10 23:49:20 +00:00
GoogleDriveWorkspaceModal,
2017-09-23 19:01:50 +00:00
GoogleDrivePublishModal,
2017-09-26 22:54:26 +00:00
DropboxAccountModal,
DropboxSaveModal,
2017-09-23 19:01:50 +00:00
DropboxPublishModal,
2017-09-26 22:54:26 +00:00
GithubAccountModal,
GithubOpenModal,
GithubSaveModal,
2018-04-27 14:37:05 +00:00
GithubWorkspaceModal,
2017-09-23 19:01:50 +00:00
GithubPublishModal,
GistSyncModal,
GistPublishModal,
2018-09-19 08:59:22 +00:00
GitlabAccountModal,
GitlabOpenModal,
GitlabPublishModal,
GitlabSaveModal,
GitlabWorkspaceModal,
2017-09-26 22:54:26 +00:00
WordpressPublishModal,
2017-09-23 19:01:50 +00:00
BloggerPublishModal,
BloggerPagePublishModal,
2017-09-26 22:54:26 +00:00
ZendeskAccountModal,
ZendeskPublishModal,
2018-01-24 07:31:54 +00:00
CouchdbWorkspaceModal,
CouchdbCredentialsModal,
},
2018-03-13 20:41:41 +00:00
computed: {
2018-09-19 08:59:22 +00:00
...mapGetters([
'isSponsor',
]),
2018-03-13 20:41:41 +00:00
...mapGetters('modal', [
'config',
]),
currentModalComponent() {
2018-03-14 00:42:26 +00:00
if (this.config.type) {
let componentName = this.config.type[0].toUpperCase();
componentName += this.config.type.slice(1);
componentName += 'Modal';
if (this.$options.components[componentName]) {
return componentName;
}
2018-03-13 20:41:41 +00:00
}
2018-03-14 00:42:26 +00:00
return null;
2018-03-13 20:41:41 +00:00
},
2018-06-07 23:56:11 +00:00
simpleModal() {
return simpleModals[this.config.type] || {};
},
2018-03-13 20:41:41 +00:00
},
methods: {
2018-09-19 08:59:22 +00:00
async sponsor() {
try {
if (!store.getters['workspace/sponsorToken']) {
// User has to sign in
await store.dispatch('modal/open', 'signInForSponsorship');
await googleHelper.signin();
syncSvc.requestSync();
}
if (!store.getters.isSponsor) {
await store.dispatch('modal/open', 'sponsor');
}
} catch (e) { /* cancel */ }
},
onEscape() {
2017-09-23 19:01:50 +00:00
this.config.reject();
editorSvc.clEditor.focus();
},
2017-10-07 11:22:24 +00:00
onTab(evt) {
const tabbables = getTabbables(this.$el);
const firstTabbable = tabbables[0];
const lastTabbable = tabbables[tabbables.length - 1];
if (evt.shiftKey && firstTabbable === evt.target) {
evt.preventDefault();
lastTabbable.focus();
} else if (!evt.shiftKey && lastTabbable === evt.target) {
evt.preventDefault();
firstTabbable.focus();
}
},
onFocusInOut(evt) {
2018-09-19 08:59:22 +00:00
const { parentNode } = evt.target;
if (parentNode && parentNode.parentNode) {
// Focus effect
2018-09-19 08:59:22 +00:00
if (parentNode.classList.contains('form-entry__field')
&& parentNode.parentNode.classList.contains('form-entry')) {
parentNode.parentNode.classList.toggle(
'form-entry--focused',
evt.type === 'focusin',
);
}
}
},
},
mounted() {
2018-06-07 23:56:11 +00:00
this.$watch(
() => this.config,
2018-06-21 19:16:33 +00:00
(isOpen) => {
if (isOpen) {
2018-06-07 23:56:11 +00:00
const tabbables = getTabbables(this.$el);
if (tabbables[0]) {
tabbables[0].focus();
}
}
},
2018-06-21 19:16:33 +00:00
{ immediate: true },
2018-06-07 23:56:11 +00:00
);
},
};
</script>
<style lang="scss">
2018-05-06 00:46:33 +00:00
@import '../styles/variables.scss';
.modal {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(160, 160, 160, 0.5);
overflow: auto;
2017-12-10 23:49:20 +00:00
2018-04-27 14:37:05 +00:00
p {
line-height: 1.5;
}
}
2018-09-19 08:59:22 +00:00
.modal__sponsor-banner {
position: fixed;
z-index: 1;
width: 100%;
color: darken($error-color, 10%);
2018-09-20 09:00:07 +00:00
background-color: transparentize(lighten($error-color, 33%), 0.075);
2018-09-19 08:59:22 +00:00
font-size: 0.9em;
line-height: 1.33;
text-align: center;
padding: 0.25em 1em;
}
.modal__inner-1 {
margin: 0 auto;
width: 100%;
min-width: 320px;
2017-11-15 08:12:56 +00:00
max-width: 480px;
}
.modal__inner-2 {
margin: 40px 10px 100px;
2017-11-26 20:58:24 +00:00
background-color: #f8f8f8;
2018-08-09 15:42:17 +00:00
padding: 50px 50px 40px;
border-radius: $border-radius-base;
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
height: $border-radius-base;
width: 100%;
2018-04-15 17:13:03 +00:00
background-image: linear-gradient(to left, #ffd700, #ffd700 23%, #a5c700 27%, #a5c700 48%, #ff8a00 52%, #ff8a00 73%, #66aefd 77%);
}
&::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
height: $border-radius-base;
width: 100%;
2018-04-15 17:13:03 +00:00
background-image: linear-gradient(to right, #ffd700, #ffd700 23%, #a5c700 27%, #a5c700 48%, #ff8a00 52%, #ff8a00 73%, #66aefd 77%);
}
}
.modal__content > :first-child,
.modal__content > .modal__image:first-child + * {
margin-top: 0;
}
2017-09-23 19:01:50 +00:00
.modal__image {
float: left;
2018-04-27 14:37:05 +00:00
width: 60px;
height: 60px;
margin: 1.5em 1.2em 0.5em 0;
2017-09-23 19:01:50 +00:00
& + *::after {
content: '';
display: block;
clear: both;
}
}
2018-04-08 14:49:10 +00:00
.modal__title {
font-weight: bold;
font-size: 1.5rem;
line-height: 1.4;
margin-top: 2.5rem;
}
.modal__sub-title {
opacity: 0.6;
2018-04-08 14:49:10 +00:00
font-size: 0.75rem;
margin-bottom: 1.5rem;
}
.modal__error {
color: #de2c00;
}
2017-10-05 07:18:21 +00:00
.modal__info {
background-color: $info-bg;
2017-09-23 19:01:50 +00:00
border-radius: $border-radius-base;
margin: 1.2em 0;
padding: 0.75em 1.25em;
2018-04-08 14:49:10 +00:00
font-size: 0.95em;
line-height: 1.6;
pre {
line-height: 1.5;
}
2017-09-23 19:01:50 +00:00
}
2018-04-27 14:37:05 +00:00
.modal__info--multiline {
padding-top: 0.1em;
padding-bottom: 0.1em;
}
.modal__button-bar {
margin-top: 2rem;
display: flex;
flex-direction: row;
justify-content: flex-end;
}
.form-entry {
margin: 1em 0;
}
.form-entry__label {
display: block;
font-size: 0.9rem;
2018-09-19 08:59:22 +00:00
color: #808080;
.form-entry--focused & {
color: darken($link-color, 10%);
}
2017-10-07 11:22:24 +00:00
.form-entry--error & {
color: darken($error-color, 10%);
}
}
2018-04-08 14:49:10 +00:00
.form-entry__label-info {
font-size: 0.75rem;
}
.form-entry__field {
2018-09-19 08:59:22 +00:00
border: 1px solid #b0b0b0;
border-radius: $border-radius-base;
position: relative;
overflow: hidden;
.form-entry--focused & {
border-color: $link-color;
2018-09-19 08:59:22 +00:00
box-shadow: 0 0 0 2.5px transparentize($link-color, 0.67);
}
2017-10-07 11:22:24 +00:00
.form-entry--error & {
border-color: $error-color;
2018-09-19 08:59:22 +00:00
box-shadow: 0 0 0 2.5px transparentize($error-color, 0.67);
2017-10-07 11:22:24 +00:00
}
}
.form-entry__actions {
text-align: right;
margin: 0.25em;
}
.form-entry__button {
width: 38px;
height: 38px;
padding: 6px;
display: inline-block;
background-color: transparent;
opacity: 0.75;
&:active,
&:focus,
&:hover {
opacity: 1;
background-color: rgba(0, 0, 0, 0.1);
}
}
.form-entry__radio,
.form-entry__checkbox {
margin: 0.25em 1em;
input {
margin-right: 0.25em;
}
}
.form-entry__info {
font-size: 0.75em;
2018-09-19 08:59:22 +00:00
opacity: 0.67;
line-height: 1.4;
margin: 0.25em 0;
}
2017-10-07 11:22:24 +00:00
.tabs {
border-bottom: 1px solid $hr-color;
margin: 1em 0 2em;
2017-10-07 11:22:24 +00:00
&::after {
content: '';
display: block;
clear: both;
}
}
.tabs__tab {
width: 50%;
float: left;
text-align: center;
line-height: 1.4;
font-weight: 400;
font-size: 1.1em;
}
.tabs__tab > a {
width: 100%;
text-decoration: none;
padding: 0.67em 0.33em;
cursor: pointer;
border-bottom: 2px solid transparent;
border-top-left-radius: $border-radius-base;
border-top-right-radius: $border-radius-base;
color: $link-color;
&:hover,
&:focus {
2018-02-15 08:40:20 +00:00
background-color: rgba(0, 0, 0, 0.05);
2017-10-07 11:22:24 +00:00
}
}
.tabs__tab--active > a {
border-bottom: 2px solid $link-color;
color: inherit;
}
</style>