mirror of
https://github.com/RayLabsHQ/gitea-mirror.git
synced 2025-12-11 05:56:46 +03:00
UI updates
This commit is contained in:
@@ -7,7 +7,7 @@ import { toast } from "sonner";
|
|||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
import { useLiveRefresh } from "@/hooks/useLiveRefresh";
|
import { useLiveRefresh } from "@/hooks/useLiveRefresh";
|
||||||
import { useConfigStatus } from "@/hooks/useConfigStatus";
|
import { useConfigStatus } from "@/hooks/useConfigStatus";
|
||||||
import { Menu, LogOut } from "lucide-react";
|
import { Menu, LogOut, PanelRightOpen, PanelRightClose } from "lucide-react";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
@@ -19,9 +19,12 @@ interface HeaderProps {
|
|||||||
currentPage?: "dashboard" | "repositories" | "organizations" | "configuration" | "activity-log";
|
currentPage?: "dashboard" | "repositories" | "organizations" | "configuration" | "activity-log";
|
||||||
onNavigate?: (page: string) => void;
|
onNavigate?: (page: string) => void;
|
||||||
onMenuClick: () => void;
|
onMenuClick: () => void;
|
||||||
|
onToggleCollapse?: () => void;
|
||||||
|
isSidebarCollapsed?: boolean;
|
||||||
|
isSidebarOpen?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Header({ currentPage, onNavigate, onMenuClick }: HeaderProps) {
|
export function Header({ currentPage, onNavigate, onMenuClick, onToggleCollapse, isSidebarCollapsed, isSidebarOpen }: HeaderProps) {
|
||||||
const { user, logout, isLoading } = useAuth();
|
const { user, logout, isLoading } = useAuth();
|
||||||
const { isLiveEnabled, toggleLive } = useLiveRefresh();
|
const { isLiveEnabled, toggleLive } = useLiveRefresh();
|
||||||
const { isFullyConfigured, isLoading: configLoading } = useConfigStatus();
|
const { isFullyConfigured, isLoading: configLoading } = useConfigStatus();
|
||||||
@@ -63,18 +66,38 @@ export function Header({ currentPage, onNavigate, onMenuClick }: HeaderProps) {
|
|||||||
return (
|
return (
|
||||||
<header className="border-b bg-background">
|
<header className="border-b bg-background">
|
||||||
<div className="flex h-[4.5rem] items-center justify-between px-4 sm:px-6">
|
<div className="flex h-[4.5rem] items-center justify-between px-4 sm:px-6">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-12">
|
||||||
{/* Hamburger Menu Button - Mobile Only */}
|
{/* Sidebar Toggle - Mobile uses slide-in, Medium uses collapse */}
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="ghost"
|
||||||
size="lg"
|
size="icon"
|
||||||
className="lg:hidden"
|
className="md:hidden h-10 w-10"
|
||||||
onClick={onMenuClick}
|
onClick={onMenuClick}
|
||||||
>
|
>
|
||||||
<Menu className="h-5 w-5" />
|
{isSidebarOpen ? (
|
||||||
|
<PanelRightOpen className="h-5 w-5" />
|
||||||
|
) : (
|
||||||
|
<PanelRightClose className="h-5 w-5" />
|
||||||
|
)}
|
||||||
<span className="sr-only">Toggle menu</span>
|
<span className="sr-only">Toggle menu</span>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
{/* Sidebar Collapse Toggle - Only on medium screens (768px - 1280px) */}
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="hidden md:flex xl:hidden h-10 w-10"
|
||||||
|
onClick={onToggleCollapse}
|
||||||
|
title={isSidebarCollapsed ? "Expand sidebar" : "Collapse sidebar"}
|
||||||
|
>
|
||||||
|
{isSidebarCollapsed ? (
|
||||||
|
<PanelRightClose className="h-5 w-5" />
|
||||||
|
) : (
|
||||||
|
<PanelRightOpen className="h-5 w-5" />
|
||||||
|
)}
|
||||||
|
<span className="sr-only">Toggle sidebar</span>
|
||||||
|
</Button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (currentPage !== 'dashboard') {
|
if (currentPage !== 'dashboard') {
|
||||||
|
|||||||
@@ -45,6 +45,13 @@ function AppWithProviders({ page: initialPage }: AppProps) {
|
|||||||
const [currentPage, setCurrentPage] = useState<AppProps['page']>(initialPage);
|
const [currentPage, setCurrentPage] = useState<AppProps['page']>(initialPage);
|
||||||
const [navigationKey, setNavigationKey] = useState(0);
|
const [navigationKey, setNavigationKey] = useState(0);
|
||||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||||
|
const [sidebarCollapsed, setSidebarCollapsed] = useState(() => {
|
||||||
|
// Check if we're on medium screens (768px - 1280px)
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
return window.innerWidth >= 768 && window.innerWidth < 1280;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
useRepoSync({
|
useRepoSync({
|
||||||
userId: user?.id,
|
userId: user?.id,
|
||||||
@@ -83,6 +90,23 @@ function AppWithProviders({ page: initialPage }: AppProps) {
|
|||||||
return () => window.removeEventListener('popstate', handlePopState);
|
return () => window.removeEventListener('popstate', handlePopState);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Handle window resize to auto-collapse sidebar on medium screens
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
const width = window.innerWidth;
|
||||||
|
// Auto-collapse on medium screens (768px - 1280px)
|
||||||
|
if (width >= 768 && width < 1280) {
|
||||||
|
setSidebarCollapsed(true);
|
||||||
|
} else if (width >= 1280) {
|
||||||
|
// Expand on large screens
|
||||||
|
setSidebarCollapsed(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
return () => window.removeEventListener('resize', handleResize);
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Show loading state only during initial auth/config loading
|
// Show loading state only during initial auth/config loading
|
||||||
const isInitialLoading = authLoading || (configLoading && !user);
|
const isInitialLoading = authLoading || (configLoading && !user);
|
||||||
|
|
||||||
@@ -113,14 +137,21 @@ function AppWithProviders({ page: initialPage }: AppProps) {
|
|||||||
currentPage={currentPage}
|
currentPage={currentPage}
|
||||||
onNavigate={handleNavigation}
|
onNavigate={handleNavigation}
|
||||||
onMenuClick={() => setSidebarOpen(!sidebarOpen)}
|
onMenuClick={() => setSidebarOpen(!sidebarOpen)}
|
||||||
|
onToggleCollapse={() => setSidebarCollapsed(!sidebarCollapsed)}
|
||||||
|
isSidebarCollapsed={sidebarCollapsed}
|
||||||
|
isSidebarOpen={sidebarOpen}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-1 relative">
|
<div className="flex flex-1 relative">
|
||||||
<Sidebar
|
<Sidebar
|
||||||
onNavigate={handleNavigation}
|
onNavigate={handleNavigation}
|
||||||
isOpen={sidebarOpen}
|
isOpen={sidebarOpen}
|
||||||
|
isCollapsed={sidebarCollapsed}
|
||||||
onClose={() => setSidebarOpen(false)}
|
onClose={() => setSidebarOpen(false)}
|
||||||
|
onToggleCollapse={() => setSidebarCollapsed(!sidebarCollapsed)}
|
||||||
/>
|
/>
|
||||||
<section className="flex-1 p-4 sm:p-6 overflow-y-auto h-[calc(100dvh-4.55rem)] w-full lg:w-[calc(100%-16rem)]">
|
<section className={`flex-1 p-4 sm:p-6 overflow-y-auto h-[calc(100dvh-4.55rem)] w-full transition-all duration-200 ${
|
||||||
|
sidebarCollapsed ? 'md:w-[calc(100%-5rem)] xl:w-[calc(100%-16rem)]' : 'md:w-[calc(100%-16rem)]'
|
||||||
|
}`}>
|
||||||
{currentPage === "dashboard" && <Dashboard />}
|
{currentPage === "dashboard" && <Dashboard />}
|
||||||
{currentPage === "repositories" && <Repository />}
|
{currentPage === "repositories" && <Repository />}
|
||||||
{currentPage === "organizations" && <Organization />}
|
{currentPage === "organizations" && <Organization />}
|
||||||
|
|||||||
@@ -3,15 +3,23 @@ import { cn } from "@/lib/utils";
|
|||||||
import { ExternalLink } from "lucide-react";
|
import { ExternalLink } from "lucide-react";
|
||||||
import { links } from "@/data/Sidebar";
|
import { links } from "@/data/Sidebar";
|
||||||
import { VersionInfo } from "./VersionInfo";
|
import { VersionInfo } from "./VersionInfo";
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip";
|
||||||
|
|
||||||
interface SidebarProps {
|
interface SidebarProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
onNavigate?: (page: string) => void;
|
onNavigate?: (page: string) => void;
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
|
isCollapsed?: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
|
onToggleCollapse?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Sidebar({ className, onNavigate, isOpen, onClose }: SidebarProps) {
|
export function Sidebar({ className, onNavigate, isOpen, isCollapsed = false, onClose, onToggleCollapse }: SidebarProps) {
|
||||||
const [currentPath, setCurrentPath] = useState<string>("");
|
const [currentPath, setCurrentPath] = useState<string>("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -53,7 +61,7 @@ export function Sidebar({ className, onNavigate, isOpen, onClose }: SidebarProps
|
|||||||
onNavigate?.(pageName);
|
onNavigate?.(pageName);
|
||||||
|
|
||||||
// Close sidebar on mobile after navigation
|
// Close sidebar on mobile after navigation
|
||||||
if (window.innerWidth < 1024) {
|
if (window.innerWidth < 768) {
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -63,7 +71,7 @@ export function Sidebar({ className, onNavigate, isOpen, onClose }: SidebarProps
|
|||||||
{/* Mobile Backdrop */}
|
{/* Mobile Backdrop */}
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<div
|
<div
|
||||||
className="fixed inset-0 backdrop-blur-sm z-40 lg:hidden"
|
className="fixed inset-0 backdrop-blur-sm z-40 md:hidden"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -71,56 +79,128 @@ export function Sidebar({ className, onNavigate, isOpen, onClose }: SidebarProps
|
|||||||
{/* Sidebar */}
|
{/* Sidebar */}
|
||||||
<aside
|
<aside
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed lg:static inset-y-0 left-0 z-50 w-64 bg-background border-r flex flex-col h-full lg:h-[calc(100vh-4.5rem)] transition-transform duration-200 ease-in-out lg:translate-x-0",
|
"fixed md:static inset-y-0 left-0 z-50 bg-background border-r flex flex-col h-full md:h-[calc(100vh-4.5rem)] transition-all duration-200 ease-in-out md:translate-x-0",
|
||||||
isOpen ? "translate-x-0" : "-translate-x-full",
|
isOpen ? "translate-x-0" : "-translate-x-full",
|
||||||
|
isCollapsed ? "md:w-20 xl:w-64" : "w-64",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex flex-col h-full">
|
<div className="flex flex-col h-full">
|
||||||
<nav className="flex flex-col gap-y-1 lg:gap-y-1 pl-2 pr-3 pt-4 flex-shrink-0">
|
<nav className={cn(
|
||||||
|
"flex flex-col pt-4 flex-shrink-0",
|
||||||
|
isCollapsed
|
||||||
|
? "md:gap-y-2 md:items-center md:px-2 xl:gap-y-1 xl:items-stretch xl:pl-2 xl:pr-3 gap-y-1 pl-2 pr-3"
|
||||||
|
: "gap-y-1 pl-2 pr-3"
|
||||||
|
)}>
|
||||||
{links.map((link, index) => {
|
{links.map((link, index) => {
|
||||||
const isActive = currentPath === link.href;
|
const isActive = currentPath === link.href;
|
||||||
const Icon = link.icon;
|
const Icon = link.icon;
|
||||||
|
|
||||||
return (
|
const button = (
|
||||||
<button
|
<button
|
||||||
key={index}
|
key={index}
|
||||||
onClick={(e) => handleNavigation(link.href, e)}
|
onClick={(e) => handleNavigation(link.href, e)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center gap-3 rounded-md px-3 py-3 lg:py-2 text-sm lg:text-sm font-medium transition-colors w-full text-left",
|
"flex items-center rounded-md text-sm font-medium transition-colors w-full",
|
||||||
|
isCollapsed
|
||||||
|
? "md:h-12 md:w-12 md:justify-center md:p-0 xl:h-auto xl:w-full xl:justify-start xl:px-3 xl:py-2 h-auto px-3 py-3"
|
||||||
|
: "px-3 py-3 md:py-2",
|
||||||
isActive
|
isActive
|
||||||
? "bg-primary text-primary-foreground"
|
? "bg-primary text-primary-foreground"
|
||||||
: "text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
: "text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Icon className="h-5 w-5 lg:h-4 lg:w-4" />
|
<Icon className={cn(
|
||||||
|
"flex-shrink-0",
|
||||||
|
isCollapsed
|
||||||
|
? "md:h-5 md:w-5 md:mr-0 xl:h-4 xl:w-4 xl:mr-3 h-5 w-5 mr-3"
|
||||||
|
: "h-5 w-5 md:h-4 md:w-4 mr-3"
|
||||||
|
)} />
|
||||||
|
<span className={cn(
|
||||||
|
"transition-all duration-200",
|
||||||
|
isCollapsed ? "md:hidden xl:inline" : "inline"
|
||||||
|
)}>
|
||||||
{link.label}
|
{link.label}
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Wrap in tooltip when collapsed on medium screens
|
||||||
|
if (isCollapsed) {
|
||||||
|
return (
|
||||||
|
<TooltipProvider key={index}>
|
||||||
|
<Tooltip delayDuration={0}>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
{button}
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="right" className="hidden md:block xl:hidden">
|
||||||
|
{link.label}
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return button;
|
||||||
})}
|
})}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div className="flex-1 min-h-0" />
|
<div className="flex-1 min-h-0" />
|
||||||
|
|
||||||
<div className="px-4 py-4 flex-shrink-0">
|
<div className={cn(
|
||||||
<div className="rounded-md bg-muted p-3 lg:p-3">
|
"py-4 flex-shrink-0",
|
||||||
|
isCollapsed ? "md:px-2 xl:px-4 px-4" : "px-4"
|
||||||
|
)}>
|
||||||
|
<div className={cn(
|
||||||
|
"rounded-md bg-muted transition-all duration-200",
|
||||||
|
isCollapsed ? "md:p-0 xl:p-3 p-3" : "p-3"
|
||||||
|
)}>
|
||||||
|
<div className={cn(
|
||||||
|
isCollapsed ? "md:hidden xl:block" : "block"
|
||||||
|
)}>
|
||||||
<h4 className="text-sm font-medium mb-2">Need Help?</h4>
|
<h4 className="text-sm font-medium mb-2">Need Help?</h4>
|
||||||
<p className="text-xs text-muted-foreground mb-3 lg:mb-2">
|
<p className="text-xs text-muted-foreground mb-3 md:mb-2">
|
||||||
Check out the documentation for help with setup and configuration.
|
Check out the documentation for help with setup and configuration.
|
||||||
</p>
|
</p>
|
||||||
<a
|
<a
|
||||||
href="/docs"
|
href="/docs"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="inline-flex items-center gap-1.5 text-xs lg:text-xs text-primary hover:underline py-2 lg:py-0"
|
className="inline-flex items-center gap-1.5 text-xs md:text-xs text-primary hover:underline py-2 md:py-0"
|
||||||
>
|
>
|
||||||
Documentation
|
Documentation
|
||||||
<ExternalLink className="h-3.5 w-3.5 lg:h-3 lg:w-3" />
|
<ExternalLink className="h-3.5 w-3.5 md:h-3 md:w-3" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
{/* Icon-only help button for collapsed state on medium screens */}
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip delayDuration={0}>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<a
|
||||||
|
href="/docs"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className={cn(
|
||||||
|
"flex items-center justify-center rounded-md hover:bg-accent transition-colors",
|
||||||
|
isCollapsed ? "md:h-12 md:w-12 xl:hidden hidden" : "hidden"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<ExternalLink className="h-5 w-5" />
|
||||||
|
</a>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="right">
|
||||||
|
Documentation
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
</div>
|
||||||
|
<div className={cn(
|
||||||
|
isCollapsed ? "md:hidden xl:block" : "block"
|
||||||
|
)}>
|
||||||
<VersionInfo />
|
<VersionInfo />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { FlipHorizontal, GitFork, RefreshCw, RotateCcw, Star, Lock, Ban, Check,
|
|||||||
import { SiGithub, SiGitea } from "react-icons/si";
|
import { SiGithub, SiGitea } from "react-icons/si";
|
||||||
import type { Repository } from "@/lib/db/schema";
|
import type { Repository } from "@/lib/db/schema";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { formatDate, getStatusColor } from "@/lib/utils";
|
import { formatDate, formatLastSyncTime, getStatusColor } from "@/lib/utils";
|
||||||
import type { FilterParams } from "@/types/filter";
|
import type { FilterParams } from "@/types/filter";
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
import { useGiteaConfig } from "@/hooks/useGiteaConfig";
|
import { useGiteaConfig } from "@/hooks/useGiteaConfig";
|
||||||
@@ -242,7 +242,7 @@ export default function RepositoryTable({
|
|||||||
{repo.status}
|
{repo.status}
|
||||||
</Badge>
|
</Badge>
|
||||||
<span className="text-xs text-muted-foreground">
|
<span className="text-xs text-muted-foreground">
|
||||||
{repo.lastMirrored ? formatDate(repo.lastMirrored) : "Never mirrored"}
|
{formatLastSyncTime(repo.lastMirrored)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -410,7 +410,7 @@ export default function RepositoryTable({
|
|||||||
<div className="h-full p-3 flex items-center justify-center flex-[0.3]">
|
<div className="h-full p-3 flex items-center justify-center flex-[0.3]">
|
||||||
<Skeleton className="h-4 w-4" />
|
<Skeleton className="h-4 w-4" />
|
||||||
</div>
|
</div>
|
||||||
<div className="h-full p-3 text-sm font-medium flex-[2.5]">
|
<div className="h-full py-3 text-sm font-medium flex-[2.3]">
|
||||||
Repository
|
Repository
|
||||||
</div>
|
</div>
|
||||||
<div className="h-full p-3 text-sm font-medium flex-[1]">Owner</div>
|
<div className="h-full p-3 text-sm font-medium flex-[1]">Owner</div>
|
||||||
@@ -437,7 +437,7 @@ export default function RepositoryTable({
|
|||||||
<div className="h-full p-3 flex items-center justify-center flex-[0.3]">
|
<div className="h-full p-3 flex items-center justify-center flex-[0.3]">
|
||||||
<Skeleton className="h-4 w-4" />
|
<Skeleton className="h-4 w-4" />
|
||||||
</div>
|
</div>
|
||||||
<div className="h-full p-3 flex-[2.5]">
|
<div className="h-full p-3 flex-[2.3]">
|
||||||
<Skeleton className="h-5 w-48" />
|
<Skeleton className="h-5 w-48" />
|
||||||
<Skeleton className="h-3 w-24 mt-1" />
|
<Skeleton className="h-3 w-24 mt-1" />
|
||||||
</div>
|
</div>
|
||||||
@@ -530,7 +530,7 @@ export default function RepositoryTable({
|
|||||||
aria-label="Select all repositories"
|
aria-label="Select all repositories"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="h-full p-3 text-sm font-medium flex-[2.5]">
|
<div className="h-full py-3 text-sm font-medium flex-[2.3]">
|
||||||
Repository
|
Repository
|
||||||
</div>
|
</div>
|
||||||
<div className="h-full p-3 text-sm font-medium flex-[1]">Owner</div>
|
<div className="h-full p-3 text-sm font-medium flex-[1]">Owner</div>
|
||||||
@@ -588,7 +588,7 @@ export default function RepositoryTable({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Repository */}
|
{/* Repository */}
|
||||||
<div className="h-full py-3 flex items-center gap-2 flex-[2.5]">
|
<div className="h-full py-3 flex items-center gap-2 flex-[2.3]">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="font-medium flex items-center gap-1">
|
<div className="font-medium flex items-center gap-1">
|
||||||
{repo.name}
|
{repo.name}
|
||||||
@@ -629,9 +629,7 @@ export default function RepositoryTable({
|
|||||||
{/* Last Mirrored */}
|
{/* Last Mirrored */}
|
||||||
<div className="h-full p-3 flex items-center flex-[1]">
|
<div className="h-full p-3 flex items-center flex-[1]">
|
||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
{repo.lastMirrored
|
{formatLastSyncTime(repo.lastMirrored)}
|
||||||
? formatDate(new Date(repo.lastMirrored))
|
|
||||||
: "Never"}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user