Последняя версия с сервера прошлого разработчика
This commit is contained in:
23
nova/resources/js/components/Detail/BadgeField.vue
Executable file
23
nova/resources/js/components/Detail/BadgeField.vue
Executable file
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<panel-item :field="field">
|
||||
<template slot="value">
|
||||
<badge
|
||||
class="mt-1"
|
||||
:label="field.label"
|
||||
:extra-classes="field.typeClass"
|
||||
/>
|
||||
</template>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Badge from '../Badge'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Badge,
|
||||
},
|
||||
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
}
|
||||
</script>
|
||||
27
nova/resources/js/components/Detail/BelongsToField.vue
Executable file
27
nova/resources/js/components/Detail/BelongsToField.vue
Executable file
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<panel-item :field="field">
|
||||
<template slot="value">
|
||||
<router-link
|
||||
v-if="field.viewable && field.value"
|
||||
:to="{
|
||||
name: 'detail',
|
||||
params: {
|
||||
resourceName: field.resourceName,
|
||||
resourceId: field.belongsToId,
|
||||
},
|
||||
}"
|
||||
class="no-underline font-bold dim text-primary"
|
||||
>
|
||||
{{ field.value }}
|
||||
</router-link>
|
||||
<p v-else-if="field.value">{{ field.value }}</p>
|
||||
<p v-else>—</p>
|
||||
</template>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
}
|
||||
</script>
|
||||
29
nova/resources/js/components/Detail/BelongsToManyField.vue
Executable file
29
nova/resources/js/components/Detail/BelongsToManyField.vue
Executable file
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<resource-index
|
||||
:field="field"
|
||||
:resource-name="field.resourceName"
|
||||
:via-resource="resourceName"
|
||||
:via-resource-id="resourceId"
|
||||
:via-relationship="field.belongsToManyRelationship"
|
||||
:relationship-type="'belongsToMany'"
|
||||
@actionExecuted="actionExecuted"
|
||||
:load-cards="false"
|
||||
:initialPerPage="field.perPage || 5"
|
||||
:should-override-meta="false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resourceName', 'resourceId', 'resource', 'field'],
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Handle the actionExecuted event and pass it up the chain.
|
||||
*/
|
||||
actionExecuted() {
|
||||
this.$emit('actionExecuted')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
34
nova/resources/js/components/Detail/BooleanField.vue
Executable file
34
nova/resources/js/components/Detail/BooleanField.vue
Executable file
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<panel-item :field="field">
|
||||
<icon
|
||||
v-if="field.value"
|
||||
slot="value"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
type="check-circle"
|
||||
class="text-success"
|
||||
/>
|
||||
<icon
|
||||
v-else
|
||||
slot="value"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
type="x-circle"
|
||||
class="text-danger"
|
||||
/>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
|
||||
computed: {
|
||||
label() {
|
||||
return this.field.value == true ? this.__('Yes') : this.__('No')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
55
nova/resources/js/components/Detail/BooleanGroupField.vue
Executable file
55
nova/resources/js/components/Detail/BooleanGroupField.vue
Executable file
@@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<panel-item :field="field">
|
||||
<template slot="value">
|
||||
<ul class="list-reset" v-if="value.length > 0">
|
||||
<li v-for="option in value" class="mb-1">
|
||||
<span
|
||||
:class="classes[option.checked]"
|
||||
class="inline-flex items-center py-1 pl-2 pr-3 rounded-full font-bold text-sm leading-tight"
|
||||
>
|
||||
<boolean-icon :value="option.checked" width="20" height="20" />
|
||||
<span class="ml-1">{{ option.label }}</span>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<span v-else>{{ this.field.noValueText }}</span>
|
||||
</template>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
|
||||
data: () => ({
|
||||
value: [],
|
||||
classes: {
|
||||
true: 'bg-success-light text-success-dark',
|
||||
false: 'bg-danger-light text-danger-dark',
|
||||
},
|
||||
}),
|
||||
|
||||
created() {
|
||||
this.field.value = this.field.value || {}
|
||||
|
||||
this.value = _(this.field.options)
|
||||
.map(o => {
|
||||
return {
|
||||
name: o.name,
|
||||
label: o.label,
|
||||
checked: this.field.value[o.name] || false,
|
||||
}
|
||||
})
|
||||
.filter(o => {
|
||||
if (this.field.hideFalseValues === true && o.checked === false) {
|
||||
return false
|
||||
} else if (this.field.hideTrueValues === true && o.checked === true) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
.value()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
121
nova/resources/js/components/Detail/CodeField.vue
Executable file
121
nova/resources/js/components/Detail/CodeField.vue
Executable file
@@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<panel-item :field="field">
|
||||
<template slot="value">
|
||||
<div class="form-input form-input-bordered px-0 overflow-hidden">
|
||||
<textarea ref="theTextarea" />
|
||||
</div>
|
||||
</template>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<style src="codemirror/lib/codemirror.css" />
|
||||
|
||||
<style src="codemirror/theme/3024-day.css" />
|
||||
<style src="codemirror/theme/3024-night.css" />
|
||||
<style src="codemirror/theme/abcdef.css" />
|
||||
<style src="codemirror/theme/ambiance-mobile.css" />
|
||||
<style src="codemirror/theme/ambiance.css" />
|
||||
<style src="codemirror/theme/base16-dark.css" />
|
||||
<style src="codemirror/theme/base16-light.css" />
|
||||
<style src="codemirror/theme/bespin.css" />
|
||||
<style src="codemirror/theme/blackboard.css" />
|
||||
<style src="codemirror/theme/cobalt.css" />
|
||||
<style src="codemirror/theme/colorforth.css" />
|
||||
<style src="codemirror/theme/darcula.css" />
|
||||
<style src="codemirror/theme/dracula.css" />
|
||||
<style src="codemirror/theme/duotone-dark.css" />
|
||||
<style src="codemirror/theme/duotone-light.css" />
|
||||
<style src="codemirror/theme/eclipse.css" />
|
||||
<style src="codemirror/theme/elegant.css" />
|
||||
<style src="codemirror/theme/erlang-dark.css" />
|
||||
<style src="codemirror/theme/gruvbox-dark.css" />
|
||||
<style src="codemirror/theme/hopscotch.css" />
|
||||
<style src="codemirror/theme/icecoder.css" />
|
||||
<style src="codemirror/theme/idea.css" />
|
||||
<style src="codemirror/theme/isotope.css" />
|
||||
<style src="codemirror/theme/lesser-dark.css" />
|
||||
<style src="codemirror/theme/liquibyte.css" />
|
||||
<style src="codemirror/theme/lucario.css" />
|
||||
<style src="codemirror/theme/material.css" />
|
||||
<style src="codemirror/theme/mbo.css" />
|
||||
<style src="codemirror/theme/mdn-like.css" />
|
||||
<style src="codemirror/theme/midnight.css" />
|
||||
<style src="codemirror/theme/monokai.css" />
|
||||
<style src="codemirror/theme/neat.css" />
|
||||
<style src="codemirror/theme/neo.css" />
|
||||
<style src="codemirror/theme/night.css" />
|
||||
<style src="codemirror/theme/oceanic-next.css" />
|
||||
<style src="codemirror/theme/panda-syntax.css" />
|
||||
<style src="codemirror/theme/paraiso-dark.css" />
|
||||
<style src="codemirror/theme/paraiso-light.css" />
|
||||
<style src="codemirror/theme/pastel-on-dark.css" />
|
||||
<style src="codemirror/theme/railscasts.css" />
|
||||
<style src="codemirror/theme/rubyblue.css" />
|
||||
<style src="codemirror/theme/seti.css" />
|
||||
<style src="codemirror/theme/shadowfox.css" />
|
||||
<style src="codemirror/theme/solarized.css" />
|
||||
<style src="codemirror/theme/ssms.css" />
|
||||
<style src="codemirror/theme/the-matrix.css" />
|
||||
<style src="codemirror/theme/tomorrow-night-bright.css" />
|
||||
<style src="codemirror/theme/tomorrow-night-eighties.css" />
|
||||
<style src="codemirror/theme/ttcn.css" />
|
||||
<style src="codemirror/theme/twilight.css" />
|
||||
<style src="codemirror/theme/vibrant-ink.css" />
|
||||
<style src="codemirror/theme/xq-dark.css" />
|
||||
<style src="codemirror/theme/xq-light.css" />
|
||||
<style src="codemirror/theme/yeti.css" />
|
||||
<style src="codemirror/theme/zenburn.css" />
|
||||
<script>
|
||||
import CodeMirror from 'codemirror'
|
||||
|
||||
// Modes
|
||||
import 'codemirror/mode/markdown/markdown'
|
||||
import 'codemirror/mode/javascript/javascript'
|
||||
import 'codemirror/mode/php/php'
|
||||
import 'codemirror/mode/ruby/ruby'
|
||||
import 'codemirror/mode/shell/shell'
|
||||
import 'codemirror/mode/sass/sass'
|
||||
import 'codemirror/mode/yaml/yaml'
|
||||
import 'codemirror/mode/yaml-frontmatter/yaml-frontmatter'
|
||||
import 'codemirror/mode/nginx/nginx'
|
||||
import 'codemirror/mode/xml/xml'
|
||||
import 'codemirror/mode/vue/vue'
|
||||
import 'codemirror/mode/dockerfile/dockerfile'
|
||||
import 'codemirror/keymap/vim'
|
||||
import 'codemirror/mode/twig/twig'
|
||||
import 'codemirror/mode/htmlmixed/htmlmixed'
|
||||
|
||||
CodeMirror.defineMode('htmltwig', function (config, parserConfig) {
|
||||
return CodeMirror.overlayMode(
|
||||
CodeMirror.getMode(config, parserConfig.backdrop || 'text/html'),
|
||||
CodeMirror.getMode(config, 'twig')
|
||||
)
|
||||
})
|
||||
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
|
||||
data: () => ({ codemirror: null }),
|
||||
|
||||
/**
|
||||
* Mount the component.
|
||||
*/
|
||||
mounted() {
|
||||
const config = {
|
||||
...{
|
||||
tabSize: 4,
|
||||
indentWithTabs: true,
|
||||
lineWrapping: true,
|
||||
lineNumbers: true,
|
||||
theme: 'dracula',
|
||||
},
|
||||
...this.field.options,
|
||||
...{ readOnly: true },
|
||||
}
|
||||
|
||||
this.codemirror = CodeMirror.fromTextArea(this.$refs.theTextarea, config)
|
||||
this.codemirror.getDoc().setValue(this.field.value)
|
||||
this.codemirror.setSize('100%', this.field.height)
|
||||
},
|
||||
}
|
||||
</script>
|
||||
9
nova/resources/js/components/Detail/CurrencyField.vue
Executable file
9
nova/resources/js/components/Detail/CurrencyField.vue
Executable file
@@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<panel-item :field="field" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
}
|
||||
</script>
|
||||
24
nova/resources/js/components/Detail/DateField.vue
Executable file
24
nova/resources/js/components/Detail/DateField.vue
Executable file
@@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<panel-item :field="field">
|
||||
<template slot="value">
|
||||
<p v-if="field.value" class="text-90">{{ formattedDate }}</p>
|
||||
<p v-else>—</p>
|
||||
</template>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
|
||||
computed: {
|
||||
formattedDate() {
|
||||
if (this.field.format) {
|
||||
return moment(this.field.value).format(this.field.format)
|
||||
}
|
||||
|
||||
return this.field.value
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
27
nova/resources/js/components/Detail/DateTimeField.vue
Executable file
27
nova/resources/js/components/Detail/DateTimeField.vue
Executable file
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<panel-item :field="field">
|
||||
<template slot="value">
|
||||
<p v-if="field.value" class="text-90">{{ localizedDateTime }}</p>
|
||||
<p v-else>—</p>
|
||||
</template>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { InteractsWithDates } from 'laravel-nova'
|
||||
|
||||
export default {
|
||||
mixins: [InteractsWithDates],
|
||||
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
|
||||
computed: {
|
||||
/**
|
||||
* Get the localized date time.
|
||||
*/
|
||||
localizedDateTime() {
|
||||
return this.localizeDateTimeField(this.field)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
101
nova/resources/js/components/Detail/FileField.vue
Executable file
101
nova/resources/js/components/Detail/FileField.vue
Executable file
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<panel-item :field="field">
|
||||
<div slot="value">
|
||||
<template v-if="shouldShowLoader">
|
||||
<ImageLoader
|
||||
:src="imageUrl"
|
||||
:maxWidth="maxWidth"
|
||||
:rounded="rounded"
|
||||
@missing="value => (missing = value)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-if="field.value && !imageUrl">
|
||||
<span class="break-words">{{ field.value }}</span>
|
||||
</template>
|
||||
|
||||
<span v-if="!field.value && !imageUrl">—</span>
|
||||
|
||||
<p v-if="shouldShowToolbar" class="flex items-center text-sm mt-3">
|
||||
<a
|
||||
v-if="field.downloadable"
|
||||
:dusk="field.attribute + '-download-link'"
|
||||
@keydown.enter.prevent="download"
|
||||
@click.prevent="download"
|
||||
tabindex="0"
|
||||
class="cursor-pointer dim btn btn-link text-primary inline-flex items-center"
|
||||
>
|
||||
<icon
|
||||
class="mr-2"
|
||||
type="download"
|
||||
view-box="0 0 24 24"
|
||||
width="16"
|
||||
height="16"
|
||||
/>
|
||||
<span class="class mt-1">{{ __('Download') }}</span>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ImageLoader from '@/components/ImageLoader'
|
||||
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
|
||||
components: { ImageLoader },
|
||||
|
||||
data: () => ({ missing: false }),
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Download the linked file
|
||||
*/
|
||||
download() {
|
||||
const { resourceName, resourceId } = this
|
||||
const attribute = this.field.attribute
|
||||
|
||||
let link = document.createElement('a')
|
||||
link.href = `/nova-api/${resourceName}/${resourceId}/download/${attribute}`
|
||||
link.download = 'download'
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
hasValue() {
|
||||
return (
|
||||
Boolean(this.field.value || this.imageUrl) && !Boolean(this.missing)
|
||||
)
|
||||
},
|
||||
|
||||
shouldShowLoader() {
|
||||
return Boolean(this.imageUrl)
|
||||
},
|
||||
|
||||
shouldShowToolbar() {
|
||||
return Boolean(this.field.downloadable && this.hasValue)
|
||||
},
|
||||
|
||||
imageUrl() {
|
||||
return this.field.previewUrl || this.field.thumbnailUrl
|
||||
},
|
||||
|
||||
rounded() {
|
||||
return this.field.rounded
|
||||
},
|
||||
|
||||
maxWidth() {
|
||||
return this.field.maxWidth || 320
|
||||
},
|
||||
|
||||
isVaporField() {
|
||||
return this.field.component == 'vapor-file-field'
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
29
nova/resources/js/components/Detail/HasManyField.vue
Executable file
29
nova/resources/js/components/Detail/HasManyField.vue
Executable file
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<resource-index
|
||||
:field="field"
|
||||
:resource-name="field.resourceName"
|
||||
:via-resource="resourceName"
|
||||
:via-resource-id="resourceId"
|
||||
:via-relationship="field.hasManyRelationship"
|
||||
:relationship-type="'hasMany'"
|
||||
@actionExecuted="actionExecuted"
|
||||
:load-cards="false"
|
||||
:initialPerPage="field.perPage || 5"
|
||||
:should-override-meta="false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resourceName', 'resourceId', 'resource', 'field'],
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Handle the actionExecuted event and pass it up the chain.
|
||||
*/
|
||||
actionExecuted() {
|
||||
this.$emit('actionExecuted')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
29
nova/resources/js/components/Detail/HasManyThroughField.vue
Executable file
29
nova/resources/js/components/Detail/HasManyThroughField.vue
Executable file
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<resource-index
|
||||
:field="field"
|
||||
:resource-name="field.resourceName"
|
||||
:via-resource="resourceName"
|
||||
:via-resource-id="resourceId"
|
||||
:via-relationship="field.hasManyThroughRelationship"
|
||||
:relationship-type="'hasManyThrough'"
|
||||
@actionExecuted="actionExecuted"
|
||||
:load-cards="false"
|
||||
:initialPerPage="field.perPage || 5"
|
||||
:should-override-meta="false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resourceName', 'resourceId', 'resource', 'field'],
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Handle the actionExecuted event and pass it up the chain.
|
||||
*/
|
||||
actionExecuted() {
|
||||
this.$emit('actionExecuted')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
29
nova/resources/js/components/Detail/HasOneField.vue
Executable file
29
nova/resources/js/components/Detail/HasOneField.vue
Executable file
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<resource-index
|
||||
:field="field"
|
||||
:resource-name="field.resourceName"
|
||||
:via-resource="resourceName"
|
||||
:via-resource-id="resourceId"
|
||||
:via-relationship="field.hasOneRelationship"
|
||||
:relationship-type="'hasOne'"
|
||||
@actionExecuted="actionExecuted"
|
||||
:load-cards="false"
|
||||
:disable-pagination="true"
|
||||
:should-override-meta="false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resourceName', 'resourceId', 'resource', 'field'],
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Handle the actionExecuted event and pass it up the chain.
|
||||
*/
|
||||
actionExecuted() {
|
||||
this.$emit('actionExecuted')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
29
nova/resources/js/components/Detail/HasOneThroughField.vue
Executable file
29
nova/resources/js/components/Detail/HasOneThroughField.vue
Executable file
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<resource-index
|
||||
:field="field"
|
||||
:resource-name="field.resourceName"
|
||||
:via-resource="resourceName"
|
||||
:via-resource-id="resourceId"
|
||||
:via-relationship="field.hasOneThroughRelationship"
|
||||
:relationship-type="'hasOneThrough'"
|
||||
@actionExecuted="actionExecuted"
|
||||
:load-cards="false"
|
||||
:disable-pagination="true"
|
||||
:should-override-meta="false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resourceName', 'resourceId', 'resource', 'field'],
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Handle the actionExecuted event and pass it up the chain.
|
||||
*/
|
||||
actionExecuted() {
|
||||
this.$emit('actionExecuted')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
40
nova/resources/js/components/Detail/HeadingField.vue
Executable file
40
nova/resources/js/components/Detail/HeadingField.vue
Executable file
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div class="bg-20 flex border-b border-t border-40 -mx-6 -my-px px-2">
|
||||
<div class="w-full py-4 px-4">
|
||||
<slot name="value">
|
||||
<p v-if="fieldValue && !shouldDisplayAsHtml" class="text-90">
|
||||
{{ fieldValue }}
|
||||
</p>
|
||||
<div
|
||||
v-else-if="fieldValue && shouldDisplayAsHtml"
|
||||
v-html="field.value"
|
||||
></div>
|
||||
<p v-else>—</p>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
|
||||
computed: {
|
||||
fieldValue() {
|
||||
if (
|
||||
this.field.value === '' ||
|
||||
this.field.value === null ||
|
||||
this.field.value === undefined
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
return String(this.field.value)
|
||||
},
|
||||
|
||||
shouldDisplayAsHtml() {
|
||||
return this.field.asHtml
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
9
nova/resources/js/components/Detail/HiddenField.vue
Executable file
9
nova/resources/js/components/Detail/HiddenField.vue
Executable file
@@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<div class="hidden" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
}
|
||||
</script>
|
||||
46
nova/resources/js/components/Detail/KeyValueField.vue
Executable file
46
nova/resources/js/components/Detail/KeyValueField.vue
Executable file
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<panel-item :field="field">
|
||||
<template slot="value">
|
||||
<KeyValueTable
|
||||
v-if="theData.length > 0"
|
||||
:edit-mode="false"
|
||||
class="overflow-hidden"
|
||||
>
|
||||
<KeyValueHeader
|
||||
:key-label="field.keyLabel"
|
||||
:value-label="field.valueLabel"
|
||||
/>
|
||||
|
||||
<div class="bg-white overflow-hidden key-value-items">
|
||||
<KeyValueItem
|
||||
v-for="item in theData"
|
||||
:item="item"
|
||||
:disabled="true"
|
||||
:key="item.key"
|
||||
/>
|
||||
</div>
|
||||
</KeyValueTable>
|
||||
</template>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import KeyValueItem from '@/components/Form/KeyValueField/KeyValueItem'
|
||||
import KeyValueHeader from '@/components/Form/KeyValueField/KeyValueHeader'
|
||||
import KeyValueTable from '@/components/Form/KeyValueField/KeyValueTable'
|
||||
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
|
||||
components: { KeyValueTable, KeyValueHeader, KeyValueItem },
|
||||
|
||||
data: () => ({ theData: [] }),
|
||||
|
||||
created() {
|
||||
this.theData = _.map(this.field.value || {}, (value, key) => ({
|
||||
key,
|
||||
value,
|
||||
}))
|
||||
},
|
||||
}
|
||||
</script>
|
||||
21
nova/resources/js/components/Detail/MarkdownField.vue
Executable file
21
nova/resources/js/components/Detail/MarkdownField.vue
Executable file
@@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<panel-item :field="field">
|
||||
<template slot="value">
|
||||
<excerpt :content="excerpt" :should-show="field.shouldShow" />
|
||||
</template>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const md = require('markdown-it')()
|
||||
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
|
||||
computed: {
|
||||
excerpt() {
|
||||
return md.render(this.field.value || '')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
32
nova/resources/js/components/Detail/MorphToActionTargetField.vue
Executable file
32
nova/resources/js/components/Detail/MorphToActionTargetField.vue
Executable file
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<panel-item :field="field">
|
||||
<template slot="value">
|
||||
<router-link
|
||||
v-if="field.viewable && field.value"
|
||||
:to="{
|
||||
name: 'detail',
|
||||
params: {
|
||||
resourceName: field.resourceName,
|
||||
resourceId: field.morphToId,
|
||||
},
|
||||
}"
|
||||
class="no-underline font-bold dim text-primary"
|
||||
>
|
||||
{{ field.name }}: {{ field.value }} ({{ field.resourceLabel }})
|
||||
</router-link>
|
||||
<p v-else-if="field.value && field.resourceLabel === null">
|
||||
{{ field.morphToType }}: {{ field.value }}
|
||||
</p>
|
||||
<p v-else-if="field.value && field.resourceLabel !== null">
|
||||
{{ field.value }}
|
||||
</p>
|
||||
<p v-else>—</p>
|
||||
</template>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resourceName', 'resourceId', 'field'],
|
||||
}
|
||||
</script>
|
||||
32
nova/resources/js/components/Detail/MorphToField.vue
Executable file
32
nova/resources/js/components/Detail/MorphToField.vue
Executable file
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<panel-item :field="field" :field-name="field.resourceLabel">
|
||||
<template slot="value">
|
||||
<router-link
|
||||
v-if="field.viewable && field.value"
|
||||
:to="{
|
||||
name: 'detail',
|
||||
params: {
|
||||
resourceName: field.resourceName,
|
||||
resourceId: field.morphToId,
|
||||
},
|
||||
}"
|
||||
class="no-underline font-bold dim text-primary"
|
||||
>
|
||||
{{ field.value }}
|
||||
</router-link>
|
||||
<p v-else-if="field.value && field.resourceLabel === null">
|
||||
{{ field.morphToType }}: {{ field.value }}
|
||||
</p>
|
||||
<p v-else-if="field.value && field.resourceLabel !== null">
|
||||
{{ field.value }}
|
||||
</p>
|
||||
<p v-else>—</p>
|
||||
</template>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resourceName', 'resourceId', 'field'],
|
||||
}
|
||||
</script>
|
||||
29
nova/resources/js/components/Detail/MorphToManyField.vue
Executable file
29
nova/resources/js/components/Detail/MorphToManyField.vue
Executable file
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<resource-index
|
||||
:field="field"
|
||||
:resource-name="field.resourceName"
|
||||
:via-resource="resourceName"
|
||||
:via-resource-id="resourceId"
|
||||
:via-relationship="field.morphToManyRelationship"
|
||||
:relationship-type="'morphToMany'"
|
||||
@actionExecuted="actionExecuted"
|
||||
:load-cards="false"
|
||||
:initialPerPage="field.perPage || 5"
|
||||
:should-override-meta="false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resourceName', 'resourceId', 'resource', 'field'],
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Handle the actionExecuted event and pass it up the chain.
|
||||
*/
|
||||
actionExecuted() {
|
||||
this.$emit('actionExecuted')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
89
nova/resources/js/components/Detail/Panel.vue
Executable file
89
nova/resources/js/components/Detail/Panel.vue
Executable file
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<div>
|
||||
<slot>
|
||||
<heading :level="1" :class="panel.helpText ? 'mb-2' : 'mb-3'">{{
|
||||
panel.name
|
||||
}}</heading>
|
||||
|
||||
<p
|
||||
v-if="panel.helpText"
|
||||
class="text-80 text-sm font-semibold italic mb-3"
|
||||
v-html="panel.helpText"
|
||||
></p>
|
||||
</slot>
|
||||
|
||||
<card class="mb-6 py-3 px-6">
|
||||
<component
|
||||
:class="{
|
||||
'remove-bottom-border': index == panel.fields.length - 1,
|
||||
}"
|
||||
:key="index"
|
||||
v-for="(field, index) in fields"
|
||||
:is="resolveComponentName(field)"
|
||||
:resource-name="resourceName"
|
||||
:resource-id="resourceId"
|
||||
:resource="resource"
|
||||
:field="field"
|
||||
@actionExecuted="actionExecuted"
|
||||
/>
|
||||
|
||||
<div
|
||||
v-if="shouldShowShowAllFieldsButton"
|
||||
class="bg-20 -mt-px -mx-6 -mb-6 border-t border-40 p-3 text-center rounded-b text-center"
|
||||
>
|
||||
<button
|
||||
class="block w-full dim text-sm text-80 font-bold"
|
||||
@click="showAllFields"
|
||||
>
|
||||
{{ __('Show All Fields') }}
|
||||
</button>
|
||||
</div>
|
||||
</card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BehavesAsPanel } from 'laravel-nova'
|
||||
|
||||
export default {
|
||||
mixins: [BehavesAsPanel],
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Resolve the component name.
|
||||
*/
|
||||
resolveComponentName(field) {
|
||||
return field.prefixComponent
|
||||
? 'detail-' + field.component
|
||||
: field.component
|
||||
},
|
||||
|
||||
/**
|
||||
* Show all of the Panel's fields.
|
||||
*/
|
||||
showAllFields() {
|
||||
return (this.panel.limit = 0)
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
/**
|
||||
* Limits the visible fields.
|
||||
*/
|
||||
fields() {
|
||||
if (this.panel.limit > 0) {
|
||||
return this.panel.fields.slice(0, this.panel.limit)
|
||||
}
|
||||
|
||||
return this.panel.fields
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if should display the 'Show all fields' button.
|
||||
*/
|
||||
shouldShowShowAllFieldsButton() {
|
||||
return this.panel.limit > 0
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
13
nova/resources/js/components/Detail/PasswordField.vue
Executable file
13
nova/resources/js/components/Detail/PasswordField.vue
Executable file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<panel-item :field="field">
|
||||
<p slot="value" class="text-90">
|
||||
·········
|
||||
</p>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
}
|
||||
</script>
|
||||
24
nova/resources/js/components/Detail/RelationshipPanel.vue
Executable file
24
nova/resources/js/components/Detail/RelationshipPanel.vue
Executable file
@@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- <h4 class="text-90 font-normal text-2xl mb-3">{{ panel.name }}</h4> -->
|
||||
|
||||
<div :key="field + resourceId" v-for="field in panel.fields">
|
||||
<component
|
||||
:is="'detail-' + field.component"
|
||||
:resource-name="resourceName"
|
||||
:resource-id="resourceId"
|
||||
:resource="resource"
|
||||
:field="field"
|
||||
@actionExecuted="actionExecuted"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BehavesAsPanel } from 'laravel-nova'
|
||||
|
||||
export default {
|
||||
mixins: [BehavesAsPanel],
|
||||
}
|
||||
</script>
|
||||
91
nova/resources/js/components/Detail/SparklineField.vue
Executable file
91
nova/resources/js/components/Detail/SparklineField.vue
Executable file
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<panel-item :field="field">
|
||||
<template slot="value">
|
||||
<div
|
||||
ref="chart"
|
||||
class="ct-chart"
|
||||
:style="{ width: chartWidth, height: chartHeight }"
|
||||
/>
|
||||
</template>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Chartist from 'chartist'
|
||||
import 'chartist/dist/chartist.min.css'
|
||||
|
||||
// Default chart diameters.
|
||||
const defaultHeight = 120
|
||||
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
|
||||
data: () => ({ chartist: null }),
|
||||
|
||||
watch: {
|
||||
'field.data': function (newData, oldData) {
|
||||
this.renderChart()
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
renderChart() {
|
||||
this.chartist.update(this.field.data)
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.chartist = new Chartist[this.chartStyle](
|
||||
this.$refs.chart,
|
||||
{ series: [this.field.data] },
|
||||
{
|
||||
height: this.chartHeight,
|
||||
width: this.chartWidth,
|
||||
showPoint: false,
|
||||
fullWidth: true,
|
||||
chartPadding: { top: 0, right: 0, bottom: 0, left: 0 },
|
||||
axisX: { showGrid: false, showLabel: false, offset: 0 },
|
||||
axisY: { showGrid: false, showLabel: false, offset: 0 },
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
computed: {
|
||||
/**
|
||||
* Determine if the field has a value other than null.
|
||||
*/
|
||||
hasData() {
|
||||
return this.field.data.length > 0
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine the chart style.
|
||||
*/
|
||||
chartStyle() {
|
||||
const validTypes = ['line', 'bar']
|
||||
let chartStyle = this.field.chartStyle.toLowerCase()
|
||||
|
||||
// Line and Bar are the only valid types.
|
||||
if (!validTypes.includes(chartStyle)) return 'Line'
|
||||
|
||||
return chartStyle.charAt(0).toUpperCase() + chartStyle.slice(1)
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine the chart height.
|
||||
*/
|
||||
chartHeight() {
|
||||
if (this.field.height) return `${this.field.height}px`
|
||||
|
||||
return `${defaultHeight}px`
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine the chart width.
|
||||
*/
|
||||
chartWidth() {
|
||||
if (this.field.width) return `${this.field.width}px`
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
34
nova/resources/js/components/Detail/StackField.vue
Executable file
34
nova/resources/js/components/Detail/StackField.vue
Executable file
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<panel-item :field="field">
|
||||
<div slot="value" :class="`text-${field.textAlign}`">
|
||||
<template v-if="hasValue">
|
||||
<div class="leading-normal">
|
||||
<component
|
||||
v-for="line in field.lines"
|
||||
:key="line.value"
|
||||
:class="line.classes"
|
||||
:is="`index-${line.component}`"
|
||||
:field="line"
|
||||
:resourceName="resourceName"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<p v-else>—</p>
|
||||
</div>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
|
||||
computed: {
|
||||
/**
|
||||
* Determine if the field has a value other than null.
|
||||
*/
|
||||
hasValue() {
|
||||
return this.field.lines
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
38
nova/resources/js/components/Detail/StatusField.vue
Executable file
38
nova/resources/js/components/Detail/StatusField.vue
Executable file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<div class="flex border-b border-40">
|
||||
<div class="w-1/4 py-4">
|
||||
<slot>
|
||||
<h4 class="font-normal text-80">{{ field.name }}</h4>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="w-3/4 py-4">
|
||||
<slot name="value">
|
||||
<div class="flex items-center">
|
||||
<span
|
||||
class="mr-3 text-60"
|
||||
v-if="field.loadingWords.includes(field.value)"
|
||||
>
|
||||
<loader width="30" />
|
||||
</span>
|
||||
|
||||
<p
|
||||
v-if="field.value"
|
||||
class="text-90"
|
||||
:class="{
|
||||
'text-danger': field.failedWords.includes(field.value),
|
||||
}"
|
||||
>
|
||||
{{ field.value }}
|
||||
</p>
|
||||
<p v-else>—</p>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
}
|
||||
</script>
|
||||
9
nova/resources/js/components/Detail/TextField.vue
Executable file
9
nova/resources/js/components/Detail/TextField.vue
Executable file
@@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<panel-item :field="field" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
}
|
||||
</script>
|
||||
17
nova/resources/js/components/Detail/TextareaField.vue
Executable file
17
nova/resources/js/components/Detail/TextareaField.vue
Executable file
@@ -0,0 +1,17 @@
|
||||
<template>
|
||||
<panel-item :field="field">
|
||||
<template slot="value">
|
||||
<excerpt
|
||||
:content="field.value"
|
||||
:plain-text="true"
|
||||
:should-show="field.shouldShow"
|
||||
/>
|
||||
</template>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
}
|
||||
</script>
|
||||
13
nova/resources/js/components/Detail/TrixField.vue
Executable file
13
nova/resources/js/components/Detail/TrixField.vue
Executable file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<panel-item :field="field">
|
||||
<template slot="value">
|
||||
<excerpt :content="field.value" :should-show="field.shouldShow" />
|
||||
</template>
|
||||
</panel-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user