toggle switches

This commit is contained in:
Michael Zhang 2023-08-23 21:47:25 -05:00
parent f276a6276e
commit aa820d4910
12 changed files with 396 additions and 58 deletions

35
lib/queries.ts Normal file
View file

@ -0,0 +1,35 @@
import { format } from "date-fns";
import { useQuery } from "react-query";
type JournalQueryDate = JournalEntry[];
interface JournalEntry {
"journal-day": number;
"original-name": string;
}
export function useJournals(dateStart: Date, dateEnd: Date) {
const fmtStart = journalFmt(dateStart);
const fmtEnd = journalFmt(dateEnd);
return useQuery(["journals", dateStart, dateEnd], async () => {
const journals: JournalQueryDate[] = await logseq.DB.datascriptQuery(`
[:find (pull ?p [*])
:where
[?b :block/page ?p]
[?p :block/journal? true]
[?p :block/journal-day ?d]
[(>= ?d ${fmtStart})] [(<= ?d ${fmtEnd})]]
`);
return new Map(
journals
.flatMap((dates) => dates)
.map((entry) => [entry["journal-day"].toString(), entry])
);
});
}
export function journalFmt(date: Date) {
return format(date, "YMMdd");
}

203
package-lock.json generated
View file

@ -13,7 +13,8 @@
"date-fns": "^2.30.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-keybind": "^0.9.4"
"react-keybind": "^0.9.4",
"react-query": "^3.39.3"
},
"devDependencies": {
"@logseq/libs": "^0.0.1-alpha.29",
@ -868,6 +869,19 @@
"node": ">= 8"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"node_modules/big-integer": {
"version": "1.6.51",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
"integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
"engines": {
"node": ">=0.6"
}
},
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@ -877,6 +891,15 @@
"node": ">=8"
}
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
@ -889,6 +912,21 @@
"node": ">=8"
}
},
"node_modules/broadcast-channel": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/broadcast-channel/-/broadcast-channel-3.7.0.tgz",
"integrity": "sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==",
"dependencies": {
"@babel/runtime": "^7.7.2",
"detect-node": "^2.1.0",
"js-sha3": "0.8.0",
"microseconds": "0.2.0",
"nano-time": "1.0.0",
"oblivious-set": "1.0.0",
"rimraf": "3.0.2",
"unload": "2.2.0"
}
},
"node_modules/browserslist": {
"version": "4.21.10",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz",
@ -1002,6 +1040,11 @@
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"dev": true
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
"node_modules/convert-source-map": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
@ -1046,6 +1089,11 @@
}
}
},
"node_modules/detect-node": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
"integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="
},
"node_modules/dompurify": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.1.tgz",
@ -1147,6 +1195,11 @@
"node": ">=8"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@ -1170,6 +1223,25 @@
"node": ">=6.9.0"
}
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
@ -1212,11 +1284,19 @@
"integrity": "sha512-808ZFYMsIRAjLAu5xkKo0TsbY9LBy9H5MazTKIEHerNkg0ymgilGfBPMR/3G7d/ihGmuK2Hw8S1izY2d3kd3wA==",
"dev": true
},
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
"dev": true
"integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw=="
},
"node_modules/is-binary-path": {
"version": "2.1.0",
@ -1260,6 +1340,11 @@
"node": ">=0.12.0"
}
},
"node_modules/js-sha3": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
"integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q=="
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -1324,12 +1409,45 @@
"yallist": "^3.0.2"
}
},
"node_modules/match-sorter": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.1.tgz",
"integrity": "sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==",
"dependencies": {
"@babel/runtime": "^7.12.5",
"remove-accents": "0.4.2"
}
},
"node_modules/microseconds": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/microseconds/-/microseconds-0.2.0.tgz",
"integrity": "sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA=="
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"node_modules/nano-time": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/nano-time/-/nano-time-1.0.0.tgz",
"integrity": "sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==",
"dependencies": {
"big-integer": "^1.6.16"
}
},
"node_modules/nanoid": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
@ -1373,6 +1491,19 @@
"node": ">=0.10.0"
}
},
"node_modules/oblivious-set": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/oblivious-set/-/oblivious-set-1.0.0.tgz",
"integrity": "sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw=="
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/path": {
"version": "0.12.7",
"resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
@ -1383,6 +1514,14 @@
"util": "^0.10.3"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@ -1466,6 +1605,31 @@
"resolved": "https://registry.npmjs.org/react-keybind/-/react-keybind-0.9.4.tgz",
"integrity": "sha512-JVlXJ4ONQFQtEDZqXpc5NZ3oLEJtj7lKCPMLsbAO6FfkXJ21VHKyDtiLUIMio3d3oSC8QfxDOQtUEeVrMW6HfQ=="
},
"node_modules/react-query": {
"version": "3.39.3",
"resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz",
"integrity": "sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==",
"dependencies": {
"@babel/runtime": "^7.5.5",
"broadcast-channel": "^3.4.1",
"match-sorter": "^6.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
},
"react-native": {
"optional": true
}
}
},
"node_modules/react-refresh": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
@ -1492,6 +1656,25 @@
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
"integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA=="
},
"node_modules/remove-accents": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.4.2.tgz",
"integrity": "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA=="
},
"node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/rollup": {
"version": "3.28.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.1.tgz",
@ -1633,6 +1816,15 @@
"node": ">=14.17"
}
},
"node_modules/unload": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/unload/-/unload-2.2.0.tgz",
"integrity": "sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==",
"dependencies": {
"@babel/runtime": "^7.6.2",
"detect-node": "^2.0.4"
}
},
"node_modules/update-browserslist-db": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
@ -1746,6 +1938,11 @@
}
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",

View file

@ -32,6 +32,7 @@
"date-fns": "^2.30.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-keybind": "^0.9.4"
"react-keybind": "^0.9.4",
"react-query": "^3.39.3"
}
}

22
randomshit.txt Normal file
View file

@ -0,0 +1,22 @@
const monthColors = [
"#AA3939",
"#FFAAAA",
"#D46A6A",
"#801515",
"#550000",
"#AA6C39",
"#FFD1AA",
"#D49A6A",
"#804515",
"#552700",
"#226666",
"#669999",
"#407F7F",
"#0D4D4D",
"#003333",
"#2D882D",
"#88CC88",
"#55AA55",
"#116611",
"#004400",
];

View file

@ -9,4 +9,8 @@ main.app {
.header {
padding-top: 40px;
flex-basis: 120px;
display: flex;
align-items: center;
}

View file

@ -2,6 +2,9 @@ import { endOfMonth, format, startOfMonth } from "date-fns";
import styles from "./App.module.scss";
import Calendar from "./calendar/Calendar";
import KeyboardShortcutWrapper from "./KeyboardShortcutWrapper";
import { QueryClient, QueryClientProvider } from "react-query";
const queryClient = new QueryClient();
export default function App() {
const onDateClick = async (date: Date) => {
@ -44,15 +47,17 @@ export default function App() {
const exit = () => logseq.hideMainUI();
return (
<KeyboardShortcutWrapper onExit={exit}>
<main className={styles.app}>
<div className="header">
Header
<button onClick={exit}>Close</button>
</div>
<QueryClientProvider client={queryClient}>
<KeyboardShortcutWrapper onExit={exit}>
<main className={styles.app}>
<div className={styles.header}>
Header
<button onClick={exit}>Close</button>
</div>
<Calendar onDateClick={onDateClick} />
</main>
</KeyboardShortcutWrapper>
<Calendar onDateClick={onDateClick} />
</main>
</KeyboardShortcutWrapper>
</QueryClientProvider>
);
}

View file

@ -13,6 +13,13 @@
.title {
font-size: 22px;
display: flex;
justify-content: space-between;
}
.controlButtons {
display: flex;
gap: 12px;
}
}

View file

@ -9,6 +9,8 @@ import {
} from "date-fns";
import Month from "./Month";
import { monthNameOf, weekBoundsOfMonth } from "lib/month";
import { useJournals } from "lib/queries";
import ToggleSwitch from "src/widgets/ToggleSwitch";
const daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
const NUM_MONTHS_SHOWN = 5;
@ -32,6 +34,9 @@ export default function Calendar({ onDateClick }: CalendarProps) {
range.map((x) => addMonths(centerMonth, x))
);
const startDate = monthsShown[0];
const endDate = monthsShown[NUM_MONTHS_SHOWN - 1];
const [firstLoad, setFirstLoad] = useState(true);
useEffect(() => {
if (firstLoad && scrollyEl && viewportHeight > 0) {
@ -72,7 +77,7 @@ export default function Calendar({ onDateClick }: CalendarProps) {
useEffect(() => {
if (!scrollyEl) return;
const children = [...scrollyEl.children];
const children: HTMLElement[] = [...scrollyEl.children];
if (children.length !== NUM_MONTHS_SHOWN) throw new Error("wtf");
const firstChild = children[0];
const lastChild = children[NUM_MONTHS_SHOWN - 1];
@ -86,7 +91,7 @@ export default function Calendar({ onDateClick }: CalendarProps) {
if (entry.target === firstChild) {
console.log("intersected");
const firstChildDate = new Date(firstChild.dataset.isodate);
const firstChildDate = new Date(firstChild.dataset.isodate!);
const prevMonth = subMonths(firstChildDate, 1);
newMonthsShown = [prevMonth, ...monthsShown];
newMonthsShown = newMonthsShown.slice(0, NUM_MONTHS_SHOWN);
@ -96,7 +101,7 @@ export default function Calendar({ onDateClick }: CalendarProps) {
scrollyEl.scrollTop - firstChild.offsetTop,
]);
} else if (entry.target === lastChild) {
const lastChildDate = new Date(lastChild.dataset.isodate);
const lastChildDate = new Date(lastChild.dataset.isodate!);
const nextMonth = addMonths(lastChildDate, 1);
newMonthsShown = [...monthsShown, nextMonth];
newMonthsShown = newMonthsShown.slice(-NUM_MONTHS_SHOWN);
@ -139,19 +144,31 @@ export default function Calendar({ onDateClick }: CalendarProps) {
// middleMonthEl?.scrollIntoView();
// }, [middleMonthRef]);
const [currentLayout, setCurrentLayout] = useState("Month");
const [currentView, setCurrentView] = useState("Calendar");
return (
<div className={styles.calendar}>
<div className={styles.header}>
<div className={styles.title}>
<b>{monthName}</b>
{centerMonth.getFullYear()}
(months shown:{" "}
{JSON.stringify(
monthsShown.map((x) =>
x.toLocaleDateString("default", { month: "long" })
)
)}
)
<div>
<b>{monthName}</b>
{centerMonth.getFullYear()}
</div>
<div className={styles.controlButtons}>
<ToggleSwitch
options={["Week", "Month", "Year"]}
value={currentLayout}
setValue={setCurrentLayout}
/>
<ToggleSwitch
options={["Calendar", "Graph"]}
value={currentView}
setValue={setCurrentView}
/>
</div>
</div>
<div className={styles.daysOfWeek}>
@ -173,6 +190,7 @@ export default function Calendar({ onDateClick }: CalendarProps) {
const props = {
month,
dateGridHeight,
dateCellHeight,
};
const ref = undefined;
// (month === currentlyShownMonth && middleMonthRef) || undefined;

View file

@ -11,40 +11,26 @@ import {
} from "date-fns";
import classNames from "classnames";
import { weekBoundsOfMonth } from "lib/month";
import { journalFmt, useJournals } from "lib/queries";
interface MonthProps {
month: Date;
dateGridHeight: number;
dateCellHeight: number;
onDateClick?: (_: Date) => void;
}
const monthColors = [
"#AA3939",
"#FFAAAA",
"#D46A6A",
"#801515",
"#550000",
"#AA6C39",
"#FFD1AA",
"#D49A6A",
"#804515",
"#552700",
"#226666",
"#669999",
"#407F7F",
"#0D4D4D",
"#003333",
"#2D882D",
"#88CC88",
"#55AA55",
"#116611",
"#004400",
];
function Month({ month, dateGridHeight, onDateClick }: MonthProps, ref) {
function Month(
{ month, dateGridHeight, dateCellHeight, onDateClick }: MonthProps,
ref
) {
const now = new Date();
const monthName = month.toLocaleString("default", { month: "long" });
const firstDay = startOfMonth(month);
const lastDay = endOfMonth(month);
const { status, data: journals } = useJournals(firstDay, lastDay);
const [startWeek, endWeek] = weekBoundsOfMonth(month);
const numWeeks = differenceInWeeks(endWeek, startWeek) + 1;
const weeksArr = Array(numWeeks)
@ -61,13 +47,18 @@ function Month({ month, dateGridHeight, onDateClick }: MonthProps, ref) {
<>
<div
className={styles.dateGrid}
style={{ height: `${dateGridHeight}px` }}
// style={{ height: `${dateGridHeight}px` }}
style={{ gridTemplateRows: `repeat(${numWeeks}, ${dateCellHeight}px)` }}
ref={ref}
data-isodate={month}
>
{datesArr.map((date) => {
const isFirst = isSameDay(date, startOfMonth(date));
const isToday = isSameDay(date, now);
const journalDate = journalFmt(date);
const hasJournal = journals?.has(journalDate);
return (
<div
key={date.toString()}
@ -78,18 +69,15 @@ function Month({ month, dateGridHeight, onDateClick }: MonthProps, ref) {
className={styles.dateNumber}
onClick={() => onDateClick?.(date)}
>
<span
className={classNames(isFirst && styles.today)}
style={
isFirst
? { backgroundColor: monthColors[date.getMonth()] }
: {}
}
>
<span className={classNames(isToday && styles.today)}>
{isFirst && monthName}
{date.getDate()}
</span>
</div>
<div className={styles.dateCellBody}>
<p>j: {JSON.stringify(hasJournal)}</p>
</div>
</div>
);
})}

View file

@ -1,3 +1,11 @@
:root {
--text-color: black;
@media (prefers-color-scheme: dark) {
--text-color: white;
}
}
html,
body,
#app {
@ -8,4 +16,5 @@ body,
padding: 0;
font-family: sans-serif;
color: var(--text-color);
}

View file

@ -0,0 +1,19 @@
.toggleSwitch {
display: flex;
gap: 6px;
border-radius: 9999px;
background-color: lightgray;
font-size: 14px;
padding: 4px;
}
.option {
border-radius: 9999px;
padding: 4px 12px;
cursor: pointer;
&.selected {
background-color: gray;
}
}

View file

@ -0,0 +1,33 @@
import classNames from "classnames";
import styles from "./ToggleSwitch.module.scss";
interface ToggleSwitchProps {
options: string[];
defaultOption?: string;
value: string;
setValue: (_: string) => any;
}
export default function ToggleSwitch({
options,
defaultOption,
value,
setValue,
}: ToggleSwitchProps) {
return (
<div className={styles.toggleSwitch}>
{options.map((option) => {
const isSelected = option === value;
return (
<div
key={option}
className={classNames(styles.option, isSelected && styles.selected)}
onClick={() => setValue(option)}
>
{option}
</div>
);
})}
</div>
);
}