From cb234b17ac70ba29500fffaf0f9f48a842dcd920 Mon Sep 17 00:00:00 2001 From: sindoring Date: Sun, 26 Jul 2026 21:09:32 +0400 Subject: [PATCH] =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=BE=D1=81=D1=82=D0=B8=20+?= =?UTF-8?q?=20=D0=BF=D0=B5=D1=80=D0=B5=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA?= =?UTF-8?q?=D0=B0=20=D1=82=D0=B5=D0=BA=D1=81=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 8 +- .../Concerns/BuildsPortalProps.php | 1 + app/Http/Controllers/LandingController.php | 17 +- app/Http/Controllers/NewsController.php | 73 +++ app/Services/NewsService.php | 5 +- config/moonwell.php | 6 +- package-lock.json | 578 ------------------ package.json | 3 - resources/css/moonwell.css | 349 +++++++++++ resources/js/Components/SiteFooter.vue | 1 + resources/js/Components/SiteHeader.vue | 3 + .../js/Pages/Landing/Components/About.vue | 12 +- .../js/Pages/Landing/Components/Features.vue | 6 +- .../js/Pages/Landing/Components/Footer.vue | 18 +- .../js/Pages/Landing/Components/Hero.vue | 19 +- .../js/Pages/Landing/Components/Join.vue | 6 +- resources/js/Pages/Landing/Components/Nav.vue | 10 +- .../js/Pages/Landing/Components/News.vue | 21 +- .../js/Pages/Landing/Components/symbols.js | 22 +- resources/js/Pages/Landing/Main.vue | 12 +- resources/js/Pages/News/Index.vue | 84 +++ resources/js/Pages/News/Show.vue | 83 +++ resources/js/moonwell/About.jsx | 38 -- resources/js/moonwell/App.jsx | 46 -- resources/js/moonwell/Background.jsx | 92 --- resources/js/moonwell/Features.jsx | 151 ----- resources/js/moonwell/Footer.jsx | 87 --- resources/js/moonwell/Hero.jsx | 45 -- resources/js/moonwell/Join.jsx | 325 ---------- resources/js/moonwell/Nav.jsx | 118 ---- resources/js/moonwell/News.jsx | 90 --- resources/js/moonwell/Realm.jsx | 58 -- resources/js/moonwell/Tweaks.jsx | 84 --- resources/js/moonwell/atoms.jsx | 111 ---- resources/js/moonwell/main.jsx | 8 - resources/views/app.blade.php | 4 + resources/views/landing.blade.php | 32 - routes/web.php | 15 +- tests/Feature/LandingPageTest.php | 4 +- tests/Feature/PublicNewsFeatureTest.php | 101 +++ vite.config.js | 2 - 41 files changed, 809 insertions(+), 1939 deletions(-) create mode 100644 app/Http/Controllers/NewsController.php create mode 100644 resources/js/Pages/News/Index.vue create mode 100644 resources/js/Pages/News/Show.vue delete mode 100644 resources/js/moonwell/About.jsx delete mode 100644 resources/js/moonwell/App.jsx delete mode 100644 resources/js/moonwell/Background.jsx delete mode 100644 resources/js/moonwell/Features.jsx delete mode 100644 resources/js/moonwell/Footer.jsx delete mode 100644 resources/js/moonwell/Hero.jsx delete mode 100644 resources/js/moonwell/Join.jsx delete mode 100644 resources/js/moonwell/Nav.jsx delete mode 100644 resources/js/moonwell/News.jsx delete mode 100644 resources/js/moonwell/Realm.jsx delete mode 100644 resources/js/moonwell/Tweaks.jsx delete mode 100644 resources/js/moonwell/atoms.jsx delete mode 100644 resources/js/moonwell/main.jsx delete mode 100644 resources/views/landing.blade.php create mode 100644 tests/Feature/PublicNewsFeatureTest.php diff --git a/.env.example b/.env.example index 635ea3a..9a4308f 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,4 @@ -APP_NAME=Moonwell +APP_NAME=MoonWell APP_ENV=local APP_KEY= APP_DEBUG=true @@ -110,9 +110,9 @@ MOONWELL_ADMIN_MIN_GMLEVEL=3 MOONWELL_ADMIN_ACCESS_COMMENT="updated via moonwell-web admin" MOONWELL_BOT_ACCOUNT_PREFIX=RNDBOT -MOONWELL_SERVER_NAME=Moonwell -MOONWELL_REALM_NAME=Moonwell -MOONWELL_SERVER_TAGLINE="Русскоязычный WotLK-сервер с прогрессией и комфортным PvE" +MOONWELL_SERVER_NAME=MoonWell +MOONWELL_REALM_NAME=MoonWell +MOONWELL_SERVER_TAGLINE="Пройди историю Азерота — от Классики до Короля-лича — в своём темпе, в одиночку или с небольшим отрядом." MOONWELL_CLIENT_VERSION=3.3.5a MOONWELL_REALMLIST="set realmlist strictlypragmatic.ru" MOONWELL_RATE_EXPERIENCE=x3 diff --git a/app/Http/Controllers/Concerns/BuildsPortalProps.php b/app/Http/Controllers/Concerns/BuildsPortalProps.php index 43130a6..52052a6 100644 --- a/app/Http/Controllers/Concerns/BuildsPortalProps.php +++ b/app/Http/Controllers/Concerns/BuildsPortalProps.php @@ -26,6 +26,7 @@ trait BuildsPortalProps ], 'urls' => [ 'home' => route('landing.index'), + 'news' => route('news.index'), 'login' => route('login'), 'cabinet' => route('cabinet.index'), 'admin' => route('admin.accounts.index'), diff --git a/app/Http/Controllers/LandingController.php b/app/Http/Controllers/LandingController.php index 88331fa..b0ee90e 100644 --- a/app/Http/Controllers/LandingController.php +++ b/app/Http/Controllers/LandingController.php @@ -29,6 +29,8 @@ class LandingController extends Controller $rates = $realmConfig['rates'] ?? []; $user = Auth::user(); $playersOnline = $accounts->onlinePlayerCount(); + $realmName = $this->canonicalMoonWellName($realmConfig['realm_name'] ?? null); + $serverName = $this->canonicalMoonWellName($realmConfig['server_name'] ?? null); $playUrl = $user !== null ? route('cabinet.client') @@ -46,6 +48,7 @@ class LandingController extends Controller 'tagType' => 'patch', 'image_url' => $item->image_url, 'featured' => $index === 0, + 'url' => route('news.show', $item), ]) ->all(); } catch (Throwable $exception) { @@ -56,7 +59,7 @@ class LandingController extends Controller $bootstrap = [ 'realm' => [ - 'name' => $realmConfig['realm_name'], + 'name' => $realmName, 'mode' => sprintf('PvE · %s rate · RU', $rates['experience'] ?? 'x1'), 'realmlist' => $realmConfig['realmlist'], 'online' => $playersOnline !== null, @@ -67,10 +70,11 @@ class LandingController extends Controller 'rates' => $rates, 'client_version' => $realmConfig['client_version'] ?? '3.3.5a', 'tagline' => $realmConfig['tagline'] ?? null, - 'server_name' => $realmConfig['server_name'] ?? 'MoonWell', + 'server_name' => $serverName, ], 'playUrl' => $playUrl, 'posts' => $posts, + 'newsIndexUrl' => route('news.index'), 'tweaks' => [ 'variant' => 'forest', 'particles' => true, @@ -163,4 +167,13 @@ class LandingController extends Controller return method_exists($bag, 'toArray') ? $bag->toArray() : []; } + + private function canonicalMoonWellName(?string $name): string + { + if ($name === null || strcasecmp($name, 'MoonWell') === 0) { + return 'MoonWell'; + } + + return $name; + } } diff --git a/app/Http/Controllers/NewsController.php b/app/Http/Controllers/NewsController.php new file mode 100644 index 0000000..c19b26c --- /dev/null +++ b/app/Http/Controllers/NewsController.php @@ -0,0 +1,73 @@ +published() + ->latest('created_at') + ->latest('id') + ->paginate(9) + ->withQueryString() + ->through(fn (News $item): array => $this->summary($item)); + + return Inertia::render('News/Index', [ + ...$this->portalProps($request), + 'articles' => $articles, + ]); + } + + public function show(Request $request, News $news): Response + { + abort_unless($news->is_published, 404); + + $moreNews = News::query() + ->published() + ->where('id', '!=', $news->id) + ->latest('created_at') + ->latest('id') + ->limit(3) + ->get() + ->map(fn (News $item): array => $this->summary($item)) + ->values() + ->all(); + + return Inertia::render('News/Show', [ + ...$this->portalProps($request), + 'article' => [ + ...$this->summary($news), + 'body' => $news->body, + 'canonical_url' => route('news.show', $news), + 'back_url' => route('news.index'), + ], + 'moreNews' => $moreNews, + ]); + } + + /** + * @return array + */ + private function summary(News $news): array + { + return [ + 'id' => $news->id, + 'title' => $news->title, + 'excerpt' => Str::limit(trim(strip_tags($news->body)), 200), + 'date' => $news->created_at?->locale(app()->getLocale())->isoFormat('D MMMM YYYY'), + 'image_url' => $news->image_url, + 'url' => route('news.show', $news), + ]; + } +} diff --git a/app/Services/NewsService.php b/app/Services/NewsService.php index edc0ca8..3d527b2 100644 --- a/app/Services/NewsService.php +++ b/app/Services/NewsService.php @@ -20,11 +20,12 @@ class NewsService /** * @return \Illuminate\Support\Collection */ - public function listForLanding(int $limit = 6): Collection + public function listForLanding(int $limit = 3): Collection { return News::query() ->published() - ->ordered() + ->latest('created_at') + ->latest('id') ->limit($limit) ->get(); } diff --git a/config/moonwell.php b/config/moonwell.php index 7fc079c..b5f577e 100644 --- a/config/moonwell.php +++ b/config/moonwell.php @@ -40,9 +40,9 @@ return [ ], 'realm' => [ - 'server_name' => env('MOONWELL_SERVER_NAME', 'Moonwell'), - 'realm_name' => env('MOONWELL_REALM_NAME', 'Moonwell'), - 'tagline' => env('MOONWELL_SERVER_TAGLINE', 'Русскоязычный WotLK-сервер с прогрессией и комфортным PvE'), + 'server_name' => env('MOONWELL_SERVER_NAME', 'MoonWell'), + 'realm_name' => env('MOONWELL_REALM_NAME', 'MoonWell'), + 'tagline' => env('MOONWELL_SERVER_TAGLINE', 'Пройди историю Азерота — от Классики до Короля-лича — в своём темпе, в одиночку или с небольшим отрядом.'), 'client_version' => env('MOONWELL_CLIENT_VERSION', '3.3.5a'), 'realmlist' => env('MOONWELL_REALMLIST', 'set realmlist 127.0.0.1'), 'rates' => [ diff --git a/package-lock.json b/package-lock.json index dac3528..778b020 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,13 +8,10 @@ "@inertiajs/vite": "^3.5.0", "@inertiajs/vue3": "^3.5.0", "@vitejs/plugin-vue": "^6.0.7", - "react": "^18.3.1", - "react-dom": "^18.3.1", "vue": "^3.5.39" }, "devDependencies": { "@tailwindcss/vite": "^4.0.0", - "@vitejs/plugin-react": "^4.3.4", "axios": "^1.11.0", "concurrently": "^9.0.1", "laravel-vite-plugin": "^2.0.0", @@ -22,148 +19,6 @@ "vite": "^7.0.7" } }, - "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", - "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-string-parser": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", @@ -182,30 +37,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/parser": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", @@ -221,72 +52,6 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", - "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", - "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/types": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", @@ -809,13 +574,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.60.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz", @@ -1413,78 +1171,12 @@ "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - } - }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "license": "MIT" }, - "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, "node_modules/@vitejs/plugin-vue": { "version": "6.0.7", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.7.tgz", @@ -1652,53 +1344,6 @@ "proxy-from-env": "^2.1.0" } }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.22", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.22.tgz", - "integrity": "sha512-6qruVrb5rse6WylFkU0FhBKKGuecWseqdpQfhkawn6ztyk2QlfwSRjsDxMCLJrkfmfN21qvhl9ABgaMeRkuwww==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", - "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.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", - "update-browserslist-db": "^1.2.3" - }, - "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", @@ -1713,27 +1358,6 @@ "node": ">= 0.4" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001791", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001791.tgz", - "integrity": "sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ==", - "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", @@ -1837,37 +1461,12 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -1903,13 +1502,6 @@ "node": ">= 0.4" } }, - "node_modules/electron-to-chromium": { - "version": "1.5.344", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.344.tgz", - "integrity": "sha512-4MxfbmNDm+KPh066EZy+eUnkcDPcZ35wNmOWzFuh/ijvHsve6kbLTLURy88uCNK5FbpN+yk2nQY6BYh1GEt+wg==", - "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", @@ -2138,16 +1730,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -2289,38 +1871,6 @@ "jiti": "lib/jiti-cli.mjs" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/laravel-precognition": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/laravel-precognition/-/laravel-precognition-2.0.0.tgz", @@ -2608,28 +2158,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -2672,13 +2200,6 @@ "node": ">= 0.6" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "node_modules/nanoid": { "version": "3.3.15", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", @@ -2697,13 +2218,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/node-releases": { - "version": "2.0.38", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.38.tgz", - "integrity": "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==", - "dev": true, - "license": "MIT" - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -2760,41 +2274,6 @@ "node": ">=10" } }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2859,25 +2338,6 @@ "tslib": "^2.1.0" } }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/shell-quote": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", @@ -2998,37 +2458,6 @@ "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.2", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", @@ -3176,13 +2605,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index b3775fd..c58904d 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,6 @@ }, "devDependencies": { "@tailwindcss/vite": "^4.0.0", - "@vitejs/plugin-react": "^4.3.4", "axios": "^1.11.0", "concurrently": "^9.0.1", "laravel-vite-plugin": "^2.0.0", @@ -19,8 +18,6 @@ "@inertiajs/vite": "^3.5.0", "@inertiajs/vue3": "^3.5.0", "@vitejs/plugin-vue": "^6.0.7", - "react": "^18.3.1", - "react-dom": "^18.3.1", "vue": "^3.5.39" } } diff --git a/resources/css/moonwell.css b/resources/css/moonwell.css index 4e74f68..dff3ec3 100644 --- a/resources/css/moonwell.css +++ b/resources/css/moonwell.css @@ -1110,6 +1110,10 @@ section { border-color: var(--panel-border-strong); transform: translateY(-2px); } +.news-card:focus-visible { + outline: 2px solid var(--moon); + outline-offset: 4px; +} .news-card.featured { grid-row: span 2; padding: 40px; @@ -1180,12 +1184,357 @@ section { gap: 8px; } +.news-all-link { + display: inline-flex; + align-items: center; + gap: 10px; + margin-top: 4px; + padding: 11px 16px; + border: 1px solid var(--panel-border-strong); + border-radius: var(--radius); + font-family: var(--f-mono); + font-size: 10px; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--moon); + transition: border-color var(--t-fast), color var(--t-fast), background var(--t-fast); +} + +.news-all-link:hover { + border-color: var(--moon); + color: var(--ivory); + background: rgba(127, 184, 212, 0.06); +} + @media (max-width: 900px) { .news-grid { grid-template-columns: 1fr; } .news-card.featured { grid-row: auto; padding: 28px; } .news-card.featured .news-title { font-size: 24px; } } +/* ------------------------- public news index ------------------------- */ +.portal-news-index { + padding-top: clamp(64px, 8vw, 110px); + padding-bottom: clamp(80px, 10vw, 140px); +} + +.portal-news-index__hero { + max-width: 830px; + margin-bottom: clamp(44px, 6vw, 74px); +} + +.portal-news-index__hero h1 { + margin: 20px 0 22px; + font-size: clamp(44px, 7vw, 86px); + text-wrap: balance; +} + +.portal-news-index__hero .lead { + max-width: 720px; + margin: 0; +} + +.portal-news-list { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 26px; +} + +.portal-news-list__card { + display: flex; + min-width: 0; + min-height: 470px; + flex-direction: column; + overflow: hidden; + border: 1px solid var(--panel-border); + border-radius: var(--radius-lg); + background: + radial-gradient(ellipse at 80% -10%, rgba(91, 58, 138, 0.15), transparent 50%), + linear-gradient(180deg, rgba(16, 20, 42, 0.66), rgba(10, 13, 31, 0.42)); + transition: border-color var(--t-fast), transform var(--t-fast), box-shadow var(--t-fast); +} + +.portal-news-list__card:hover { + border-color: var(--panel-border-strong); + transform: translateY(-3px); + box-shadow: 0 24px 70px rgba(0, 0, 0, 0.24); +} + +.portal-news-list__card:focus-visible { + outline: 2px solid var(--moon); + outline-offset: 4px; +} + +.portal-news-list__cover { + display: grid; + width: 100%; + aspect-ratio: 16 / 9; + flex: 0 0 auto; + place-items: center; + border-bottom: 1px solid var(--panel-border); + background-position: center; + background-size: cover; +} + +.portal-news-list__cover.empty { + background: + radial-gradient(circle at 50% 50%, rgba(127, 184, 212, 0.12), transparent 38%), + repeating-linear-gradient(45deg, transparent 0 16px, rgba(127, 184, 212, 0.025) 16px 17px); +} + +.portal-news-list__cover.empty span { + font-family: var(--f-display); + font-size: 34px; + color: var(--moon); + filter: drop-shadow(0 0 18px rgba(127, 184, 212, 0.42)); +} + +.portal-news-list__content { + display: flex; + flex: 1; + flex-direction: column; + gap: 15px; + padding: 26px; +} + +.portal-news-list__content h2 { + font-size: clamp(22px, 2.2vw, 30px); + line-height: 1.22; +} + +.portal-news-list__content > p { + margin: 0; + font-family: var(--f-serif); + font-size: 17px; + line-height: 1.55; + color: var(--text-soft); +} + +.portal-news-index__empty { + padding: clamp(60px, 10vw, 110px) 30px; + border: 1px dashed var(--panel-border-strong); + border-radius: var(--radius-lg); + text-align: center; + background: rgba(127, 184, 212, 0.025); +} + +.portal-news-index__empty > span { + display: block; + margin-bottom: 18px; + font-size: 32px; + color: var(--moon); +} + +.portal-news-index__empty h2 { font-size: clamp(28px, 4vw, 42px); } +.portal-news-index__empty p { + margin: 14px 0 28px; + font-family: var(--f-serif); + font-size: 19px; + color: var(--text-soft); +} + +.portal-pagination { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 8px; + margin-top: 52px; +} + +.portal-pagination a, +.portal-pagination span { + display: grid; + min-width: 42px; + height: 42px; + padding: 0 13px; + place-items: center; + border: 1px solid var(--panel-border); + border-radius: var(--radius); + font-family: var(--f-mono); + font-size: 10px; + color: var(--text-mute); +} + +.portal-pagination a { + transition: border-color var(--t-fast), color var(--t-fast), background var(--t-fast); +} + +.portal-pagination a:hover, +.portal-pagination a.active { + border-color: var(--moon); + color: var(--ivory); + background: rgba(127, 184, 212, 0.08); +} + +.portal-pagination .disabled { opacity: 0.36; } + +@media (max-width: 1000px) { + .portal-news-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } +} + +@media (max-width: 640px) { + .portal-news-list { grid-template-columns: 1fr; } + .portal-news-list__card { min-height: auto; } + .portal-news-list__content { padding: 22px; } + .portal-pagination a:first-of-type, + .portal-pagination a:last-of-type, + .portal-pagination span:first-child, + .portal-pagination span:last-child { min-width: 74px; } +} + +/* ------------------------- public news article ------------------------- */ +.portal-news-page { + max-width: 1040px; + padding-top: clamp(54px, 8vw, 110px); + padding-bottom: clamp(68px, 9vw, 120px); +} + +.portal-news-back { + display: inline-flex; + align-items: center; + gap: 10px; + margin-bottom: clamp(38px, 6vw, 70px); + font-family: var(--f-mono); + font-size: 10px; + letter-spacing: 0.18em; + text-transform: uppercase; + color: var(--text-mute); + transition: color var(--t-fast); +} + +.portal-news-back:hover { color: var(--moon); } + +.portal-news-hero { + max-width: 880px; +} + +.portal-news-hero h1 { + margin: 24px 0; + font-size: clamp(42px, 7vw, 82px); + text-wrap: balance; +} + +.portal-news-hero .lead { + max-width: 760px; + margin: 0; + font-size: clamp(20px, 2vw, 26px); +} + +.portal-news-cover { + width: 100%; + max-height: 620px; + margin: clamp(42px, 6vw, 72px) 0; + border: 1px solid var(--panel-border-strong); + border-radius: var(--radius-lg); + object-fit: cover; + box-shadow: 0 28px 90px rgba(0, 0, 0, 0.34); +} + +.portal-news-body { + max-width: 780px; + margin: clamp(44px, 6vw, 76px) auto 0; +} + +.portal-news-body p { + margin: 0 0 1.45em; + white-space: pre-line; + font-family: var(--f-serif); + font-size: clamp(20px, 2.1vw, 25px); + line-height: 1.72; + color: var(--text-soft); +} + +.portal-news-body p:first-child::first-letter { + float: left; + margin: 0.08em 0.12em 0 0; + font-family: var(--f-display); + font-size: 3.2em; + line-height: 0.78; + color: var(--moon); +} + +.portal-news-end { + display: flex; + align-items: center; + gap: 14px; + max-width: 780px; + margin: 56px auto 0; + padding-top: 28px; + border-top: 1px solid var(--panel-border); + font-family: var(--f-mono); + font-size: 10px; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--moon); +} + +.portal-news-end a { transition: color var(--t-fast); } +.portal-news-end a:hover { color: var(--ivory); } + +.portal-news-more { + padding-bottom: clamp(80px, 10vw, 140px); +} + +.portal-news-more__head { + padding-top: 50px; + border-top: 1px solid var(--panel-border); +} + +.portal-news-more__head h2 { + margin: 16px 0 34px; + font-size: clamp(32px, 4vw, 50px); +} + +.portal-news-more__grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 22px; +} + +.portal-news-more__card { + display: flex; + min-height: 280px; + flex-direction: column; + gap: 14px; + padding: 24px; + border: 1px solid var(--panel-border); + border-radius: var(--radius-lg); + background: linear-gradient(180deg, rgba(16, 20, 42, 0.58), rgba(10, 13, 31, 0.36)); + transition: border-color var(--t-fast), transform var(--t-fast); +} + +.portal-news-more__card:hover { + border-color: var(--panel-border-strong); + transform: translateY(-2px); +} + +.portal-news-more__card img { + width: calc(100% + 48px); + height: 150px; + margin: -24px -24px 6px; + border-bottom: 1px solid var(--panel-border); + object-fit: cover; +} + +.portal-news-more__card h3 { + font-size: 23px; + line-height: 1.25; +} + +.portal-news-more__card > p { + margin: 0; + font-family: var(--f-serif); + font-size: 17px; + line-height: 1.5; + color: var(--text-soft); +} + +@media (max-width: 800px) { + .portal-news-more__grid { grid-template-columns: 1fr; } + .portal-news-more__card { min-height: auto; } + .portal-news-body p { font-size: 20px; } +} + /* ------------------------- footer ------------------------- */ .footer { padding: clamp(80px, 10vw, 140px) 0 48px; diff --git a/resources/js/Components/SiteFooter.vue b/resources/js/Components/SiteFooter.vue index 84ef30a..6b029fe 100644 --- a/resources/js/Components/SiteFooter.vue +++ b/resources/js/Components/SiteFooter.vue @@ -16,6 +16,7 @@ defineProps({ {{ site.name }} diff --git a/resources/js/Components/SiteHeader.vue b/resources/js/Components/SiteHeader.vue index 5282af4..8ff7a7a 100644 --- a/resources/js/Components/SiteHeader.vue +++ b/resources/js/Components/SiteHeader.vue @@ -14,6 +14,7 @@ const menuOpen = ref(false); const currentPath = computed(() => page.url.split('?')[0]); const isCabinet = computed(() => currentPath.value.startsWith('/cabinet')); const isAdmin = computed(() => currentPath.value.startsWith('/admin')); +const isNews = computed(() => currentPath.value.startsWith('/news')); const cabinetUrl = computed(() => ( props.auth.authenticated ? props.urls.cabinet @@ -47,6 +48,7 @@ onBeforeUnmount(() => {