* Add TipTap editor and renderer components
* Change market description editor to rich text
* Type description as JSON, fix string-based logic
- Delete make-predictions.tsx
- Delete feed logic that showed descriptions
* wip Fix API validation
* fix type error
* fix extension import (backend)
In firebase, typescript compiles imports into common js imports
like `const StarterKit = require("@tiptap/starter-kit")`
Even though StarterKit is exported from the cjs file, it gets imported
as undefined. But it magically works if we import *
If you're reading this in the future, consider replacing StarterKit with
the entire list of extensions.
* Stop load on fail create market, improve warning
* Refactor editor as hook / fix infinite submit bug
Move state of editor back up to parent
We have to do this later anyways to allow parent to edit
* Add images - display, paste + uploading
* add uploading state of image
* Fix placeholder, misc styling
min height, quote
* Fix appending to description
* code review fixes: rename, refactor, chop carets
* Add hint & upload button on new lines
- bump to Tailwind 3.1 for arbitrary variants
* clean up, run prettier
* rename FileButton to FileUploadButton
* add image extension as functions dependency
		
	
			
		
			
				
	
	
		
			77 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			77 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { MAX_TAG_LENGTH } from '../contract'
 | |
| import { generateText, JSONContent } from '@tiptap/core'
 | |
| // Tiptap starter extensions
 | |
| import { Blockquote } from '@tiptap/extension-blockquote'
 | |
| import { Bold } from '@tiptap/extension-bold'
 | |
| import { BulletList } from '@tiptap/extension-bullet-list'
 | |
| import { Code } from '@tiptap/extension-code'
 | |
| import { CodeBlock } from '@tiptap/extension-code-block'
 | |
| import { Document } from '@tiptap/extension-document'
 | |
| import { HardBreak } from '@tiptap/extension-hard-break'
 | |
| import { Heading } from '@tiptap/extension-heading'
 | |
| import { History } from '@tiptap/extension-history'
 | |
| import { HorizontalRule } from '@tiptap/extension-horizontal-rule'
 | |
| import { Italic } from '@tiptap/extension-italic'
 | |
| import { ListItem } from '@tiptap/extension-list-item'
 | |
| import { OrderedList } from '@tiptap/extension-ordered-list'
 | |
| import { Paragraph } from '@tiptap/extension-paragraph'
 | |
| import { Strike } from '@tiptap/extension-strike'
 | |
| import { Text } from '@tiptap/extension-text'
 | |
| // other tiptap extensions
 | |
| import { Image } from '@tiptap/extension-image'
 | |
| 
 | |
| export function parseTags(text: string) {
 | |
|   const regex = /(?:^|\s)(?:[#][a-z0-9_]+)/gi
 | |
|   const matches = (text.match(regex) || []).map((match) =>
 | |
|     match.trim().substring(1).substring(0, MAX_TAG_LENGTH)
 | |
|   )
 | |
|   const tagSet = new Set()
 | |
|   const uniqueTags: string[] = []
 | |
|   // Keep casing of last tag.
 | |
|   matches.reverse()
 | |
|   for (const tag of matches) {
 | |
|     const lowercase = tag.toLowerCase()
 | |
|     if (!tagSet.has(lowercase)) {
 | |
|       tagSet.add(lowercase)
 | |
|       uniqueTags.push(tag)
 | |
|     }
 | |
|   }
 | |
|   uniqueTags.reverse()
 | |
|   return uniqueTags
 | |
| }
 | |
| 
 | |
| export function parseWordsAsTags(text: string) {
 | |
|   const taggedText = text
 | |
|     .split(/\s+/)
 | |
|     .map((tag) => (tag.startsWith('#') ? tag : `#${tag}`))
 | |
|     .join(' ')
 | |
|   return parseTags(taggedText)
 | |
| }
 | |
| 
 | |
| // can't just do [StarterKit, Image...] because it doesn't work with cjs imports
 | |
| export const exhibitExts = [
 | |
|   Blockquote,
 | |
|   Bold,
 | |
|   BulletList,
 | |
|   Code,
 | |
|   CodeBlock,
 | |
|   Document,
 | |
|   HardBreak,
 | |
|   Heading,
 | |
|   History,
 | |
|   HorizontalRule,
 | |
|   Italic,
 | |
|   ListItem,
 | |
|   OrderedList,
 | |
|   Paragraph,
 | |
|   Strike,
 | |
|   Text,
 | |
| 
 | |
|   Image,
 | |
| ]
 | |
| // export const exhibitExts = [StarterKit as unknown as Extension, Image]
 | |
| 
 | |
| export function richTextToString(text?: JSONContent) {
 | |
|   return !text ? '' : generateText(text, exhibitExts)
 | |
| }
 |