Fixes responsiveness on the charts
This commit is contained in:
@@ -130,59 +130,4 @@ function rangeToMs(range: WorkspaceChartTimeRange) {
|
|||||||
case "30d":
|
case "30d":
|
||||||
return 30 * 24 * 60 * 60 * 1000;
|
return 30 * 24 * 60 * 60 * 1000;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function intervalToMs(interval: WorkspaceChartInterval) {
|
|
||||||
switch (interval) {
|
|
||||||
case "1m":
|
|
||||||
return 60 * 1000;
|
|
||||||
case "5m":
|
|
||||||
return 5 * 60 * 1000;
|
|
||||||
case "15m":
|
|
||||||
return 15 * 60 * 1000;
|
|
||||||
case "1h":
|
|
||||||
return 60 * 60 * 1000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function aggregatePoints(
|
|
||||||
points: WorkspaceChartPoint[],
|
|
||||||
interval: WorkspaceChartInterval,
|
|
||||||
): WorkspaceChartPoint[] {
|
|
||||||
const bucketMs = intervalToMs(interval);
|
|
||||||
|
|
||||||
if (bucketMs === 0) {
|
|
||||||
return points;
|
|
||||||
}
|
|
||||||
|
|
||||||
const buckets = new Map<number, number[]>();
|
|
||||||
|
|
||||||
for (const point of points) {
|
|
||||||
const time = new Date(point.timestamp).getTime();
|
|
||||||
|
|
||||||
if (!Number.isFinite(time)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bucketTime = Math.floor(time / bucketMs) * bucketMs;
|
|
||||||
|
|
||||||
const values = buckets.get(bucketTime) ?? [];
|
|
||||||
|
|
||||||
if (point.value !== null && Number.isFinite(point.value)) {
|
|
||||||
values.push(point.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
buckets.set(bucketTime, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Array.from(buckets.entries())
|
|
||||||
.sort(([a], [b]) => a - b)
|
|
||||||
.map(([bucketTime, values]) => ({
|
|
||||||
timestamp: new Date(bucketTime).toISOString(),
|
|
||||||
value: average(values),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
function average(values: number[]) {
|
|
||||||
return values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
||||||
}
|
}
|
||||||
@@ -537,7 +537,7 @@ export function ClimateChartsPage({ theme }: ClimateChartsPageProps) {
|
|||||||
}, [layoutMode]);
|
}, [layoutMode]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4 pb-6">
|
<div className="flex h-[calc(100vh-88px)] min-h-0 flex-col gap-3 overflow-hidden pb-2">
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
isDark
|
isDark
|
||||||
@@ -715,8 +715,8 @@ export function ClimateChartsPage({ theme }: ClimateChartsPageProps) {
|
|||||||
}}
|
}}
|
||||||
className={
|
className={
|
||||||
isDark
|
isDark
|
||||||
? `${RADIUS} flex min-h-[360px] items-center justify-center border-2 border-dashed border-[#4FD1C5] bg-[#07101B]/60 text-sm font-black text-[#4FD1C5]`
|
? `${RADIUS} flex min-h-0 items-center justify-center border-2 border-dashed border-[#4FD1C5] bg-[#07101B]/60 text-sm font-black text-[#4FD1C5]`
|
||||||
: `${RADIUS} flex min-h-[360px] items-center justify-center border-2 border-dashed border-[#0F766E] bg-[#ECFDF5] text-sm font-black text-[#0F766E]`
|
: `${RADIUS} flex min-h-0 items-center justify-center border-2 border-dashed border-[#0F766E] bg-[#ECFDF5] text-sm font-black text-[#0F766E]`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Colocar em novo espaço
|
Colocar em novo espaço
|
||||||
@@ -858,10 +858,10 @@ function WorkspaceChartContainer({
|
|||||||
}}
|
}}
|
||||||
className={
|
className={
|
||||||
canReceiveMove
|
canReceiveMove
|
||||||
? "relative rounded-[7px] ring-2 ring-[#4FD1C5]/50 transition"
|
? "relative min-h-0 overflow-hidden rounded-[7px] ring-2 ring-[#4FD1C5]/50 transition"
|
||||||
: isMoving
|
: isMoving
|
||||||
? "relative rounded-[7px] opacity-60 ring-2 ring-[#4FD1C5]"
|
? "relative min-h-0 overflow-hidden rounded-[7px] opacity-60 ring-2 ring-[#4FD1C5]"
|
||||||
: "relative rounded-[7px]"
|
: "relative min-h-0 overflow-hidden rounded-[7px]"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="absolute right-4 top-4 z-20 flex items-center gap-1.5">
|
<div className="absolute right-4 top-4 z-20 flex items-center gap-1.5">
|
||||||
@@ -1462,15 +1462,19 @@ function EmptyVariableList({ theme }: { theme: "dark" | "light" }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function layoutGridClass(layoutMode: ChartLayoutMode) {
|
function layoutGridClass(layoutMode: ChartLayoutMode) {
|
||||||
if (layoutMode === "twoColumns") {
|
|
||||||
return "grid gap-4 2xl:grid-cols-2";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (layoutMode === "fourGrid") {
|
if (layoutMode === "fourGrid") {
|
||||||
return "grid gap-4 2xl:grid-cols-2";
|
return "grid min-h-0 flex-1 grid-cols-2 grid-rows-2 gap-3 overflow-hidden";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "grid gap-4";
|
if (layoutMode === "twoColumns") {
|
||||||
|
return "grid min-h-0 flex-1 grid-cols-2 gap-3 overflow-hidden";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layoutMode === "twoRows") {
|
||||||
|
return "grid min-h-0 flex-1 grid-rows-2 gap-3 overflow-hidden";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "grid min-h-0 flex-1 gap-3 overflow-hidden";
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVisibleSlotCount(layoutMode: ChartLayoutMode) {
|
function getVisibleSlotCount(layoutMode: ChartLayoutMode) {
|
||||||
@@ -1566,8 +1570,8 @@ function EmptyWorkspace({
|
|||||||
<section
|
<section
|
||||||
className={
|
className={
|
||||||
isDark
|
isDark
|
||||||
? `${RADIUS} flex min-h-[520px] items-center justify-center border border-dashed border-[#33445F] bg-[#0E1726]/70`
|
? `${RADIUS} flex min-h-0 flex-1 items-center justify-center border border-dashed border-[#33445F] bg-[#0E1726]/70`
|
||||||
: `${RADIUS} flex min-h-[520px] items-center justify-center border border-dashed border-[#CBD5E1] bg-white`
|
: `${RADIUS} flex min-h-0 flex-1 items-center justify-center border border-dashed border-[#CBD5E1] bg-white`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="max-w-[420px] text-center">
|
<div className="max-w-[420px] text-center">
|
||||||
|
|||||||
@@ -539,7 +539,7 @@ export function MeteoChartsPage({
|
|||||||
}, [layoutMode]);
|
}, [layoutMode]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4 pb-6">
|
<div className="flex h-[calc(100vh-88px)] min-h-0 flex-col gap-3 overflow-hidden pb-2">
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
isDark
|
isDark
|
||||||
@@ -728,8 +728,8 @@ export function MeteoChartsPage({
|
|||||||
}}
|
}}
|
||||||
className={
|
className={
|
||||||
isDark
|
isDark
|
||||||
? `${RADIUS} flex min-h-[360px] items-center justify-center border-2 border-dashed border-[#4FD1C5] bg-[#07101B]/60 text-sm font-black text-[#4FD1C5]`
|
? `${RADIUS} flex min-h-0 items-center justify-center border-2 border-dashed border-[#4FD1C5] bg-[#07101B]/60 text-sm font-black text-[#4FD1C5]`
|
||||||
: `${RADIUS} flex min-h-[360px] items-center justify-center border-2 border-dashed border-[#0F766E] bg-[#ECFDF5] text-sm font-black text-[#0F766E]`
|
: `${RADIUS} flex min-h-0 items-center justify-center border-2 border-dashed border-[#0F766E] bg-[#ECFDF5] text-sm font-black text-[#0F766E]`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Colocar em novo espaço
|
Colocar em novo espaço
|
||||||
@@ -869,10 +869,10 @@ function WorkspaceChartContainer({
|
|||||||
}}
|
}}
|
||||||
className={
|
className={
|
||||||
canReceiveMove
|
canReceiveMove
|
||||||
? "relative rounded-[7px] ring-2 ring-[#4FD1C5]/50 transition"
|
? "relative min-h-0 overflow-hidden rounded-[7px] ring-2 ring-[#4FD1C5]/50 transition"
|
||||||
: isMoving
|
: isMoving
|
||||||
? "relative rounded-[7px] opacity-60 ring-2 ring-[#4FD1C5]"
|
? "relative min-h-0 overflow-hidden rounded-[7px] opacity-60 ring-2 ring-[#4FD1C5]"
|
||||||
: "relative rounded-[7px]"
|
: "relative min-h-0 overflow-hidden rounded-[7px]"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="absolute right-4 top-4 z-20 flex items-center gap-1.5">
|
<div className="absolute right-4 top-4 z-20 flex items-center gap-1.5">
|
||||||
@@ -1630,9 +1630,19 @@ function EmptyVariableList({ theme }: { theme: "dark" | "light" }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function layoutGridClass(layoutMode: ChartLayoutMode) {
|
function layoutGridClass(layoutMode: ChartLayoutMode) {
|
||||||
if (layoutMode === "twoColumns") return "grid gap-4 2xl:grid-cols-2";
|
if (layoutMode === "fourGrid") {
|
||||||
if (layoutMode === "fourGrid") return "grid gap-4 2xl:grid-cols-2";
|
return "grid min-h-0 flex-1 grid-cols-2 grid-rows-2 gap-3 overflow-hidden";
|
||||||
return "grid gap-4";
|
}
|
||||||
|
|
||||||
|
if (layoutMode === "twoColumns") {
|
||||||
|
return "grid min-h-0 flex-1 grid-cols-2 gap-3 overflow-hidden";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layoutMode === "twoRows") {
|
||||||
|
return "grid min-h-0 flex-1 grid-rows-2 gap-3 overflow-hidden";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "grid min-h-0 flex-1 gap-3 overflow-hidden";
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVisibleSlotCount(layoutMode: ChartLayoutMode) {
|
function getVisibleSlotCount(layoutMode: ChartLayoutMode) {
|
||||||
@@ -1728,8 +1738,8 @@ function EmptyWorkspace({
|
|||||||
<section
|
<section
|
||||||
className={
|
className={
|
||||||
isDark
|
isDark
|
||||||
? `${RADIUS} flex min-h-[520px] items-center justify-center border border-dashed border-[#33445F] bg-[#0E1726]/70`
|
? `${RADIUS} flex min-h-0 flex-1 items-center justify-center border border-dashed border-[#33445F] bg-[#0E1726]/70`
|
||||||
: `${RADIUS} flex min-h-[520px] items-center justify-center border border-dashed border-[#CBD5E1] bg-white`
|
: `${RADIUS} flex min-h-0 flex-1 items-center justify-center border border-dashed border-[#CBD5E1] bg-white`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="max-w-[420px] text-center">
|
<div className="max-w-[420px] text-center">
|
||||||
|
|||||||
@@ -361,10 +361,10 @@ export function SynopticPage({ theme }: SynopticPageProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={isDark ? "h-full text-white" : "h-full text-[#0F172A]"}>
|
<div className={isDark ? "h-full text-white" : "h-full text-[#0F172A]"}>
|
||||||
<div className="flex h-[calc(100vh-104px)] min-h-[560px] min-w-[1024px] flex-col gap-2 overflow-hidden min-[1220px]:gap-3">
|
<div className="flex h-[calc(100vh-104px)] min-h-0 min-w-0 flex-col gap-2 overflow-hidden min-[1220px]:gap-3">
|
||||||
<WorkspaceBar />
|
<WorkspaceBar isDark={isDark} />
|
||||||
|
|
||||||
<main className="grid min-h-0 flex-1 grid-cols-[200px_minmax(520px,1fr)_220px] gap-2 overflow-hidden min-[1220px]:grid-cols-[220px_minmax(600px,1fr)_240px] min-[1450px]:grid-cols-[270px_minmax(720px,1fr)_290px] min-[1220px]:gap-3">
|
<main className="grid min-h-0 min-w-0 flex-1 grid-cols-[180px_minmax(0,1fr)_210px] gap-2 overflow-hidden min-[1180px]:grid-cols-[200px_minmax(0,1fr)_230px] min-[1320px]:grid-cols-[230px_minmax(0,1fr)_260px] min-[1450px]:grid-cols-[270px_minmax(0,1fr)_290px] min-[1220px]:gap-3">
|
||||||
<VariablesPanel
|
<VariablesPanel
|
||||||
isDark={isDark}
|
isDark={isDark}
|
||||||
variables={synoptic.variables}
|
variables={synoptic.variables}
|
||||||
@@ -379,10 +379,11 @@ export function SynopticPage({ theme }: SynopticPageProps) {
|
|||||||
onVariablePointerUp={handleVariablePointerUp}
|
onVariablePointerUp={handleVariablePointerUp}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<section className="relative min-h-0 overflow-hidden rounded-[8px] bg-[#0E1726]">
|
<section className={isDark ? "relative min-h-0 min-w-0 overflow-hidden rounded-[8px] bg-[#0E1726]" : "relative min-h-0 min-w-0 overflow-hidden rounded-[8px] border border-[#D7DEE8] bg-white"}>
|
||||||
<Toolbar />
|
<Toolbar isDark={isDark} />
|
||||||
|
|
||||||
<CanvasMock
|
<CanvasMock
|
||||||
|
isDark={isDark}
|
||||||
canvasRef={canvasRef}
|
canvasRef={canvasRef}
|
||||||
items={items}
|
items={items}
|
||||||
variablesById={variablesById}
|
variablesById={variablesById}
|
||||||
@@ -408,7 +409,7 @@ export function SynopticPage({ theme }: SynopticPageProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function WorkspaceBar() {
|
function WorkspaceBar({ isDark }: { isDark: boolean }) {
|
||||||
return (
|
return (
|
||||||
<section className="flex h-[52px] shrink-0 items-center justify-between gap-3 bg-transparent min-[1220px]:h-[58px]">
|
<section className="flex h-[52px] shrink-0 items-center justify-between gap-3 bg-transparent min-[1220px]:h-[58px]">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
@@ -419,7 +420,7 @@ function WorkspaceBar() {
|
|||||||
<div className="mt-2 flex items-center gap-2">
|
<div className="mt-2 flex items-center gap-2">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="flex min-w-0 items-center gap-2 text-[15px] font-black leading-none tracking-[-0.03em] text-white"
|
className={isDark ? "flex min-w-0 items-center gap-2 text-[15px] font-black leading-none tracking-[-0.03em] text-white" : "flex min-w-0 items-center gap-2 text-[15px] font-black leading-none tracking-[-0.03em] text-[#0F172A]"}
|
||||||
>
|
>
|
||||||
<span className="truncate">Estufa Principal</span>
|
<span className="truncate">Estufa Principal</span>
|
||||||
<ChevronDown className="h-4 w-4 shrink-0 text-[#7F8CA3]" />
|
<ChevronDown className="h-4 w-4 shrink-0 text-[#7F8CA3]" />
|
||||||
@@ -428,11 +429,11 @@ function WorkspaceBar() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex min-w-0 items-center gap-2 overflow-x-auto pb-1">
|
<div className="flex min-w-0 items-center gap-2 overflow-x-auto pb-1">
|
||||||
<WorkspaceButton icon={<FolderPlus className="h-4 w-4" />} label="Novo" />
|
<WorkspaceButton isDark={isDark} icon={<FolderPlus className="h-4 w-4" />} label="Novo" />
|
||||||
<WorkspaceButton icon={<Save className="h-4 w-4" />} label="Guardar" primary />
|
<WorkspaceButton isDark={isDark} icon={<Save className="h-4 w-4" />} label="Guardar" primary />
|
||||||
<WorkspaceButton icon={<RefreshCw className="h-4 w-4" />} label="Atualizar" />
|
<WorkspaceButton isDark={isDark} icon={<RefreshCw className="h-4 w-4" />} label="Atualizar" />
|
||||||
|
|
||||||
<div className="ml-1 flex h-9 shrink-0 items-center gap-2 rounded-[6px] border border-[#263247] bg-[#0E1726] px-3 text-xs font-black text-[#A8B3C7] min-[1220px]:ml-3 min-[1220px]:px-4">
|
<div className={isDark ? "ml-1 flex h-9 shrink-0 items-center gap-2 rounded-[6px] border border-[#263247] bg-[#0E1726] px-3 text-xs font-black text-[#A8B3C7] min-[1220px]:ml-3 min-[1220px]:px-4" : "ml-1 flex h-9 shrink-0 items-center gap-2 rounded-[6px] border border-[#D7DEE8] bg-white px-3 text-xs font-black text-slate-600 min-[1220px]:ml-3 min-[1220px]:px-4"}>
|
||||||
<span className="h-2 w-2 rounded-full bg-[#18B8A6]" />
|
<span className="h-2 w-2 rounded-full bg-[#18B8A6]" />
|
||||||
Alterações guardadas
|
Alterações guardadas
|
||||||
</div>
|
</div>
|
||||||
@@ -442,10 +443,12 @@ function WorkspaceBar() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function WorkspaceButton({
|
function WorkspaceButton({
|
||||||
|
isDark,
|
||||||
icon,
|
icon,
|
||||||
label,
|
label,
|
||||||
primary,
|
primary,
|
||||||
}: {
|
}: {
|
||||||
|
isDark: boolean;
|
||||||
icon: ReactNode;
|
icon: ReactNode;
|
||||||
label: string;
|
label: string;
|
||||||
primary?: boolean;
|
primary?: boolean;
|
||||||
@@ -465,7 +468,11 @@ function WorkspaceButton({
|
|||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="flex h-9 shrink-0 items-center gap-2 rounded-[6px] border border-[#263247] bg-[#0E1726] px-3 text-xs font-black text-[#D7DEE8] transition hover:border-[#36506D] hover:text-white"
|
className={
|
||||||
|
isDark
|
||||||
|
? "flex h-9 shrink-0 items-center gap-2 rounded-[6px] border border-[#263247] bg-[#0E1726] px-3 text-xs font-black text-[#D7DEE8] transition hover:border-[#36506D] hover:text-white"
|
||||||
|
: "flex h-9 shrink-0 items-center gap-2 rounded-[6px] border border-[#D7DEE8] bg-white px-3 text-xs font-black text-slate-700 transition hover:bg-[#F8FAFC] hover:text-[#0F172A]"
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{icon}
|
{icon}
|
||||||
{label}
|
{label}
|
||||||
@@ -528,11 +535,11 @@ function VariablesPanel({
|
|||||||
<aside
|
<aside
|
||||||
className={
|
className={
|
||||||
isDark
|
isDark
|
||||||
? "flex min-h-0 flex-col rounded-[8px] border border-[#263247] bg-[#0E1726]"
|
? "flex min-h-0 min-w-0 flex-col rounded-[8px] border border-[#263247] bg-[#0E1726]"
|
||||||
: "flex min-h-0 flex-col rounded-[8px] border border-[#D7DEE8] bg-white"
|
: "flex min-h-0 min-w-0 flex-col rounded-[8px] border border-[#D7DEE8] bg-white"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="flex h-12 shrink-0 items-center justify-between border-b border-[#263247]/70 px-3 min-[1450px]:px-4">
|
<div className={isDark ? "flex h-12 shrink-0 items-center justify-between border-b border-[#263247]/70 px-3 min-[1450px]:px-4" : "flex h-12 shrink-0 items-center justify-between border-b border-[#D7DEE8] px-3 min-[1450px]:px-4"}>
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-base font-black">Variáveis</h2>
|
<h2 className="text-base font-black">Variáveis</h2>
|
||||||
<p className="text-[11px] font-bold text-[#7F8CA3]">
|
<p className="text-[11px] font-bold text-[#7F8CA3]">
|
||||||
@@ -553,7 +560,9 @@ function VariablesPanel({
|
|||||||
className={
|
className={
|
||||||
activeGroup === item
|
activeGroup === item
|
||||||
? "shrink-0 border-b-2 border-[#18B8A6] pb-2 text-[#18B8A6]"
|
? "shrink-0 border-b-2 border-[#18B8A6] pb-2 text-[#18B8A6]"
|
||||||
: "shrink-0 pb-2 text-[#7F8CA3] transition hover:text-white"
|
: isDark
|
||||||
|
? "shrink-0 pb-2 text-[#7F8CA3] transition hover:text-white"
|
||||||
|
: "shrink-0 pb-2 text-slate-500 transition hover:text-[#0F172A]"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{item}
|
{item}
|
||||||
@@ -617,7 +626,7 @@ function VariablesPanel({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{groupVariables.length === 0 ? (
|
{groupVariables.length === 0 ? (
|
||||||
<div className="border-t border-[#1C2A3D] px-3 py-3 text-[11px] font-bold text-[#7F8CA3]">
|
<div className={isDark ? "border-t border-[#1C2A3D] px-3 py-3 text-[11px] font-bold text-[#7F8CA3]" : "border-t border-[#E2E8F0] px-3 py-3 text-[11px] font-bold text-slate-500"}>
|
||||||
Sem variáveis disponíveis
|
Sem variáveis disponíveis
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -684,7 +693,7 @@ function VariablesPanel({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Toolbar() {
|
function Toolbar({ isDark }: { isDark: boolean }) {
|
||||||
const tools = [
|
const tools = [
|
||||||
{ label: "Selecionar", icon: <LocateFixed className="h-4 w-4" />, active: true },
|
{ label: "Selecionar", icon: <LocateFixed className="h-4 w-4" />, active: true },
|
||||||
{ label: "Mover", icon: <Move className="h-4 w-4" /> },
|
{ label: "Mover", icon: <Move className="h-4 w-4" /> },
|
||||||
@@ -693,14 +702,16 @@ function Toolbar() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="absolute left-3 right-3 top-3 z-20 flex items-start justify-between gap-2 min-[1450px]:left-4 min-[1450px]:right-4 min-[1450px]:top-4">
|
<div className="absolute left-3 right-3 top-3 z-20 flex items-start justify-between gap-2 min-[1450px]:left-4 min-[1450px]:right-4 min-[1450px]:top-4">
|
||||||
<div className="flex max-w-[calc(100%-88px)] items-center gap-1 overflow-x-auto rounded-[8px] border border-[#263247] bg-[#07101B]/92 p-1 shadow-xl backdrop-blur">
|
<div className={isDark ? "flex max-w-[calc(100%-88px)] items-center gap-1 overflow-x-auto rounded-[8px] border border-[#263247] bg-[#07101B]/92 p-1 shadow-xl backdrop-blur" : "flex max-w-[calc(100%-88px)] items-center gap-1 overflow-x-auto rounded-[8px] border border-[#D7DEE8] bg-white/92 p-1 shadow-xl backdrop-blur"}>
|
||||||
{tools.map((tool) => (
|
{tools.map((tool) => (
|
||||||
<button
|
<button
|
||||||
key={tool.label}
|
key={tool.label}
|
||||||
className={
|
className={
|
||||||
tool.active
|
tool.active
|
||||||
? "flex h-9 shrink-0 items-center gap-2 rounded-[6px] border border-[#18B8A6] bg-[#18B8A6]/15 px-3 text-xs font-black text-[#18B8A6] min-[1450px]:px-4"
|
? "flex h-9 shrink-0 items-center gap-2 rounded-[6px] border border-[#18B8A6] bg-[#18B8A6]/15 px-3 text-xs font-black text-[#18B8A6] min-[1450px]:px-4"
|
||||||
: "flex h-9 shrink-0 items-center gap-2 rounded-[6px] px-3 text-xs font-bold text-[#A8B3C7] transition hover:bg-white/10 hover:text-white min-[1450px]:px-4"
|
: isDark
|
||||||
|
? "flex h-9 shrink-0 items-center gap-2 rounded-[6px] px-3 text-xs font-bold text-[#A8B3C7] transition hover:bg-white/10 hover:text-white min-[1450px]:px-4"
|
||||||
|
: "flex h-9 shrink-0 items-center gap-2 rounded-[6px] px-3 text-xs font-bold text-slate-600 transition hover:bg-[#F1F5F9] hover:text-[#0F172A] min-[1450px]:px-4"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{tool.icon}
|
{tool.icon}
|
||||||
@@ -709,8 +720,8 @@ function Toolbar() {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex shrink-0 items-center gap-1 rounded-[8px] border border-[#263247] bg-[#07101B]/92 p-1 shadow-xl backdrop-blur">
|
<div className={isDark ? "flex shrink-0 items-center gap-1 rounded-[8px] border border-[#263247] bg-[#07101B]/92 p-1 shadow-xl backdrop-blur" : "flex shrink-0 items-center gap-1 rounded-[8px] border border-[#D7DEE8] bg-white/92 p-1 shadow-xl backdrop-blur"}>
|
||||||
<button className={smallToolClass}>
|
<button className={smallToolClass(isDark)}>
|
||||||
<Settings2 className="h-4 w-4" />
|
<Settings2 className="h-4 w-4" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -719,6 +730,7 @@ function Toolbar() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function CanvasMock({
|
function CanvasMock({
|
||||||
|
isDark,
|
||||||
canvasRef,
|
canvasRef,
|
||||||
items,
|
items,
|
||||||
variablesById,
|
variablesById,
|
||||||
@@ -728,6 +740,7 @@ function CanvasMock({
|
|||||||
onCardPointerMove,
|
onCardPointerMove,
|
||||||
onCardPointerUp,
|
onCardPointerUp,
|
||||||
}: {
|
}: {
|
||||||
|
isDark: boolean;
|
||||||
canvasRef: RefObject<HTMLDivElement | null>;
|
canvasRef: RefObject<HTMLDivElement | null>;
|
||||||
items: MapItem[];
|
items: MapItem[];
|
||||||
variablesById: Map<string, SynopticVariable>;
|
variablesById: Map<string, SynopticVariable>;
|
||||||
@@ -738,7 +751,7 @@ function CanvasMock({
|
|||||||
onCardPointerUp: (event: PointerEvent<HTMLDivElement>) => void;
|
onCardPointerUp: (event: PointerEvent<HTMLDivElement>) => void;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full items-center justify-center overflow-hidden bg-[#07101B] p-2">
|
<div className={isDark ? "flex h-full w-full items-center justify-center overflow-hidden bg-[#07101B] p-2" : "flex h-full w-full items-center justify-center overflow-hidden bg-[#F8FAFC] p-2"}>
|
||||||
<div
|
<div
|
||||||
ref={canvasRef}
|
ref={canvasRef}
|
||||||
className="relative h-full max-h-full max-w-full overflow-hidden rounded-[6px]"
|
className="relative h-full max-h-full max-w-full overflow-hidden rounded-[6px]"
|
||||||
@@ -752,8 +765,8 @@ function CanvasMock({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{items.length === 0 && (
|
{items.length === 0 && (
|
||||||
<div className="pointer-events-none absolute left-1/2 top-1/2 z-10 -translate-x-1/2 -translate-y-1/2 rounded-[8px] border border-dashed border-[#18B8A6]/50 bg-[#07101B]/80 px-5 py-4 text-center shadow-xl">
|
<div className={isDark ? "pointer-events-none absolute left-1/2 top-1/2 z-10 -translate-x-1/2 -translate-y-1/2 rounded-[8px] border border-dashed border-[#18B8A6]/50 bg-[#07101B]/80 px-5 py-4 text-center shadow-xl" : "pointer-events-none absolute left-1/2 top-1/2 z-10 -translate-x-1/2 -translate-y-1/2 rounded-[8px] border border-dashed border-[#18B8A6]/60 bg-white/85 px-5 py-4 text-center shadow-xl"}>
|
||||||
<p className="text-sm font-black text-white">
|
<p className={isDark ? "text-sm font-black text-white" : "text-sm font-black text-[#0F172A]"}>
|
||||||
Arraste variáveis para a imagem
|
Arraste variáveis para a imagem
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-xs font-bold text-[#7F8CA3]">
|
<p className="mt-1 text-xs font-bold text-[#7F8CA3]">
|
||||||
@@ -783,7 +796,7 @@ function CanvasMock({
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
<div className="absolute bottom-4 left-4 z-20 flex flex-col overflow-hidden rounded-[7px] border border-[#263247] bg-[#07101B]/90 shadow-xl">
|
<div className={isDark ? "absolute bottom-4 left-4 z-20 flex flex-col overflow-hidden rounded-[7px] border border-[#263247] bg-[#07101B]/90 shadow-xl" : "absolute bottom-4 left-4 z-20 flex flex-col overflow-hidden rounded-[7px] border border-[#D7DEE8] bg-white/90 shadow-xl"}>
|
||||||
<button className="grid h-9 w-9 place-items-center text-white hover:bg-white/10 min-[1450px]:h-10 min-[1450px]:w-10">
|
<button className="grid h-9 w-9 place-items-center text-white hover:bg-white/10 min-[1450px]:h-10 min-[1450px]:w-10">
|
||||||
<Plus className="h-5 w-5" />
|
<Plus className="h-5 w-5" />
|
||||||
</button>
|
</button>
|
||||||
@@ -795,7 +808,7 @@ function CanvasMock({
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="absolute bottom-4 right-4 z-20 rounded-[7px] bg-[#07101B]/90 px-3 py-2 text-xs font-black text-white shadow-xl">
|
<div className={isDark ? "absolute bottom-4 right-4 z-20 rounded-[7px] bg-[#07101B]/90 px-3 py-2 text-xs font-black text-white shadow-xl" : "absolute bottom-4 right-4 z-20 rounded-[7px] bg-white/90 px-3 py-2 text-xs font-black text-[#0F172A] shadow-xl"}>
|
||||||
100%
|
100%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -928,17 +941,17 @@ function PropertiesPanel({
|
|||||||
<aside
|
<aside
|
||||||
className={
|
className={
|
||||||
isDark
|
isDark
|
||||||
? "flex min-h-0 flex-col rounded-[8px] border border-[#263247] bg-[#0E1726]"
|
? "flex min-h-0 min-w-0 flex-col rounded-[8px] border border-[#263247] bg-[#0E1726]"
|
||||||
: "flex min-h-0 flex-col rounded-[8px] border border-[#D7DEE8] bg-white"
|
: "flex min-h-0 min-w-0 flex-col rounded-[8px] border border-[#D7DEE8] bg-white"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="flex h-12 shrink-0 items-center justify-between border-b border-[#263247]/70 px-3 min-[1450px]:px-4">
|
<div className={isDark ? "flex h-12 shrink-0 items-center justify-between border-b border-[#263247]/70 px-3 min-[1450px]:px-4" : "flex h-12 shrink-0 items-center justify-between border-b border-[#D7DEE8] px-3 min-[1450px]:px-4"}>
|
||||||
<h2 className="text-base font-black">Propriedades</h2>
|
<h2 className="text-base font-black">Propriedades</h2>
|
||||||
<X className="h-4 w-4 text-[#7F8CA3]" />
|
<X className="h-4 w-4 text-[#7F8CA3]" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="min-h-0 flex-1 overflow-y-auto p-3 min-[1450px]:p-4">
|
<div className="min-h-0 flex-1 overflow-y-auto p-3 min-[1450px]:p-4">
|
||||||
<div className="rounded-[7px] border border-[#263247] bg-[#07101B] p-4 text-center">
|
<div className={isDark ? "rounded-[7px] border border-[#263247] bg-[#07101B] p-4 text-center" : "rounded-[7px] border border-[#D7DEE8] bg-[#F8FAFC] p-4 text-center"}>
|
||||||
<p className="text-sm font-black">Nenhum item selecionado</p>
|
<p className="text-sm font-black">Nenhum item selecionado</p>
|
||||||
<p className="mt-1 text-xs font-bold text-[#7F8CA3]">
|
<p className="mt-1 text-xs font-bold text-[#7F8CA3]">
|
||||||
Arraste uma variável para a imagem.
|
Arraste uma variável para a imagem.
|
||||||
@@ -955,11 +968,11 @@ function PropertiesPanel({
|
|||||||
<aside
|
<aside
|
||||||
className={
|
className={
|
||||||
isDark
|
isDark
|
||||||
? "flex min-h-0 flex-col rounded-[8px] border border-[#263247] bg-[#0E1726]"
|
? "flex min-h-0 min-w-0 flex-col rounded-[8px] border border-[#263247] bg-[#0E1726]"
|
||||||
: "flex min-h-0 flex-col rounded-[8px] border border-[#D7DEE8] bg-white"
|
: "flex min-h-0 min-w-0 flex-col rounded-[8px] border border-[#D7DEE8] bg-white"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="flex h-12 shrink-0 items-center justify-between border-b border-[#263247]/70 px-3 min-[1450px]:px-4">
|
<div className={isDark ? "flex h-12 shrink-0 items-center justify-between border-b border-[#263247]/70 px-3 min-[1450px]:px-4" : "flex h-12 shrink-0 items-center justify-between border-b border-[#D7DEE8] px-3 min-[1450px]:px-4"}>
|
||||||
<h2 className="text-base font-black">Propriedades</h2>
|
<h2 className="text-base font-black">Propriedades</h2>
|
||||||
<X className="h-4 w-4 text-[#7F8CA3]" />
|
<X className="h-4 w-4 text-[#7F8CA3]" />
|
||||||
</div>
|
</div>
|
||||||
@@ -993,6 +1006,7 @@ function PropertiesPanel({
|
|||||||
|
|
||||||
<PanelSection title="Cartão">
|
<PanelSection title="Cartão">
|
||||||
<SegmentedControl
|
<SegmentedControl
|
||||||
|
isDark={isDark}
|
||||||
value={selectedItem.variant}
|
value={selectedItem.variant}
|
||||||
options={[
|
options={[
|
||||||
{ label: "Compacto", value: "compact" },
|
{ label: "Compacto", value: "compact" },
|
||||||
@@ -1007,7 +1021,9 @@ function PropertiesPanel({
|
|||||||
className={
|
className={
|
||||||
selectedItem.showLabel
|
selectedItem.showLabel
|
||||||
? "flex h-10 w-full items-center justify-between rounded-[6px] border border-[#18B8A6] bg-[#18B8A6]/10 px-3 text-sm font-black text-[#18B8A6]"
|
? "flex h-10 w-full items-center justify-between rounded-[6px] border border-[#18B8A6] bg-[#18B8A6]/10 px-3 text-sm font-black text-[#18B8A6]"
|
||||||
: "flex h-10 w-full items-center justify-between rounded-[6px] border border-[#263247] bg-[#07101B] px-3 text-sm font-bold text-[#A8B3C7]"
|
: isDark
|
||||||
|
? "flex h-10 w-full items-center justify-between rounded-[6px] border border-[#263247] bg-[#07101B] px-3 text-sm font-bold text-[#A8B3C7]"
|
||||||
|
: "flex h-10 w-full items-center justify-between rounded-[6px] border border-[#D7DEE8] bg-[#F8FAFC] px-3 text-sm font-bold text-slate-600"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Mostrar nome
|
Mostrar nome
|
||||||
@@ -1070,16 +1086,18 @@ function clampPercent(value: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function SegmentedControl({
|
function SegmentedControl({
|
||||||
|
isDark,
|
||||||
value,
|
value,
|
||||||
options,
|
options,
|
||||||
onChange,
|
onChange,
|
||||||
}: {
|
}: {
|
||||||
|
isDark: boolean;
|
||||||
value: string;
|
value: string;
|
||||||
options: { label: string; value: string }[];
|
options: { label: string; value: string }[];
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-2 rounded-[6px] border border-[#263247] bg-[#07101B] p-1">
|
<div className={isDark ? "grid grid-cols-2 rounded-[6px] border border-[#263247] bg-[#07101B] p-1" : "grid grid-cols-2 rounded-[6px] border border-[#D7DEE8] bg-[#F8FAFC] p-1"}>
|
||||||
{options.map((option) => (
|
{options.map((option) => (
|
||||||
<button
|
<button
|
||||||
key={option.value}
|
key={option.value}
|
||||||
@@ -1088,7 +1106,9 @@ function SegmentedControl({
|
|||||||
className={
|
className={
|
||||||
value === option.value
|
value === option.value
|
||||||
? "h-8 rounded-[5px] bg-[#18B8A6] text-xs font-black text-white"
|
? "h-8 rounded-[5px] bg-[#18B8A6] text-xs font-black text-white"
|
||||||
: "h-8 rounded-[5px] text-xs font-bold text-[#7F8CA3] transition hover:text-white"
|
: isDark
|
||||||
|
? "h-8 rounded-[5px] text-xs font-bold text-[#7F8CA3] transition hover:text-white"
|
||||||
|
: "h-8 rounded-[5px] text-xs font-bold text-slate-500 transition hover:text-[#0F172A]"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{option.label}
|
{option.label}
|
||||||
@@ -1098,8 +1118,11 @@ function SegmentedControl({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const smallToolClass =
|
function smallToolClass(isDark: boolean) {
|
||||||
"grid h-9 w-9 place-items-center rounded-[6px] text-[#A8B3C7] transition hover:bg-white/10 hover:text-white";
|
return isDark
|
||||||
|
? "grid h-9 w-9 place-items-center rounded-[6px] text-[#A8B3C7] transition hover:bg-white/10 hover:text-white"
|
||||||
|
: "grid h-9 w-9 place-items-center rounded-[6px] text-slate-600 transition hover:bg-[#F1F5F9] hover:text-[#0F172A]";
|
||||||
|
}
|
||||||
|
|
||||||
function formatVariableValue(variable: SynopticVariable) {
|
function formatVariableValue(variable: SynopticVariable) {
|
||||||
if (variable.value === null || variable.value === undefined) {
|
if (variable.value === null || variable.value === undefined) {
|
||||||
|
|||||||
Reference in New Issue
Block a user