-
Notifications
You must be signed in to change notification settings - Fork 326
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds an example using [steventey/novel](https://github.com/steven-tey/novel). > [!NOTE] > This example was part of #746 but might as well pull it out to it's own thing For convenience, it adds some additional dx helpers exported from `uploadthing/client`: - `generateReactHelpers.getRouteConfig(endpoint: keyof Router): ExpandedRouteConfig`: helper to extract the route config outside of react context - `isValidFileSize(file: File, config: ExpandedRouteConfig): boolean`: validate a file is within the accepted range `isValidFileType(file: File, config: ExpandedRouteConfig): boolean`: validate a file has an accepted type https://github.com/pingdotgg/uploadthing/blob/0ad4378d38a686615840dc1136d25b7f6ddaef08/examples/with-novel/uploadthing/novel-plugin.ts#L50-L61 https://github.com/pingdotgg/uploadthing/assets/51714798/524a4f4d-16ac-45b8-b17f-269dee549591
- Loading branch information
1 parent
5d7351f
commit 8aa19e4
Showing
33 changed files
with
3,703 additions
and
111 deletions.
There are no files selected for viewing
This file contains 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,8 @@ | ||
--- | ||
"uploadthing": minor | ||
"@uploadthing/react": minor | ||
--- | ||
|
||
feat: add `generateReactHelpers.getRouteConfig`, `isValidFileSize` and `isValidFileType` helpers | ||
|
||
💡 See https://github.com/pingdotgg/uploadthing/blob/main/examples/with-novel/uploadthing/novel-plugin.ts#L50-L61 for a live example utilizing these helpers. |
This file contains 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,3 @@ | ||
# Go to https://uploadthing.com/dashboard to get your API secret | ||
UPLOADTHING_SECRET='sk_live_xxx' | ||
UPLOADTHING_APP_ID='xxx' |
This file contains 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,27 @@ | ||
# Integrating UploadThing with Novel | ||
|
||
<a href="https://stackblitz.com/github/pingdotgg/uploadthing/tree/main/examples/with-novel"> | ||
<img height="64" src="https://github.com/pingdotgg/uploadthing/assets/51714798/45907a4e-aa64-401a-afb3-b6c6df6eb71f" /> | ||
</a> | ||
|
||
This is a stripped down version of the Novel Web app. See the original full | ||
source code at: https://github.com/steven-tey/novel/tree/main/apps/web | ||
|
||
For the UploadThing specific code in this example, see | ||
[uploadthing/novel-plugin.ts](./uploadthing/novel-plugin.ts). | ||
|
||
## QuickStart | ||
|
||
1. Grab an API key from the UploadThing dashboard: | ||
https://uploadthing.com/dashboard | ||
2. `cp .env.example .env` and paste in your API key in the newly created `.env` | ||
file | ||
3. `pnpm i && pnpm dev` | ||
4. Use the editor and upload files! | ||
|
||
## Further reference | ||
|
||
Check out the docs at: | ||
|
||
- https://docs.uploadthing.com/getting-started/appdir | ||
- https://novel.sh/docs |
Binary file not shown.
This file contains 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,47 @@ | ||
import { Crimson_Text, Inconsolata, Inter } from "next/font/google"; | ||
import localFont from "next/font/local"; | ||
|
||
export const cal = localFont({ | ||
src: "./CalSans-SemiBold.otf", | ||
variable: "--font-title", | ||
}); | ||
|
||
export const crimsonBold = Crimson_Text({ | ||
weight: "700", | ||
variable: "--font-title", | ||
subsets: ["latin"], | ||
}); | ||
|
||
export const inter = Inter({ | ||
variable: "--font-default", | ||
subsets: ["latin"], | ||
}); | ||
|
||
export const inconsolataBold = Inconsolata({ | ||
weight: "700", | ||
variable: "--font-title", | ||
subsets: ["latin"], | ||
}); | ||
|
||
export const crimson = Crimson_Text({ | ||
weight: "400", | ||
variable: "--font-default", | ||
subsets: ["latin"], | ||
}); | ||
|
||
export const inconsolata = Inconsolata({ | ||
variable: "--font-default", | ||
subsets: ["latin"], | ||
}); | ||
|
||
export const titleFontMapper = { | ||
Default: cal.variable, | ||
Serif: crimsonBold.variable, | ||
Mono: inconsolataBold.variable, | ||
}; | ||
|
||
export const defaultFontMapper = { | ||
Default: inter.variable, | ||
Serif: crimson.variable, | ||
Mono: inconsolata.variable, | ||
}; |
This file contains 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,96 @@ | ||
@tailwind base; | ||
@tailwind components; | ||
@tailwind utilities; | ||
|
||
@layer base { | ||
:root { | ||
--background: 0 0% 100%; | ||
--foreground: 222.2 84% 4.9%; | ||
|
||
--card: 0 0% 100%; | ||
--card-foreground: 222.2 84% 4.9%; | ||
|
||
--popover: 0 0% 100%; | ||
--popover-foreground: 222.2 84% 4.9%; | ||
|
||
--primary: 222.2 47.4% 11.2%; | ||
--primary-foreground: 210 40% 98%; | ||
|
||
--secondary: 210 40% 96.1%; | ||
--secondary-foreground: 222.2 47.4% 11.2%; | ||
|
||
--muted: 210 40% 96.1%; | ||
--muted-foreground: 215.4 16.3% 46.9%; | ||
|
||
--accent: 210 40% 96.1%; | ||
--accent-foreground: 222.2 47.4% 11.2%; | ||
|
||
--destructive: 0 84.2% 60.2%; | ||
--destructive-foreground: 210 40% 98%; | ||
|
||
--border: 214.3 31.8% 91.4%; | ||
--input: 214.3 31.8% 91.4%; | ||
--ring: 222.2 84% 4.9%; | ||
|
||
--radius: 0.5rem; | ||
|
||
--novel-highlight-default: #ffffff; | ||
--novel-highlight-purple: #f6f3f8; | ||
--novel-highlight-red: #fdebeb; | ||
--novel-highlight-yellow: #fbf4a2; | ||
--novel-highlight-blue: #c1ecf9; | ||
--novel-highlight-green: #acf79f; | ||
--novel-highlight-orange: #faebdd; | ||
--novel-highlight-pink: #faf1f5; | ||
--novel-highlight-gray: #f1f1ef; | ||
} | ||
|
||
.dark { | ||
--background: 222.2 84% 4.9%; | ||
--foreground: 210 40% 98%; | ||
|
||
--card: 222.2 84% 4.9%; | ||
--card-foreground: 210 40% 98%; | ||
|
||
--popover: 222.2 84% 4.9%; | ||
--popover-foreground: 210 40% 98%; | ||
|
||
--primary: 210 40% 98%; | ||
--primary-foreground: 222.2 47.4% 11.2%; | ||
|
||
--secondary: 217.2 32.6% 17.5%; | ||
--secondary-foreground: 210 40% 98%; | ||
|
||
--muted: 217.2 32.6% 17.5%; | ||
--muted-foreground: 215 20.2% 65.1%; | ||
|
||
--accent: 217.2 32.6% 17.5%; | ||
--accent-foreground: 210 40% 98%; | ||
|
||
--destructive: 0 62.8% 30.6%; | ||
--destructive-foreground: 210 40% 98%; | ||
|
||
--border: 217.2 32.6% 17.5%; | ||
--input: 217.2 32.6% 17.5%; | ||
--ring: 212.7 26.8% 83.9%; | ||
|
||
--novel-highlight-default: #000000; | ||
--novel-highlight-purple: #3f2c4b; | ||
--novel-highlight-red: #5c1a1a; | ||
--novel-highlight-yellow: #5c4b1a; | ||
--novel-highlight-blue: #1a3d5c; | ||
--novel-highlight-green: #1a5c20; | ||
--novel-highlight-orange: #5c3a1a; | ||
--novel-highlight-pink: #5c1a3a; | ||
--novel-highlight-gray: #3a3a3a; | ||
} | ||
} | ||
|
||
@layer base { | ||
* { | ||
@apply border-border; | ||
} | ||
body { | ||
@apply bg-background text-foreground; | ||
} | ||
} |
This file contains 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,170 @@ | ||
.ProseMirror { | ||
@apply p-12 px-8 sm:px-12; | ||
} | ||
|
||
.ProseMirror .is-editor-empty:first-child::before { | ||
content: attr(data-placeholder); | ||
float: left; | ||
color: hsl(var(--muted-foreground)); | ||
pointer-events: none; | ||
height: 0; | ||
} | ||
.ProseMirror .is-empty::before { | ||
content: attr(data-placeholder); | ||
float: left; | ||
color: hsl(var(--muted-foreground)); | ||
pointer-events: none; | ||
height: 0; | ||
} | ||
|
||
/* Custom image styles */ | ||
|
||
.ProseMirror img { | ||
transition: filter 0.1s ease-in-out; | ||
|
||
&:hover { | ||
cursor: pointer; | ||
filter: brightness(90%); | ||
} | ||
|
||
&.ProseMirror-selectednode { | ||
outline: 3px solid #5abbf7; | ||
filter: brightness(90%); | ||
} | ||
} | ||
|
||
.img-placeholder { | ||
position: relative; | ||
|
||
&:before { | ||
content: ""; | ||
box-sizing: border-box; | ||
position: absolute; | ||
top: 50%; | ||
left: 50%; | ||
width: 36px; | ||
height: 36px; | ||
border-radius: 50%; | ||
border: 3px solid var(--novel-stone-200); | ||
border-top-color: var(--novel-stone-800); | ||
animation: spinning 0.6s linear infinite; | ||
} | ||
} | ||
|
||
@keyframes spinning { | ||
to { | ||
transform: rotate(360deg); | ||
} | ||
} | ||
|
||
/* Custom TODO list checkboxes – shoutout to this awesome tutorial: https://moderncss.dev/pure-css-custom-checkbox-style/ */ | ||
|
||
ul[data-type="taskList"] li > label { | ||
margin-right: 0.2rem; | ||
user-select: none; | ||
} | ||
|
||
@media screen and (max-width: 768px) { | ||
ul[data-type="taskList"] li > label { | ||
margin-right: 0.5rem; | ||
} | ||
} | ||
|
||
ul[data-type="taskList"] li > label input[type="checkbox"] { | ||
-webkit-appearance: none; | ||
appearance: none; | ||
background-color: hsl(var(--background)); | ||
margin: 0; | ||
cursor: pointer; | ||
width: 1.2em; | ||
height: 1.2em; | ||
position: relative; | ||
top: 5px; | ||
border: 2px solid hsl(var(--border)); | ||
margin-right: 0.3rem; | ||
display: grid; | ||
place-content: center; | ||
|
||
&:hover { | ||
background-color: hsl(var(--accent)); | ||
} | ||
|
||
&:active { | ||
background-color: hsl(var(--accent)); | ||
} | ||
|
||
&::before { | ||
content: ""; | ||
width: 0.65em; | ||
height: 0.65em; | ||
transform: scale(0); | ||
transition: 120ms transform ease-in-out; | ||
box-shadow: inset 1em 1em; | ||
transform-origin: center; | ||
clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%); | ||
} | ||
|
||
&:checked::before { | ||
transform: scale(1); | ||
} | ||
} | ||
|
||
ul[data-type="taskList"] li[data-checked="true"] > div > p { | ||
color: var(--muted-foreground); | ||
text-decoration: line-through; | ||
text-decoration-thickness: 2px; | ||
} | ||
|
||
/* Overwrite tippy-box original max-width */ | ||
|
||
.tippy-box { | ||
max-width: 400px !important; | ||
} | ||
|
||
.ProseMirror:not(.dragging) .ProseMirror-selectednode { | ||
outline: none !important; | ||
background-color: var(--novel-highlight-blue); | ||
transition: background-color 0.2s; | ||
box-shadow: none; | ||
} | ||
|
||
.drag-handle { | ||
position: fixed; | ||
opacity: 1; | ||
transition: opacity ease-in 0.2s; | ||
border-radius: 0.25rem; | ||
|
||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' style='fill: rgba(0, 0, 0, 0.5)'%3E%3Cpath d='M3,2 C2.44771525,2 2,1.55228475 2,1 C2,0.44771525 2.44771525,0 3,0 C3.55228475,0 4,0.44771525 4,1 C4,1.55228475 3.55228475,2 3,2 Z M3,6 C2.44771525,6 2,5.55228475 2,5 C2,4.44771525 2.44771525,4 3,4 C3.55228475,4 4,4.44771525 4,5 C4,5.55228475 3.55228475,6 3,6 Z M3,10 C2.44771525,10 2,9.55228475 2,9 C2,8.44771525 2.44771525,8 3,8 C3.55228475,8 4,8.44771525 4,9 C4,9.55228475 3.55228475,10 3,10 Z M7,2 C6.44771525,2 6,1.55228475 6,1 C6,0.44771525 6.44771525,0 7,0 C7.55228475,0 8,0.44771525 8,1 C8,1.55228475 7.55228475,2 7,2 Z M7,6 C6.44771525,6 6,5.55228475 6,5 C6,4.44771525 6.44771525,4 7,4 C7.55228475,4 8,4.44771525 8,5 C8,5.55228475 7.55228475,6 7,6 Z M7,10 C6.44771525,10 6,9.55228475 6,9 C6,8.44771525 6.44771525,8 7,8 C7.55228475,8 8,8.44771525 8,9 C8,9.55228475 7.55228475,10 7,10 Z'%3E%3C/path%3E%3C/svg%3E"); | ||
background-size: calc(0.5em + 0.375rem) calc(0.5em + 0.375rem); | ||
background-repeat: no-repeat; | ||
background-position: center; | ||
width: 1.2rem; | ||
height: 1.5rem; | ||
z-index: 50; | ||
cursor: grab; | ||
|
||
&:hover { | ||
background-color: var(--novel-stone-100); | ||
transition: background-color 0.2s; | ||
} | ||
|
||
&:active { | ||
background-color: var(--novel-stone-200); | ||
transition: background-color 0.2s; | ||
cursor: grabbing; | ||
} | ||
|
||
&.hide { | ||
opacity: 0; | ||
pointer-events: none; | ||
} | ||
|
||
@media screen and (max-width: 600px) { | ||
display: none; | ||
pointer-events: none; | ||
} | ||
} | ||
|
||
.dark .drag-handle { | ||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' style='fill: rgba(255, 255, 255, 0.5)'%3E%3Cpath d='M3,2 C2.44771525,2 2,1.55228475 2,1 C2,0.44771525 2.44771525,0 3,0 C3.55228475,0 4,0.44771525 4,1 C4,1.55228475 3.55228475,2 3,2 Z M3,6 C2.44771525,6 2,5.55228475 2,5 C2,4.44771525 2.44771525,4 3,4 C3.55228475,4 4,4.44771525 4,5 C4,5.55228475 3.55228475,6 3,6 Z M3,10 C2.44771525,10 2,9.55228475 2,9 C2,8.44771525 2.44771525,8 3,8 C3.55228475,8 4,8.44771525 4,9 C4,9.55228475 3.55228475,10 3,10 Z M7,2 C6.44771525,2 6,1.55228475 6,1 C6,0.44771525 6.44771525,0 7,0 C7.55228475,0 8,0.44771525 8,1 C8,1.55228475 7.55228475,2 7,2 Z M7,6 C6.44771525,6 6,5.55228475 6,5 C6,4.44771525 6.44771525,4 7,4 C7.55228475,4 8,4.44771525 8,5 C8,5.55228475 7.55228475,6 7,6 Z M7,10 C6.44771525,10 6,9.55228475 6,9 C6,8.44771525 6.44771525,8 7,8 C7.55228475,8 8,8.44771525 8,9 C8,9.55228475 7.55228475,10 7,10 Z'%3E%3C/path%3E%3C/svg%3E"); | ||
} |
This file contains 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,12 @@ | ||
import { uploadRouter } from "@/uploadthing/server"; | ||
|
||
import { createRouteHandler } from "uploadthing/next"; | ||
|
||
export const runtime = "edge"; | ||
|
||
export const { GET, POST } = createRouteHandler({ | ||
router: uploadRouter, | ||
config: { | ||
logLevel: "debug", | ||
}, | ||
}); |
Oops, something went wrong.