"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",
"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"
// 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
--- /dev/null
+{{-- 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>
--- /dev/null
+{{-- 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>
--- /dev/null
+{{-- 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>
--- /dev/null
+{{-- 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>
--- /dev/null
+{{-- 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>
'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',
'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',
'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',
'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',
'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',
'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
+
<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 }">
// 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');