mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-12-06 00:16:49 +00:00
@@ -5,6 +5,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>Nginx Proxy Manager</title>
|
<title>Nginx Proxy Manager</title>
|
||||||
<meta name="description" content="In The Office Planner" />
|
<meta name="description" content="In The Office Planner" />
|
||||||
|
<link rel="preload" href="/images/logo-no-text.svg" as="image" type="image/svg+xml" fetchPriority="high">
|
||||||
<link
|
<link
|
||||||
rel="apple-touch-icon"
|
rel="apple-touch-icon"
|
||||||
sizes="180x180"
|
sizes="180x180"
|
||||||
|
|||||||
@@ -13,6 +13,15 @@
|
|||||||
--tblr-backdrop-opacity: 0.8 !important;
|
--tblr-backdrop-opacity: 0.8 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-bs-theme="dark"] .modal-content {
|
||||||
|
--tblr-modal-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-bs-theme="dark"] .modal-backdrop {
|
||||||
|
--tblr-backdrop-bg: #000 !important;
|
||||||
|
--tblr-backdrop-opacity: 0.65 !important;
|
||||||
|
}
|
||||||
|
|
||||||
.domain-name {
|
.domain-name {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
@@ -95,3 +104,15 @@ label.row {
|
|||||||
border-radius: var(--tblr-border-radius) 0 0 var(--tblr-border-radius);
|
border-radius: var(--tblr-border-radius) 0 0 var(--tblr-border-radius);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fix for dropdown menus being clipped by table-responsive containers. */
|
||||||
|
.table-responsive .dropdown {
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix for Tabler scrollbar compensation */
|
||||||
|
@media (min-width: 992px) {
|
||||||
|
:host, :root {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,11 @@ import { useTheme } from "src/hooks";
|
|||||||
import { changeLocale, getFlagCodeForLocale, localeOptions, T } from "src/locale";
|
import { changeLocale, getFlagCodeForLocale, localeOptions, T } from "src/locale";
|
||||||
import styles from "./LocalePicker.module.css";
|
import styles from "./LocalePicker.module.css";
|
||||||
|
|
||||||
function LocalePicker() {
|
interface Props {
|
||||||
|
menuAlign?: "start" | "end";
|
||||||
|
}
|
||||||
|
|
||||||
|
function LocalePicker({ menuAlign = "start" }: Props) {
|
||||||
const { locale, setLocale } = useLocaleState();
|
const { locale, setLocale } = useLocaleState();
|
||||||
const { getTheme } = useTheme();
|
const { getTheme } = useTheme();
|
||||||
|
|
||||||
@@ -23,7 +27,10 @@ function LocalePicker() {
|
|||||||
<button type="button" className={cns} data-bs-toggle="dropdown">
|
<button type="button" className={cns} data-bs-toggle="dropdown">
|
||||||
<Flag countryCode={getFlagCodeForLocale(locale)} />
|
<Flag countryCode={getFlagCodeForLocale(locale)} />
|
||||||
</button>
|
</button>
|
||||||
<div className="dropdown-menu">
|
<div className={cn("dropdown-menu", {
|
||||||
|
"dropdown-menu-end": menuAlign === "end",
|
||||||
|
})}
|
||||||
|
>
|
||||||
{localeOptions.map((item) => {
|
{localeOptions.map((item) => {
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
|
|||||||
@@ -2,5 +2,5 @@ interface Props {
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
export function SiteContainer({ children }: Props) {
|
export function SiteContainer({ children }: Props) {
|
||||||
return <div className="container-xl py-3">{children}</div>;
|
return <div className="container-xl py-3 min-w-0 overflow-x-auto">{children}</div>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export function SiteHeader() {
|
|||||||
>
|
>
|
||||||
<span className="navbar-toggler-icon" />
|
<span className="navbar-toggler-icon" />
|
||||||
</button>
|
</button>
|
||||||
<div className="navbar-brand navbar-brand-autodark d-none-navbar-horizontal pe-0 pe-md-3">
|
<div className="navbar-brand navbar-brand-autodark pe-0 pe-md-3">
|
||||||
<NavLink to="/">
|
<NavLink to="/">
|
||||||
<div className={styles.logo}>
|
<div className={styles.logo}>
|
||||||
<img
|
<img
|
||||||
@@ -48,11 +48,11 @@ export function SiteHeader() {
|
|||||||
<ThemeSwitcher />
|
<ThemeSwitcher />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="nav-item d-none d-md-flex me-3">
|
<div className="nav-item d-md-flex">
|
||||||
<div className="nav-item dropdown">
|
<div className="nav-item dropdown">
|
||||||
<a
|
<a
|
||||||
href="/"
|
href="/"
|
||||||
className="nav-link d-flex lh-1 p-0 px-2"
|
className="nav-link d-flex lh-1"
|
||||||
data-bs-toggle="dropdown"
|
data-bs-toggle="dropdown"
|
||||||
aria-label="Open user menu"
|
aria-label="Open user menu"
|
||||||
>
|
>
|
||||||
@@ -70,6 +70,22 @@ export function SiteHeader() {
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div className="dropdown-menu dropdown-menu-end dropdown-menu-arrow">
|
<div className="dropdown-menu dropdown-menu-end dropdown-menu-arrow">
|
||||||
|
<div className="d-md-none">
|
||||||
|
{/* biome-ignore lint/a11y/noStaticElementInteractions lint/a11y/useKeyWithClickEvents: This div is not interactive. */}
|
||||||
|
<div className="p-2 pb-1 pe-1 d-flex align-items-center" onClick={e => e.stopPropagation()}>
|
||||||
|
<div className="ps-2 pe-1 me-auto">
|
||||||
|
<div>{currentUser?.nickname}</div>
|
||||||
|
<div className="mt-1 small text-secondary text-nowrap">
|
||||||
|
<T id={isAdmin ? "role.admin" : "role.standard-user"} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="d-flex align-items-center">
|
||||||
|
<ThemeSwitcher className="me-n2" />
|
||||||
|
<LocalePicker menuAlign="end" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="dropdown-divider" />
|
||||||
|
</div>
|
||||||
<a
|
<a
|
||||||
href="?"
|
href="?"
|
||||||
className="dropdown-item"
|
className="dropdown-item"
|
||||||
|
|||||||
@@ -176,17 +176,13 @@ const getMenuDropown = (item: MenuItem, onClick?: () => void) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function SiteMenu() {
|
export function SiteMenu() {
|
||||||
// This is hacky AF. But that's the price of using a non-react UI kit.
|
const closeMenu = () => setTimeout(() => {
|
||||||
const closeMenus = () => {
|
const navbarToggler = document.querySelector<HTMLElement>(".navbar-toggler");
|
||||||
const navMenus = document.querySelectorAll(".nav-item.dropdown");
|
const navbarMenu = document.querySelector("#navbar-menu");
|
||||||
navMenus.forEach((menu) => {
|
if (navbarToggler && navbarMenu?.classList.contains("show")) {
|
||||||
menu.classList.remove("show");
|
navbarToggler.click();
|
||||||
const dropdown = menu.querySelector(".dropdown-menu");
|
}
|
||||||
if (dropdown) {
|
}, 300);
|
||||||
dropdown.classList.remove("show");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="navbar-expand-md">
|
<header className="navbar-expand-md">
|
||||||
@@ -198,7 +194,7 @@ export function SiteMenu() {
|
|||||||
<ul className="navbar-nav">
|
<ul className="navbar-nav">
|
||||||
{menuItems.length > 0 &&
|
{menuItems.length > 0 &&
|
||||||
menuItems.map((item) => {
|
menuItems.map((item) => {
|
||||||
return getMenuItem(item, closeMenus);
|
return getMenuItem(item, closeMenu);
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,10 +12,12 @@ interface TableLayoutProps<TFields> {
|
|||||||
function TableLayout<TFields>(props: TableLayoutProps<TFields>) {
|
function TableLayout<TFields>(props: TableLayoutProps<TFields>) {
|
||||||
const hasRows = props.tableInstance.getRowModel().rows.length > 0;
|
const hasRows = props.tableInstance.getRowModel().rows.length > 0;
|
||||||
return (
|
return (
|
||||||
<table className="table table-vcenter table-selectable mb-0">
|
<div className="table-responsive">
|
||||||
{hasRows ? <TableHeader tableInstance={props.tableInstance} /> : null}
|
<table className="table table-vcenter table-selectable mb-0">
|
||||||
<TableBody {...props} />
|
{hasRows ? <TableHeader tableInstance={props.tableInstance} /> : null}
|
||||||
</table>
|
<TableBody {...props} />
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,3 @@
|
|||||||
.logo {
|
.logo {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.helperBtns {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
right: 10px;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import cn from "classnames";
|
|
||||||
import { Field, Form, Formik } from "formik";
|
import { Field, Form, Formik } from "formik";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import Alert from "react-bootstrap/Alert";
|
import Alert from "react-bootstrap/Alert";
|
||||||
@@ -43,17 +42,17 @@ export default function Login() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Page className="page page-center">
|
<Page className="page page-center">
|
||||||
<div className={cn("d-none", "d-md-flex", styles.helperBtns)}>
|
|
||||||
<LocalePicker />
|
|
||||||
<ThemeSwitcher />
|
|
||||||
</div>
|
|
||||||
<div className="container container-tight py-4">
|
<div className="container container-tight py-4">
|
||||||
<div className="text-center mb-4">
|
<div className="d-flex justify-content-between align-items-center mb-4 ps-4 pe-3">
|
||||||
<img
|
<img
|
||||||
className={styles.logo}
|
className={styles.logo}
|
||||||
src="/images/logo-text-horizontal-grey.png"
|
src="/images/logo-text-horizontal-grey.png"
|
||||||
alt="Nginx Proxy Manager"
|
alt="Nginx Proxy Manager"
|
||||||
/>
|
/>
|
||||||
|
<div className="d-flex align-items-center gap-1">
|
||||||
|
<LocalePicker />
|
||||||
|
<ThemeSwitcher />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="card card-md">
|
<div className="card card-md">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
|
|||||||
Reference in New Issue
Block a user