From cda70cce355b03583e8375c431d57fe8d991e01c Mon Sep 17 00:00:00 2001 From: Ivan Dimitrov Date: Sun, 12 Nov 2023 14:12:26 +0200 Subject: [PATCH] Squashed commit of the following: commit 263ac7d58539235c9c3762d9bee037449f7099e9 Author: Ivan Dimitrov Date: Sun Nov 12 14:11:50 2023 +0200 touches commit 81f56ab63bd60f27a1d2635673b3834bf31a25da Author: Ivan Dimitrov Date: Sun Nov 12 14:00:41 2023 +0200 writing technical details for the API commit fc90f9b2288b4dc955ece07af43a42979398a3e7 Author: Ivan Dimitrov Date: Sun Nov 12 13:22:15 2023 +0200 code blocks with a copy button commit 9d08417a639cfc5673a2f00cd1fed56b6d640bb0 Author: Ivan Dimitrov Date: Sat Nov 11 21:53:55 2023 +0200 content n sheet --- _content/cases/stepsy.wiki.md | 111 +++++++++++++++++++++++-- bun.lockb | Bin 195967 -> 189055 bytes package.json | 4 +- src/app/c/[...slug]/content.module.css | 12 ++- src/app/c/[...slug]/page.tsx | 21 ++++- src/app/components/cases.tsx | 2 +- src/app/components/code-block.tsx | 40 +++++++++ src/app/globals.css | 4 + tailwind.config.ts | 10 +-- 9 files changed, 179 insertions(+), 25 deletions(-) create mode 100644 src/app/components/code-block.tsx diff --git a/_content/cases/stepsy.wiki.md b/_content/cases/stepsy.wiki.md index 0349747..4312134 100644 --- a/_content/cases/stepsy.wiki.md +++ b/_content/cases/stepsy.wiki.md @@ -6,8 +6,17 @@ date: Jul 29, 2023 - Nov 5, 2023 z: 5 --- -
-Solution +This project aims to be a Google Drive frontend. It uses the Google APIs to fetch document data and display that data in a wiki-style web page. + + +![thumbnail](/thumbnail.png) + + +It supports Google Docs, Google Sheets, Google Slides, PDFs and regular files. + +--- + +### Technical overview I chose NextJS as the backbone for this project as it offers the greatest amount of flexibility while still being very powerful both on the client as well as on the server with an active community and thriving ecosystem. @@ -31,12 +40,100 @@ The UI/UX uses TailwindCSS and DaisyUI to make everything a fast, modern, optimi React was used with TypeScript to provide a nice modern client-side experience between transitions and interactions. This setup supports maximum optimization as you can see in the screenshots below allowing the app to reach a lighthouse score of 100 on all but one (it has 99) pages. Both mobile and desktop is supported. -
- -This project aims to be a Google Drive frontend. It uses the Google APIs to fetch document data and display that data in a wiki-style web page. -![thumbnail](/thumbnail.png) +--- -It supports Google Docs, Google Sheets, Google Slides, PDFs and regular files. +### Google API details + +Configure NextAuth for Google: + +```ts +export default NextAuth({ +... + providers: [ + GoogleProvider({ + clientId: process.env.GOOGLE_CLIENT_ID!, + clientSecret: process.env.GOOGLE_CLIENT_SECRET!, + authorization: { + params: { + access_type: "offline", + prompt: "consent", + scope: "openid profile email https://www.googleapis.com/auth/drive", + }, + }, + }), + ], +... +``` + +Create an auth client for logged in users + +```ts +let authClient = new google.auth.OAuth2( + process.env.GOOGLE_CLIENT_ID, + process.env.GOOGLE_CLIENT_SECRET, +); +authClient.setCredentials({ + access_token: accessToken, // this comes from the logged in user info + refresh_token: refreshToken, // same for this +}); +``` + +or one for anonymous users using a Google service account + +```ts +authClient = new google.auth.JWT({ + email: serviceAccount.client_email, + key: serviceAccount.private_key, + scopes: ["https://www.googleapis.com/auth/drive"], +}); +``` + +Create the drive client + +```ts +const drive = google.drive({ + version: "v3", + auth: authClient, +}); +``` + +You can now use this client to query the API + +```ts +const file = (await drive.files.get({fileId})).data; +``` + +```ts +const folderContents = (await drive.files.list({ q: `'${folderId}' in parents` })) + .data.files; +``` + +```ts +const googleDocHtml = (await drive.files.export({ + fileId: googleDocId, + mimeType: "text/html", +})).data; +``` + +```ts +const shortcutTarget = await drive.files.get({ + fileId, + fields: "shortcutDetails/targetId", +}); +const targetId = shortcutTarget.data.shortcutDetails?.targetId +``` + +Google doesn't export everything to HTML. They provide document renderers as iFrames. + +```tsx + +``` + +```tsx +// This is used for PDFs or regular text files + +``` + diff --git a/bun.lockb b/bun.lockb index d9a9cae2ab4eac89f65c1d3319151d3acc3ab4a4..cfff84b3d22b311b057046322bfe0471a269cb2b 100755 GIT binary patch delta 37867 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 delta 41922 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 mG%zjCd!K^Z)>oSbGK7R0W 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 diff --git a/package.json b/package.json index 97800ad..c80645c 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@fortawesome/free-solid-svg-icons": "^6.4.2", "@fortawesome/react-fontawesome": "latest", "gray-matter": "^4.0.3", + "highlight.js": "^11.9.0", "next": "latest", "react": "latest", "react-dom": "latest", @@ -23,8 +24,7 @@ "rehype-highlight": "^7.0.0", "rehype-raw": "^7.0.0", "remark-frontmatter": "^5.0.0", - "remark-gfm": "^4.0.0", - "tailwind-highlightjs": "^2.0.1" + "remark-gfm": "^4.0.0" }, "devDependencies": { "typescript": "latest", diff --git a/src/app/c/[...slug]/content.module.css b/src/app/c/[...slug]/content.module.css index 2b55e18..54cbbbc 100644 --- a/src/app/c/[...slug]/content.module.css +++ b/src/app/c/[...slug]/content.module.css @@ -1,3 +1,7 @@ +.md * { + @apply py-2 +} + .md ol { @apply list-decimal list-inside } @@ -5,6 +9,10 @@ @apply list-disc list-inside } +.md hr { + @apply m-4 +} + .md blockquote { @apply border-l-neutral-500 border-l-4 p-2 } @@ -17,8 +25,8 @@ @apply p-20 } -.md details * { - @apply p-2 +.md code { + @apply rounded-lg } .md h1 { diff --git a/src/app/c/[...slug]/page.tsx b/src/app/c/[...slug]/page.tsx index 11f0ad6..6843292 100644 --- a/src/app/c/[...slug]/page.tsx +++ b/src/app/c/[...slug]/page.tsx @@ -1,12 +1,15 @@ +import "highlight.js/styles/github-dark.css" +import styles from "./content.module.css" import { getAllPaths, getContent } from "$lib/content"; import Markdown from "react-markdown"; import remarkGfm from "remark-gfm"; import remarkFrontmatter from "remark-frontmatter"; -import styles from "./content.module.css" import Image from "next/image"; import rehypeRaw from "rehype-raw"; import rehypeHighlight from "rehype-highlight"; import { notFound } from "next/navigation"; +import Link from "next/link"; +import CodeBlock from "$components/code-block"; type Params = { slug: string[] @@ -58,12 +61,22 @@ export default function Content({ params }: Props) { remarkPlugins={[remarkGfm, remarkFrontmatter]} rehypePlugins={[rehypeRaw, rehypeHighlight]} components={{ - img({ height, width, src, alt }) { + img({ height, width, src, alt, className }) { return ( - {alt!} + {alt!} ) + }, + a({ href, children, className }) { + return ( + {children} + ) + }, + pre({ children, className }) { + return ( + + ) } }} > @@ -72,7 +85,7 @@ export default function Content({ params }: Props) { return (

-
+
{title()} {goal()} {role()} diff --git a/src/app/components/cases.tsx b/src/app/components/cases.tsx index 42f9abf..ad53d50 100644 --- a/src/app/components/cases.tsx +++ b/src/app/components/cases.tsx @@ -4,7 +4,7 @@ import { getCases } from "../lib/content"; const Cases = () =>
{getCases().filter(c => !c.data.draft).sort(c => Number(c.data.z)).reverse().map((c) => c.data).map((d) => -
+
{d.title} {d.date} diff --git a/src/app/components/code-block.tsx b/src/app/components/code-block.tsx new file mode 100644 index 0000000..5fcba8a --- /dev/null +++ b/src/app/components/code-block.tsx @@ -0,0 +1,40 @@ +"use client" +import { faCheck, faCopy } from "@fortawesome/free-solid-svg-icons" +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" +import { ReactNode, useState } from "react" + +type Props = { + className?: string + children?: ReactNode +} + +const getText = (node: any) => { + const props = node.props + if (!props) { + return node + } + const c = props.children + return typeof c === "string" ? c : c.map(getText).join("") +} + +const CodeBlock = ({ className, children }: Props) => { + const [visible, setVisible] = useState("invisible") + return ( +
+ +
{children}
+
+ ) +} + +export default CodeBlock; diff --git a/src/app/globals.css b/src/app/globals.css index da968af..16d3fbd 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -10,6 +10,10 @@ main { @apply flex flex-col w-full h-full } +main * { + @apply border-amber-50 +} + svg { @apply w-14 h-14 text-amber-100 hover:text-cyan-500 } diff --git a/tailwind.config.ts b/tailwind.config.ts index 0d293a4..b27a408 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -6,14 +6,6 @@ const config: Config = { './src/components/**/*.{js,ts,jsx,tsx,mdx}', './src/app/**/*.{js,ts,jsx,tsx,mdx}', ], - safelist: [{ - pattern: /hljs+/, - }], - theme: { - hljs: { - theme: 'night-owl', - }, - }, - plugins: [require('tailwind-highlightjs')], + plugins: [], } export default config