Skip to content

Commit

Permalink
Merge pull request #189 from alimranahmed/187-cosmetic-changes-in-adm…
Browse files Browse the repository at this point in the history
…in-panel

#187: User photo and favicon can also be changed
  • Loading branch information
alimranahmed authored Sep 14, 2024
2 parents 860de0a + 0540ea7 commit bc27bf2
Show file tree
Hide file tree
Showing 17 changed files with 201 additions and 25 deletions.
21 changes: 17 additions & 4 deletions app/Http/Controllers/FileController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,30 @@

namespace App\Http\Controllers;

use App\Models\Config;
use App\Models\Image;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\BinaryFileResponse;

class FileController extends Controller
{
public function path($uuid): BinaryFileResponse
public function path(string $imageUuidOrConfigName): BinaryFileResponse
{
/** @var ?Image $image */
$image = Image::query()->where('uuid', $uuid)->firstOrFail();
/** @var ?Image $src */
$src = Image::query()
->where('uuid', $imageUuidOrConfigName)
->value('src');

return response()->download(Storage::path($image->src));
if ($src === null) {
$src = Config::query()
->where('name', $imageUuidOrConfigName)
->value('value');
}

if ($src == null) {
abort(404);
}

return response()->download(Storage::path($src));
}
}
91 changes: 91 additions & 0 deletions app/Livewire/Backend/Config/ImageForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

namespace App\Livewire\Backend\Config;

use App\Models\Config;
use Exception;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Storage;
use Livewire\Attributes\Validate;
use Livewire\Component;
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
use Livewire\WithFileUploads;

class ImageForm extends Component
{
use WithFileUploads;

#[Validate('nullable|file|mimes:ico,png,svg||max:200')] // 200MB
public ?TemporaryUploadedFile $favicon = null;

#[Validate('nullable|image|max:1024')] // 1MB
public ?TemporaryUploadedFile $user_photo = null;

public array $existingPaths;

public function mount(): void
{
$this->existingPaths = [
Config::FAVICON => Config::getPath(Config::FAVICON),
Config::USER_PHOTO => Config::getPath(Config::USER_PHOTO),
];
}

/**
* @throws \Exception
*/
public function saveConfigFile(string $configName): void
{
if ($this->{$configName} === null) {
return;
}

$this->validate();

if (! in_array($configName, [Config::FAVICON, Config::USER_PHOTO], true)) {
throw new Exception("Invalid config name: \"$configName\" for upload file.");
}

$this->deleteConfigMedia($configName);

$path = $this->{$configName}->storeAs(
path: 'configs',
name: "$configName.".$this->{$configName}->getClientOriginalExtension()
);

$this->insertConfig($configName, $path);

$this->redirect(route('backend.config.index'));
}

public function resetConfigFile(string $configName): void
{
Config::query()->where('name', $configName)->delete();
$this->deleteConfigMedia($configName);
$this->redirect(route('backend.config.index'));
}

private function deleteConfigMedia(string $configName): void
{
/** @var Config $config */
$config = Config::query()->where('name', $configName)->first();
if ($config) {
Storage::delete($config->value);
}
}

private function insertConfig($configName, string $path): void
{
Config::query()->updateOrCreate([
'name' => $configName,
], [
'value' => $path,
'is_media' => true,
]);
}

public function render(): View
{
return view('livewire.backend.config.image-form');
}
}
4 changes: 3 additions & 1 deletion app/Livewire/Backend/Config/Index.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ class Index extends Component

public function render(): View
{
$configs = Config::all();
$configs = Config::query()
->whereNotIn('name', [Config::FAVICON, Config::USER_PHOTO])
->get();

return view('livewire.backend.config.index', compact('configs'));
}
Expand Down
21 changes: 21 additions & 0 deletions app/Models/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Models;

use http\Exception\InvalidArgumentException;
use Illuminate\Database\Eloquent\Model;
use stdClass;

Expand All @@ -11,6 +12,10 @@
*/
class Config extends Model
{
public const FAVICON = 'favicon';

public const USER_PHOTO = 'user_photo';

protected $guarded = ['id'];

public static function get($name): ?string
Expand All @@ -28,4 +33,20 @@ public static function allFormatted($isActive = 1): stdClass

return $configs;
}

public static function getPath(string $name): string
{
$defaultPath = match ($name) {
self::FAVICON => asset('img/favicon.png'),
self::USER_PHOTO => asset('img/user.png'),
};

if ($defaultPath == null) {
throw new InvalidArgumentException('Invalid config name: '.$name);
}

$path = Config::query()->where('name', $name)->value('value');

return $path ? route('file', [$name]) : asset($defaultPath);
}
}
1 change: 1 addition & 0 deletions public/build/assets/app-Bk3J1bwy.css

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion public/build/assets/app-CfqnFTeb.css

This file was deleted.

2 changes: 1 addition & 1 deletion public/build/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"resources/css/app.css": {
"file": "assets/app-CfqnFTeb.css",
"file": "assets/app-Bk3J1bwy.css",
"src": "resources/css/app.css",
"isEntry": true
},
Expand Down
2 changes: 1 addition & 1 deletion resources/views/components/backend/form/button.blade.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@props(['type' => 'submit'])
<button type="{{$type}}"
wire:loading.attr="disabled" wire:loading.class="cursor-wait"
wire:loading.attr="disabled" wire:loading.class="cursor-wait animate-pulse"
{{$attributes->merge(['class' => 'block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600'])}}>
{{$slot}}
</button>
21 changes: 15 additions & 6 deletions resources/views/components/backend/navbar.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ class="bg-gray-800 flex text-sm rounded-full focus:outline-none focus:ring-2 foc
id="user-menu-button" aria-expanded="false" aria-haspopup="true">
<span class="sr-only">Open user menu</span>
<img class="h-8 w-8 rounded-full"
src="{{asset('img/user.png')}}"
alt="">
src="{{\App\Models\Config::getPath(\App\Models\Config::USER_PHOTO)}}"
alt="User's Photo">
</button>
</div>

Expand All @@ -60,16 +60,25 @@ class="bg-gray-800 flex text-sm rounded-full focus:outline-none focus:ring-2 foc
class="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg py-1 bg-white ring-1 ring-black ring-opacity-5 focus:outline-none"
role="menu" aria-orientation="vertical" aria-labelledby="user-menu-button" tabindex="-1">
<!-- Active: "bg-gray-100", Not Active: "" -->
<a href="{{route('user-profile')}}" class="block px-4 py-2 text-sm text-gray-700"
<a href="{{route('user-profile')}}"
wire:navigate
class="block px-4 py-2 text-sm text-gray-700"
role="menuitem" tabindex="-1"
id="user-menu-item-0">Your Profile</a>
<a href="{{route('backend.user.password.edit')}}"
class="block px-4 py-2 text-sm text-gray-700" role="menuitem" tabindex="-1"
wire:navigate
class="block px-4 py-2 text-sm text-gray-700"
role="menuitem" tabindex="-1"
id="user-menu-item-0">Change Password</a>
<a href="{{route('backend.config.index')}}" class="block px-4 py-2 text-sm text-gray-700"
<a href="{{route('backend.config.index')}}"
wire:navigate
class="block px-4 py-2 text-sm text-gray-700"
role="menuitem" tabindex="-1"
id="user-menu-item-1">Settings</a>
<a href="{{route('logout')}}" class="block px-4 py-2 text-sm text-gray-700" role="menuitem"
<a href="{{route('logout')}}"
wire:navigate
class="block px-4 py-2 text-sm text-gray-700"
role="menuitem"
tabindex="-1"
id="user-menu-item-2">Sign out</a>
</div>
Expand Down
2 changes: 1 addition & 1 deletion resources/views/components/frontend/header.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

@vite(['resources/css/app.css', 'resources/js/app.js'])

<link rel="shortcut icon" type="image/png" href="{{asset('img/favicon.png')}}"/>
<link rel="shortcut icon" type="image/png" href="{{\App\Models\Config::getPath(\App\Models\Config::FAVICON)}}"/>

<title>{{$title}}</title>

Expand Down
4 changes: 2 additions & 2 deletions resources/views/components/frontend/navbar.blade.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!--Medium Device-->
<div class="mb-0 py-2 justify-between items-center hidden md:flex">
<a href="/" class="flex items-center">
<img src="{{asset('img/user.png')}}" alt="logo" class="rounded-full h-10 w-10 object-cover object-center">
<img src="{{\App\Models\Config::getPath(\App\Models\Config::USER_PHOTO)}}" alt="logo" class="rounded-full h-10 w-10 object-cover object-center">
<div class="ml-4 font-semibold">Al Imran Ahmed</div>
</a>
<form action="{{route("search-article")}}">
Expand Down Expand Up @@ -32,7 +32,7 @@ class="px-2 text-blue-800 focus:outline-none rounded-r-full border-r border-t bo
<div class="flex justify-between items-center">

<a href="/" class="flex items-center">
<img src="{{asset('img/user.png')}}" alt="logo"
<img src="{{\App\Models\Config::getPath(\App\Models\Config::USER_PHOTO)}}" alt="logo"
class="rounded-full h-10 w-10 object-cover object-center">
<div class="ml-4 font-semibold">Al Imran Ahmed</div>
</a>
Expand Down
2 changes: 1 addition & 1 deletion resources/views/components/frontend/seo-meta.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
'author' => $article->user->name,
'title' => $article->heading,
'description' => \Illuminate\Support\Arr::get($article->meta, 'description', mb_substr($article->content, 0, 152).'...'),
'image' => \Illuminate\Support\Arr::get($article->meta, 'image_url', asset('img/user.png')),
'image' => \Illuminate\Support\Arr::get($article->meta, 'image_url', \App\Models\Config::getPath(\App\Models\Config::USER_PHOTO)),
'url' => route('get-article', $article->slug),
'site' => url('/'),
'site_name' => config('app.name'),
Expand Down
2 changes: 1 addition & 1 deletion resources/views/components/layouts/backend.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

@vite(['resources/css/app.css', 'resources/js/app.js'])

<link rel="shortcut icon" type="image/png" href="{{asset('img/favicon.png')}}"/>
<link rel="shortcut icon" type="image/png" href="{{\App\Models\Config::getPath(\App\Models\Config::FAVICON)}}"/>

<title>{{$globalConfigs->site_title}}</title>

Expand Down
2 changes: 1 addition & 1 deletion resources/views/frontend/pages/about.blade.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<x-layouts.frontend>
<div class="md:flex mt-10 pb-3 border-b">
<div class="w-1/2 md:w-1/3 text-center m-auto">
<img src="{{asset('img/user.png')}}"
<img src="{{\App\Models\Config::getPath(\App\Models\Config::USER_PHOTO)}}"
class="rounded-full"
alt="Al Imran Ahmed"/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class="text-xs py-1 px-1 rounded cursor-pointer bg-red-400 text-white hover:bg-r
</div>
@endforeach

<div class="text-green-600" wire:loading wire:target="image_file">
<div class="text-green-600 animate-pulse" wire:loading wire:target="image_file">
File is being uploaded...
</div>

Expand Down
39 changes: 39 additions & 0 deletions resources/views/livewire/backend/config/image-form.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
@php use App\Models\Config;use Illuminate\Support\Str; @endphp
<div>
<div class="flex">
@foreach([Config::FAVICON, Config::USER_PHOTO] as $file_name)
<form class="mr-3" wire:submit="saveConfigFile('{{$file_name}}')">
<div class="text-center">{{Str::title($file_name)}}</div>
<img src="{{${$file_name} ? ${$file_name}->temporaryUrl() : $existingPaths[$file_name] }}" class="w-32 h-32 bg-indigo-100 border p-1 rounded mb-2" alt="Favicon">

<label for="{{$file_name}}" class="cursor-pointer mt-1">
<input id="{{$file_name}}" type="file" wire:model="{{$file_name}}" class="sr-only"/>
<span class="text-slate-900 rounded px-2 leading-6 text-sm bg-indigo-300 hover:bg-indigo-400 py-1">Change</span>
</label>

@if(${$file_name} && !$errors->has('file_name'))
<button class="text-slate-900 rounded px-2 leading-6 text-sm bg-green-300 hover:bg-green-400"
wire:target="saveFavicon"
wire:loading.attr="disabled"
wire:loading.class="cursor-wait animate-pulse">Save
</button>
@else
<span class="text-slate-900 rounded px-2 leading-6 text-sm bg-red-300 hover:bg-red-400 py-1 cursor-pointer"
wire:target="resetConfigFile"
wire:loading.attr="disabled"
wire:loading.class="cursor-wait animate-pulse"
wire:click="resetConfigFile('{{$file_name}}')"
>Reset</span>
@endif
</form>
@endforeach
</div>

@error('favicon')
<div class="text-red-500 text-sm italic">{{ $message }}</div>
@enderror

@error('user_photo')
<div class="text-red-500 text-sm italic">{{ $message }}</div>
@enderror
</div>
9 changes: 5 additions & 4 deletions resources/views/livewire/backend/config/index.blade.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<div>
<livewire:backend.config.image-form/>
<x-backend.table>
<x-slot name="head">
<x-backend.table.th>Name</x-backend.table.th>
Expand All @@ -9,15 +10,15 @@
@foreach($configs as $config)
<tr>
@if($editingConfig && $editingConfig['id'] == $config->id)
<form>
<form wire:key="{{$config->id}}">
<x-backend.table.td>
<x-backend.form.input wire:model="editingConfig.name" name="config.name" disabled></x-backend.form.input>
<x-backend.form.input wire:model="editingConfig.name" name="config.name" disabled/>
</x-backend.table.td>
<x-backend.table.td>
<x-backend.form.input wire:model="editingConfig.value" name="config.name"></x-backend.form.input>
<x-backend.form.input wire:model="editingConfig.value" name="config.name"/>
</x-backend.table.td>
<x-backend.table.td>
<x-backend.form.button wire:click="update({{$config}})">Update</x-backend.form.button>
<x-backend.form.button wire:click="update()">Update</x-backend.form.button>
</x-backend.table.td>
</form>
@else
Expand Down

0 comments on commit bc27bf2

Please sign in to comment.