mirror of
https://github.com/axllent/mailpit.git
synced 2025-07-13 01:20:22 +02:00
Feature: Mobile and tablet HTML preview toggle in desktop mode
This commit is contained in:
@ -91,6 +91,89 @@
|
|||||||
|
|
||||||
#preview-html {
|
#preview-html {
|
||||||
min-height: 300px;
|
min-height: 300px;
|
||||||
|
|
||||||
|
&.tablet,
|
||||||
|
&.phone {
|
||||||
|
border: solid $gray-300 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#responsive-view {
|
||||||
|
margin: auto;
|
||||||
|
transition: width 0.5s;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&.tablet,
|
||||||
|
&.phone {
|
||||||
|
border-radius: 35px;
|
||||||
|
box-sizing: content-box;
|
||||||
|
padding-bottom: 76px;
|
||||||
|
padding-top: 54px;
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
background: $gray-800;
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
height: 100% !important;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.phone {
|
||||||
|
&::before {
|
||||||
|
border-radius: 5px;
|
||||||
|
background: $gray-600;
|
||||||
|
top: 22px;
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
height: 10px;
|
||||||
|
left: 50%;
|
||||||
|
position: absolute;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border-radius: 20px;
|
||||||
|
background: $gray-900;
|
||||||
|
bottom: 20px;
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 65px;
|
||||||
|
height: 40px;
|
||||||
|
left: 50%;
|
||||||
|
position: absolute;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.tablet {
|
||||||
|
&::before {
|
||||||
|
border-radius: 50%;
|
||||||
|
border: solid #b5b0b0 2px;
|
||||||
|
top: 22px;
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
left: 50%;
|
||||||
|
position: absolute;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border-radius: 50%;
|
||||||
|
border: solid #b5b0b0 2px;
|
||||||
|
bottom: 23px;
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
left: 50%;
|
||||||
|
position: absolute;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-group-item.message:first-child {
|
.list-group-item.message:first-child {
|
||||||
@ -302,8 +385,8 @@ pre[class*="language-"] {
|
|||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
@media screen and (max-width: 767px) {
|
@media screen and (max-width: 767px) {
|
||||||
pre[class*="language-"]:after,
|
pre[class*="language-"]::after,
|
||||||
pre[class*="language-"]:before {
|
pre[class*="language-"]::before {
|
||||||
bottom: 14px;
|
bottom: 14px;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,15 @@ export default {
|
|||||||
showTags: false, // to force rerendering of component
|
showTags: false, // to force rerendering of component
|
||||||
messageTags: [],
|
messageTags: [],
|
||||||
allTags: [],
|
allTags: [],
|
||||||
loadHeaders: false
|
loadHeaders: false,
|
||||||
|
showMobileBtns: false,
|
||||||
|
scaleHTMLPreview: 'display',
|
||||||
|
// keys names match bootstrap icon names
|
||||||
|
responsiveSizes: {
|
||||||
|
phone: 'width: 322px; height: 570px',
|
||||||
|
tablet: 'width: 768px; height: 1024px',
|
||||||
|
display: 'width: 100%; height: 100%',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -38,6 +46,7 @@ export default {
|
|||||||
self.messageTags = self.message.Tags;
|
self.messageTags = self.message.Tags;
|
||||||
self.allTags = self.existingTags;
|
self.allTags = self.existingTags;
|
||||||
self.loadHeaders = false;
|
self.loadHeaders = false;
|
||||||
|
self.scaleHTMLPreview = 'display';// default view
|
||||||
// delay to select first tab and add HTML highlighting (prev/next)
|
// delay to select first tab and add HTML highlighting (prev/next)
|
||||||
self.$nextTick(function () {
|
self.$nextTick(function () {
|
||||||
self.renderUI();
|
self.renderUI();
|
||||||
@ -55,6 +64,14 @@ export default {
|
|||||||
if (this.showTags) {
|
if (this.showTags) {
|
||||||
this.saveTags();
|
this.saveTags();
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
scaleHTMLPreview() {
|
||||||
|
if (this.scaleHTMLPreview == 'display') {
|
||||||
|
let self = this;
|
||||||
|
window.setTimeout(function () {
|
||||||
|
self.resizeIframes();
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -124,15 +141,14 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
resizeIframes: function () {
|
resizeIframes: function () {
|
||||||
|
if (this.scaleHTMLPreview != 'display') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let h = document.getElementById('preview-html');
|
let h = document.getElementById('preview-html');
|
||||||
if (h) {
|
if (h) {
|
||||||
h.style.height = h.contentWindow.document.body.scrollHeight + 50 + 'px';
|
h.style.height = h.contentWindow.document.body.scrollHeight + 50 + 'px';
|
||||||
}
|
}
|
||||||
|
|
||||||
let s = document.getElementById('message-src');
|
|
||||||
if (s) {
|
|
||||||
s.style.height = s.contentWindow.document.body.scrollHeight + 50 + 'px';
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
saveTags: function () {
|
saveTags: function () {
|
||||||
@ -245,29 +261,45 @@ export default {
|
|||||||
<nav>
|
<nav>
|
||||||
<div class="nav nav-tabs my-3" id="nav-tab" role="tablist">
|
<div class="nav nav-tabs my-3" id="nav-tab" role="tablist">
|
||||||
<button class="nav-link" id="nav-html-tab" data-bs-toggle="tab" data-bs-target="#nav-html" type="button"
|
<button class="nav-link" id="nav-html-tab" data-bs-toggle="tab" data-bs-target="#nav-html" type="button"
|
||||||
role="tab" aria-controls="nav-html" aria-selected="true" v-if="message.HTML">HTML</button>
|
role="tab" aria-controls="nav-html" aria-selected="true" v-if="message.HTML"
|
||||||
|
v-on:click="showMobileBtns = true">HTML</button>
|
||||||
<button class="nav-link" id="nav-html-source-tab" data-bs-toggle="tab" data-bs-target="#nav-html-source"
|
<button class="nav-link" id="nav-html-source-tab" data-bs-toggle="tab" data-bs-target="#nav-html-source"
|
||||||
type="button" role="tab" aria-controls="nav-html-source" aria-selected="false" v-if="message.HTML">
|
type="button" role="tab" aria-controls="nav-html-source" aria-selected="false" v-if="message.HTML"
|
||||||
|
v-on:click="showMobileBtns = false">
|
||||||
HTML <span class="d-sm-none">Src</span><span class="d-none d-sm-inline">Source</span>
|
HTML <span class="d-sm-none">Src</span><span class="d-none d-sm-inline">Source</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="nav-link" id="nav-plain-text-tab" data-bs-toggle="tab" data-bs-target="#nav-plain-text"
|
<button class="nav-link" id="nav-plain-text-tab" data-bs-toggle="tab" data-bs-target="#nav-plain-text"
|
||||||
type="button" role="tab" aria-controls="nav-plain-text" aria-selected="false"
|
type="button" role="tab" aria-controls="nav-plain-text" aria-selected="false"
|
||||||
:class="message.HTML == '' ? 'show' : ''">Text</button>
|
:class="message.HTML == '' ? 'show' : ''" v-on:click="showMobileBtns = false">Text</button>
|
||||||
<button class="nav-link" id="nav-headers-tab" data-bs-toggle="tab" data-bs-target="#nav-headers"
|
<button class="nav-link" id="nav-headers-tab" data-bs-toggle="tab" data-bs-target="#nav-headers"
|
||||||
type="button" role="tab" aria-controls="nav-headers" aria-selected="false">
|
type="button" role="tab" aria-controls="nav-headers" aria-selected="false"
|
||||||
|
v-on:click="showMobileBtns = false">
|
||||||
<span class="d-sm-none">Hdrs</span><span class="d-none d-sm-inline">Headers</span>
|
<span class="d-sm-none">Hdrs</span><span class="d-none d-sm-inline">Headers</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="nav-link" id="nav-raw-tab" data-bs-toggle="tab" data-bs-target="#nav-raw" type="button"
|
<button class="nav-link" id="nav-raw-tab" data-bs-toggle="tab" data-bs-target="#nav-raw" type="button"
|
||||||
role="tab" aria-controls="nav-raw" aria-selected="false">Raw</button>
|
role="tab" aria-controls="nav-raw" aria-selected="false"
|
||||||
|
v-on:click="showMobileBtns = false">Raw</button>
|
||||||
|
|
||||||
|
<div class="d-none d-lg-block ms-auto me-2" v-if="showMobileBtns">
|
||||||
|
<template v-for="vals, key in responsiveSizes">
|
||||||
|
<button class="btn" :class="scaleHTMLPreview == key ? 'btn-outline-primary' : ''"
|
||||||
|
:disabled="scaleHTMLPreview == key" :title="'Switch to ' + key + ' view'"
|
||||||
|
v-on:click="scaleHTMLPreview = key">
|
||||||
|
<i class="bi" :class="'bi-' + key"></i>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="tab-content mb-5" id="nav-tabContent">
|
<div class="tab-content mb-5" id="nav-tabContent">
|
||||||
<div v-if="message.HTML != ''" class="tab-pane fade show" id="nav-html" role="tabpanel"
|
<div v-if="message.HTML != ''" class="tab-pane fade show" id="nav-html" role="tabpanel"
|
||||||
aria-labelledby="nav-html-tab" tabindex="0">
|
aria-labelledby="nav-html-tab" tabindex="0">
|
||||||
<iframe target-blank="" class="tab-pane" id="preview-html" :srcdoc="message.HTML" v-on:load="resizeIframe"
|
<div id="responsive-view" :class="scaleHTMLPreview" :style="responsiveSizes[scaleHTMLPreview]">
|
||||||
seamless frameborder="0" style="width: 100%; height: 100%;">
|
<iframe target-blank="" class="tab-pane d-block" id="preview-html" :srcdoc="message.HTML"
|
||||||
</iframe>
|
v-on:load="resizeIframe" seamless frameborder="0" style="width: 100%; height: 100%;">
|
||||||
|
</iframe>
|
||||||
|
</div>
|
||||||
<Attachments v-if="allAttachments(message).length" :message="message"
|
<Attachments v-if="allAttachments(message).length" :message="message"
|
||||||
:attachments="allAttachments(message)"></Attachments>
|
:attachments="allAttachments(message)"></Attachments>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user