diff --git a/apps/website/app/(docs)/docs/page.tsx b/apps/website/app/(docs)/docs/page.tsx new file mode 100644 index 000000000..150386013 --- /dev/null +++ b/apps/website/app/(docs)/docs/page.tsx @@ -0,0 +1,33 @@ +import Link from "next/link"; +import Image from "next/image"; + +export default function DocsPage() { + return ( +
+
+

+ Future Home of All the Docs +

+

+ For now, here are the{" "} + + Roam Docs{" "} + +

+
+ +
+
+
+ ); +} diff --git a/apps/website/app/(docs)/docs/roam/[slug]/page.tsx b/apps/website/app/(docs)/docs/roam/[slug]/page.tsx new file mode 100644 index 000000000..15611ada1 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/[slug]/page.tsx @@ -0,0 +1,92 @@ +import fs from "fs/promises"; +import path from "path"; +import { notFound } from "next/navigation"; +import { Metadata } from "next"; +import { DocsHeader } from "~/components/DocsHeader"; +import { Prose } from "~/components/Prose"; +import { collectSections } from "~/utils/sections"; +import { TableOfContents } from "~/components/TableOfContents"; +import { getMarkdownPage } from "~/utils/getMarkdownFile"; + +type Params = { + params: Promise<{ + slug: string; + }>; +}; + +const PATH = "app/(docs)/docs/roam/pages"; +const DIRECTORY = path.join(process.cwd(), PATH); + +export default async function Page({ params }: Params) { + try { + const { slug } = await params; + const { data, contentHtml } = await getMarkdownPage({ + slug, + directory: DIRECTORY, + }); + const tableOfContents = await collectSections(contentHtml); + + return ( + <> +
+
+ + +
+ +
+ {/* */} +
+ + + ); + } catch (error) { + console.error("Error rendering docs page:", error); + return notFound(); + } +} + +export async function generateStaticParams() { + try { + const directoryExists = await fs + .stat(DIRECTORY) + .then((stats) => stats.isDirectory()) + .catch(() => false); + + if (!directoryExists) { + console.log("No docs directory found"); + return []; + } + + const files = await fs.readdir(DIRECTORY); + + return files + .filter((filename) => filename.endsWith(".md")) + .map((filename) => ({ + slug: filename.replace(/\.md$/, ""), + })); + } catch (error) { + console.error("Error generating static params:", error); + return []; + } +} + +export async function generateMetadata({ params }: Params): Promise { + try { + const { slug } = await params; + const { data } = await getMarkdownPage({ + slug, + directory: DIRECTORY, + }); + + return { + title: data.title, + authors: [{ name: data.author }], + }; + } catch (error) { + console.error("Error generating metadata:", error); + return { + title: "Docs", + }; + } +} diff --git a/apps/website/app/(docs)/docs/roam/layout.tsx b/apps/website/app/(docs)/docs/roam/layout.tsx new file mode 100644 index 000000000..14fbc70f5 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/layout.tsx @@ -0,0 +1,10 @@ +import { Layout } from "~/components/Layout"; +import { navigation } from "./navigation"; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return {children}; +} diff --git a/apps/website/app/(docs)/docs/roam/navigation.ts b/apps/website/app/(docs)/docs/roam/navigation.ts new file mode 100644 index 000000000..3f94b2a68 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/navigation.ts @@ -0,0 +1,80 @@ +import { NavigationList } from "~/components/Navigation"; + +const ROOT = "/docs/roam"; + +export const navigation: NavigationList = [ + { + title: "🏠 Welcome!", + links: [ + { title: "Getting Started", href: `${ROOT}/getting-started` }, + { title: "Installation", href: `${ROOT}/installation` }, + ], + }, + { + title: "πŸ—ΊοΈ GUIDES", + links: [ + { + title: "Creating Nodes", + href: `${ROOT}/creating-discourse-nodes`, + }, + { + title: "Creating Relationships", + href: `${ROOT}/creating-discourse-relationships`, + }, + { + title: "Exploring", + href: `${ROOT}/exploring-discourse-graph`, + }, + { + title: "Querying", + href: `${ROOT}/querying-discourse-graph`, + }, + { + title: "Extending", + href: `${ROOT}/extending-personalizing-graph`, + }, + { + title: "Sharing", + href: `${ROOT}/sharing-discourse-graph`, + }, + ], + }, + { + title: "🧱 FUNDAMENTALS", + links: [ + { + title: "What is a Discourse Graph?", + href: `${ROOT}/what-is-discourse-graph`, + }, + { + title: "Grammar", + href: `${ROOT}/grammar`, + }, + ], + }, + { + title: "🚒 USE CASES", + links: [ + { + title: "Literature Reviewing", + href: `${ROOT}/literature-reviewing`, + }, + { + title: "Zettelkasten", + href: `${ROOT}/enhanced-zettelkasten`, + }, + { + title: "Reading Clubs / Seminars", + href: `${ROOT}/reading-clubs`, + }, + { + title: "Lab notebooks", + href: `${ROOT}/lab-notebooks`, + }, + { + title: "Product / Research Roadmapping", + href: `${ROOT}/research-roadmapping`, + }, + ], + }, +]; diff --git a/apps/website/app/(docs)/docs/roam/page.tsx b/apps/website/app/(docs)/docs/roam/page.tsx new file mode 100644 index 000000000..4496ed7bf --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/page.tsx @@ -0,0 +1,13 @@ +import { redirect, notFound } from "next/navigation"; +import { navigation } from "./navigation"; + +export default function Page() { + const firstSection = navigation[0]; + const firstLink = firstSection?.links[0]; + + if (!firstLink?.href) { + notFound(); + } + + redirect(firstLink.href); +} diff --git a/apps/website/app/(docs)/docs/roam/pages/base-grammar.md b/apps/website/app/(docs)/docs/roam/pages/base-grammar.md new file mode 100644 index 000000000..d27acdddb --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/base-grammar.md @@ -0,0 +1,27 @@ +--- +title: "Base Grammar" +date: "2025-01-01" +author: "" +published: true +--- + +## Base grammar + +This is what ships with the extension. + +### Nodes + +- QUE - Question +- CLM - Claim +- EVD - Evidence +- Source + +### Relations + +- EVD Informs QUE +- EVD Supports CLM +- EVD Opposes CLM + +Motivation for this base grammar is described in this [article](https://oasislab.pubpub.org/pub/54t0y9mk/release/3). + +This base grammar may be most useful for projects that interact with empirical evidence where you want to clearly distinguish between theory and evidence, and retain provenance to the source citations if you want to get more context. diff --git a/apps/website/app/(docs)/docs/roam/pages/creating-discourse-nodes.md b/apps/website/app/(docs)/docs/roam/pages/creating-discourse-nodes.md new file mode 100644 index 000000000..04e99fa10 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/creating-discourse-nodes.md @@ -0,0 +1,24 @@ +--- +title: "Creating Discourse Nodes" +date: "2025-01-01" +author: "" +published: true +--- + +The extension makes it easy to factor parts of your notes into formal of a discourse graph (claims, evidence, etc.). + +Steps to create a discourse graph node: + +1. Select the text you want to turn into a formal discourse graph node +2. Press the trigger hotkey (default is `\`) to open up the Node Menu +3. Press the appropriate shortcut key (e.g., E for Evidence) + +The system will create a new page with the text as title, appropriate metadata, and template you have defined. + +## Demo + +https://www.loom.com/share/471fcf7dc13246439cb35feedb110470 + +You can customize the template for specific nodes in the Settings Panel. + +![](/docs/roam/node-template.png) diff --git a/apps/website/app/(docs)/docs/roam/pages/creating-discourse-relationships.md b/apps/website/app/(docs)/docs/roam/pages/creating-discourse-relationships.md new file mode 100644 index 000000000..5d5a76d34 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/creating-discourse-relationships.md @@ -0,0 +1,24 @@ +--- +title: "Creating Discourse Relationships" +date: "2025-01-01" +author: "" +published: true +--- + +One of the main features of the Discourse Graph extension is the ability to **create formal discourse relations between nodes just by writing and outlining!** + +The extension has an in-built [grammar](./grammar) that enables it to recognize when certain patterns of writing and outlining are meant to express particular discourse relations (e.g., support, oppose, inform) between discourse nodes. When it recognizes these patterns, it "writes" them to a formal discourse graph data structure, that you can then use to explore or query your discourse graph. + +## Stock Patterns + +- Take a look at [Relations Patterns](./relations-patterns) + +### Verifying relations + +You can verify any created relations by checking the [discourse context](./discourse-context) of the claim, evidence, or question page. + +Or by running a [query](./querying-discourse-graph) for the specific relation. + +## Digging deeper + +Want to recognize other patterns that aren't listed here? Or don't like these? You can [change them](./extending-personalizing-graph)! But you might first want to [understand how the grammar works](./grammar). diff --git a/apps/website/app/(docs)/docs/roam/pages/discourse-attributes.md b/apps/website/app/(docs)/docs/roam/pages/discourse-attributes.md new file mode 100644 index 000000000..27c95e933 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/discourse-attributes.md @@ -0,0 +1,65 @@ +--- +title: "Discourse Attributes" +date: "2025-01-01" +author: "" +published: true +--- + +- [Discourse Context](./discourse-context) +- [Discourse Context Overlay](./discourse-context-overlay) +- [Discourse Attributes](./discourse-attributes) +- [Node Index](./node-index) + +## Define Discourse Attributes + +You can define discourse attributes that for each discourse node, which compute a numerical "score" for each instance of the node based on its discourse relations to other nodes. In the extension, we call these **discourse attributes**. + +These attributes can be handy for sorting/querying nodes. For instance, if you create a discourse attribute for Claim nodes that is a function of the number of Evidence nodes that Support the Claim, like this: + +![](/docs/roam/settings-discourse-attributes.png) + +You can add discourse attributes as a column to display and sort/filter by when [Querying your discourse graph](./querying-discourse-graph.md) by adding a `Discourse:{label}` selection. + +For example, in the index for Claims, you can return the Evidence attribute as a column (Select), and then sort in descending order by that attribute. + +## Basic Discourse Relation Functions + +A discourse attribute consists of one or more **discourse functions**, joined by one or more math operations. You can think of the discourse functions as variables that get their value from some discourse relations the node participates in. + +Here is the template for each discourse function: `{count:relationName:targetType}` + +- `count` is the operation. Atm, this is the only supported operation for basic discourse functions. We also have experimental discourse functions that operate over the discourse attributes of related nodes (see below), which allow for other operations such as `sum` and `average` +- `relationName` is the name of the relation you want to use for the function, such as `Supported By` or `Informed By` +- `targetType` is the name of the type of target of the relation you want to use for the function (since nodes can have relationships of the same name with multiple other nodes, such as `Supported By:Claim` or `Supported By:Evidence`) + +Here are some examples: + +- `{count:Supported By:Evidence}` +- `{count:Informed By:Source}` +- `{count:Opposed By:Claim}` + +You can use basic math operations to combine multiple discourse functions. For example, you might want to combine information across the supporting and opposing relationships to gauge how "robust" a Claim is, and give different weights to support from evidence vs. claims. You could express it like this: + +`{count:Supported By:Evidence} + {count:Supported By:Claim}*0.5 - {count:Opposed By:Evidence} - {count:Opposed By:Claim}*0.5` + +This function sums up the number of supporting relations and subtracts the number of opposing relations, but gives only half weight (`*0.5`) to supporting/opposing relations from Claims. + +## Compound Discourse Functions + +We have an experimental feature that allows us to access discourse attributes from related nodes to compute a discourse attribute. This allows us to experiment with more sophisticated ways to reason over our discourse nodes. + +For example, if a Claim that only gets direct support from other Claims (e.g., because it is quite general), we might care to distinguish if its supporting Claims are themselves also supported by Evidence. + +If each Claim node has a discourse attribute called Evidence that looks like this: + +`{count:Supported By:Evidence} - {count:Opposed By:Evidence}` + +We can define a compound discourse function that _averages_ over the Evidence attribute of Claims that support the Claim. Like this: + +`{average:Supported By:Claim:Evidence}` + +The syntax for these compound discourse functions is: + +`{operation:relationName:targetType:targetDiscourseAttribute}` + +This generalizes the syntax for the basic discourse functions by adding a discourse attribute to access from the targets, and the option of using additional operations than `count` (for now, we only support `sum` and `average`) for the function. diff --git a/apps/website/app/(docs)/docs/roam/pages/discourse-context-overlay.md b/apps/website/app/(docs)/docs/roam/pages/discourse-context-overlay.md new file mode 100644 index 000000000..d2b4b5991 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/discourse-context-overlay.md @@ -0,0 +1,42 @@ +--- +title: "Discourse Context Overlay" +date: "2025-01-01" +author: "" +published: true +--- + +- [Discourse Context](./discourse-context) +- [Discourse Context Overlay](./discourse-context-overlay) +- [Discourse Attributes](./discourse-attributes) +- [Node Index](./node-index) + +The Discourse Context Overlay adds an icon next to each discourse node wherever it is referenced. This icon provides access to two key features: + +1. a popover to view the [Discourse context](./discourse-context) of the node inline, and +2. a "Discourse Score" component that displays a customizable score for the node that is some function of its relations to other nodes in the discourse graph. + +The overlay is an optional feature that is turned off by default. To turn it on, go to the grammar tab in the config page and check the box for overlay. + +![](/docs/roam/settings-discourse-context-overlay.png) + +## Popover + +The popover is simple to operate. Simply click on the icon to bring up the [discourse context](./discourse-context) component in-line for quick reference. + +![](/docs/roam/discourse-context-overlay.gif) + +## Discourse Score + +By default, the Discourse Score displays the count of the total number of discourse relations for that node (the number on the left), as well as a count of the total number of references to that node in the graph. + +For example, the following score display denotes that the node participates in 5 discourse relations with other nodes, which can be seen in detail in the discourse context popover (1 informs, 1 supports, 2 consistent with, and 1 sourced by; note that 2 of these relations are [custom relations](./extending-personalizing-graph)). + +![](/docs/roam/discourse-context-overlay-score.png) + +You can think of this default Discourse Score as a rough sense of how "robust" a given node is (discourse relations are more structured, high-signal relationships) relative to how "important" it is (raw references are often noisy). If you'd like, you can also experiment with different functions of discourse relations to a node by defining your own [Discourse Attributes](./discourse-attributes), and have them show up in the overlay! + +## Demo + +(old video demo) + +https://www.loom.com/share/b3d6094cd14a466081b8aa8495eb6542 diff --git a/apps/website/app/(docs)/docs/roam/pages/discourse-context.md b/apps/website/app/(docs)/docs/roam/pages/discourse-context.md new file mode 100644 index 000000000..163ca8331 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/discourse-context.md @@ -0,0 +1,25 @@ +--- +title: "Discourse Context" +date: "2025-01-01" +author: "" +published: true +--- + +- [Discourse Context](./discourse-context) +- [Discourse Context Overlay](./discourse-context-overlay) +- [Discourse Attributes](./discourse-attributes) +- [Node Index](./node-index) + +The discourse context component adds a "higher-signal" linked references section to each discourse node, that allows you to explore _discourse_ relations (e.g., inform, support, etc.) between this node and other nodes in your discourse graph. + +## Group by target node + +![](https://oasis-lab.gitbook.io/~gitbook/image?url=https%3A%2F%2F3894211722-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVpoqQNZpk4qG2nMcQUaw%252Fuploads%252FKUFTbmuisbYgKl6y6OYI%252Fd-context%2520group%2520by.gif%3Falt%3Dmedia%26token%3D2e68551f-6872-486d-acc8-afc5d7fd13ef&width=768&dpr=4&quality=100&sign=7ef4ba41&sv=2) + +## Filter results + +![](https://oasis-lab.gitbook.io/~gitbook/image?url=https%3A%2F%2F3894211722-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVpoqQNZpk4qG2nMcQUaw%252Fuploads%252FnL8aiyQwHfSJ80JTcAkC%252Ffilter%2520results.gif%3Falt%3Dmedia%26token%3D422b4351-8e3a-4e8a-8ce1-744463638089&width=768&dpr=4&quality=100&sign=b9a5e3ab&sv=2) + +## Demo + +https://www.loom.com/share/0c66e95d0c71426e8090a8bc1cbf8544 diff --git a/apps/website/app/(docs)/docs/roam/pages/enhanced-zettelkasten.md b/apps/website/app/(docs)/docs/roam/pages/enhanced-zettelkasten.md new file mode 100644 index 000000000..36ba3e2c9 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/enhanced-zettelkasten.md @@ -0,0 +1,12 @@ +--- +title: "Enhanced Zettelkasten" +date: "2025-01-01" +author: "" +published: true +--- + +Maarten Van Doorn has integrated the discourse graph into his take on applying the zettelkasten to his research. + +Here is a video overview: + +[https://www.youtube.com/watch?v=mNzUAICf4Rk](https://www.youtube.com/watch?v=mNzUAICf4Rk) diff --git a/apps/website/app/(docs)/docs/roam/pages/exploring-discourse-graph.md b/apps/website/app/(docs)/docs/roam/pages/exploring-discourse-graph.md new file mode 100644 index 000000000..d4b46da78 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/exploring-discourse-graph.md @@ -0,0 +1,13 @@ +--- +title: "Exploring Your Discourse Graph" +date: "2025-01-01" +author: "" +published: true +--- + +The extension adds features to enable you to seamlessly explore your discourse graph to enhance your thinking. + +- [Discourse Context](./discourse-context) +- [Discourse Context Overlay](./discourse-context-overlay) +- [Discourse Attributes](./discourse-attributes) +- [Node Index](./node-index) diff --git a/apps/website/app/(docs)/docs/roam/pages/extending-personalizing-graph.md b/apps/website/app/(docs)/docs/roam/pages/extending-personalizing-graph.md new file mode 100644 index 000000000..25c602dcd --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/extending-personalizing-graph.md @@ -0,0 +1,24 @@ +--- +title: "Extending and Personalizing Your Discourse Graph" +date: "2025-01-01" +author: "" +published: true +--- + +You can define new nodes and relation patterns to fit your own needs! + +Some users have extended the grammar quite extensively! + +For example, here is a video from a user who extended the grammar to cover structured international law research: + +[https://www.youtube.com/watch?v=rST7cKMO_Ds](https://www.youtube.com/watch?v=rST7cKMO_Ds) + +Others have also extended the grammar to integrate with their primary results from their own experiments, to richly contextualize each new result and experiment with questions shared with past research. + +Detailed instructions coming soon! + +For now, here is a quick demo video of creating an incredibly useful "consistent with" relation pattern that recognizes when any pair of evidence both supports the same thing, implying that they are consistent with each other. + +[https://www.loom.com/share/cb9e526a98764e95a459a6db2b66e46a](https://www.loom.com/share/cb9e526a98764e95a459a6db2b66e46a) + +To extend the grammar, it will likely be useful to [learn more about the fundamentals of the extension's grammar and how it works](./grammar). diff --git a/apps/website/app/(docs)/docs/roam/pages/getting-started.md b/apps/website/app/(docs)/docs/roam/pages/getting-started.md new file mode 100644 index 000000000..e07821574 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/getting-started.md @@ -0,0 +1,32 @@ +--- +title: "Getting Started" +date: "2025-01-01" +author: "" +published: true +--- + +The Discourse Graph extension enables [Roam](https://roamresearch.com/) users to seamlessly add additional semantic structure to their notes, including specified page types and link types that [model scientific discourse](./what-is-discourse-graph), to enable more complex and structured [knowledge synthesis work](https://oasislab.pubpub.org/pub/54t0y9mk/release/3), such as a complex interdisciplinary literature review, and enhanced collaboration with others on this work. + +## Overview + +Here is a relatively brief walkthrough of some of the main features of the extension, including creating discourse nodes and relations, and [using](./exploring-your-discourse-graph), [querying](./querying-your-discourse-graph), and [sharing](./sharing-your-discourse-graph) the discourse graph. This is done in the context of an actual ongoing literature review. + +[https://www.loom.com/share/2ec80422301c451b888b65ee1d283b40](https://www.loom.com/share/2ec80422301c451b888b65ee1d283b40) + +## Guides: Jump right in + +Follow our handy guides to get started on the basics as quickly as possible: + +- [Creating Discourse Nodes](./creating-discourse-nodes) +- [Creating Discourse Relationships](./creating-discourse-relationships) +- [Exploring your Discourse Graph](./exploring-discourse-graph) +- [Querying your Discourse Graph](./querying-discourse-graph) +- [Extending and Personalizing your Discourse Graph](./extending-personalizing-discourse-graph) + +## Fundamentals: Dive a little deeper + +Learn the fundamentals of the Discourse Graph extension to get a deeper understanding of our main features: + +- [What is a Discourse Graph?](./what-is-discourse-graph) +- [The Discourse Graph Extension Grammar](./grammar) +- [The Base Grammar: Questions, Claims, and Evidence](./base-grammar) diff --git a/apps/website/app/(docs)/docs/roam/pages/grammar.md b/apps/website/app/(docs)/docs/roam/pages/grammar.md new file mode 100644 index 000000000..268889614 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/grammar.md @@ -0,0 +1,31 @@ +--- +title: "Extension Grammar" +date: "2025-01-01" +author: "" +published: true +--- + +- [Nodes](./nodes) +- [Operators and Relations](./operators-relations) +- [Relations Patterns](./relations-patterns) +- [Base Grammar](./base-grammar) + +The basic technical intuition behind the extension is that it creates a mapping between the following two elements: + +- **Human-readable, natural writing patterns in Roam** such as pages, blocks, page/block references, and indentation +- **Discourse graph nodes and relations** such as questions, claims, evidence, and relations like support/oppose/inform + +This works because writing in Roam is instantiated as transactions on an underlying [Datomic](https://docs.datomic.com/cloud/whatis/data-model.html) database, queryable via [the Datomic dialect of Datalog](http://www.learndatalogtoday.org/). At it's most basic level, the extension's discourse graph grammar is defined in terms of higher-order combinations of Datalog queries. + +The purpose of this mapping is to make it possible to write and outline as naturally as possible, to help your own thinking, and then have the extension [recognize](./creating-discourse-relationships) (and "make real") the important relationships in your thinking that you have specified, so you and others can build on it in the near or later future as you continue your work. + +For this reason, if you want to better understand how the extension works, and especially if you want to [extend or customize its grammar](./extending-personalizing-graph), it is very useful to get a robust intuition for how Datomic and Datalog work. + +Here are two helpful entry points for this: + +- [https://www.zsolt.blog/2021/01/Roam-Data-Structure-Query.html](https://www.zsolt.blog/2021/01/Roam-Data-Structure-Query.html) +- [http://www.learndatalogtoday.org/](http://www.learndatalogtoday.org/) + +## Relation grammar building blocks + +[Nodes](./nodes) diff --git a/apps/website/app/(docs)/docs/roam/pages/installation.md b/apps/website/app/(docs)/docs/roam/pages/installation.md new file mode 100644 index 000000000..5b8e77e30 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/installation.md @@ -0,0 +1,14 @@ +--- +title: "Installation" +date: "2025-01-01" +author: "" +published: true +--- + +The Discourse Graphs extension can be installed via Roam Depot: + +![](/docs/roam/roam-depot-settings.png) + +![](/docs/roam/roam-depot-settings.png) + +Then type in "Discourse Graphs" in the search bar and click install. diff --git a/apps/website/app/(docs)/docs/roam/pages/lab-notebooks.md b/apps/website/app/(docs)/docs/roam/pages/lab-notebooks.md new file mode 100644 index 000000000..892fd78c5 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/lab-notebooks.md @@ -0,0 +1,8 @@ +--- +title: "Lab Notebooks" +date: "2025-01-01" +author: "" +published: true +--- + +Description coming soon! diff --git a/apps/website/app/(docs)/docs/roam/pages/literature-reviewing.md b/apps/website/app/(docs)/docs/roam/pages/literature-reviewing.md new file mode 100644 index 000000000..7a0cbde73 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/literature-reviewing.md @@ -0,0 +1,14 @@ +--- +title: "Literature Reviewing" +date: "2025-01-01" +author: "" +published: true +--- + +This is currently the most common use case. + +Lukas Kawerau (aka Cortex Futura) has a course that integrates the extension into a complete system for academic literature reviewing and writing: [https://learn.cortexfutura.com/p/cite-to-write-v2](https://learn.cortexfutura.com/p/cite-to-write-v2) + +Lukas gives a short overview of how in this tweet thread: + +[https://x.com/cortexfutura/status/1441795897680011276](https://x.com/cortexfutura/status/1441795897680011276) diff --git a/apps/website/app/(docs)/docs/roam/pages/node-index.md b/apps/website/app/(docs)/docs/roam/pages/node-index.md new file mode 100644 index 000000000..b9a6e57d0 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/node-index.md @@ -0,0 +1,17 @@ +--- +title: "Node Index" +date: "2025-01-01" +author: "" +published: true +--- + +- [Discourse Context](./discourse-context) +- [Discourse Context Overlay](./discourse-context-overlay) +- [Discourse Attributes](./discourse-attributes) +- [Node Index](./node-index) + +The extension has node settings tabs for each node you define, which provides a query over all of your nodes of that type. For example, you can go to the Claim tab to see all the Claim nodes in your graph. + +![](/docs/roam/settings-node-index.png) + +This can be quite handy in multiplayer settings, for example, to quickly view the latest question nodes that have been added to the graph, or who authored them, by modifying the default index query, just like a [regular query](./querying-discourse-graph). diff --git a/apps/website/app/(docs)/docs/roam/pages/nodes.md b/apps/website/app/(docs)/docs/roam/pages/nodes.md new file mode 100644 index 000000000..45743963c --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/nodes.md @@ -0,0 +1,23 @@ +--- +title: "Nodes" +date: "2025-01-01" +author: "" +published: true +--- + +- `discourse node` + + - as defined in your grammar (e.g., base grammar will include CLM or EVD, for example) + +- `block` +- `page` + +It is not possible to directly specify that a source or target node in a relation pattern is a `block` or `page`. These are variables that are defined implicitly at the moment, by what incoming and/or outgoing relations it connects to. + +For example, if a node's incoming relation is `references`, that implies it is a page. Similarly, if the node's incoming relation is `has child` or `has ancestor`, that implies the node is a block. + +When in doubt, check the preview of your relation pattern to ensure you're correctly expressing your intentions! + +## Next + +- [Operators and Relations](./operators-relations) diff --git a/apps/website/app/(docs)/docs/roam/pages/operators-relations.md b/apps/website/app/(docs)/docs/roam/pages/operators-relations.md new file mode 100644 index 000000000..c36957fe4 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/operators-relations.md @@ -0,0 +1,71 @@ +--- +title: "Operators and Relations" +date: "2025-01-01" +author: "" +published: true +--- + +## Roam-native + +### `references` + +- **description**: a block references some page. NOTE: you'll need to then chain that with something like `has title` or `with text` to identify the page. +- **source**: a `block` +- **target**: a `page` +- example: + + - this block references \[\[some page\]\] + +### `is in page` + +- **description**: source is in some page. NOTE: you'll need to then chain that with something like `has title` or `with text` to identify the page. +- **source**: a `block` +- **target**: a `page` + +### `has ancestor` + +- **description**: a block has some ancestor (i.e., the block is in the indentation path of some target, whether directly or indirectly) +- **source**: a `block` +- **target**: a `block` or `page` + +### `has child` + +- **description**: a block or page has some direct child (directly indented underneath) +- **source**: a `block` or `page` +- **target**: a `block` + +### `has descendant` + +- **description**: a block has some descendant (i.e., the target block is in the indentation path of the source, whether directly or indirectly). NOTE: you'll need to then chain that with something like `has title` or `with text` to identify the block. +- **source**: a `block` or `page` +- **target**: a `block` + +### `has title` + +- **description**: source text exactly matches some text +- **source**: a `page`, `block`, or `discourse node` +- **target**: a `string` that specifies the target title to match + +### `with text` + +- **description**: node content contains some text +- **source:** a `page`, `block`, or `discourse node` +- **target**: a `string` that specifies the target text to find in the node content + +### `has attribute` + +- **description**: has a child block with some attribute +- **source**: a `page` or `discourse node` +- **target**: a `string` that specifies the target attribute to be matched + +## Discourse-graph only + +### `is a` + +- **description**: exact match to user-defined `discourse nodes` only (ALTHOUGH the autocomplete will allow you to specify other stuff that don't make sense) +- **source**: a `page` (since all discourse nodes must be pages) +- **target**: a `discourse node` (defined in your grammar) + +## Next + +- [Relations Patterns](./relations-patterns) diff --git a/apps/website/app/(docs)/docs/roam/pages/querying-discourse-graph.md b/apps/website/app/(docs)/docs/roam/pages/querying-discourse-graph.md new file mode 100644 index 000000000..bdc8a669c --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/querying-discourse-graph.md @@ -0,0 +1,66 @@ +--- +title: "Querying Your Discourse Graph" +date: "2025-01-01" +author: "" +published: true +--- + +## Query Drawer + +The query drawer component allows you to construct structured queries over your discourse graph, based on discourse relations (e.g., "find all evidence that supports/opposes a claim"), and reason over the results in a structured, tabular format (e.g., "find all evidence that supports a claim, and allow me to filter/sort by methodological details"). + +### Making a query + +Use Command Palette (⌘+`P` on Mac,`CTRL`\+ `P` otherwise) to access the query drawer. + +![](/docs/roam/command-palette-query-drawer.png) + +A query drawer component will open from the left. From there, you can construct structured queries of your discourse graph and explore their results in a tabular format. + +![](/docs/roam/query-drawer.png) + +## Common Query Examples + +### Evidence that Informs a Question + +![](/docs/roam/query-drawer-informs.png) + +### Evidence that Supports a Claim + +![](/docs/roam/query-drawer-supports.png) + +## Advanced Query Examples + +### Mix discourse and Roam queries + +Example: find all evidence that informs a question, but only if it was collected in a specific location (this example assumes at least some evidence pages have an attribute `Location::` in them) + +![](/docs/roam/query-drawer-advanced.png) + +### Select node attributes to display as attributes of results + +Example: find all evidence that informs a question, and select a methods attribute to display so we can sort/filter on it (this example assumes at least some evidence pages have an attribute `testingRegime::` in them) + +![](/docs/roam/query-drawer-advanced2.png) + +### Select discourse attributes to display as attributes of results + +If you have defined [Discourse Attributes](./discourse-attributes) for the node you want to query, you can select it as a column in your query. The syntax for accessing a node's discourse attribute as a select is`discourse:discourseAttributeName`. + +Example: find all claims and display their "Evidence" discourse attributes (number of supporting evidence relations) as a column. + +![](/docs/roam/query-drawer-advanced3.png) + +## Naming a query + +You can name a query if you like! + +![](/docs/roam/query-drawer-naming.gif) + +## Saving a query to its own page + +You can save a query to its own page if you want to keep it around for easier access. + +![](/docs/roam/query-drawer-save-to-page.png) + +It will be saved to the namespace `discourse-graph/queries/` by default. diff --git a/apps/website/app/(docs)/docs/roam/pages/reading-clubs.md b/apps/website/app/(docs)/docs/roam/pages/reading-clubs.md new file mode 100644 index 000000000..22f945120 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/reading-clubs.md @@ -0,0 +1,10 @@ +--- +title: "Reading Clubs" +date: "2025-01-01" +author: "" +published: true +--- + +Description coming soon! + +[Get in touch](mailto:joechan@umd.edu) if you're interested in joining a Reading Club! diff --git a/apps/website/app/(docs)/docs/roam/pages/relations-patterns.md b/apps/website/app/(docs)/docs/roam/pages/relations-patterns.md new file mode 100644 index 000000000..442f0fa25 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/relations-patterns.md @@ -0,0 +1,54 @@ +--- +title: "Relations and Patterns" +date: "2025-01-01" +author: "" +published: true +--- + +## Stock Patterns + +The extension ships with the ability to recognize three such writing/outlining patterns. Give them a try! + +- [Informed](#question-informed-by-evidence) +- [Supported](#claim-supported-by-evidence) +- [Opposed](#claim-opposed-by-evidence) + +### Question Informed by Evidence + +- Go into a Question page. + +- Create a block, and reference an evidence page. + +Like this: + +![](/docs/roam/relation-informs.png) + +The system now formally recognizes that this piece of evidence **informs** the question (and equivalently, the question is **informed by** that evidence)! + +### Claim Supported by Evidence + +Create a block anywhere, and reference a claim page. We'll call this the claim block. + +Indent a block underneath the claim block. And reference the page `[[SupportedBy]]`. We'll call this the connecting block. + +Indent a block underneath the connecting block. And reference an evidence page. + +Like this: + +![](/docs/roam/relation-supports.png) + +The system now formally recognizes that this piece of evidence **supports** that claim (and equivalently, the claim is **supported by** that evidence)! + +### Claim Opposed by Evidence + +Create a block anywhere and reference a claim page. We'll call this the claim block. + +Indent a block underneath the claim block. And reference the page `[[OpposedBy]]`. We'll call this the connecting block. + +Indent a block underneath the connecting block. And reference an evidence page. + +Like this: + +![](/docs/roam/relation-opposes.png) + +The system now formally recognizes that this piece of evidence **opposes** that claim (and equivalently, the claim is **opposed by** that evidence)! diff --git a/apps/website/app/(docs)/docs/roam/pages/research-roadmapping.md b/apps/website/app/(docs)/docs/roam/pages/research-roadmapping.md new file mode 100644 index 000000000..293bbeafc --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/research-roadmapping.md @@ -0,0 +1,8 @@ +--- +title: "Research Roadmapping" +date: "2025-01-01" +author: "" +published: true +--- + +Description coming soon! diff --git a/apps/website/app/(docs)/docs/roam/pages/sharing-discourse-graph.md b/apps/website/app/(docs)/docs/roam/pages/sharing-discourse-graph.md new file mode 100644 index 000000000..4e8018078 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/sharing-discourse-graph.md @@ -0,0 +1,62 @@ +--- +title: "Sharing Your Discourse Graph" +date: "2025-01-01" +author: "" +published: true +--- + +You can export your discourse graph as a whole, or from queries of your graph, to archive your most important notes, or share them with others. + +The extension exports to a number of formats, select an export option to see the options available. + +![](/docs/roam/command-palette-export.png) + +Demo: + +[https://www.loom.com/share/ca222cb93efb4ed890b4c9e91f05db52](https://www.loom.com/share/ca222cb93efb4ed890b4c9e91f05db52) + +## Export Options + +We have a range of options for customizing the markdown export. These can be found on the `Export` tab of the discourse graph configuration. + +![](/docs/roam/settings-export.png) + +Here is a brief explanation of each option: + +`Max Filename Length` + +- sets the maximum length of the filenames; this is important if you have page names that are quite long and may run afoul of, say, Windows' filename length limit of 250-260 characters. + +`Remove Special Characters` + +- removes all "special characters" that may lead to trouble for filenames in different operating systems, such as `?` (not allowed on Windows) or `/` (denotes file/folder boundaries). + +`Simplified Filename` + +- strips away all "template" characters (i.e., everything except the `{content}` in the node format: for example, if you define a Claim node as `[[CLM]] - {content}`, and have a Claim node `[[[[CLM]] - people are lazy]]`, the exported filename will be `people are lazy` + +`Frontmatter` + +- specifies what properties to add to the YAML. + +- By default, the properties are: + + - `title: {text}` + - `author: {author}` + - `date: {date}` + +- You can add properties as key-value pairs in the same format: + + - ![](/docs/roam/settings-export-frontmatter.png) + +`Resolve Block References` and `Resolve Block Embeds` + +- control whether you want to resolve block references/embeds in your export. You can keep this turned off if you are unsure of the privacy implications of references/embeds. + +`Link Type` + +- controls whether inline page references are wikilinks (`[[like this]]`) or alias (`[like this](pageName.md)`) + +## Example + +Here is an example of a discourse graph exported to Obsidian-compatible markdown: [https://publish.obsidian.md/joelchan-notes](https://publish.obsidian.md/joelchan-notes) diff --git a/apps/website/app/(docs)/docs/roam/pages/what-is-discourse-graph.md b/apps/website/app/(docs)/docs/roam/pages/what-is-discourse-graph.md new file mode 100644 index 000000000..c674c3948 --- /dev/null +++ b/apps/website/app/(docs)/docs/roam/pages/what-is-discourse-graph.md @@ -0,0 +1,20 @@ +--- +title: "What is Discourse Graph" +date: "2025-01-01" +author: "" +published: true +--- + +**Discourse graphs** are an information model for bodies of knowledge that emphasize discourse moves (such as questions, claims, and evidence), and relations (such as support or opposition), rather than papers or sources as the main units. + +To give an intuition for what it is, here is a figure of a visual representation of a simple discourse graph for a body of literature on bans and antisocial behavior in online forums. You may recognize similarities to things like argument maps. + +![](/docs/roam/argument-map.png) + +Consider how that information model foregrounds the conceptual building blocks and relationships that are important for synthesis, compared to a typical "[iTunes for papers](http://joelchan.me/assets/pdf/2019-cscw-beyond-itunes-for-papers.pdf)" model that foregrounds documents in a way that forces us to drudge through [tedious extraction work](https://dl.acm.org/doi/abs/10.1145/3295750.3298937) before we can do the thinking we want to do! + +![](/docs/roam/bans-hate-speech.png) + +This information model (theoretically!) has high potential for augmenting individual and collective "research-grade" synthesis (e.g., lit reviews for a dissertation or grant proposal). + +Discourse graphs are not a new idea (you can read more about it in [this short (academic-focused) write-up](http://joelchan.me/assets/pdf/Discourse_Graphs_for_Augmented_Knowledge_Synthesis_What_and_Why.pdf) or this more [practically-oriented article](https://oasislab.pubpub.org/pub/54t0y9mk/release/3)), but the potential to use it for everyday research work is! diff --git a/apps/website/app/(docs)/layout.tsx b/apps/website/app/(docs)/layout.tsx new file mode 100644 index 000000000..1f2f69e7b --- /dev/null +++ b/apps/website/app/(docs)/layout.tsx @@ -0,0 +1,38 @@ +import { type Metadata } from "next"; +import { Inter } from "next/font/google"; +import clsx from "clsx"; +import { customScrollbar } from "~/components/Layout"; +import { DESCRIPTION } from "~/data/constants"; +import "~/globals.css"; + +const inter = Inter({ + subsets: ["latin"], + display: "swap", + variable: "--font-inter", +}); + +export const metadata: Metadata = { + title: { + template: "%s - Docs", + default: "Discourse Graphs - Documentation", + }, + description: DESCRIPTION, +}; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + +
{children}
+ + + ); +} diff --git a/apps/website/app/(home)/blog/[slug]/page.tsx b/apps/website/app/(home)/blog/[slug]/page.tsx index da837bf1d..6162e7c87 100644 --- a/apps/website/app/(home)/blog/[slug]/page.tsx +++ b/apps/website/app/(home)/blog/[slug]/page.tsx @@ -2,7 +2,8 @@ import fs from "fs/promises"; import path from "path"; import { notFound } from "next/navigation"; import { Metadata } from "next"; -import { getBlog } from "../readBlogs"; +import { getMarkdownPage } from "~/utils/getMarkdownFile"; +import { BLOG_PATH } from "~/data/constants"; type Params = { params: Promise<{ @@ -13,7 +14,10 @@ type Params = { export default async function BlogPost({ params }: Params) { try { const { slug } = await params; - const { data, contentHtml } = await getBlog(slug); + const { data, contentHtml } = await getMarkdownPage({ + slug, + directory: BLOG_PATH, + }); return (
@@ -41,7 +45,7 @@ export default async function BlogPost({ params }: Params) { export async function generateStaticParams() { try { - const blogPath = path.join(process.cwd(), "app/blog/posts"); + const blogPath = path.join(process.cwd(), BLOG_PATH); // 1) Check if the directory exists const directoryExists = await fs .stat(blogPath) @@ -74,7 +78,10 @@ export async function generateStaticParams() { export async function generateMetadata({ params }: Params): Promise { try { const { slug } = await params; - const { data } = await getBlog(slug); + const { data } = await getMarkdownPage({ + slug, + directory: BLOG_PATH, + }); return { title: data.title, diff --git a/apps/website/app/(home)/blog/readBlogs.tsx b/apps/website/app/(home)/blog/readBlogs.tsx index bfaeb3bae..0c3ea7b7b 100644 --- a/apps/website/app/(home)/blog/readBlogs.tsx +++ b/apps/website/app/(home)/blog/readBlogs.tsx @@ -1,12 +1,10 @@ -import { remark } from "remark"; -import html from "remark-html"; -import { notFound } from "next/navigation"; import path from "path"; import fs from "fs/promises"; import matter from "gray-matter"; -import { BlogSchema, type Blog, BlogFrontmatter } from "./schema"; +import { BlogSchema, type Blog } from "./schema"; +import { BLOG_PATH } from "~/data/constants"; -const BLOG_DIRECTORY = path.join(process.cwd(), "app/blog/posts"); +const BLOG_DIRECTORY = path.join(process.cwd(), BLOG_PATH); async function validateBlogDirectory(): Promise { try { @@ -35,11 +33,6 @@ async function processBlogFile(filename: string): Promise { } } -async function getMarkdownContent(content: string): Promise { - const processedContent = await remark().use(html).process(content); - return processedContent.toString(); -} - export async function getAllBlogs(): Promise { try { const directoryExists = await validateBlogDirectory(); @@ -57,31 +50,6 @@ export async function getAllBlogs(): Promise { } } -export async function getBlog( - slug: string, -): Promise<{ data: BlogFrontmatter; contentHtml: string }> { - try { - const filePath = path.join(BLOG_DIRECTORY, `${slug}.md`); - await fs.access(filePath); - - const fileContent = await fs.readFile(filePath, "utf-8"); - const { data: rawData, content } = matter(fileContent); - const data = BlogSchema.parse(rawData); - - if (!data.published) { - console.log(`Post ${slug} is not published`); - return notFound(); - } - - const contentHtml = await getMarkdownContent(content); - - return { data, contentHtml }; - } catch (error) { - console.error("Error loading blog post:", error); - return notFound(); - } -} - export async function getLatestBlogs(): Promise { const blogs = await getAllBlogs(); return blogs diff --git a/apps/website/app/(home)/layout.tsx b/apps/website/app/(home)/layout.tsx index b6ad2c427..26c10585e 100644 --- a/apps/website/app/(home)/layout.tsx +++ b/apps/website/app/(home)/layout.tsx @@ -1,24 +1,26 @@ import type { Metadata } from "next"; import "~/globals.css"; -import { PostHogProvider } from "../providers"; +import { PostHogProvider } from "~/providers"; import Link from "next/link"; -import Image from "next/image"; import { Inter } from "next/font/google"; -import { getAllBlogs } from "~/(home)/blog/readBlogs"; +import { getAllBlogs } from "./blog/readBlogs"; +import { Logo } from "~/components/Logo"; +import { SHORT_DESCRIPTION } from "~/data/constants"; +import { DESCRIPTION } from "~/data/constants"; export const metadata: Metadata = { title: "Discourse Graphs | A Tool for Collaborative Knowledge Synthesis", - description: - "Discourse Graphs are a tool and ecosystem for collaborative knowledge synthesis, enabling researchers to map ideas and arguments in a modular, composable graph format.", + description: DESCRIPTION, + openGraph: { title: "Discourse Graphs", - description: "A tool and ecosystem for collaborative knowledge synthesis", + description: SHORT_DESCRIPTION, type: "website", }, twitter: { card: "summary_large_image", title: "Discourse Graphs", - description: "A tool and ecosystem for collaborative knowledge synthesis", + description: SHORT_DESCRIPTION, }, }; @@ -38,18 +40,7 @@ export default async function RootLayout({ className={`flex min-h-screen flex-col bg-neutral-light ${inter.className}`} >
- - Discourse Graphs Logo - - - Discourse Graphs - - +