Skip to content

Commit

Permalink
Feat(ui): Viewport size switcher to test responsive/mobile view (Impl…
Browse files Browse the repository at this point in the history
…ements #482) (#1447)
  • Loading branch information
rnwood committed Apr 28, 2024
1 parent 1ef2ac4 commit 8d6dd1a
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 293 deletions.
7 changes: 7 additions & 0 deletions Rnwood.Smtp4dev/ClientApp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Rnwood.Smtp4dev/ClientApp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"brace": "^0.11.1",
"core-js": "^3.36.1",
"cross-env": "^7.0.3",
"device-sizes": "^1.2.3",
"element-plus": "^2.7.0",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9",
Expand Down
86 changes: 82 additions & 4 deletions Rnwood.Smtp4dev/ClientApp/src/components/messageviewhtml.vue
Original file line number Diff line number Diff line change
@@ -1,26 +1,72 @@
<template>

<div class="hfillpanel" v-loading="!html">

<div class="toolbar">
<el-select style="flex: 1 0 200px;" v-model="selectedViewportSizeName" filterable @change="viewportRotate=false">
<el-option v-for="item in availableViewportSizes"
:key="item.name"
:label="item.name"
:value="item.name" />

<template #prefix>
<el-icon><Monitor /></el-icon>
</template>

</el-select>

<el-switch v-model="viewportRotate" v-if="!selectedViewportSize.fill" active-text="Rotate" size="medium" />

<el-select style="flex: 0 0 100px;" v-model="selectedZoomLevelName">
<el-option v-for="item in availableZoomLevels"
:key="item.name"
:label="item.name"
:value="item.name" />

<template #prefix>
<el-icon><ZoomOut /></el-icon>
</template>

</el-select>

</div>

<el-alert v-if="error" type="error">
{{error.message}}

<el-button v-on:click="loadMessage">Retry</el-button>
</el-alert>
<el-alert v-if="wasSanitized" type="warning">
Message HTML was sanizited for display. <el-button type="danger" size="small" v-on:click="disableSanitization">Disable (DANGER!)</el-button>
Message HTML was sanitized for display. <el-button type="danger" size="small" v-on:click="disableSanitization">Disable (DANGER!)</el-button>
</el-alert>

<iframe class="fill" @load="onHtmlFrameLoaded" ref="htmlframe"></iframe>
<div class="fill" style="display: flex; flex-direction: column;">
<iframe :style="htmlFrameStyles" @load="onHtmlFrameLoaded" ref="htmlframe"></iframe>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Watch, toNative } from 'vue-facing-decorator'
import MessagesController from "../ApiClient/MessagesController";
import ServerController from "../ApiClient/ServerController";
import Message from "../ApiClient/Message";
import * as srcDoc from 'srcdoc-polyfill';
import sanitizeHtml from 'sanitize-html';
import { deviceSizes, Brand } from 'device-sizes'
type ViewPortSize = {
name: string
fill?: boolean
height?: number,
width?: number
}
type ZoomLevel = {
name: string,
scale: number
}
@Component
class MessageViewHtml extends Vue {
Expand All @@ -31,6 +77,39 @@
sanitizedHtml: string | null = null;
wasSanitized: boolean = false;
availableViewportSizes: ViewPortSize[] = [{ name: "Normal", fill: true }].concat(Object.values(deviceSizes).map(d => ({
name: `${Brand[d.brand]} ${d.name} (${d.size}")`, fill: false, width: d.width / d.scale, height: d.height / d.scale
})));
selectedViewportSizeName = "Normal";
viewportRotate = false;
availableZoomLevels: ZoomLevel[] = [{ name: "150%", scale: 1.5 },{ name: "125%", scale: 1.25 },{ name: "100%", scale: 1 }, { name: "75%", scale: 0.75 }, { name: "50%", scale: 0.5 }]
selectedZoomLevelName = "100%";
get selectedViewportSize(): ViewPortSize {
return this.availableViewportSizes.find(s => s.name == this.selectedViewportSizeName) ?? this.availableViewportSizes[0];
}
get selectedZoomLevel(): ZoomLevel {
return this.availableZoomLevels.find(s => s.name == this.selectedZoomLevelName) ?? this.availableZoomLevels[0];
}
get htmlFrameStyles() {
const height = this.viewportRotate ? this.selectedViewportSize.width : this.selectedViewportSize.height;
const width = this.viewportRotate ? this.selectedViewportSize.height : this.selectedViewportSize.width;
return {
border: (this.selectedViewportSize.fill ? '0' : '5px solid black'),
'align-self': (this.selectedViewportSize.fill ? 'stretch' : 'center'),
'flex-grow': `${this.selectedViewportSize.fill ? 1 : 0}`,
'flex-shrink': 0,
'height': `${(height ?? 0) * this.selectedZoomLevel.scale}px`,
width: (this.selectedViewportSize.fill ? '100%' : ((width ?? 0) * this.selectedZoomLevel.scale) + 'px'),
'transform-origin': "top left",
transform: `scale(${this.selectedZoomLevel.scale})`
};
}
error: Error | null = null;
loading = false;
Expand Down Expand Up @@ -100,7 +179,6 @@
}
async created() {
this.loadMessage();
}
Expand Down
1 change: 1 addition & 0 deletions Rnwood.Smtp4dev/ClientApp/src/css/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ pre.source code {

.toolbar {
display: flex;
flex: 0 0 content;
flex-wrap: wrap;
column-gap: 6px;
row-gap: 6px;
Expand Down

0 comments on commit 8d6dd1a

Please sign in to comment.