Fix theme consistency, i18n completeness, CSS variable naming, and hardcoded strings

This commit is contained in:
openhands committed 2026-07-09 18:13:22 +02:00
1 parent 0abd490f67
commit b058a3827b
37 files changed
+431 -214

No files matched your search

+1 -1
View File
@@ -72,7 +72,7 @@ export default async function AdminApplications() {
{applications.length === 0 ? (
<div className="admin-empty">{t("noApplications")}</div>
) : (
<div className="grid cols-2">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
{applications.map((a) => {
const username = userMap.get(a.userId);
return (
+1 -1
View File
@@ -137,7 +137,7 @@ export default async function AdminCalendarCampaign({
</thead>
<tbody>
{rewards.map((r) => (
<tr key={r.id} className="border-t border-[var(--border)]">
<tr key={r.id} className="border-t border-[var(--border-subtle)]">
<td>{r.id}</td>
<td>{r.productName || <span className="text-sm text-gray-500 dark:text-gray-400">—</span>}</td>
<td className="text-sm text-gray-500 dark:text-gray-400 whitespace-nowrap">{r.itemId > 0 ? r.itemId : "—"}</td>
+1 -1
View File
@@ -83,7 +83,7 @@ export default async function AdminCalendar() {
{campaigns.length === 0 ? (
<div className="admin-empty">{t("noCampaigns")}</div>
) : (
<div className="grid cols-3">
<div className="grid grid-cols-1 gap-4 md:grid-cols-3">
{campaigns.map((c) => {
const enabled = c.enabled === "1";
const count = rewardCounts.get(c.id) ?? 0;
+1 -1
View File
@@ -122,7 +122,7 @@ export default async function AdminCatalogPage({
</thead>
<tbody>
{items.map((it) => (
<tr key={it.id} style={{ borderTop: "1px solid var(--border)" }}>
<tr key={it.id} style={{ borderTop: "1px solid var(--border-subtle)" }}>
<td>{it.id}</td>
<td>
{it.catalogName}
+1 -1
View File
@@ -141,7 +141,7 @@ export default async function CommandoCentrum() {
</section>
{/* ── Server info + diagnostics ──────────────────────────── */}
<div className="grid cols-2">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<section className="admin-card p-5">
<h2 className="admin-section-title">{t("serverInfo")}</h2>
<div className="grid grid-cols-[repeat(auto-fit,minmax(150px,1fr))] gap-2.5">
+1 -1
View File
@@ -73,7 +73,7 @@ export function FaviconForm({ currentUrl }: { currentUrl: string | null }) {
<img
src={preview}
alt="Favicon preview"
className="w-16 h-16 rounded-lg border-2 border-[var(--border)] object-contain bg-white"
className="w-16 h-16 rounded-lg border-2 border-[var(--border-subtle)] object-contain bg-white"
/>
<div className="text-xs text-[var(--color-text-muted)] break-all">{preview}</div>
</div>
+3 -3
View File
@@ -85,7 +85,7 @@ export function FaviconGenerator({ onSave }: Props) {
ref={canvasRef}
width={SIZE}
height={SIZE}
className="border-2 border-[var(--border)] rounded-xl shadow-lg"
className="border-2 border-[var(--border-subtle)] rounded-xl shadow-lg"
style={{ width: 128, height: 128, imageRendering: "pixelated" }}
/>
</div>
@@ -114,7 +114,7 @@ export function FaviconGenerator({ onSave }: Props) {
type="color"
value={bgColor}
onChange={(e) => setBgColor(e.target.value)}
className="w-10 h-10 rounded-lg cursor-pointer border border-[var(--border)]"
className="w-10 h-10 rounded-lg cursor-pointer border border-[var(--border-subtle)]"
/>
<span className="text-xs text-[var(--color-text-muted)] font-mono">{bgColor}</span>
</div>
@@ -142,7 +142,7 @@ export function FaviconGenerator({ onSave }: Props) {
type="color"
value={textColor}
onChange={(e) => setTextColor(e.target.value)}
className="w-10 h-10 rounded-lg cursor-pointer border border-[var(--border)]"
className="w-10 h-10 rounded-lg cursor-pointer border border-[var(--border-subtle)]"
/>
<span className="text-xs text-[var(--color-text-muted)] font-mono">{textColor}</span>
</div>
+1 -1
View File
@@ -72,7 +72,7 @@ export default async function AdminIp() {
/>
</div>
<div className="grid cols-2">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
{/* ── Whitelist ──────────────────── */}
<section className="mt-6">
<h2 className="admin-section-title">{t("whitelist")}</h2>
+2 -2
View File
@@ -163,10 +163,10 @@ async function Topbar({ staff }: { staff: { id: number; username: string; rank:
const t = await getTranslations("pages.admin.nav");
return (
<header className="flex items-center justify-between gap-4 bg-[var(--color-surface)] border border-[var(--border)] rounded-2xl px-5 py-3 mb-5 shadow-card">
<header className="flex items-center justify-between gap-4 bg-[var(--color-surface)] border border-[var(--border-subtle)] rounded-2xl px-5 py-3 mb-5 shadow-card">
<div className="flex items-center gap-3">
<h2 className="m-0 text-base font-extrabold text-[var(--color-text)]">{t("housekeeping")}</h2>
<span className="hidden sm:inline-block w-px h-5 bg-[var(--border)]" />
<span className="hidden sm:inline-block w-px h-5 bg-[var(--border-subtle)]" />
<span className="hidden sm:inline text-xs text-[var(--color-text-muted)]">
{t("hotelManagementPanel")}
</span>
+1 -1
View File
@@ -103,7 +103,7 @@ export default async function AdminDashboard() {
) : (
<div className="space-y-0">
{activity.map((a, i) => (
<div key={String(a.id)} className={`flex items-center gap-3 py-2.5 ${i > 0 ? "border-t border-[var(--border)]" : ""}`}>
<div key={String(a.id)} className={`flex items-center gap-3 py-2.5 ${i > 0 ? "border-t border-[var(--border-subtle)]" : ""}`}>
<div className="w-7 h-7 rounded-full bg-[var(--color-primary)]/10 grid place-items-center flex-none">
<Activity size={12} className="text-[var(--color-primary)]" />
</div>
+1 -1
View File
@@ -44,7 +44,7 @@ export default async function AdminPhotos() {
{photos.length === 0 ? (
<div className="admin-empty">{t("noPhotos")}</div>
) : (
<div className="grid cols-3">
<div className="grid grid-cols-1 gap-4 md:grid-cols-3">
{photos.map((p) => (
<div key={String(p.id)} className="admin-card" style={{ padding: 0, overflow: "hidden" }}>
{/* eslint-disable-next-line @next/next/no-img-element */}
+1 -1
View File
@@ -119,7 +119,7 @@ export default async function AdminRadioApiKeysPage() {
{t("apiKeysForm.generateHint")}
</p>
<form action={createApiKey} className="admin-card">
<div className="grid cols-2">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label htmlFor="new_name" style={{ display: "block", fontWeight: 700 }}>
{t("apiKeysForm.name")}
+1 -1
View File
@@ -118,7 +118,7 @@ export default async function AdminRadioAutoDjPage() {
<section className="mt-6">
<h2 className="admin-section-title">{t("autoDjForm.addTrack")}</h2>
<form action={createTrack} className="admin-card">
<div className="grid cols-2">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label htmlFor="new_title" style={{ display: 'block', fontWeight: 700 }}>
{t("autoDjForm.title")}
+2 -2
View File
@@ -101,7 +101,7 @@ export default async function AdminRadioBannersPage() {
<section className="mt-6">
<h2 className="admin-section-title">{t("banners.addBanner")}</h2>
<form action={createRadioBanner} className="admin-card">
<div className="grid cols-2">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label htmlFor="new_imagePath" style={{ display: 'block', fontWeight: 700 }}>
{t("banners.form.imagePath")}
@@ -185,7 +185,7 @@ export default async function AdminRadioBannersPage() {
<form action={updateRadioBanner}>
<input type="hidden" name="id" value={String(b.id)} />
<div className="grid cols-2">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label
htmlFor={`img_${b.id}`}
+1 -1
View File
@@ -108,7 +108,7 @@ export default async function AdminRadioPointsPage({
<section className="mt-6">
<h2 className="admin-section-title">{t("pointsForm.settings")}</h2>
<form action={savePoints}>
<div className="grid cols-2">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label htmlFor="radio_points_enabled" style={{ display: "block", fontWeight: 700 }}>
{t("pointsForm.pointsEnabled")}
+1 -1
View File
@@ -84,7 +84,7 @@ export default async function AdminRadioRanksPage() {
<section className="mt-6">
<h2 className="admin-section-title">{t("ranksForm.addRank")}</h2>
<form action={createRadioRank} className="admin-card">
<div className="grid cols-3">
<div className="grid grid-cols-1 gap-4 md:grid-cols-3">
<div>
<label htmlFor="new_name" style={{ display: 'block', fontWeight: 700 }}>
{t("ranksForm.name")}
+1 -1
View File
@@ -279,7 +279,7 @@ export default async function AdminRadioSettingsPage() {
{groups.map((group) => (
<section key={group.title} className="admin-card" style={{ marginBottom: '1.25rem' }}>
<h2 style={{ marginTop: 0 }}>{group.title}</h2>
<div className="grid cols-2">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
{group.fields.map((field) => (
<div key={field.key}>
<label
+1 -1
View File
@@ -83,7 +83,7 @@ export default async function AdminTagsPage() {
<form action={createTag} className="admin-card mb-6">
<h3 style={{ marginTop: 0 }}>{t("addTag")}</h3>
<div className="grid cols-2">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label htmlFor="new_name" style={{ display: 'block', fontWeight: 700 }}>
{t("name")}
+1 -1
View File
@@ -62,7 +62,7 @@ export default async function AdminTeams() {
<div className="admin-card" style={{ marginBottom: "1.5rem" }}>
<h3 style={{ marginTop: 0 }}>{t("newTeamRank")}</h3>
<form action={createTeam} style={{ display: "grid", gap: "0.6rem" }}>
<div className="grid cols-2">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<label style={{ display: "grid", gap: "0.25rem" }}>
<span className="text-sm text-gray-500 dark:text-gray-400">{t("rankName")}</span>
<input name="rankName" placeholder={t("rankNamePlaceholder")} required />
+1 -1
View File
@@ -96,7 +96,7 @@ export default async function AdminUserEdit({
<form action={updateUser} className="admin-card">
<input type="hidden" name="id" value={user.id} />
<div className="grid cols-2">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<label>
{t("email")}
<input name="mail" type="email" defaultValue={user.mail ?? ""} maxLength={500} />
+1 -1
View File
@@ -79,7 +79,7 @@ export default async function AdminUserDetail({
<section className="mt-6">
<h2 className="admin-section-title">{t("detail.actions")}</h2>
<div className="grid cols-2">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<form action={giveCurrency} className="admin-card">
<input type="hidden" name="userId" value={user.id} />
<h3 className="text-sm font-bold text-[var(--color-text)] m-0 mb-3">{t("detail.giveCurrency")}</h3>
+1 -1
View File
@@ -92,7 +92,7 @@ export default async function AdminVouchers() {
<form action={createVoucher} className="admin-card mb-6">
<h3 style={{ marginTop: 0 }}>{t("newVoucher")}</h3>
<div className="grid cols-2" style={{ marginBottom: "0.75rem" }}>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2" style={{ marginBottom: "0.75rem" }}>
<label style={{ display: "flex", flexDirection: "column", gap: "0.3rem" }}>
<span className="text-sm text-gray-500 dark:text-gray-400">{t("form.code")}</span>
<input name="code" placeholder={t("form.codePlaceholder")} maxLength={255} required />
+1 -1
View File
@@ -80,7 +80,7 @@ export default async function AdminVpn({
</label>
</div>
<div className="grid cols-2">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label
htmlFor="vpn_provider"
+2 -2
View File
@@ -47,7 +47,7 @@ export default async function AdminWriteableBoxes() {
<section className="mt-6">
<h2 className="admin-section-title">{t("newBox")}</h2>
<form action={createBox} className="grid cols-2">
<form action={createBox} className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label htmlFor="new_title" style={{ display: "block", fontWeight: 700 }}>
{t("form.name")}
@@ -127,7 +127,7 @@ export default async function AdminWriteableBoxes() {
</span>
</div>
<form action={updateBox} className="grid cols-2">
<form action={updateBox} className="grid grid-cols-1 gap-4 md:grid-cols-2">
<input type="hidden" name="id" value={String(box.id)} />
<div>
<label
+3 -3
View File
@@ -334,7 +334,7 @@ function EndpointRow({ endpoint }: { endpoint: Endpoint }) {
alignItems: "center",
gap: "0.5rem 0.75rem",
padding: "0.7rem 0",
borderTop: "1px solid var(--border)",
borderTop: "1px solid var(--border-subtle)",
}}
>
<code
@@ -346,7 +346,7 @@ function EndpointRow({ endpoint }: { endpoint: Endpoint }) {
"ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace",
fontSize: "0.85rem",
background: "color-mix(in srgb, var(--color-text-muted) 8%, transparent)",
border: "1px solid var(--border)",
border: "1px solid var(--border-subtle)",
borderRadius: "var(--radius-sm)",
padding: "0.3rem 0.55rem",
whiteSpace: "nowrap",
@@ -396,7 +396,7 @@ export default function DevelopersPage() {
"ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace",
fontSize: "0.85rem",
background: "color-mix(in srgb, var(--color-text-muted) 8%, transparent)",
border: "1px solid var(--border)",
border: "1px solid var(--border-subtle)",
borderRadius: "var(--radius-sm)",
padding: "0.6rem 0.75rem",
whiteSpace: "pre-wrap",
+4 -20
View File
@@ -66,7 +66,7 @@
--input-focus-color: #eeb425;
--navbar-height: 56px;
--muted: var(--color-text-muted);
--border: color-mix(in srgb, var(--color-text-muted) 18%, transparent);
--border-subtle: color-mix(in srgb, var(--color-text-muted) 18%, transparent);
}
/* Dark mode (toggled by html.dark; wins over :root + ThemeVars via specificity). */
@@ -250,22 +250,6 @@ a:hover {
transform: translateY(-3px);
box-shadow: var(--shadow-card-hover);
}
.grid {
display: grid;
gap: 1rem;
}
.grid.cols-2 {
grid-template-columns: repeat(2, 1fr);
}
.grid.cols-3 {
grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 720px) {
.grid.cols-2,
.grid.cols-3 {
grid-template-columns: 1fr;
}
}
.article-img {
width: 100%;
height: 140px;
@@ -408,7 +392,7 @@ tbody tr:hover {
.admin-card {
background: var(--color-navbar);
color: var(--color-navbar-text);
border: 1px solid var(--border);
border: 1px solid var(--border-subtle);
border-radius: 16px;
box-shadow: var(--shadow-card);
padding: 1.25rem;
@@ -452,7 +436,7 @@ tbody tr:hover {
.admin-page table {
width: 100%;
background: var(--color-navbar);
border: 1px solid var(--border);
border: 1px solid var(--border-subtle);
border-radius: 16px;
overflow: hidden;
box-shadow: var(--shadow-card);
@@ -462,7 +446,7 @@ tbody tr:hover {
.admin-page thead th {
background: color-mix(in srgb, var(--color-primary) 8%, var(--color-navbar));
color: var(--color-text-muted);
border-bottom: 1px solid var(--border);
border-bottom: 1px solid var(--border-subtle);
white-space: nowrap;
font-size: 0.68rem;
font-weight: 700;
+4 -4
View File
@@ -28,7 +28,7 @@ export function StatusCard({
icon?: ReactNode;
}) {
return (
<div className="bg-[var(--color-surface)] border border-[var(--border)] rounded-2xl p-5 shadow-card hover:shadow-card-hover transition-shadow duration-200">
<div className="bg-[var(--color-surface)] border border-[var(--border-subtle)] rounded-2xl p-5 shadow-card hover:shadow-card-hover transition-shadow duration-200">
<div className="flex items-center justify-between gap-3 mb-3">
<span className="text-[0.65rem] font-bold uppercase tracking-widest text-[var(--color-text-muted)]">{label}</span>
{icon ? (
@@ -62,7 +62,7 @@ export function DiagnosticRow({
"bg-[var(--color-primary)]/18";
return (
<div className="flex items-center gap-2.5 py-2 px-0.5 border-t border-[var(--border)] first:border-t-0">
<div className="flex items-center gap-2.5 py-2 px-0.5 border-t border-[var(--border-subtle)] first:border-t-0">
<span className={`flex-none w-[9px] h-[9px] rounded-full ${dotColor}`} aria-hidden />
<span className="font-bold text-sm">{label}</span>
<span className="flex-1 text-[0.82rem] text-[var(--color-text-muted)]">{detail}</span>
@@ -102,7 +102,7 @@ export function OnlineUsersWidget({
};
return (
<div className="bg-[var(--color-surface)] rounded-xl border border-[var(--border)] p-6">
<div className="bg-[var(--color-surface)] rounded-xl border border-[var(--border-subtle)] p-6">
<div className="flex justify-between items-center mb-4">
<h3 className="m-0 text-lg font-semibold text-[var(--color-text)]">Online Now</h3>
<span className="text-sm text-[var(--color-text-muted)] bg-[var(--color-primary)]/10 px-3 py-1 rounded-full">
@@ -125,7 +125,7 @@ export function OnlineUsersWidget({
<img
src={`https://www.habbo.com/habbo-imaging/avatarimage?width=50&height=62&direction=2&headonly=1&crop=face&action=wav&gender=m&look=${encodeURIComponent(user.look)}`}
alt={user.username}
className="w-full h-full rounded object-cover border border-[var(--border)]"
className="w-full h-full rounded object-cover border border-[var(--border-subtle)]"
loading="lazy"
/>
{user.roomId && user.roomName && (
+9 -9
View File
@@ -68,8 +68,8 @@ export default async function GuestView() {
<img src="/assets/images/EnterHubbly.png" alt="Register" className="block" />
</div>
<span
className="pointer-events-none absolute inset-0 flex items-center text-4xl font-extrabold text-white"
style={{ textShadow: "1px 1px 2px rgba(0,0,0,0.8)", marginLeft: "15px" }}
className="pointer-events-none absolute inset-0 flex items-center text-4xl font-extrabold text-white text-shadow"
style={{ marginLeft: "15px" }}
>
REGISTER NOW
</span>
@@ -77,8 +77,8 @@ export default async function GuestView() {
{recentUsers.length > 0 && (
<div
className="overflow-hidden rounded-lg border bg-white dark:bg-gray-800"
style={{ borderColor: "color-mix(in srgb, var(--color-text-muted) 22%, transparent)" }}
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"
@@ -93,8 +93,8 @@ export default async function GuestView() {
{recentUsers.map((u) => (
<div
key={u.username}
className="relative overflow-visible rounded-md bg-white p-0 shadow-lg dark:bg-gray-800"
style={{ width: "50px", height: "50px", justifySelf: "center" }}
className="relative overflow-visible rounded-md p-0 shadow-lg"
style={{ width: "50px", height: "50px", justifySelf: "center", backgroundColor: "var(--color-surface)" }}
>
<img
src={avatarImageUrl(imager, u.look, { headOnly: true, direction: 3 })}
@@ -121,8 +121,8 @@ export default async function GuestView() {
<div className="flex w-full flex-col gap-4 md:w-2/3">
<div
className="overflow-hidden rounded-lg border bg-white dark:bg-gray-800"
style={{ borderColor: "color-mix(in srgb, var(--color-text-muted) 22%, transparent)" }}
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"
@@ -135,7 +135,7 @@ export default async function GuestView() {
</div>
<div className="p-4">
{articles.length === 0 ? (
<p className="py-8 text-center text-gray-500 dark:text-gray-400">No articles available</p>
<p className="py-8 text-center" style={{ color: "var(--color-text-muted)" }}>{t("noArticles")}</p>
) : (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
{articles.map((a) => (
+2 -2
View File
@@ -124,7 +124,7 @@ export default async function UserView({ userId, username, look }: UserViewProps
</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 text-gray-500 dark:text-white md:mb-0 md:text-left">
<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)" }}>
{t("noFriendsOnline")}
</p>
) : (
@@ -178,7 +178,7 @@ export default async function UserView({ userId, username, look }: UserViewProps
<div className="p-3">
<h3 className="text-sm font-semibold">{latestArticle.title}</h3>
{latestArticle.shortStory && (
<p className="mt-1 text-xs text-gray-500 dark:text-gray-400">
<p className="mt-1 text-xs" style={{ color: "var(--color-text-muted)" }}>
{excerpt(latestArticle.shortStory, 100)}
</p>
)}
+1 -2
View File
@@ -20,8 +20,7 @@ export async function Navigation() {
<div className="flex items-center gap-x-1 md:gap-x-1 flex-1 md:flex-none">
<Link href="/" className="nav-item shrink-0">
<img src="/assets/images/icons/navigation/me.png" alt="" className="w-5 h-5 mr-1.5" />
<span className="hidden sm:inline">{t("home")}</span>
<span className="sm:hidden">{t("home")}</span>
<span>{t("home")}</span>
</Link>
</div>
+1 -1
View File
@@ -20,7 +20,7 @@ export async function SiteHeader() {
online = 0;
}
const bannerUrl = header && header !== "/assets/images/background.png" ? header : "/assets/images/mybobba_banner.png";
const bannerUrl = header && header !== "/assets/images/background.png" ? header : "/assets/images/banner.png";
return (
<div className="site-header relative w-full overflow-hidden" style={{ minHeight: "18rem" }}>
+93 -35
View File
File diff suppressed because it is too large. Load diff
-1
View File
@@ -724,7 +724,6 @@
"logs": "Logs",
"wordFilter": "Word filter",
"maintenance": "Maintenance",
"housekeeping": "Housekeeping",
"rooms": "Rooms",
"emailTemplates": "Email templates",
"theme": "Theme",
+94 -36
View File
File diff suppressed because it is too large. Load diff
+94 -36
View File
File diff suppressed because it is too large. Load diff
+94 -36
View File
File diff suppressed because it is too large. Load diff
+3
View File
@@ -386,6 +386,7 @@ mv /var/log/emu/emulator.log /var/log/emu/\$file_name
java -Dfile.encoding=UTF8 -Xmx2G -jar $jar
EOJ
chmod +x emulator; ok "Launch script updated"
cd "$SCRIPT_DIR"
ROLLBACK_NEEDED=false
else
info "Emulator: already up to date"
@@ -396,6 +397,7 @@ update_renderer() {
step 3 8 "Update Nitro_Render_V3"
if git_update "$NITRO_RENDERER" "$NITRO_BRANCH"; then
HAD_UPDATES=true; UPDATED_REPOS+=("Nitro_Render_V3")
cd "$NITRO_RENDERER"
spinner_start "Installing deps..."
yarn install --frozen-lockfile 2>&1 || { clean_node_modules && yarn install 2>&1; } || { spinner_stop fail; die "yarn install failed"; }
spinner_stop ok; ok "Renderer dependencies installed"
@@ -408,6 +410,7 @@ update_client() {
step 4 8 "Update & Build Nitro-V3"
if git_update "$NITRO_CLIENT" "$NITRO_BRANCH"; then
HAD_UPDATES=true; NITRO_BUILT=true; UPDATED_REPOS+=("Nitro-V3")
cd "$NITRO_CLIENT"
spinner_start "Installing deps..."
yarn install --frozen-lockfile 2>&1 || { clean_node_modules && yarn install 2>&1; } || { spinner_stop fail; die "yarn install failed"; }
spinner_stop ok