]> _ Git - odl.git/commitdiff
WIP #4822 @8
authorStephen Cameron <stephen@cubedesigners.com>
Tue, 16 Nov 2021 20:35:41 +0000 (21:35 +0100)
committerStephen Cameron <stephen@cubedesigners.com>
Tue, 16 Nov 2021 20:35:41 +0000 (21:35 +0100)
package-lock.json
package.json
resources/js/media-library.js
resources/views/components/close.blade.php [new file with mode: 0644]
resources/views/components/media-library/filter-interface.blade.php [new file with mode: 0644]
resources/views/components/media-library/filter-list.blade.php [new file with mode: 0644]
resources/views/components/media-library/index.blade.php [new file with mode: 0644]
resources/views/components/media-library/player.blade.php [new file with mode: 0644]
resources/views/front/media-library.blade.php
resources/views/layouts/app.blade.php
webpack.mix.js

index 02f668802cc1fa3e1474e8b96291a4bc619b1728..696a89c10827c08931405cd806377c410ba35688 100644 (file)
@@ -12,6 +12,7 @@
                 "isotope-layout": "^3.0.6",
                 "laravel-mix": "^6.0.6",
                 "lodash": "^4.17.19",
+                "plyr": "^3.6.9",
                 "postcss": "^8.3.10",
                 "postcss-import": "^14.0.2",
                 "tailwindcss": "^2.2.17"
             "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
             "dev": true
         },
+        "node_modules/core-js": {
+            "version": "3.19.1",
+            "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.1.tgz",
+            "integrity": "sha512-Tnc7E9iKd/b/ff7GFbhwPVzJzPztGrChB8X8GLqoYGdEOG8IpLnK1xPyo3ZoO3HsK6TodJS58VGPOxA+hLHQMg==",
+            "dev": true,
+            "hasInstallScript": true,
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/core-js"
+            }
+        },
         "node_modules/core-js-compat": {
             "version": "3.18.3",
             "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.18.3.tgz",
                 "node": ">=8.0.0"
             }
         },
+        "node_modules/custom-event-polyfill": {
+            "version": "1.0.7",
+            "resolved": "https://registry.npmjs.org/custom-event-polyfill/-/custom-event-polyfill-1.0.7.tgz",
+            "integrity": "sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==",
+            "dev": true
+        },
         "node_modules/debug": {
             "version": "4.3.2",
             "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
                 "json5": "lib/cli.js"
             }
         },
+        "node_modules/loadjs": {
+            "version": "4.2.0",
+            "resolved": "https://registry.npmjs.org/loadjs/-/loadjs-4.2.0.tgz",
+            "integrity": "sha512-AgQGZisAlTPbTEzrHPb6q+NYBMD+DP9uvGSIjSUM5uG+0jG15cb8axWpxuOIqrmQjn6scaaH8JwloiP27b2KXA==",
+            "dev": true
+        },
         "node_modules/locate-path": {
             "version": "5.0.0",
             "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
                 "node": ">=8"
             }
         },
+        "node_modules/plyr": {
+            "version": "3.6.9",
+            "resolved": "https://registry.npmjs.org/plyr/-/plyr-3.6.9.tgz",
+            "integrity": "sha512-KYi6o0799iw6yWZSmpZyx0tcrdNB+uGrUb/pskBjBzUax8fevzkqUx9A5vayYRBjlSme2UA8fHjTw3SMeHEvRA==",
+            "dev": true,
+            "dependencies": {
+                "core-js": "^3.10.1",
+                "custom-event-polyfill": "^1.0.7",
+                "loadjs": "^4.2.0",
+                "rangetouch": "^2.0.1",
+                "url-polyfill": "^1.1.12"
+            }
+        },
         "node_modules/portfinder": {
             "version": "1.0.28",
             "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
                 "node": ">= 0.6"
             }
         },
+        "node_modules/rangetouch": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/rangetouch/-/rangetouch-2.0.1.tgz",
+            "integrity": "sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA==",
+            "dev": true
+        },
         "node_modules/raw-body": {
             "version": "2.4.0",
             "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
                 "querystring": "0.2.0"
             }
         },
+        "node_modules/url-polyfill": {
+            "version": "1.1.12",
+            "resolved": "https://registry.npmjs.org/url-polyfill/-/url-polyfill-1.1.12.tgz",
+            "integrity": "sha512-mYFmBHCapZjtcNHW0MDq9967t+z4Dmg5CJ0KqysK3+ZbyoNOWQHksGCTWwDhxGXllkWlOc10Xfko6v4a3ucM6A==",
+            "dev": true
+        },
         "node_modules/url/node_modules/punycode": {
             "version": "1.3.2",
             "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
             "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
             "dev": true
         },
+        "core-js": {
+            "version": "3.19.1",
+            "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.1.tgz",
+            "integrity": "sha512-Tnc7E9iKd/b/ff7GFbhwPVzJzPztGrChB8X8GLqoYGdEOG8IpLnK1xPyo3ZoO3HsK6TodJS58VGPOxA+hLHQMg==",
+            "dev": true
+        },
         "core-js-compat": {
             "version": "3.18.3",
             "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.18.3.tgz",
                 "css-tree": "^1.1.2"
             }
         },
+        "custom-event-polyfill": {
+            "version": "1.0.7",
+            "resolved": "https://registry.npmjs.org/custom-event-polyfill/-/custom-event-polyfill-1.0.7.tgz",
+            "integrity": "sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==",
+            "dev": true
+        },
         "debug": {
             "version": "4.3.2",
             "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
                 }
             }
         },
+        "loadjs": {
+            "version": "4.2.0",
+            "resolved": "https://registry.npmjs.org/loadjs/-/loadjs-4.2.0.tgz",
+            "integrity": "sha512-AgQGZisAlTPbTEzrHPb6q+NYBMD+DP9uvGSIjSUM5uG+0jG15cb8axWpxuOIqrmQjn6scaaH8JwloiP27b2KXA==",
+            "dev": true
+        },
         "locate-path": {
             "version": "5.0.0",
             "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
                 "find-up": "^4.0.0"
             }
         },
+        "plyr": {
+            "version": "3.6.9",
+            "resolved": "https://registry.npmjs.org/plyr/-/plyr-3.6.9.tgz",
+            "integrity": "sha512-KYi6o0799iw6yWZSmpZyx0tcrdNB+uGrUb/pskBjBzUax8fevzkqUx9A5vayYRBjlSme2UA8fHjTw3SMeHEvRA==",
+            "dev": true,
+            "requires": {
+                "core-js": "^3.10.1",
+                "custom-event-polyfill": "^1.0.7",
+                "loadjs": "^4.2.0",
+                "rangetouch": "^2.0.1",
+                "url-polyfill": "^1.1.12"
+            }
+        },
         "portfinder": {
             "version": "1.0.28",
             "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
             "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
             "dev": true
         },
+        "rangetouch": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/rangetouch/-/rangetouch-2.0.1.tgz",
+            "integrity": "sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA==",
+            "dev": true
+        },
         "raw-body": {
             "version": "2.4.0",
             "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
                 }
             }
         },
+        "url-polyfill": {
+            "version": "1.1.12",
+            "resolved": "https://registry.npmjs.org/url-polyfill/-/url-polyfill-1.1.12.tgz",
+            "integrity": "sha512-mYFmBHCapZjtcNHW0MDq9967t+z4Dmg5CJ0KqysK3+ZbyoNOWQHksGCTWwDhxGXllkWlOc10Xfko6v4a3ucM6A==",
+            "dev": true
+        },
         "util": {
             "version": "0.11.1",
             "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
index 1d99dfd32287ca9604df430335250bc4536716ea..939c6e9fd1186314e2c3e40db628307cd17f3cc3 100644 (file)
@@ -17,6 +17,7 @@
         "isotope-layout": "^3.0.6",
         "laravel-mix": "^6.0.6",
         "lodash": "^4.17.19",
+        "plyr": "^3.6.9",
         "postcss": "^8.3.10",
         "postcss-import": "^14.0.2",
         "tailwindcss": "^2.2.17"
index 99418049739621cdc775c093b40d766235317ea0..49a1358a7955589edcf496903e9a110dd1c1df99 100644 (file)
@@ -1,11 +1,16 @@
 // Media Library functionality
 export default (options = {}) => ({
     filters: options.filters || {}, // Filters JSON array is passed in from HTML
-    gridSelector: options.gridSelector || false,
+    gridSelector: options.gridSelector || false, // CSS selector for main Isotope element
     filtersOpen: false,
     activeTypeFilters: [],
     activeThemeFilters: [],
     isotope: {},
+    playerOpen: false,
+    playerType: 'video', // Can be 'video' or 'audio'
+    playerSrc: '',
+    playerPoster: '',
+    playerMIME: '',
 
     get themeFilterList() {
         // Convert active theme filters array into class string for Isotope
diff --git a/resources/views/components/close.blade.php b/resources/views/components/close.blade.php
new file mode 100644 (file)
index 0000000..b473860
--- /dev/null
@@ -0,0 +1,11 @@
+{{-- Close --}}
+<a href="#" class="absolute top-8 right-8 flex" {{ $attributes }}>
+    <span class="mr-8">Fermer</span>
+
+    <svg class="stroke-current" xmlns="http://www.w3.org/2000/svg" width="33" height="26" viewBox="0 0 25.098 25.098">
+        <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
+            <path d="m1.414 23.683 22.27-22.27"/>
+            <path d="m1.414 1.414 22.27 22.27"/>
+        </g>
+    </svg>
+</a>
diff --git a/resources/views/components/media-library/filter-interface.blade.php b/resources/views/components/media-library/filter-interface.blade.php
new file mode 100644 (file)
index 0000000..a719053
--- /dev/null
@@ -0,0 +1,85 @@
+{{-- FILTER SELECTION INTERFACE (full screen overlay) --}}
+
+@aware(['types', 'themes'])
+
+<div class="filters-overlay
+            fixed top-0 left-0 w-screen h-screen
+            flex items-center
+            bg-blue text-white
+            px-30
+            z-20
+            transition ease-out-cubic duration-500"
+     x-show="filtersOpen"
+     x-transition:enter-start="opacity-0"
+     x-transition:enter-end="opacity-100"
+     x-transition:leave-start="opacity-100"
+     x-transition:leave-end="opacity-0"
+     x-cloak>
+
+    {{-- Close --}}
+    <x-close @click.prevent="filtersOpen = false" />
+
+    <div class="w-full">
+
+        <h2 class="text-6xl uppercase">Filtres</h2>
+
+        {{-- Filter Options --}}
+        <div class="flex mt-15">
+            {{-- Media Type Filters --}}
+            <div class="w-1/3">
+                <h3 class="font-medium text-4xl mb-5">Média</h3>
+                <div class="grid grid-cols-1 gap-5">
+                    @foreach($types as $type_id => $type)
+                        <label>
+                            <input type="checkbox"
+                                   value="media-{{ $type_id }}"
+                                   x-model="activeTypeFilters"
+                                   class="peer sr-only">
+                            <span class="inline-block cursor-pointer
+                                         font-secondary font-medium
+                                         py-2.5 px-5 rounded-full border
+                                         peer-checked:bg-white peer-checked:text-black
+                                         transition">
+                                    {{ $type }}
+                                </span>
+                        </label>
+                    @endforeach
+                </div>
+            </div>
+
+            {{-- Theme Filters --}}
+            <div class="w-2/3">
+                <h3 class="font-medium text-4xl mb-5">Thème</h3>
+                <div class="grid grid-cols-2 gap-5">
+                    @foreach($themes as $theme_id => $theme)
+                        <label>
+                            <input type="checkbox"
+                                   value="theme-{{ $theme_id }}"
+                                   x-model="activeThemeFilters"
+                                   class="peer sr-only">
+                            <span class="inline-block cursor-pointer
+                                         font-secondary font-medium
+                                         whitespace-nowrap
+                                         py-2.5 px-5 rounded-full border
+                                         peer-checked:bg-white peer-checked:text-black
+                                         transition">
+                                    {{ $theme }}
+                                </span>
+                        </label>
+                    @endforeach
+                </div>
+            </div>
+
+        </div>
+
+        <div class="text-right mt-20">
+            <button @click="filtersOpen = false"
+                    class="bg-blue-dark
+                           font-medium
+                           py-3 px-8 rounded-full">
+                Valider
+            </button>
+        </div>
+
+    </div>
+</div>
diff --git a/resources/views/components/media-library/filter-list.blade.php b/resources/views/components/media-library/filter-list.blade.php
new file mode 100644 (file)
index 0000000..9d20d45
--- /dev/null
@@ -0,0 +1,63 @@
+{{-- FILTERS --}}
+<div class="mt-10 space-x-2 space-y-2">
+
+    {{-- FILTER INTERFACE BUTTON --}}
+    <a @click.prevent="filtersOpen = true"
+       href="#"
+       class="inline-block py-4 px-6 rounded-full
+                      bg-black hover:bg-blue
+                      mt-2 {{-- Margin top added here so layout doesn't shift when last filter is removed --}}
+           border border-black hover:border-blue {{-- Needs border so it matches the height of filter buttons --}}
+           text-white font-secondary font-medium leading-none">
+        Filtrer
+    </a>
+
+    {{-- ACTIVE [MEDIA TYPE] FILTERS (JS) --}}
+    {{-- Media types must be filtered separately from themes --}}
+    <template x-for="activeTypeFilter in activeTypeFilters">
+        <div class="relative inline-flex
+                            py-4 pl-4 pr-12
+                            rounded-full border border-grey-200
+                            leading-none
+                            font-secondary font-medium text-black">
+            <span x-text="filters[activeTypeFilter]" class="whitespace-nowrap"></span>
+            {{-- REMOVE (X) ICON --}}
+            <a href="#"
+               @click.prevent="removeTypeFilter(activeTypeFilter)"
+               class="absolute w-7 h-7 right-2 top-1/2 transform -translate-y-1/2
+                              flex items-center justify-center
+                              rounded-full bg-grey-200 text-current">
+                <svg class="stroke-current" xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 10.828 10.828">
+                    <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
+                        <path d="m1.414 9.414 8-8"/>
+                        <path data-name="Path 46" d="m1.414 1.414 8 8"/>
+                    </g>
+                </svg>
+            </a>
+        </div>
+    </template>
+
+    {{-- ACTIVE [THEME] FILTERS (JS) --}}
+    <template x-for="activeThemeFilter in activeThemeFilters">
+        <div class="relative inline-flex
+                            py-4 pl-4 pr-12
+                            rounded-full border border-grey-200
+                            leading-none
+                            font-secondary font-medium text-black">
+            <span x-text="filters[activeThemeFilter]" class="whitespace-nowrap"></span>
+            {{-- REMOVE (X) ICON --}}
+            <a href="#"
+               @click.prevent="removeThemeFilter(activeThemeFilter)"
+               class="absolute w-7 h-7 right-2 top-1/2 transform -translate-y-1/2
+                              flex items-center justify-center
+                              rounded-full bg-grey-200 text-current">
+                <svg class="stroke-current" xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 10.828 10.828">
+                    <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
+                        <path d="m1.414 9.414 8-8"/>
+                        <path data-name="Path 46" d="m1.414 1.414 8 8"/>
+                    </g>
+                </svg>
+            </a>
+        </div>
+    </template>
+</div>
diff --git a/resources/views/components/media-library/index.blade.php b/resources/views/components/media-library/index.blade.php
new file mode 100644 (file)
index 0000000..1beda02
--- /dev/null
@@ -0,0 +1,81 @@
+{{-- Media Library widget --}}
+{{-- See alpine.js for setup and media-library.js for code --}}
+@php
+    // Set defaults in case data is empty
+    $types ??= [];
+    $themes ??= [];
+
+    // Format arrays for use on frontend
+    $media_filters = collect($types)->mapWithKeys(function($item, $key) {
+        return ["media-$key" => $item];
+    });
+    $theme_filters = collect($themes)->mapWithKeys(function($item, $key) {
+        return ["theme-$key" => $item];
+    });
+    $filters = array_merge($media_filters->toArray(), $theme_filters->toArray());
+
+@endphp
+
+@push('before_scripts')
+    <script src="{{ asset('js/isotope.js') }}"></script>
+@endpush
+
+{{-- See media_library() definition in resources/js/media-library.js --}}
+<div x-data="media_library({ gridSelector: '.media-grid', filters: {{ json_encode($filters) }} })">
+
+    <x-media-library.filter-list />
+
+    {{-- MEDIA LIBRARY GRID --}}
+    {{-- Negative margins applied here to offset margins used in Isotope grid --}}
+    <div class="media-grid mt-10 -mb-16 -mx-2.5">
+        @foreach ($media as $item)
+            <div @click="playerOpen = true;
+                         playerType = '{{ $item['type'] }}';
+                         playerSrc = '{{ $item['file'] }}';
+                         playerPoster = '{{ $item['image'] }}';
+                         playerMIME = '{{ $item['mime_type'] }}'"
+                 class="media-item
+                        {{-- Width is 25% minus the gutters (2 * 0.625rem that comes from mx-2.5) --}}
+                        float-left w-[calc(25%-1.25rem)] mx-2.5 mb-16
+                        media-{{ $item['type'] }}
+                        theme-{{ $item['theme']['id'] }}">
+                <div class="media-item-image relative bg-cover bg-no-repeat rounded-md pb-[56.25%]" style="background-image:url({{ $item['image'] }})">
+
+                    {{-- Play Icon --}}
+                    <svg class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"
+                         xmlns="http://www.w3.org/2000/svg" width="22.47%" viewBox="0 0 59.999 59.999">
+                        {{-- Icon BG --}}
+                        <path d="M0 29.999a30 30 0 1 0 30-30 30 30 0 0 0-30 30Z" fill="#0725e2"/>
+
+                        <g fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
+                            @if ($item['type'] === 'audio')
+                                {{-- Audio Play Icon --}}
+                                <path d="M15.999 25.324h5.324v9.317h-5.324Z"/>
+                                <path d="M35.321 24.635a7.561 7.561 0 0 1 0 10.693 7.523 7.523 0 0 0 0-10.693Z"/>
+                                <path d="M39.644 21.627a11.815 11.815 0 0 1 0 16.709 11.756 11.756 0 0 0 0-16.709Z"/>
+                                <path d="M21.323 25.324 30.64 20v19.966l-9.317-5.325Z"/>
+                            @else
+                                {{-- Video Play Icon --}}
+                                <path d="m26.5 38.5 12-8-12-8Z" />
+                            @endif
+                        </g>
+                    </svg>
+
+                    <x-duration class="absolute bottom-2 right-2 font-secondary text-white">{{ $item['duration'] }}</x-duration>
+                </div>
+                {{-- THEME LABEL --}}
+                <div class="mt-2.5 font-secondary font-medium text-xs leading-none" style="color:{{ $item['theme']['color'] }}">
+                    {{ $item['theme']['title'] }}
+                </div>
+                <div class="mt-1.5 font-semibold leading-snug">
+                    {{ $item['title'] }}
+                </div>
+            </div>
+        @endforeach
+    </div>
+
+    <x-media-library.player />
+
+    <x-media-library.filter-interface />
+
+</div>
diff --git a/resources/views/components/media-library/player.blade.php b/resources/views/components/media-library/player.blade.php
new file mode 100644 (file)
index 0000000..8beacd0
--- /dev/null
@@ -0,0 +1,47 @@
+{{-- MEDIA PLAYER (full screen overlay) --}}
+
+@push('before_css')
+    <link href="{{ asset('css/plyr.css') }}" rel="stylesheet">
+@endpush
+
+@push('before_scripts')
+    <script src="{{ asset('js/plyr.js') }}"></script>
+@endpush
+
+<div class="player-overlay
+            fixed top-0 left-0 w-screen h-screen
+            flex items-center
+            bg-white text-black
+            px-30
+            z-20
+            transition ease-out-cubic duration-500"
+     x-show="playerOpen"
+     x-transition:enter-start="opacity-0"
+     x-transition:enter-end="opacity-100"
+     x-transition:leave-start="opacity-100"
+     x-transition:leave-end="opacity-0"
+     x-cloak>
+
+    <x-close @click.prevent="playerOpen = false; playerType = '';" />
+
+    <div class="w-full">
+
+        <template x-if="playerType === 'video'">
+            <video class="w-full" x-init="plyr = new Plyr($el)"
+                   {{-- Must call load() on video when changing the source
+                   (ref: https://github.com/alpinejs/alpine/discussions/2180 --}}
+                   x-effect="() => playerSrc && $el.load()"
+                   playsinline autoplay controls :data-poster="playerPoster">
+                <source :src="playerSrc" :type="playerMIME">
+            </video>
+        </template>
+
+        <template x-if="playerType === 'audio'">
+            <audio id="player" controls autoplay>
+                <source :src="playerSrc" :type="playerMIME">
+            </audio>
+        </template>
+
+
+    </div>
+</div>
index 2c86c164ec730f5499865fa5f170040c7c920c00..16f5666202d7cf7ca2413aecff35b538b5dfed55 100644 (file)
@@ -10,7 +10,8 @@
                 'type' => 'video',
                 'duration' => '78',
                 'image' => 'https://odl.paris.cubedesigners.com/storage/46/conversions/VIDEO2-poster.jpg',
-                'file' => '#',
+                'file' => 'https://odl.paris.cubedesigners.com/storage/46/VIDEO2.mov',
+                'mime_type' => 'video/mp4',
                 'theme' => [
                     'id' => 1,
                     'title' => 'Gouvernance',
@@ -22,7 +23,8 @@
                 'type' => 'video',
                 'duration' => '192',
                 'image' => 'https://odl.paris.cubedesigners.com/storage/4/conversions/Big-rock-at-the-beach-poster.jpg',
-                'file' => '#',
+                'file' => 'https://odl.paris.cubedesigners.com/storage/4/Big-rock-at-the-beach.mp4',
+                'mime_type' => 'video/mp4',
                 'theme' => [
                     'id' => 2,
                     'title' => 'Communication',
@@ -34,7 +36,8 @@
                 'type' => 'video',
                 'duration' => '322',
                 'image' => 'https://odl.paris.cubedesigners.com/storage/46/conversions/VIDEO2-poster.jpg',
-                'file' => '#',
+                'file' => 'https://odl.paris.cubedesigners.com/storage/46/VIDEO2.mov',
+                'mime_type' => 'video/mp4',
                 'theme' => [
                     'id' => 3,
                     'title' => 'Organisation',
@@ -46,7 +49,8 @@
                 'type' => 'audio',
                 'duration' => '987',
                 'image' => 'https://odl.paris.cubedesigners.com/storage/4/conversions/Big-rock-at-the-beach-poster.jpg',
-                'file' => '#',
+                'file' => 'https://odl.paris.cubedesigners.com/storage/83/hs1mp3.mp3',
+                'mime_type' => 'audio/mpeg',
                 'theme' => [
                     'id' => 4,
                     'title' => 'Système d’information',
@@ -58,7 +62,8 @@
                 'type' => 'video',
                 'duration' => '414',
                 'image' => 'https://odl.paris.cubedesigners.com/storage/46/conversions/VIDEO2-poster.jpg',
-                'file' => '#',
+                'file' => 'https://odl.paris.cubedesigners.com/storage/46/VIDEO2.mov',
+                'mime_type' => 'video/mp4',
                 'theme' => [
                     'id' => 1,
                     'title' => 'Gouvernance',
@@ -70,7 +75,8 @@
                 'type' => 'audio',
                 'duration' => '45',
                 'image' => 'https://odl.paris.cubedesigners.com/storage/4/conversions/Big-rock-at-the-beach-poster.jpg',
-                'file' => '#',
+                'file' => 'https://odl.paris.cubedesigners.com/storage/83/hs1mp3.mp3',
+                'mime_type' => 'audio/mpeg',
                 'theme' => [
                     'id' => 2,
                     'title' => 'Communication',
             '4' => "Système d'information",
             '8' => "Conditions techniques",
         ];
-
-        // Format arrays for use on frontend
-        $media_filters = collect($media_types)->mapWithKeys(function($item, $key) {
-            return ["media-$key" => $item];
-        });
-        $theme_filters = collect($themes)->mapWithKeys(function($item, $key) {
-            return ["theme-$key" => $item];
-        });
-        $filters = array_merge($media_filters->toArray(), $theme_filters->toArray());
-
     @endphp
 
-    {{-- Media Library widget --}}
-    {{-- See alpine.js for setup and media-library.js for code --}}
-    <div x-data="media_library({ gridSelector: '.media-grid', filters: {{ json_encode($filters) }} })">
-
-        <h1 class="uppercase">Médiathèque</h1>
-
-        {{-- FILTERS --}}
-        <div class="mt-10 space-x-2 space-y-2">
-
-            {{-- FILTER INTERFACE BUTTON --}}
-            <a @click.prevent="filtersOpen = true"
-               href="#"
-               class="inline-block py-4 px-6 rounded-full
-                      bg-black hover:bg-blue
-                      mt-2 {{-- Margin top added here so layout doesn't shift when last filter is removed --}}
-                      border border-black hover:border-blue {{-- Needs border so it matches the height of filter buttons --}}
-                      text-white font-secondary font-medium leading-none">
-                Filtrer
-            </a>
-
-            {{-- ACTIVE [MEDIA TYPE] FILTERS (JS) --}}
-            {{-- Media types must be filtered separately from themes --}}
-            <template x-for="activeTypeFilter in activeTypeFilters">
-                <div class="relative inline-flex
-                            py-4 pl-4 pr-12
-                            rounded-full border border-grey-200
-                            leading-none
-                            font-secondary font-medium text-black">
-                    <span x-text="filters[activeTypeFilter]" class="whitespace-nowrap"></span>
-                    {{-- REMOVE (X) ICON --}}
-                    <a href="#"
-                       @click.prevent="removeTypeFilter(activeTypeFilter)"
-                       class="absolute w-7 h-7 right-2 top-1/2 transform -translate-y-1/2
-                              flex items-center justify-center
-                              rounded-full bg-grey-200 text-current">
-                        <svg class="stroke-current" xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 10.828 10.828">
-                            <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
-                                <path d="m1.414 9.414 8-8"/>
-                                <path data-name="Path 46" d="m1.414 1.414 8 8"/>
-                            </g>
-                        </svg>
-                    </a>
-                </div>
-            </template>
-
-            {{-- ACTIVE [THEME] FILTERS (JS) --}}
-            <template x-for="activeThemeFilter in activeThemeFilters">
-                <div class="relative inline-flex
-                            py-4 pl-4 pr-12
-                            rounded-full border border-grey-200
-                            leading-none
-                            font-secondary font-medium text-black">
-                    <span x-text="filters[activeThemeFilter]" class="whitespace-nowrap"></span>
-                    {{-- REMOVE (X) ICON --}}
-                    <a href="#"
-                       @click.prevent="removeThemeFilter(activeThemeFilter)"
-                       class="absolute w-7 h-7 right-2 top-1/2 transform -translate-y-1/2
-                              flex items-center justify-center
-                              rounded-full bg-grey-200 text-current">
-                        <svg class="stroke-current" xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 10.828 10.828">
-                            <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
-                                <path d="m1.414 9.414 8-8"/>
-                                <path data-name="Path 46" d="m1.414 1.414 8 8"/>
-                            </g>
-                        </svg>
-                    </a>
-                </div>
-            </template>
-        </div>
-
-        {{-- MEDIA LIBRARY GRID --}}
-        {{-- Negative margins applied here to offset margins used in Isotope grid --}}
-        <div class="media-grid mt-10 -mb-16 -mx-2.5">
-            @foreach ($media as $item)
-                <div class="media-item
-                            {{-- Width is 25% minus the gutters (2 * 0.625rem that comes from mx-2.5) --}}
-                            float-left w-[calc(25%-1.25rem)] mx-2.5 mb-16
-                            media-{{ $item['type'] }}
-                            theme-{{ $item['theme']['id'] }}">
-                    <div class="media-item-image relative bg-cover bg-no-repeat rounded-md pb-[56.25%]" style="background-image:url({{ $item['image'] }})">
-
-                        {{-- Play Icon --}}
-                        <svg class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"
-                             xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewBox="0 0 59.999 59.999">
-                            <g fill="#0725e2">
-                                <path d="M0 29.999a30 30 0 1 0 30-30 30 30 0 0 0-30 30Z"/>
-                                <path d="m26.5 38.5 12-8-12-8Z" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
-                            </g>
-                        </svg>
-
-                        <x-duration class="absolute bottom-2 right-2 font-secondary text-white">{{ $item['duration'] }}</x-duration>
-                    </div>
-                    {{-- THEME LABEL --}}
-                    <div class="mt-2.5 font-secondary font-medium text-xs leading-none" style="color:{{ $item['theme']['color'] }}">
-                        {{ $item['theme']['title'] }}  [{{ strtoupper($item['type']) }}]
-                    </div>
-                    <div class="mt-1.5 font-semibold leading-snug">
-                        {{ $item['title'] }}
-                    </div>
-                </div>
-            @endforeach
-        </div>
-
-        {{-- FILTER SELECTION INTERFACE (full screen overlay) --}}
-        <div class="filters-overlay
-                    fixed top-0 left-0 w-screen h-screen
-                    flex items-center
-                    bg-blue text-white
-                    px-30
-                    z-20
-                    transition ease-out-cubic duration-500"
-             x-show="filtersOpen"
-             x-transition:enter-start="opacity-0"
-             x-transition:enter-end="opacity-100"
-             x-transition:leave-start="opacity-100"
-             x-transition:leave-end="opacity-0"
-             x-cloak>
+    <h1 class="uppercase">Médiathèque</h1>
 
-            {{-- Close --}}
-            <a href="#" @click.prevent="filtersOpen = false" class="absolute top-8 right-8 flex">
-                <span class="mr-8">Fermer</span>
-
-                <svg class="stroke-current" xmlns="http://www.w3.org/2000/svg" width="33" height="26" viewBox="0 0 25.098 25.098">
-                    <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
-                        <path d="m1.414 23.683 22.27-22.27"/>
-                        <path d="m1.414 1.414 22.27 22.27"/>
-                    </g>
-                </svg>
-            </a>
-
-            <div class="w-full">
-
-                <h2 class="text-6xl uppercase">Filtres</h2>
-
-                {{-- Filter Options --}}
-                <div class="flex mt-15">
-                    {{-- Media Type Filters --}}
-                    <div class="w-1/3">
-                        <h3 class="font-medium text-4xl mb-5">Média</h3>
-                        <div class="grid grid-cols-1 gap-5">
-                            @foreach($media_types as $media_type_id => $media_type)
-                                <label>
-                                    <input type="checkbox"
-                                           value="media-{{ $media_type_id }}"
-                                           x-model="activeTypeFilters"
-                                           class="peer sr-only">
-                                    <span class="inline-block cursor-pointer
-                                                 font-secondary font-medium
-                                                 py-2.5 px-5 rounded-full border
-                                                 peer-checked:bg-white peer-checked:text-black
-                                                 transition">
-                                    {{ $media_type }}
-                                </span>
-                                </label>
-                            @endforeach
-                        </div>
-                    </div>
-
-                    {{-- Theme Filters --}}
-                    <div class="w-2/3">
-                        <h3 class="font-medium text-4xl mb-5">Thème</h3>
-                        <div class="grid grid-cols-2 gap-5">
-                            @foreach($themes as $theme_id => $theme)
-                                <label>
-                                    <input type="checkbox"
-                                           value="theme-{{ $theme_id }}"
-                                           x-model="activeThemeFilters"
-                                           class="peer sr-only">
-                                    <span class="inline-block cursor-pointer
-                                                 font-secondary font-medium
-                                                 whitespace-nowrap
-                                                 py-2.5 px-5 rounded-full border
-                                                 peer-checked:bg-white peer-checked:text-black
-                                                 transition">
-                                    {{ $theme }}
-                                </span>
-                                </label>
-                            @endforeach
-                        </div>
-                    </div>
-
-                </div>
-
-                <div class="text-right mt-20">
-                    <button @click="filtersOpen = false"
-                            class="bg-blue-dark
-                                   font-medium
-                                   py-3 px-8 rounded-full">
-                        Valider
-                    </button>
-                </div>
-
-            </div>
-        </div>
-
-    </div>
+    {{-- Media library (components/media-library/index.blade.php) --}}
+    <x-media-library :themes="$themes" :types="$media_types" :media="$media"></x-media-library>
 
 @endsection
 
-@push('before_scripts')
-    <script src="{{ asset('js/isotope.js') }}"></script>
-@endpush
+
index 4722bff26c813623d37a5849c4607c24371758be..c7c23ad5b91ff7bb9676c6d54249fac194db4826 100644 (file)
@@ -3,7 +3,9 @@
 <head>
     <meta charset="UTF-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    @stack('before_css')
     <link href="{{ asset('css/app.css') }}" rel="stylesheet">
+    @stack('after_css')
     <title>{{ config('app.name') }}</title>
 </head>
 <body class="font-primary p-8" :class="menuOpen && 'menu-open'" x-data="{ menuOpen: false }">
index eacbded548ab081a1ddf7a96056ebc4d05f9a16a..233a7b0e38034eaf0b9a4f4e22c74a57f585d651 100644 (file)
@@ -9,3 +9,7 @@ mix.js('resources/js/app.js', 'public/js')
 
 // Copy pre-compiled Isotope JS package
 mix.copy('node_modules/isotope-layout/dist/isotope.pkgd.min.js', 'public/js/isotope.js');
+
+// Copy Plyr resources
+mix.copy('node_modules/plyr/dist/plyr.min.js', 'public/js/plyr.js');
+mix.copy('node_modules/plyr/dist/plyr.css', 'public/css/plyr.css');