diff --git a/app/Domains/Dashboard/Controllers/DashboardController.php b/app/Domains/Dashboard/Controllers/DashboardController.php new file mode 100644 index 0000000..c37456b --- /dev/null +++ b/app/Domains/Dashboard/Controllers/DashboardController.php @@ -0,0 +1,32 @@ +checkAuth()) { + return $this->renderForLoggedInUser($request); + } + + return redirect()->intended('/login'); + + dd('U'); + return $this->renderForGuest($request); + + } + + private function renderForLoggedInUser(Request $request) { + $authCheckProvider = new AuthCheckProvider; + $inertiaProvider = new InertiaProvider('Dashboard/Dashboard', ['appName' => app('tenant')->name]); + return $inertiaProvider->render(); + } + + private function renderForGuest(Request $request) { + } +} diff --git a/app/Domains/Dashboard/Views/Dashboard.vue b/app/Domains/Dashboard/Views/Dashboard.vue new file mode 100644 index 0000000..5d0b9d7 --- /dev/null +++ b/app/Domains/Dashboard/Views/Dashboard.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/app/Domains/UserManagement/Controllers/LogOutController.php b/app/Domains/UserManagement/Controllers/LogOutController.php new file mode 100644 index 0000000..3b4456b --- /dev/null +++ b/app/Domains/UserManagement/Controllers/LogOutController.php @@ -0,0 +1,21 @@ +session()->invalidate(); + + // CSRF-Token regenerieren (für Sicherheit) + $request->session()->regenerateToken(); + + // Redirect z.B. zur Login-Seite + return redirect()->intended('/')->with('status', 'Erfolgreich abgemeldet!'); + } +} diff --git a/app/Domains/UserManagement/Controllers/LoginController.php b/app/Domains/UserManagement/Controllers/LoginController.php new file mode 100644 index 0000000..640cbde --- /dev/null +++ b/app/Domains/UserManagement/Controllers/LoginController.php @@ -0,0 +1,51 @@ +session()->has('errors')) { + $errors = $request->session()->get('errors')->getBag('default')->getMessages(); + } + + + $inertiaProvider = new InertiaProvider('UserManagement/Login', ['errors' => $errors, 'appName' => app('tenant')->name]); + return $inertiaProvider->render(); + } + + public function doLogin(Request $request) + { + + $credentials = $request->validate([ + 'username' => ['required', 'string'], + 'password' => ['required'], + ], + [ + 'username.required' => 'Bitte gib deinen Anmeldenamen ein.', + 'username.string' => 'Der Anmeldename muss eine E-Mail-Adresse sein.', + 'password.required' => 'Bitte gib dein Passwort ein.', + ]); + + #$credentials = ['username' => 'development', 'password' => 'development']; + + if (!Auth::attempt($credentials)) { + return back()->withErrors([ + 'username' => 'Diese Zugangsdaten sind ungültig.', + ]); + } + + $request->session()->regenerate(); + $user = Auth::user(); + + +# dd($user->firstname . ' ' . $user->lastname); + + return redirect()->intended('/'); + } +} diff --git a/app/Domains/UserManagement/Views/Login.vue b/app/Domains/UserManagement/Views/Login.vue new file mode 100644 index 0000000..0616102 --- /dev/null +++ b/app/Domains/UserManagement/Views/Login.vue @@ -0,0 +1,64 @@ + + + + + diff --git a/app/Http/Controllers/TestRenderInertiaProvider.php b/app/Http/Controllers/TestRenderInertiaProvider.php new file mode 100644 index 0000000..8e30566 --- /dev/null +++ b/app/Http/Controllers/TestRenderInertiaProvider.php @@ -0,0 +1,13 @@ + app('tenant')->name]); + return $inertiaProvider->render(); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 04308d2..f93e9d6 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -38,6 +38,7 @@ class User extends Authenticatable 'first_aid_permission', 'bank_account_iban', 'password', + 'active', ]; /** diff --git a/app/Providers/AuthCheckProvider.php b/app/Providers/AuthCheckProvider.php new file mode 100644 index 0000000..c93b018 --- /dev/null +++ b/app/Providers/AuthCheckProvider.php @@ -0,0 +1,23 @@ +check()) { + return false; + } + + $user = auth()->user(); + $tenant = app('tenant'); + return $user->active && $tenant->slug === $user->tenant; + } + + public function getUserRole() : ?string { + if (!$this->checkLoggedIn()) { + return null; + } + + return auth()->user()->user_role; + } +} diff --git a/app/Providers/InertiaProvider.php b/app/Providers/InertiaProvider.php index e4cf233..49be165 100644 --- a/app/Providers/InertiaProvider.php +++ b/app/Providers/InertiaProvider.php @@ -2,6 +2,7 @@ namespace App\Providers; +use App\Models\User; use Inertia\Inertia; use Inertia\Response; @@ -10,17 +11,43 @@ final class InertiaProvider private string $vueFile; private array $props; + private ?User $user; + public function __construct(string $vueFile, array $props) { + $this->user = auth()->user(); $this->vueFile = $vueFile; $this->props = $props; - } - public function render() : Response { + $this->props['navbar'] = $this->generateNavbar(); + $this->props['tenant'] = app('tenant')->local_group_name; + $this->props['user'] = $this->user; + $this->props['currentPath'] = request()->path(); + return Inertia::render( str_replace('/', '/Views/', $this->vueFile), $this->props ); } + + private function generateNavbar() : array { + $navigation = [ + 'personal' => [], + 'common' => [], + 'costunits' => [], + 'events' => [], + ]; + + $navigation['personal'][] = ['url' => '/', 'display' => 'Home']; + if (null !== $this->user) { + $navigation['personal'][] = ['url' => '/personal-data', 'display' => 'Meine Daten']; + $navigation['personal'][] = ['url' => '/messages', 'display' => 'Meine Nachrichten']; + } + + $navigation['common'][] = ['url' => '/capture-invoice', 'display' => 'Neue Abrechnung']; + $navigation['common'][] = ['url' => '/available-events', 'display' => 'Verfügbare Veranstaltungen']; + + return $navigation; + } } diff --git a/app/Providers/TenantUserProvider.php b/app/Providers/TenantUserProvider.php index 51702b9..c15b9cc 100644 --- a/app/Providers/TenantUserProvider.php +++ b/app/Providers/TenantUserProvider.php @@ -16,7 +16,11 @@ class TenantUserProvider extends EloquentUserProvider } } - $query->where('tenant', app('tenant')->slug); + $query->where([ + 'tenant' => app('tenant')->slug, + 'active' => true + + ]); return $query->first(); } diff --git a/app/Scopes/CommonController.php b/app/Scopes/CommonController.php new file mode 100644 index 0000000..18f4c94 --- /dev/null +++ b/app/Scopes/CommonController.php @@ -0,0 +1,12 @@ +checkLoggedIn(); + } +} diff --git a/app/Views/Components/Icon.vue b/app/Views/Components/Icon.vue new file mode 100644 index 0000000..24996a4 --- /dev/null +++ b/app/Views/Components/Icon.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/Views/Components/ShadowedBox.vue b/app/Views/Components/ShadowedBox.vue new file mode 100644 index 0000000..e81fa41 --- /dev/null +++ b/app/Views/Components/ShadowedBox.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/app/Views/Partials/GlobalWidgets/GlobalWidgets.vue b/app/Views/Partials/GlobalWidgets/GlobalWidgets.vue new file mode 100644 index 0000000..268200f --- /dev/null +++ b/app/Views/Partials/GlobalWidgets/GlobalWidgets.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/config/session.php b/config/session.php index 5b541b7..cac7a5b 100644 --- a/config/session.php +++ b/config/session.php @@ -32,7 +32,7 @@ return [ | */ - 'lifetime' => (int) env('SESSION_LIFETIME', 120), + 'lifetime' => (int) env('SESSION_LIFETIME', 43200), // 30 days 'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false), diff --git a/database/migrations/2026_01_30_140002_create_users_table.php b/database/migrations/2026_01_30_140002_create_users_table.php index 5833b76..b745d24 100644 --- a/database/migrations/2026_01_30_140002_create_users_table.php +++ b/database/migrations/2026_01_30_140002_create_users_table.php @@ -62,7 +62,7 @@ return new class extends Migration $table->string('first_aid_permission')->nullable(); $table->string('bank_account_iban')->nullable(); $table->string('activation_token')->nullable(); - $table->boolean('activated')->default(false); + $table->boolean('active')->default(false); $table->foreign('tenant')->references('slug')->on('tenants')->cascadeOnDelete()->cascadeOnUpdate(); $table->foreign('user_role')->references('slug')->on('user_roles')->cascadeOnDelete()->cascadeOnUpdate(); diff --git a/docker-compose.dev b/docker-compose.dev index 6a7134d..ea842a7 100644 --- a/docker-compose.dev +++ b/docker-compose.dev @@ -48,6 +48,11 @@ services: sh -c " npm install && npm install vue3-toastify && npm install @inertiajs/progress && npm install @inertiajs/progress && + npm install @fortawesome/fontawesome-svg-core && + npm install @fortawesome/free-solid-svg-icons && + npm install @fortawesome/vue-fontawesome@latest && + + while true; do npm run build echo 'Vite Dev-Server beendet. Neustart in 3 Sekunden...' diff --git a/docker/nginx/default.conf b/docker/nginx/default.conf index c16a27b..52e8b16 100644 --- a/docker/nginx/default.conf +++ b/docker/nginx/default.conf @@ -29,6 +29,17 @@ server { fastcgi_pass mareike-app:9000; # Containername vom PHP-FPM fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - } + } + + # In der Nginx-Konfiguration von mareike.local + location /build/assets/ { + # Erlaubt explizit deine Subdomain + add_header 'Access-Control-Allow-Origin' "$http_origin" always; + add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'Content-Type, X-Inertia' always; + + # Falls du alle Subdomains von mareike.local erlauben willst: + # + } } diff --git a/package-lock.json b/package-lock.json index bf4ce3c..7cc4a6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,9 @@ "packages": { "": { "dependencies": { + "@fortawesome/fontawesome-svg-core": "^7.1.0", + "@fortawesome/free-solid-svg-icons": "^7.1.0", + "@fortawesome/vue-fontawesome": "^3.1.3", "@inertiajs/progress": "^0.2.7", "@inertiajs/vue3": "^2.3.12", "vue": "^3.5.27", @@ -13,10 +16,12 @@ "devDependencies": { "@tailwindcss/vite": "^4.0.0", "@vitejs/plugin-vue": "^6.0.3", + "autoprefixer": "^10.4.24", "axios": "^1.11.0", "concurrently": "^9.0.1", "laravel-vite-plugin": "^2.0.0", - "tailwindcss": "^4.0.0", + "postcss": "^8.5.6", + "tailwindcss": "^4.1.18", "vite": "^7.0.7" } }, @@ -508,6 +513,49 @@ "node": ">=18" } }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-7.1.0.tgz", + "integrity": "sha512-l/BQM7fYntsCI//du+6sEnHOP6a74UixFyOYUyz2DLMXKx+6DEhfR3F2NYGE45XH1JJuIamacb4IZs9S0ZOWLA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.1.0.tgz", + "integrity": "sha512-fNxRUk1KhjSbnbuBxlWSnBLKLBNun52ZBTcs22H/xEEzM6Ap81ZFTQ4bZBxVQGQgVY0xugKGoRcCbaKjLQ3XZA==", + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-common-types": "7.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-7.1.0.tgz", + "integrity": "sha512-Udu3K7SzAo9N013qt7qmm22/wo2hADdheXtBfxFTecp+ogsc0caQNRKEb7pkvvagUGOpG9wJC1ViH6WXs8oXIA==", + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "7.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/vue-fontawesome": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-3.1.3.tgz", + "integrity": "sha512-OHHUTLPEzdwP8kcYIzhioUdUOjZ4zzmi+midwa4bqscza4OJCOvTKJEHkXNz8PgZ23kWci1HkKVX0bm8f9t9gQ==", + "license": "MIT", + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6 || ~7", + "vue": ">= 3.0.0 < 4" + } + }, "node_modules/@inertiajs/core": { "version": "2.3.12", "resolved": "https://registry.npmjs.org/@inertiajs/core/-/core-2.3.12.tgz", @@ -1421,6 +1469,43 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/autoprefixer": { + "version": "10.4.24", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", + "integrity": "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001766", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/axios": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.4.tgz", @@ -1432,6 +1517,50 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -1461,6 +1590,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/caniuse-lite": { + "version": "1.0.30001766", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz", + "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1612,6 +1762,13 @@ "node": ">= 0.4" } }, + "node_modules/electron-to-chromium": { + "version": "1.5.283", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.283.tgz", + "integrity": "sha512-3vifjt1HgrGW/h76UEeny+adYApveS9dH2h3p57JYzBSXJIKUJAvtmIytDKjcSCt9xHfrNCFJ7gts6vkhuq++w==", + "dev": true, + "license": "ISC" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -1802,6 +1959,20 @@ "node": ">= 6" } }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -2315,6 +2486,13 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, "node_modules/nprogress": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", @@ -2380,6 +2558,13 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -2659,6 +2844,37 @@ "dev": true, "license": "0BSD" }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/vite": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", diff --git a/package.json b/package.json index 457f442..b9b69b2 100644 --- a/package.json +++ b/package.json @@ -10,13 +10,18 @@ "devDependencies": { "@tailwindcss/vite": "^4.0.0", "@vitejs/plugin-vue": "^6.0.3", + "autoprefixer": "^10.4.24", "axios": "^1.11.0", "concurrently": "^9.0.1", "laravel-vite-plugin": "^2.0.0", - "tailwindcss": "^4.0.0", + "postcss": "^8.5.6", + "tailwindcss": "^4.1.18", "vite": "^7.0.7" }, "dependencies": { + "@fortawesome/fontawesome-svg-core": "^7.1.0", + "@fortawesome/free-solid-svg-icons": "^7.1.0", + "@fortawesome/vue-fontawesome": "^3.1.3", "@inertiajs/progress": "^0.2.7", "@inertiajs/vue3": "^2.3.12", "vue": "^3.5.27", diff --git a/public/css/app.css b/public/css/app.css new file mode 100644 index 0000000..fc27ddc --- /dev/null +++ b/public/css/app.css @@ -0,0 +1,125 @@ +@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; +@source '../../storage/framework/views/*.php'; +@source '../**/*.blade.php'; +@source '../**/*.js'; + +html { + background-color: #FAFAFB !important; +} + +.content { + padding: 50px 0px; +} + +.main { + margin: 0 auto; + box-shadow: 20px 54px 15px rgba(0, 0, 0, 0.1); + border-radius: 0 10px 0 0; + flex: 1; + display: flex; + flex-direction: column; + overflow: hidden; +} + +.header { + height: 80px; /* Höhe anpassen */ + align-items: center; + justify-content: space-between; + width: calc(100% - 40px); + +} + +.header .anonymous-actions { + position: relative; + right: calc(-100% + 330px); + width: 350px; + overflow: hidden; + border-radius: 50px 0 0 50px; + background-color: #FAFAFB !important; + text-align: right; + padding: 10px; + top: -75px; +} + +.header .user-info { + position: relative; + right: calc(-100% + 275px); + width: 295px; + overflow: hidden; + border-radius: 50px 0 0 50px; + background-color: #FAFAFB !important; + text-align: right; + padding: 10px; + top: -75px; +} + +.header .left-side { + height: 75px; + background: #ffffff; + align-content: center; + padding: 0 50px; + box-shadow: 0 1px 3px rgba(0,0,0,0.1); + width: 100%; + margin-top: -5px; + +} + +.flexbox { + display: flex; + background-color: #FAFAFB; + height: 100%; + padding: 0; + gap: 1px; + margin: 0; + + +} + +/* Layout */ +.app-layout { + display: flex; + height: 95vh; + margin: 20px; + background: #f0f2f5; + font-family: sans-serif; +} + +.sidebar { + flex-basis:275px; + box-shadow: 2px 0 5px rgba(0,0,0,0.1); + display: flex; + flex-direction: column; + height: 100%; + background-color: #ffffff !important; +} + +.logo { + display: flex; + align-items: center; + justify-content: center; +} + +.logo img { + width: 135px !important; + height: 70px !important; +} + +.footer { + height: 40px; + background: #666666; + border-top: 1px solid #ddd; + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + color: #ffffff; +} + +th { + text-align: left; + padding-right: 1em; +} + +th:after { + content: ":"; +} diff --git a/public/css/elements.css b/public/css/elements.css new file mode 100644 index 0000000..56e0e27 --- /dev/null +++ b/public/css/elements.css @@ -0,0 +1,47 @@ +/* Toaster */ +.toaster { + position: fixed; + bottom: 20px; + right: 20px; + background: #4caf50; + color: #fff; + padding: 12px 20px; + border-radius: 6px; + box-shadow: 0 2px 8px rgba(0,0,0,0.2); +} + +input[type="text"], +input[type="email"], +input[type="password"] { + width: 100%; + font-size: 13pt; + padding: 5px; + border: 1px solid #ccc; + border-radius: 5px; + color: #656363; +} + +input[type="text"]:focus, +input[type="email"]:focus, +input[type="password"]:focus { + outline: none; + border-color: #1d4899; +} + + +table { + width: 100%; +} + +button, input[type="submit"] { + cursor: pointer; + background-color: #ffffff; + border: 1px solid #809dd5 !important; + padding: 10px 20px; + font-weight: bold; +} + +button:hover, input[type="submit"]:hover { + background-color: #1d4899; + color: #ffffff; +} diff --git a/public/images/logo.png b/public/images/logo.png new file mode 100644 index 0000000..38a9503 Binary files /dev/null and b/public/images/logo.png differ diff --git a/resources/css/app.css b/resources/css/app.css deleted file mode 100644 index 3e6abea..0000000 --- a/resources/css/app.css +++ /dev/null @@ -1,11 +0,0 @@ -@import 'tailwindcss'; - -@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; -@source '../../storage/framework/views/*.php'; -@source '../**/*.blade.php'; -@source '../**/*.js'; - -@theme { - --font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol', 'Noto Color Emoji'; -} diff --git a/resources/js/app.js b/resources/js/app.js index 05e5ddc..4ac41e8 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -5,6 +5,15 @@ import { InertiaProgress } from '@inertiajs/progress' import Vue3Toastify, { toast } from 'vue3-toastify' import 'vue3-toastify/dist/index.css' +import { library } from '@fortawesome/fontawesome-svg-core' +import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' + +// Icons importieren +import { faUser, faTrash, faCheck } from '@fortawesome/free-solid-svg-icons' + +library.add(faUser, faTrash, faCheck) + + InertiaProgress.init() createInertiaApp({ @@ -24,12 +33,28 @@ createInertiaApp({ const vueApp = createApp({ render: () => h(App, props) }) vueApp.use(plugin) + + vueApp.component('font-awesome-icon', FontAwesomeIcon) + vueApp.use(Vue3Toastify, { - autoClose: 3000, - position: 'top-right', + autoClose: 10000, + position: 'bottom-right', pauseOnHover: true, + hideProgressBar: false, // Progressbar anzeigen + toastDefaults: { + success: { + style: {background: '#4caf50', color: '#fff'}, // grün + progressStyle: {background: '#2e7d32', height: '4px'}, + }, + error: { + style: {background: '#f44336', color: '#fff'}, // rot + progressStyle: {background: '#c62828', height: '4px'}, + }, + }, }) + + vueApp.config.globalProperties.$toast = toast vueApp.mount(el) }, diff --git a/resources/js/layouts/AppLayout.vue b/resources/js/layouts/AppLayout.vue new file mode 100644 index 0000000..e2c85af --- /dev/null +++ b/resources/js/layouts/AppLayout.vue @@ -0,0 +1,195 @@ + + + + + diff --git a/resources/views/app.blade.php b/resources/views/app.blade.php index ec72952..d63bb32 100644 --- a/resources/views/app.blade.php +++ b/resources/views/app.blade.php @@ -1,10 +1,19 @@ + + + + + + + + @vite('resources/js/app.js') + @inertiaHead diff --git a/routes/web.php b/routes/web.php index 5b73edb..c85a4b6 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,16 +1,39 @@ group(function () { + Route::get('/', DashboardController::class); + + + + Route::middleware(['auth'])->group(function () { + + Route::get('/messages', fn () => inertia('Messages')); + Route::post('/logout', [LogoutController::class, 'logout']); + + }); + + + + + + + + route::get('/logout', LogOutController::class); + route::post('/login', [LoginController::class, 'doLogin']); + route::get('/login', [LoginController::class, 'loginForm']); + + + Route::get('/messages', [TestRenderInertiaProvider::class, 'index']); }); -Route::get('/inertia', function () { - return Inertia::render('Pages/Home', [ - 'appName' => config('app.name'), - ]); -}); + diff --git a/vite.config.js b/vite.config.js index 7ae0d0b..08e87b7 100644 --- a/vite.config.js +++ b/vite.config.js @@ -4,6 +4,7 @@ import laravel from 'laravel-vite-plugin' import path from 'path' export default defineConfig({ + base: '', plugins: [ laravel({ input: 'resources/js/app.js', @@ -18,4 +19,9 @@ export default defineConfig({ '@domains': path.resolve(__dirname, 'app/Domains'), }, }, + server: { + host: true, // Dev-Server auch über Subdomains erreichbar + strictPort: true, // verhindert zufällige Portwechsel + cors: true, // erlaubt Dev-HMR über Subdomains + }, })