diff --git a/zero.Api/Endpoints/Media/Maps/MediaBasic.cs b/zero.Api/Endpoints/Media/Maps/MediaBasic.cs index 19e12b90..948804cd 100644 --- a/zero.Api/Endpoints/Media/Maps/MediaBasic.cs +++ b/zero.Api/Endpoints/Media/Maps/MediaBasic.cs @@ -8,7 +8,9 @@ public class MediaBasic : ZeroIdEntity public bool IsFolder { get; set; } - public string Image { get; set; } + public string Source { get; set; } + + public string Preview { get; set; } public int Children { get; set; } diff --git a/zero.Api/Endpoints/Media/Maps/MediaMapperProfile.cs b/zero.Api/Endpoints/Media/Maps/MediaMapperProfile.cs index 9946192d..eb459283 100644 --- a/zero.Api/Endpoints/Media/Maps/MediaMapperProfile.cs +++ b/zero.Api/Endpoints/Media/Maps/MediaMapperProfile.cs @@ -30,10 +30,15 @@ public class MediaMapperProfile : ZeroMapperProfile target.Children = 0; target.Size = source.Size; + if (source.Path.HasValue()) + { + target.Source = FileSystem.MapToPublicPath(source.Path); + } + if (source.ImageMeta != null && source.ImageMeta.Thumbnails.Any()) { string path = source.ImageMeta.Thumbnails.GetValueOrDefault("preview"); - target.Image = path.IsNullOrEmpty() ? null : FileSystem.MapToPublicPath(path); + target.Preview = path.IsNullOrEmpty() ? null : FileSystem.MapToPublicPath(path); } } diff --git a/zero.Backoffice.UI/app/components/ui-datagrid.vue b/zero.Backoffice.UI/app/components/ui-datagrid.vue index bd00e730..67b08769 100644 --- a/zero.Backoffice.UI/app/components/ui-datagrid.vue +++ b/zero.Backoffice.UI/app/components/ui-datagrid.vue @@ -55,7 +55,11 @@ // for block items block: false, // ability to select items - selectable: false + selectable: false, + // whether the query params should be set for page + search + setQuery: true, + // custom scroll container + scrollContainerSelector: null }; export default { @@ -167,7 +171,7 @@ if (!initial && this.configuration.scrollToTop) { - let container = document.querySelector('.app-main'); + let container = document.querySelector(this.configuration.scrollContainerSelector || '.app-main'); if (container) { @@ -227,21 +231,24 @@ // a property has changed and therefore we update the URL and table content onChange() { - let params = {}; - - if (+this.filter.page > 1) + if (this.configuration.setQuery) { - params.page = +this.filter.page; - } - if (this.filter.search) - { - params.search = this.filter.search; - } + let params = {}; - const query = Qs.stringify(params); - const path = this.$route.href.split('?')[0] + (query ? '?' + query : ''); + if (+this.filter.page > 1) + { + params.page = +this.filter.page; + } + if (this.filter.search) + { + params.search = this.filter.search; + } - history.replaceState(null, null, path); + const query = Qs.stringify(params); + const path = this.$route.href.split('?')[0] + (query ? '?' + query : ''); + + history.replaceState(null, null, path); + } this.debouncedUpdate(); }, diff --git a/zero.Backoffice.UI/app/modules/media/components/field-imagepicker.vue b/zero.Backoffice.UI/app/modules/media/components/field-imagepicker.vue new file mode 100644 index 00000000..ac08b662 --- /dev/null +++ b/zero.Backoffice.UI/app/modules/media/components/field-imagepicker.vue @@ -0,0 +1,36 @@ + + + + \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/media/components/field-mediapicker.vue b/zero.Backoffice.UI/app/modules/media/components/field-mediapicker.vue new file mode 100644 index 00000000..808dbded --- /dev/null +++ b/zero.Backoffice.UI/app/modules/media/components/field-mediapicker.vue @@ -0,0 +1,40 @@ + + + + \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/media/components/media-previews.vue b/zero.Backoffice.UI/app/modules/media/components/media-previews.vue new file mode 100644 index 00000000..4d0d4d0f --- /dev/null +++ b/zero.Backoffice.UI/app/modules/media/components/media-previews.vue @@ -0,0 +1,165 @@ + + + + + + + \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/media/components/ui-mediapicker.vue b/zero.Backoffice.UI/app/modules/media/components/ui-mediapicker.vue new file mode 100644 index 00000000..76ee0279 --- /dev/null +++ b/zero.Backoffice.UI/app/modules/media/components/ui-mediapicker.vue @@ -0,0 +1,182 @@ + + + + + + \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/media/overlays/media.vue b/zero.Backoffice.UI/app/modules/media/overlays/media.vue new file mode 100644 index 00000000..ac27f503 --- /dev/null +++ b/zero.Backoffice.UI/app/modules/media/overlays/media.vue @@ -0,0 +1,194 @@ + + + + + + \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/media/pages/overview/overview-item.vue b/zero.Backoffice.UI/app/modules/media/pages/overview/overview-item.vue index c5ec1242..e652df45 100644 --- a/zero.Backoffice.UI/app/modules/media/pages/overview/overview-item.vue +++ b/zero.Backoffice.UI/app/modules/media/pages/overview/overview-item.vue @@ -1,10 +1,10 @@  @@ -106,6 +106,7 @@ methods: { + async getItems(query) { if (!query) @@ -129,6 +130,17 @@ }, + getLink(item) + { + if (item.isFolder) + { + return { name: 'media', params: { parentId: item.id } }; + } + + return { name: 'media-edit', params: { id: item.id } }; + }, + + onSelected(selection) { this.selected = selection; diff --git a/zero.Backoffice.UI/app/modules/media/plugin.ts b/zero.Backoffice.UI/app/modules/media/plugin.ts index f092c3cb..b53aa60e 100644 --- a/zero.Backoffice.UI/app/modules/media/plugin.ts +++ b/zero.Backoffice.UI/app/modules/media/plugin.ts @@ -6,7 +6,10 @@ export default { install(app: ZeroPluginOptions) { - //app.vue.component('ui-countrypicker', defineAsyncComponent(() => import('./ui-countrypicker.vue'))); + app.vue.component('ui-mediapicker', defineAsyncComponent(() => import('./components/ui-mediapicker.vue'))); + + app.fieldType('media', defineAsyncComponent(() => import('./components/field-mediapicker.vue'))); + app.fieldType('image', defineAsyncComponent(() => import('./components/field-imagepicker.vue'))); app.route({ name: 'media', path: '/media/:parentId?', component: () => import('./pages/overview/overview.vue'), props: true }); app.route({ name: 'media-edit', path: '/media/edit/:id?', component: () => import('./pages/detail/detail.vue'), props: true }); @@ -14,4 +17,37 @@ export default { //app.schema('countries', () => import('./schemas/list')); app.schema('media:edit', () => import('./schemas/editor')); } -} as ZeroPlugin; \ No newline at end of file +} as ZeroPlugin; + + +declare module 'zero/schemas' +{ + export interface ZeroEditorField + { + /** + * Renders a media picker + * @param {MediaFieldOptions} [options] - Custom options + */ + media(options?: MediaFieldOptions): ZeroEditorField; + + /** + * Renders an image picker + * @param {MediaBaseFieldOptions} [options] - Custom options + */ + image(options?: MediaBaseFieldOptions): ZeroEditorField; + } + + export type MediaTypeFor = 'all' | 'images' | 'videos' | 'documents'; + + export interface MediaBaseFieldOptions extends PickerFieldOptions + { + disableSelect?: boolean; + disableUpload?: boolean; + fileExtensions?: Array; + } + + export interface MediaFieldOptions extends MediaBaseFieldOptions + { + for?: MediaTypeFor; + } +} \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/media/ui-countrypicker.vue b/zero.Backoffice.UI/app/modules/media/ui-countrypicker.vue deleted file mode 100644 index 34356f88..00000000 --- a/zero.Backoffice.UI/app/modules/media/ui-countrypicker.vue +++ /dev/null @@ -1,61 +0,0 @@ - - - - \ No newline at end of file diff --git a/zero.Backoffice.UI/app/modules/settings/demo.ts b/zero.Backoffice.UI/app/modules/settings/demo.ts index e4364e10..de7df2a1 100644 --- a/zero.Backoffice.UI/app/modules/settings/demo.ts +++ b/zero.Backoffice.UI/app/modules/settings/demo.ts @@ -6,6 +6,8 @@ const editor = new ZeroEditor('demo'); editor.field('name', { label: 'Text' }).text({ maxLength: 120 }); editor.field('isActive', { label: 'Toggle', horizontal: true }).toggle(); +editor.field('images', { label: 'Images' }).image({ limit: 4 }); +editor.field('docs', { label: 'Documents' }).media({ limit: 1 }); editor.field('number', { label: 'Number' }).number(); editor.field('output', { label: 'Number' }).output(); editor.field('rte', { label: 'Number' }).rte(); diff --git a/zero.Backoffice.UI/app/modules/settings/demo.vue b/zero.Backoffice.UI/app/modules/settings/demo.vue index 4eada026..40dad0e9 100644 --- a/zero.Backoffice.UI/app/modules/settings/demo.vue +++ b/zero.Backoffice.UI/app/modules/settings/demo.vue @@ -19,7 +19,9 @@ output: 'This is an output', rte: '', textarea: 'A textarea\nfor you', - state: 'red' + state: 'red', + images: ['media.zpkxfjkgciom', 'media.w2cntwlrcueb', 'media.1waxp46ho8hu'], + docs: null }, route: 'demo', disabled: false diff --git a/zero.Core/Media/MediaFileSystem.cs b/zero.Core/Media/MediaFileSystem.cs index 05fdecb4..2d0e5294 100644 --- a/zero.Core/Media/MediaFileSystem.cs +++ b/zero.Core/Media/MediaFileSystem.cs @@ -14,6 +14,10 @@ public class MediaFileSystem : PhysicalFileSystem, IMediaFileSystem /// public override string MapToPublicPath(string path) { + if (path.IsNullOrEmpty()) + { + return null; + } return PublicPathPrefix + path.TrimStart('/'); } }