UNPKG

quasar-ui-example-viewer

Version:

Display Vue code examples with template, script and style parts with optional source and codepen links

450 lines (409 loc) 13.1 kB
import { QBtn, QCard, QCardSection, QSeparator, QSlideTransition, QSpace, QTab, QTabs, QTabPanel, QTabPanels, QToolbar, QToolbarTitle, QTooltip, copyToClipboard, openURL } from 'quasar' import { QRibbon } from '@quasar/quasar-ui-qribbon' import { QMarkdown } from '@quasar/quasar-ui-qmarkdown' import { slugify } from '../utils/pageUtils' import Codepen from './Codepen' const mdiGithub = 'M12,2A10,10 0 0,0 2,12C2,16.42 4.87,20.17 8.84,21.5C9.34,21.58 9.5,21.27 9.5,21C9.5,20.77 9.5,20.14 9.5,19.31C6.73,19.91 6.14,17.97 6.14,17.97C5.68,16.81 5.03,16.5 5.03,16.5C4.12,15.88 5.1,15.9 5.1,15.9C6.1,15.97 6.63,16.93 6.63,16.93C7.5,18.45 8.97,18 9.54,17.76C9.63,17.11 9.89,16.67 10.17,16.42C7.95,16.17 5.62,15.31 5.62,11.5C5.62,10.39 6,9.5 6.65,8.79C6.55,8.54 6.2,7.5 6.75,6.15C6.75,6.15 7.59,5.88 9.5,7.17C10.29,6.95 11.15,6.84 12,6.84C12.85,6.84 13.71,6.95 14.5,7.17C16.41,5.88 17.25,6.15 17.25,6.15C17.8,7.5 17.45,8.54 17.35,8.79C18,9.5 18.38,10.39 18.38,11.5C18.38,15.32 16.04,16.16 13.81,16.41C14.17,16.72 14.5,17.33 14.5,18.26C14.5,19.6 14.5,20.68 14.5,21C14.5,21.27 14.66,21.59 15.17,21.5C19.14,20.16 22,16.42 22,12A10,10 0 0,0 12,2Z' // const mdiCodepen = 'M8.21 12L6.88 12.89V11.11L8.21 12M11.47 9.82V7.34L7.31 10.12L9.16 11.36L11.47 9.82M16.7 10.12L12.53 7.34V9.82L14.84 11.36L16.7 10.12M7.31 13.88L11.47 16.66V14.18L9.16 12.64L7.31 13.88M12.53 14.18V16.66L16.7 13.88L14.84 12.64L12.53 14.18M12 10.74L10.12 12L12 13.26L13.88 12L12 10.74M22 12C22 17.5 17.5 22 12 22C6.5 22 2 17.5 2 12C2 6.5 6.5 2 12 2C17.5 2 22 6.5 22 12M18.18 10.12C18.18 10.09 18.18 10.07 18.18 10.05L18.17 10L18.17 10L18.16 9.95C18.15 9.94 18.15 9.93 18.14 9.91L18.13 9.89L18.11 9.85L18.1 9.83L18.08 9.8L18.06 9.77L18.03 9.74L18 9.72L18 9.7L17.96 9.68L17.95 9.67L12.3 5.91C12.12 5.79 11.89 5.79 11.71 5.91L6.05 9.67L6.05 9.68L6 9.7C6 9.71 6 9.72 6 9.72L5.97 9.74L5.94 9.77L5.93 9.8L5.9 9.83L5.89 9.85L5.87 9.89L5.86 9.91L5.84 9.95L5.84 10L5.83 10L5.82 10.05C5.82 10.07 5.82 10.09 5.82 10.12V13.88C5.82 13.91 5.82 13.93 5.82 13.95L5.83 14L5.84 14L5.84 14.05C5.85 14.06 5.85 14.07 5.86 14.09L5.87 14.11L5.89 14.15L5.9 14.17L5.92 14.2L5.94 14.23C5.95 14.24 5.96 14.25 5.97 14.26L6 14.28L6 14.3L6.04 14.32L6.05 14.33L11.71 18.1C11.79 18.16 11.9 18.18 12 18.18C12.1 18.18 12.21 18.15 12.3 18.1L17.95 14.33L17.96 14.32L18 14.3L18 14.28L18.03 14.26L18.06 14.23L18.08 14.2L18.1 14.17L18.11 14.15L18.13 14.11L18.14 14.09L18.16 14.05L18.16 14L18.17 14L18.18 13.95C18.18 13.93 18.18 13.91 18.18 13.88V10.12M17.12 12.89V11.11L15.79 12L17.12 12.89Z' const mdiContentCopy = 'M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z' const mdiCodeTags = 'M14.6,16.6L19.2,12L14.6,7.4L16,6L22,12L16,18L14.6,16.6M9.4,16.6L4.8,12L9.4,7.4L8,6L2,12L8,18L9.4,16.6Z' const laCodepen = 'M 16 2.84375 L 15.4375 3.21875 L 3.4375 11.25 L 3 11.53125 L 3 20.46875 L 3.4375 20.75 L 15.4375 28.78125 L 16 29.15625 L 16.5625 28.78125 L 28.5625 20.75 L 29 20.46875 L 29 11.53125 L 28.5625 11.25 L 16.5625 3.21875 Z M 15 5.90625 L 15 11.34375 L 9.84375 14.8125 L 5.8125 12.09375 Z M 17 5.90625 L 26.1875 12.09375 L 22.15625 14.8125 L 17 11.34375 Z M 16 13.09375 L 20.34375 16 L 16 18.90625 L 11.65625 16 Z M 5 13.9375 L 8.0625 16 L 5 18.0625 Z M 27 13.9375 L 27 18.0625 L 23.9375 16 Z M 9.875 17.1875 L 15 20.65625 L 15 26.09375 L 5.8125 19.90625 Z M 22.125 17.1875 L 26.1875 19.90625 L 17 26.09375 L 17 20.65625 Z|0 0 32 32' const matDone = 'M0 0h24v24H0z@@fill:none;&&M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z' export default { name: 'ExampleViewer', props: { title: { type: String, required: true }, file: { type: String, required: true, validator: v => v.length > 0 }, codepenTitle: String, jsPaths: Array, cssPaths: Array, tooltipLabel: { type: String, default: 'View sources' }, ribbonColor: { type: String, default: '#c0c0c0' }, ribbonTextColor: { type: String, default: 'rgb(0,0,0,.58)' }, ribbonLeafColor: { type: String, default: '#a0a0a0' }, locationUrl: String, locationIcon: { type: String, }, noEdit: Boolean, noCopy: Boolean, copyIcon: String, copyLabel: { type: String, default: 'Copy to clipboard' }, copyResponse: { type: String, default: 'Copied to clipboard' }, noLineNumbers: Boolean, noAnchor: Boolean, anchorResponse: { type: String, default: 'Anchor copied to clipboard' } }, data () { return { component: null, tabs: [], currentTab: 'template', parts: {}, expanded: false } }, created () { this.codepen = laCodepen this.github = mdiGithub this.copy = mdiContentCopy this.code = mdiCodeTags this.done = matDone }, mounted () { import( /* webpackChunkName: "examples" */ /* webpackMode: "lazy-once" */ `examples/${this.file}.vue` ).then(comp => { this.component = comp.default import( /* webpackChunkName: "examples-source" */ /* webpackMode: "lazy-once" */ `!raw-loader!examples/${this.file}.vue` ).then(comp => { this.__parseComponent(comp.default) }) }) }, computed: { __slugifiedTitle () { return this.__slugify('example-' + this.title) } }, methods: { __slugify: slugify, __copyHeading () { if (this.noAnchor === true) { return } if (window && window.location && document) { const text = window.location.origin + window.location.pathname + '#' + this.__slugifiedTitle const el = document.getElementById(this.__slugifiedTitle) if (el) { el.id = '' window.location.hash = '#' + this.__slugifiedTitle setTimeout(() => { el.id = this.__slugifiedTitle }, 300) copyToClipboard(text) this.$q.notify({ message: this.anchorResponse, color: this.$q.dark.isActive ? 'grey-10' : 'white', textColor: this.$q.dark.isActive ? 'amber' : 'primary', icon: this.done, position: 'top', timeout: 2000 }) } } }, __parseComponent (comp) { const template = this.__parseTemplate('template', comp), script = this.__parseTemplate('script', comp), style = this.__parseTemplate('style', comp) this.parts = { template, script, style } this.tabs = ['template', 'script', 'style'].filter(type => this.parts[type]) }, __parseTemplate (target, template) { const string = `(<${target}(.*)?>[\\w\\W]*<\\/${target}>)`, regex = new RegExp(string, 'g'), parsed = regex.exec(template) || [] return parsed[1] || '' }, __openLocation () { openURL(`${this.locationUrl}/${this.file}.vue`) }, __openCodepen () { this.$refs.codepen.open(this.parts) }, __copyTab (tab) { copyToClipboard(this.parts[this.tabs[tab]]) this.$q.notify({ message: this.copyResponse, color: this.$q.dark.isActive ? 'grey-10' : 'white', textColor: this.$q.dark.isActive ? 'amber' : 'primary', icon: 'done', position: 'top', timeout: 2000 }) }, __renderRibbon (h) { return h(QRibbon, { props: { position: 'left', color: this.ribbonTextColor, backgroundColor: this.ribbonColor, leafColor: this.ribbonLeafColor, leafPosition: 'bottom', decoration: 'rounded-out' } }, [ h(QToolbarTitle, { staticClass: this.noAnchor !== true ? 'example-title' : '', on: { click: this.__copyHeading } }, [ h('span', { staticClass: 'ellipsis' }, this.title) ]) ]) }, __renderToolbar (h) { return h(QToolbar, [ this.__renderRibbon(h), h(QSpace), h('div', { staticClass: 'col-auto' }, [ this.locationUrl && h(QBtn, { props: { dense: true, flat: true, round: true, icon: (this.locationIcon ? this.locationIcon : this.github) }, on: { click: this.__openLocation } }), this.noEdit !== true && h(QBtn, { props: { dense: true, flat: true, round: true, icon: this.codepen }, on: { click: this.__openCodepen } }), h(QBtn, { props: { dense: true, flat: true, round: true, icon: this.code }, on: { click: v => { this.expanded = !this.expanded } } }, [ h(QTooltip, this.tooltipLabel) ]) ]) ]) }, __renderTabs (h) { return h(QTabs, { staticClass: 'text-caption' + (!this.$q.dark.isActive ? ' bg-grey-2 text-grey-7' : ''), props: { value: this.currentTab, align: 'left', activeColor: this.$q.dark.isActive ? 'amber' : void 0, indicatorColor: this.$q.dark.isActive ? 'amber' : 'primary', dense: true, breakpoint: 0 }, on: { input: v => { this.currentTab = v } } }, [ ...Object.keys(this.tabs).map(tab => h(QTab, { key: `tab-${this.tabs[tab]}`, props: { name: this.tabs[tab], label: this.tabs[tab] } })) ]) }, __renderCopy (h, tab) { if (this.noCopy !== true) { return h(QBtn, { staticClass: 'absolute', style: { top: '15px', right: '15px' }, props: { color: this.$q.dark.isActive ? 'amber' : 'primary', dense: true, flat: true, round: true, icon: (this.copyIcon ? this.copyIcon : this.copy) }, on: { click: v => { this.__copyTab(tab) } } }, [ h(QTooltip, this.copyLabel) ]) } }, __renderTabPanel (h) { const type = {} type.style = '```css\n' type.template = '```html\n' type.script = '```js\n' const end = '\n```' return [ ...Object.keys(this.tabs).map(tab => h(QTabPanel, { key: `panel-${this.tabs[tab]}`, staticClass: 'q-pa-none relative-position', props: { name: this.tabs[tab] } }, [ h(QMarkdown, { staticClass: '', props: { noLineNumbers: this.noLineNumbers } }, [ `${type[this.tabs[tab]]}${this.parts[this.tabs[tab]]}${end}` ]), this.__renderCopy(h, tab) ]))] }, __renderTabPanels (h) { return h(QTabPanels, { props: { value: this.currentTab, animated: true }, on: { input: v => { this.currentTab = v } } }, [ this.__renderTabPanel(h) ]) }, __renderInnerCard (h) { return h(QCard, [ this.__renderTabs(h), this.__renderTabPanels(h) ]) }, __renderExpansionItem (h) { return h(QSlideTransition, [ this.expanded && h('div', { }, [ this.__renderInnerCard(h) ]) ]) }, __renderComponent (h) { return h('div', { staticClass: 'row' }, [ h(this.component, { staticClass: 'col' }) ]) }, __renderSlot (h, slot) { return h(QCardSection, [ slot() ]) }, __renderCard (h) { const slot = this.$scopedSlots.default return h(QCard, { staticClass: 'no-shadow', props: { flat: true, bordered: true, } }, [ this.__renderToolbar(h), h(QSeparator), this.__renderExpansionItem(h), slot ? this.__renderSlot(h, slot) : void 0, slot ? h(QSeparator) : void 0, h(QCardSection, { staticClass: 'no-shadow', style: { padding: 0 } }, [ this.__renderComponent(h) ]) ]) }, __renderCodepen (h) { return h(Codepen, { ref: 'codepen', props: { codepenTitle: this.codepenTitle, title: this.title, slugifiedTitle: this.__slugifiedTitle, jsPaths: this.jsPaths, cssPaths: this.cssPaths } }) } }, render (h) { return h('section', { staticClass: 'q-pa-md overflow-auto', attrs: { id: this.__slugifiedTitle } }, [ this.__renderCard(h), this.__renderCodepen(h) ]) } }