diff --git a/public/css/app.css b/public/css/app.css
index cde978e..e3430e4 100644
--- a/public/css/app.css
+++ b/public/css/app.css
@@ -473,6 +473,9 @@ Ensure the default browser behavior of the `hidden` attribute.
-webkit-animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
+.cursor-pointer {
+ cursor: pointer;
+}
.cursor-not-allowed {
cursor: not-allowed;
}
@@ -497,6 +500,14 @@ Ensure the default browser behavior of the `hidden` attribute.
.rounded {
border-radius: 0.25rem;
}
+.rounded-t-md {
+ border-top-left-radius: 0.375rem;
+ border-top-right-radius: 0.375rem;
+}
+.rounded-b-md {
+ border-bottom-right-radius: 0.375rem;
+ border-bottom-left-radius: 0.375rem;
+}
.border {
border-width: 1px;
}
@@ -504,6 +515,10 @@ Ensure the default browser behavior of the `hidden` attribute.
--tw-border-opacity: 1;
border-color: rgb(0 0 0 / var(--tw-border-opacity));
}
+.bg-black {
+ --tw-bg-opacity: 1;
+ background-color: rgb(0 0 0 / var(--tw-bg-opacity));
+}
.bg-stone-800 {
--tw-bg-opacity: 1;
background-color: rgb(41 37 36 / var(--tw-bg-opacity));
@@ -512,6 +527,9 @@ Ensure the default browser behavior of the `hidden` attribute.
-o-object-fit: scale-down;
object-fit: scale-down;
}
+.p-2 {
+ padding: 0.5rem;
+}
.p-1 {
padding: 0.25rem;
}
@@ -532,6 +550,14 @@ Ensure the default browser behavior of the `hidden` attribute.
.pr-2 {
padding-right: 0.5rem;
}
+.text-base {
+ font-size: 1rem;
+ line-height: 1.5rem;
+}
+.text-gray-500 {
+ --tw-text-opacity: 1;
+ color: rgb(107 114 128 / var(--tw-text-opacity));
+}
.text-neutral-500 {
--tw-text-opacity: 1;
color: rgb(115 115 115 / var(--tw-text-opacity));
@@ -540,6 +566,9 @@ Ensure the default browser behavior of the `hidden` attribute.
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
+.opacity-75 {
+ opacity: 0.75;
+}
.shadow {
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
@@ -555,6 +584,20 @@ Ensure the default browser behavior of the `hidden` attribute.
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
+.delay-150 {
+ transition-delay: 150ms;
+}
+.duration-300 {
+ transition-duration: 300ms;
+}
+.ease-in-out {
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+}
+.hover\:scale-90:hover {
+ --tw-scale-x: .9;
+ --tw-scale-y: .9;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
.hover\:text-orange-400:hover {
--tw-text-opacity: 1;
color: rgb(251 146 60 / var(--tw-text-opacity));
diff --git a/public/js/app.js b/public/js/app.js
index 03cb31f..d74da18 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -19576,8 +19576,8 @@ __webpack_require__.r(__webpack_exports__);
window.history.pushState({}, '', url);
},
galleryUrl: function galleryUrl(page) {
- var url = _config__WEBPACK_IMPORTED_MODULE_0__.isNotProduction ? '/gallery.json' : '/gallery';
- url += "?page=" + page;
+ var url = _config__WEBPACK_IMPORTED_MODULE_0__.isNotProduction ? '/gallery.json' : "/gallery?timestamp=".concat(new Date().getTime());
+ url += "&page=" + page;
if (this.filters) {
url += '&filter[tags]=' + this.filters;
@@ -19588,7 +19588,12 @@ __webpack_require__.r(__webpack_exports__);
getImages: function getImages(page) {
var _this = this;
- axios.get(this.galleryUrl(page)).then(function (response) {
+ axios.get(this.galleryUrl(page), {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-Robots-Tag': 'noindex, nofollow'
+ }
+ }).then(function (response) {
var _response$data = response.data,
data = _response$data.data,
current_page = _response$data.current_page,
@@ -19629,7 +19634,8 @@ __webpack_require__.r(__webpack_exports__);
props: {
image: {
required: false,
- type: String
+ type: Object,
+ "default": null
}
}
});
@@ -19686,7 +19692,12 @@ __webpack_require__.r(__webpack_exports__);
_this = this;
var url = _config__WEBPACK_IMPORTED_MODULE_0__.isNotProduction ? '/tags.json' : '/tags/';
- axios.get(url + ((_this$filters = this.filters) !== null && _this$filters !== void 0 ? _this$filters : '')).then(function (response) {
+ axios.get(url + ((_this$filters = this.filters) !== null && _this$filters !== void 0 ? _this$filters : ''), {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-Robots-Tag': 'noindex, nofollow'
+ }
+ }).then(function (response) {
_this.navigation = response.data;
_this.removeTheAllTag();
@@ -19987,8 +19998,9 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
alt: image.alt,
image: image.thumbnail,
key: "image-".concat(index),
+ onContextmenu: _cache[0] || (_cache[0] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)(function () {}, ["prevent"])),
onClick: function onClick($event) {
- return $data.currentImage = image.image;
+ return $data.currentImage = image;
}
}, null, 8
/* PROPS */
@@ -20007,7 +20019,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
}, [$data.currentImage ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createBlock)(_component_modal, {
key: 0,
image: $data.currentImage,
- onClose: _cache[0] || (_cache[0] = function ($event) {
+ onClose: _cache[1] || (_cache[1] = function ($event) {
return $data.currentImage = null;
})
}, null, 8
@@ -20038,21 +20050,39 @@ var _withScopeId = function _withScopeId(n) {
};
var _hoisted_1 = {
+ key: 0,
"class": "modal"
};
-var _hoisted_2 = ["src"];
+var _hoisted_2 = {
+ "class": "rounded-t-md flex justify-between bg-black opacity-75 text-base text-gray-500 p-2"
+};
+
+var _hoisted_3 = /*#__PURE__*/_withScopeId(function () {
+ return /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", null, "Click to Close", -1
+ /* HOISTED */
+ );
+});
+
+var _hoisted_4 = ["src"];
function render(_ctx, _cache, $props, $setup, $data, $options) {
return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", {
"class": "shadow",
- onClick: _cache[0] || (_cache[0] = function ($event) {
+ onContextmenu: _cache[0] || (_cache[0] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)(function ($event) {
+ return _ctx.$emit("close");
+ }, ["prevent"])),
+ onClick: _cache[1] || (_cache[1] = function ($event) {
return _ctx.$emit("close");
})
- }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_1, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("img", {
- src: $props.image,
- "class": "object-scale-down max-w-screen max-h-screen"
+ }, [$props.image ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_1, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_2, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($props.image.alt), 1
+ /* TEXT */
+ ), _hoisted_3]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("img", {
+ src: $props.image.image,
+ "class": "rounded-b-md cursor-pointer object-scale-down max-w-screen max-h-screen"
}, null, 8
/* PROPS */
- , _hoisted_2)])]);
+ , _hoisted_4)])) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)("v-if", true)], 32
+ /* HYDRATE_EVENTS */
+ );
}
/***/ }),
@@ -20290,7 +20320,7 @@ var _hoisted_1 = ["src", "alt"];
function render(_ctx, _cache, $props, $setup, $data, $options) {
return $props.image ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("img", {
key: 0,
- "class": "w-full",
+ "class": "transition delay-150 duration-300 ease-in-out hover:scale-90 cursor-pointer w-full",
src: $props.image,
alt: $props.alt
}, null, 8
diff --git a/src/Console/Commands/GenerateImages.php b/src/Console/Commands/GenerateImages.php
index 789739d..2eaac7a 100644
--- a/src/Console/Commands/GenerateImages.php
+++ b/src/Console/Commands/GenerateImages.php
@@ -10,6 +10,8 @@
class GenerateImages extends Command
{
+ const MISSING_IMAGE_COLOR = '#ffb52e';
+
const THUMBNAIL_WIDTH = 125;
const THUMBNAIL_HEIGHT = 175;
const THUMBNAIL_QUALITY = 75;
@@ -39,7 +41,7 @@ class GenerateImages extends Command
*
* @return int
*/
- public function handle()
+ public function handle() : int
{
$originalImages = Storage::disk("gallery-originals")->allFiles();
@@ -58,6 +60,7 @@ public function handle()
}
$this->createMissingThumbnail();
+ $this->createMissingImage();
return 0;
}
@@ -82,7 +85,7 @@ private function resizeImage($originalImage)
->save($thumbPath, self::THUMBNAIL_QUALITY, pathinfo($gallery->thumb, PATHINFO_EXTENSION));
$image = Image::make($originalPath);
- list($width, $height) = $this->calculateWidthHeight($image);
+ [$width, $height] = $this->calculateWidthHeight($image);
$image->resize($width, $height, function ($constraint) {
$constraint->aspectRatio();
})->save($imagePath);
@@ -97,7 +100,7 @@ private function resizeImage($originalImage)
* @param \Intervention\Image\Image $image
* @return array
*/
- private function calculateWidthHeight(\Intervention\Image\Image $image)
+ private function calculateWidthHeight(\Intervention\Image\Image $image) : array
{
$width = self::MAX_IMAGE_WIDTH;
$height = self::MAX_IMAGE_HEIGHT;
@@ -116,15 +119,32 @@ private function createMissingThumbnail()
$img = Image::canvas(self::THUMBNAIL_WIDTH, self::THUMBNAIL_HEIGHT, '#ffa500');
$img
->line(0, 0, self::THUMBNAIL_WIDTH, self::THUMBNAIL_HEIGHT, function ($draw) {
- $draw->color('#ffb52e');
+ $draw->color(self::MISSING_IMAGE_COLOR);
})
->line(self::THUMBNAIL_WIDTH, 0, 0, self::THUMBNAIL_HEIGHT, function ($draw) {
- $draw->color('#ffb52e');
+ $draw->color(self::MISSING_IMAGE_COLOR);
})
- ->text('Missing Image', 28, 20, function ($font) {
+ ->text('Missing Image', round(self::THUMBNAIL_WIDTH / 2 - 34), 20, function ($font) {
$font->color('#000');
});
- $img->save(Storage::disk('gallery')->path('missing.gif'), 90, 'gif');
- $this->info('Created missing image: ' . Storage::disk('gallery')->path('missing.gif'));
+ $img->save(Storage::disk('gallery')->path('missing-thumbnail.gif'), 90, 'gif');
+ $this->info('Created missing thumbnail: ' . Storage::disk('gallery')->path('missing-thumbnail.gif'));
+ }
+
+ private function createMissingImage()
+ {
+ $img = Image::canvas(self::MAX_IMAGE_WIDTH, self::MAX_IMAGE_HEIGHT, '#ffa500');
+ $img
+ ->line(0, 0, self::MAX_IMAGE_WIDTH, self::MAX_IMAGE_HEIGHT, function ($draw) {
+ $draw->color(self::MISSING_IMAGE_COLOR);
+ })
+ ->line(self::MAX_IMAGE_WIDTH, 0, 0, self::MAX_IMAGE_HEIGHT, function ($draw) {
+ $draw->color(self::MISSING_IMAGE_COLOR);
+ })
+ ->text('Missing Image', round(self::MAX_IMAGE_WIDTH / 2 - 34), 20, function ($font) {
+ $font->color('#000');
+ });
+ $img->save(Storage::disk('gallery')->path('missing-image.gif'), 90, 'gif');
+ $this->info('Created missing image: ' . Storage::disk('gallery')->path('missing-image.gif'));
}
}
diff --git a/src/Http/Controllers/Controller.php b/src/Http/Controllers/Controller.php
deleted file mode 100644
index 0614c5a..0000000
--- a/src/Http/Controllers/Controller.php
+++ /dev/null
@@ -1,15 +0,0 @@
-json([
'children' =>
- UberTags::where('parent', 0)
+ UberTags::query()->where('parent', 0)
->get()
->filter(function ($tag) {
return Route::has($tag->name);
@@ -25,11 +25,11 @@ public function __invoke($filters = '')
$childFilters = array_slice($names, 1);
return response()->json([
- 'current' => UberTags::where('name', $currentFilter)
+ 'current' => UberTags::query()->where('name', $currentFilter)
->with('parent')
->first(),
'children' =>
- UberTags::whereIn('name', $childFilters)
+ UberTags::query()->whereIn('name', $childFilters)
//->children()
->with('parent')
->orderBy('name')
diff --git a/src/Models/UberGallery.php b/src/Models/UberGallery.php
index 7335af0..ddbe5cd 100644
--- a/src/Models/UberGallery.php
+++ b/src/Models/UberGallery.php
@@ -2,6 +2,7 @@
namespace LisaFehr\Gallery\Models;
+use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@@ -23,7 +24,7 @@ class UberGallery extends Model
'text',
];
- public function tag()
+ public function tag() : \Illuminate\Database\Eloquent\Relations\HasOneThrough
{
return $this->hasOneThrough(
UberTags::class,
@@ -35,25 +36,25 @@ public function tag()
);
}
- public function getImageAttribute()
+ public function getImageAttribute() : string
{
$url = $this->tag->directory . '/' . $this->img . '.' . $this->type;
if (Storage::disk('gallery')->exists($url)) {
- return Storage::disk('gallery')->url($url);
+ return Storage::disk('gallery')->temporaryUrl($url, Carbon::now()->addDay());
}
- return Storage::disk('gallery')->url('/missing.gif');
+ return Storage::disk('gallery')->url('/missing-image.gif');
}
- public function getThumbnailAttribute()
+ public function getThumbnailAttribute() : ?string
{
if (! $this->tag) {
return null;
}
$url = $this->tag->directory . '/t/' . $this->thumb;
if (Storage::disk('gallery')->exists($url)) {
- return Storage::disk('gallery')->url($url);
+ return Storage::disk('gallery')->temporaryUrl($url, Carbon::now()->addDay());
}
- return Storage::disk('gallery')->url('/missing.gif');
+ return Storage::disk('gallery')->url('/missing-thumbnail.gif');
}
public function scopeTags(Builder $builder, ...$tags)
@@ -65,7 +66,7 @@ public function scopeTags(Builder $builder, ...$tags)
->whereIn('uber_tags.name', $tags);
}
- public function toArray()
+ public function toArray() : array
{
return [
'image' => $this->image,
diff --git a/src/Models/UberTags.php b/src/Models/UberTags.php
index 89caac5..3c1021e 100644
--- a/src/Models/UberTags.php
+++ b/src/Models/UberTags.php
@@ -30,7 +30,7 @@ class UberTags extends Model
'parent',
];
- public function scopeAllChildren(Builder $builder)
+ public function scopeAllChildren(Builder $builder) : Builder
{
$children = $builder->select('children', 'id')->having('children', '=', 1);
$parents = $builder->pluck('id');
@@ -42,10 +42,10 @@ public function scopeAllChildren(Builder $builder)
$collect = $collect->merge($parents);
$children = $current->contains('children', '1');
}
- return self::whereIn('id', $collect);
+ return self::query()->whereIn('id', $collect);
}
- public function scopeChildren(Builder $builder)
+ public function scopeChildren(Builder $builder) : Builder
{
$parents = $builder->pluck('id');
$collect = collect([]);
@@ -54,10 +54,10 @@ public function scopeChildren(Builder $builder)
$parents = $current->pluck('id');
$collect = $collect->merge($parents);
- return self::whereIn('id', $collect);
+ return self::query()->whereIn('id', $collect);
}
- public function parent()
+ public function parent() : \Illuminate\Database\Eloquent\Relations\HasOne
{
return $this->hasOne(self::class, 'id', 'parent');
}
diff --git a/src/Providers/AppServiceProvider.php b/src/Providers/AppServiceProvider.php
index ce18c5d..3deea49 100644
--- a/src/Providers/AppServiceProvider.php
+++ b/src/Providers/AppServiceProvider.php
@@ -2,6 +2,8 @@
namespace LisaFehr\Gallery\Providers;
+use Illuminate\Support\Facades\Storage;
+use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;
use LisaFehr\Gallery\Console\Commands\GenerateImages;
use LisaFehr\Gallery\Console\Commands\InstallCommand;
@@ -36,5 +38,13 @@ public function boot()
InstallCommand::class,
]);
}
+
+ Storage::disk('gallery')->buildTemporaryUrlsUsing(function ($path, $expiration, $options) {
+ return URL::temporarySignedRoute(
+ 'gallery.temp',
+ $expiration,
+ array_merge($options, ['path' => $path])
+ );
+ });
}
}
diff --git a/src/resources/js/components/gallery.vue b/src/resources/js/components/gallery.vue
index 814b388..7834688 100644
--- a/src/resources/js/components/gallery.vue
+++ b/src/resources/js/components/gallery.vue
@@ -3,7 +3,7 @@