Compare commits

...

2 Commits

Author SHA1 Message Date
anulax1225 a8fb1ee866 Added cache control on all photos and album ago%!(EXTRA string=3 days)
anulax1225 5d36ac33c2 Reworked the home page ago%!(EXTRA string=3 days)
  1. 13
      app/Http/Controllers/AlbumController.php
  2. 16
      app/Http/Controllers/S3Controller.php
  3. 2
      app/Models/Album.php
  4. 2
      app/Models/Photo.php
  5. 2
      resources/js/Layouts/Layout.vue
  6. 20
      resources/js/Pages/Album/Partials/Edit.vue
  7. 12
      resources/js/Pages/Album/Partials/Show.vue
  8. 2
      resources/js/Pages/Home.vue
  9. 12
      resources/js/Pages/Homea.vue
  10. 3
      resources/js/Pages/Photo/Partials/Modal.vue
  11. 3
      resources/js/Pages/Photo/Partials/PanelShow.vue
  12. 5
      resources/js/Pages/Photo/Partials/Show.vue
  13. 14
      resources/js/utils.js

@ -109,6 +109,19 @@ public function store(Request $request)
return redirect(route("album.index"))->with(["message" => "Photo ajouté avec success"]); return redirect(route("album.index"))->with(["message" => "Photo ajouté avec success"]);
} }
public function update(Request $request, string $id)
{
$request->validate([
"name" => "required|string|max:255",
]);
$album = Album::where("uuid", $request->id)->first();
if(!$album) redirect()->back()->withErrors(["uuid" => "Album introuvable" ]);
$album->update([
"name" => $request->name
]);
return redirect(route("album.index"))->with(["message" => "Album modifié avec success"]);
}
public function addPhotos(Request $request) public function addPhotos(Request $request)
{ {
$album = Album::where("uuid", $request->id)->first(); $album = Album::where("uuid", $request->id)->first();

@ -98,8 +98,20 @@ public function ProxyS3(Request $request)
public function Download(Request $request) public function Download(Request $request)
{ {
$url = S3::signUrl($request->key); if(!$request->key) return redirect()->back()->withErrors("error", "Aucun fichier a été télécharger.");
return redirect($url); $url = $request->key;
$filename = pathinfo($request->key, PATHINFO_BASENAME);
if(!Storage::disk("s3")->exists($url)) return redirect()->back()->withErrors("error", "Fichier introuvable.");
$path = pathinfo($url, PATHINFO_DIRNAME);
return response()->streamDownload(function() use ($url) {
$stream = Storage::disk('s3')->readStream($url);
while (!feof($stream)) {
echo fread($stream, 256 * 1024);
flush();
}
fclose($stream);
}, $filename, ['Cache-Control' => "max-age=86400" ]);
} }
} }

@ -20,7 +20,7 @@ public function jsonSerialize():array
'uuid' => $this->uuid, 'uuid' => $this->uuid,
'name' => $this->name, 'name' => $this->name,
'path' => $this->path, 'path' => $this->path,
'image' => S3::signUrl($this->path), 'image' => $this->path,
'user' => $this->user, 'user' => $this->user,
'created_at' => date("d.m.Y", strtotime($this->created_at)), 'created_at' => date("d.m.Y", strtotime($this->created_at)),
]; ];

@ -20,7 +20,7 @@ public function jsonSerialize():array
return [ return [
'uuid' => $this->uuid, 'uuid' => $this->uuid,
'name' => $this->name, 'name' => $this->name,
'path' => S3::signUrl($this->path), 'path' => $this->path,
'user' => $this->user, 'user' => $this->user,
'created_at' => date("d.m.Y", strtotime($this->created_at)), 'created_at' => date("d.m.Y", strtotime($this->created_at)),
]; ];

@ -17,7 +17,7 @@ const toggleMenu = () => {
<template> <template>
<nav class="sticky z-20 w-full top-0 right-0 left-0"> <nav class="sticky z-20 w-full top-0 right-0 left-0">
<div class="w-full h-16 z-40 flex desktop:px-[17.5%] laptop:px-[12.5%] px-2 justify-between border-b border-gray-300 bg-gray-50 text-gray-900"> <div class="w-full h-16 z-40 flex desktop:px-[12.5%] laptop:px-[7.5%] px-2 justify-between border-b border-gray-300 bg-gray-50 text-gray-900">
<div :class="{ 'w-full': !user }" class="flex h-full justify-between"> <div :class="{ 'w-full': !user }" class="flex h-full justify-between">
<Link :href="user ? route('photo.index') : route('home')" :class="'h-full mr-5 z-40 w-fit'"> <Link :href="user ? route('photo.index') : route('home')" :class="'h-full mr-5 z-40 w-fit'">
<img src="/img/logo.png" class="h-full laptop:py-1.5 py-3"> <img src="/img/logo.png" class="h-full laptop:py-1.5 py-3">

@ -1,5 +1,6 @@
<script setup> <script setup>
import TextInput from '@/Components/TextInput.vue'; import TextInput from '@/Components/TextInput.vue';
import Utils from '@/utils';
import { useForm } from '@inertiajs/vue3'; import { useForm } from '@inertiajs/vue3';
const props = defineProps({ const props = defineProps({
@ -16,25 +17,24 @@ const form = useForm({
const emits = defineEmits(["close"]); const emits = defineEmits(["close"]);
const submit = () => { const submit = () => {
form.post("/photo/" + props.photo.uuid , { form.post(route("album.update", props.album.uuid) , {
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-CSRF-Token": document.querySelector('input[name=_token]').value, "X-CSRF-Token": document.querySelector('input[name=_token]').value,
}, },
}); });
form.name = "";
emits("close"); emits("close");
} }
</script> </script>
<template> <template>
<div class="text-left text-black shadow-md shadow-gray-500 rounded-lg <div class="text-left text-black shadow-md shadow-gray-500 rounded-lg z-40
bg-gray-50 overflow-hidden border border-gray-300 p-2 w-72" > bg-gray-50 overflow-hidden border border-gray-300 p-2 w-72 pointer-events-none">
<form @submit.prevent="submit"> <form>
<TextInput :placeholder="'Changer le nom de la photo'" :class="'w-full'" v-model="form.name"/> <TextInput :placeholder="'Changer le nom de la album'" :class="'w-full'" v-model="form.name"/>
<div class="w-full flex mt-3"> <div class="w-full flex mt-3">
<button type="submit" class="text-white font-semibold p-1 px-2 bg-primary rounded-md">Changer</button> <button @click.prevent="submit" class="text-white font-semibold p-1 px-2 bg-primary rounded-md">Changer</button>
</div> </div>
</form> </form>
</div> </div>
</template> </template>

@ -42,6 +42,7 @@ const deleteAlbum = async (e) => {
</script> </script>
<template> <template>
<div class="relative w-full">
<Link :href="'/album/' + props.album.uuid" :class="{ <Link :href="'/album/' + props.album.uuid" :class="{
'border-r': (props.index + 1) % props.columns != 0, 'border-r': (props.index + 1) % props.columns != 0,
'border-b': props.index < props.length - props.columns, 'border-b': props.index < props.length - props.columns,
@ -51,14 +52,6 @@ const deleteAlbum = async (e) => {
class="group relative w-full overflow-hidden border-white hover:scale-[1.003] flex items-center bg-black/90"> class="group relative w-full overflow-hidden border-white hover:scale-[1.003] flex items-center bg-black/90">
<div class="hidden absolute left-0 right-0 top-0 p-2 group-hover:flex justify-between"> <div class="hidden absolute left-0 right-0 top-0 p-2 group-hover:flex justify-between">
<div class="flex items-center"> <div class="flex items-center">
<div class="relative">
<button @click="(e) => { Utils.Prevent(e); albumState.edit = !albumState.edit; }" class="bg-black/50 p-1 rounded-md mr-2"><img src="/icons/modify.svg" class="h-6 invert"></button>
<!-- <Edit v-if="albumState.edit"
@close="() => albumState.edit = false"
:album="props.album"
:class="'absolute left-0 top-full mt-2'"
/> -->
</div>
<button @click="deleteAlbum" class="bg-red-600 p-1 rounded-md"><img src="/icons/delete.png" class="h-6 invert"></button> <button @click="deleteAlbum" class="bg-red-600 p-1 rounded-md"><img src="/icons/delete.png" class="h-6 invert"></button>
</div> </div>
</div> </div>
@ -66,6 +59,7 @@ const deleteAlbum = async (e) => {
<p class="laptop:text-sm text-xs text-white bg-black/30 p-1 px-3 rounded">{{ props.album.name }}</p> <p class="laptop:text-sm text-xs text-white bg-black/30 p-1 px-3 rounded">{{ props.album.name }}</p>
<p class="laptop:text-sm text-xs text-white bg-black/30 p-1 px-3 rounded">publier par {{ props.album.user.name }}</p> <p class="laptop:text-sm text-xs text-white bg-black/30 p-1 px-3 rounded">publier par {{ props.album.user.name }}</p>
</div> </div>
<img :src="props.album.image" class="w-full bg-white"> <img :src="Utils.DownloadUrl(props.album.image)" class="w-full bg-white">
</Link> </Link>
</div>
</template> </template>

@ -10,7 +10,7 @@ import Layout from '@/Layouts/Layout.vue';
<template #content> <template #content>
<div class="relative w-full laptop:max-h-[50rem] flex items-center overflow-hidden max-h-96"> <div class="relative w-full laptop:max-h-[50rem] flex items-center overflow-hidden max-h-96">
<div class="flex justify-center items-center absolute top-0 bottom-0 right-0 left-0 bg-gradient-to-t from-gray-200/25 via-[25%] via-white/20 to-[50%] to-white/5"> <div class="flex justify-center items-center absolute top-0 bottom-0 right-0 left-0 bg-gradient-to-t from-gray-200/25 via-[25%] via-white/20 to-[50%] to-white/5">
<p class="text-center text-white/65 laptop:text-[220px] text-8xl laptop:leading-[180px] font-bold">Scout Baslac</p> <p class="text-center text-white/65 laptop:text-6xl text-3xl font-bold">Scout Baslac</p>
</div> </div>
<img src="/img/sarasin.png" class="w-full laptop:pb-96 "> <img src="/img/sarasin.png" class="w-full laptop:pb-96 ">
</div> </div>

@ -10,21 +10,21 @@ import Layout from '@/Layouts/Layout.vue';
<template #content> <template #content>
<div class=" text-gray-900"> <div class=" text-gray-900">
<div class="relative w-full max-h-[calc(100vh+1rem)] flex items-center overflow-hidden"> <div class="relative w-full max-h-[50vh] flex items-center overflow-hidden">
<img src="/img/sarasin.png" class="h-full laptop:pb-96 object-cover" alt="Image de présentation du groupe scout" /> <img src="/img/sarasin.png" class="h-full laptop:pb-96 object-cover" alt="Image de présentation du groupe scout" />
<!-- Gradient doux : du transparent en haut vers un noir très léger en bas --> <!-- Gradient doux : du transparent en haut vers un noir très léger en bas bg-gradient-to-b from-transparent via-gray-200 via-[90%] to-gray-200 -->
<div class="absolute top-0 bottom-0 right-0 left-0 inset-0 flex items-center justify-center bg-gradient-to-b from-transparent via-gray-200 via-[90%] to-gray-200"> <div class="absolute top-0 bottom-0 right-0 left-0 inset-0 flex items-center justify-center">
<h1 class="text-center text-white laptop:text-[260px] text-7xl laptop:leading-[180px] font-extrabold drop-shadow-lg transition duration-500 hover:scale-105"> <h1 class="text-center text-white/50 laptop:text-[200px] text-7xl font-extrabold drop-shadow-lg transition duration-500">
Scout Baslac Scout Baslac
</h1> </h1>
</div> </div>
</div> </div>
<!-- Contenu principal avec animation et grilles --> <!-- Contenu principal avec animation et grilles -->
<div class="w-full desktop:px-[17.5%] laptop:px-[12.5%] px-4 pb-12 space-y-12"> <div class="w-full desktop:px-[17.5%] laptop:px-[12.5%] px-4 mt-10 pb-12 space-y-12">
<!-- Carte "Qui sommes-nous ?" --> <!-- Carte "Qui sommes-nous ?" -->
<transition name="fade" mode="out-in"> <transition name="fade" mode="out-in">
<div class="bg-gray-100 shadow-xl rounded-lg overflow-hidden transform transition duration-200 hover:scale-105"> <div class="bg-gray-100 shadow-xl rounded-lg overflow-hidden transform transition duration-200">
<div class="flex flex-col lg:flex-row"> <div class="flex flex-col lg:flex-row">
<!-- Partie Image --> <!-- Partie Image -->
<div class="lg:w-1/2 relative max-h-56 hover:p-trans-in p-trans-out duration-200 overflow-hidden"> <div class="lg:w-1/2 relative max-h-56 hover:p-trans-in p-trans-out duration-200 overflow-hidden">

@ -1,4 +1,5 @@
<script setup> <script setup>
import Utils from '@/utils';
import { reactive } from 'vue'; import { reactive } from 'vue';
@ -69,7 +70,7 @@ const closeOnEscape = (e) => {
<img src="/icons/next.svg" class="h-16 rotate-180"> <img src="/icons/next.svg" class="h-16 rotate-180">
</button> </button>
<div class="relative h-full laptop:w-full w-[300px] flex items-center justify-center"> <div class="relative h-full laptop:w-full w-[300px] flex items-center justify-center">
<img :src="photo.path" class="laptop:h-full"> <img :src="Utils.DownloadUrl(photo.path)" class="laptop:h-full">
</div> </div>
<button @click="nextPhoto" class="pl-3 hover:scale-105"> <button @click="nextPhoto" class="pl-3 hover:scale-105">
<img src="/icons/next.svg" class="h-16"> <img src="/icons/next.svg" class="h-16">

@ -4,6 +4,7 @@ import { useForm } from '@inertiajs/vue3';
import { reactive } from 'vue'; import { reactive } from 'vue';
import Edit from './Edit.vue'; import Edit from './Edit.vue';
import axios from 'axios'; import axios from 'axios';
import Utils from '@/utils';
const props = defineProps({ const props = defineProps({
photo: { photo: {
@ -58,6 +59,6 @@ const imageChange = () => {
<p class="text-sm text-white">publier par {{ props.photo.user.name }}</p> <p class="text-sm text-white">publier par {{ props.photo.user.name }}</p>
</div> </div>
</div> </div>
<img :src="props.photo.path" class="w-full bg-white"> <img :src="Utils.DownloadUrl(props.photo.path)" class="w-full bg-white">
</div> </div>
</template> </template>

@ -4,6 +4,7 @@ import { useForm } from '@inertiajs/vue3';
import { reactive } from 'vue'; import { reactive } from 'vue';
import Edit from './Edit.vue'; import Edit from './Edit.vue';
import axios from 'axios'; import axios from 'axios';
import Utils from '@/utils';
const props = defineProps({ const props = defineProps({
photo: { photo: {
@ -47,7 +48,7 @@ const emits = defineEmits(["full-screen", "delete-photo"]);
<div class="flex items-center"> <div class="flex items-center">
<button @click="() => emits('full-screen', props.photo.uuid)" class="bg-black/50 p-1 rounded-md mr-2"><img src="/icons/full-screen.svg" class="h-6 invert"></button> <button @click="() => emits('full-screen', props.photo.uuid)" class="bg-black/50 p-1 rounded-md mr-2"><img src="/icons/full-screen.svg" class="h-6 invert"></button>
<div class="laptop:relative"> <div class="laptop:relative">
<button v-if="!props.noEdit"@click="photoState.edit = !photoState.edit" class="bg-black/50 p-1 rounded-md mr-2"><img src="/icons/modify.svg" class="h-6 invert"></button> <button v-if="!props.noEdit" @click="photoState.edit = !photoState.edit" class="bg-black/50 p-1 rounded-md mr-2"><img src="/icons/modify.svg" class="h-6 invert"></button>
<Edit v-if="photoState.edit && !props.noEdit" <Edit v-if="photoState.edit && !props.noEdit"
@close="() => photoState.edit = false" @close="() => photoState.edit = false"
:photo="props.photo" :photo="props.photo"
@ -64,6 +65,6 @@ const emits = defineEmits(["full-screen", "delete-photo"]);
<p class="laptop:text-sm text-xs text-white">publier par {{ props.photo.user.name }}</p> <p class="laptop:text-sm text-xs text-white">publier par {{ props.photo.user.name }}</p>
</div> </div>
</div> </div>
<img :src="props.photo.path" class="w-full bg-white"> <img :src="Utils.DownloadUrl(props.photo.path)" class="w-full bg-white">
</div> </div>
</template> </template>

@ -3,4 +3,18 @@ export default class Utils {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
} }
static openInNewTab(url) {
window.open(url, '_blank').focus();
}
static openInThisTab(url) {
window.location.href = url;
}
static DownloadUrl(key)
{
return route("s3.download") + "?key=" + key;
}
} }

Loading…
Cancel
Save