source-editor.stories.tsx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. import SourceEditor from '../../js/features/source-editor/components/source-editor'
  2. import { ScopeDecorator } from '../decorators/scope'
  3. import { useScope } from '../hooks/use-scope'
  4. import { useMeta } from '../hooks/use-meta'
  5. import React, { FC, useState } from 'react'
  6. import { FileTreePathContext } from '@/features/file-tree/contexts/file-tree-path'
  7. import RangesTracker from '@overleaf/ranges-tracker'
  8. import useExposedState from '@/shared/hooks/use-exposed-state'
  9. import { EditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
  10. import { DocId } from '../../../types/project-settings'
  11. import { StoryObj } from '@storybook/react-webpack5'
  12. import { DocumentContainer } from '@/features/ide-react/editor/document-container'
  13. import { EditorPropertiesContext } from '@/features/ide-react/context/editor-properties-context'
  14. type Story = StoryObj<typeof SourceEditor>
  15. const EditorOpenDocProvider: FC<
  16. React.PropsWithChildren<{
  17. initialOpenDocName: string | null
  18. initialDocument: DocumentContainer
  19. }>
  20. > = ({ children, initialOpenDocName, initialDocument }) => {
  21. const [currentDocumentId, setCurrentDocumentId] =
  22. useExposedState<DocId | null>(null, 'editor.open_doc_id')
  23. const [openDocName, setOpenDocName] = useExposedState<string | null>(
  24. initialOpenDocName,
  25. 'editor.open_doc_name'
  26. )
  27. const [currentDocument, setCurrentDocument] =
  28. useState<DocumentContainer | null>(initialDocument)
  29. const value = {
  30. currentDocumentId,
  31. setCurrentDocumentId,
  32. openDocName,
  33. setOpenDocName,
  34. currentDocument,
  35. setCurrentDocument,
  36. }
  37. return (
  38. <EditorOpenDocContext.Provider value={value}>
  39. {children}
  40. </EditorOpenDocContext.Provider>
  41. )
  42. }
  43. const LatexEditorOpenDocProvider: FC<React.PropsWithChildren> = ({
  44. children,
  45. }) => (
  46. <EditorOpenDocProvider
  47. initialOpenDocName="example.tex"
  48. initialDocument={
  49. mockDoc(content.tex, changes.tex) as unknown as DocumentContainer
  50. }
  51. >
  52. {children}
  53. </EditorOpenDocProvider>
  54. )
  55. const MarkdownEditorOpenDocProvider: FC<React.PropsWithChildren> = ({
  56. children,
  57. }) => (
  58. <EditorOpenDocProvider
  59. initialOpenDocName="example.md"
  60. initialDocument={
  61. mockDoc(content.md, changes.md) as unknown as DocumentContainer
  62. }
  63. >
  64. {children}
  65. </EditorOpenDocProvider>
  66. )
  67. const BibtexEditorOpenDocProvider: FC<React.PropsWithChildren> = ({
  68. children,
  69. }) => (
  70. <EditorOpenDocProvider
  71. initialOpenDocName="example.bib"
  72. initialDocument={
  73. mockDoc(content.bib, changes.bib) as unknown as DocumentContainer
  74. }
  75. >
  76. {children}
  77. </EditorOpenDocProvider>
  78. )
  79. const VisualEditorPropertiesProvider: FC<React.PropsWithChildren> = ({
  80. children,
  81. }) => {
  82. const [showVisual, setShowVisual] = useState(true)
  83. const value = {
  84. showVisual,
  85. setShowVisual,
  86. showVisualForFile: () => showVisual,
  87. showSymbolPalette: true,
  88. setShowSymbolPalette: () => undefined,
  89. toggleSymbolPalette: () => undefined,
  90. opening: true,
  91. setOpening: () => undefined,
  92. trackChanges: false,
  93. setTrackChanges: () => undefined,
  94. wantTrackChanges: false,
  95. setWantTrackChanges: () => undefined,
  96. errorState: false,
  97. setErrorState: () => undefined,
  98. }
  99. return (
  100. <EditorPropertiesContext.Provider value={value}>
  101. {children}
  102. </EditorPropertiesContext.Provider>
  103. )
  104. }
  105. const FileTreePathProvider: FC<React.PropsWithChildren> = ({ children }) => (
  106. <FileTreePathContext.Provider
  107. value={{
  108. dirname: () => null,
  109. findEntityByPath: () => null,
  110. pathInFolder: () => null,
  111. previewByPath: (path: string) =>
  112. path === 'frog.jpg'
  113. ? {
  114. extension: 'png',
  115. url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51AAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TpaJVETuIOGSogmBBVMRRq1CECqFWaNXB5NIvaNKQpLg4Cq4FBz8Wqw4uzro6uAqC4AeIq4uToouU+L+k0CLWg+N+vLv3uHsHCNUi06y2cUDTbTMRi4qp9KoYeIWAPnShB6Mys4w5SYqj5fi6h4+vdxGe1frcn6NbzVgM8InEs8wwbeIN4ulN2+C8TxxieVklPiceM+mCxI9cVzx+45xzWeCZITOZmCcOEYu5JlaamOVNjXiKOKxqOuULKY9VzluctWKZ1e/JXxjM6CvLXKc5hBgWsQQJIhSUUUARNiK06qRYSNB+tIV/0PVL5FLIVQAjxwJK0CC7fvA/+N2tlZ2c8JKCUaD9xXE+hoHALlCrOM73sePUTgD/M3ClN/ylKjDzSXqloYWPgN5t4OK6oSl7wOUOMPBkyKbsSn6aQjYLvJ/RN6WB/lugc83rrb6P0wcgSV3Fb4CDQ2AkR9nrLd7d0dzbv2fq/f0ARfNylZJUgMQAAAAGYktHRABuAP8AAGHZRr4AAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfnAhELEhgyPeVkAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAyVJREFUeNrt1rEJgDAURVGVNCmS2hS6PziCteIYWjuEbiEfOWeEV1xe35bt6QhjnlYjBJLzbYRABhMAggUgWIBgAQgWgGABggUgWACCBQgWgGABCBYgWACCBSBYgGABCBaAYAGCBSBYAIIFCBaAYAEIFiBYAIIFIFiAYAEIFiBYAIIFIFiAYAEIFoBgAYIFIFgAggUIFoBgAQgWIFgAggUgWIBgAQgWgGABggUgWACCBQgWgGABCBYgWACCBSBYgGABCBYgWACCBSBYgGABCBaAYAGCBSBYAIIFCBaAYAEIFiBYAIIFIFiAYAEIFoBgAYIFIFgAggUIFoBgAQgWIFgAggUgWIBgAQgWIFgAggUgWIBgAQgWgGABggUgWACCBQgWgGABCBbwX6m13QqB5HwbIZBSLyN4WACCBQgWgGABCBYgWACCBSBYgGABCBaAYAGCBSBYAIIFCBaAYAEIFiBYAIIFCBaAYAEIFiBYAIIFIFiAYAEIFoBgAYIFIFgAggUIFoBgAQgWIFgAggUgWIBgAQgWgGABggUgWACCBQgWgGABCBYgWACCBQgWgGABCBYgWACCBSBYgGABCBaAYAGCBSBYAIIFCBaAYAEIFiBYAIIFIFiAYAEIFoBgAYIFIFgAggUIFoBgAQgWIFgAggUIFoBgAQgWIFgAggUgWIBgAQgWgGABggUgWACCBQgWgGABCBYgWACCBSBYgGABCBaAYAGCBfCFVMtphUBKvYwQSBsPI3hYAIIFCBaAYAEIFiBYAIIFIFiAYAEIFoBgAYIFIFgAggUIFoBgAQgWIFgAggUIFoBgAQgWIFgAggUgWIBgAQgWgGABggUgWACCBQgWgGABCBYgWACCBSBYgGABCBaAYAGCBSBYAIIFCBaAYAEIFiBYAIIFCBaAYAEIFiBYAIIFIFiAYAEIFoBgAYIFIFgAggUIFoBgAQgWIFgAggUgWIBgAQgWgGABggUgWACCBQgWgGABCBYgWACCBQgWgGABCBYgWACCBSBYgGABCBaAYAGCBSBYAIIFCBaAYAEIFiBYAIIFIFiAYAEIFoBgAYIF8IUXjtUMuBMh1xAAAAAASUVORK5CYII=',
  116. }
  117. : null,
  118. }}
  119. >
  120. {children}
  121. </FileTreePathContext.Provider>
  122. )
  123. export default {
  124. title: 'Editor / Source Editor',
  125. component: SourceEditor,
  126. decorators: [
  127. (Story: any) => (
  128. <div style={{ height: '90vh' }}>
  129. <Story />
  130. </div>
  131. ),
  132. ],
  133. }
  134. const settings = {
  135. fontSize: 12,
  136. fontFamily: 'monaco',
  137. lineHeight: 'normal',
  138. editorTheme: 'textmate',
  139. overallTheme: '',
  140. mode: 'default',
  141. autoComplete: true,
  142. autoPairDelimiters: true,
  143. trackChanges: true,
  144. syntaxValidation: false,
  145. }
  146. const permissions = {
  147. write: true,
  148. }
  149. export const Latex: Story = {
  150. decorators: [
  151. Story =>
  152. ScopeDecorator(Story, {
  153. mockCompileOnLoad: true,
  154. providers: {
  155. FileTreePathProvider,
  156. EditorOpenDocProvider: LatexEditorOpenDocProvider,
  157. },
  158. }),
  159. (Story, { globals }) => {
  160. // FIXME: useScope has no effect
  161. useScope({
  162. rootFolder: {
  163. name: 'rootFolder',
  164. id: 'root-folder-id',
  165. type: 'folder',
  166. children: [
  167. {
  168. name: 'example.tex.tex',
  169. id: 'example-doc-id',
  170. type: 'doc',
  171. selected: false,
  172. $$hashKey: 'object:89',
  173. },
  174. {
  175. name: 'frog.jpg',
  176. id: 'frog-image-id',
  177. type: 'file',
  178. linkedFileData: null,
  179. created: '2023-05-04T16:11:04.352Z',
  180. $$hashKey: 'object:108',
  181. },
  182. ],
  183. selected: false,
  184. },
  185. settings: {
  186. ...settings,
  187. overallTheme: globals.theme === 'default-' ? '' : globals.theme,
  188. },
  189. permissions,
  190. })
  191. useMeta({
  192. 'ol-showSymbolPalette': true,
  193. })
  194. return <Story />
  195. },
  196. ],
  197. }
  198. export const Markdown: Story = {
  199. decorators: [
  200. Story =>
  201. ScopeDecorator(Story, {
  202. mockCompileOnLoad: true,
  203. providers: {
  204. FileTreePathProvider,
  205. EditorOpenDocProvider: MarkdownEditorOpenDocProvider,
  206. },
  207. }),
  208. (Story, { globals }) => {
  209. // FIXME: useScope has no effect
  210. useScope({
  211. settings: {
  212. ...settings,
  213. overallTheme: globals.theme === 'default-' ? '' : globals.theme,
  214. },
  215. permissions,
  216. })
  217. return <Story />
  218. },
  219. ],
  220. }
  221. export const Visual: Story = {
  222. decorators: [
  223. Story =>
  224. ScopeDecorator(Story, {
  225. mockCompileOnLoad: true,
  226. providers: {
  227. FileTreePathProvider,
  228. EditorOpenDocProvider: LatexEditorOpenDocProvider,
  229. EditorPropertiesProvider: VisualEditorPropertiesProvider,
  230. },
  231. }),
  232. (Story, { globals }) => {
  233. // FIXME: useScope has no effect, so this does nothing
  234. useScope({
  235. settings: {
  236. ...settings,
  237. overallTheme: globals.theme === 'default-' ? '' : globals.theme,
  238. },
  239. permissions,
  240. })
  241. useMeta({
  242. 'ol-mathJaxPath': 'https://unpkg.com/mathjax@4.1.2/tex-svg.js',
  243. 'ol-project_id': '63e21c07946dd8c76505f85a',
  244. })
  245. return <Story />
  246. },
  247. ],
  248. }
  249. export const Bibtex: Story = {
  250. decorators: [
  251. Story =>
  252. ScopeDecorator(Story, {
  253. mockCompileOnLoad: true,
  254. providers: {
  255. FileTreePathProvider,
  256. EditorOpenDocProvider: BibtexEditorOpenDocProvider,
  257. },
  258. }),
  259. (Story, { globals }) => {
  260. // FIXME: useScope has no effect
  261. useScope({
  262. settings: {
  263. ...settings,
  264. overallTheme: globals.theme === 'default-' ? '' : globals.theme,
  265. },
  266. permissions,
  267. })
  268. return <Story />
  269. },
  270. ],
  271. }
  272. const MAX_DOC_LENGTH = 2 * 1024 * 1024 // ol-maxDocLength
  273. const mockDoc = (content: string, changes: Array<Record<string, any>> = []) => {
  274. const mockShareJSDoc = {
  275. getText() {
  276. return content
  277. },
  278. on() {
  279. // do nothing
  280. },
  281. insert() {
  282. // do nothing
  283. },
  284. del() {
  285. // do nothing
  286. },
  287. emit: (...args: any[]) => {
  288. console.log(...args)
  289. },
  290. }
  291. return {
  292. doc_id: 'story-doc',
  293. getSnapshot: () => {
  294. return content
  295. },
  296. attachToCM6: (cm6: any) => {
  297. cm6.attachShareJs(mockShareJSDoc, MAX_DOC_LENGTH)
  298. },
  299. detachFromCM6: () => {
  300. // Do nothing
  301. },
  302. getType: () => {
  303. return 'sharejs-text-ot'
  304. },
  305. on: () => {
  306. // Do nothing
  307. },
  308. off: () => {
  309. // Do nothing
  310. },
  311. setTrackChangesIdSeeds: () => {
  312. // Do nothing
  313. },
  314. setTrackChangesUserId: () => {
  315. // Do nothing
  316. },
  317. getTrackingChanges: () => {
  318. return true
  319. },
  320. getInflightOp: () => {
  321. return null
  322. },
  323. getPendingOp: () => {
  324. return null
  325. },
  326. ranges: new RangesTracker(changes, []),
  327. hasBufferedOps: () => false,
  328. }
  329. }
  330. const changes: Record<string, Array<Record<string, any>>> = {
  331. tex: [
  332. {
  333. id: '1',
  334. op: {
  335. i: 'Your introduction goes here! Simply start writing your document and use the Recompile button to view the updated PDF preview. Examples of commonly used commands and features are listed below, to help you get started.',
  336. p: 583,
  337. },
  338. meta: {
  339. user_id: '1',
  340. ts: new Date().toString(),
  341. },
  342. },
  343. ],
  344. md: [],
  345. bib: [],
  346. }
  347. const content = {
  348. tex: `\\documentclass{article}
  349. % Language setting
  350. % Replace \`english' with e.g. \`spanish' to change the document language
  351. \\usepackage[english]{babel}
  352. % Set page size and margins
  353. % Replace \`letterpaper' with \`a4paper' for UK/EU standard size
  354. \\usepackage[letterpaper,top=2cm,bottom=2cm,left=3cm,right=3cm,marginparwidth=1.75cm]{geometry}
  355. % Useful packages
  356. \\usepackage{amsmath}
  357. \\usepackage{graphicx}
  358. \\usepackage[colorlinks=true, allcolors=blue]{hyperref}
  359. \\title{Your Paper}
  360. \\author{You}
  361. \\begin{document}
  362. \\maketitle
  363. \\begin{abstract}
  364. Your abstract.
  365. \\end{abstract}
  366. \\section{Introduction}
  367. Your introduction goes here! Simply start writing your document and use the Recompile button to view the updated PDF preview. Examples of commonly used commands and features are listed below, to help you get started.
  368. Once you're familiar with the editor, you can find various project settings in the Overleaf menu, accessed via the button in the very top left of the editor. To view tutorials, user guides, and further documentation, please visit our \\href{https://www.overleaf.com/learn}{help library}, or head to our plans page to \\href{https://www.overleaf.com/user/subscription/plans}{choose your plan}.
  369. \\section{Some examples to get started}
  370. \\subsection{How to create Sections and Subsections}
  371. Simply use the section and subsection commands, as in this example document! With Overleaf, all the formatting and numbering is handled automatically according to the template you've chosen. If you're using Rich Text mode, you can also create new section and subsections via the buttons in the editor toolbar.
  372. \\subsection{How to include Figures}
  373. First you have to upload the image file from your computer using the upload link in the file-tree menu. Then use the includegraphics command to include it in your document. Use the figure environment and the caption command to add a number and a caption to your figure. See the code for Figure \\ref{fig:frog} in this section for an example.
  374. Note that your figure will automatically be placed in the most appropriate place for it, given the surrounding text and taking into account other figures or tables that may be close by. You can find out more about adding images to your documents in this help article on \\href{https://www.overleaf.com/learn/how-to/Including_images_on_Overleaf}{including images on Overleaf}.
  375. \\begin{figure}
  376. \\centering
  377. \\includegraphics[width=0.25\\linewidth]{frog.jpg}
  378. \\caption{This frog was uploaded via the file-tree menu.}\\label{fig:frog}
  379. \\end{figure}
  380. \\subsection{How to add Tables}
  381. Use the table and tabular environments for basic tables --- see Table~\\ref{tab:widgets}, for example. For more information, please see this help article on \\href{https://www.overleaf.com/learn/latex/tables}{tables}.
  382. \\begin{table}
  383. \\centering
  384. \\begin{tabular}{l|r}
  385. Item & Quantity \\\\\\hline
  386. Widgets & 42 \\\\
  387. Gadgets & 13
  388. \\end{tabular}
  389. \\caption{\\label{tab:widgets}An example table.}
  390. \\end{table}
  391. \\subsection{How to add Comments and Track Changes}
  392. Comments can be added to your project by highlighting some text and clicking \`\`Add comment'' in the top right of the editor pane. To view existing comments, click on the Review menu in the toolbar above. To reply to a comment, click on the Reply button in the lower right corner of the comment. You can close the Review pane by clicking its name on the toolbar when you're done reviewing for the time being.
  393. Track changes are available on all our \\href{https://www.overleaf.com/user/subscription/plans}{premium plans}, and can be toggled on or off using the option at the top of the Review pane. Track changes allow you to keep track of every change made to the document, along with the person making the change.
  394. \\subsection{How to add Lists}
  395. You can make lists with automatic numbering \\dots
  396. \\begin{enumerate}
  397. \\item Like this,
  398. \\item and like this.
  399. \\end{enumerate}
  400. \\dots or bullet points \\dots
  401. \\begin{itemize}
  402. \\item Like this,
  403. \\item and like this.
  404. \\end{itemize}
  405. \\subsection{How to write Mathematics}
  406. \\LaTeX{} is great at typesetting mathematics. Let $X_1, X_2, \\ldots, X_n$ be a sequence of independent and identically distributed random variables with $\\text{E}[X_i] = \\mu$ and $\\text{Var}[X_i] = \\sigma^2 < \\infty$, and let
  407. \\[S_n = \\frac{X_1 + X_2 + \\cdots + X_n}{n}
  408. = \\frac{1}{n}\\sum_{i}^{n} X_i\\]
  409. denote their mean. Then as $n$ approaches infinity, the random variables $\\sqrt{n}(S_n - \\mu)$ converge in distribution to a normal $\\mathcal{N}(0, \\sigma^2)$.
  410. \\subsection{How to change the margins and paper size}
  411. Usually the template you're using will have the page margins and paper size set correctly for that use-case. For example, if you're using a journal article template provided by the journal publisher, that template will be formatted according to their requirements. In these cases, it's best not to alter the margins directly.
  412. If however you're using a more general template, such as this one, and would like to alter the margins, a common way to do so is via the geometry package. You can find the geometry package loaded in the preamble at the top of this example file, and if you'd like to learn more about how to adjust the settings, please visit this help article on \\href{https://www.overleaf.com/learn/latex/page_size_and_margins}{page size and margins}.
  413. \\subsection{How to change the document language and spell check settings}
  414. Overleaf supports many different languages, including multiple different languages within one document.
  415. To configure the document language, simply edit the option provided to the babel package in the preamble at the top of this example project. To learn more about the different options, please visit this help article on \\href{https://www.overleaf.com/learn/latex/International_language_support}{international language support}.
  416. To change the spell check language, simply open the Overleaf menu at the top left of the editor window, scroll down to the spell check setting, and adjust accordingly.
  417. \\subsection{How to add Citations and a References List}
  418. You can simply upload a \\verb|.bib| file containing your BibTeX entries, created with a tool such as JabRef. You can then cite entries from it, like this: \\cite{greenwade93}. Just remember to specify a bibliography style, as well as the filename of the \\verb|.bib|. You can find a \\href{https://www.overleaf.com/help/97-how-to-include-a-bibliography-using-bibtex}{video tutorial here} to learn more about BibTeX.
  419. If you have an \\href{https://www.overleaf.com/user/subscription/plans}{upgraded account}, you can also import your Mendeley or Zotero library directly as a \\verb|.bib| file, via the upload menu in the file-tree.
  420. \\subsection{Good luck!}
  421. We hope you find Overleaf useful, and do take a look at our \\href{https://www.overleaf.com/learn}{help library} for more tutorials and user guides! Please also let us know if you have any feedback using the Contact Us link at the bottom of the Overleaf menu --- or use the contact form at \\url{https://www.overleaf.com/contact}.
  422. \\bibliographystyle{alpha}
  423. \\bibliography{sample}
  424. \\end{document}`,
  425. md: `# Heading
  426. This is **bold**
  427. This is _italic_`,
  428. bib: `@book{texbook,
  429. author = {Donald E. Knuth},
  430. year = {1986},
  431. title = {The {\\TeX} Book},
  432. publisher = {Addison-Wesley Professional}
  433. }
  434. @book{latex:companion,
  435. author = {Frank Mittelbach and Michel Gossens
  436. and Johannes Braams and David Carlisle
  437. and Chris Rowley},
  438. year = {2004},
  439. title = {The {\\LaTeX} Companion},
  440. publisher = {Addison-Wesley Professional},
  441. edition = {2}
  442. }
  443. @book{latex2e,
  444. author = {Leslie Lamport},
  445. year = {1994},
  446. title = {{\\LaTeX}: a Document Preparation System},
  447. publisher = {Addison Wesley},
  448. address = {Massachusetts},
  449. edition = {2}
  450. }
  451. @article{knuth:1984,
  452. title={Literate Programming},
  453. author={Donald E. Knuth},
  454. journal={The Computer Journal},
  455. volume={27},
  456. number={2},
  457. pages={97--111},
  458. year={1984},
  459. publisher={Oxford University Press}
  460. }
  461. @inproceedings{lesk:1977,
  462. title={Computer Typesetting of Technical Journals on {UNIX}},
  463. author={Michael Lesk and Brian Kernighan},
  464. booktitle={Proceedings of American Federation of
  465. Information Processing Societies: 1977
  466. National Computer Conference},
  467. pages={879--888},
  468. year={1977},
  469. address={Dallas, Texas}
  470. }
  471. `,
  472. }