344 lines
7.3 KiB
Vue
344 lines
7.3 KiB
Vue
<template>
|
|
<article class="one-demo" :class="{ codeExpanded }">
|
|
<section class="demo">
|
|
<browser-window
|
|
v-if="browser"
|
|
:url="browser"
|
|
width="calc(100% - 40px)"
|
|
height="400px"
|
|
>
|
|
<one-iframe
|
|
global-style="body { margin: 0 !important; } .veui-layout { min-width: auto !important; }"
|
|
>
|
|
<slot />
|
|
</one-iframe>
|
|
</browser-window>
|
|
<slot v-else />
|
|
</section>
|
|
<section v-if="$slots.desc" class="desc">
|
|
<slot name="desc" />
|
|
</section>
|
|
<section class="actions">
|
|
<veui-button
|
|
v-tooltip="t(codeExpanded ? 'hideCode' : 'showCode')"
|
|
ui="icon"
|
|
@click="codeExpanded = !codeExpanded"
|
|
>
|
|
<veui-icon
|
|
scale="1.2"
|
|
:name="codeExpanded ? 'one-demo-code-off' : 'one-demo-code'"
|
|
/>
|
|
</veui-button>
|
|
<veui-button
|
|
v-tooltip="t(editing ? 'closeEditor' : 'openEditor')"
|
|
class="toggle-editor"
|
|
ui="text"
|
|
@click="editing = !editing"
|
|
>
|
|
Live
|
|
</veui-button>
|
|
<!-- 禁用跳转Github -->
|
|
<!-- <one-edit-link class="edit" variant="quiet" type="demo" :path="path" /> -->
|
|
</section>
|
|
<section
|
|
v-if="$slots.source"
|
|
ref="source"
|
|
class="source"
|
|
:style="{ height: codeExpanded ? `${sourceHeight || 0}px` : '0' }"
|
|
>
|
|
<div class="source-toolbar">
|
|
<veui-button
|
|
v-tooltip="t('@onelive.copyCode')"
|
|
ui="icon reverse"
|
|
@click="copy"
|
|
>
|
|
<veui-icon name="copy" />
|
|
</veui-button>
|
|
</div>
|
|
<slot name="source" />
|
|
</section>
|
|
<transition name="editor">
|
|
<one-repl
|
|
v-if="editing"
|
|
class="one-demo-editor"
|
|
:class="{
|
|
'one-demo-editor-shrink': !editorExpanded,
|
|
}"
|
|
:code="code"
|
|
:expanded="editorExpanded"
|
|
:browser="!!browser"
|
|
@close="handleEditorClose"
|
|
@toggle="handleEditorToggle"
|
|
/>
|
|
</transition>
|
|
</article>
|
|
</template>
|
|
|
|
<script>
|
|
import Vue from "vue";
|
|
import { Button, Icon } from "veui";
|
|
import tooltip from "veui/directives/tooltip";
|
|
import modal from "veui/managers/modal";
|
|
import i18n from "veui/mixins/i18n";
|
|
import toast from "veui/plugins/toast";
|
|
import { BrowserWindow } from "vue-windows";
|
|
import { getLocale } from "../common/i18n";
|
|
import { play } from "../common/play";
|
|
import OneIframe from "./OneIframe";
|
|
import OneEditLink from "./OneEditLink";
|
|
import OneRepl from "./OneRepl";
|
|
import "veui-theme-dls-icons/copy";
|
|
|
|
Vue.use(toast);
|
|
|
|
export default {
|
|
name: "one-demo",
|
|
directives: {
|
|
tooltip,
|
|
},
|
|
components: {
|
|
"veui-button": Button,
|
|
"veui-icon": Icon,
|
|
BrowserWindow,
|
|
OneIframe,
|
|
OneEditLink,
|
|
OneRepl,
|
|
},
|
|
mixins: [i18n],
|
|
props: {
|
|
browser: String,
|
|
path: String,
|
|
},
|
|
data() {
|
|
return {
|
|
code: "",
|
|
sourceHeight: 0,
|
|
codeExpanded: false,
|
|
editing: false,
|
|
editorExpanded: true,
|
|
};
|
|
},
|
|
computed: {
|
|
lock() {
|
|
return this.editing && this.editorExpanded;
|
|
},
|
|
},
|
|
watch: {
|
|
lock(value) {
|
|
if (value) {
|
|
modal.open();
|
|
} else {
|
|
modal.close();
|
|
}
|
|
},
|
|
},
|
|
mounted() {
|
|
let source = this.$refs.source;
|
|
let style = source.style;
|
|
style.height = "";
|
|
style.height = source.offsetHeight;
|
|
this.sourceHeight = source.offsetHeight;
|
|
style.height = "0";
|
|
|
|
this.code = this.$refs.source?.querySelector("pre")?.textContent || "";
|
|
},
|
|
destroyed() {
|
|
modal.close();
|
|
},
|
|
methods: {
|
|
play(vendor) {
|
|
let locale = getLocale(this.$route.path);
|
|
play(this.$refs.source.textContent, { locale, vendor });
|
|
},
|
|
async copy() {
|
|
try {
|
|
await navigator.clipboard.writeText(this.code);
|
|
this.$toast.success(this.t("@onelive.copySuccess"));
|
|
} catch (e) {
|
|
this.$toast.error(this.t("@onelive.copyFailed"));
|
|
}
|
|
},
|
|
handleEditorClose() {
|
|
this.editing = false;
|
|
},
|
|
handleEditorToggle(val) {
|
|
this.editorExpanded = val;
|
|
},
|
|
},
|
|
};
|
|
|
|
Icon.register({
|
|
"one-demo-code": {
|
|
width: 24,
|
|
height: 24,
|
|
d: "M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6l6 6l1.4-1.4zm5.2 0l4.6-4.6l-4.6-4.6L16 6l6 6l-6 6l-1.4-1.4z",
|
|
},
|
|
"one-demo-code-off": {
|
|
width: 24,
|
|
height: 24,
|
|
d: "M19.17 12l-4.58-4.59L16 6l6 6l-3.59 3.59L17 14.17L19.17 12zM1.39 4.22l4.19 4.19L2 12l6 6l1.41-1.41L4.83 12L7 9.83l12.78 12.78l1.41-1.41L2.81 2.81L1.39 4.22z",
|
|
},
|
|
"one-demo-codesandbox": {
|
|
width: 32,
|
|
height: 32,
|
|
d: "M2.667 8l13.938-8l13.943 8l.12 15.932L16.605 32L2.667 24zm2.786 3.307v6.344l4.458 2.479v4.688l5.297 3.063V16.85zm22.318 0l-9.755 5.542V27.88l5.292-3.063v-4.682l4.464-2.484zM6.844 8.802l9.74 5.526l9.76-5.573l-5.161-2.932l-4.547 2.594l-4.573-2.625z",
|
|
},
|
|
"one-demo-stackblitz": {
|
|
width: 28,
|
|
height: 28,
|
|
d: "M12.747 16.273h-7.46L18.925 1.5l-3.671 10.227h7.46L9.075 26.5l3.671-10.227z",
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<style src="vue-windows/dist/vue-windows.css"></style>
|
|
|
|
<style lang="stylus" scoped>
|
|
.one-demo {
|
|
overflow: hidden;
|
|
}
|
|
|
|
.demo {
|
|
border: 1px solid #eee;
|
|
border-top-left-radius: 4px;
|
|
border-top-right-radius: 4px;
|
|
padding: 30px;
|
|
|
|
& >>> .style-module_body__14MV- {
|
|
overflow: hidden;
|
|
transform: translate(0, 0);
|
|
padding: 0;
|
|
}
|
|
}
|
|
|
|
.desc {
|
|
border: 1px solid #eee;
|
|
padding: 18px 20px;
|
|
background-color: #fcfcfc;
|
|
}
|
|
|
|
.source {
|
|
position: relative;
|
|
overflow: hidden;
|
|
transition: height 0.3s;
|
|
|
|
& >>> pre {
|
|
margin-top: 0;
|
|
margin-bottom: 0;
|
|
border-top-right-radius: 0;
|
|
border-top-left-radius: 0;
|
|
}
|
|
}
|
|
|
|
.desc, .source >>> pre, .actions {
|
|
margin-top: -1px;
|
|
}
|
|
|
|
.actions {
|
|
position: relative;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
line-height: 2;
|
|
width: 100%;
|
|
height: 48px;
|
|
border: 1px solid #eee;
|
|
border-bottom-left-radius: 4px;
|
|
border-bottom-right-radius: 4px;
|
|
background-color: #fff;
|
|
transition: background-color 0.3s;
|
|
outline: none;
|
|
|
|
.codeExpanded & {
|
|
border-radius: 0;
|
|
}
|
|
|
|
.veui-button:not(.toggle-editor) {
|
|
font-size: 18px;
|
|
}
|
|
|
|
.veui-button + .veui-button {
|
|
margin-left: 12px;
|
|
}
|
|
}
|
|
|
|
.edit {
|
|
position: absolute;
|
|
right: 30px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
font-size: 12px;
|
|
}
|
|
|
|
.one-demo-editor {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
z-index: 10;
|
|
background-color: #fff;
|
|
transition: bottom 0.1s, box-shadow 0.2s;
|
|
|
|
&-shrink {
|
|
bottom: 50vh;
|
|
box-shadow: 0 0 4px #0006;
|
|
}
|
|
}
|
|
|
|
.editor-enter-active, .editor-leave-active {
|
|
transform-origin: 50% 50%;
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.editor-enter, .editor-leave-to {
|
|
opacity: 0;
|
|
transform: scale(0.99) translateY(3px);
|
|
}
|
|
|
|
.toggle-editor {
|
|
height: 20px;
|
|
padding: 0 3px;
|
|
font-weight: 600;
|
|
|
|
&::after {
|
|
content: none !important;
|
|
}
|
|
|
|
&, &:hover, &[data-focus-visible-added], &:active {
|
|
border: 1.5px solid currentColor !important;
|
|
}
|
|
|
|
&[data-focus-visible-added] {
|
|
border-color: #0052cc !important;
|
|
box-shadow: 0 0 0 2px rgba(0, 102, 255, 0.2) !important;
|
|
}
|
|
}
|
|
|
|
.source-toolbar {
|
|
position: absolute;
|
|
top: 12px;
|
|
right: 28px;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.veui-button[ui~='icon'][ui~='reverse'] {
|
|
color: #ebedf5;
|
|
|
|
&:hover, &[data-focus-visible-added] {
|
|
color: #f6f7fa;
|
|
}
|
|
|
|
&:active {
|
|
color: #fff;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
.toggle-editor {
|
|
display: none;
|
|
}
|
|
}
|
|
</style>
|