From 78144d00837e1bbd0be435c39a6d552f0a49c8b5 Mon Sep 17 00:00:00 2001 From: Ryan Pandya Date: Sun, 24 Nov 2024 02:33:20 -0800 Subject: [PATCH] Now able to create categories! --- apps/cli/src/commands/categories.ts | 106 ++++++++++++++++++ apps/cli/src/commands/colors.ts | 14 ++- apps/cli/src/index.ts | 7 +- .../dashboard/categories/CategoriesView.tsx | 2 +- .../categories/EditCategoryDialog.tsx | 4 +- .../web/components/settings/ColorSettings.tsx | 38 +++---- ....sql => 0000_awesome_stepford_cuckoos.sql} | 4 +- .../db/migrations/meta/0000_snapshot.json | 10 +- packages/db/migrations/meta/_journal.json | 4 +- packages/db/reset.ts | 27 ----- packages/db/schema.ts | 11 +- packages/shared/types/categories.ts | 16 ++- packages/shared/types/colors.ts | 2 + packages/trpc/routers/categories.ts | 96 +++++++++++----- packages/trpc/routers/colors.ts | 36 +++++- scripts/create_categories.sh | 79 +++++++++++++ scripts/create_colors.sh | 11 ++ 17 files changed, 364 insertions(+), 103 deletions(-) create mode 100644 apps/cli/src/commands/categories.ts rename packages/db/migrations/{0000_gigantic_doctor_strange.sql => 0000_awesome_stepford_cuckoos.sql} (95%) delete mode 100644 packages/db/reset.ts create mode 100644 scripts/create_categories.sh create mode 100644 scripts/create_colors.sh diff --git a/apps/cli/src/commands/categories.ts b/apps/cli/src/commands/categories.ts new file mode 100644 index 0000000..34c6704 --- /dev/null +++ b/apps/cli/src/commands/categories.ts @@ -0,0 +1,106 @@ +import { getGlobalOptions } from "@/lib/globals"; +import { + printError, + printErrorMessageWithReason, + printObject, + printSuccess, +} from "@/lib/output"; +import { getAPIClient } from "@/lib/trpc"; +import { Command } from "@commander-js/extra-typings"; +import { getBorderCharacters, table } from "table"; + +export const categoriesCmd = new Command() + .name("categories") + .description("Manipulate categories"); + +categoriesCmd + .command("list") + .description("lists all defined categories") + .action(async () => { + const api = getAPIClient(); + + try { + const categories = (await api.categories.list.query()).categories; + // colors.sort((a, b) => b.numCategories - a.numCategories); + if (getGlobalOptions().json) { + printObject(categories); + } else { + const data: string[][] = [["Code", "Name", "Description", "Color"]]; + + categories.forEach((c) => { + data.push([c.code.toString(), c.name, c.description ?? "none", c.color.name]); + }); + console.log( + data.length <= 1 ? + "No categories found. Add one with `lifetracker categories create `" : + table(data, { + // border: getBorderCharacters("ramac"), + // singleLine: true, + drawVerticalLine: (lineIndex, columnCount) => { + return lineIndex === 0 || lineIndex === columnCount; + }, + drawHorizontalLine: (lineIndex, rowCount) => { + return lineIndex < 2 || lineIndex === rowCount; + }, + }), + ); + } + } catch (error) { + printErrorMessageWithReason("Failed to list all categories", error as object); + } + }); + +categoriesCmd + .command("create") + .description("create a category") + .argument("", "the code of the category") + .argument("", "the name of the category") + .argument("", "the description of the category") + .argument("[color]", "the color of the category") + .option('-p, --parent ', "specify a parent category by code") + .action(async (codeStr: string, name: string, description: string, colorName?: string, flags?) => { + const api = getAPIClient(); + + const color = flags?.parent === undefined ? + (await api.colors.get.query({ colorName: colorName! })) + : + (await api.categories.get.query({ categoryCode: parseInt(flags.parent) })).color + + + try { + await api.categories.create + .mutate({ + code: parseFloat(codeStr), + name: name, + description: description, + color: color, + }) + .then(printSuccess(`Successfully created the category "${name}"`)) + .catch(printError(`Failed to create the category "${name}"`)); + api.categories.list + } + catch (e) { + console.log(e); + } + }); + + +categoriesCmd + .command("delete") + .description("delete a category") + .argument("", "the code of the category") + .action(async (codeStr: string) => { + const api = getAPIClient(); + + try { + await api.categories.delete + .mutate({ + categoryCode: parseInt(codeStr), + }) + .then(printSuccess(`Successfully deleted category "${codeStr}"`)) + .catch(printError(`Failed to delete category "${codeStr}"`)); + } + catch (e) { + console.log(e); + } + }); diff --git a/apps/cli/src/commands/colors.ts b/apps/cli/src/commands/colors.ts index b71c315..3b62110 100644 --- a/apps/cli/src/commands/colors.ts +++ b/apps/cli/src/commands/colors.ts @@ -25,17 +25,23 @@ colorsCmd if (getGlobalOptions().json) { printObject(colors); } else { - const data: string[][] = [["Id", "Name", "Hexcode", "user"]]; + const data: string[][] = [["Name", "Hexcode", "Inverse"]]; colors.forEach((color) => { - data.push([color.id, color.name, color.hexcode, color.userId]); + data.push([color.name, color.hexcode, color.inverse]); }); console.log( data.length <= 1 ? "No colors found. Add one with `lifetracker colors create `" : table(data, { - border: getBorderCharacters("ramac"), - singleLine: true, + // border: getBorderCharacters("ramac"), + // singleLine: true, + drawVerticalLine: (lineIndex, columnCount) => { + return lineIndex === 0 || lineIndex === columnCount; + }, + drawHorizontalLine: (lineIndex, rowCount) => { + return lineIndex < 2 || lineIndex === rowCount; + }, }), ); } diff --git a/apps/cli/src/index.ts b/apps/cli/src/index.ts index 72d428e..62a840a 100644 --- a/apps/cli/src/index.ts +++ b/apps/cli/src/index.ts @@ -3,6 +3,7 @@ import { Command, Option } from "@commander-js/extra-typings"; import { whoamiCmd } from "@/commands/whoami"; import { colorsCmd } from "@/commands/colors"; +import { categoriesCmd } from "@/commands/categories"; import { config } from "dotenv"; @@ -34,11 +35,9 @@ const program = new Command() : "0.0.0", ); -program.addCommand(whoamiCmd, { - isDefault: true -}); +program.addCommand(whoamiCmd); program.addCommand(colorsCmd); - +program.addCommand(categoriesCmd); setGlobalOptions(program.opts()); diff --git a/apps/web/components/dashboard/categories/CategoriesView.tsx b/apps/web/components/dashboard/categories/CategoriesView.tsx index 2c76a90..d8c56ac 100644 --- a/apps/web/components/dashboard/categories/CategoriesView.tsx +++ b/apps/web/components/dashboard/categories/CategoriesView.tsx @@ -52,7 +52,7 @@ export default function CategoriesView() { {categories.categories.map((c) => ( - + {c.code} {c.name} {c.description} diff --git a/apps/web/components/dashboard/categories/EditCategoryDialog.tsx b/apps/web/components/dashboard/categories/EditCategoryDialog.tsx index 65d6161..56c09d9 100644 --- a/apps/web/components/dashboard/categories/EditCategoryDialog.tsx +++ b/apps/web/components/dashboard/categories/EditCategoryDialog.tsx @@ -33,9 +33,9 @@ import { TRPCClientError } from "@trpc/client"; import { useForm } from "react-hook-form"; import { z } from "zod"; -import { zLabelSchema } from "@lifetracker/shared/types/categories"; +import { zCategorySchema } from "@lifetracker/shared/types/categories"; -type CreateLabelSchema = z.infer; +type CreateCategorySchema = z.infer; export default function EditCategoryDialog({ children, diff --git a/apps/web/components/settings/ColorSettings.tsx b/apps/web/components/settings/ColorSettings.tsx index 7b729f4..5cab769 100644 --- a/apps/web/components/settings/ColorSettings.tsx +++ b/apps/web/components/settings/ColorSettings.tsx @@ -19,26 +19,26 @@ import AddColor from "./AddColor"; // import EditCategoryDialog from "./EditCategoryDialog"; import Link from "next/link"; -export default function ColorssView() { +export default function ColorsView() { const { data: session } = useSession(); const { data: colors } = api.colors.list.useQuery(); - // const invalidateColorList = api.useUtils().colors.list.invalidate; - // const { mutate: deleteColor, isPending: isDeletionPending } = - // api.colors.delete.useMutation({ - // onSuccess: () => { - // toast({ - // description: "Color deleted", - // }); - // invalidateCategoryList(); - // }, - // onError: (e) => { - // toast({ - // variant: "destructive", - // description: `Something went wrong: ${e.message}`, - // }); - // }, - // }); + const invalidateColorList = api.useUtils().colors.list.invalidate; + const { mutate: deleteColor, isPending: isDeletionPending } = + api.colors.delete.useMutation({ + onSuccess: () => { + toast({ + description: "Color deleted", + }); + invalidateColorList(); + }, + onError: (e) => { + toast({ + variant: "destructive", + description: `Something went wrong: ${e.message}`, + }); + }, + }); const ColorsTable = ({ colors }) => ( @@ -52,13 +52,13 @@ export default function ColorssView() { {c.name} - numEntries + {c.numCategories} deleteColor({ colorId: c.id })} + onClick={() => deleteColor({ colorName: c.name })} loading={false} > diff --git a/packages/db/migrations/0000_gigantic_doctor_strange.sql b/packages/db/migrations/0000_awesome_stepford_cuckoos.sql similarity index 95% rename from packages/db/migrations/0000_gigantic_doctor_strange.sql rename to packages/db/migrations/0000_awesome_stepford_cuckoos.sql index 7275c61..b2b7499 100644 --- a/packages/db/migrations/0000_gigantic_doctor_strange.sql +++ b/packages/db/migrations/0000_awesome_stepford_cuckoos.sql @@ -28,7 +28,7 @@ CREATE TABLE `category` ( `id` text PRIMARY KEY NOT NULL, `createdAt` integer NOT NULL, `name` text NOT NULL, - `code` integer NOT NULL, + `code` real NOT NULL, `description` text, `colorId` text NOT NULL, `parentId` text, @@ -86,7 +86,7 @@ CREATE TABLE `verificationToken` ( --> statement-breakpoint CREATE UNIQUE INDEX `apiKey_keyId_unique` ON `apiKey` (`keyId`);--> statement-breakpoint CREATE UNIQUE INDEX `apiKey_name_userId_unique` ON `apiKey` (`name`,`userId`);--> statement-breakpoint -CREATE UNIQUE INDEX `category_userId_name_unique` ON `category` (`userId`,`name`);--> statement-breakpoint +CREATE UNIQUE INDEX `category_userId_code_unique` ON `category` (`userId`,`code`);--> statement-breakpoint CREATE UNIQUE INDEX `color_userId_name_unique` ON `color` (`userId`,`name`);--> statement-breakpoint CREATE UNIQUE INDEX `day_date_unique` ON `day` (`date`);--> statement-breakpoint CREATE UNIQUE INDEX `user_email_unique` ON `user` (`email`); \ No newline at end of file diff --git a/packages/db/migrations/meta/0000_snapshot.json b/packages/db/migrations/meta/0000_snapshot.json index ee3d996..4ea3071 100644 --- a/packages/db/migrations/meta/0000_snapshot.json +++ b/packages/db/migrations/meta/0000_snapshot.json @@ -1,7 +1,7 @@ { "version": "6", "dialect": "sqlite", - "id": "d35127c1-6892-410e-b933-d7ec7aabe6f5", + "id": "7f1d6157-2405-4b96-be6a-a4bfb35f9aaf", "prevId": "00000000-0000-0000-0000-000000000000", "tables": { "account": { @@ -219,7 +219,7 @@ }, "code": { "name": "code", - "type": "integer", + "type": "real", "primaryKey": false, "notNull": true, "autoincrement": false @@ -254,11 +254,11 @@ } }, "indexes": { - "category_userId_name_unique": { - "name": "category_userId_name_unique", + "category_userId_code_unique": { + "name": "category_userId_code_unique", "columns": [ "userId", - "name" + "code" ], "isUnique": true } diff --git a/packages/db/migrations/meta/_journal.json b/packages/db/migrations/meta/_journal.json index 9d840bf..ce44a57 100644 --- a/packages/db/migrations/meta/_journal.json +++ b/packages/db/migrations/meta/_journal.json @@ -5,8 +5,8 @@ { "idx": 0, "version": "6", - "when": 1732260188078, - "tag": "0000_gigantic_doctor_strange", + "when": 1732441653703, + "tag": "0000_awesome_stepford_cuckoos", "breakpoints": true } ] diff --git a/packages/db/reset.ts b/packages/db/reset.ts deleted file mode 100644 index c5f33ca..0000000 --- a/packages/db/reset.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { db } from "./drizzle"; -import { apiKeys, users } from "./schema"; -import { generateApiKey } from "../trpc/auth"; -import { and, count, eq } from "drizzle-orm"; - -db.transaction(async (trx) => { - const ryan = await trx - .insert(users) - .values({ - name: "Ryan Pandya", - email: "ryan@ryanpandya.com", - password: "$2a$10$ngv9752uxDT11hSPfdZmAe2D8VXLB9mcXkN7TRPI5GZQCuriIu1gC", - role: "admin", - }) - .returning({ - id: users.id, - name: users.name, - email: users.email, - role: users.role, - }); - - db.query.users.findFirst({ - where: eq(users.email, "ryan@ryanpandya.com"), - }).then((user) => { - generateApiKey("CLI App", ryan.id); - }); -}); diff --git a/packages/db/schema.ts b/packages/db/schema.ts index 8f4fc42..14130a6 100644 --- a/packages/db/schema.ts +++ b/packages/db/schema.ts @@ -5,6 +5,7 @@ import { AnySQLiteColumn, index, integer, + real, primaryKey, sqliteTable, text, @@ -28,6 +29,10 @@ export function calcInverseColor(hexcode: string): string { return luminance > 186 ? "#000000" : "#ffffff"; } +// export function calcCategoryParent(parentId: string | null){ +// return parentId ?? +// } + export const config = sqliteTable("config", { @@ -155,7 +160,7 @@ export const categories = sqliteTable( .$defaultFn(() => createId()), createdAt: createdAtField(), name: text("name").notNull(), - code: integer("code").notNull(), + code: real("code").notNull(), description: text("description"), colorId: text("colorId") .notNull() @@ -165,8 +170,8 @@ export const categories = sqliteTable( .notNull() .references(() => users.id, { onDelete: "cascade" }), }, - (lb) => ({ - uniq: unique().on(lb.userId, lb.name) + (c) => ({ + uniq: unique().on(c.userId, c.code) }), ); diff --git a/packages/shared/types/categories.ts b/packages/shared/types/categories.ts index 34b7ec2..ece63b6 100644 --- a/packages/shared/types/categories.ts +++ b/packages/shared/types/categories.ts @@ -1,14 +1,26 @@ import { z } from "zod"; +import { zColorSchema } from "./colors"; export const zCategorySchema = z.object({ - id: z.string(), code: z.coerce.number(), name: z.string(), - colorId: z.string(), description: z.string().optional(), + color: zColorSchema, + parentId: z.string().optional(), }); export type ZCategories = z.infer; +export const zCreateCategorySchema = z.object({ + code: z.coerce.number(), + name: z.string(), + description: z.string().optional(), + color: z.string(), + parentId: z.string().optional(), +}); +export type ZCreateCategories = z.infer; + + + export const zGetCategoryResponseSchema = z.object({ id: z.string(), code: z.number(), diff --git a/packages/shared/types/colors.ts b/packages/shared/types/colors.ts index abf3e0c..7748999 100644 --- a/packages/shared/types/colors.ts +++ b/packages/shared/types/colors.ts @@ -3,5 +3,7 @@ import { z } from "zod"; export const zColorSchema = z.object({ name: z.string(), hexcode: z.string(), + inverse: z.string().optional(), + id: z.string().optional(), }); export type ZColor = z.infer; diff --git a/packages/trpc/routers/categories.ts b/packages/trpc/routers/categories.ts index 88749ca..3bf1e32 100644 --- a/packages/trpc/routers/categories.ts +++ b/packages/trpc/routers/categories.ts @@ -3,18 +3,22 @@ import { and, desc, eq, inArray, notExists } from "drizzle-orm"; import { z } from "zod"; import { SqliteError } from "@lifetracker/db"; -import { categories } from "@lifetracker/db/schema"; +import { categories, colors } from "@lifetracker/db/schema"; import { + ZCategories, zCategorySchema, + ZCreateCategories, + zCreateCategorySchema, zGetCategoryResponseSchema, zUpdateCategoryRequestSchema } from "@lifetracker/shared/types/categories"; import type { Context } from "../index"; import { authedProcedure, router } from "../index"; +import { zColorSchema } from "@lifetracker/shared/types/colors"; -function conditionFromInput(input: { categoryId: string }, userId: string) { - return and(eq(categories.id, input.categoryId), eq(categories.userId, userId)); +function conditionFromInput(input: { categoryCode: string }, userId: string) { + return and(eq(categories.code, input.categoryCode), eq(categories.userId, userId)); } async function createCategory( @@ -22,10 +26,8 @@ async function createCategory( ctx: Context, ) { - console.log("Creating a category"); - return ctx.db.transaction(async (trx) => { - + console.log("Creating a category", input); try { const result = await trx .insert(categories) @@ -33,23 +35,31 @@ async function createCategory( name: input.name, code: input.code, description: input.description, - color: input.color, + colorId: input.color.id, userId: ctx.user!.id, + parentId: input.parentId ?? undefined }) .returning({ id: categories.id, name: categories.name, code: categories.code, description: categories.description, - color: categories.color, + colorId: categories.colorId }); - return result[0]; + const { colorId, ...newCategory } = result[0]; + + return { + color: input.color, + ...newCategory + }; + } catch (e) { + console.log(e); if (e instanceof SqliteError) { if (e.code == "SQLITE_CONSTRAINT_UNIQUE") { throw new TRPCError({ code: "BAD_REQUEST", - message: "Line 48 trpc routers categories.ts", + message: "There's already a category with this code", }); } } @@ -93,7 +103,10 @@ export const categoriesAppRouter = router({ categories: z.array( z.object({ id: z.string(), + code: z.number(), name: z.string(), + description: z.string().optional(), + color: zColorSchema, }), ), }), @@ -102,34 +115,43 @@ export const categoriesAppRouter = router({ const dbCategories = await ctx.db .select({ id: categories.id, + code: categories.code, name: categories.name, + description: categories.description, + color: { + name: colors.name, + hexcode: colors.hexcode, + inverse: colors.inverse + } }) - .from(categories); - - // console.log("Listing cats"); - // console.log(dbCategories); - // console.log(dbCategories.map(({ ...category }) => ({ - // ...category - // }))); + .from(categories) + .leftJoin(colors, eq(categories.colorId, colors.id)) + ; return { - categories: dbCategories.map(({ ...category }) => ({ - ...category + categories: dbCategories.map(({ color, ...category }) => ({ + ...category, + color, })), }; }), get: authedProcedure .input( z.object({ - categoryId: z.string(), + categoryCode: z.number(), }), ) - .output(zGetCategoryResponseSchema) + .output(zCategorySchema) .query(async ({ input, ctx }) => { const res = await ctx.db .select({ id: categories.id, - name: categories.name + code: categories.code, + name: categories.name, + description: categories.description, + colorId: categories.colorId, + parentId: categories.parentId, + userId: categories.userId, }) .from(categories) .where( @@ -155,11 +177,28 @@ export const categoriesAppRouter = router({ { ai: 0, human: 0 }, ); - return { - id: res[0].id, - name: res[0].name, - numEntries: 420 + const [color] = await ctx.db.select().from(colors).where( + and( + and(eq(colors.id, res[0].colorId), eq(colors.userId, res[0].userId)), + eq(res[0].userId, ctx.user.id), + ) + ); + + const categoryId: string = res[0].id; + + const { id, ...categoryProps } = res[0]; + const category: ZCategories = { + color: color, + ...categoryProps }; + + if (category.parentId == null) { + category.parentId = categoryId; + } + + console.log(category); + + return category; }), create: authedProcedure .input(zCategorySchema) @@ -168,12 +207,11 @@ export const categoriesAppRouter = router({ id: z.string(), code: z.number(), name: z.string(), - color: z.string().default("#000000"), + color: zColorSchema, description: z.string().optional(), }), ) .mutation(async ({ input, ctx }) => { - console.log("Just started creating a category"); return createCategory(input, ctx); }), update: authedProcedure @@ -240,7 +278,7 @@ export const categoriesAppRouter = router({ delete: authedProcedure .input( z.object({ - categoryId: z.string(), + categoryCode: z.number(), }), ) .mutation(async ({ input, ctx }) => { diff --git a/packages/trpc/routers/colors.ts b/packages/trpc/routers/colors.ts index a526b3e..81164eb 100644 --- a/packages/trpc/routers/colors.ts +++ b/packages/trpc/routers/colors.ts @@ -12,7 +12,7 @@ import { authedProcedure, router } from "../index"; import { titleCase } from "title-case"; function conditionFromInput(input: { colorName: string }, userId: string) { - return and(eq(titleCase(colors.name), titleCase(input.colorName)), eq(colors.userId, userId)); + return and(eq(colors.name, titleCase(input.colorName)), eq(colors.userId, userId)); } async function createColor( @@ -62,7 +62,8 @@ export const colorsAppRouter = router({ id: z.string(), name: z.string(), hexcode: z.string(), - userId: z.string(), + inverse: z.string(), + numCategories: z.number(), }), ), })) @@ -72,13 +73,14 @@ export const colorsAppRouter = router({ id: colors.id, name: colors.name, hexcode: colors.hexcode, - userId: colors.userId, + inverse: colors.inverse, }) .from(colors); return { colors: dbColors.map(({ ...color }) => ({ ...color, + numCategories: 0 })), }; }), @@ -108,4 +110,32 @@ export const colorsAppRouter = router({ throw new TRPCError({ code: "NOT_FOUND" }); } }), + get: authedProcedure + .input( + z.object({ + colorName: z.string(), + }), + ) + .output( + z.object({ + id: z.string(), + name: z.string(), + hexcode: z.string(), + })) + .query(async ({ input, ctx }) => { + const res = await ctx.db + .select({ + id: colors.id, + name: colors.name, + hexcode: colors.hexcode, + }) + .from(colors) + .where(conditionFromInput(input, ctx.user.id)); + + if (res.length == 0) { + throw new TRPCError({ code: "NOT_FOUND" }); + } + + return res[0]; + }), }); diff --git a/scripts/create_categories.sh b/scripts/create_categories.sh new file mode 100644 index 0000000..56aab76 --- /dev/null +++ b/scripts/create_categories.sh @@ -0,0 +1,79 @@ +pnpm --filter=@lifetracker/cli run run categories create 0 "Sleep" "Time spent sleeping." black +pnpm --filter=@lifetracker/cli run run categories create --parent 0 0.4 "Travel sleep" "Typically shitty half-sleep on a plane or in a car." +pnpm --filter=@lifetracker/cli run run categories create --parent 0 0.5 "Nap" "Sleep other than at night." +pnpm --filter=@lifetracker/cli run run categories create --parent 0 0.9 "Sick" "Resting while sick or injured." +pnpm --filter=@lifetracker/cli run run categories create 1 "Family" "Time spent with family." crimson +pnpm --filter=@lifetracker/cli run run categories create --parent 1 13 "Wedding, etc." "Wedding and related stuff." +pnpm --filter=@lifetracker/cli run run categories create --parent 1 15 "Neighborhood / Community" "Local family, if you will." +pnpm --filter=@lifetracker/cli run run categories create --parent 1 16 "Watching something" "TV, movies, or the like, watched with family." +pnpm --filter=@lifetracker/cli run run categories create 2 "Friends" "Time spent with friends." teal +pnpm --filter=@lifetracker/cli run run categories create --parent 2 22 "Party" "Party with friends." +pnpm --filter=@lifetracker/cli run run categories create --parent 2 26 "Active / Sports" "Playing active games or sports with friends." +pnpm --filter=@lifetracker/cli run run categories create --parent 2 28 "Meal" "Preparing or eating a meal with friends." +pnpm --filter=@lifetracker/cli run run categories create --parent 2 29 "Drugs" "Drugs with friends." +pnpm --filter=@lifetracker/cli run run categories create 3 "Jen" "Time spent on dates or primarily with/for Jen." pink +pnpm --filter=@lifetracker/cli run run categories create --parent 3 31 "Jen's family" "Time spent with Jen's family." +pnpm --filter=@lifetracker/cli run run categories create --parent 3 32 "Jen's friends" "Time with primarily Jen's friends." +pnpm --filter=@lifetracker/cli run run categories create --parent 3 33 "Sex" "Sex or sex-related activities." +pnpm --filter=@lifetracker/cli run run categories create --parent 3 34 "Exploring" "Exploring and adventuring, with a more urban (non-nature) focus." +pnpm --filter=@lifetracker/cli run run categories create --parent 3 35 "Errands & Logistics" "When shit needs to get done, for me and Jen." +pnpm --filter=@lifetracker/cli run run categories create --parent 3 36 "Watching something" "Watching a movie, TV show, or Internet stuff with Jen." +pnpm --filter=@lifetracker/cli run run categories create --parent 3 37 "Hiking / Adventuring" "Hiking, camping, and backcountry adventures with an active focus." +pnpm --filter=@lifetracker/cli run run categories create --parent 3 38 "Meal with Jen" "Cooking, eating out, or just having a meal with my love." +pnpm --filter=@lifetracker/cli run run categories create --parent 3 39 "Relaxing / Napping" "Rest and cuddles, other than primarily for sleep or sex." +pnpm --filter=@lifetracker/cli run run categories create 4 "Flying" "Anything related to private flying." blue +pnpm --filter=@lifetracker/cli run run categories create --parent 4 41 "Airports, etc." "Dealing with FBOs, getting in or out of the plane, etc." +pnpm --filter=@lifetracker/cli run run categories create --parent 4 42 "Flying with friends" "Tour or flight for fun with friends." +pnpm --filter=@lifetracker/cli run run categories create --parent 4 43 "Flying with Jen" "A flying trip primarily for me and Jen." +pnpm --filter=@lifetracker/cli run run categories create --parent 4 44 "Flight planning" "Checking weather, planning, filing flight plan, etc." +pnpm --filter=@lifetracker/cli run run categories create --parent 4 45 "Flying for work" "A primarily business-oriented flying trip." +pnpm --filter=@lifetracker/cli run run categories create --parent 4 46 "Maintenance" "A primarily maintenance-related flying trip." +pnpm --filter=@lifetracker/cli run run categories create --parent 4 47 "Training" "A primarily training-related flying trip." +pnpm --filter=@lifetracker/cli run run categories create --parent 4 49 "Other Flying Related" "e.g., Phone calls, research, buying/selling" +pnpm --filter=@lifetracker/cli run run categories create 5 "Work" "Time spent working for money." green +pnpm --filter=@lifetracker/cli run run categories create --parent 5 51 "Investors" "Pitching, diligence, calls, or somehow convincing investors to pony up." +pnpm --filter=@lifetracker/cli run run categories create --parent 5 52 "Cofounders" "Meeting with one or more of Perumal, Bonney, TM." +pnpm --filter=@lifetracker/cli run run categories create --parent 5 53 "[REMAP ME] Wedding prep" "This was set up because I was working so hard on the wedding in 2023 I thought I was going to die, but it really doesn't have much use being in the 5s." +pnpm --filter=@lifetracker/cli run run categories create --parent 5 55 "Board" "Dealing with Board members or Board matters." +pnpm --filter=@lifetracker/cli run run categories create --parent 5 56 "Emails" "Getting the inbox under control." +pnpm --filter=@lifetracker/cli run run categories create --parent 5 57 "Work meditation" "Thinking, ruminating, or journaling about work." +pnpm --filter=@lifetracker/cli run run categories create --parent 5 58 "Socializing" "Out building work-related relationships." +pnpm --filter=@lifetracker/cli run run categories create 6 "Productive" "Time spent active (working out), fulfilling obligations, running errands, doing work without pay, or otherwise in a useful and productive way." orange +pnpm --filter=@lifetracker/cli run run categories create --parent 6 61 "Cleaning" "Tidying, organizing, or cleaning a space." +pnpm --filter=@lifetracker/cli run run categories create --parent 6 62 "Relationship work" "Having important conversations or working on the big stuff." +pnpm --filter=@lifetracker/cli run run categories create --parent 6 63 "Home maintenance" "Productivity related to the home or household." +pnpm --filter=@lifetracker/cli run run categories create --parent 6 65 "Personal finances / Life admin" "Chores related to life administration and personal finances." +pnpm --filter=@lifetracker/cli run run categories create --parent 6 66 "Outdoor exercise" "Walking, running, biking, or hiking outdoors." +pnpm --filter=@lifetracker/cli run run categories create --parent 6 67 "Gym" "Working on my fitness in a gym." +pnpm --filter=@lifetracker/cli run run categories create --parent 6 68 "Meditation / Therapy" "Working on myself." +pnpm --filter=@lifetracker/cli run run categories create --parent 6 69 "Bureaucracy / Bullshit" "Working on a needed but Kafkaesque nightmare chore." +pnpm --filter=@lifetracker/cli run run categories create 7 "Hobbies & Skills" "Time used for personal development, improving skills, or what I consider to be productive hobbies." yellow +pnpm --filter=@lifetracker/cli run run categories create --parent 7 71 "Language learning" "Learning, studying, reading, or practicing a foreign language." +pnpm --filter=@lifetracker/cli run run categories create --parent 7 72 "Cooking" "Preparing food." +pnpm --filter=@lifetracker/cli run run categories create --parent 7 73 "Home improvement" "Fun or useful stuff for the house, including gardening, automation, or other projecs that are basically hobbies." +pnpm --filter=@lifetracker/cli run run categories create --parent 7 75 "Reading" "Reading an article, book, or something else edifying." +pnpm --filter=@lifetracker/cli run run categories create --parent 7 76 "Organizing / Workflow" "Working on a hobby or skill, but doing the boring / annoying bits." +pnpm --filter=@lifetracker/cli run run categories create --parent 7 78 "Programming / Computers" "Nerding out and building something with computers." +pnpm --filter=@lifetracker/cli run run categories create --parent 7 79 "Shopping" "Shopping that isn't a waste of time." +pnpm --filter=@lifetracker/cli run run categories create 8 "Relaxation & Leisure" "Time spent gaming, relaxing, consuming entertainment, or participating in passive activities." purple +pnpm --filter=@lifetracker/cli run run categories create --parent 8 81 "Watching something" "Watching something produced for the screen (TV / Movies / Tiktok / YouTube)" +pnpm --filter=@lifetracker/cli run run categories create --parent 8 82 "Hot tub / Sauna / Pool" "Sweating or swimming in a relaxing way, other than to get clean." +pnpm --filter=@lifetracker/cli run run categories create --parent 8 83 "Masturbation" "Self sex." +pnpm --filter=@lifetracker/cli run run categories create --parent 8 87 "Drugs" "Exploring the inner cosmos." +pnpm --filter=@lifetracker/cli run run categories create --parent 8 88 "Video games" "High-octane relaxation." +pnpm --filter=@lifetracker/cli run run categories create --parent 8 89 "Social media" "Scrolling." +pnpm --filter=@lifetracker/cli run run categories create 9 "Waste" "Time better spent doing something else." red +pnpm --filter=@lifetracker/cli run run categories create --parent 9 91 "Waiting / Killing time" "Literally staring at a clock with nothing else to do." +pnpm --filter=@lifetracker/cli run run categories create --parent 9 93 "Fight" "Not understanding or communicating well." +pnpm --filter=@lifetracker/cli run run categories create --parent 9 96 "Disaster" "Something has gone horribly wrong, and everything else is canceled." +pnpm --filter=@lifetracker/cli run run categories create --parent 9 97 "Shopping" "Ah, mindless consumerism!" +pnpm --filter=@lifetracker/cli run run categories create --parent 9 98 "Can't sleep" "Lying in bed wishing I was asleep." +pnpm --filter=@lifetracker/cli run run categories create --parent 9 99 "Stress eating / drinking / smoking" "Shoveling empty calories or toxins, knowing it's a mistake." +pnpm --filter=@lifetracker/cli run run categories create 10 "Health & Travel" "Time spent for personal hygiene, getting around, or similar." lime +pnpm --filter=@lifetracker/cli run run categories create --parent 10 101 "Food" "A regular ol' meal." +pnpm --filter=@lifetracker/cli run run categories create --parent 10 103 "Bath" "Taking a bath." +pnpm --filter=@lifetracker/cli run run categories create --parent 10 104 "Travel" "Getting from a place to another place." +pnpm --filter=@lifetracker/cli run run categories create --parent 10 105 "Bathroom" "Getting clean to go somewhere or do something -- or, flossing, brushing, and getting ready for bed.." +pnpm --filter=@lifetracker/cli run run categories create --parent 10 106 "Packing & Cleaning" "Packing for a trip and cleaning before or after a trip." +pnpm --filter=@lifetracker/cli run run categories create --parent 10 107 "Medical / Health" "A doctor, dentist, hospital visit, or appointment of some kind." +pnpm --filter=@lifetracker/cli run run categories create --parent 10 108 "Grooming / Massage" "Taking care of myself in a more aesthetic or relaxing way." \ No newline at end of file diff --git a/scripts/create_colors.sh b/scripts/create_colors.sh new file mode 100644 index 0000000..7aeaa51 --- /dev/null +++ b/scripts/create_colors.sh @@ -0,0 +1,11 @@ +pnpm --filter=@lifetracker/cli run run colors create Black "#273036" +pnpm --filter=@lifetracker/cli run run colors create Blue "#00A9B3" +pnpm --filter=@lifetracker/cli run run colors create Lime "#BFFF55" +pnpm --filter=@lifetracker/cli run run colors create Green "#189749" +pnpm --filter=@lifetracker/cli run run colors create Pink "#FF65AE" +pnpm --filter=@lifetracker/cli run run colors create Purple "#5B3AB1" +pnpm --filter=@lifetracker/cli run run colors create Orange "#FF6D01" +pnpm --filter=@lifetracker/cli run run colors create Yellow "#FFF336" +pnpm --filter=@lifetracker/cli run run colors create Teal "#005744" +pnpm --filter=@lifetracker/cli run run colors create Crimson "#C71634" +pnpm --filter=@lifetracker/cli run run colors create Red "#FF2816" \ No newline at end of file