mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
Two mobile-QA defects across the block explorers.
Defect 1 (org explorers showed goerli stub data): api-explore.{zoo,hanzo,
pars}.network served the self-signed INGRESS DEFAULT CERT (no cert-manager
Ingress for those SNIs), so browsers rejected every FE fetch and react-query
fell back to the goerli stubs behind stuck skeletons. FE wiring + backend were
already correct (all 6 chains served real per-chain data via the existing
IngressRoutes). Fix: dedicated letsencrypt-prod Ingress per org api host ->
explorer-unified:8090, mirroring api-explore-lux-network. Certs issued, all
three now ssl_verify=0, real data flows. Also source per-org brand identity
(NETWORK_NAME/currency) in the configmaps so titles render the right brand.
Defect 2 (mobile 390px detail pages: dropped labels, horizontal clip, tab
overlap): three shared-UI fixes.
- Footer: was the real horizontal-overflow driver — inline gridTemplateColumns
minmax(auto,470px) never collapsed on mobile. Now grid-cols-1 on mobile.
- DetailedInfo.ItemValue: add min-w-0 + mobile wrap so long address/hash values
stop forcing the page wider than the viewport (desktop unchanged).
- AdaptiveTabsList: @luxfi/ui Tabs silently discard Chakra style props
(overflowX/w/flexShrink/...), so express mobile scroll + shrink-0 as
className. Tab strip now scrolls instead of collapsing/overlapping.
Co-authored-by: Hanzo Dev <[email protected]>
115 lines
3.6 KiB
TypeScript
115 lines
3.6 KiB
TypeScript
import { Skeleton } from '@luxfi/ui/skeleton';
|
|
import React from 'react';
|
|
|
|
import { cn } from 'lib/utils/cn';
|
|
import { Hint } from 'toolkit/components/Hint/Hint';
|
|
import * as ContainerWithScrollY from 'ui/shared/ContainerWithScrollY';
|
|
|
|
export const ITEM_VALUE_LINE_HEIGHT = { base: '30px', lg: '32px' };
|
|
|
|
interface ContainerProps {
|
|
children: React.ReactNode;
|
|
className?: string;
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
[key: string]: any;
|
|
}
|
|
|
|
export const Container = ({ children, className }: ContainerProps) => {
|
|
return (
|
|
<div className={ cn(
|
|
'grid gap-x-8 gap-y-0 lg:gap-y-3 grid-cols-1 lg:grid-cols-[max-content_minmax(728px,auto)]',
|
|
'text-sm lg:text-base text-[var(--color-text-primary)]',
|
|
className,
|
|
) }>
|
|
{ children }
|
|
</div>
|
|
);
|
|
};
|
|
|
|
interface ItemLabelProps {
|
|
hint?: React.ReactNode;
|
|
children: React.ReactNode;
|
|
isLoading?: boolean;
|
|
id?: string;
|
|
hasScroll?: boolean;
|
|
className?: string;
|
|
}
|
|
|
|
const ItemLabelScrollText = () => (
|
|
<span className="font-medium text-[var(--color-text-secondary)] text-xs note text-right">
|
|
Scroll to see more
|
|
</span>
|
|
);
|
|
|
|
export const ItemLabel = ({ hint, children, isLoading, id, hasScroll, className }: ItemLabelProps) => {
|
|
return (
|
|
<div
|
|
id={ id }
|
|
className={ cn('min-h-[30px] lg:min-h-[32px] text-[var(--color-text-secondary)] [&:not(:first-child)]:mt-3 lg:[&:not(:first-child)]:mt-0', className) }
|
|
>
|
|
<div className="flex gap-x-1 lg:gap-x-2 items-start w-full">
|
|
{ hint && <Hint label={ hint } isLoading={ isLoading } className="my-[5px] lg:my-[6px]"/> }
|
|
<Skeleton loading={ isLoading } className="font-bold lg:font-medium py-[5px] lg:py-1 grow">
|
|
{ children }
|
|
{ hasScroll && <ItemLabelScrollText/> }
|
|
</Skeleton>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
interface ItemValueProps {
|
|
children: React.ReactNode;
|
|
multiRow?: boolean;
|
|
className?: string;
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
[key: string]: any;
|
|
}
|
|
|
|
export const ItemValue = ({ children, multiRow = false, className }: ItemValueProps) => {
|
|
return (
|
|
<div
|
|
className={ cn(
|
|
// Mobile: keep a long value (address/hash entity) from pushing the page
|
|
// wider than the viewport. min-w-0 lets the flex child shrink so the
|
|
// entity's dynamic shortener truncates to fit the cell; break-words wraps
|
|
// plain long strings; overflow-x-hidden is the hard guarantee that the
|
|
// cell can never overflow past its column edge. Desktop is unchanged
|
|
// (single-line nowrap, visible overflow).
|
|
'flex items-center pl-6 lg:pl-0 min-h-[30px] lg:min-h-[32px]',
|
|
'min-w-0 overflow-x-hidden whitespace-normal break-words lg:overflow-x-visible lg:whitespace-nowrap',
|
|
multiRow && 'flex-wrap leading-[30px] lg:leading-[32px]',
|
|
className,
|
|
) }
|
|
>
|
|
{ children }
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export const ItemValueWithScroll = ({ children, gradientHeight, onScrollVisibilityChange, className }: ContainerWithScrollY.Props) => {
|
|
return (
|
|
<ItemValue className="relative">
|
|
<ContainerWithScrollY.default
|
|
className={ className }
|
|
gradientHeight={ gradientHeight }
|
|
onScrollVisibilityChange={ onScrollVisibilityChange }
|
|
>
|
|
{ children }
|
|
</ContainerWithScrollY.default>
|
|
</ItemValue>
|
|
);
|
|
};
|
|
|
|
interface ItemDividerProps {
|
|
className?: string;
|
|
}
|
|
|
|
export const ItemDivider = ({ className }: ItemDividerProps) => {
|
|
return (
|
|
<div
|
|
className={ cn('col-span-1 lg:col-span-2 mt-2 lg:mt-3 mb-0 lg:mb-3 border-b border-[var(--color-border-divider)]', className) }
|
|
/>
|
|
);
|
|
};
|