Skip to content

Commit 3bd5c59

Browse files
authored
Merge pull request #13 from acmucsd/website-colab
feat(website): add open in colab link to every notebook
2 parents 19cc8eb + 8a74ff7 commit 3bd5c59

File tree

10 files changed

+119
-11
lines changed

10 files changed

+119
-11
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import s from "./styles.module.scss";
2+
3+
import type { ReactNode } from "react"
4+
5+
interface BeforeMarkdownProps {
6+
children: ReactNode
7+
}
8+
9+
const BeforeMarkdown = ({ children }: BeforeMarkdownProps) => {
10+
return (
11+
<div className={s.wrapper}>
12+
{children}
13+
</div>
14+
)
15+
}
16+
17+
export default BeforeMarkdown
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.wrapper {
2+
margin-bottom: 2rem;
3+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// AUTOGENERATED FILE -- DO NOT EDIT DIRECTLY
2+
declare namespace StylesModuleScssNamespace {
3+
export interface IStylesModuleScss {
4+
wrapper: string;
5+
}
6+
}
7+
8+
declare const StylesModuleScssModule: StylesModuleScssNamespace.IStylesModuleScss;
9+
10+
export = StylesModuleScssModule;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { useMemo } from "react"
2+
import Link from "next/link"
3+
4+
import s from "./styles.module.scss"
5+
6+
const REPO_OWNER = 'acmucsd'
7+
const REPO_NAME = 'acm-ai-workshops'
8+
const DEFAULT_BRANCH = 'main'
9+
const getColabUrl = (fsPath: string[]) => `https://colab.research.google.com/github/${REPO_OWNER}/${REPO_NAME}/blob/${DEFAULT_BRANCH}/${fsPath.map(encodeURIComponent).join('/')}`
10+
11+
interface OpenInColabProps {
12+
fsPath: string[]
13+
}
14+
15+
const OpenInColab = ({ fsPath }: OpenInColabProps) => {
16+
const colabUrl = useMemo(() => getColabUrl(fsPath), [fsPath])
17+
18+
return (
19+
<Link href={colabUrl}><a className={s.link}>
20+
Open in Colab
21+
<svg className={s.external} width="1em" height="1em" viewBox="0 0 48 48" fill="currentColor">
22+
<path d="M36 24c-1.2 0-2 0.8-2 2v12c0 1.2-0.8 2-2 2h-22c-1.2
23+
0-2-0.8-2-2v-22c0-1.2 0.8-2 2-2h12c1.2 0 2-0.8 2-2s-0.8-2-2-2h-12c-3.4
24+
0-6 2.6-6 6v22c0 3.4 2.6 6 6 6h22c3.4 0 6-2.6
25+
6-6v-12c0-1.2-0.8-2-2-2z" />
26+
<path d="M43.8 5.2c-0.2-0.4-0.6-0.8-1-1-0.2-0.2-0.6-0.2-0.8-0.2h-12c-1.2
27+
0-2 0.8-2 2s0.8 2 2 2h7.2l-18.6 18.6c-0.8 0.8-0.8 2 0 2.8 0.4 0.4 0.8
28+
0.6 1.4 0.6s1-0.2 1.4-0.6l18.6-18.6v7.2c0 1.2 0.8 2 2 2s2-0.8
29+
2-2v-12c0-0.2 0-0.6-0.2-0.8z" />
30+
</svg>
31+
</a></Link>
32+
)
33+
}
34+
35+
export default OpenInColab
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
@use "@/styles/colors";
2+
3+
.link {
4+
padding: 0.5rem;
5+
font-weight: 600;
6+
7+
transition: color 400ms ease;
8+
9+
&:hover {
10+
color: colors.$red;
11+
}
12+
}
13+
14+
.external {
15+
display: inline-block;
16+
width: 1em;
17+
height: 1em;
18+
text-align: baseline;
19+
margin-left: 0.25em;
20+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// AUTOGENERATED FILE -- DO NOT EDIT DIRECTLY
2+
declare namespace StylesModuleScssNamespace {
3+
export interface IStylesModuleScss {
4+
external: string;
5+
link: string;
6+
}
7+
}
8+
9+
declare const StylesModuleScssModule: StylesModuleScssNamespace.IStylesModuleScss;
10+
11+
export = StylesModuleScssModule;

website/src/layout/pages/CategoryPage/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import ContentWrapper from "@/layout/components/ContentWrapper";
1010
import ContentContainer from "@/layout/components/ContentContainer";
1111
import CategoryItemsGrid from "@/layout/components/CategoryItemsGrid";
1212

13-
export default function CategoryPage ({ breadcrumb, sidebar, items }: CategoryPageProps) {
13+
export default function CategoryPage ({ slug, sidebar, items }: CategoryPageProps) {
1414
const { asPath } = useRouter()
1515

1616
return (

website/src/layout/pages/DocPage/index.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import SidebarContainer from "@/layout/components/SidebarContainer";
77
import ContentWrapper from "@/layout/components/ContentWrapper";
88
import ContentContainer from "@/layout/components/ContentContainer";
99
import TocContainer from "@/layout/components/TocContainer";
10+
import BeforeMarkdown from "@/layout/components/BeforeMarkdown";
11+
import OpenInColab from "@/layout/components/OpenInColab";
1012
import MarkdownWrapper from "@/layout/components/MarkdownWrapper";
1113
import Navbar from "@/components/Navbar";
1214
import Sidebar from "@/components/Sidebar";
@@ -15,7 +17,7 @@ import components from "@/mdx/components";
1517

1618
import type { DocPageProps } from "@/layout/pages/types";
1719

18-
export default function DocPage ({ breadcrumb, sidebar, code }: DocPageProps) {
20+
export default function DocPage ({ slug, fsPath, sidebar, code }: DocPageProps) {
1921
const { asPath } = useRouter();
2022
const { default: Component, toc } = useMemo(() => getMDXExport(code), [code])
2123

@@ -30,6 +32,9 @@ export default function DocPage ({ breadcrumb, sidebar, code }: DocPageProps) {
3032
<SidebarContainer><Sidebar items={sidebar} activePath={asPath} /></SidebarContainer>
3133
<ContentWrapper>
3234
<ContentContainer>
35+
<BeforeMarkdown>
36+
<OpenInColab fsPath={fsPath} />
37+
</BeforeMarkdown>
3338
<MarkdownWrapper>
3439
<MDXContent />
3540
</MarkdownWrapper>

website/src/layout/pages/types/index.d.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ export type Doc = {
77
title: string;
88
description?: string;
99
href: string;
10+
fsPath: string[];
1011
}
1112

1213
export type Category = {
1314
type: Doc['category'];
1415
title: string;
1516
description?: string;
1617
href: string;
18+
fsPath: string[];
1719
}
1820

1921
export type Item = Doc | Category;
@@ -22,16 +24,19 @@ export interface WithSidebar {
2224
sidebar: SidebarItemType[];
2325
}
2426

25-
export interface WithBreadcrumbs {
26-
breadcrumb: string[];
27-
sidebar: SidebarItemType[];
27+
export interface WithSlug {
28+
slug: string[];
2829
}
2930

3031
export interface WithPath {
3132
path: string;
3233
}
3334

34-
export interface CommonPageProps extends WithSidebar, WithBreadcrumbs {}
35+
export interface WithFsPath {
36+
fsPath: string[];
37+
}
38+
39+
export interface CommonPageProps extends WithSidebar, WithSlug, WithFsPath { }
3540

3641
export interface DocPageProps extends CommonPageProps {
3742
type: Doc['type'];

website/src/pages/workshops/[...slug].tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import { createPipeline } from "@/lib/pipeline";
44
import { workshopsConfig } from "@/lib/pipeline/workshops";
55
import { slugToHref } from "@/utils/slugToHref";
66

7-
import { useRouter } from "next/router";
8-
97
import CategoryPage from "@/layout/pages/CategoryPage";
108
import DocPage from "@/layout/pages/DocPage";
119

@@ -33,13 +31,14 @@ export const getStaticProps: GetStaticProps = async ({ params }) => {
3331
case 'directory':
3432
const flattenedItems = Object.values(entry.items)
3533
.map((entry) => {
36-
const { type, title, description } = (() => {
34+
const { type, title, description, fsPath } = (() => {
3735
switch (entry.type) {
3836
case 'file':
3937
return {
4038
type: 'doc',
4139
title: entry.title,
4240
description: entry.description,
41+
fsPath: entry.fsPath
4342
} as Doc
4443
case 'directory':
4544
const numItems = Object.keys(entry.items).length;
@@ -49,16 +48,18 @@ export const getStaticProps: GetStaticProps = async ({ params }) => {
4948
description: numItems === 1
5049
? `${numItems} item`
5150
: `${numItems} items`,
51+
fsPath: entry.fsPath,
5252
} as Category
5353
}
5454
})();
5555
const href = slugToHref(entry.slug, workshopsConfig.baseUrl);
5656

5757
return {
5858
type,
59-
href,
6059
title,
6160
description,
61+
href,
62+
fsPath,
6263
}
6364
})
6465
;
@@ -75,12 +76,13 @@ export const getStaticProps: GetStaticProps = async ({ params }) => {
7576
title: entry.title,
7677
// source: mdx,
7778
code,
79+
fsPath: entry.fsPath,
7880
} as Omit<DocPageProps, keyof CommonPageProps>
7981
}
8082
})();
8183

8284
const props = {
83-
breadcrumb: slug,
85+
slug,
8486
sidebar,
8587
...uniqueProps,
8688
}

0 commit comments

Comments
 (0)