-
Notifications
You must be signed in to change notification settings - Fork 4
ENG-1605: Initial skeleton website/layout #934
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
sid597
wants to merge
10
commits into
main
Choose a base branch
from
eng-1605-initial-skeleton-websitelayout
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
4da613e
[ENG-1605] Add /extract-nodes skeleton page
sid597 91d5560
Remove @repo/ui/globals.css import from extract layout
sid597 07e6c20
Address review: remove nested html/body, align tab counts
sid597 f9e4493
Rename sectionLabelClass to SECTION_LABEL_CLASS
sid597 22e6b65
Use shadcn components and correct node types from ontology
sid597 ede441f
Fix eslint and prettier for shadcn components
sid597 c092e41
Colocate data in components, use full contract shapes
sid597 624b3fd
All types checked, sample for each type, 2 cards expanded
sid597 1fde9ae
Restore shadcn Button with custom color overrides
sid597 c6b8f64
Use shadcn everywhere, colored pills only on result cards
sid597 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
230 changes: 230 additions & 0 deletions
230
apps/website/app/(extract)/extract-nodes/components/MainContent.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,230 @@ | ||
| import { Badge } from "@repo/ui/components/ui/badge"; | ||
| import { Button } from "@repo/ui/components/ui/button"; | ||
| import { Card, CardContent } from "@repo/ui/components/ui/card"; | ||
| import { Checkbox } from "@repo/ui/components/ui/checkbox"; | ||
| import { Copy } from "lucide-react"; | ||
|
|
||
| const NODE_TYPE_COLORS: Record<string, string> = { | ||
| claim: "#7DA13E", | ||
| question: "#99890E", | ||
| hypothesis: "#7C4DFF", | ||
| evidence: "#dc0c4a", | ||
| result: "#E6A23C", | ||
| source: "#9E9E9E", | ||
| theory: "#8B5CF6", | ||
| }; | ||
|
|
||
| const SAMPLE_NODES = [ | ||
| { | ||
| nodeType: "claim", | ||
| content: | ||
| "Basolateral secretion of Wnt5a is essential for establishing apical-basal polarity in epithelial cells.", | ||
| supportSnippet: | ||
| '"Wnt5a secreted from the basolateral surface was both necessary and sufficient for the establishment of apical-basal polarity" (p.9)', | ||
| sourceSection: "Discussion", | ||
| }, | ||
| { | ||
| nodeType: "evidence", | ||
| content: | ||
| "Wnt5a was detected exclusively in the basolateral medium of polarized MDCK cells grown on Transwell filters, with no detectable signal in the apical fraction.", | ||
| supportSnippet: | ||
| '"Western blot analysis of conditioned media showed Wnt5a protein exclusively in the basolateral fraction (Fig. 2A, lanes 3-4)"', | ||
| sourceSection: "Results", | ||
| }, | ||
| { | ||
| nodeType: "question", | ||
| content: | ||
| "What is the mechanism by which Wnt5a polarized secretion is directed to the basolateral membrane?", | ||
| supportSnippet: | ||
| '"The mechanism that directs Wnt5a specifically to the basolateral surface remains an open question" (p.11)', | ||
| sourceSection: "Discussion", | ||
| }, | ||
| { | ||
| nodeType: "hypothesis", | ||
| content: | ||
| "Ror2 receptor activation at the basolateral surface mediates Wnt5a-dependent lumen positioning.", | ||
| supportSnippet: | ||
| '"We hypothesize that Ror2, as the primary receptor for Wnt5a at the basolateral membrane, transduces the polarity signal required for single-lumen formation"', | ||
| sourceSection: "Discussion", | ||
| }, | ||
| { | ||
| nodeType: "result", | ||
| content: | ||
| "shRNA-mediated knockdown of Wnt5a resulted in multi-lumen cysts in 68% of colonies compared to 12% in control conditions.", | ||
| supportSnippet: | ||
| '"Quantification of cyst morphology revealed 68 ± 4% multi-lumen cysts in Wnt5a-KD versus 12 ± 3% in controls (Fig. 4B, p < 0.001)"', | ||
| sourceSection: "Results", | ||
| }, | ||
| { | ||
| nodeType: "source", | ||
| content: "Yamamoto et al. (2015) Nature Cell Biology 17(8):1024-1035", | ||
| supportSnippet: | ||
| "Primary research article on Wnt5a basolateral secretion and lumen formation in polarized epithelia.", | ||
| sourceSection: "References", | ||
| }, | ||
| { | ||
| nodeType: "theory", | ||
| content: | ||
| "Non-canonical Wnt signaling through the planar cell polarity pathway is a conserved mechanism for epithelial lumen morphogenesis.", | ||
| supportSnippet: | ||
| '"Our findings place Wnt5a upstream of the PCP pathway in the regulation of epithelial lumen morphogenesis, consistent with the broader role of non-canonical Wnt signaling in tissue polarity"', | ||
| sourceSection: "Discussion", | ||
| }, | ||
| { | ||
| nodeType: "evidence", | ||
| content: | ||
| "Co-immunoprecipitation showed that Wnt5a preferentially binds Ror2 receptor at the basolateral surface.", | ||
| supportSnippet: | ||
| '"IP-Western analysis demonstrated direct Wnt5a-Ror2 interaction in basolateral but not apical membrane fractions (Fig. 5C)"', | ||
| sourceSection: "Results", | ||
| }, | ||
| { | ||
| nodeType: "claim", | ||
| content: | ||
| "Loss of Wnt5a function disrupts lumen formation in 3D cyst cultures derived from epithelial cells.", | ||
| supportSnippet: | ||
| '"These data demonstrate that Wnt5a is required for proper lumen formation in three-dimensional culture systems"', | ||
| sourceSection: "Discussion", | ||
| }, | ||
| ]; | ||
|
|
||
| const EXPANDED_INDICES = new Set([0, 1]); | ||
|
|
||
| const typeCounts = SAMPLE_NODES.reduce<Record<string, number>>((acc, node) => { | ||
| acc[node.nodeType] = (acc[node.nodeType] ?? 0) + 1; | ||
| return acc; | ||
| }, {}); | ||
|
|
||
| const TABS = [ | ||
| { id: "all", label: "All", count: SAMPLE_NODES.length, color: undefined }, | ||
| ...Object.entries(typeCounts).map(([nodeType, count]) => ({ | ||
| id: nodeType, | ||
| label: nodeType.charAt(0).toUpperCase() + nodeType.slice(1), | ||
| count, | ||
| color: NODE_TYPE_COLORS[nodeType], | ||
| })), | ||
| ]; | ||
|
|
||
| // eslint-disable-next-line @typescript-eslint/naming-convention | ||
| export const MainContent = () => { | ||
sid597 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return ( | ||
| <section className="flex min-h-[420px] flex-1 overflow-hidden rounded-[24px] border border-slate-200/85 bg-white shadow-[0_24px_48px_-36px_rgba(15,23,42,0.55)]"> | ||
| <div className="flex flex-1 flex-col overflow-hidden bg-[linear-gradient(180deg,#ffffff_0%,#f8fafc_100%)]"> | ||
| <div className="relative shrink-0 border-b border-slate-200/80 bg-[linear-gradient(135deg,#ffffff_0%,#f8fbff_100%)] px-4 py-4 lg:px-5"> | ||
| <div className="absolute inset-x-0 top-0 h-[2px] bg-[linear-gradient(90deg,#0ea5e9_0%,#22d3ee_45%,#34d399_100%)]" /> | ||
| <h2 className="text-[24px] font-semibold tracking-[-0.024em] text-slate-900"> | ||
| Basolateral secretion of Wnt5a in polarized epithelial cells is | ||
| required for apical lumen formation | ||
| </h2> | ||
| <p className="mt-1 text-[15px] text-slate-500"> | ||
| Yamamoto H, Komekado H, Kikuchi A | ||
| </p> | ||
| </div> | ||
|
|
||
| <div className="shrink-0 border-b border-slate-200/70 bg-white/95 px-4 lg:px-5"> | ||
| <div className="flex gap-1 py-2"> | ||
| {TABS.map((tab) => ( | ||
| <Badge | ||
| key={tab.id} | ||
| variant={tab.id === "all" ? "default" : "outline"} | ||
| className={ | ||
| tab.id === "all" | ||
| ? "bg-slate-900 px-3 py-1.5 text-[14px] font-semibold text-white hover:bg-slate-800" | ||
| : "px-3 py-1.5 text-[14px] font-semibold text-slate-600" | ||
| } | ||
| > | ||
| {tab.color && ( | ||
| <span | ||
| className="mr-1.5 inline-block h-2 w-2 rounded-full" | ||
| style={{ backgroundColor: tab.color }} | ||
| /> | ||
| )} | ||
| {tab.label} {tab.count} | ||
| </Badge> | ||
| ))} | ||
| </div> | ||
| </div> | ||
|
|
||
| <div className="flex-1 overflow-y-auto bg-[radial-gradient(120%_100%_at_50%_0%,#f8fbff_0%,#f8fafc_52%,#f3f7fb_100%)] p-4 lg:p-5"> | ||
| <div className="space-y-2.5"> | ||
| {SAMPLE_NODES.map((node, index) => { | ||
| const color = NODE_TYPE_COLORS[node.nodeType] ?? "#64748b"; | ||
| const isExpanded = EXPANDED_INDICES.has(index); | ||
| return ( | ||
| <Card key={index} className="rounded-2xl border-slate-200/85"> | ||
| <CardContent className="p-4"> | ||
| <div className="flex items-start gap-3"> | ||
| <Checkbox checked className="mt-1" /> | ||
| <div className="min-w-0 flex-1"> | ||
| <div className="mb-2 flex flex-wrap items-center gap-2"> | ||
| <span | ||
| className="rounded px-1.5 py-0.5 text-[11px] font-bold uppercase tracking-wider text-white" | ||
| style={{ backgroundColor: color }} | ||
| > | ||
| {node.nodeType} | ||
| </span> | ||
| {node.sourceSection && ( | ||
| <span className="text-[13px] text-slate-400"> | ||
| {node.sourceSection} | ||
| </span> | ||
| )} | ||
| </div> | ||
| <p className="text-[15px] leading-relaxed text-slate-800"> | ||
| {node.content} | ||
| </p> | ||
| {isExpanded ? ( | ||
| <> | ||
| <div className="mt-2 rounded-lg bg-slate-50 px-3 py-2"> | ||
| <p className="text-[13px] italic leading-relaxed text-slate-500"> | ||
| {node.supportSnippet} | ||
| </p> | ||
| </div> | ||
| <Button | ||
| variant="ghost" | ||
| size="sm" | ||
| className="mt-1 h-auto p-0 text-[13px] font-medium text-slate-400 hover:text-slate-600" | ||
| > | ||
| Hide details | ||
| </Button> | ||
| </> | ||
| ) : ( | ||
| <Button | ||
| variant="ghost" | ||
| size="sm" | ||
| className="mt-1 h-auto p-0 text-[13px] font-medium text-slate-400 hover:text-slate-600" | ||
| > | ||
| Show details | ||
| </Button> | ||
| )} | ||
| </div> | ||
| </div> | ||
| </CardContent> | ||
| </Card> | ||
| ); | ||
| })} | ||
| </div> | ||
| </div> | ||
|
|
||
| <div className="flex shrink-0 flex-col gap-3 border-t border-slate-200/85 bg-white/95 px-4 py-3.5 backdrop-blur sm:flex-row sm:items-center sm:justify-between lg:px-5"> | ||
| <div className="flex items-center gap-2.5"> | ||
| <Button | ||
| variant="outline" | ||
| size="sm" | ||
| className="rounded-full border-slate-200 text-slate-600" | ||
| > | ||
| Deselect All | ||
| </Button> | ||
| <span className="text-[14px] font-medium tabular-nums text-slate-500"> | ||
| {SAMPLE_NODES.length} of {SAMPLE_NODES.length} selected | ||
| </span> | ||
| </div> | ||
|
|
||
| <Button className="gap-2 rounded-full bg-slate-900 text-white hover:bg-slate-800"> | ||
| <Copy className="h-4 w-4" /> | ||
| Copy to Clipboard | ||
| </Button> | ||
| </div> | ||
| </div> | ||
| </section> | ||
| ); | ||
| }; | ||
145 changes: 145 additions & 0 deletions
145
apps/website/app/(extract)/extract-nodes/components/Sidebar.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| import { Button } from "@repo/ui/components/ui/button"; | ||
| import { Checkbox } from "@repo/ui/components/ui/checkbox"; | ||
| import { ChevronDown } from "lucide-react"; | ||
|
|
||
| const NODE_TYPES = [ | ||
| { | ||
| label: "Claim", | ||
| description: | ||
| "An assertion about how something works or should work. Usually a single declarative sentence.", | ||
| candidateTag: "#clm-candidate", | ||
| color: "#7DA13E", | ||
| }, | ||
| { | ||
| label: "Question", | ||
| description: | ||
| "An unknown being explored through research. Framed as a question that can be investigated.", | ||
| candidateTag: "#que-candidate", | ||
| color: "#99890E", | ||
| }, | ||
| { | ||
| label: "Hypothesis", | ||
| description: | ||
| "A proposed answer to a question. Collects evidence for or against.", | ||
| candidateTag: "#hyp-candidate", | ||
| color: "#7C4DFF", | ||
| }, | ||
| { | ||
| label: "Evidence", | ||
| description: | ||
| "A discrete observation from a published dataset or experiment. Usually in past tense with observable, model system, and method.", | ||
| candidateTag: "#evd-candidate", | ||
| color: "#dc0c4a", | ||
| }, | ||
| { | ||
| label: "Result", | ||
| description: | ||
| "A discrete observation from ongoing research, in past tense. Includes source context.", | ||
| candidateTag: "#res-candidate", | ||
| color: "#E6A23C", | ||
| }, | ||
| { | ||
| label: "Source", | ||
| description: "A referenced publication or external resource.", | ||
| candidateTag: "#src-candidate", | ||
| color: "#9E9E9E", | ||
| }, | ||
| { | ||
| label: "Theory", | ||
| description: "A theoretical framework or model that explains phenomena.", | ||
| candidateTag: "#the-candidate", | ||
| color: "#8B5CF6", | ||
| }, | ||
| ]; | ||
|
|
||
| const SECTION_LABEL_CLASS = | ||
| "mb-3 block px-1 text-[18px] font-semibold tracking-[-0.016em] text-slate-800"; | ||
|
|
||
| // eslint-disable-next-line @typescript-eslint/naming-convention | ||
| export const Sidebar = () => { | ||
sid597 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return ( | ||
| <aside className="flex w-full shrink-0 flex-col overflow-hidden rounded-[24px] border border-slate-200/85 bg-white shadow-[0_26px_52px_-38px_rgba(15,23,42,0.6)] lg:w-[390px] xl:w-[420px]"> | ||
| <div className="flex-1 overflow-y-auto p-4 lg:p-5"> | ||
| <section className="mb-6"> | ||
| <h3 className={SECTION_LABEL_CLASS}>Paper</h3> | ||
| <div className="flex w-full items-start gap-3 rounded-2xl border border-slate-200 bg-white p-3.5"> | ||
| <div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-gradient-to-b from-rose-500 to-rose-600"> | ||
| <span className="text-[11px] font-bold tracking-[0.02em] text-white"> | ||
| </span> | ||
| </div> | ||
| <div className="min-w-0 flex-1 pt-0.5"> | ||
| <p className="truncate text-[16px] font-semibold leading-tight text-slate-900"> | ||
| Yamamoto et al. - 2015 - Basolate... | ||
| </p> | ||
| <p className="mt-1 text-[14px] leading-tight text-slate-500"> | ||
| 7.8 MB ·{" "} | ||
| <span className="font-medium text-slate-500">Replace file</span> | ||
| </p> | ||
| </div> | ||
| </div> | ||
| </section> | ||
|
|
||
| <section className="mb-6"> | ||
| <h3 className={SECTION_LABEL_CLASS}>Model</h3> | ||
| <Button | ||
| variant="outline" | ||
| className="w-full justify-between rounded-xl border-slate-300 px-3.5 py-3 text-[16px] font-medium text-slate-700" | ||
| > | ||
| <span>Claude Sonnet 4.6</span> | ||
| <ChevronDown className="h-4 w-4 text-slate-500" /> | ||
| </Button> | ||
| </section> | ||
|
|
||
| <section className="mb-5"> | ||
| <h3 className={SECTION_LABEL_CLASS}>Research Question</h3> | ||
| <div className="w-full rounded-xl border border-slate-300 bg-white px-3.5 py-3 text-[16px] text-slate-700"> | ||
| What are the molecular determinants of lumenoid formation in hiPSCs? | ||
| </div> | ||
| </section> | ||
|
|
||
| <div className="mx-1 mb-5 border-t border-slate-200" /> | ||
|
|
||
| <section> | ||
| <div className="mb-2.5 flex items-center justify-between px-1"> | ||
| <h3 className="text-[18px] font-semibold tracking-[-0.016em] text-slate-800"> | ||
| Node Types | ||
| </h3> | ||
| <span className="text-[13px] font-semibold tabular-nums text-slate-500"> | ||
| {NODE_TYPES.length}/{NODE_TYPES.length} | ||
| </span> | ||
| </div> | ||
|
|
||
| <div className="space-y-1.5"> | ||
| {NODE_TYPES.map((type) => ( | ||
| <label | ||
| key={type.candidateTag} | ||
| className="flex w-full cursor-pointer items-center gap-2.5 rounded-xl border border-slate-200 bg-white px-2.5 py-2 text-slate-800 shadow-sm" | ||
| > | ||
| <Checkbox checked /> | ||
| <div className="min-w-0 flex-1"> | ||
| <span className="text-[16px] font-medium">{type.label}</span> | ||
| <p className="truncate text-[12px] text-slate-400"> | ||
| {type.description} | ||
| </p> | ||
| </div> | ||
| <span className="shrink-0 text-[11px] font-medium text-slate-400"> | ||
| {type.candidateTag} | ||
| </span> | ||
| </label> | ||
| ))} | ||
| </div> | ||
| </section> | ||
| </div> | ||
|
|
||
| <div className="border-t border-slate-200/90 bg-white/95 p-4 backdrop-blur-xl"> | ||
| <p className="mb-2 text-[14px] font-medium text-slate-500"> | ||
| Ready to run extraction. | ||
| </p> | ||
| <Button className="w-full rounded-xl bg-slate-900 py-6 text-[17px] font-semibold text-white hover:bg-slate-800"> | ||
| Re-Extract | ||
| </Button> | ||
| </div> | ||
| </aside> | ||
| ); | ||
| }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { MainContent } from "./components/MainContent"; | ||
| import { Sidebar } from "./components/Sidebar"; | ||
|
|
||
| const ExtractNodesPage = () => { | ||
sid597 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return ( | ||
| <div className="flex h-full w-full flex-1 flex-col gap-4 p-4 lg:flex-row lg:gap-5 lg:p-5"> | ||
| <Sidebar /> | ||
| <MainContent /> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default ExtractNodesPage; | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.