From 7898df6162c7cf42d7467cec045163c05e8af482 Mon Sep 17 00:00:00 2001
From: Jim Hodapp <james.hodapp@gmail.com>
Date: Sat, 12 Oct 2024 17:06:49 -0500
Subject: [PATCH 01/14] Simple initial TipTap editor instance wrapped as the
 CoachingNotes component

---
 .vscode/settings.json                         |   3 +
 package-lock.json                             | 854 +++++++++++++++++-
 package.json                                  |  11 +
 src/app/coaching-sessions/[id]/page.tsx       | 145 ++-
 src/app/login/page.tsx                        |   4 +-
 .../ui/coaching-sessions/coaching-notes.tsx   |  64 ++
 .../ui/coaching-sessions/tiptap-editor.tsx    | 191 ++++
 src/lib/api/notes.ts                          | 321 +++----
 src/styles/styles.scss                        |  95 ++
 9 files changed, 1435 insertions(+), 253 deletions(-)
 create mode 100644 src/components/ui/coaching-sessions/coaching-notes.tsx
 create mode 100644 src/components/ui/coaching-sessions/tiptap-editor.tsx
 create mode 100644 src/styles/styles.scss

diff --git a/.vscode/settings.json b/.vscode/settings.json
index 843828d..31cb34b 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -14,4 +14,7 @@
     "[html]": {
         "editor.formatOnSave": true
     },
+    "tailwindCSS.experimental.classRegex": [
+        "class:\\s*?[\"'`]([^\"'`]*).*?,"
+    ]
 }
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index d7d260c..e0b05d1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -28,6 +28,16 @@
         "@radix-ui/react-tabs": "^1.0.4",
         "@radix-ui/react-toast": "^1.1.5",
         "@radix-ui/react-tooltip": "^1.0.7",
+        "@tailwindcss/typography": "^0.5.15",
+        "@tiptap/extension-bubble-menu": "^2.8.0",
+        "@tiptap/extension-bullet-list": "^2.8.0",
+        "@tiptap/extension-heading": "^2.8.0",
+        "@tiptap/extension-list-item": "^2.8.0",
+        "@tiptap/extension-ordered-list": "^2.8.0",
+        "@tiptap/extension-underline": "^2.8.0",
+        "@tiptap/pm": "^2.8.0",
+        "@tiptap/react": "^2.8.0",
+        "@tiptap/starter-kit": "^2.8.0",
         "axios": "^1.6.7",
         "class-variance-authority": "^0.7.0",
         "clsx": "^2.1.0",
@@ -38,6 +48,7 @@
         "react": "^18",
         "react-day-picker": "^8.10.0",
         "react-dom": "^18",
+        "sass": "^1.79.4",
         "tailwind-merge": "^2.2.0",
         "tailwindcss-animate": "^1.0.7",
         "ts-luxon": "^4.5.2",
@@ -483,6 +494,16 @@
         "node": ">=14"
       }
     },
+    "node_modules/@popperjs/core": {
+      "version": "2.11.8",
+      "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
+      "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+      "license": "MIT",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/popperjs"
+      }
+    },
     "node_modules/@radix-ui/number": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz",
@@ -1602,6 +1623,12 @@
         "@babel/runtime": "^7.13.10"
       }
     },
+    "node_modules/@remirror/core-constants": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz",
+      "integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==",
+      "license": "MIT"
+    },
     "node_modules/@rushstack/eslint-patch": {
       "version": "1.10.2",
       "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz",
@@ -1622,12 +1649,473 @@
         "tslib": "^2.4.0"
       }
     },
+    "node_modules/@tailwindcss/typography": {
+      "version": "0.5.15",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.15.tgz",
+      "integrity": "sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA==",
+      "license": "MIT",
+      "dependencies": {
+        "lodash.castarray": "^4.4.0",
+        "lodash.isplainobject": "^4.0.6",
+        "lodash.merge": "^4.6.2",
+        "postcss-selector-parser": "6.0.10"
+      },
+      "peerDependencies": {
+        "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20"
+      }
+    },
+    "node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": {
+      "version": "6.0.10",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
+      "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
+      "license": "MIT",
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@tiptap/core": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.8.0.tgz",
+      "integrity": "sha512-xsqDI4BNzYRWRtBq7+/38ThhqEr7uG9Njip1x+9/wgR3vWPBFnBkYJTz6jSxS35NRE6BSnERm4/B/vrLuY1Hdw==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/pm": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-blockquote": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.8.0.tgz",
+      "integrity": "sha512-m3CKrOIvV7fY1Ak2gYf5LkKiz6AHxHpg6wxfVaJvdBqXgLyVtHo552N+A4oSHOSRbB4AG9EBQ2NeBM8cdEQ4MA==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-bold": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.8.0.tgz",
+      "integrity": "sha512-U1YkZBxDkSLNvPNiqxB5g42IeJHr27C7zDb/yGQN2xL4UBeg4O9xVhCFfe32f6tLwivSL0dar4ScElpaCJuqow==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-bubble-menu": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.8.0.tgz",
+      "integrity": "sha512-swg+myJPN60LduQvLMF4hVBqP5LOIN01INZBzBI8egz8QufqtSyRCgXl7Xcma0RT5xIXnZSG9XOqNFf2rtkjKA==",
+      "license": "MIT",
+      "dependencies": {
+        "tippy.js": "^6.3.7"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/pm": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-bullet-list": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.8.0.tgz",
+      "integrity": "sha512-H4O2X0ozbc/ce9/XF1H98sqWVUdtt7jzy7hMBunwmY8ZxI4dHtcRkeg81CZbpKTqOqRrMCLWjE3M2tgiDXrDkA==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/extension-list-item": "^2.7.0",
+        "@tiptap/extension-text-style": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-code": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.8.0.tgz",
+      "integrity": "sha512-VSFn3sFF6qPpOGkXFhik8oYRH5iByVJpFEFd/duIEftmS0MdPzkbSItOpN3mc9xsJ5dCX80LYaResSj5hr5zkA==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-code-block": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.8.0.tgz",
+      "integrity": "sha512-POuA5Igx+Dto0DTazoBFAQTj/M/FCdkqRVD9Uhsxhv49swPyANTJRr05vgbgtHB+NDDsZfCawVh7pI0IAD/O0w==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/pm": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-document": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.8.0.tgz",
+      "integrity": "sha512-mp7Isx1sVc/ifeW4uW/PexGQ9exN3NRUOebSpnLfqXeWYk4y1RS1PA/3+IHkOPVetbnapgPjFx/DswlCP3XLjA==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-dropcursor": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.8.0.tgz",
+      "integrity": "sha512-rAFvx44YuT6dtS1c+ALw0ROAGI16l5L1HxquL4hR1gtxDcTieST5xhw5bkshXlmrlfotZXPrhokzqA7qjhZtJw==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/pm": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-floating-menu": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.8.0.tgz",
+      "integrity": "sha512-H4QT61CrkLqisnGGC7zgiYmsl2jXPHl89yQCbdlkQN7aw11H7PltcJS2PJguL0OrRVJS/Mv/VTTUiMslmsEV5g==",
+      "license": "MIT",
+      "dependencies": {
+        "tippy.js": "^6.3.7"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/pm": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-gapcursor": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.8.0.tgz",
+      "integrity": "sha512-Be1LWCmvteQInOnNVN+HTqc1XWsj1bCl+Q7et8qqNjtGtTaCbdCp8ppcH1SKJxNTM/RLUtPyJ8FDgOTj51ixCA==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/pm": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-hard-break": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.8.0.tgz",
+      "integrity": "sha512-vqiIfviNiCmy/pJTHuDSCAGL2O4QDEdDmAvGJu8oRmElUrnlg8DbJUfKvn6DWQHNSQwRb+LDrwWlzAYj1K9u6A==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-heading": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.8.0.tgz",
+      "integrity": "sha512-4inWgrTPiqlivPmEHFOM5ck2UsmOsbKKPtqga6bALvWPmCv24S6/EBwFp8Jz4YABabXDnkviihmGu0LpP9D69w==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-history": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.8.0.tgz",
+      "integrity": "sha512-u5YS0J5Egsxt8TUWMMAC3QhPZaak+IzQeyHch4gtqxftx96tprItY7AD/A3pGDF2uCSnN+SZrk6yVexm6EncDw==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/pm": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-horizontal-rule": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.8.0.tgz",
+      "integrity": "sha512-Sn/MI8WVFBoIYSIHA9NJryJIyCEzZdRysau8pC5TFnfifre0QV1ksPz2bgF+DyCD69ozQiRdBBHDEwKe47ZbfQ==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/pm": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-italic": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.8.0.tgz",
+      "integrity": "sha512-PwwSE2LTYiHI47NJnsfhBmPiLE8IXZYqaSoNPU6flPrk1KxEzqvRI1joKZBmD9wuqzmHJ93VFIeZcC+kfwi8ZA==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-list-item": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.8.0.tgz",
+      "integrity": "sha512-o7OGymGxB0B9x3x2prp3KBDYFuBYGc5sW69O672jk8G52DqhzzndgPnkk0qUn8nXAUKuDGbJmpmHVA2kagqnRg==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-ordered-list": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.8.0.tgz",
+      "integrity": "sha512-sCvNbcTS1+5QTTXwUPFa10vf5I1pr8sGcOTIh0G+a5ZkS5+6FxT12k7VLzPt39QyNbOi+77U2o4Xr4XyaEkfSg==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/extension-list-item": "^2.7.0",
+        "@tiptap/extension-text-style": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-paragraph": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.8.0.tgz",
+      "integrity": "sha512-XgxxNNbuBF48rAGwv7/s6as92/xjm/lTZIGTq9aG13ClUKFtgdel7C33SpUCcxg3cO2WkEyllXVyKUiauFZw/A==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-strike": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.8.0.tgz",
+      "integrity": "sha512-ezkDiXxQ3ME/dDMMM7tAMkKRi6UWw7tIu+Mx7Os0z8HCGpVBk1gFhLlhEd8I5rJaPZr4tK1wtSehMA9bscFGQw==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-text": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.8.0.tgz",
+      "integrity": "sha512-EDAdFFzWOvQfVy7j3qkKhBpOeE5thkJaBemSWfXI93/gMVc0ZCdLi24mDvNNgUHlT+RjlIoQq908jZaaxLKN2A==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-text-style": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-2.8.0.tgz",
+      "integrity": "sha512-jJp0vcZ2Ty7RvIL0VU6dm1y+fTfXq1lN2GwtYzYM0ueFuESa+Qo8ticYOImyWZ3wGJGVrjn7OV9r0ReW0/NYkQ==",
+      "license": "MIT",
+      "peer": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-underline": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-2.8.0.tgz",
+      "integrity": "sha512-1ouuHwZJphT8OosAmp6x8e+Wly3cUd1pNWBiOutJX+6QRGBXJnIKFCzn8YOTlWhg1YQigisG7dNF3YdlyuRNHw==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/pm": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.8.0.tgz",
+      "integrity": "sha512-eMGpRooUMvKz/vOpnKKppApMSoNM325HxTdAJvTlVAmuHp5bOY5kyY1kfUlePRiVx1t1UlFcXs3kecFwkkBD3Q==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-changeset": "^2.2.1",
+        "prosemirror-collab": "^1.3.1",
+        "prosemirror-commands": "^1.6.0",
+        "prosemirror-dropcursor": "^1.8.1",
+        "prosemirror-gapcursor": "^1.3.2",
+        "prosemirror-history": "^1.4.1",
+        "prosemirror-inputrules": "^1.4.0",
+        "prosemirror-keymap": "^1.2.2",
+        "prosemirror-markdown": "^1.13.0",
+        "prosemirror-menu": "^1.2.4",
+        "prosemirror-model": "^1.22.3",
+        "prosemirror-schema-basic": "^1.2.3",
+        "prosemirror-schema-list": "^1.4.1",
+        "prosemirror-state": "^1.4.3",
+        "prosemirror-tables": "^1.4.0",
+        "prosemirror-trailing-node": "^3.0.0",
+        "prosemirror-transform": "^1.10.0",
+        "prosemirror-view": "^1.33.10"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      }
+    },
+    "node_modules/@tiptap/react": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-2.8.0.tgz",
+      "integrity": "sha512-o/aSCjO5Nu4MsNpTF+N1SzYzVQvvBiclmTOZX2E6usZ8jre5zmKfXHDSZnjGSRTK6z6kw5KW8wpjRQha03f9mg==",
+      "license": "MIT",
+      "dependencies": {
+        "@tiptap/extension-bubble-menu": "^2.8.0",
+        "@tiptap/extension-floating-menu": "^2.8.0",
+        "@types/use-sync-external-store": "^0.0.6",
+        "fast-deep-equal": "^3",
+        "use-sync-external-store": "^1.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/pm": "^2.7.0",
+        "react": "^17.0.0 || ^18.0.0",
+        "react-dom": "^17.0.0 || ^18.0.0"
+      }
+    },
+    "node_modules/@tiptap/react/node_modules/use-sync-external-store": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz",
+      "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==",
+      "license": "MIT",
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+      }
+    },
+    "node_modules/@tiptap/starter-kit": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-2.8.0.tgz",
+      "integrity": "sha512-r7UwaTrECkQoheWVZKFDqtL5tBx07x7IFT+prfgnsVlYFutGWskVVqzCDvD3BDmrg5PzeCWYZrQGlPaLib7tjg==",
+      "license": "MIT",
+      "dependencies": {
+        "@tiptap/core": "^2.8.0",
+        "@tiptap/extension-blockquote": "^2.8.0",
+        "@tiptap/extension-bold": "^2.8.0",
+        "@tiptap/extension-bullet-list": "^2.8.0",
+        "@tiptap/extension-code": "^2.8.0",
+        "@tiptap/extension-code-block": "^2.8.0",
+        "@tiptap/extension-document": "^2.8.0",
+        "@tiptap/extension-dropcursor": "^2.8.0",
+        "@tiptap/extension-gapcursor": "^2.8.0",
+        "@tiptap/extension-hard-break": "^2.8.0",
+        "@tiptap/extension-heading": "^2.8.0",
+        "@tiptap/extension-history": "^2.8.0",
+        "@tiptap/extension-horizontal-rule": "^2.8.0",
+        "@tiptap/extension-italic": "^2.8.0",
+        "@tiptap/extension-list-item": "^2.8.0",
+        "@tiptap/extension-ordered-list": "^2.8.0",
+        "@tiptap/extension-paragraph": "^2.8.0",
+        "@tiptap/extension-strike": "^2.8.0",
+        "@tiptap/extension-text": "^2.8.0",
+        "@tiptap/pm": "^2.8.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      }
+    },
     "node_modules/@types/json5": {
       "version": "0.0.29",
       "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
       "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
       "dev": true
     },
+    "node_modules/@types/linkify-it": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
+      "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
+      "license": "MIT"
+    },
+    "node_modules/@types/markdown-it": {
+      "version": "14.1.2",
+      "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
+      "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/linkify-it": "^5",
+        "@types/mdurl": "^2"
+      }
+    },
+    "node_modules/@types/mdurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
+      "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
+      "license": "MIT"
+    },
     "node_modules/@types/node": {
       "version": "20.12.7",
       "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
@@ -1662,6 +2150,12 @@
         "@types/react": "*"
       }
     },
+    "node_modules/@types/use-sync-external-store": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
+      "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
+      "license": "MIT"
+    },
     "node_modules/@typescript-eslint/parser": {
       "version": "6.21.0",
       "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
@@ -1879,8 +2373,7 @@
     "node_modules/argparse": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-      "dev": true
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
     },
     "node_modules/aria-hidden": {
       "version": "1.2.4",
@@ -2664,6 +3157,12 @@
       "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
       "dev": true
     },
+    "node_modules/crelt": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
+      "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
+      "license": "MIT"
+    },
     "node_modules/cross-spawn": {
       "version": "7.0.3",
       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -2904,6 +3403,18 @@
         "node": ">=10.13.0"
       }
     },
+    "node_modules/entities": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+      "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
     "node_modules/es-abstract": {
       "version": "1.23.3",
       "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
@@ -3075,7 +3586,6 @@
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
       "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
-      "dev": true,
       "engines": {
         "node": ">=10"
       },
@@ -3498,8 +4008,7 @@
     "node_modules/fast-deep-equal": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
-      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
-      "dev": true
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
     },
     "node_modules/fast-glob": {
       "version": "3.3.2",
@@ -4001,6 +4510,12 @@
         "node": ">= 4"
       }
     },
+    "node_modules/immutable": {
+      "version": "4.3.7",
+      "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz",
+      "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==",
+      "license": "MIT"
+    },
     "node_modules/import-fresh": {
       "version": "3.3.0",
       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -4589,6 +5104,15 @@
       "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
       "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
     },
+    "node_modules/linkify-it": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
+      "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
+      "license": "MIT",
+      "dependencies": {
+        "uc.micro": "^2.0.0"
+      }
+    },
     "node_modules/locate-path": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -4604,11 +5128,22 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/lodash.castarray": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
+      "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==",
+      "license": "MIT"
+    },
+    "node_modules/lodash.isplainobject": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+      "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
+      "license": "MIT"
+    },
     "node_modules/lodash.merge": {
       "version": "4.6.2",
       "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
-      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
-      "dev": true
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
     },
     "node_modules/loose-envify": {
       "version": "1.4.0",
@@ -4637,6 +5172,29 @@
         "react": "^16.5.1 || ^17.0.0 || ^18.0.0"
       }
     },
+    "node_modules/markdown-it": {
+      "version": "14.1.0",
+      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
+      "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^2.0.1",
+        "entities": "^4.4.0",
+        "linkify-it": "^5.0.0",
+        "mdurl": "^2.0.0",
+        "punycode.js": "^2.3.1",
+        "uc.micro": "^2.1.0"
+      },
+      "bin": {
+        "markdown-it": "bin/markdown-it.mjs"
+      }
+    },
+    "node_modules/mdurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
+      "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
+      "license": "MIT"
+    },
     "node_modules/merge2": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -5011,6 +5569,12 @@
         "node": ">= 0.8.0"
       }
     },
+    "node_modules/orderedmap": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz",
+      "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==",
+      "license": "MIT"
+    },
     "node_modules/p-limit": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -5310,6 +5874,201 @@
         "react-is": "^16.13.1"
       }
     },
+    "node_modules/prosemirror-changeset": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.2.1.tgz",
+      "integrity": "sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-transform": "^1.0.0"
+      }
+    },
+    "node_modules/prosemirror-collab": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz",
+      "integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-state": "^1.0.0"
+      }
+    },
+    "node_modules/prosemirror-commands": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.6.0.tgz",
+      "integrity": "sha512-xn1U/g36OqXn2tn5nGmvnnimAj/g1pUx2ypJJIe8WkVX83WyJVC5LTARaxZa2AtQRwntu9Jc5zXs9gL9svp/mg==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-model": "^1.0.0",
+        "prosemirror-state": "^1.0.0",
+        "prosemirror-transform": "^1.0.0"
+      }
+    },
+    "node_modules/prosemirror-dropcursor": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.1.tgz",
+      "integrity": "sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-state": "^1.0.0",
+        "prosemirror-transform": "^1.1.0",
+        "prosemirror-view": "^1.1.0"
+      }
+    },
+    "node_modules/prosemirror-gapcursor": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.3.2.tgz",
+      "integrity": "sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-keymap": "^1.0.0",
+        "prosemirror-model": "^1.0.0",
+        "prosemirror-state": "^1.0.0",
+        "prosemirror-view": "^1.0.0"
+      }
+    },
+    "node_modules/prosemirror-history": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.4.1.tgz",
+      "integrity": "sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-state": "^1.2.2",
+        "prosemirror-transform": "^1.0.0",
+        "prosemirror-view": "^1.31.0",
+        "rope-sequence": "^1.3.0"
+      }
+    },
+    "node_modules/prosemirror-inputrules": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.4.0.tgz",
+      "integrity": "sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-state": "^1.0.0",
+        "prosemirror-transform": "^1.0.0"
+      }
+    },
+    "node_modules/prosemirror-keymap": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.2.tgz",
+      "integrity": "sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-state": "^1.0.0",
+        "w3c-keyname": "^2.2.0"
+      }
+    },
+    "node_modules/prosemirror-markdown": {
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.1.tgz",
+      "integrity": "sha512-Sl+oMfMtAjWtlcZoj/5L/Q39MpEnVZ840Xo330WJWUvgyhNmLBLN7MsHn07s53nG/KImevWHSE6fEj4q/GihHw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/markdown-it": "^14.0.0",
+        "markdown-it": "^14.0.0",
+        "prosemirror-model": "^1.20.0"
+      }
+    },
+    "node_modules/prosemirror-menu": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.2.4.tgz",
+      "integrity": "sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==",
+      "license": "MIT",
+      "dependencies": {
+        "crelt": "^1.0.0",
+        "prosemirror-commands": "^1.0.0",
+        "prosemirror-history": "^1.0.0",
+        "prosemirror-state": "^1.0.0"
+      }
+    },
+    "node_modules/prosemirror-model": {
+      "version": "1.23.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.23.0.tgz",
+      "integrity": "sha512-Q/fgsgl/dlOAW9ILu4OOhYWQbc7TQd4BwKH/RwmUjyVf8682Be4zj3rOYdLnYEcGzyg8LL9Q5IWYKD8tdToreQ==",
+      "license": "MIT",
+      "dependencies": {
+        "orderedmap": "^2.0.0"
+      }
+    },
+    "node_modules/prosemirror-schema-basic": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.3.tgz",
+      "integrity": "sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-model": "^1.19.0"
+      }
+    },
+    "node_modules/prosemirror-schema-list": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.4.1.tgz",
+      "integrity": "sha512-jbDyaP/6AFfDfu70VzySsD75Om2t3sXTOdl5+31Wlxlg62td1haUpty/ybajSfJ1pkGadlOfwQq9kgW5IMo1Rg==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-model": "^1.0.0",
+        "prosemirror-state": "^1.0.0",
+        "prosemirror-transform": "^1.7.3"
+      }
+    },
+    "node_modules/prosemirror-state": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.3.tgz",
+      "integrity": "sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-model": "^1.0.0",
+        "prosemirror-transform": "^1.0.0",
+        "prosemirror-view": "^1.27.0"
+      }
+    },
+    "node_modules/prosemirror-tables": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.5.0.tgz",
+      "integrity": "sha512-VMx4zlYWm7aBlZ5xtfJHpqa3Xgu3b7srV54fXYnXgsAcIGRqKSrhiK3f89omzzgaAgAtDOV4ImXnLKhVfheVNQ==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-keymap": "^1.1.2",
+        "prosemirror-model": "^1.8.1",
+        "prosemirror-state": "^1.3.1",
+        "prosemirror-transform": "^1.2.1",
+        "prosemirror-view": "^1.13.3"
+      }
+    },
+    "node_modules/prosemirror-trailing-node": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz",
+      "integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@remirror/core-constants": "3.0.0",
+        "escape-string-regexp": "^4.0.0"
+      },
+      "peerDependencies": {
+        "prosemirror-model": "^1.22.1",
+        "prosemirror-state": "^1.4.2",
+        "prosemirror-view": "^1.33.8"
+      }
+    },
+    "node_modules/prosemirror-transform": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.10.1.tgz",
+      "integrity": "sha512-jANxn50pNsBT7042mM4pxKpGyzgJWen/GrfCEQOPtHa5gLrQ2+0OgDtuQu2noG1X0+2cQ5uPsWqCRy7w7J+obw==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-model": "^1.21.0"
+      }
+    },
+    "node_modules/prosemirror-view": {
+      "version": "1.34.3",
+      "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.34.3.tgz",
+      "integrity": "sha512-mKZ54PrX19sSaQye+sef+YjBbNu2voNwLS1ivb6aD2IRmxRGW64HU9B644+7OfJStGLyxvOreKqEgfvXa91WIA==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-model": "^1.20.0",
+        "prosemirror-state": "^1.0.0",
+        "prosemirror-transform": "^1.1.0"
+      }
+    },
     "node_modules/proxy-from-env": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -5324,6 +6083,15 @@
         "node": ">=6"
       }
     },
+    "node_modules/punycode.js": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
+      "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/queue-microtask": {
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -5593,6 +6361,12 @@
         "url": "https://github.com/sponsors/isaacs"
       }
     },
+    "node_modules/rope-sequence": {
+      "version": "1.3.4",
+      "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz",
+      "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==",
+      "license": "MIT"
+    },
     "node_modules/run-parallel": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -5650,6 +6424,51 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/sass": {
+      "version": "1.79.4",
+      "resolved": "https://registry.npmjs.org/sass/-/sass-1.79.4.tgz",
+      "integrity": "sha512-K0QDSNPXgyqO4GZq2HO5Q70TLxTH6cIT59RdoCHMivrC8rqzaTw5ab9prjz9KUN1El4FLXrBXJhik61JR4HcGg==",
+      "license": "MIT",
+      "dependencies": {
+        "chokidar": "^4.0.0",
+        "immutable": "^4.0.0",
+        "source-map-js": ">=0.6.2 <2.0.0"
+      },
+      "bin": {
+        "sass": "sass.js"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/sass/node_modules/chokidar": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz",
+      "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==",
+      "license": "MIT",
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/sass/node_modules/readdirp": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz",
+      "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
     "node_modules/scheduler": {
       "version": "0.23.0",
       "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
@@ -6125,6 +6944,15 @@
         "node": ">=0.8"
       }
     },
+    "node_modules/tippy.js": {
+      "version": "6.3.7",
+      "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
+      "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@popperjs/core": "^2.9.0"
+      }
+    },
     "node_modules/to-regex-range": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -6288,6 +7116,12 @@
         "node": ">=14.17"
       }
     },
+    "node_modules/uc.micro": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
+      "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
+      "license": "MIT"
+    },
     "node_modules/unbox-primitive": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
@@ -6402,6 +7236,12 @@
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
       "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
     },
+    "node_modules/w3c-keyname": {
+      "version": "2.2.8",
+      "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
+      "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
+      "license": "MIT"
+    },
     "node_modules/which": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/package.json b/package.json
index c539ea3..7a3e3e3 100644
--- a/package.json
+++ b/package.json
@@ -29,6 +29,16 @@
     "@radix-ui/react-tabs": "^1.0.4",
     "@radix-ui/react-toast": "^1.1.5",
     "@radix-ui/react-tooltip": "^1.0.7",
+    "@tailwindcss/typography": "^0.5.15",
+    "@tiptap/extension-bubble-menu": "^2.8.0",
+    "@tiptap/extension-bullet-list": "^2.8.0",
+    "@tiptap/extension-heading": "^2.8.0",
+    "@tiptap/extension-list-item": "^2.8.0",
+    "@tiptap/extension-ordered-list": "^2.8.0",
+    "@tiptap/extension-underline": "^2.8.0",
+    "@tiptap/pm": "^2.8.0",
+    "@tiptap/react": "^2.8.0",
+    "@tiptap/starter-kit": "^2.8.0",
     "axios": "^1.6.7",
     "class-variance-authority": "^0.7.0",
     "clsx": "^2.1.0",
@@ -39,6 +49,7 @@
     "react": "^18",
     "react-day-picker": "^8.10.0",
     "react-dom": "^18",
+    "sass": "^1.79.4",
     "tailwind-merge": "^2.2.0",
     "tailwindcss-animate": "^1.0.7",
     "ts-luxon": "^4.5.2",
diff --git a/src/app/coaching-sessions/[id]/page.tsx b/src/app/coaching-sessions/[id]/page.tsx
index 3fdfaf5..d84ac2a 100644
--- a/src/app/coaching-sessions/[id]/page.tsx
+++ b/src/app/coaching-sessions/[id]/page.tsx
@@ -12,19 +12,18 @@ import { PresetActions } from "@/components/ui/preset-actions";
 import { PresetSelector } from "@/components/ui/preset-selector";
 import { current, future, past } from "@/data/presets";
 import { useAppStateStore } from "@/lib/providers/app-state-store-provider";
-import { useEffect, useState } from "react";
+import { useEffect, useRef, useState } from "react";
 import {
   createNote,
   fetchNotesByCoachingSessionId,
   updateNote,
 } from "@/lib/api/notes";
-import { noteToString } from "@/types/note";
+import { defaultNote, Note, noteToString } from "@/types/note";
 import { useAuthStore } from "@/lib/providers/auth-store-provider";
 
 import { siteConfig } from "@/site.config";
 import { CoachingSessionTitle } from "@/components/ui/coaching-sessions/coaching-session-title";
 import { OverarchingGoalContainer } from "@/components/ui/coaching-sessions/overarching-goal-container";
-import { Id } from "@/types/general";
 import {
   HoverCard,
   HoverCardContent,
@@ -33,6 +32,10 @@ import {
 import { Label } from "@/components/ui/label";
 import { Button } from "@/components/ui/button";
 import { LockClosedIcon, SymbolIcon } from "@radix-ui/react-icons";
+import {
+  CoachingNotes,
+  EditorRef,
+} from "@/components/ui/coaching-sessions/coaching-notes";
 
 // export const metadata: Metadata = {
 //   title: "Coaching Session",
@@ -40,13 +43,12 @@ import { LockClosedIcon, SymbolIcon } from "@radix-ui/react-icons";
 // };
 
 export default function CoachingSessionsPage() {
-  const [noteId, setNoteId] = useState<Id>("");
-  const [note, setNote] = useState<string>("");
+  const [note, setNote] = useState<Note>(defaultNote());
   const [syncStatus, setSyncStatus] = useState<string>("");
   const { userId } = useAuthStore((state) => ({ userId: state.userId }));
-  const { coachingSession, coachingRelationship } = useAppStateStore(
-    (state) => state
-  );
+  const { coachingSession } = useAppStateStore((state) => state);
+  const [isLoading, setIsLoading] = useState(false);
+  const editorRef = useRef<EditorRef>(null);
 
   async function fetchNote() {
     if (!coachingSession.id) {
@@ -55,48 +57,79 @@ export default function CoachingSessionsPage() {
       );
       return;
     }
+    if (isLoading) {
+      console.debug(
+        "Not issuing a new Note fetch because a previous fetch is still in progress."
+      );
+    }
+
+    setIsLoading(true);
 
     await fetchNotesByCoachingSessionId(coachingSession.id)
       .then((notes) => {
         const note = notes[0];
         if (notes.length > 0) {
-          console.trace("note: " + noteToString(note));
-          setNoteId(note.id);
-          setNote(note.body);
+          console.trace("Fetched note: " + noteToString(note));
+          setEditorContent(note.body);
+          setNote(note);
           setSyncStatus("Notes refreshed");
+          setEditorFocussed();
         } else {
-          console.trace("No Notes associated with this coachingSession.id");
+          console.trace(
+            "No Notes associated with this coachingSession.id: " +
+              coachingSession.id
+          );
         }
       })
       .catch((err) => {
         console.error(
-          "Failed to fetch Note for current coaching session: " + err
+          "Failed to fetch Note for current coaching session id: " +
+            coachingSession.id +
+            ". Error: " +
+            err
         );
       });
+
+    setIsLoading(false);
   }
 
   useEffect(() => {
     fetchNote();
-  }, [coachingSession.id, noteId]);
+  }, []);
 
-  const handleInputChange = (value: string) => {
-    setNote(value);
+  const setEditorContent = (content: string) => {
+    editorRef.current?.setContent(`${content}`);
+  };
 
-    if (noteId && coachingSession.id && userId) {
-      updateNote(noteId, coachingSession.id, userId, value)
-        .then((note) => {
-          console.trace("Updated Note: " + noteToString(note));
+  const setEditorFocussed = () => {
+    editorRef.current?.setFocussed();
+  };
+
+  const handleOnChange = (value: string) => {
+    console.debug("isLoading (before update/create): " + isLoading);
+    console.debug(
+      "coachingSession.id (before update/create): " + coachingSession.id
+    );
+    console.debug("userId (before update/create): " + userId);
+    console.debug("value (before update/create): " + value);
+    console.debug("--------------------------------");
+
+    if (!isLoading && note.id && coachingSession.id && userId) {
+      updateNote(note.id, coachingSession.id, userId, value)
+        .then((updatedNote) => {
+          setNote(updatedNote);
+          console.trace("Updated Note: " + noteToString(updatedNote));
           setSyncStatus("All changes saved");
         })
         .catch((err) => {
           setSyncStatus("Failed to save changes");
           console.error("Failed to update Note: " + err);
         });
-    } else if (!noteId && coachingSession.id && userId) {
+    } else if (!isLoading && !note.id && coachingSession.id && userId) {
       createNote(coachingSession.id, userId, value)
-        .then((note) => {
-          console.trace("Newly created Note: " + noteToString(note));
-          setNoteId(note.id);
+        .then((createdNote) => {
+          setNote(createdNote);
+          console.trace("Newly created Note: " + noteToString(createdNote));
           setSyncStatus("All changes saved");
         })
         .catch((err) => {
@@ -145,7 +178,7 @@ export default function CoachingSessionsPage() {
         <div className="grid h-full items-stretch gap-6 md:grid-cols-[1fr_200px]">
           <div className="flex-col space-y-4 sm:flex md:order-1">
             <Tabs defaultValue="notes" className="flex-1">
-              <TabsList className="grid flex w-128 grid-cols-2 justify-start">
+              <TabsList className="flex w-128 grid-cols-2 justify-start">
                 <TabsTrigger value="notes">Notes</TabsTrigger>
                 <TabsTrigger value="console">Console</TabsTrigger>
                 <TabsTrigger value="coachs_notes" className="hidden">
@@ -158,8 +191,9 @@ export default function CoachingSessionsPage() {
               <TabsContent value="notes">
                 <div className="flex h-full flex-col space-y-4">
                   <CoachingNotes
-                    value={note}
-                    onChange={handleInputChange}
+                    ref={editorRef}
+                    value={note.body}
+                    onChange={handleOnChange}
                     onKeyDown={handleKeyDown}
                   ></CoachingNotes>
                   <p className="text-sm text-muted-foreground">{syncStatus}</p>
@@ -210,60 +244,3 @@ export default function CoachingSessionsPage() {
     </>
   );
 }
-
-// A debounced input CoachingNotes textarea component
-// TODO: move this into the components dir
-const CoachingNotes: React.FC<{
-  value: string;
-  onChange: (value: string) => void;
-  onKeyDown: () => void;
-}> = ({ value, onChange, onKeyDown }) => {
-  const WAIT_INTERVAL = 1000;
-  const [timer, setTimer] = useState<number | undefined>(undefined);
-  const [note, setNote] = useState<string>(value);
-
-  // Make sure the internal value prop updates when the component interface's
-  // value prop changes.
-  useEffect(() => {
-    setNote(value);
-  }, [value]);
-
-  const handleSessionNoteChange = (
-    e: React.ChangeEvent<HTMLTextAreaElement>
-  ) => {
-    const newValue = e.target.value;
-    setNote(newValue);
-
-    if (timer) {
-      clearTimeout(timer);
-    }
-
-    const newTimer = window.setTimeout(() => {
-      onChange(newValue);
-    }, WAIT_INTERVAL);
-
-    setTimer(newTimer);
-  };
-
-  const handleOnKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
-    onKeyDown();
-  };
-
-  useEffect(() => {
-    return () => {
-      if (timer) {
-        clearTimeout(timer);
-      }
-    };
-  }, [timer]);
-
-  return (
-    <Textarea
-      placeholder="Session notes"
-      value={note}
-      className="p-4 min-h-[400px] md:min-h-[630px] lg:min-h-[630px]"
-      onChange={handleSessionNoteChange}
-      onKeyDown={handleOnKeyDown}
-    />
-  );
-};
diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx
index 6c9a881..38376da 100644
--- a/src/app/login/page.tsx
+++ b/src/app/login/page.tsx
@@ -8,8 +8,8 @@ import { UserAuthForm } from "@/components/user-auth-form";
 import { siteConfig } from "@/site.config";
 
 export const metadata: Metadata = {
-  title: "Authentication",
-  description: "Authentication forms built using the components.",
+  title: "Welcome to Refactor Coaching",
+  description: siteConfig.description,
 };
 
 export default function AuthenticationPage() {
diff --git a/src/components/ui/coaching-sessions/coaching-notes.tsx b/src/components/ui/coaching-sessions/coaching-notes.tsx
new file mode 100644
index 0000000..0cc1d2f
--- /dev/null
+++ b/src/components/ui/coaching-sessions/coaching-notes.tsx
@@ -0,0 +1,64 @@
+"use client";
+
+import { forwardRef, useCallback, useEffect, useRef, useState } from "react";
+import { TipTapEditor } from "@/components/ui/coaching-sessions/tiptap-editor";
+
+export interface EditorRef {
+  setContent: (content: string) => void;
+  setFocussed: () => void;
+}
+
+interface CoachingNotesProps {
+  value: string;
+  onChange: (content: string) => void;
+  onKeyDown: () => void;
+}
+
+const CoachingNotes = forwardRef<EditorRef, CoachingNotesProps>(
+  ({ value, onChange, onKeyDown }, ref) => {
+    const WAIT_INTERVAL = 1000;
+    const timerRef = useRef<number | undefined>(undefined);
+    const [note, setNote] = useState<string>(value);
+
+    useEffect(() => {
+      setNote(value);
+    }, [value]);
+
+    const handleSessionNoteChange = useCallback(
+      (newValue: string) => {
+        onKeyDown();
+        setNote(newValue);
+
+        if (timerRef.current) {
+          clearTimeout(timerRef.current);
+        }
+
+        timerRef.current = window.setTimeout(() => {
+          console.debug(
+            "Calling onChange() from CoachingNotes::handleSessionNoteChange() timer"
+          );
+          onChange(newValue);
+        }, WAIT_INTERVAL);
+      },
+      [onKeyDown, onChange, WAIT_INTERVAL]
+    );
+
+    useEffect(() => {
+      return () => {
+        if (timerRef.current) {
+          clearTimeout(timerRef.current);
+        }
+      };
+    }, []);
+
+    return (
+      <TipTapEditor
+        ref={ref}
+        editorContent={note}
+        onChange={handleSessionNoteChange}
+      />
+    );
+  }
+);
+
+export { CoachingNotes };
diff --git a/src/components/ui/coaching-sessions/tiptap-editor.tsx b/src/components/ui/coaching-sessions/tiptap-editor.tsx
new file mode 100644
index 0000000..81834f8
--- /dev/null
+++ b/src/components/ui/coaching-sessions/tiptap-editor.tsx
@@ -0,0 +1,191 @@
+"use client";
+
+import { useEditor, EditorContent } from "@tiptap/react";
+
+import StarterKit from "@tiptap/starter-kit";
+import BulletList from "@tiptap/extension-bullet-list";
+import ListItem from "@tiptap/extension-list-item";
+import OrderedList from "@tiptap/extension-ordered-list";
+import Underline from "@tiptap/extension-underline";
+import {
+  Bold,
+  Heading1,
+  Heading2,
+  Heading3,
+  Italic,
+  Underline as UnderlineIcon,
+  List,
+  ListOrdered,
+  Strikethrough,
+} from "lucide-react";
+import { Button } from "@/components/ui/button";
+import { forwardRef, useImperativeHandle } from "react";
+
+import "@/styles/styles.scss";
+import { EditorRef } from "./coaching-notes";
+
+interface TipTapProps {
+  editorContent: string;
+  onChange: (content: string) => void;
+}
+
+const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
+  ({ editorContent, onChange }, ref) => {
+    const editor = useEditor(
+      {
+        extensions: [StarterKit, ListItem, Underline],
+
+        autofocus: false,
+        immediatelyRender: false,
+
+        editorProps: {
+          attributes: {
+            class:
+              "shadow appearance-none min-h-[150px] border rounded w-full py-2 px-3 bg-white text-black text-sm mt-0 md:mt-3 leading-tight focus:outline-none focus:shadow-outline",
+          },
+        },
+
+        content: editorContent,
+        onUpdate: ({ editor }) => {
+          onChange(JSON.stringify(editor.getJSON()));
+        },
+      },
+      []
+    );
+
+    useImperativeHandle(ref, () => ({
+      setContent: (content: string) => {
+        editor?.commands.setContent(JSON.parse(content));
+      },
+
+      setFocussed: () => {
+        editor?.chain().focus().run();
+      },
+    }));
+
+    if (!editor) {
+      return null;
+    }
+
+    return (
+      <div className="flex flex-col justify-stretch min-h-[200px] border rounded border-b-0">
+        <div className="flex items-center gap-0 mb-0">
+          {/* Bold Button */}
+          <Button
+            variant="ghost"
+            onClick={() => editor.chain().focus().toggleBold().run()}
+            className={`p-2 rounded ${
+              editor.isActive("bold") ? "bg-gray-200" : ""
+            }`}
+            title="Bold (Ctrl+B)"
+          >
+            <Bold className="h-4 w-4" />
+          </Button>
+
+          {/* Italic Button */}
+          <Button
+            variant="ghost"
+            onClick={() => editor.chain().focus().toggleItalic().run()}
+            className={`p-2 rounded ${
+              editor.isActive("italic") ? "bg-gray-200" : ""
+            }`}
+            title="Italic (Ctrl+I)"
+          >
+            <Italic className="h-4 w-4" />
+          </Button>
+
+          {/* Underline Button */}
+          <Button
+            variant="ghost"
+            onClick={() => editor.chain().focus().toggleUnderline().run()}
+            className={`p-2 rounded ${
+              editor.isActive("underline") ? "bg-gray-200" : ""
+            }`}
+            title="Italic (Ctrl+I)"
+          >
+            <UnderlineIcon className="h-4 w-4" />
+          </Button>
+
+          {/* Strikethrough Button */}
+          <Button
+            variant="ghost"
+            onClick={() => editor.chain().focus().toggleStrike().run()}
+            className={`p-2 rounded ${
+              editor.isActive("strike") ? "bg-gray-200" : ""
+            }`}
+            title="Strike Through (Ctrl+Shift+X)"
+          >
+            <Strikethrough className="h-4 w-4" />
+          </Button>
+
+          {/* Heading 1 */}
+          <Button
+            variant="ghost"
+            onClick={() =>
+              editor.chain().focus().toggleHeading({ level: 1 }).run()
+            }
+            className={`p-2 rounded ${
+              editor.isActive("heading", { level: 1 }) ? "bg-gray-200" : ""
+            }`}
+          >
+            <Heading1 className="h-4 w-4" />
+          </Button>
+
+          {/* Heading */}
+          <Button
+            variant="ghost"
+            onClick={() =>
+              editor.chain().focus().toggleHeading({ level: 2 }).run()
+            }
+            className={`p-2 rounded ${
+              editor.isActive("heading", { level: 2 }) ? "bg-gray-200" : ""
+            }`}
+          >
+            <Heading2 className="h-4 w-4" />
+          </Button>
+
+          {/* Heading 3 */}
+          <Button
+            variant="ghost"
+            onClick={() =>
+              editor.chain().focus().toggleHeading({ level: 3 }).run()
+            }
+            className={`p-2 rounded ${
+              editor.isActive("heading", { level: 3 }) ? "bg-gray-200" : ""
+            }`}
+          >
+            <Heading3 className="h-4 w-4" />
+          </Button>
+
+          {/* Bullet List Button */}
+          <Button
+            variant="ghost"
+            onClick={() => editor.chain().focus().toggleBulletList().run()}
+            className={`p-2 rounded ${
+              editor.isActive("bulletList") ? "bg-gray-200" : ""
+            }`}
+            title="Bullet List"
+          >
+            <List className="h-4 w-4" />
+          </Button>
+
+          {/* Ordered List Button */}
+          <Button
+            variant="ghost"
+            onClick={() => editor.chain().focus().toggleOrderedList().run()}
+            className={`p-2 rounded ${
+              editor.isActive("orderedList") ? "bg-gray-200" : ""
+            }`}
+            title="Ordered List"
+          >
+            <ListOrdered className="h-4 w-4" />
+          </Button>
+        </div>
+        {/* Editor Content */}
+        <EditorContent editor={editor} />
+      </div>
+    );
+  }
+);
+
+export { TipTapEditor };
diff --git a/src/lib/api/notes.ts b/src/lib/api/notes.ts
index 2254d19..cd85076 100644
--- a/src/lib/api/notes.ts
+++ b/src/lib/api/notes.ts
@@ -1,171 +1,172 @@
 // Interacts with the note endpoints
 
 import { Id } from "@/types/general";
-import { defaultNote, isNote, isNoteArray, Note, noteToString, parseNote } from "@/types/note";
+import {
+  defaultNote,
+  isNote,
+  isNoteArray,
+  Note,
+  parseNote,
+} from "@/types/note";
 import { AxiosError, AxiosResponse } from "axios";
 
 export const fetchNotesByCoachingSessionId = async (
-    coachingSessionId: Id
-  ): Promise<Note[]> => {
-    const axios = require("axios");
-  
-    var notes: Note[] = [];
-    var err: string = "";
-  
-    const data = await axios
-      .get(`http://localhost:4000/notes`, {
-        params: {
-          coaching_session_id: coachingSessionId,
-        },
-        withCredentials: true,
-        setTimeout: 5000, // 5 seconds before timing out trying to log in with the backend
-        headers: {
-          "X-Version": "0.0.1",
-        },
-      })
-      .then(function (response: AxiosResponse) {
-        // handle success
-        var notes_data = response.data.data;
-        if (isNoteArray(notes_data)) {
-            notes_data.forEach((note_data: any) => {
-                notes.push(parseNote(note_data))
-            });
-        }
-      })
-      .catch(function (error: AxiosError) {
-        // handle error
-        console.error(error.response?.status);
-        if (error.response?.status == 401) {
-          console.error("Retrieval of Note failed: unauthorized.");
-          err = "Retrieval of Note failed: unauthorized.";
-        } else if (error.response?.status == 404) {
-          console.error("Retrieval of Note failed: Note by coaching session Id (" + coachingSessionId + ") not found.");
-          err = "Retrieval of Note failed: Note by coaching session Id (" + coachingSessionId + ") not found.";
-        } else {
-          console.log(error);
-          console.error(
-            `Retrieval of Note by coaching session Id (` + coachingSessionId + `) failed.`
-          );
-          err =
-            `Retrieval of Note by coaching session Id (` + coachingSessionId + `) failed.`;
-        }
-      });
-
-    if (err)
-      throw err;
-  
-    return notes;
-  };
+  coachingSessionId: Id
+): Promise<Note[]> => {
+  const axios = require("axios");
 
-export const createNote = async (
-    coaching_session_id: Id,
-    user_id: Id,
-    body: string
-  ): Promise<Note> => {
-    const axios = require("axios");
-  
-    const newNoteJson = {
-        coaching_session_id: coaching_session_id,
-        user_id: user_id,
-        body: body
-    };
-    console.debug("newNoteJson: " + JSON.stringify(newNoteJson));
-    // A full real note to be returned from the backend with the same body
-    var createdNote: Note = defaultNote();
-    var err: string = "";
-  
-    //var strNote: string = noteToString(note);
-    const data = await axios
-      .post(`http://localhost:4000/notes`, newNoteJson, {
-        withCredentials: true,
-        setTimeout: 5000, // 5 seconds before timing out trying to log in with the backend
-        headers: {
-          "X-Version": "0.0.1",
-          "Content-Type": "application/json",
-        },
-      })
-      .then(function (response: AxiosResponse) {
-        // handle success
-        const noteStr = response.data.data;
-        if (isNote(noteStr)) {
-          createdNote = parseNote(noteStr);
-        }
-      })
-      .catch(function (error: AxiosError) {
-        // handle error
-        console.error(error.response?.status);
-        if (error.response?.status == 401) {
-          console.error("Creation of Note failed: unauthorized.");
-          err = "Creation of Note failed: unauthorized.";
-        } else if (error.response?.status == 500) {
-          console.error(
-            "Creation of Note failed: internal server error."
-          );
-          err = "Creation of Note failed: internal server error.";
-        } else {
-          console.log(error);
-          console.error(`Creation of new Note failed.`);
-          err = `Creation of new Note failed.`;
-        }
+  var notes: Note[] = [];
+  var err: string = "";
+
+  const data = await axios
+    .get(`http://localhost:4000/notes`, {
+      params: {
+        coaching_session_id: coachingSessionId,
+      },
+      withCredentials: true,
+      setTimeout: 5000, // 5 seconds before timing out trying to log in with the backend
+      headers: {
+        "X-Version": "0.0.1",
+      },
+    })
+    .then(function (response: AxiosResponse) {
+      // handle success
+      var notes_data = response.data.data;
+      if (isNoteArray(notes_data)) {
+        notes_data.forEach((note_data: any) => {
+          notes.push(parseNote(note_data));
+        });
       }
-    );
-    
-    if (err)
-      throw err;
-  
-    return createdNote;
+    })
+    .catch(function (error: AxiosError) {
+      // handle error
+      console.error(error.response?.status);
+      if (error.response?.status == 401) {
+        err = "Retrieval of Note failed: unauthorized.";
+      } else if (error.response?.status == 404) {
+        err =
+          "Retrieval of Note failed: Note by coaching session Id (" +
+          coachingSessionId +
+          ") not found.";
+      } else {
+        err =
+          `Retrieval of Note by coaching session Id (` +
+          coachingSessionId +
+          `) failed.`;
+      }
+    });
+
+  if (err) {
+    console.log(err);
+    throw err;
+  }
+
+  return notes;
+};
+
+export const createNote = async (
+  coaching_session_id: Id,
+  user_id: Id,
+  body: string
+): Promise<Note> => {
+  const axios = require("axios");
+
+  const newNoteJson = {
+    coaching_session_id: coaching_session_id,
+    user_id: user_id,
+    body: body,
   };
+  console.debug("newNoteJson: " + JSON.stringify(newNoteJson));
+  // A full real note to be returned from the backend with the same body
+  var createdNote: Note = defaultNote();
+  var err: string = "";
 
-  export const updateNote = async (
-    id: Id,
-    user_id: Id,
-    coaching_session_id: Id,
-    body: string,
-  ): Promise<Note> => {
-    const axios = require("axios");
-  
-    var updatedNote: Note = defaultNote();
-    var err: string = "";
-  
-    const newNoteJson = {
-        coaching_session_id: coaching_session_id,
-        user_id: user_id,
-        body: body
-    };
-
-    const data = await axios
-      .put(`http://localhost:4000/notes/${id}`, newNoteJson, {
-        withCredentials: true,
-        setTimeout: 5000, // 5 seconds before timing out trying to log in with the backend
-        headers: {
-          "X-Version": "0.0.1",
-          "Content-Type": "application/json",
-        },
-      })
-      .then(function (response: AxiosResponse) {
-        // handle success
-        if (isNote(response.data.data)) {
-          updatedNote = response.data.data;
-        }
-      })
-      .catch(function (error: AxiosError) {
-        // handle error
-        console.error(error.response?.status);
-        if (error.response?.status == 401) {
-          console.error("Update of Note failed: unauthorized.");
-          err = "Update of Organization failed: unauthorized.";
-        } else if (error.response?.status == 500) {
-          console.error("Update of Organization failed: internal server error.");
-          err = "Update of Organization failed: internal server error.";
-        } else {
-          console.log(error);
-          console.error(`Update of new Organization failed.`);
-          err = `Update of new Organization failed.`;
-        }
-      });
-
-    if (err)
-      throw err;
-  
-    return updatedNote;
+  //var strNote: string = noteToString(note);
+  const data = await axios
+    .post(`http://localhost:4000/notes`, newNoteJson, {
+      withCredentials: true,
+      setTimeout: 5000, // 5 seconds before timing out trying to log in with the backend
+      headers: {
+        "X-Version": "0.0.1",
+        "Content-Type": "application/json",
+      },
+    })
+    .then(function (response: AxiosResponse) {
+      // handle success
+      const noteStr = response.data.data;
+      if (isNote(noteStr)) {
+        createdNote = parseNote(noteStr);
+      }
+    })
+    .catch(function (error: AxiosError) {
+      // handle error
+      console.error(error.response?.status);
+      if (error.response?.status == 401) {
+        err = "Creation of Note failed: unauthorized.";
+      } else if (error.response?.status == 500) {
+        err = "Creation of Note failed: internal server error.";
+      } else {
+        err = `Creation of new Note failed: ${error}`;
+      }
+    });
+
+  if (err) {
+    console.log(err);
+    throw err;
+  }
+
+  return createdNote;
+};
+
+export const updateNote = async (
+  id: Id,
+  user_id: Id,
+  coaching_session_id: Id,
+  body: string
+): Promise<Note> => {
+  const axios = require("axios");
+
+  var updatedNote: Note = defaultNote();
+  var err: string = "";
+
+  const newNoteJson = {
+    id: id,
+    coaching_session_id: coaching_session_id,
+    user_id: user_id,
+    body: body,
   };
+
+  const data = await axios
+    .put(`http://localhost:4000/notes/${id}`, newNoteJson, {
+      withCredentials: true,
+      setTimeout: 5000, // 5 seconds before timing out trying to log in with the backend
+      headers: {
+        "X-Version": "0.0.1",
+        "Content-Type": "application/json",
+      },
+    })
+    .then(function (response: AxiosResponse) {
+      // handle success
+      if (isNote(response.data.data)) {
+        updatedNote = response.data.data;
+      }
+    })
+    .catch(function (error: AxiosError) {
+      // handle error
+      console.error(error.response?.status);
+      if (error.response?.status == 401) {
+        err = "Update of Note failed: unauthorized.";
+      } else if (error.response?.status == 500) {
+        err = "Update of Note failed: internal server error.";
+      } else {
+        err = `Update of new Note failed: ${error}`;
+      }
+    });
+
+  if (err) {
+    console.log(err);
+    throw err;
+  }
+
+  return updatedNote;
+};
diff --git a/src/styles/styles.scss b/src/styles/styles.scss
new file mode 100644
index 0000000..1d5a9f4
--- /dev/null
+++ b/src/styles/styles.scss
@@ -0,0 +1,95 @@
+/* Basic TipTap editor styles */
+.tiptap {
+    :first-child {
+      margin-top: 0;
+    }
+  
+    /* List styles */
+    ul, 
+    ol {
+      padding: 0 1rem;
+      margin: 1.0rem 1rem 1.25rem 0.4rem;
+      
+      li p {
+        margin-top: 0.25em;
+        margin-bottom: 0.25em;
+      }
+    }
+
+    ul { list-style-type: disc; }
+
+    ol { list-style-type: decimal; }
+  
+    /* Heading styles */
+    h1, 
+    h2, 
+    h3, 
+    h4, 
+    h5, 
+    h6 {
+      line-height: 1.1;
+      //margin-top: 2.5rem;
+      text-wrap: pretty;
+    }
+  
+    h1, 
+    h2 {
+       margin-top: 1.0rem;
+    //   margin-bottom: 1.5rem;
+    }
+  
+    h1 { 
+      font-size: 1.4rem; 
+    }
+  
+    h2 { 
+      font-size: 1.2rem; 
+    }
+  
+    h3 { 
+      font-size: 1.1rem; 
+    }
+  
+    h4, 
+    h5, 
+    h6 { 
+      font-size: 1rem; 
+    }
+  
+    /* Code and preformatted text styles */
+    code {
+      background-color: var(--purple-light);
+      border-radius: 0.4rem;
+      color: var(--black);
+      font-size: 0.85rem;
+      padding: 0.25em 0.3em;
+    }
+  
+    pre {
+      background: var(--black);
+      border-radius: 0.5rem;
+      color: var(--white);
+      font-family: 'JetBrainsMono', monospace;
+      margin: 1.5rem 0;
+      padding: 0.75rem 1rem;
+  
+      code {
+        background: none;
+        color: inherit;
+        font-size: 0.8rem;
+        padding: 0;
+      }
+    }
+  
+    blockquote {
+      border-left: 3px solid var(--gray-3);
+      margin: 1.5rem 0;
+      padding-left: 1rem;
+    }
+  
+    hr {
+      border: none;
+      border-top: 1px solid var(--gray-2);
+      margin: 2rem 0;
+    }
+  }

From ef2f305b5d04e5d601d2a41cbd1d6ed990370bfd Mon Sep 17 00:00:00 2001
From: Jim Hodapp <james.hodapp@gmail.com>
Date: Sat, 12 Oct 2024 17:13:50 -0500
Subject: [PATCH 02/14] Set min-heights for different media breakpoints

---
 src/components/ui/coaching-sessions/tiptap-editor.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/ui/coaching-sessions/tiptap-editor.tsx b/src/components/ui/coaching-sessions/tiptap-editor.tsx
index 81834f8..edd2a77 100644
--- a/src/components/ui/coaching-sessions/tiptap-editor.tsx
+++ b/src/components/ui/coaching-sessions/tiptap-editor.tsx
@@ -41,7 +41,7 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
         editorProps: {
           attributes: {
             class:
-              "shadow appearance-none min-h-[150px] border rounded w-full py-2 px-3 bg-white text-black text-sm mt-0 md:mt-3 leading-tight focus:outline-none focus:shadow-outline",
+              "shadow appearance-none lg:min-h-[600px] sm:min-h-[200px] md:min-h-[400px] border rounded w-full py-2 px-3 bg-white text-black text-sm mt-0 md:mt-3 leading-tight focus:outline-none focus:shadow-outline",
           },
         },
 

From 41448307a3caa65cc6a62a775dbd1e63c868ad4a Mon Sep 17 00:00:00 2001
From: Jim Hodapp <james.hodapp@gmail.com>
Date: Sat, 12 Oct 2024 20:02:32 -0500
Subject: [PATCH 03/14] Some style/margin tweaks to the editor and toolbar.

---
 src/components/ui/coaching-sessions/tiptap-editor.tsx | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/components/ui/coaching-sessions/tiptap-editor.tsx b/src/components/ui/coaching-sessions/tiptap-editor.tsx
index edd2a77..93a3510 100644
--- a/src/components/ui/coaching-sessions/tiptap-editor.tsx
+++ b/src/components/ui/coaching-sessions/tiptap-editor.tsx
@@ -41,7 +41,7 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
         editorProps: {
           attributes: {
             class:
-              "shadow appearance-none lg:min-h-[600px] sm:min-h-[200px] md:min-h-[400px] border rounded w-full py-2 px-3 bg-white text-black text-sm mt-0 md:mt-3 leading-tight focus:outline-none focus:shadow-outline",
+              "shadow appearance-none lg:min-h-[600px] sm:min-h-[200px] md:min-h-[400px] rounded w-full py-2 px-3 bg-white text-black text-sm mt-0 md:mt-3 leading-tight focus:outline-none focus:shadow-outline",
           },
         },
 
@@ -68,8 +68,9 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
     }
 
     return (
-      <div className="flex flex-col justify-stretch min-h-[200px] border rounded border-b-0">
-        <div className="flex items-center gap-0 mb-0">
+      <div className="flex flex-col justify-stretch border rounded border-b-0">
+        {/* Toolbar style */}
+        <div className="flex items-center gap-0 mt-1 mx-1 mb-0">
           {/* Bold Button */}
           <Button
             variant="ghost"

From fae7addbdd5212c7b8552b861614c54e6dd90d8a Mon Sep 17 00:00:00 2001
From: Jim Hodapp <james.hodapp@gmail.com>
Date: Sat, 12 Oct 2024 20:16:40 -0500
Subject: [PATCH 04/14] Add Refactor logo to login page

---
 src/app/login/page.tsx | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx
index 38376da..bd50509 100644
--- a/src/app/login/page.tsx
+++ b/src/app/login/page.tsx
@@ -6,6 +6,7 @@ import { cn } from "@/lib/utils";
 import { buttonVariants } from "@/components/ui/button";
 import { UserAuthForm } from "@/components/user-auth-form";
 import { siteConfig } from "@/site.config";
+import { Icons } from "@/components/ui/icons";
 
 export const metadata: Metadata = {
   title: "Welcome to Refactor Coaching",
@@ -44,7 +45,7 @@ export default function AuthenticationPage() {
         <div className="relative hidden h-full flex-col bg-muted p-10 text-white lg:flex dark:border-r">
           <div className="absolute inset-0 bg-zinc-900" />
           <div className="relative z-20 flex items-center text-lg font-medium">
-            <svg
+            {/* <svg
               xmlns="http://www.w3.org/2000/svg"
               viewBox="0 0 24 24"
               fill="none"
@@ -55,7 +56,23 @@ export default function AuthenticationPage() {
               className="mr-2 h-6 w-6"
             >
               <path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3" />
-            </svg>
+            </svg> */}
+            <Link
+              href="/dashboard"
+              className="mr-2 flex items-center space-x-2"
+            >
+              <div
+                className={cn(
+                  buttonVariants({
+                    variant: "ghost",
+                  }),
+                  "w-9 px-0"
+                )}
+              >
+                <Icons.refactor_logo className="h-7 w-7" />
+                <span className="sr-only">Refactor</span>
+              </div>
+            </Link>
             {siteConfig.name}
           </div>
           <div className="relative z-20 mt-auto">

From 003eec66d912eb096d40ad9af1bcc364533814cb Mon Sep 17 00:00:00 2001
From: Jim Hodapp <james.hodapp@gmail.com>
Date: Sat, 12 Oct 2024 20:22:03 -0500
Subject: [PATCH 05/14] Update the URL of the Refactor logo link

---
 src/app/login/page.tsx | 14 +-------------
 1 file changed, 1 insertion(+), 13 deletions(-)

diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx
index bd50509..d15fd3c 100644
--- a/src/app/login/page.tsx
+++ b/src/app/login/page.tsx
@@ -45,20 +45,8 @@ export default function AuthenticationPage() {
         <div className="relative hidden h-full flex-col bg-muted p-10 text-white lg:flex dark:border-r">
           <div className="absolute inset-0 bg-zinc-900" />
           <div className="relative z-20 flex items-center text-lg font-medium">
-            {/* <svg
-              xmlns="http://www.w3.org/2000/svg"
-              viewBox="0 0 24 24"
-              fill="none"
-              stroke="currentColor"
-              strokeWidth="2"
-              strokeLinecap="round"
-              strokeLinejoin="round"
-              className="mr-2 h-6 w-6"
-            >
-              <path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3" />
-            </svg> */}
             <Link
-              href="/dashboard"
+              href="https://www.refactorcoach.com"
               className="mr-2 flex items-center space-x-2"
             >
               <div

From 1af4d7eb192deb49288395dbc5c2c06d0a9333c2 Mon Sep 17 00:00:00 2001
From: Jim Hodapp <james.hodapp@gmail.com>
Date: Sun, 13 Oct 2024 18:40:02 -0500
Subject: [PATCH 06/14] Tweak editor styling further, add text highlighting and
 code blocks (style doesn't work correctly yet for this)

---
 package-lock.json                             | 14 ++++++
 package.json                                  |  1 +
 src/app/coaching-sessions/[id]/page.tsx       |  2 +-
 .../ui/coaching-sessions/tiptap-editor.tsx    | 43 +++++++++++++++++--
 src/components/ui/site-header.tsx             |  2 +-
 src/styles/styles.scss                        | 28 ++++++------
 6 files changed, 71 insertions(+), 19 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index e0b05d1..f07bde6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -32,6 +32,7 @@
         "@tiptap/extension-bubble-menu": "^2.8.0",
         "@tiptap/extension-bullet-list": "^2.8.0",
         "@tiptap/extension-heading": "^2.8.0",
+        "@tiptap/extension-highlight": "^2.8.0",
         "@tiptap/extension-list-item": "^2.8.0",
         "@tiptap/extension-ordered-list": "^2.8.0",
         "@tiptap/extension-underline": "^2.8.0",
@@ -1859,6 +1860,19 @@
         "@tiptap/core": "^2.7.0"
       }
     },
+    "node_modules/@tiptap/extension-highlight": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-highlight/-/extension-highlight-2.8.0.tgz",
+      "integrity": "sha512-vyqX7D449nuARhI0AyRqtIZReFg3sfc/U/q1p3JOjtUoW6z2jmDTzshiKRrSg+Jf7Hhzj1pqwU+6+CpelPPDpA==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
     "node_modules/@tiptap/extension-history": {
       "version": "2.8.0",
       "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.8.0.tgz",
diff --git a/package.json b/package.json
index 7a3e3e3..d43b11c 100644
--- a/package.json
+++ b/package.json
@@ -33,6 +33,7 @@
     "@tiptap/extension-bubble-menu": "^2.8.0",
     "@tiptap/extension-bullet-list": "^2.8.0",
     "@tiptap/extension-heading": "^2.8.0",
+    "@tiptap/extension-highlight": "^2.8.0",
     "@tiptap/extension-list-item": "^2.8.0",
     "@tiptap/extension-ordered-list": "^2.8.0",
     "@tiptap/extension-underline": "^2.8.0",
diff --git a/src/app/coaching-sessions/[id]/page.tsx b/src/app/coaching-sessions/[id]/page.tsx
index d84ac2a..ba3ea8c 100644
--- a/src/app/coaching-sessions/[id]/page.tsx
+++ b/src/app/coaching-sessions/[id]/page.tsx
@@ -95,7 +95,7 @@ export default function CoachingSessionsPage() {
 
   useEffect(() => {
     fetchNote();
-  }, []);
+  }, [coachingSession.id]);
 
   const setEditorContent = (content: string) => {
     editorRef.current?.setContent(`${content}`);
diff --git a/src/components/ui/coaching-sessions/tiptap-editor.tsx b/src/components/ui/coaching-sessions/tiptap-editor.tsx
index 93a3510..78c44e7 100644
--- a/src/components/ui/coaching-sessions/tiptap-editor.tsx
+++ b/src/components/ui/coaching-sessions/tiptap-editor.tsx
@@ -4,6 +4,7 @@ import { useEditor, EditorContent } from "@tiptap/react";
 
 import StarterKit from "@tiptap/starter-kit";
 import BulletList from "@tiptap/extension-bullet-list";
+import Highlight from "@tiptap/extension-highlight";
 import ListItem from "@tiptap/extension-list-item";
 import OrderedList from "@tiptap/extension-ordered-list";
 import Underline from "@tiptap/extension-underline";
@@ -12,11 +13,13 @@ import {
   Heading1,
   Heading2,
   Heading3,
+  Highlighter,
   Italic,
   Underline as UnderlineIcon,
   List,
   ListOrdered,
   Strikethrough,
+  Braces,
 } from "lucide-react";
 import { Button } from "@/components/ui/button";
 import { forwardRef, useImperativeHandle } from "react";
@@ -33,7 +36,14 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
   ({ editorContent, onChange }, ref) => {
     const editor = useEditor(
       {
-        extensions: [StarterKit, ListItem, Underline],
+        extensions: [
+          StarterKit,
+          ListItem,
+          Underline,
+          Highlight,
+          BulletList,
+          OrderedList,
+        ],
 
         autofocus: false,
         immediatelyRender: false,
@@ -41,7 +51,9 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
         editorProps: {
           attributes: {
             class:
-              "shadow appearance-none lg:min-h-[600px] sm:min-h-[200px] md:min-h-[400px] rounded w-full py-2 px-3 bg-white text-black text-sm mt-0 md:mt-3 leading-tight focus:outline-none focus:shadow-outline",
+              // Make this responsive to light/dark mode
+              // Also is the background what's preventing the codeblock background color from working?
+              "shadow appearance-none lg:min-h-[440px] sm:min-h-[200px] md:min-h-[350px] rounded w-full py-2 px-3 bg-inherit text-black text-sm mt-0 md:mt-3 leading-tight focus:outline-none focus:shadow-outline",
           },
         },
 
@@ -114,11 +126,23 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
             className={`p-2 rounded ${
               editor.isActive("strike") ? "bg-gray-200" : ""
             }`}
-            title="Strike Through (Ctrl+Shift+X)"
+            title="Strike Through"
           >
             <Strikethrough className="h-4 w-4" />
           </Button>
 
+          {/* Highlight Button */}
+          <Button
+            variant="ghost"
+            onClick={() => editor.chain().focus().toggleHighlight().run()}
+            className={`p-2 rounded ${
+              editor.isActive("highlight") ? "bg-gray-200" : ""
+            }`}
+            title="Highlight Text"
+          >
+            <Highlighter className="h-4 w-4" />
+          </Button>
+
           {/* Heading 1 */}
           <Button
             variant="ghost"
@@ -128,6 +152,7 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
             className={`p-2 rounded ${
               editor.isActive("heading", { level: 1 }) ? "bg-gray-200" : ""
             }`}
+            title="Heading1"
           >
             <Heading1 className="h-4 w-4" />
           </Button>
@@ -141,6 +166,7 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
             className={`p-2 rounded ${
               editor.isActive("heading", { level: 2 }) ? "bg-gray-200" : ""
             }`}
+            title="Heading2"
           >
             <Heading2 className="h-4 w-4" />
           </Button>
@@ -154,6 +180,7 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
             className={`p-2 rounded ${
               editor.isActive("heading", { level: 3 }) ? "bg-gray-200" : ""
             }`}
+            title="Heading3"
           >
             <Heading3 className="h-4 w-4" />
           </Button>
@@ -181,6 +208,16 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
           >
             <ListOrdered className="h-4 w-4" />
           </Button>
+
+          <Button
+            variant="ghost"
+            onClick={() => editor.chain().focus().toggleCodeBlock().run()}
+            className={`p-2 rounded ${
+              editor.isActive("codeBlock") ? "is-active" : ""
+            }`}
+          >
+            <Braces className="h-4 w-4" />
+          </Button>
         </div>
         {/* Editor Content */}
         <EditorContent editor={editor} />
diff --git a/src/components/ui/site-header.tsx b/src/components/ui/site-header.tsx
index 1e97c57..102e50a 100644
--- a/src/components/ui/site-header.tsx
+++ b/src/components/ui/site-header.tsx
@@ -19,7 +19,7 @@ export function SiteHeader() {
 
   return (
     <header className="sticky top-0 z-50 w-full border-b border-border/40 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
-      <div className="flex h-14 pl-4 max-w-screen-2xl items-start">
+      <div className="flex h-14 pl-4 pt-2 max-w-screen-2xl items-start">
         <MainNav />
         <MobileNav />
         <div className="flex flex-1 items-center justify-between space-x-2 md:justify-end">
diff --git a/src/styles/styles.scss b/src/styles/styles.scss
index 1d5a9f4..918ee32 100644
--- a/src/styles/styles.scss
+++ b/src/styles/styles.scss
@@ -8,7 +8,7 @@
     ul, 
     ol {
       padding: 0 1rem;
-      margin: 1.0rem 1rem 1.25rem 0.4rem;
+      margin: 0.5rem 1.0rem 0.5rem 0.4rem;
       
       li p {
         margin-top: 0.25em;
@@ -66,20 +66,20 @@
     }
   
     pre {
-      background: var(--black);
-      border-radius: 0.5rem;
-      color: var(--white);
-      font-family: 'JetBrainsMono', monospace;
-      margin: 1.5rem 0;
-      padding: 0.75rem 1rem;
-  
-      code {
-        background: none;
-        color: inherit;
-        font-size: 0.8rem;
-        padding: 0;
+        background: var(--black);
+        border-radius: 0.5rem;
+        color: var(--white);
+        font-family: 'JetBrainsMono', monospace;
+        margin: 1.5rem 0;
+        padding: 0.75rem 1rem;
+    
+        code {
+          background: none;
+          color: inherit;
+          font-size: 0.8rem;
+          padding: 0;
+        }
       }
-    }
   
     blockquote {
       border-left: 3px solid var(--gray-3);

From e4beccc2c8ec94f16b6d63bc199e94a79b04597a Mon Sep 17 00:00:00 2001
From: Jim Hodapp <james.hodapp@gmail.com>
Date: Tue, 15 Oct 2024 22:53:44 -0500
Subject: [PATCH 07/14] Code block with syntax highlighting working, but
 styling not quite correct yet

---
 package-lock.json                             |  86 ++++++-
 package.json                                  |   1 +
 src/app/coaching-sessions/[id]/page.tsx       |   6 +-
 .../ui/coaching-sessions/code-block.tsx       |  39 +++
 .../ui/coaching-sessions/tiptap-editor.tsx    |  33 ++-
 src/styles/code-block.scss                    |  14 ++
 src/styles/styles.scss                        | 235 ++++++++++++------
 7 files changed, 325 insertions(+), 89 deletions(-)
 create mode 100644 src/components/ui/coaching-sessions/code-block.tsx
 create mode 100644 src/styles/code-block.scss

diff --git a/package-lock.json b/package-lock.json
index f07bde6..bce0ed3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -31,6 +31,7 @@
         "@tailwindcss/typography": "^0.5.15",
         "@tiptap/extension-bubble-menu": "^2.8.0",
         "@tiptap/extension-bullet-list": "^2.8.0",
+        "@tiptap/extension-code-block-lowlight": "^2.8.0",
         "@tiptap/extension-heading": "^2.8.0",
         "@tiptap/extension-highlight": "^2.8.0",
         "@tiptap/extension-list-item": "^2.8.0",
@@ -1776,6 +1777,23 @@
         "@tiptap/pm": "^2.7.0"
       }
     },
+    "node_modules/@tiptap/extension-code-block-lowlight": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.8.0.tgz",
+      "integrity": "sha512-6RRGtzmRXlUrxJXz6cuTIpGTeMe+0Mz3XBQaZ0t7Y7PgbBDFj9tw9+LeO4eHLS/SraX4Y+P73HzKe03AdfQ95A==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/extension-code-block": "^2.7.0",
+        "@tiptap/pm": "^2.7.0",
+        "highlight.js": "^11",
+        "lowlight": "^2 || ^3"
+      }
+    },
     "node_modules/@tiptap/extension-document": {
       "version": "2.8.0",
       "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.8.0.tgz",
@@ -2102,6 +2120,16 @@
         "url": "https://github.com/sponsors/ueberdosis"
       }
     },
+    "node_modules/@types/hast": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
+      "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@types/unist": "*"
+      }
+    },
     "node_modules/@types/json5": {
       "version": "0.0.29",
       "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
@@ -2164,6 +2192,13 @@
         "@types/react": "*"
       }
     },
+    "node_modules/@types/unist": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
+      "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
+      "license": "MIT",
+      "peer": true
+    },
     "node_modules/@types/use-sync-external-store": {
       "version": "0.0.6",
       "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
@@ -3344,7 +3379,6 @@
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
       "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
-      "dev": true,
       "engines": {
         "node": ">=6"
       }
@@ -3354,6 +3388,20 @@
       "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
       "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
     },
+    "node_modules/devlop": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
+      "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "dequal": "^2.0.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
     "node_modules/didyoumean": {
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
@@ -4515,6 +4563,16 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/highlight.js": {
+      "version": "11.10.0",
+      "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.10.0.tgz",
+      "integrity": "sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==",
+      "license": "BSD-3-Clause",
+      "peer": true,
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
     "node_modules/ignore": {
       "version": "5.3.1",
       "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
@@ -5170,6 +5228,32 @@
         "loose-envify": "cli.js"
       }
     },
+    "node_modules/lowlight": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-3.1.0.tgz",
+      "integrity": "sha512-CEbNVoSikAxwDMDPjXlqlFYiZLkDJHwyGu/MfOsJnF3d7f3tds5J3z8s/l9TMXhzfsJCCJEAsD78842mwmg0PQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "devlop": "^1.0.0",
+        "highlight.js": "~11.9.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/lowlight/node_modules/highlight.js": {
+      "version": "11.9.0",
+      "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.9.0.tgz",
+      "integrity": "sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==",
+      "license": "BSD-3-Clause",
+      "peer": true,
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
     "node_modules/lru-cache": {
       "version": "10.2.0",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz",
diff --git a/package.json b/package.json
index d43b11c..3e25f93 100644
--- a/package.json
+++ b/package.json
@@ -32,6 +32,7 @@
     "@tailwindcss/typography": "^0.5.15",
     "@tiptap/extension-bubble-menu": "^2.8.0",
     "@tiptap/extension-bullet-list": "^2.8.0",
+    "@tiptap/extension-code-block-lowlight": "^2.8.0",
     "@tiptap/extension-heading": "^2.8.0",
     "@tiptap/extension-highlight": "^2.8.0",
     "@tiptap/extension-list-item": "^2.8.0",
diff --git a/src/app/coaching-sessions/[id]/page.tsx b/src/app/coaching-sessions/[id]/page.tsx
index ba3ea8c..6c34138 100644
--- a/src/app/coaching-sessions/[id]/page.tsx
+++ b/src/app/coaching-sessions/[id]/page.tsx
@@ -153,7 +153,7 @@ export default function CoachingSessionsPage() {
 
   return (
     <>
-      <div className="h-full flex-col md:flex">
+      <div className="flex-col h-full md:flex">
         <div className="flex flex-col items-start justify-between space-y-2 py-4 px-4 sm:flex-row sm:items-center sm:space-y-0 md:h-16">
           <CoachingSessionTitle
             locale={siteConfig.locale}
@@ -177,7 +177,7 @@ export default function CoachingSessionsPage() {
       <div className="row-span-1 h-full py-4 px-4">
         <div className="grid h-full items-stretch gap-6 md:grid-cols-[1fr_200px]">
           <div className="flex-col space-y-4 sm:flex md:order-1">
-            <Tabs defaultValue="notes" className="flex-1">
+            <Tabs defaultValue="notes">
               <TabsList className="flex w-128 grid-cols-2 justify-start">
                 <TabsTrigger value="notes">Notes</TabsTrigger>
                 <TabsTrigger value="console">Console</TabsTrigger>
@@ -189,7 +189,7 @@ export default function CoachingSessionsPage() {
                 </TabsTrigger>
               </TabsList>
               <TabsContent value="notes">
-                <div className="flex h-full flex-col space-y-4">
+                <div className="flex-col h-full space-y-4">
                   <CoachingNotes
                     ref={editorRef}
                     value={note.body}
diff --git a/src/components/ui/coaching-sessions/code-block.tsx b/src/components/ui/coaching-sessions/code-block.tsx
new file mode 100644
index 0000000..6b198f2
--- /dev/null
+++ b/src/components/ui/coaching-sessions/code-block.tsx
@@ -0,0 +1,39 @@
+import React from "react";
+import { NodeViewProps, NodeViewWrapper, NodeViewContent } from "@tiptap/react";
+
+import "@/styles/code-block.scss";
+
+const CodeBlock: React.FC<NodeViewProps> = ({
+  node,
+  updateAttributes,
+  extension,
+}) => {
+  const language = node.attrs.language || "auto";
+
+  return (
+    <NodeViewWrapper className="code-block">
+      <select
+        contentEditable={false}
+        defaultValue={language}
+        onChange={(event: React.ChangeEvent<HTMLSelectElement>) =>
+          updateAttributes({ language: event.target.value })
+        }
+      >
+        <option value="auto">auto</option>
+        <option disabled>—</option>
+        {extension.options.lowlight
+          .listLanguages()
+          .map((lang: string, index: number) => (
+            <option key={index} value={lang}>
+              {lang}
+            </option>
+          ))}
+      </select>
+      <pre>
+        <NodeViewContent as="code" />
+      </pre>
+    </NodeViewWrapper>
+  );
+};
+
+export default CodeBlock;
diff --git a/src/components/ui/coaching-sessions/tiptap-editor.tsx b/src/components/ui/coaching-sessions/tiptap-editor.tsx
index 78c44e7..73f4662 100644
--- a/src/components/ui/coaching-sessions/tiptap-editor.tsx
+++ b/src/components/ui/coaching-sessions/tiptap-editor.tsx
@@ -1,6 +1,6 @@
 "use client";
 
-import { useEditor, EditorContent } from "@tiptap/react";
+import { useEditor, EditorContent, ReactNodeViewRenderer } from "@tiptap/react";
 
 import StarterKit from "@tiptap/starter-kit";
 import BulletList from "@tiptap/extension-bullet-list";
@@ -8,6 +8,7 @@ import Highlight from "@tiptap/extension-highlight";
 import ListItem from "@tiptap/extension-list-item";
 import OrderedList from "@tiptap/extension-ordered-list";
 import Underline from "@tiptap/extension-underline";
+import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
 import {
   Bold,
   Heading1,
@@ -24,9 +25,27 @@ import {
 import { Button } from "@/components/ui/button";
 import { forwardRef, useImperativeHandle } from "react";
 
-import "@/styles/styles.scss";
 import { EditorRef } from "./coaching-notes";
 
+import css from "highlight.js/lib/languages/css";
+import js from "highlight.js/lib/languages/javascript";
+import ts from "highlight.js/lib/languages/typescript";
+import html from "highlight.js/lib/languages/xml";
+// Load all languages with "all" or common languages with "common"
+import { all, createLowlight } from "lowlight";
+
+// eslint-disable-next-line
+import CodeBlock from "@/components/ui/coaching-sessions/code-block";
+
+import "@/styles/styles.scss";
+
+const lowlight = createLowlight(all);
+
+lowlight.register("html", html);
+lowlight.register("css", css);
+lowlight.register("js", js);
+lowlight.register("ts", ts);
+
 interface TipTapProps {
   editorContent: string;
   onChange: (content: string) => void;
@@ -43,6 +62,11 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
           Highlight,
           BulletList,
           OrderedList,
+          CodeBlockLowlight.extend({
+            addNodeView() {
+              return ReactNodeViewRenderer(CodeBlock);
+            },
+          }).configure({ lowlight }),
         ],
 
         autofocus: false,
@@ -53,7 +77,8 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
             class:
               // Make this responsive to light/dark mode
               // Also is the background what's preventing the codeblock background color from working?
-              "shadow appearance-none lg:min-h-[440px] sm:min-h-[200px] md:min-h-[350px] rounded w-full py-2 px-3 bg-inherit text-black text-sm mt-0 md:mt-3 leading-tight focus:outline-none focus:shadow-outline",
+              // "tiptap ProseMirror",
+              "tiptap ProseMirror shadow appearance-none lg:min-h-[440px] sm:min-h-[200px] md:min-h-[350px] rounded w-full py-2 px-3 bg-inherit text-black text-sm mt-0 md:mt-3 leading-tight focus:outline-none focus:shadow-outline",
           },
         },
 
@@ -80,7 +105,7 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
     }
 
     return (
-      <div className="flex flex-col justify-stretch border rounded border-b-0">
+      <div className="border rounded">
         {/* Toolbar style */}
         <div className="flex items-center gap-0 mt-1 mx-1 mb-0">
           {/* Bold Button */}
diff --git a/src/styles/code-block.scss b/src/styles/code-block.scss
new file mode 100644
index 0000000..a63ac30
--- /dev/null
+++ b/src/styles/code-block.scss
@@ -0,0 +1,14 @@
+.tiptap {
+    .code-block {
+        position: relative;
+      
+        select {
+          position: absolute;
+          background-color: white;
+          border: round($number: 5);
+          //background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="Black" d="M7 10l5 5 5-5z"/></svg>');
+          right: 0.5rem;
+          top: 0.5rem;
+        }
+      }
+  }
\ No newline at end of file
diff --git a/src/styles/styles.scss b/src/styles/styles.scss
index 918ee32..3be1ad2 100644
--- a/src/styles/styles.scss
+++ b/src/styles/styles.scss
@@ -1,95 +1,168 @@
 /* Basic TipTap editor styles */
 .tiptap {
-    :first-child {
-      margin-top: 0;
-    }
-  
-    /* List styles */
-    ul, 
-    ol {
-      padding: 0 1rem;
-      margin: 0.5rem 1.0rem 0.5rem 0.4rem;
-      
-      li p {
-        margin-top: 0.25em;
-        margin-bottom: 0.25em;
-      }
+  :first-child {
+    margin-top: 0;
+  }
+
+  /* List styles */
+  ul,
+  ol {
+    padding: 0 1rem;
+    margin: 0.5rem 1rem 0.5rem 0.4rem;
+
+    li p {
+      margin-top: 0.25em;
+      margin-bottom: 0.25em;
     }
+  }
+
+  ul {
+    list-style-type: disc;
+  }
+
+  ol {
+    list-style-type: decimal;
+  }
+
+  /* Heading styles */
+  h1,
+  h2,
+  h3,
+  h4,
+  h5,
+  h6 {
+    line-height: 1.1;
+    //margin-top: 2.5rem;
+    text-wrap: pretty;
+  }
+
+  h1,
+  h2 {
+    margin-top: 1rem;
+    margin-bottom: 1rem;
+  }
+
+  h1 {
+    font-size: 1.4rem;
+  }
+
+  h2 {
+    font-size: 1.2rem;
+  }
+
+  h3 {
+    font-size: 1.0rem;
+  }
 
-    ul { list-style-type: disc; }
-
-    ol { list-style-type: decimal; }
-  
-    /* Heading styles */
-    h1, 
-    h2, 
-    h3, 
-    h4, 
-    h5, 
-    h6 {
-      line-height: 1.1;
-      //margin-top: 2.5rem;
-      text-wrap: pretty;
+  h4,
+  h5,
+  h6 {
+    font-size: 1rem;
+  }
+
+  pre {
+    background: black;
+    border-radius: 0.5rem;
+    color: white;
+    font-family: "JetBrainsMono", monospace;
+    margin: 1.5rem 0;
+    padding: 0.75rem 1rem;
+
+    code {
+      background: none;
+      color: inherit;
+      font-size: 0.8rem;
+      padding: 0;
     }
-  
-    h1, 
-    h2 {
-       margin-top: 1.0rem;
-    //   margin-bottom: 1.5rem;
+
+    /* Code styling */
+    .hljs-comment,
+    .hljs-quote {
+      color: #616161;
     }
-  
-    h1 { 
-      font-size: 1.4rem; 
+
+    .hljs-variable,
+    .hljs-template-variable,
+    .hljs-attribute,
+    .hljs-tag,
+    .hljs-name,
+    .hljs-regexp,
+    .hljs-link,
+    .hljs-name,
+    .hljs-selector-id,
+    .hljs-selector-class {
+      color: #f98181;
     }
-  
-    h2 { 
-      font-size: 1.2rem; 
+
+    .hljs-number,
+    .hljs-meta,
+    .hljs-built_in,
+    .hljs-builtin-name,
+    .hljs-literal,
+    .hljs-type,
+    .hljs-params {
+      color: #fbbc88;
     }
-  
-    h3 { 
-      font-size: 1.1rem; 
+
+    .hljs-string,
+    .hljs-symbol,
+    .hljs-bullet {
+      color: #b9f18d;
     }
-  
-    h4, 
-    h5, 
-    h6 { 
-      font-size: 1rem; 
+
+    .hljs-title,
+    .hljs-section {
+      color: #faf594;
     }
-  
-    /* Code and preformatted text styles */
-    code {
-      background-color: var(--purple-light);
-      border-radius: 0.4rem;
-      color: var(--black);
-      font-size: 0.85rem;
-      padding: 0.25em 0.3em;
+
+    .hljs-keyword,
+    .hljs-selector-tag {
+      color: #70cff8;
     }
-  
-    pre {
-        background: var(--black);
-        border-radius: 0.5rem;
-        color: var(--white);
-        font-family: 'JetBrainsMono', monospace;
-        margin: 1.5rem 0;
-        padding: 0.75rem 1rem;
-    
-        code {
-          background: none;
-          color: inherit;
-          font-size: 0.8rem;
-          padding: 0;
-        }
-      }
-  
-    blockquote {
-      border-left: 3px solid var(--gray-3);
-      margin: 1.5rem 0;
-      padding-left: 1rem;
+
+    .hljs-emphasis {
+      font-style: italic;
     }
-  
-    hr {
-      border: none;
-      border-top: 1px solid var(--gray-2);
-      margin: 2rem 0;
+
+    .hljs-strong {
+      font-weight: 700;
     }
   }
+
+  /* Code and preformatted text styles */
+  // code {
+  //   background-color: var(--purple-light);
+  //   border-radius: 0.4rem;
+  //   color: var(--black);
+  //   font-size: 0.85rem;
+  //   padding: 0.25em 0.3em;
+  // }
+
+  // pre {
+  //     background: var(--black);
+  //     border-radius: 0.5rem;
+  //     color: var(--white);
+  //     font-family: 'JetBrainsMono', monospace;
+  //     margin: 1.5rem 0;
+  //     padding: 0.75rem 1rem;
+
+  //     code {
+  //       background: none;
+  //       color: inherit;
+  //       font-size: 0.8rem;
+  //       padding: 0;
+  //     }
+  //   }
+
+  // blockquote {
+  //   border-left: 3px solid var(--gray-3);
+  //   margin: 1.5rem 0;
+  //   padding-left: 1rem;
+  // }
+
+  hr {
+    border: none;
+    border-top: 1px solid var(--gray-2);
+    margin: 2rem 0;
+  }
+}

From d2c703f91324b2bdee45f60d7f9102608eef23b2 Mon Sep 17 00:00:00 2001
From: Jim Hodapp <james.hodapp@gmail.com>
Date: Tue, 15 Oct 2024 23:03:00 -0500
Subject: [PATCH 08/14] Take care of build errors

---
 package-lock.json                                      | 9 +++++----
 src/app/coaching-sessions/[id]/page.tsx                | 2 +-
 src/components/ui/coaching-sessions/coaching-notes.tsx | 2 ++
 src/components/ui/coaching-sessions/tiptap-editor.tsx  | 2 ++
 4 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index bce0ed3..3835d36 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2820,9 +2820,9 @@
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001612",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz",
-      "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==",
+      "version": "1.0.30001668",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001668.tgz",
+      "integrity": "sha512-nWLrdxqCdblixUO+27JtGJJE/txpJlyUy5YN1u53wLZkP0emYCo5zgS6QYft7VUYR42LGgi/S5hdLZTrnyIddw==",
       "funding": [
         {
           "type": "opencollective",
@@ -2836,7 +2836,8 @@
           "type": "github",
           "url": "https://github.com/sponsors/ai"
         }
-      ]
+      ],
+      "license": "CC-BY-4.0"
     },
     "node_modules/chalk": {
       "version": "4.1.2",
diff --git a/src/app/coaching-sessions/[id]/page.tsx b/src/app/coaching-sessions/[id]/page.tsx
index 6c34138..e997151 100644
--- a/src/app/coaching-sessions/[id]/page.tsx
+++ b/src/app/coaching-sessions/[id]/page.tsx
@@ -95,7 +95,7 @@ export default function CoachingSessionsPage() {
 
   useEffect(() => {
     fetchNote();
-  }, [coachingSession.id]);
+  }, [coachingSession.id, isLoading]);
 
   const setEditorContent = (content: string) => {
     editorRef.current?.setContent(`${content}`);
diff --git a/src/components/ui/coaching-sessions/coaching-notes.tsx b/src/components/ui/coaching-sessions/coaching-notes.tsx
index 0cc1d2f..b270bf9 100644
--- a/src/components/ui/coaching-sessions/coaching-notes.tsx
+++ b/src/components/ui/coaching-sessions/coaching-notes.tsx
@@ -61,4 +61,6 @@ const CoachingNotes = forwardRef<EditorRef, CoachingNotesProps>(
   }
 );
 
+CoachingNotes.displayName = "CoachingNotes";
+
 export { CoachingNotes };
diff --git a/src/components/ui/coaching-sessions/tiptap-editor.tsx b/src/components/ui/coaching-sessions/tiptap-editor.tsx
index 73f4662..4ac881c 100644
--- a/src/components/ui/coaching-sessions/tiptap-editor.tsx
+++ b/src/components/ui/coaching-sessions/tiptap-editor.tsx
@@ -251,4 +251,6 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
   }
 );
 
+TipTapEditor.displayName = "TipTapEditor";
+
 export { TipTapEditor };

From 8a65343ae88d992c3ce90a9407720f879de74590 Mon Sep 17 00:00:00 2001
From: Jim Hodapp <james.hodapp@gmail.com>
Date: Fri, 18 Oct 2024 10:37:56 -0500
Subject: [PATCH 09/14] Add a styled language selector to set code block syntax
 highlighting for chosen language. Also enable use of tailwindcss tags and
 classes in scss files.

---
 package-lock.json                             | 28 ++++++++--
 package.json                                  |  1 +
 postcss.config.js                             |  2 +
 .../ui/coaching-sessions/code-block.tsx       | 25 ++++-----
 .../programming-language-selector.tsx         | 52 +++++++++++++++++++
 .../ui/coaching-sessions/tiptap-editor.tsx    |  7 +--
 src/styles/code-block.scss                    | 38 +++++++++-----
 src/styles/styles.scss                        | 48 +++++------------
 8 files changed, 130 insertions(+), 71 deletions(-)
 create mode 100644 src/components/ui/coaching-sessions/programming-language-selector.tsx

diff --git a/package-lock.json b/package-lock.json
index 3835d36..39ded47 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -64,6 +64,7 @@
         "eslint": "^8",
         "eslint-config-next": "14.1.0",
         "postcss": "^8",
+        "postcss-import": "^16.1.0",
         "tailwindcss": "^3.3.0",
         "typescript": "^5"
       }
@@ -5840,16 +5841,18 @@
       }
     },
     "node_modules/postcss-import": {
-      "version": "15.1.0",
-      "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
-      "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+      "version": "16.1.0",
+      "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-16.1.0.tgz",
+      "integrity": "sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==",
+      "dev": true,
+      "license": "MIT",
       "dependencies": {
         "postcss-value-parser": "^4.0.0",
         "read-cache": "^1.0.0",
         "resolve": "^1.1.7"
       },
       "engines": {
-        "node": ">=14.0.0"
+        "node": ">=18.0.0"
       },
       "peerDependencies": {
         "postcss": "^8.0.0"
@@ -7009,6 +7012,23 @@
         "tailwindcss": ">=3.0.0 || insiders"
       }
     },
+    "node_modules/tailwindcss/node_modules/postcss-import": {
+      "version": "15.1.0",
+      "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
+      "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+      "license": "MIT",
+      "dependencies": {
+        "postcss-value-parser": "^4.0.0",
+        "read-cache": "^1.0.0",
+        "resolve": "^1.1.7"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.0.0"
+      }
+    },
     "node_modules/tapable": {
       "version": "2.2.1",
       "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
diff --git a/package.json b/package.json
index 3e25f93..824da6b 100644
--- a/package.json
+++ b/package.json
@@ -65,6 +65,7 @@
     "eslint": "^8",
     "eslint-config-next": "14.1.0",
     "postcss": "^8",
+    "postcss-import": "^16.1.0",
     "tailwindcss": "^3.3.0",
     "typescript": "^5"
   }
diff --git a/postcss.config.js b/postcss.config.js
index 12a703d..32bebda 100644
--- a/postcss.config.js
+++ b/postcss.config.js
@@ -1,6 +1,8 @@
 module.exports = {
   plugins: {
+    'postcss-import': {},
     tailwindcss: {},
+    'postcss-nested': {},
     autoprefixer: {},
   },
 };
diff --git a/src/components/ui/coaching-sessions/code-block.tsx b/src/components/ui/coaching-sessions/code-block.tsx
index 6b198f2..8e532b6 100644
--- a/src/components/ui/coaching-sessions/code-block.tsx
+++ b/src/components/ui/coaching-sessions/code-block.tsx
@@ -1,5 +1,6 @@
 import React from "react";
 import { NodeViewProps, NodeViewWrapper, NodeViewContent } from "@tiptap/react";
+import { ProgrammingLanguageSelector } from "./programming-language-selector";
 
 import "@/styles/code-block.scss";
 
@@ -12,23 +13,15 @@ const CodeBlock: React.FC<NodeViewProps> = ({
 
   return (
     <NodeViewWrapper className="code-block">
-      <select
-        contentEditable={false}
-        defaultValue={language}
-        onChange={(event: React.ChangeEvent<HTMLSelectElement>) =>
-          updateAttributes({ language: event.target.value })
-        }
-      >
-        <option value="auto">auto</option>
-        <option disabled>—</option>
-        {extension.options.lowlight
+      <ProgrammingLanguageSelector
+        languages={extension.options.lowlight
           .listLanguages()
-          .map((lang: string, index: number) => (
-            <option key={index} value={lang}>
-              {lang}
-            </option>
-          ))}
-      </select>
+          .map((lang: string, index: number) => lang)}
+        placeholder={language}
+        onSelect={(languageTitle: string) => {
+          updateAttributes({ language: languageTitle });
+        }}
+      ></ProgrammingLanguageSelector>
       <pre>
         <NodeViewContent as="code" />
       </pre>
diff --git a/src/components/ui/coaching-sessions/programming-language-selector.tsx b/src/components/ui/coaching-sessions/programming-language-selector.tsx
new file mode 100644
index 0000000..763ba29
--- /dev/null
+++ b/src/components/ui/coaching-sessions/programming-language-selector.tsx
@@ -0,0 +1,52 @@
+"use client";
+
+import * as React from "react";
+import { PopoverProps } from "@radix-ui/react-popover";
+
+import {
+  Select,
+  SelectContent,
+  SelectGroup,
+  SelectItem,
+  SelectLabel,
+  SelectTrigger,
+  SelectValue,
+} from "@/components/ui/select";
+
+import "@/styles/code-block.scss";
+
+interface ProgrammingLanguageSelectorProps extends PopoverProps {
+  languages: string[];
+  placeholder: string;
+  onSelect: (language: string) => void;
+}
+
+export function ProgrammingLanguageSelector({
+  languages,
+  placeholder,
+  onSelect,
+  ...props
+}: ProgrammingLanguageSelectorProps) {
+  const [selectedLanguage, setSelectedLanguage] =
+    React.useState<string>(placeholder);
+
+  return (
+    <Select
+      onValueChange={(language) => {
+        setSelectedLanguage(language);
+        onSelect(language);
+      }}
+    >
+      <SelectTrigger>
+        <SelectValue placeholder={selectedLanguage}>
+          {selectedLanguage}
+        </SelectValue>
+      </SelectTrigger>
+      <SelectContent>
+        {languages.map((language) => (
+          <SelectItem value={language}>{language}</SelectItem>
+        ))}
+      </SelectContent>
+    </Select>
+  );
+}
diff --git a/src/components/ui/coaching-sessions/tiptap-editor.tsx b/src/components/ui/coaching-sessions/tiptap-editor.tsx
index 4ac881c..29895ed 100644
--- a/src/components/ui/coaching-sessions/tiptap-editor.tsx
+++ b/src/components/ui/coaching-sessions/tiptap-editor.tsx
@@ -23,7 +23,7 @@ import {
   Braces,
 } from "lucide-react";
 import { Button } from "@/components/ui/button";
-import { forwardRef, useImperativeHandle } from "react";
+import { forwardRef, useCallback, useEffect, useImperativeHandle } from "react";
 
 import { EditorRef } from "./coaching-notes";
 
@@ -75,10 +75,7 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
         editorProps: {
           attributes: {
             class:
-              // Make this responsive to light/dark mode
-              // Also is the background what's preventing the codeblock background color from working?
-              // "tiptap ProseMirror",
-              "tiptap ProseMirror shadow appearance-none lg:min-h-[440px] sm:min-h-[200px] md:min-h-[350px] rounded w-full py-2 px-3 bg-inherit text-black text-sm mt-0 md:mt-3 leading-tight focus:outline-none focus:shadow-outline",
+              "tiptap ProseMirror shadow appearance-none lg:min-h-[440px] sm:min-h-[200px] md:min-h-[350px] rounded w-full py-2 px-3 bg-inherit text-black dark:text-white text-sm mt-0 md:mt-3 leading-tight focus:outline-none focus:shadow-outline",
           },
         },
 
diff --git a/src/styles/code-block.scss b/src/styles/code-block.scss
index a63ac30..b54c566 100644
--- a/src/styles/code-block.scss
+++ b/src/styles/code-block.scss
@@ -1,14 +1,28 @@
+@import "tailwindcss/base";
+@import "tailwindcss/components";
+@import "tailwindcss/utilities";
+
 .tiptap {
-    .code-block {
-        position: relative;
-      
-        select {
-          position: absolute;
-          background-color: white;
-          border: round($number: 5);
-          //background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="Black" d="M7 10l5 5 5-5z"/></svg>');
-          right: 0.5rem;
-          top: 0.5rem;
-        }
+  .code-block {
+    position: relative;
+
+    button {
+      // Only show on code-block hover
+      @apply invisible;
+      position: absolute;
+      @apply text-black dark:text-white;
+      @apply bg-white dark:bg-black;
+      height: 1.3rem;
+      width: 8rem;
+      right: 0.5rem;
+      top: 0.5rem;
+    }
+
+    &:hover {
+      button {
+        // Show the button on code-block hover
+        @apply visible;
       }
-  }
\ No newline at end of file
+    }
+  }
+}
diff --git a/src/styles/styles.scss b/src/styles/styles.scss
index 3be1ad2..02601e4 100644
--- a/src/styles/styles.scss
+++ b/src/styles/styles.scss
@@ -1,3 +1,9 @@
+@import "tailwindcss/base";
+@import "tailwindcss/components";
+@import "tailwindcss/utilities";
+
+// Your custom SCSS styles here
+
 /* Basic TipTap editor styles */
 .tiptap {
   :first-child {
@@ -32,7 +38,6 @@
   h5,
   h6 {
     line-height: 1.1;
-    //margin-top: 2.5rem;
     text-wrap: pretty;
   }
 
@@ -51,7 +56,7 @@
   }
 
   h3 {
-    font-size: 1.0rem;
+    font-size: 1rem;
   }
 
   h4,
@@ -61,11 +66,11 @@
   }
 
   pre {
-    background: black;
+    background: rgb(46, 43, 41);
     border-radius: 0.5rem;
     color: white;
     font-family: "JetBrainsMono", monospace;
-    margin: 1.5rem 0;
+    margin: 1.0rem 0;
     padding: 0.75rem 1rem;
 
     code {
@@ -129,36 +134,11 @@
     }
   }
 
-  /* Code and preformatted text styles */
-  // code {
-  //   background-color: var(--purple-light);
-  //   border-radius: 0.4rem;
-  //   color: var(--black);
-  //   font-size: 0.85rem;
-  //   padding: 0.25em 0.3em;
-  // }
-
-  // pre {
-  //     background: var(--black);
-  //     border-radius: 0.5rem;
-  //     color: var(--white);
-  //     font-family: 'JetBrainsMono', monospace;
-  //     margin: 1.5rem 0;
-  //     padding: 0.75rem 1rem;
-
-  //     code {
-  //       background: none;
-  //       color: inherit;
-  //       font-size: 0.8rem;
-  //       padding: 0;
-  //     }
-  //   }
-
-  // blockquote {
-  //   border-left: 3px solid var(--gray-3);
-  //   margin: 1.5rem 0;
-  //   padding-left: 1rem;
-  // }
+  blockquote {
+    border-left: 3px solid var(--gray-3);
+    margin: 1.5rem 0;
+    padding-left: 1rem;
+  }
 
   hr {
     border: none;

From 03744a0622ecdb53b0e30be81af6e79fca4cb9cf Mon Sep 17 00:00:00 2001
From: Jim Hodapp <james.hodapp@gmail.com>
Date: Fri, 18 Oct 2024 11:08:47 -0500
Subject: [PATCH 10/14] Address warnings, no longer user TipTap StarterKit
 extension preferring to explicitly list all extensions used.

---
 .../programming-language-selector.tsx         |  6 ++--
 .../ui/coaching-sessions/tiptap-editor.tsx    | 36 ++++++++++++-------
 2 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/src/components/ui/coaching-sessions/programming-language-selector.tsx b/src/components/ui/coaching-sessions/programming-language-selector.tsx
index 763ba29..52bed72 100644
--- a/src/components/ui/coaching-sessions/programming-language-selector.tsx
+++ b/src/components/ui/coaching-sessions/programming-language-selector.tsx
@@ -43,8 +43,10 @@ export function ProgrammingLanguageSelector({
         </SelectValue>
       </SelectTrigger>
       <SelectContent>
-        {languages.map((language) => (
-          <SelectItem value={language}>{language}</SelectItem>
+        {languages.map((language, index) => (
+          <SelectItem key={index.toString()} value={language}>
+            {language}
+          </SelectItem>
         ))}
       </SelectContent>
     </Select>
diff --git a/src/components/ui/coaching-sessions/tiptap-editor.tsx b/src/components/ui/coaching-sessions/tiptap-editor.tsx
index 29895ed..700a785 100644
--- a/src/components/ui/coaching-sessions/tiptap-editor.tsx
+++ b/src/components/ui/coaching-sessions/tiptap-editor.tsx
@@ -2,20 +2,26 @@
 
 import { useEditor, EditorContent, ReactNodeViewRenderer } from "@tiptap/react";
 
-import StarterKit from "@tiptap/starter-kit";
+import Bold from "@tiptap/extension-bold";
 import BulletList from "@tiptap/extension-bullet-list";
+import Document from "@tiptap/extension-document";
+import Heading from "@tiptap/extension-heading";
 import Highlight from "@tiptap/extension-highlight";
+import Italic from "@tiptap/extension-italic";
 import ListItem from "@tiptap/extension-list-item";
 import OrderedList from "@tiptap/extension-ordered-list";
+import Paragraph from "@tiptap/extension-paragraph";
+import Strike from "@tiptap/extension-strike";
+import Text from "@tiptap/extension-text";
 import Underline from "@tiptap/extension-underline";
 import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
 import {
-  Bold,
+  Bold as BoldIcon,
   Heading1,
   Heading2,
   Heading3,
   Highlighter,
-  Italic,
+  Italic as ItalicIcon,
   Underline as UnderlineIcon,
   List,
   ListOrdered,
@@ -23,7 +29,7 @@ import {
   Braces,
 } from "lucide-react";
 import { Button } from "@/components/ui/button";
-import { forwardRef, useCallback, useEffect, useImperativeHandle } from "react";
+import { forwardRef, useImperativeHandle } from "react";
 
 import { EditorRef } from "./coaching-notes";
 
@@ -56,17 +62,23 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
     const editor = useEditor(
       {
         extensions: [
-          StarterKit,
-          ListItem,
-          Underline,
-          Highlight,
           BulletList,
-          OrderedList,
           CodeBlockLowlight.extend({
             addNodeView() {
               return ReactNodeViewRenderer(CodeBlock);
             },
           }).configure({ lowlight }),
+          Bold,
+          Document,
+          Heading,
+          Highlight,
+          Italic,
+          ListItem,
+          OrderedList,
+          Paragraph,
+          Strike,
+          Text,
+          Underline,
         ],
 
         autofocus: false,
@@ -114,7 +126,7 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
             }`}
             title="Bold (Ctrl+B)"
           >
-            <Bold className="h-4 w-4" />
+            <BoldIcon className="h-4 w-4" />
           </Button>
 
           {/* Italic Button */}
@@ -126,7 +138,7 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
             }`}
             title="Italic (Ctrl+I)"
           >
-            <Italic className="h-4 w-4" />
+            <ItalicIcon className="h-4 w-4" />
           </Button>
 
           {/* Underline Button */}
@@ -136,7 +148,7 @@ const TipTapEditor = forwardRef<EditorRef, TipTapProps>(
             className={`p-2 rounded ${
               editor.isActive("underline") ? "bg-gray-200" : ""
             }`}
-            title="Italic (Ctrl+I)"
+            title="Underline (Ctrl+U)"
           >
             <UnderlineIcon className="h-4 w-4" />
           </Button>

From 0063554adbabbcbab2a0b4b3dbed6c7f92a7d346 Mon Sep 17 00:00:00 2001
From: Jim Hodapp <james.hodapp@gmail.com>
Date: Fri, 18 Oct 2024 11:15:32 -0500
Subject: [PATCH 11/14] Hide unnecessary tabs for MVP feature set.

---
 src/app/coaching-sessions/[id]/page.tsx                     | 4 +++-
 .../ui/coaching-sessions/overarching-goal-container.tsx     | 6 ++++--
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/app/coaching-sessions/[id]/page.tsx b/src/app/coaching-sessions/[id]/page.tsx
index e997151..85b6c8d 100644
--- a/src/app/coaching-sessions/[id]/page.tsx
+++ b/src/app/coaching-sessions/[id]/page.tsx
@@ -180,7 +180,9 @@ export default function CoachingSessionsPage() {
             <Tabs defaultValue="notes">
               <TabsList className="flex w-128 grid-cols-2 justify-start">
                 <TabsTrigger value="notes">Notes</TabsTrigger>
-                <TabsTrigger value="console">Console</TabsTrigger>
+                <TabsTrigger value="console" className="hidden">
+                  Console
+                </TabsTrigger>
                 <TabsTrigger value="coachs_notes" className="hidden">
                   <div className="flex gap-2 items-start">
                     <LockClosedIcon className="mt-1" />
diff --git a/src/components/ui/coaching-sessions/overarching-goal-container.tsx b/src/components/ui/coaching-sessions/overarching-goal-container.tsx
index 767456f..4d6f712 100644
--- a/src/components/ui/coaching-sessions/overarching-goal-container.tsx
+++ b/src/components/ui/coaching-sessions/overarching-goal-container.tsx
@@ -215,10 +215,12 @@ const OverarchingGoalContainer: React.FC<{
               <div className="grid flex-1 items-start gap-4 sm:py-0 md:gap-8">
                 <Tabs defaultValue="agreements">
                   <div className="flex items-center">
-                    <TabsList className="grid grid-cols-3">
+                    <TabsList className="grid grid-cols-2">
                       <TabsTrigger value="agreements">Agreements</TabsTrigger>
                       <TabsTrigger value="actions">Actions</TabsTrigger>
-                      <TabsTrigger value="program">Program</TabsTrigger>
+                      <TabsTrigger value="program" className="hidden">
+                        Program
+                      </TabsTrigger>
                     </TabsList>
                   </div>
                   <TabsContent value="agreements">

From 0c05c897d4f9b550b21a400784645e308167a6b6 Mon Sep 17 00:00:00 2001
From: Jim Hodapp <james.hodapp@gmail.com>
Date: Fri, 18 Oct 2024 11:22:35 -0500
Subject: [PATCH 12/14] Remove unused imports and fix other warning.

---
 .../ui/coaching-sessions/coaching-session-title.tsx      | 9 +--------
 src/types/general.ts                                     | 9 +--------
 2 files changed, 2 insertions(+), 16 deletions(-)

diff --git a/src/components/ui/coaching-sessions/coaching-session-title.tsx b/src/components/ui/coaching-sessions/coaching-session-title.tsx
index c88f11b..d6b3e4a 100644
--- a/src/components/ui/coaching-sessions/coaching-session-title.tsx
+++ b/src/components/ui/coaching-sessions/coaching-session-title.tsx
@@ -7,14 +7,7 @@ import {
   SessionTitle,
   SessionTitleStyle,
 } from "@/types/session-title";
-import {
-  CoachingRelationshipWithUserNames,
-  coachingRelationshipWithUserNamesToString,
-} from "@/types/coaching_relationship_with_user_names";
-import {
-  CoachingSession,
-  coachingSessionToString,
-} from "@/types/coaching-session";
+import { CoachingRelationshipWithUserNames } from "@/types/coaching_relationship_with_user_names";
 import { useAppStateStore } from "@/lib/providers/app-state-store-provider";
 
 const CoachingSessionTitle: React.FC<{
diff --git a/src/types/general.ts b/src/types/general.ts
index 96ed079..85b93f1 100644
--- a/src/types/general.ts
+++ b/src/types/general.ts
@@ -47,12 +47,5 @@ export function actionStatusToString(actionStatus: ItemStatus): string {
 /// return a valid DateTime object instance.
 export function getDateTimeFromString(dateTime: string): DateTime {
   const dt = dateTime.trim();
-  if (dt.length == 0) {
-    console.warn(
-      "Return DateTime.now() since input dateTime string was empty."
-    );
-    return DateTime.now();
-  }
-
-  return DateTime.fromISO(dt);
+  return dt.trim().length > 0 ? DateTime.fromISO(dt) : DateTime.now();
 }

From 7762efcd4aef00419aa7c11b1dc2c29789d40f06 Mon Sep 17 00:00:00 2001
From: Jim Hodapp <james.hodapp@gmail.com>
Date: Fri, 18 Oct 2024 11:26:41 -0500
Subject: [PATCH 13/14] Remove another warning.

---
 src/components/ui/user-nav.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/ui/user-nav.tsx b/src/components/ui/user-nav.tsx
index bf42dfa..1998df3 100644
--- a/src/components/ui/user-nav.tsx
+++ b/src/components/ui/user-nav.tsx
@@ -50,7 +50,7 @@ export function UserNav() {
       <DropdownMenuTrigger asChild>
         <Button variant="ghost" className="relative mx-2 h-8 w-8 rounded-full">
           <Avatar className="h-9 w-9">
-            <AvatarImage src="/avatars/03.png" alt="@jhodapp" />
+            {/* <AvatarImage src="/avatars/03.png" alt="@jhodapp" /> */}
             <AvatarFallback>
               {userFirstLastLettersToString(
                 userSession.first_name,

From bbcff41559ed4cc48edad3801035cab81d8b2a2c Mon Sep 17 00:00:00 2001
From: Jim Hodapp <james.hodapp@gmail.com>
Date: Fri, 18 Oct 2024 12:45:16 -0500
Subject: [PATCH 14/14] Update src/lib/api/notes.ts

Remove commented out line.
---
 src/lib/api/notes.ts | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/lib/api/notes.ts b/src/lib/api/notes.ts
index cd85076..9f1eeb7 100644
--- a/src/lib/api/notes.ts
+++ b/src/lib/api/notes.ts
@@ -81,7 +81,6 @@ export const createNote = async (
   var createdNote: Note = defaultNote();
   var err: string = "";
 
-  //var strNote: string = noteToString(note);
   const data = await axios
     .post(`http://localhost:4000/notes`, newNoteJson, {
       withCredentials: true,