preview.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import { definePreview } from '@storybook/react-webpack5'
  2. import addonA11y from '@storybook/addon-a11y'
  3. import addonDesigns from '@storybook/addon-designs'
  4. import addonDocs from '@storybook/addon-docs'
  5. import addonLinks from '@storybook/addon-links'
  6. // Storybook does not (currently) support async loading of "stories". Therefore
  7. // the strategy in frontend/js/i18n.ts does not work (because we cannot wait on
  8. // the promise to resolve).
  9. // Therefore we have to use the synchronous method for configuring
  10. // react-i18next. Because this, we can only hard-code a single language.
  11. import i18n from 'i18next'
  12. import { initReactI18next } from 'react-i18next'
  13. // @ts-ignore
  14. import en from '../../../services/web/locales/en.json'
  15. function resetMeta() {
  16. window.metaAttributesCache = new Map()
  17. window.metaAttributesCache.set('ol-i18n', { currentLangCode: 'en' })
  18. window.metaAttributesCache.set('ol-capabilities', ['chat'])
  19. window.metaAttributesCache.set('ol-compileSettings', {
  20. compileTimeout: 20,
  21. })
  22. window.metaAttributesCache.set('ol-ExposedSettings', {
  23. adminEmail: 'placeholder@example.com',
  24. appName: 'Overleaf',
  25. cookieDomain: '.overleaf.stories',
  26. dropboxAppName: 'Overleaf-Stories',
  27. emailConfirmationDisabled: false,
  28. enableSubscriptions: true,
  29. hasAffiliationsFeature: false,
  30. hasLinkUrlFeature: true,
  31. hasLinkedProjectFileFeature: true,
  32. hasLinkedProjectOutputFileFeature: true,
  33. hasSamlFeature: true,
  34. ieeeBrandId: 15,
  35. isOverleaf: true,
  36. labsEnabled: true,
  37. maxEntitiesPerProject: 10,
  38. maxUploadSize: 5 * 1024 * 1024,
  39. recaptchaDisabled: {
  40. invite: true,
  41. login: true,
  42. passwordReset: true,
  43. register: true,
  44. addEmail: true,
  45. },
  46. sentryAllowedOriginRegex: '',
  47. siteUrl: 'http://localhost',
  48. templateLinks: [],
  49. textExtensions: [
  50. 'tex',
  51. 'latex',
  52. 'sty',
  53. 'cls',
  54. 'bst',
  55. 'bib',
  56. 'bibtex',
  57. 'txt',
  58. 'tikz',
  59. 'mtx',
  60. 'rtex',
  61. 'md',
  62. 'asy',
  63. 'lbx',
  64. 'bbx',
  65. 'cbx',
  66. 'm',
  67. 'lco',
  68. 'dtx',
  69. 'ins',
  70. 'ist',
  71. 'def',
  72. 'clo',
  73. 'ldf',
  74. 'rmd',
  75. 'lua',
  76. 'gv',
  77. 'mf',
  78. 'lhs',
  79. 'lean',
  80. 'lean4',
  81. 'hs',
  82. 'mk',
  83. 'xmpdata',
  84. 'cfg',
  85. 'rnw',
  86. 'ltx',
  87. 'inc',
  88. ],
  89. editableFilenames: ['latexmkrc', '.latexmkrc', 'makefile', 'gnumakefile'],
  90. validRootDocExtensions: ['tex', 'Rtex', 'ltx', 'Rnw'],
  91. fileIgnorePattern:
  92. '**/{{__MACOSX,.git,.texpadtmp,.R}{,/**},.!(latexmkrc),*.{dvi,aux,log,toc,out,pdfsync,synctex,synctex(busy),fdb_latexmk,fls,nlo,ind,glo,gls,glg,bbl,blg,doc,docx,gz,swp}}',
  93. projectUploadTimeout: 12000,
  94. })
  95. }
  96. i18n.use(initReactI18next).init({
  97. lng: 'en',
  98. // still using the v3 plural suffixes
  99. compatibilityJSON: 'v3',
  100. resources: {
  101. en: { translation: en },
  102. },
  103. react: {
  104. useSuspense: false,
  105. transSupportBasicHtmlNodes: false,
  106. },
  107. interpolation: {
  108. prefix: '__',
  109. suffix: '__',
  110. unescapeSuffix: 'HTML',
  111. skipOnVariables: true,
  112. escapeValue: false,
  113. defaultVariables: {
  114. appName: 'Overleaf',
  115. },
  116. },
  117. })
  118. export default definePreview({
  119. addons: [addonA11y(), addonDesigns(), addonDocs(), addonLinks()],
  120. parameters: {
  121. // Automatically mark prop-types like onClick, onToggle, etc as Storybook
  122. // "actions", so that they are logged in the Actions pane at the bottom of the
  123. // viewer
  124. actions: { argTypesRegex: '^on.*' },
  125. docs: {
  126. story: {
  127. // render stories in iframes, to isolate modals
  128. inline: false,
  129. },
  130. },
  131. options: {
  132. storySort: {
  133. method: 'alphabetical',
  134. order: [
  135. 'Storybook Guideline',
  136. ['Foundations', 'Storybook builds', 'Feature Flags'],
  137. 'Shared',
  138. ],
  139. },
  140. },
  141. },
  142. globalTypes: {
  143. theme: {
  144. name: 'Theme',
  145. description: 'Editor theme',
  146. defaultValue: 'main-',
  147. toolbar: {
  148. icon: 'circlehollow',
  149. items: [
  150. { value: 'main-', title: 'Default' },
  151. { value: 'main-light-', title: 'Light' },
  152. ],
  153. },
  154. },
  155. },
  156. loaders: [
  157. async () => {
  158. return {
  159. mainStyle: await import(
  160. // @ts-ignore
  161. `!!to-string-loader!css-loader!resolve-url-loader!sass-loader!../../../services/web/frontend/stylesheets/main-style.scss`
  162. ),
  163. }
  164. },
  165. ],
  166. decorators: [
  167. (Story, context) => {
  168. const { mainStyle } = context.loaded
  169. resetMeta()
  170. return (
  171. <div
  172. data-theme={
  173. context.globals.theme === 'main-light-' ? 'light' : 'default'
  174. }
  175. >
  176. {mainStyle && <style>{mainStyle.default}</style>}
  177. <Story {...context} />
  178. </div>
  179. )
  180. },
  181. ],
  182. })
  183. // Populate meta for top-level access in modules on import
  184. resetMeta()