chore: remove dead code and unused dependencies
- Delete 4 unused files detected by knip - Remove lint-staged, eslint-config-prettier, plausible-tracker - Clean up knip.json entry patterns
This commit is contained in:
1 parent
7f8d083763
commit
5fa342018d
7 files changed
-618
No files matched your search
@@ -5,10 +5,6 @@
|
||||
"src/app/**/layout.{ts,tsx}",
|
||||
"src/app/**/route.{ts,tsx}",
|
||||
"src/app/**/{error,not-found,loading,template,default,global-error}.{ts,tsx}",
|
||||
"src/app/**/actions.{ts,tsx}",
|
||||
"next.config.ts",
|
||||
"src/proxy.ts",
|
||||
"src/instrumentation.ts",
|
||||
"sentry.{server,edge}.config.ts"
|
||||
],
|
||||
"project": ["src/**/*.{ts,tsx}"],
|
||||
|
||||
@@ -103,13 +103,10 @@
|
||||
"babel-plugin-react-compiler": "^1.0.0",
|
||||
"dotenv": "^16.4.0",
|
||||
"eslint": "^10.7.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-unused-imports": "^4.4.1",
|
||||
"husky": "^9.1.7",
|
||||
"knip": "^6.27.0",
|
||||
"lint-staged": "^17.1.0",
|
||||
"pino-pretty": "^13.1.3",
|
||||
"plausible-tracker": "^0.3.9",
|
||||
"postcss": "^8.5.21",
|
||||
"prisma": "^7.9.0",
|
||||
"tailwindcss": "^4.3.3",
|
||||
|
||||
Generated
-45
@@ -194,9 +194,6 @@ importers:
|
||||
eslint:
|
||||
specifier: ^10.7.0
|
||||
version: 10.7.0([email protected])
|
||||
eslint-config-prettier:
|
||||
specifier: ^10.1.8
|
||||
version: 10.1.8([email protected]([email protected]))
|
||||
eslint-plugin-unused-imports:
|
||||
specifier: ^4.4.1
|
||||
version: 4.4.1(@typescript-eslint/[email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected]([email protected]))([email protected]))([email protected]([email protected]))
|
||||
@@ -206,15 +203,9 @@ importers:
|
||||
knip:
|
||||
specifier: ^6.27.0
|
||||
version: 6.27.0
|
||||
lint-staged:
|
||||
specifier: ^17.1.0
|
||||
version: 17.1.0
|
||||
pino-pretty:
|
||||
specifier: ^13.1.3
|
||||
version: 13.1.3
|
||||
plausible-tracker:
|
||||
specifier: ^0.3.9
|
||||
version: 0.3.9
|
||||
postcss:
|
||||
specifier: ^8.5.19
|
||||
version: 8.5.21
|
||||
@@ -3465,12 +3456,6 @@ packages:
|
||||
engines: {node: '>=6.0'}
|
||||
hasBin: true
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
eslint: '>=7.0.0'
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-oZGYUz1X3sRMGUB+0cZyK2VcvRX5lm/vB56PgNNcU+7ficUCKm66oZWKUubXWnOuPjQ8PvmXtCViXBMONPe7tQ==}
|
||||
peerDependencies:
|
||||
@@ -4134,11 +4119,6 @@ packages:
|
||||
resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-d7UQRu/9ZPgfu4+hu/k0wny5GEaIxo+2jb2LJqQDkE7cHRTm1HGqNUDq5UOwsGPpjpaNAFmgAsYo3TR+i9cSJw==}
|
||||
engines: {node: '>=22.22.1'}
|
||||
hasBin: true
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==}
|
||||
engines: {node: '>=6.11.5'}
|
||||
@@ -4633,11 +4613,6 @@ packages:
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-hMhneYm3GCPyQon88SZrVJx+LlqhM1kZFQbuAgXPoh/Az2YvO1B6bitT9qlhpiTdJlsT5lsr3gPmzoVjb5CDXA==}
|
||||
engines: {node: '>=10'}
|
||||
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -5096,10 +5071,6 @@ packages:
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-1Yowhzjf0ivGMrTIkY9hav5TxobO9qIVqUE41fiCGMGgc3CLlf4MY+9AHmZqBWgDTue0fY9zWjYFVyf6Diuobw==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
|
||||
engines: {node: '>=0.6.19'}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -8525,10 +8496,6 @@ snapshots:
|
||||
optionalDependencies:
|
||||
source-map: 0.6.1
|
||||
|
||||
[email protected]([email protected]([email protected])):
|
||||
dependencies:
|
||||
eslint: 10.7.0([email protected])
|
||||
|
||||
[email protected](@typescript-eslint/[email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected]([email protected]))([email protected]))([email protected]([email protected])):
|
||||
dependencies:
|
||||
eslint: 10.7.0([email protected])
|
||||
@@ -9260,14 +9227,6 @@ snapshots:
|
||||
lightningcss-win32-arm64-msvc: 1.32.0
|
||||
lightningcss-win32-x64-msvc: 1.32.0
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
picomatch: 4.0.5
|
||||
string-argv: 0.3.2
|
||||
tinyexec: 1.2.4
|
||||
optionalDependencies:
|
||||
yaml: 2.9.0
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
@@ -9745,8 +9704,6 @@ snapshots:
|
||||
exsolve: 1.1.0
|
||||
pathe: 2.0.3
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
@@ -10305,8 +10262,6 @@ snapshots:
|
||||
- bare-abort-controller
|
||||
- react-native-b4a
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
is-fullwidth-code-point: 2.0.0
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export { CatalogItemsTable } from "./catalog-items-table";
|
||||
export { FurniIcon } from "./furni-icon";
|
||||
export type { BaseItemData, CatalogItemData, InlineEdit } from "./types";
|
||||
export { DEFAULT_NEW_ITEM, getPointsLabel, POINTS_TYPES } from "./types";
|
||||
@@ -1,254 +0,0 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { headers } from "next/headers";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { HomeLoginForm } from "@/components/auth/home-login-form";
|
||||
import { Reveal } from "@/components/motion-reveal";
|
||||
import { avatarImageUrl, excerpt } from "@/lib/format";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { captchaConfig } from "@/lib/services/captcha";
|
||||
import { siteSettings } from "@/lib/services/site-settings";
|
||||
|
||||
export default async function GuestView() {
|
||||
const t = await getTranslations("pages.home");
|
||||
const imager =
|
||||
(await siteSettings.get(
|
||||
"habbo_imaging_url",
|
||||
"https://www.habbo.com/habbo-imaging/avatarimage",
|
||||
)) ?? "";
|
||||
const cfg = await captchaConfig();
|
||||
const nonce = (await headers()).get("x-nonce") ?? undefined;
|
||||
|
||||
let articles: Array<{
|
||||
slug: string;
|
||||
title: string;
|
||||
shortStory: string;
|
||||
image: string;
|
||||
}> = [];
|
||||
try {
|
||||
articles = await prisma.websiteArticles.findMany({
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: 8,
|
||||
select: { slug: true, title: true, shortStory: true, image: true },
|
||||
});
|
||||
} catch {}
|
||||
|
||||
let recentUsers: Array<{ username: string; look: string }> = [];
|
||||
try {
|
||||
recentUsers = await prisma.user.findMany({
|
||||
orderBy: { lastOnline: "desc" },
|
||||
take: 12,
|
||||
select: { username: true, look: true },
|
||||
});
|
||||
} catch {}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4 md:flex-row">
|
||||
<Reveal className="flex w-full flex-col gap-4 md:w-1/3 md:flex-shrink-0">
|
||||
<div
|
||||
className="overflow-hidden rounded-lg border"
|
||||
style={{
|
||||
borderColor:
|
||||
"color-mix(in srgb, var(--color-text-muted) 22%, transparent)",
|
||||
}}
|
||||
>
|
||||
<div className="relative h-[120px] overflow-hidden md:h-[150px]">
|
||||
<div
|
||||
className="absolute inset-0"
|
||||
style={{
|
||||
backgroundImage: "url(/assets/images/kasja_mepage_header.png)",
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center 30%",
|
||||
backgroundRepeat: "no-repeat",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="absolute inset-0"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(135deg, rgba(0,0,0,0.65) 0%, rgba(0,0,0,0.15) 50%, rgba(0,0,0,0.5) 100%)",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="absolute -bottom-8 right-4 w-32 h-32 rounded-full opacity-[0.12] blur-[60px]"
|
||||
style={{ background: "var(--color-primary)" }}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="p-3"
|
||||
style={{ backgroundColor: "var(--color-surface)" }}
|
||||
>
|
||||
<HomeLoginForm
|
||||
captcha={{
|
||||
provider: cfg.provider,
|
||||
siteKey: cfg.siteKey || undefined,
|
||||
field: cfg.field || undefined,
|
||||
}}
|
||||
nonce={nonce}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a href="/register" className="relative block">
|
||||
<div
|
||||
className="inline-block overflow-hidden rounded-lg border"
|
||||
style={{
|
||||
borderColor:
|
||||
"color-mix(in srgb, var(--color-text-muted) 22%, transparent)",
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src="/assets/images/EnterHubbly.png"
|
||||
alt="Register"
|
||||
width={300}
|
||||
height={100}
|
||||
className="block"
|
||||
unoptimized
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
className="pointer-events-none absolute inset-0 flex items-center text-4xl font-extrabold text-white text-shadow"
|
||||
style={{ marginLeft: "15px" }}
|
||||
>
|
||||
REGISTER NOW
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{recentUsers.length > 0 && (
|
||||
<div
|
||||
className="overflow-hidden rounded-lg border"
|
||||
style={{
|
||||
borderColor:
|
||||
"color-mix(in srgb, var(--color-text-muted) 22%, transparent)",
|
||||
backgroundColor: "var(--color-surface)",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="flex h-12 w-full items-center justify-center bg-repeat"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(140deg, #0A1F0A 0%, #0F2D0F 20%, #153C15 40%, #1B4A1B 60%, #205820 75%, #1A4A1A 90%, #143814 100%)",
|
||||
}}
|
||||
>
|
||||
<h2 className="px-3 text-xl font-bold text-white">
|
||||
Recent Users
|
||||
</h2>
|
||||
</div>
|
||||
<div className="grid grid-cols-4 sm:grid-cols-6 gap-3 p-3">
|
||||
{recentUsers.map((u) => (
|
||||
<div
|
||||
key={u.username}
|
||||
className="relative overflow-visible rounded-md p-0 shadow-lg"
|
||||
style={{
|
||||
width: "50px",
|
||||
height: "50px",
|
||||
justifySelf: "center",
|
||||
backgroundColor: "var(--color-surface)",
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={avatarImageUrl(imager, u.look, {
|
||||
headOnly: true,
|
||||
direction: 3,
|
||||
})}
|
||||
alt={u.username}
|
||||
width={50}
|
||||
height={62}
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "-12px",
|
||||
left: "50%",
|
||||
transform: "translateX(-50%)",
|
||||
maxWidth: "none",
|
||||
maxHeight: "none",
|
||||
}}
|
||||
unoptimized
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Reveal>
|
||||
|
||||
<Reveal delay={0.15} className="flex w-full flex-col gap-4 md:w-2/3">
|
||||
<div
|
||||
className="overflow-hidden rounded-lg border"
|
||||
style={{
|
||||
borderColor:
|
||||
"color-mix(in srgb, var(--color-text-muted) 22%, transparent)",
|
||||
backgroundColor: "var(--color-surface)",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="flex h-12 w-full items-center justify-center"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(140deg, #1a3a5c 0%, #1e4a6e 20%, #2a5a80 40%, #3a6a90 60%, #4a7aa0 75%, #3a6a90 90%, #2a5a80 100%)",
|
||||
}}
|
||||
>
|
||||
<h2 className="text-xl font-bold text-white">
|
||||
{t("latestNews") || "Latest News"}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-4">
|
||||
{articles.length === 0 ? (
|
||||
<p
|
||||
className="py-8 text-center"
|
||||
style={{
|
||||
color:
|
||||
"var(--color-text-muted-readable, var(--color-text-muted))",
|
||||
}}
|
||||
>
|
||||
{t("noArticles")}
|
||||
</p>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
{articles.map((a) => (
|
||||
<Link
|
||||
key={a.slug}
|
||||
href={`/news/${a.slug}`}
|
||||
className="group relative w-full overflow-hidden rounded-lg transition-all duration-200"
|
||||
style={{
|
||||
height: "215px",
|
||||
backgroundColor: "var(--color-surface)",
|
||||
border:
|
||||
"1px solid color-mix(in srgb, var(--color-text-muted) 15%, transparent)",
|
||||
}}
|
||||
>
|
||||
<div className="relative h-full w-full overflow-hidden rounded-lg">
|
||||
<Image
|
||||
src={a.image}
|
||||
alt={a.title}
|
||||
fill
|
||||
className="rounded-lg object-cover transition-all duration-300 group-hover:scale-105"
|
||||
unoptimized
|
||||
/>
|
||||
<div
|
||||
className="absolute left-0 w-full p-2"
|
||||
style={{
|
||||
bottom: "-2px",
|
||||
background:
|
||||
"linear-gradient(to top, rgba(0,0,0,0.85) 0%, transparent 100%)",
|
||||
}}
|
||||
>
|
||||
<h3 className="truncate text-lg font-semibold text-white text-shadow-sm">
|
||||
{a.title}
|
||||
</h3>
|
||||
{a.shortStory && (
|
||||
<p className="truncate text-xs font-normal text-white text-shadow-sm">
|
||||
{excerpt(a.shortStory, 80)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,289 +0,0 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { Reveal } from "@/components/motion-reveal";
|
||||
import { avatarImageUrl, excerpt } from "@/lib/format";
|
||||
import { resolveHotelName } from "@/lib/hotel-name";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { siteSettings } from "@/lib/services/site-settings";
|
||||
|
||||
interface UserViewProps {
|
||||
userId: number;
|
||||
username: string;
|
||||
look: string;
|
||||
motto?: string | null;
|
||||
}
|
||||
|
||||
export default async function UserView({
|
||||
userId,
|
||||
username,
|
||||
look,
|
||||
motto,
|
||||
}: UserViewProps) {
|
||||
const t = await getTranslations("pages.home");
|
||||
const hotelName = await resolveHotelName();
|
||||
const imager =
|
||||
(await siteSettings.get(
|
||||
"habbo_imaging_url",
|
||||
"https://www.habbo.com/habbo-imaging/avatarimage",
|
||||
)) ?? "";
|
||||
|
||||
let onlineFriends: Array<{ username: string; look: string }> = [];
|
||||
try {
|
||||
const friendships = await prisma.messengerFriendships.findMany({
|
||||
where: { OR: [{ userOneId: userId }, { userTwoId: userId }] },
|
||||
select: { userOneId: true, userTwoId: true },
|
||||
});
|
||||
const friendIds = friendships.map((f) =>
|
||||
f.userOneId === userId ? f.userTwoId : f.userOneId,
|
||||
);
|
||||
if (friendIds.length > 0) {
|
||||
onlineFriends = await prisma.user.findMany({
|
||||
where: { id: { in: friendIds }, online: "1" },
|
||||
take: 10,
|
||||
select: { username: true, look: true },
|
||||
});
|
||||
}
|
||||
} catch {}
|
||||
|
||||
const [latestArticle] = await prisma.websiteArticles
|
||||
.findMany({
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: 1,
|
||||
select: { slug: true, title: true, shortStory: true, image: true },
|
||||
})
|
||||
.catch(() => []);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 md:flex-row">
|
||||
<Reveal className="flex w-full flex-col gap-6 md:w-3/4">
|
||||
<div className="relative flex h-[340px] items-start overflow-hidden rounded-lg">
|
||||
<div
|
||||
className="absolute inset-0"
|
||||
style={{
|
||||
backgroundImage: "url(/assets/images/kasja_mepage_header.png)",
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center 30%",
|
||||
backgroundRepeat: "no-repeat",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="absolute inset-0"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(135deg, rgba(0,0,0,0.6) 0%, rgba(0,0,0,0.15) 40%, rgba(0,0,0,0.25) 65%, rgba(0,0,0,0.6) 100%)",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="absolute -bottom-10 -right-10 w-64 h-64 rounded-full opacity-[0.15] blur-[80px]"
|
||||
style={{ background: "var(--color-primary)" }}
|
||||
/>
|
||||
<div
|
||||
className="absolute -top-10 -left-10 w-48 h-48 rounded-full opacity-[0.08] blur-[60px]"
|
||||
style={{ background: "var(--color-primary)" }}
|
||||
/>
|
||||
<div
|
||||
className="relative z-10 mx-auto mt-8 flex w-[95%] max-w-3xl items-center justify-between rounded-2xl px-8 py-6"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(135deg, rgba(0,0,0,0.4) 0%, rgba(0,0,0,0.2) 100%)",
|
||||
boxShadow: "0 8px 32px rgba(0,0,0,0.3)",
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center gap-6">
|
||||
<Link
|
||||
href={`/u/${username}`}
|
||||
className="transition-transform duration-300 hover:scale-105"
|
||||
>
|
||||
<div
|
||||
className="rounded-full p-[3px]"
|
||||
style={{
|
||||
border: "3px solid var(--panel-border-color)",
|
||||
boxShadow:
|
||||
"0 0 24px color-mix(in srgb, var(--panel-border-color) 50%, transparent)",
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={avatarImageUrl(imager, look, {
|
||||
size: "l",
|
||||
direction: 2,
|
||||
})}
|
||||
alt={username}
|
||||
width={110}
|
||||
height={190}
|
||||
className="drop-shadow-2xl"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
unoptimized
|
||||
/>
|
||||
</div>
|
||||
</Link>
|
||||
<div
|
||||
className="flex flex-col gap-1.5 rounded-xl px-4 py-2"
|
||||
style={{
|
||||
background:
|
||||
"color-mix(in srgb, var(--color-surface) 88%, transparent)",
|
||||
backdropFilter: "blur(8px)",
|
||||
}}
|
||||
>
|
||||
<Link
|
||||
href={`/u/${username}`}
|
||||
className="text-2xl font-bold drop-shadow-lg hover:underline"
|
||||
style={{ color: "var(--color-text)" }}
|
||||
>
|
||||
{username}
|
||||
</Link>
|
||||
<p
|
||||
className="text-sm drop-shadow-md max-w-[240px] leading-tight"
|
||||
style={{
|
||||
color:
|
||||
"color-mix(in srgb, var(--color-text) 80%, transparent)",
|
||||
}}
|
||||
>
|
||||
{motto || "Welcome back!"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<Link
|
||||
href="/client"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
prefetch={true}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="group rounded-full px-7 py-3 text-sm font-bold tracking-wider transition-all duration-300 hover:scale-105 active:scale-95"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(135deg, color-mix(in srgb, var(--color-primary) 92%, white), color-mix(in srgb, var(--color-primary) 92%, black))",
|
||||
color:
|
||||
"var(--button-text-color-readable, var(--button-text-color))",
|
||||
border:
|
||||
"1px solid color-mix(in srgb, var(--color-primary) 60%, rgba(255,255,255,0.2))",
|
||||
boxShadow:
|
||||
"0 4px 24px color-mix(in srgb, var(--color-primary) 35%, transparent), inset 0 1px 0 rgba(255,255,255,0.2)",
|
||||
}}
|
||||
>
|
||||
{t("enterHotel", { hotelName })}
|
||||
<svg
|
||||
className="inline-block ml-2 w-4 h-4 transition-transform duration-300 group-hover:translate-x-0.5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
role="img"
|
||||
aria-label="Enter"
|
||||
>
|
||||
<title>Enter</title>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2.5}
|
||||
d="M9 5l7 7-7 7"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="flex flex-col gap-3 rounded-lg border p-1 lg:flex-row"
|
||||
style={{
|
||||
backgroundColor: "var(--color-surface)",
|
||||
borderColor:
|
||||
"color-mix(in srgb, var(--color-text-muted) 22%, transparent)",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="relative flex items-center justify-center rounded p-2 text-sm font-semibold"
|
||||
style={{ backgroundColor: "var(--panel-border-color)" }}
|
||||
>
|
||||
<span className="relative text-white">{t("onlineFriends")}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 px-3">
|
||||
{onlineFriends.length === 0 ? (
|
||||
<p
|
||||
className="mb-3 block w-full text-center text-xs font-medium md:mb-0 md:text-left"
|
||||
style={{
|
||||
color:
|
||||
"var(--color-text-muted-readable, var(--color-text-muted))",
|
||||
}}
|
||||
>
|
||||
{t("noFriendsOnline")}
|
||||
</p>
|
||||
) : (
|
||||
onlineFriends.map((f) => (
|
||||
<Link
|
||||
key={f.username}
|
||||
href={`/u/${f.username}`}
|
||||
className="transition-all duration-200 hover:scale-110"
|
||||
>
|
||||
<Image
|
||||
src={avatarImageUrl(imager, f.look, { headOnly: true })}
|
||||
alt={f.username}
|
||||
width={40}
|
||||
height={40}
|
||||
className="h-10 w-10"
|
||||
title={f.username}
|
||||
unoptimized
|
||||
/>
|
||||
</Link>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Reveal>
|
||||
|
||||
<Reveal delay={0.15} className="flex w-full flex-col gap-6 md:w-1/4">
|
||||
{latestArticle ? (
|
||||
<div
|
||||
className="overflow-hidden rounded-lg border"
|
||||
style={{
|
||||
backgroundColor: "var(--color-surface)",
|
||||
borderColor:
|
||||
"color-mix(in srgb, var(--color-text-muted) 22%, transparent)",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="flex h-12 items-center justify-center"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(140deg, #1a3a5c 0%, #1e4a6e 20%, #2a5a80 40%, #3a6a90 60%, #4a7aa0 75%, #3a6a90 90%, #2a5a80 100%)",
|
||||
}}
|
||||
>
|
||||
<h2 className="text-lg font-bold text-white">
|
||||
{t("latestArticle")}
|
||||
</h2>
|
||||
</div>
|
||||
<Link href={`/news/${latestArticle.slug}`} className="group block">
|
||||
<div className="relative aspect-[16/9] overflow-hidden">
|
||||
<Image
|
||||
src={latestArticle.image}
|
||||
alt={latestArticle.title}
|
||||
fill
|
||||
className="object-cover transition-transform duration-300 group-hover:scale-105"
|
||||
unoptimized
|
||||
/>
|
||||
</div>
|
||||
<div className="p-3">
|
||||
<h3 className="text-sm font-semibold">{latestArticle.title}</h3>
|
||||
{latestArticle.shortStory && (
|
||||
<p
|
||||
className="mt-1 text-xs"
|
||||
style={{
|
||||
color:
|
||||
"var(--color-text-muted-readable, var(--color-text-muted))",
|
||||
}}
|
||||
>
|
||||
{excerpt(latestArticle.shortStory, 100)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
) : null}
|
||||
</Reveal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
export {
|
||||
LaravelEncrypter,
|
||||
phpSerializeString,
|
||||
phpUnserializeString,
|
||||
} from "./laravel-encrypter";
|
||||
export {
|
||||
checkLogin,
|
||||
hashPassword,
|
||||
isMd5Of,
|
||||
type LoginCheck,
|
||||
md5Hex,
|
||||
verifyPassword,
|
||||
} from "./password";
|
||||
export {
|
||||
generateSsoTicket,
|
||||
issueSsoTicket,
|
||||
type SsoUserUpdater,
|
||||
} from "./sso-ticket";
|
||||
export { generateTotp, totpKeyUri, verifyTotp } from "./totp";
|
||||
Reference in new issue
Block a user