From 60f2ab99b3884045f3c2e8a94cebc4d39e011b95 Mon Sep 17 00:00:00 2001 From: Max Leiter Date: Wed, 23 Mar 2022 15:42:22 -0700 Subject: [PATCH] client: lint with useTabs --- client/.prettierrc | 3 +- client/components/new-post/title/index.tsx | 2 +- client/lib/generate-uuid.ts | 74 ++++++++++---------- client/lib/get-post-path.ts | 18 ++--- client/lib/hooks/use-shared-state.ts | 8 +-- client/lib/hooks/use-signed-in.ts | 46 ++++++------- client/lib/hooks/use-theme.ts | 34 ++++----- client/lib/hooks/use-trace-route.ts | 26 +++---- client/lib/time-ago.ts | 50 +++++++------- client/lib/types.d.ts | 28 ++++---- client/pages/api/markdown/[id].ts | 80 +++++++++++----------- client/pages/api/raw/[id].ts | 50 +++++++------- client/pages/api/render-markdown.ts | 62 ++++++++--------- 13 files changed, 241 insertions(+), 240 deletions(-) diff --git a/client/.prettierrc b/client/.prettierrc index c424cfdc..cda1eceb 100644 --- a/client/.prettierrc +++ b/client/.prettierrc @@ -2,5 +2,6 @@ "semi": false, "trailingComma": "none", "singleQuote": false, - "printWidth": 80 + "printWidth": 80, + "useTabs": true } diff --git a/client/components/new-post/title/index.tsx b/client/components/new-post/title/index.tsx index 9d4c453c..001752fa 100644 --- a/client/components/new-post/title/index.tsx +++ b/client/components/new-post/title/index.tsx @@ -1,4 +1,4 @@ -import { ChangeEvent, memo, useCallback, useEffect, useState } from 'react' +import { ChangeEvent, memo, useEffect, useState } from 'react' import { Text } from '@geist-ui/core' import ShiftBy from '@components/shift-by' diff --git a/client/lib/generate-uuid.ts b/client/lib/generate-uuid.ts index b207aa0e..9083f37f 100644 --- a/client/lib/generate-uuid.ts +++ b/client/lib/generate-uuid.ts @@ -1,39 +1,39 @@ export default function generateUUID() { - if (typeof crypto === "object") { - if (typeof crypto.randomUUID === "function") { - // https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID - return crypto.randomUUID() - } - if ( - typeof crypto.getRandomValues === "function" && - typeof Uint8Array === "function" - ) { - // https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid - const callback = (c: string) => { - const num = Number(c) - return ( - num ^ - (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (num / 4))) - ).toString(16) - } - return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, callback) - } - } - let timestamp = new Date().getTime() - let perforNow = - (typeof performance !== "undefined" && - performance.now && - performance.now() * 1000) || - 0 - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { - let random = Math.random() * 16 - if (timestamp > 0) { - random = (timestamp + random) % 16 | 0 - timestamp = Math.floor(timestamp / 16) - } else { - random = (perforNow + random) % 16 | 0 - perforNow = Math.floor(perforNow / 16) - } - return (c === "x" ? random : (random & 0x3) | 0x8).toString(16) - }) + if (typeof crypto === "object") { + if (typeof crypto.randomUUID === "function") { + // https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID + return crypto.randomUUID() + } + if ( + typeof crypto.getRandomValues === "function" && + typeof Uint8Array === "function" + ) { + // https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid + const callback = (c: string) => { + const num = Number(c) + return ( + num ^ + (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (num / 4))) + ).toString(16) + } + return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, callback) + } + } + let timestamp = new Date().getTime() + let perforNow = + (typeof performance !== "undefined" && + performance.now && + performance.now() * 1000) || + 0 + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + let random = Math.random() * 16 + if (timestamp > 0) { + random = (timestamp + random) % 16 | 0 + timestamp = Math.floor(timestamp / 16) + } else { + random = (perforNow + random) % 16 | 0 + perforNow = Math.floor(perforNow / 16) + } + return (c === "x" ? random : (random & 0x3) | 0x8).toString(16) + }) } diff --git a/client/lib/get-post-path.ts b/client/lib/get-post-path.ts index 77e85b2d..5235cdfa 100644 --- a/client/lib/get-post-path.ts +++ b/client/lib/get-post-path.ts @@ -1,13 +1,13 @@ import type { PostVisibility } from "./types" export default function getPostPath(visibility: PostVisibility, id: string) { - switch (visibility) { - case "private": - return `/post/private/${id}` - case "protected": - return `/post/protected/${id}` - case "unlisted": - case "public": - return `/post/${id}` - } + switch (visibility) { + case "private": + return `/post/private/${id}` + case "protected": + return `/post/protected/${id}` + case "unlisted": + case "public": + return `/post/${id}` + } } diff --git a/client/lib/hooks/use-shared-state.ts b/client/lib/hooks/use-shared-state.ts index cc111400..c21b4915 100644 --- a/client/lib/hooks/use-shared-state.ts +++ b/client/lib/hooks/use-shared-state.ts @@ -2,10 +2,10 @@ import useSWR from "swr" // https://2020.paco.me/blog/shared-hook-state-with-swr const useSharedState = (key: string, initial?: T) => { - const { data: state, mutate: setState } = useSWR(key, { - fallbackData: initial - }) - return [state, setState] as const + const { data: state, mutate: setState } = useSWR(key, { + fallbackData: initial + }) + return [state, setState] as const } export default useSharedState diff --git a/client/lib/hooks/use-signed-in.ts b/client/lib/hooks/use-signed-in.ts index 3f97123e..343609ba 100644 --- a/client/lib/hooks/use-signed-in.ts +++ b/client/lib/hooks/use-signed-in.ts @@ -4,32 +4,32 @@ import { useEffect, useState } from "react" import useSharedState from "./use-shared-state" const useSignedIn = () => { - const [signedIn, setSignedIn] = useSharedState( - "signedIn", - typeof window === "undefined" ? false : !!Cookies.get("drift-token") - ) - const token = Cookies.get("drift-token") - const router = useRouter() - const signin = (token: string) => { - setSignedIn(true) - Cookies.set("drift-token", token) - } + const [signedIn, setSignedIn] = useSharedState( + "signedIn", + typeof window === "undefined" ? false : !!Cookies.get("drift-token") + ) + const token = Cookies.get("drift-token") + const router = useRouter() + const signin = (token: string) => { + setSignedIn(true) + Cookies.set("drift-token", token) + } - const signout = () => { - setSignedIn(false) - Cookies.remove("drift-token") - router.push("/") - } + const signout = () => { + setSignedIn(false) + Cookies.remove("drift-token") + router.push("/") + } - useEffect(() => { - if (token) { - setSignedIn(true) - } else { - setSignedIn(false) - } - }, [setSignedIn, token]) + useEffect(() => { + if (token) { + setSignedIn(true) + } else { + setSignedIn(false) + } + }, [setSignedIn, token]) - return { signedIn, signin, token, signout } + return { signedIn, signin, token, signout } } export default useSignedIn diff --git a/client/lib/hooks/use-theme.ts b/client/lib/hooks/use-theme.ts index be71719d..9f08a145 100644 --- a/client/lib/hooks/use-theme.ts +++ b/client/lib/hooks/use-theme.ts @@ -2,26 +2,26 @@ import { useCallback, useEffect } from "react" import useSharedState from "./use-shared-state" const useTheme = () => { - const isClient = typeof window === "object" - const [themeType, setThemeType] = useSharedState("theme", "light") + const isClient = typeof window === "object" + const [themeType, setThemeType] = useSharedState("theme", "light") - useEffect(() => { - if (!isClient) return - const storedTheme = localStorage.getItem("drift-theme") - if (storedTheme) { - setThemeType(storedTheme) - } - }, [isClient, setThemeType]) + useEffect(() => { + if (!isClient) return + const storedTheme = localStorage.getItem("drift-theme") + if (storedTheme) { + setThemeType(storedTheme) + } + }, [isClient, setThemeType]) - const changeTheme = useCallback(() => { - setThemeType((last) => { - const newTheme = last === "dark" ? "light" : "dark" - localStorage.setItem("drift-theme", newTheme) - return newTheme - }) - }, [setThemeType]) + const changeTheme = useCallback(() => { + setThemeType((last) => { + const newTheme = last === "dark" ? "light" : "dark" + localStorage.setItem("drift-theme", newTheme) + return newTheme + }) + }, [setThemeType]) - return { theme: themeType, changeTheme } + return { theme: themeType, changeTheme } } export default useTheme diff --git a/client/lib/hooks/use-trace-route.ts b/client/lib/hooks/use-trace-route.ts index 863ae808..ff74bfc6 100644 --- a/client/lib/hooks/use-trace-route.ts +++ b/client/lib/hooks/use-trace-route.ts @@ -1,19 +1,19 @@ import { useRef, useEffect } from "react" function useTraceUpdate(props: { [key: string]: any }) { - const prev = useRef(props) - useEffect(() => { - const changedProps = Object.entries(props).reduce((ps, [k, v]) => { - if (prev.current[k] !== v) { - ps[k] = [prev.current[k], v] - } - return ps - }, {} as { [key: string]: any }) - if (Object.keys(changedProps).length > 0) { - console.log("Changed props:", changedProps) - } - prev.current = props - }) + const prev = useRef(props) + useEffect(() => { + const changedProps = Object.entries(props).reduce((ps, [k, v]) => { + if (prev.current[k] !== v) { + ps[k] = [prev.current[k], v] + } + return ps + }, {} as { [key: string]: any }) + if (Object.keys(changedProps).length > 0) { + console.log("Changed props:", changedProps) + } + prev.current = props + }) } export default useTraceUpdate diff --git a/client/lib/time-ago.ts b/client/lib/time-ago.ts index 9d723282..46a14e84 100644 --- a/client/lib/time-ago.ts +++ b/client/lib/time-ago.ts @@ -2,42 +2,42 @@ // which is based on https://stackoverflow.com/questions/3177836/how-to-format-time-since-xxx-e-g-4-minutes-ago-similar-to-stack-exchange-site const epochs = [ - ["year", 31536000], - ["month", 2592000], - ["day", 86400], - ["hour", 3600], - ["minute", 60], - ["second", 1] + ["year", 31536000], + ["month", 2592000], + ["day", 86400], + ["hour", 3600], + ["minute", 60], + ["second", 1] ] as const // Get duration const getDuration = (timeAgoInSeconds: number) => { - for (let [name, seconds] of epochs) { - const interval = Math.floor(timeAgoInSeconds / seconds) + for (let [name, seconds] of epochs) { + const interval = Math.floor(timeAgoInSeconds / seconds) - if (interval >= 1) { - return { - interval: interval, - epoch: name - } - } - } + if (interval >= 1) { + return { + interval: interval, + epoch: name + } + } + } - return { - interval: 0, - epoch: "second" - } + return { + interval: 0, + epoch: "second" + } } // Calculate const timeAgo = (date: Date) => { - const timeAgoInSeconds = Math.floor( - (new Date().getTime() - new Date(date).getTime()) / 1000 - ) - const { interval, epoch } = getDuration(timeAgoInSeconds) - const suffix = interval === 1 ? "" : "s" + const timeAgoInSeconds = Math.floor( + (new Date().getTime() - new Date(date).getTime()) / 1000 + ) + const { interval, epoch } = getDuration(timeAgoInSeconds) + const suffix = interval === 1 ? "" : "s" - return `${interval} ${epoch}${suffix} ago` + return `${interval} ${epoch}${suffix} ago` } export default timeAgo diff --git a/client/lib/types.d.ts b/client/lib/types.d.ts index fec78e12..462c8803 100644 --- a/client/lib/types.d.ts +++ b/client/lib/types.d.ts @@ -1,29 +1,29 @@ export type PostVisibility = "unlisted" | "private" | "public" | "protected" export type ThemeProps = { - theme: "light" | "dark" | string - changeTheme: () => void + theme: "light" | "dark" | string + changeTheme: () => void } export type Document = { - title: string - content: string - id: string + title: string + content: string + id: string } export type File = { - id: string - title: string - content: string - html: string + id: string + title: string + content: string + html: string } type Files = File[] export type Post = { - id: string - title: string - description: string - visibility: PostVisibility - files: Files + id: string + title: string + description: string + visibility: PostVisibility + files: Files } diff --git a/client/pages/api/markdown/[id].ts b/client/pages/api/markdown/[id].ts index 8ac01ff3..cfb734f0 100644 --- a/client/pages/api/markdown/[id].ts +++ b/client/pages/api/markdown/[id].ts @@ -3,52 +3,52 @@ import type { NextApiHandler } from "next" import markdown from "@lib/render-markdown" const renderMarkdown: NextApiHandler = async (req, res) => { - const { id } = req.query - const file = await fetch(`${process.env.API_URL}/files/raw/${id}`, { - headers: { - Accept: "text/plain", - "x-secret-key": process.env.SECRET_KEY || "", - Authorization: `Bearer ${req.cookies["drift-token"]}` - } - }) + const { id } = req.query + const file = await fetch(`${process.env.API_URL}/files/raw/${id}`, { + headers: { + Accept: "text/plain", + "x-secret-key": process.env.SECRET_KEY || "", + Authorization: `Bearer ${req.cookies["drift-token"]}` + } + }) - const json = await file.json() - const { content, title } = json - const renderAsMarkdown = [ - "markdown", - "md", - "mdown", - "mkdn", - "mkd", - "mdwn", - "mdtxt", - "mdtext", - "text", - "" - ] - const fileType = () => { - const pathParts = title.split(".") - const language = pathParts.length > 1 ? pathParts[pathParts.length - 1] : "" - return language - } - const type = fileType() - let contentToRender: string = "\n" + content + const json = await file.json() + const { content, title } = json + const renderAsMarkdown = [ + "markdown", + "md", + "mdown", + "mkdn", + "mkd", + "mdwn", + "mdtxt", + "mdtext", + "text", + "" + ] + const fileType = () => { + const pathParts = title.split(".") + const language = pathParts.length > 1 ? pathParts[pathParts.length - 1] : "" + return language + } + const type = fileType() + let contentToRender: string = "\n" + content - if (!renderAsMarkdown.includes(type)) { - contentToRender = `~~~${type} + if (!renderAsMarkdown.includes(type)) { + contentToRender = `~~~${type} ${content} ~~~` - } + } - if (typeof contentToRender !== "string") { - res.status(400).send("content must be a string") - return - } + if (typeof contentToRender !== "string") { + res.status(400).send("content must be a string") + return + } - res.setHeader("Content-Type", "text/plain") - res.setHeader("Cache-Control", "public, max-age=4800") - res.status(200).write(markdown(contentToRender)) - res.end() + res.setHeader("Content-Type", "text/plain") + res.setHeader("Cache-Control", "public, max-age=4800") + res.status(200).write(markdown(contentToRender)) + res.end() } export default renderMarkdown diff --git a/client/pages/api/raw/[id].ts b/client/pages/api/raw/[id].ts index cd665253..d07eb525 100644 --- a/client/pages/api/raw/[id].ts +++ b/client/pages/api/raw/[id].ts @@ -1,33 +1,33 @@ import { NextApiRequest, NextApiResponse } from "next" const getRawFile = async (req: NextApiRequest, res: NextApiResponse) => { - const { id, download } = req.query - const file = await fetch(`${process.env.API_URL}/files/raw/${id}`, { - headers: { - Accept: "text/plain", - "x-secret-key": process.env.SECRET_KEY || "", - Authorization: `Bearer ${req.cookies["drift-token"]}` - } - }) - const json = await file.json() - res.setHeader("Content-Type", "text/plain; charset=utf-8") - res.setHeader("Cache-Control", "s-maxage=86400") - if (file.ok) { - const data = json - const { title, content } = data - // serve the file raw as plain text + const { id, download } = req.query + const file = await fetch(`${process.env.API_URL}/files/raw/${id}`, { + headers: { + Accept: "text/plain", + "x-secret-key": process.env.SECRET_KEY || "", + Authorization: `Bearer ${req.cookies["drift-token"]}` + } + }) + const json = await file.json() + res.setHeader("Content-Type", "text/plain; charset=utf-8") + res.setHeader("Cache-Control", "s-maxage=86400") + if (file.ok) { + const data = json + const { title, content } = data + // serve the file raw as plain text - if (download) { - res.setHeader("Content-Disposition", `attachment; filename="${title}"`) - } else { - res.setHeader("Content-Disposition", `inline; filename="${title}"`) - } + if (download) { + res.setHeader("Content-Disposition", `attachment; filename="${title}"`) + } else { + res.setHeader("Content-Disposition", `inline; filename="${title}"`) + } - res.status(200).write(content, "utf-8") - res.end() - } else { - res.status(404).send("File not found") - } + res.status(200).write(content, "utf-8") + res.end() + } else { + res.status(404).send("File not found") + } } export default getRawFile diff --git a/client/pages/api/render-markdown.ts b/client/pages/api/render-markdown.ts index 5e5e76f0..9b02b60b 100644 --- a/client/pages/api/render-markdown.ts +++ b/client/pages/api/render-markdown.ts @@ -3,41 +3,41 @@ import type { NextApiHandler } from "next" import markdown from "@lib/render-markdown" const renderMarkdown: NextApiHandler = async (req, res) => { - const { content, title } = req.body - const renderAsMarkdown = [ - "markdown", - "md", - "mdown", - "mkdn", - "mkd", - "mdwn", - "mdtxt", - "mdtext", - "text", - "" - ] - const fileType = () => { - const pathParts = title.split(".") - const language = pathParts.length > 1 ? pathParts[pathParts.length - 1] : "" - return language - } - const type = fileType() - let contentToRender: string = content || "" + const { content, title } = req.body + const renderAsMarkdown = [ + "markdown", + "md", + "mdown", + "mkdn", + "mkd", + "mdwn", + "mdtxt", + "mdtext", + "text", + "" + ] + const fileType = () => { + const pathParts = title.split(".") + const language = pathParts.length > 1 ? pathParts[pathParts.length - 1] : "" + return language + } + const type = fileType() + let contentToRender: string = content || "" - if (!renderAsMarkdown.includes(type)) { - contentToRender = `~~~${type} + if (!renderAsMarkdown.includes(type)) { + contentToRender = `~~~${type} ${content} ~~~` - } else { - contentToRender = "\n" + content - } + } else { + contentToRender = "\n" + content + } - if (typeof contentToRender !== "string") { - res.status(400).send("content must be a string") - return - } - res.status(200).write(markdown(contentToRender)) - res.end() + if (typeof contentToRender !== "string") { + res.status(400).send("content must be a string") + return + } + res.status(200).write(markdown(contentToRender)) + res.end() } export default renderMarkdown