fix: Add Livewire config and custom 404 page for subdirectory support

- Add config/livewire.php with app_url and asset_url settings
- Add custom 404 error page with consistent design
- Add error translations for all 8 languages

For subdirectory deployment:
1. Set APP_URL to include subdirectory (e.g., https://example.com/kb)
2. Set ASSET_URL if using CDN
3. Clear config cache after deployment
This commit is contained in:
2025-11-29 17:27:40 +09:00
parent ac56889a87
commit 9625268e67
10 changed files with 209 additions and 0 deletions

114
src/config/livewire.php Normal file
View File

@@ -0,0 +1,114 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Livewire Assets URL
|--------------------------------------------------------------------------
|
| This value sets the path to Livewire JavaScript assets, for cases where
| your app's domain root is not the correct path. By default, Livewire
| will load its JavaScript assets from the app's "relative root".
|
| Examples: "/assets", "myurl.com/app".
|
*/
'asset_url' => env('ASSET_URL'),
/*
|--------------------------------------------------------------------------
| Livewire App URL
|--------------------------------------------------------------------------
|
| This value should be used if livewire assets are served from CDN.
| Livewire will communicate with an app through this url.
|
| Examples: "https://my-app.com", "myurl.com/app".
|
*/
'app_url' => env('APP_URL'),
/*
|--------------------------------------------------------------------------
| Livewire Endpoint Middleware Group
|--------------------------------------------------------------------------
|
| This value sets the middleware group that will be applied to the main
| Livewire "message" endpoint (the endpoint that gets hit everytime
| a Livewire component updates). It is set to "web" by default.
|
*/
'middleware_group' => 'web',
/*
|--------------------------------------------------------------------------
| Livewire Temporary File Uploads Endpoint Configuration
|--------------------------------------------------------------------------
|
| Livewire handles file uploads by storing uploads in a temporary directory
| before the file is stored permanently. All file uploads are directed
| to a global endpoint for temporary storage. Here you may configure.
|
*/
'temporary_file_upload' => [
'disk' => null,
'rules' => null,
'directory' => null,
'middleware' => null,
'preview_mimes' => [
'png', 'gif', 'bmp', 'svg', 'wav', 'mp4',
'mov', 'avi', 'wmv', 'mp3', 'm4a',
'jpg', 'jpeg', 'mpga', 'webp', 'wma',
],
'max_upload_time' => 5,
'cleanup' => true,
],
/*
|--------------------------------------------------------------------------
| Render On Redirect
|--------------------------------------------------------------------------
|
| This value determines if Livewire will render before it's redirected
| or not. Setting it to "false" will mean the render method is skipped
| when performing a redirect, potentially improving performances.
|
*/
'render_on_redirect' => false,
/*
|--------------------------------------------------------------------------
| Navigate (SPA mode)
|--------------------------------------------------------------------------
|
| By default, Livewire uses the "replace" strategy for SPA navigation
| which can sometimes cause issues with subdirectory deployments.
|
*/
'navigate' => [
'show_progress_bar' => true,
'progress_bar_color' => '#2299dd',
],
/*
|--------------------------------------------------------------------------
| Inject Assets
|--------------------------------------------------------------------------
|
| By default, Livewire automatically injects its JavaScript and styles
| into the <head> and <body> of your pages. If you want to disable
| this behavior and manually include assets, set this to false.
|
*/
'inject_assets' => true,
];

View File

@@ -115,6 +115,14 @@
'already_registered' => 'Bereits registriert?', 'already_registered' => 'Bereits registriert?',
], ],
// Errors
'errors' => [
'404_title' => 'Seite nicht gefunden',
'page_not_found' => 'Seite nicht gefunden',
'page_not_found_description' => 'Die gesuchte Seite konnte nicht gefunden werden.',
'back_to_home' => 'Zurück zur Startseite',
],
// Profile // Profile
'profile' => [ 'profile' => [
'title' => 'Profil', 'title' => 'Profil',

View File

@@ -115,6 +115,14 @@
'already_registered' => 'Already registered?', 'already_registered' => 'Already registered?',
], ],
// Errors
'errors' => [
'404_title' => 'Page Not Found',
'page_not_found' => 'Page Not Found',
'page_not_found_description' => 'The page you are looking for could not be found.',
'back_to_home' => 'Back to Home',
],
// Profile // Profile
'profile' => [ 'profile' => [
'title' => 'Profile', 'title' => 'Profile',

View File

@@ -115,6 +115,14 @@
'already_registered' => '¿Ya está registrado?', 'already_registered' => '¿Ya está registrado?',
], ],
// Errors
'errors' => [
'404_title' => 'Página no encontrada',
'page_not_found' => 'Página no encontrada',
'page_not_found_description' => 'No se pudo encontrar la página que está buscando.',
'back_to_home' => 'Volver al inicio',
],
// Profile // Profile
'profile' => [ 'profile' => [
'title' => 'Perfil', 'title' => 'Perfil',

View File

@@ -115,6 +115,14 @@
'already_registered' => 'Déjà inscrit ?', 'already_registered' => 'Déjà inscrit ?',
], ],
// Errors
'errors' => [
'404_title' => 'Page non trouvée',
'page_not_found' => 'Page non trouvée',
'page_not_found_description' => 'La page que vous recherchez est introuvable.',
'back_to_home' => 'Retour à l\'accueil',
],
// Profile // Profile
'profile' => [ 'profile' => [
'title' => 'Profil', 'title' => 'Profil',

View File

@@ -115,6 +115,14 @@
'already_registered' => '既にアカウントをお持ちですか?', 'already_registered' => '既にアカウントをお持ちですか?',
], ],
// Errors
'errors' => [
'404_title' => 'ページが見つかりません',
'page_not_found' => 'ページが見つかりません',
'page_not_found_description' => 'お探しのページは見つかりませんでした。',
'back_to_home' => 'ホームに戻る',
],
// Profile // Profile
'profile' => [ 'profile' => [
'title' => 'プロフィール', 'title' => 'プロフィール',

View File

@@ -115,6 +115,14 @@
'already_registered' => '이미 계정이 있으신가요?', 'already_registered' => '이미 계정이 있으신가요?',
], ],
// Errors
'errors' => [
'404_title' => '페이지를 찾을 수 없습니다',
'page_not_found' => '페이지를 찾을 수 없습니다',
'page_not_found_description' => '찾고 계신 페이지를 찾을 수 없습니다.',
'back_to_home' => '홈으로 돌아가기',
],
// Profile // Profile
'profile' => [ 'profile' => [
'title' => '프로필', 'title' => '프로필',

View File

@@ -115,6 +115,14 @@
'already_registered' => '已有账号?', 'already_registered' => '已有账号?',
], ],
// Errors
'errors' => [
'404_title' => '页面未找到',
'page_not_found' => '页面未找到',
'page_not_found_description' => '您要查找的页面不存在。',
'back_to_home' => '返回首页',
],
// Profile // Profile
'profile' => [ 'profile' => [
'title' => '个人资料', 'title' => '个人资料',

View File

@@ -115,6 +115,14 @@
'already_registered' => '已有帳號?', 'already_registered' => '已有帳號?',
], ],
// Errors
'errors' => [
'404_title' => '頁面未找到',
'page_not_found' => '頁面未找到',
'page_not_found_description' => '您要查找的頁面不存在。',
'back_to_home' => '返回首頁',
],
// Profile // Profile
'profile' => [ 'profile' => [
'title' => '個人資料', 'title' => '個人資料',

View File

@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ __('messages.errors.404_title') }} - {{ config('app.name') }}</title>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="font-sans antialiased">
<div class="min-h-screen bg-gray-100 flex flex-col items-center justify-center">
<div class="text-center">
<h1 class="text-9xl font-bold text-gray-300">404</h1>
<h2 class="text-2xl font-semibold text-gray-700 mt-4">
{{ __('messages.errors.page_not_found') }}
</h2>
<p class="text-gray-500 mt-2">
{{ __('messages.errors.page_not_found_description') }}
</p>
<div class="mt-8">
<a href="{{ url('/') }}" class="inline-flex items-center px-6 py-3 bg-indigo-600 text-white font-medium rounded-md hover:bg-indigo-700 transition">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path>
</svg>
{{ __('messages.errors.back_to_home') }}
</a>
</div>
</div>
</div>
</body>
</html>