add dashboard calendar week strip; styles
This commit is contained in:
@@ -957,7 +957,7 @@ export function App() {
|
|||||||
<header className="catalog-header">
|
<header className="catalog-header">
|
||||||
<div className="catalog-brand">
|
<div className="catalog-brand">
|
||||||
<span className="catalog-logo">Plant-Man</span>
|
<span className="catalog-logo">Plant-Man</span>
|
||||||
<span className="catalog-subtitle">Plant Care Supply</span>
|
<span className="catalog-subtitle">Plant care workbench</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="catalog-contact">
|
<div className="catalog-contact">
|
||||||
<strong>{plants.length}</strong>
|
<strong>{plants.length}</strong>
|
||||||
@@ -967,7 +967,7 @@ export function App() {
|
|||||||
|
|
||||||
<div className="catalog-layout">
|
<div className="catalog-layout">
|
||||||
<aside className="catalog-sidebar">
|
<aside className="catalog-sidebar">
|
||||||
<h2>Concepts</h2>
|
<h2>Workbench</h2>
|
||||||
<nav className="catalog-nav" aria-label="Primary navigation">
|
<nav className="catalog-nav" aria-label="Primary navigation">
|
||||||
<div className="nav-group">
|
<div className="nav-group">
|
||||||
<h3>Operations</h3>
|
<h3>Operations</h3>
|
||||||
@@ -1297,7 +1297,7 @@ function getViewTitle(view: View) {
|
|||||||
case 'flags':
|
case 'flags':
|
||||||
return 'Plant Flags';
|
return 'Plant Flags';
|
||||||
default:
|
default:
|
||||||
return 'Plant-Man';
|
return 'Dashboard';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { useMemo, useState } from 'react';
|
||||||
import { CalendarCheck, Plus } from 'lucide-react';
|
import { CalendarCheck, Plus } from 'lucide-react';
|
||||||
import type { CareTask, Plant } from '../domain';
|
import type { CareTask, Plant } from '../domain';
|
||||||
import { PlantCard } from './PlantCard';
|
import { PlantCard } from './PlantCard';
|
||||||
@@ -26,6 +27,10 @@ export function HomeView({
|
|||||||
onOpenPlant,
|
onOpenPlant,
|
||||||
}: HomeViewProps) {
|
}: HomeViewProps) {
|
||||||
const dueTaskGroups = groupDueTasks(careTasks);
|
const dueTaskGroups = groupDueTasks(careTasks);
|
||||||
|
const weekDays = useMemo(() => getWeekDays(), []);
|
||||||
|
const [selectedDate, setSelectedDate] = useState(() => weekDays[0]?.dateKey ?? getDateKey(new Date()));
|
||||||
|
const selectedDay = weekDays.find((day) => day.dateKey === selectedDate) ?? weekDays[0];
|
||||||
|
const selectedTasks = getTasksForDate(careTasks, selectedDate);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -39,6 +44,62 @@ export function HomeView({
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section className="section" aria-labelledby="calendar-heading">
|
||||||
|
<div className="section-heading">
|
||||||
|
<h2 id="calendar-heading">Care Calendar</h2>
|
||||||
|
<span className="schedule-count">{selectedTasks.length} selected</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="week-strip" role="tablist" aria-label="Care tasks by day">
|
||||||
|
{weekDays.map((day) => {
|
||||||
|
const dayTasks = getTasksForDate(careTasks, day.dateKey);
|
||||||
|
const hasDueTasks = dayTasks.some((task) => task.status === 'due');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className="week-day"
|
||||||
|
type="button"
|
||||||
|
role="tab"
|
||||||
|
aria-selected={day.dateKey === selectedDate}
|
||||||
|
key={day.dateKey}
|
||||||
|
onClick={() => setSelectedDate(day.dateKey)}
|
||||||
|
>
|
||||||
|
<span>{day.label}</span>
|
||||||
|
<strong>{day.dayNumber}</strong>
|
||||||
|
<small>{dayTasks.length}</small>
|
||||||
|
{hasDueTasks ? <span className="week-day-alert" aria-hidden="true" /> : null}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="task-list">
|
||||||
|
<p className="task-list-label">{selectedDay?.heading ?? 'Selected day'}</p>
|
||||||
|
{!isLoading && selectedTasks.length === 0 ? (
|
||||||
|
<p className="empty-state">No care scheduled for this day.</p>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{selectedTasks.map((task) => (
|
||||||
|
<article className="task-row" key={`calendar-${task.id}`}>
|
||||||
|
<span className={`status-dot ${task.status}`} />
|
||||||
|
<div>
|
||||||
|
<h3>{task.action}</h3>
|
||||||
|
<p>{task.plantName} - {task.due}</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
className="small-action"
|
||||||
|
type="button"
|
||||||
|
disabled={task.status !== 'due'}
|
||||||
|
onClick={() => onCompleteTask(task)}
|
||||||
|
>
|
||||||
|
<CalendarCheck size={16} />
|
||||||
|
Log
|
||||||
|
</button>
|
||||||
|
</article>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section className="section" aria-labelledby="care-heading">
|
<section className="section" aria-labelledby="care-heading">
|
||||||
<div className="section-heading">
|
<div className="section-heading">
|
||||||
<h2 id="care-heading">Due Care</h2>
|
<h2 id="care-heading">Due Care</h2>
|
||||||
@@ -153,3 +214,64 @@ function formatPlantNames(tasks: CareTask[]) {
|
|||||||
|
|
||||||
return `${names.slice(0, 3).join(', ')} + ${names.length - 3} more`;
|
return `${names.slice(0, 3).join(', ')} + ${names.length - 3} more`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getWeekDays() {
|
||||||
|
const today = new Date();
|
||||||
|
|
||||||
|
return Array.from({ length: 7 }, (_, index) => {
|
||||||
|
const date = new Date(today);
|
||||||
|
date.setDate(today.getDate() + index);
|
||||||
|
const dateKey = getDateKey(date);
|
||||||
|
|
||||||
|
return {
|
||||||
|
dateKey,
|
||||||
|
dayNumber: date.getDate().toString(),
|
||||||
|
heading: index === 0
|
||||||
|
? 'Today'
|
||||||
|
: date.toLocaleDateString(undefined, { weekday: 'long', month: 'short', day: 'numeric' }),
|
||||||
|
label: index === 0
|
||||||
|
? 'Today'
|
||||||
|
: date.toLocaleDateString(undefined, { weekday: 'short' }),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTasksForDate(tasks: CareTask[], dateKey: string) {
|
||||||
|
const todayKey = getDateKey(new Date());
|
||||||
|
|
||||||
|
return tasks
|
||||||
|
.filter((task) => {
|
||||||
|
if (!task.dueDate) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dateKey === todayKey) {
|
||||||
|
return task.dueDate <= todayKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
return task.dueDate === dateKey;
|
||||||
|
})
|
||||||
|
.sort(compareCareTasks);
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareCareTasks(left: CareTask, right: CareTask) {
|
||||||
|
const dueComparison = (left.dueDate ?? '').localeCompare(right.dueDate ?? '');
|
||||||
|
if (dueComparison !== 0) {
|
||||||
|
return dueComparison;
|
||||||
|
}
|
||||||
|
|
||||||
|
const plantComparison = left.plantName.localeCompare(right.plantName);
|
||||||
|
if (plantComparison !== 0) {
|
||||||
|
return plantComparison;
|
||||||
|
}
|
||||||
|
|
||||||
|
return left.action.localeCompare(right.action);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDateKey(date: Date) {
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(date.getDate()).padStart(2, '0');
|
||||||
|
|
||||||
|
return `${year}-${month}-${day}`;
|
||||||
|
}
|
||||||
|
|||||||
@@ -214,6 +214,7 @@ export type CareTask = {
|
|||||||
careActivityId: number;
|
careActivityId: number;
|
||||||
careActionId: number;
|
careActionId: number;
|
||||||
action: string;
|
action: string;
|
||||||
|
dueDate: string | null;
|
||||||
due: string;
|
due: string;
|
||||||
status: CareStatus;
|
status: CareStatus;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,24 +1,26 @@
|
|||||||
:root {
|
:root {
|
||||||
color: #161616;
|
color: #24342c;
|
||||||
background: #f4f4f4;
|
background: #f6f5ef;
|
||||||
font-family: 'IBM Plex Sans', Arial, Helvetica, sans-serif;
|
font-family: 'IBM Plex Sans', Arial, Helvetica, sans-serif;
|
||||||
font-synthesis: none;
|
font-synthesis: none;
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
--border: #e0e0e0;
|
--border: #ded8ca;
|
||||||
--rule: #c6c6c6;
|
--rule: #cbbfaaaa;
|
||||||
--muted: #6f6f6f;
|
--muted: #6d776c;
|
||||||
--panel: #fff;
|
--panel: #fffdf7;
|
||||||
--side: #f4f4f4;
|
--side: #efeee5;
|
||||||
--row: #f4f4f4;
|
--row: #f8f6ee;
|
||||||
--hover: #e8f0fe;
|
--hover: #eef4e8;
|
||||||
--link: #0f62fe;
|
--link: #3d6f4b;
|
||||||
--focus: #0f62fe;
|
--focus: #2f6f7e;
|
||||||
--field: #f4f4f4;
|
--field: #f5f3eb;
|
||||||
--layer: #fff;
|
--layer: #fffdf7;
|
||||||
--warning: #8a5a00;
|
--warning: #9a6508;
|
||||||
--danger: #da1e28;
|
--danger: #b44336;
|
||||||
--ok: #198038;
|
--ok: #3f7d55;
|
||||||
|
--soil: #7c6144;
|
||||||
|
--sage: #dbe7d2;
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
@@ -30,7 +32,9 @@ body {
|
|||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
background: #f4f4f4;
|
background:
|
||||||
|
linear-gradient(180deg, rgba(219, 231, 210, 0.55), rgba(246, 245, 239, 0) 260px),
|
||||||
|
#f6f5ef;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,12 +119,12 @@ p {
|
|||||||
grid-template-columns: minmax(190px, 260px) minmax(260px, 680px) minmax(120px, 1fr);
|
grid-template-columns: minmax(190px, 260px) minmax(260px, 680px) minmax(120px, 1fr);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 18px;
|
gap: 18px;
|
||||||
min-height: 64px;
|
min-height: 68px;
|
||||||
padding: 10px 22px;
|
padding: 12px 24px;
|
||||||
border-bottom: 0;
|
border-bottom: 1px solid #274333;
|
||||||
background: #161616;
|
background: #1f3528;
|
||||||
color: #f4f4f4;
|
color: #fffdf7;
|
||||||
box-shadow: none;
|
box-shadow: 0 1px 0 rgba(36, 52, 44, 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
.catalog-brand {
|
.catalog-brand {
|
||||||
@@ -129,7 +133,7 @@ p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.catalog-logo {
|
.catalog-logo {
|
||||||
color: #fff;
|
color: #fffdf7;
|
||||||
font-size: 1.65rem;
|
font-size: 1.65rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
@@ -137,7 +141,7 @@ p {
|
|||||||
|
|
||||||
.catalog-subtitle,
|
.catalog-subtitle,
|
||||||
.catalog-contact span {
|
.catalog-contact span {
|
||||||
color: #c6c6c6;
|
color: #c8d7c3;
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
@@ -145,7 +149,7 @@ p {
|
|||||||
.catalog-contact {
|
.catalog-contact {
|
||||||
display: grid;
|
display: grid;
|
||||||
justify-items: end;
|
justify-items: end;
|
||||||
color: #fff;
|
color: #fffdf7;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,13 +167,14 @@ p {
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
border-right: 1px solid var(--border);
|
border-right: 1px solid var(--border);
|
||||||
border-left: 1px solid var(--border);
|
border-left: 1px solid var(--border);
|
||||||
|
background: var(--panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
.catalog-sidebar {
|
.catalog-sidebar {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 64px;
|
top: 68px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
min-height: calc(100vh - 64px);
|
min-height: calc(100vh - 68px);
|
||||||
padding: 16px 16px 24px 22px;
|
padding: 16px 16px 24px 22px;
|
||||||
border-right: 1px solid var(--border);
|
border-right: 1px solid var(--border);
|
||||||
background: var(--side);
|
background: var(--side);
|
||||||
@@ -178,7 +183,7 @@ p {
|
|||||||
.catalog-sidebar h2,
|
.catalog-sidebar h2,
|
||||||
.catalog-help h3 {
|
.catalog-help h3 {
|
||||||
margin: 0 0 8px;
|
margin: 0 0 8px;
|
||||||
color: #161616;
|
color: #24342c;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,9 +212,10 @@ p {
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
min-height: 36px;
|
min-height: 36px;
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
border: 0;
|
border: 1px solid transparent;
|
||||||
|
border-radius: 6px;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: #525252;
|
color: #4f5f54;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@@ -232,17 +238,19 @@ p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.catalog-nav button:hover {
|
.catalog-nav button:hover {
|
||||||
background: #e8e8e8;
|
border-color: #d2c8b7;
|
||||||
color: #161616;
|
background: #f7f4ea;
|
||||||
|
color: #24342c;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-button:hover {
|
.text-button:hover {
|
||||||
color: #0043ce;
|
color: #294f36;
|
||||||
}
|
}
|
||||||
|
|
||||||
.catalog-nav button[aria-current='page'] {
|
.catalog-nav button[aria-current='page'] {
|
||||||
background: #e0e0e0;
|
border-color: #c4d5bc;
|
||||||
color: #161616;
|
background: var(--sage);
|
||||||
|
color: #24342c;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,15 +260,16 @@ p {
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 3px;
|
width: 3px;
|
||||||
background: var(--link);
|
border-radius: 999px;
|
||||||
|
background: var(--ok);
|
||||||
content: '';
|
content: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
.catalog-help {
|
.catalog-help {
|
||||||
margin-top: 22px;
|
margin-top: 22px;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
border-top: 1px solid #cfcfcf;
|
border-top: 1px solid #d2c8b7;
|
||||||
color: #333;
|
color: #4d5a51;
|
||||||
font-size: 0.86rem;
|
font-size: 0.86rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,8 +279,8 @@ p {
|
|||||||
|
|
||||||
.catalog-main {
|
.catalog-main {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding: 16px 22px 36px;
|
padding: 18px 22px 40px;
|
||||||
background: #fff;
|
background: var(--panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
.catalog-page-title {
|
.catalog-page-title {
|
||||||
@@ -285,7 +294,8 @@ p {
|
|||||||
|
|
||||||
.catalog-page-title h1 {
|
.catalog-page-title h1 {
|
||||||
margin: 0 0 6px;
|
margin: 0 0 6px;
|
||||||
font-weight: 500;
|
color: #24342c;
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
@@ -310,7 +320,7 @@ p {
|
|||||||
.plant-row,
|
.plant-row,
|
||||||
.task-row {
|
.task-row {
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: 0;
|
border-radius: 8px;
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
@@ -320,8 +330,8 @@ p {
|
|||||||
grid-template-columns: minmax(0, 1fr) auto;
|
grid-template-columns: minmax(0, 1fr) auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
padding: 10px 12px;
|
padding: 12px 14px;
|
||||||
border-top: 0;
|
border-left: 4px solid var(--link);
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-panel h2 {
|
.summary-panel h2 {
|
||||||
@@ -331,7 +341,7 @@ p {
|
|||||||
|
|
||||||
.summary-panel p {
|
.summary-panel p {
|
||||||
max-width: 68ch;
|
max-width: 68ch;
|
||||||
color: #444;
|
color: #59675d;
|
||||||
font-size: 0.86rem;
|
font-size: 0.86rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,7 +352,8 @@ p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.editor-panel {
|
.editor-panel {
|
||||||
padding: 10px 12px;
|
padding: 12px;
|
||||||
|
background: #fbfaf4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-heading,
|
.section-heading,
|
||||||
@@ -364,10 +375,10 @@ p {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
border: 0;
|
border: 1px solid #cfc4b4;
|
||||||
border-radius: 0;
|
border-radius: 6px;
|
||||||
background: #e0e0e0;
|
background: #f4f0e5;
|
||||||
color: #161616;
|
color: #24342c;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
@@ -376,7 +387,8 @@ p {
|
|||||||
min-height: 34px;
|
min-height: 34px;
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
background: var(--link);
|
background: var(--link);
|
||||||
color: #fff;
|
border-color: var(--link);
|
||||||
|
color: #fffdf7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.small-action {
|
.small-action {
|
||||||
@@ -402,12 +414,13 @@ p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.primary-action:hover:not(:disabled) {
|
.primary-action:hover:not(:disabled) {
|
||||||
background: #0353e9;
|
background: #315c3d;
|
||||||
}
|
}
|
||||||
|
|
||||||
.small-action:hover:not(:disabled),
|
.small-action:hover:not(:disabled),
|
||||||
.icon-button:hover:not(:disabled) {
|
.icon-button:hover:not(:disabled) {
|
||||||
background: #d0d0d0;
|
border-color: #b8aa98;
|
||||||
|
background: #e9e2d4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.plant-mark svg,
|
.plant-mark svg,
|
||||||
@@ -419,6 +432,76 @@ p {
|
|||||||
height: 15px;
|
height: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.week-strip {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(7, minmax(0, 1fr));
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.week-day {
|
||||||
|
position: relative;
|
||||||
|
display: grid;
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 74px;
|
||||||
|
align-content: space-between;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #fbfaf4;
|
||||||
|
color: #24342c;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.week-day:hover {
|
||||||
|
border-color: #b8aa98;
|
||||||
|
background: var(--hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.week-day[aria-selected='true'] {
|
||||||
|
border-color: var(--link);
|
||||||
|
background: var(--sage);
|
||||||
|
box-shadow: inset 0 0 0 1px var(--link);
|
||||||
|
}
|
||||||
|
|
||||||
|
.week-day span:first-child,
|
||||||
|
.week-day small {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.week-day strong {
|
||||||
|
color: #24342c;
|
||||||
|
font-size: 1.35rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.week-day small {
|
||||||
|
display: inline-flex;
|
||||||
|
width: fit-content;
|
||||||
|
min-width: 22px;
|
||||||
|
min-height: 20px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0 6px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #ece6d9;
|
||||||
|
color: #4f5f54;
|
||||||
|
}
|
||||||
|
|
||||||
|
.week-day-alert {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 8px;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: var(--danger);
|
||||||
|
}
|
||||||
|
|
||||||
.task-list,
|
.task-list,
|
||||||
.plant-list,
|
.plant-list,
|
||||||
.plant-grid,
|
.plant-grid,
|
||||||
@@ -426,7 +509,7 @@ p {
|
|||||||
display: grid;
|
display: grid;
|
||||||
gap: 0;
|
gap: 0;
|
||||||
border-top: 1px solid var(--border);
|
border-top: 1px solid var(--border);
|
||||||
background: #fff;
|
background: var(--panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-row,
|
.task-row,
|
||||||
@@ -435,8 +518,9 @@ p {
|
|||||||
.detail-row {
|
.detail-row {
|
||||||
min-height: 42px;
|
min-height: 42px;
|
||||||
border: 0;
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
border-bottom: 1px solid var(--border);
|
border-bottom: 1px solid var(--border);
|
||||||
background: #fff;
|
background: var(--panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-row:nth-child(even),
|
.task-row:nth-child(even),
|
||||||
@@ -462,14 +546,14 @@ p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.task-row-group {
|
.task-row-group {
|
||||||
background: #f4f4f4;
|
background: #f3efe3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-list-label {
|
.task-list-label {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 7px 8px 5px;
|
padding: 7px 8px 5px;
|
||||||
border-bottom: 1px solid var(--border);
|
border-bottom: 1px solid var(--border);
|
||||||
background: #f4f4f4;
|
background: #f3efe3;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
font-size: 0.76rem;
|
font-size: 0.76rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -510,7 +594,7 @@ p {
|
|||||||
display: inline;
|
display: inline;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
color: #444;
|
color: #59675d;
|
||||||
font-size: 0.86rem;
|
font-size: 0.86rem;
|
||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@@ -549,7 +633,7 @@ p {
|
|||||||
.detail-row p,
|
.detail-row p,
|
||||||
.taxon,
|
.taxon,
|
||||||
.empty-state {
|
.empty-state {
|
||||||
color: #444;
|
color: #59675d;
|
||||||
font-size: 0.86rem;
|
font-size: 0.86rem;
|
||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
}
|
}
|
||||||
@@ -599,13 +683,13 @@ dd {
|
|||||||
.empty-state {
|
.empty-state {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
border-bottom: 1px solid var(--border);
|
border-bottom: 1px solid var(--border);
|
||||||
background: #f4f4f4;
|
background: #f8f6ee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-dot {
|
.status-dot {
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
border-radius: 0;
|
border-radius: 999px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-dot.due {
|
.status-dot.due {
|
||||||
@@ -626,29 +710,29 @@ dd {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 6px;
|
padding: 0 6px;
|
||||||
border: 1px solid currentColor;
|
border: 1px solid currentColor;
|
||||||
border-radius: 0;
|
border-radius: 999px;
|
||||||
background: #fff;
|
background: var(--panel);
|
||||||
font-size: 0.72rem;
|
font-size: 0.72rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-pill.due {
|
.status-pill.due {
|
||||||
background: #fff1f1;
|
background: #fbe9e4;
|
||||||
color: var(--danger);
|
color: var(--danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-pill.soon {
|
.status-pill.soon {
|
||||||
background: #fff8d6;
|
background: #fbefd2;
|
||||||
color: var(--warning);
|
color: var(--warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-pill.ok {
|
.status-pill.ok {
|
||||||
background: #defbe6;
|
background: #e5f1df;
|
||||||
color: var(--ok);
|
color: var(--ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-pill.unscheduled {
|
.status-pill.unscheduled {
|
||||||
background: #e0e0e0;
|
background: #ece6d9;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -663,7 +747,7 @@ dd {
|
|||||||
.flag-assignment-form label {
|
.flag-assignment-form label {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
color: #525252;
|
color: #4f5f54;
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
@@ -675,11 +759,10 @@ dd {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 34px;
|
min-height: 34px;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
border: 0;
|
border: 1px solid #cfc4b4;
|
||||||
border-bottom: 1px solid #8d8d8d;
|
border-radius: 6px;
|
||||||
border-radius: 0;
|
|
||||||
background: var(--field);
|
background: var(--field);
|
||||||
color: #161616;
|
color: #24342c;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,7 +782,8 @@ dd {
|
|||||||
align-self: end;
|
align-self: end;
|
||||||
padding: 5px 7px;
|
padding: 5px 7px;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
background: #f4f4f4;
|
border-radius: 6px;
|
||||||
|
background: #f8f6ee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.plant-form .toggle-field input,
|
.plant-form .toggle-field input,
|
||||||
@@ -722,12 +806,13 @@ dd {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
background: #fff;
|
border-radius: 8px;
|
||||||
|
background: var(--panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
.resource-picker legend {
|
.resource-picker legend {
|
||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
color: #161616;
|
color: #24342c;
|
||||||
font-size: 0.82rem;
|
font-size: 0.82rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
@@ -777,7 +862,7 @@ dd {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-bottom: 1px solid var(--border);
|
border-bottom: 1px solid var(--border);
|
||||||
background: #fff;
|
background: var(--panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
.activity-resource-header,
|
.activity-resource-header,
|
||||||
@@ -850,7 +935,7 @@ dd {
|
|||||||
|
|
||||||
.schedule-hint {
|
.schedule-hint {
|
||||||
margin: 8px 0 0;
|
margin: 8px 0 0;
|
||||||
color: #444;
|
color: #59675d;
|
||||||
font-size: 0.86rem;
|
font-size: 0.86rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -860,7 +945,8 @@ dd {
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
border-left: 3px solid var(--link);
|
border-left: 3px solid var(--link);
|
||||||
background: #f4f4f4;
|
border-radius: 0 6px 6px 0;
|
||||||
|
background: #f3efe3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.schedule-preview span {
|
.schedule-preview span {
|
||||||
@@ -871,7 +957,7 @@ dd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.schedule-preview strong {
|
.schedule-preview strong {
|
||||||
color: #161616;
|
color: #24342c;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
@@ -890,7 +976,8 @@ dd {
|
|||||||
margin: 10px 0 0;
|
margin: 10px 0 0;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
background: #fff;
|
border-radius: 8px;
|
||||||
|
background: var(--panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
.schedule-options legend,
|
.schedule-options legend,
|
||||||
@@ -919,8 +1006,8 @@ dd {
|
|||||||
.schedule-end-options input[type='number'] {
|
.schedule-end-options input[type='number'] {
|
||||||
min-height: 34px;
|
min-height: 34px;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
border: 0;
|
border: 1px solid #cfc4b4;
|
||||||
border-bottom: 1px solid #8d8d8d;
|
border-radius: 6px;
|
||||||
background: var(--field);
|
background: var(--field);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -930,8 +1017,9 @@ dd {
|
|||||||
height: 28px;
|
height: 28px;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
background: #f4f4f4;
|
border-radius: 6px;
|
||||||
color: #161616;
|
background: #f8f6ee;
|
||||||
|
color: #24342c;
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -942,7 +1030,7 @@ dd {
|
|||||||
|
|
||||||
.weekday-options label:has(input:checked) {
|
.weekday-options label:has(input:checked) {
|
||||||
border-color: var(--link);
|
border-color: var(--link);
|
||||||
background: #e8f0ff;
|
background: var(--sage);
|
||||||
color: var(--link);
|
color: var(--link);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -959,11 +1047,10 @@ dd {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 34px;
|
min-height: 34px;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
border: 0;
|
border: 1px solid #cfc4b4;
|
||||||
border-bottom: 1px solid #8d8d8d;
|
border-radius: 6px;
|
||||||
border-radius: 0;
|
|
||||||
background: var(--field);
|
background: var(--field);
|
||||||
color: #161616;
|
color: #24342c;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compact-plant-list {
|
.compact-plant-list {
|
||||||
@@ -1019,7 +1106,7 @@ dd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.plant-detail-meta strong {
|
.plant-detail-meta strong {
|
||||||
color: #161616;
|
color: #24342c;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
@@ -1090,7 +1177,8 @@ dd {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 7px;
|
padding: 0 7px;
|
||||||
border: 1px solid #999;
|
border: 1px solid #999;
|
||||||
color: #161616;
|
border-radius: 999px;
|
||||||
|
color: #24342c;
|
||||||
font-size: 0.74rem;
|
font-size: 0.74rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
@@ -1100,7 +1188,8 @@ dd {
|
|||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
border-bottom: 1px solid var(--border);
|
border-bottom: 1px solid var(--border);
|
||||||
background: #f4f4f4;
|
border-radius: 8px;
|
||||||
|
background: #f8f6ee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flag-assignment-form label {
|
.flag-assignment-form label {
|
||||||
@@ -1199,6 +1288,17 @@ dd {
|
|||||||
padding: 12px;
|
padding: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.week-strip {
|
||||||
|
display: flex;
|
||||||
|
overflow-x: auto;
|
||||||
|
overscroll-behavior-x: contain;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.week-day {
|
||||||
|
flex: 0 0 78px;
|
||||||
|
}
|
||||||
|
|
||||||
.catalog-page-title {
|
.catalog-page-title {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -350,6 +350,7 @@ namespace plant_manager
|
|||||||
int CareActivityId,
|
int CareActivityId,
|
||||||
int CareActionId,
|
int CareActionId,
|
||||||
string Action,
|
string Action,
|
||||||
|
string? DueDate,
|
||||||
string Due,
|
string Due,
|
||||||
string Status)
|
string Status)
|
||||||
{
|
{
|
||||||
@@ -368,6 +369,7 @@ namespace plant_manager
|
|||||||
schedule.CareActivityId,
|
schedule.CareActivityId,
|
||||||
schedule.CareActionId,
|
schedule.CareActionId,
|
||||||
schedule.CareActivity.Name,
|
schedule.CareActivity.Name,
|
||||||
|
nextCare?.ToString("yyyy-MM-dd"),
|
||||||
PlantCareFormatter.FormatRelativeDate(nextCare, today, "Unscheduled"),
|
PlantCareFormatter.FormatRelativeDate(nextCare, today, "Unscheduled"),
|
||||||
PlantCareFormatter.GetStatus(nextCare, today));
|
PlantCareFormatter.GetStatus(nextCare, today));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user