New-project menu: split into Quarto and LaTeX blank/example options
Build and Deploy Verso / deploy (push) Successful in 7m44s
Build and Deploy Verso / deploy (push) Successful in 7m44s
Replace the generic "Blank project" / "Example project" entries with four flavour-specific ones in both the New-project dropdown and the welcome-screen dropdown: - Blank Quarto project -> empty main.qmd (format: typst) - Blank LaTeX project -> empty main.tex - Example Quarto project -> a Reveal.js presentation showcasing images, math, a table, code and incremental lists (new template project_files/example-project-quarto/) - Example LaTeX project -> the existing LaTeX example Backend: ProjectController.newProject now dispatches the `template` value (blank_quarto/blank_latex/example_quarto/example_latex, plus the legacy 'example'/'none') to createBasicProject(flavour) / createExampleProject(flavour). _createRootDoc takes a root-doc name so each flavour gets the right extension — this also fixes the LaTeX example, whose root doc was wrongly created as main.qmd, back to main.tex (matching the acceptance test). Signatures stay backward compatible (flavour defaults: blank=quarto, example=latex). Also refresh the README: Verso now runs Quarto and LaTeX side by side (engine chosen by root-file extension), not Quarto instead of LaTeX. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
3e10d1c4ee
commit
2a9c4cfe81
@@ -1,15 +1,15 @@
|
||||
# Verso
|
||||
|
||||
**A collaborative real-time editor for Quarto presentations and documents.**
|
||||
**A collaborative real-time editor for Quarto and LaTeX presentations and documents.**
|
||||
|
||||
Verso is a fork of [Overleaf](https://github.com/overleaf/overleaf) adapted to compile [Quarto](https://quarto.org) documents instead of LaTeX. It keeps Overleaf's real-time collaboration infrastructure while replacing the LaTeX/CLSI compiler with Quarto, enabling collaborative editing of `.qmd` files with instant PDF (via Typst) or HTML (RevealJS) preview.
|
||||
Verso is a fork of [Overleaf](https://github.com/overleaf/overleaf) that adds first-class [Quarto](https://quarto.org) support alongside Overleaf's existing LaTeX toolchain. It keeps Overleaf's real-time collaboration infrastructure and runs **two compilers side by side**: `.qmd` files are built with Quarto (PDF via Typst, or HTML via RevealJS), while `.tex` files still compile with `latexmk`/TeX Live. The engine is selected automatically from the root file's extension, so Quarto and LaTeX projects coexist.
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
- **Real-time collaboration** — multiple users editing the same `.qmd` file simultaneously, powered by Overleaf's operational-transformation engine
|
||||
- **Quarto compilation** — documents are compiled with Quarto on every save
|
||||
- **Dual compiler** — `.qmd` files build with Quarto; `.tex` files build with `latexmk`/TeX Live. The runner is chosen by the root file's extension, so LaTeX and Quarto projects live side by side
|
||||
- **Two output formats** — set `format: typst` in the YAML frontmatter for a PDF preview, or `format: revealjs` for an interactive HTML presentation rendered in an iframe
|
||||
- **Document outline** — headings (`#`, `##`, `###`) are extracted and shown in the sidebar outline panel
|
||||
- **Math, code, tables** — standard Quarto/Pandoc Markdown features all work
|
||||
@@ -44,7 +44,7 @@ Then open `http://localhost` in your browser. On first run, visit `/launchpad` t
|
||||
### Build from source
|
||||
|
||||
```bash
|
||||
# Build the base image (installs Quarto)
|
||||
# Build the base image (installs Quarto + TeX Live)
|
||||
cd server-ce
|
||||
make build-base
|
||||
|
||||
@@ -56,7 +56,7 @@ The two Dockerfiles are:
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `server-ce/Dockerfile-base` | Base OS image — installs system deps and Quarto |
|
||||
| `server-ce/Dockerfile-base` | Base OS image — installs system deps, Quarto, and a TeX Live (`latexmk`) toolchain |
|
||||
| `server-ce/Dockerfile` | Application image — installs Node services, compiles frontend |
|
||||
|
||||
## Architecture
|
||||
@@ -70,7 +70,7 @@ browser ──→ nginx:80
|
||||
└── /project/*/output/* → clsi-nginx:8080 (compiled output files)
|
||||
|
||||
web → document-updater → Redis pub/sub → real-time → browser
|
||||
web → CLSI (quarto render) → output files → nginx → browser
|
||||
web → CLSI (quarto render / latexmk) → output files → nginx → browser
|
||||
```
|
||||
|
||||
Key services:
|
||||
@@ -80,7 +80,7 @@ Key services:
|
||||
| `web` | HTTP API, React frontend, auth, project management |
|
||||
| `real-time` | WebSocket layer, live cursor and edit sync |
|
||||
| `document-updater` | Operational transformation, Redis pub/sub |
|
||||
| `clsi` | Quarto compiler — runs `quarto render` and serves output |
|
||||
| `clsi` | Compiler — runs `quarto render` (`.qmd`) or `latexmk` (`.tex`) and serves output |
|
||||
| `docstore` | Document text storage (MongoDB) |
|
||||
| `filestore` | Binary file storage (S3 or local) |
|
||||
| `project-history` | Change history and version tracking |
|
||||
@@ -111,6 +111,18 @@ For PDF output, change `format: revealjs` to `format: typst`.
|
||||
> **Note on display math**: put `$$...$$` on a single line.
|
||||
> Multi-line display math blocks can cause YAML parse errors in some Quarto versions.
|
||||
|
||||
## Writing a LaTeX document
|
||||
|
||||
LaTeX still works exactly as in Overleaf. A project whose root file is a `.tex`
|
||||
file (e.g. `main.tex`) compiles with `latexmk`/TeX Live instead of Quarto — the
|
||||
engine is chosen from the root file's extension, no setting required. The
|
||||
**Example LaTeX project** in the *New project* menu is a ready-made starting
|
||||
point; **Blank LaTeX project** gives you an empty `main.tex`.
|
||||
|
||||
> The bundled TeX Live is a minimal `scheme-basic` install. Documents needing
|
||||
> extra packages may not build out of the box yet — see `server-ce/Dockerfile-base`
|
||||
> for how to switch to a fuller TeX Live scheme.
|
||||
|
||||
## Environment variables
|
||||
|
||||
Verso inherits all of Overleaf's environment variables (prefixed `OVERLEAF_`).
|
||||
|
||||
@@ -323,12 +323,44 @@ const _ProjectController = {
|
||||
req.body.projectName != null ? req.body.projectName.trim() : undefined
|
||||
const { template } = req.body
|
||||
|
||||
const project = await (template === 'example'
|
||||
? ProjectCreationHandler.promises.createExampleProject(
|
||||
// The "template" selects flavour (Quarto vs LaTeX) and kind (blank vs
|
||||
// example). 'example'/'none' are kept for backwards compatibility.
|
||||
let project
|
||||
switch (template) {
|
||||
case 'example':
|
||||
case 'example_latex':
|
||||
project = await ProjectCreationHandler.promises.createExampleProject(
|
||||
userId,
|
||||
projectName
|
||||
projectName,
|
||||
{},
|
||||
'latex'
|
||||
)
|
||||
: ProjectCreationHandler.promises.createBasicProject(userId, projectName))
|
||||
break
|
||||
case 'example_quarto':
|
||||
project = await ProjectCreationHandler.promises.createExampleProject(
|
||||
userId,
|
||||
projectName,
|
||||
{},
|
||||
'quarto'
|
||||
)
|
||||
break
|
||||
case 'blank_latex':
|
||||
project = await ProjectCreationHandler.promises.createBasicProject(
|
||||
userId,
|
||||
projectName,
|
||||
'latex'
|
||||
)
|
||||
break
|
||||
case 'blank_quarto':
|
||||
case 'none':
|
||||
default:
|
||||
project = await ProjectCreationHandler.promises.createBasicProject(
|
||||
userId,
|
||||
projectName,
|
||||
'quarto'
|
||||
)
|
||||
break
|
||||
}
|
||||
|
||||
ProjectAuditLogHandler.addEntryIfManagedInBackground(
|
||||
project._id,
|
||||
|
||||
@@ -85,11 +85,19 @@ async function createProjectFromSnippet(ownerId, projectName, docLines) {
|
||||
return project
|
||||
}
|
||||
|
||||
async function createBasicProject(ownerId, projectName) {
|
||||
async function createBasicProject(ownerId, projectName, flavour = 'quarto') {
|
||||
const project = await _createBlankProject(ownerId, projectName)
|
||||
|
||||
const docLines = await _buildTemplate('mainbasic.qmd', ownerId, projectName)
|
||||
await _createRootDoc(project, ownerId, docLines)
|
||||
// Verso compiles .qmd with Quarto and .tex with latexmk; the root file's
|
||||
// extension selects the runner (see CompileManager._isQuartoFile in CLSI),
|
||||
// so a blank project's flavour is just a choice of template + root name.
|
||||
const { templateName, rootDocName } =
|
||||
flavour === 'latex'
|
||||
? { templateName: 'mainbasic.tex', rootDocName: 'main.tex' }
|
||||
: { templateName: 'mainbasic.qmd', rootDocName: 'main.qmd' }
|
||||
|
||||
const docLines = await _buildTemplate(templateName, ownerId, projectName)
|
||||
await _createRootDoc(project, ownerId, docLines, rootDocName)
|
||||
|
||||
AnalyticsManager.recordEventForUserInBackground(ownerId, 'project-created', {
|
||||
projectId: project._id,
|
||||
@@ -163,20 +171,29 @@ async function populateClsiCacheForExampleProject(
|
||||
return projectId
|
||||
}
|
||||
|
||||
async function createExampleProject(ownerId, projectName, attributes = {}) {
|
||||
async function createExampleProject(
|
||||
ownerId,
|
||||
projectName,
|
||||
attributes = {},
|
||||
flavour = 'latex'
|
||||
) {
|
||||
const project = await _createBlankProject(ownerId, projectName, attributes)
|
||||
|
||||
const { fileEntries, docEntries } = await _addExampleProjectFiles(
|
||||
ownerId,
|
||||
projectName,
|
||||
project
|
||||
)
|
||||
await populateClsiCacheForExampleProject(
|
||||
ownerId,
|
||||
project,
|
||||
fileEntries,
|
||||
docEntries
|
||||
)
|
||||
const { fileEntries, docEntries } =
|
||||
flavour === 'quarto'
|
||||
? await _addQuartoExampleProjectFiles(ownerId, projectName, project)
|
||||
: await _addExampleProjectFiles(ownerId, projectName, project)
|
||||
|
||||
if (flavour !== 'quarto') {
|
||||
// clsi-cache warming keys on a single static example; only do it for the
|
||||
// long-standing LaTeX example to avoid the "content is not static" guard.
|
||||
await populateClsiCacheForExampleProject(
|
||||
ownerId,
|
||||
project,
|
||||
fileEntries,
|
||||
docEntries
|
||||
)
|
||||
}
|
||||
|
||||
AnalyticsManager.recordEventForUserInBackground(ownerId, 'project-created', {
|
||||
projectId: project._id,
|
||||
@@ -191,7 +208,12 @@ async function _addExampleProjectFiles(ownerId, projectName, project) {
|
||||
ownerId,
|
||||
projectName
|
||||
)
|
||||
const rootDoc = await _createRootDoc(project, ownerId, mainDocLines)
|
||||
const rootDoc = await _createRootDoc(
|
||||
project,
|
||||
ownerId,
|
||||
mainDocLines,
|
||||
'main.tex'
|
||||
)
|
||||
|
||||
const bibDocLines = await _buildTemplate(
|
||||
`${templateProjectDir}/sample.bib`,
|
||||
@@ -229,6 +251,40 @@ async function _addExampleProjectFiles(ownerId, projectName, project) {
|
||||
}
|
||||
}
|
||||
|
||||
async function _addQuartoExampleProjectFiles(ownerId, projectName, project) {
|
||||
const mainDocLines = await _buildTemplate(
|
||||
'example-project-quarto/main.qmd',
|
||||
ownerId,
|
||||
projectName
|
||||
)
|
||||
const rootDoc = await _createRootDoc(
|
||||
project,
|
||||
ownerId,
|
||||
mainDocLines,
|
||||
'main.qmd'
|
||||
)
|
||||
|
||||
const imagePath = path.join(
|
||||
import.meta.dirname,
|
||||
'/../../../templates/project_files/example-project-quarto/frog.jpg'
|
||||
)
|
||||
const { fileRef } = await ProjectEntityUpdateHandler.promises.addFile(
|
||||
project._id,
|
||||
project.rootFolder[0]._id,
|
||||
'frog.jpg',
|
||||
imagePath,
|
||||
null,
|
||||
ownerId,
|
||||
null
|
||||
)
|
||||
return {
|
||||
fileEntries: [{ path: fileRef.name, file: fileRef }],
|
||||
docEntries: [
|
||||
{ path: 'main.qmd', doc: rootDoc, docLines: mainDocLines.join('\n') },
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
async function _createBlankProject(
|
||||
ownerId,
|
||||
projectName,
|
||||
@@ -299,12 +355,17 @@ async function _createBlankProject(
|
||||
return project
|
||||
}
|
||||
|
||||
async function _createRootDoc(project, ownerId, docLines) {
|
||||
async function _createRootDoc(
|
||||
project,
|
||||
ownerId,
|
||||
docLines,
|
||||
rootDocName = 'main.qmd'
|
||||
) {
|
||||
try {
|
||||
const { doc } = await ProjectEntityUpdateHandler.promises.addDoc(
|
||||
project._id,
|
||||
project.rootFolder[0]._id,
|
||||
'main.qmd',
|
||||
rootDocName,
|
||||
docLines,
|
||||
ownerId,
|
||||
null
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 95 KiB |
@@ -0,0 +1,84 @@
|
||||
---
|
||||
title: "<%= project_name %>"
|
||||
author: "<%= user.first_name %> <%= user.last_name %>"
|
||||
date: "<%= month %> <%= year %>"
|
||||
format:
|
||||
revealjs:
|
||||
theme: simple
|
||||
slide-number: true
|
||||
chalkboard: true
|
||||
---
|
||||
|
||||
## Welcome to Verso
|
||||
|
||||
This is an example **presentation** written in [Quarto](https://quarto.org)
|
||||
and rendered to interactive HTML slides with Reveal.js.
|
||||
|
||||
- Write your slides in plain Markdown
|
||||
- Mix in math, code, images and tables
|
||||
- Hit **Recompile** to see your changes instantly
|
||||
|
||||
::: aside
|
||||
Use the arrow keys to navigate, and press `f` for fullscreen.
|
||||
:::
|
||||
|
||||
## Mathematics
|
||||
|
||||
Inline math such as $E = mc^2$ renders inline, and display equations are
|
||||
centered automatically:
|
||||
|
||||
$$
|
||||
\int_{-\infty}^{\infty} e^{-x^2}\,dx = \sqrt{\pi}
|
||||
$$
|
||||
|
||||
. . .
|
||||
|
||||
You can reveal content step by step by separating it with `. . .`.
|
||||
|
||||
## Two columns
|
||||
|
||||
:::: {.columns}
|
||||
|
||||
::: {.column width="55%"}
|
||||
### Figures sit nicely beside text
|
||||
|
||||
Fenced columns let you place an explanation next to a figure — perfect for
|
||||
walking an audience through a diagram.
|
||||
:::
|
||||
|
||||
::: {.column width="45%"}
|
||||

|
||||
:::
|
||||
|
||||
::::
|
||||
|
||||
## Tables
|
||||
|
||||
| Engine | Output | Best for |
|
||||
|--------|:------:|-----------------------|
|
||||
| Typst | PDF | Fast, modern layout |
|
||||
| Reveal | HTML | Interactive slides |
|
||||
| LaTeX | PDF | Classic STEM articles |
|
||||
|
||||
: Quarto can target several output formats from one source. {.striped .hover}
|
||||
|
||||
## Code
|
||||
|
||||
Code blocks are syntax-highlighted out of the box:
|
||||
|
||||
```python
|
||||
def greet(name):
|
||||
return f"Hello, {name}!"
|
||||
|
||||
print(greet("Verso"))
|
||||
```
|
||||
|
||||
## Incremental lists {.incremental}
|
||||
|
||||
- Quarto turns Markdown into beautiful documents
|
||||
- The same source can become a PDF, a website or these slides
|
||||
- Now make this deck your own — edit `main.qmd`!
|
||||
|
||||
## Thank you {.center}
|
||||
|
||||
Questions? Start editing and explore what Quarto can do.
|
||||
@@ -192,24 +192,48 @@ function NewProjectButton({
|
||||
<DropdownItem
|
||||
onClick={e =>
|
||||
handleModalMenuClick(e, {
|
||||
modalVariant: 'blank_project',
|
||||
dropdownMenuEvent: 'blank-project',
|
||||
modalVariant: 'blank_quarto',
|
||||
dropdownMenuEvent: 'blank-project-quarto',
|
||||
})
|
||||
}
|
||||
>
|
||||
{t('blank_project')}
|
||||
{t('blank_quarto_project')}
|
||||
</DropdownItem>
|
||||
</li>
|
||||
<li role="none">
|
||||
<DropdownItem
|
||||
onClick={e =>
|
||||
handleModalMenuClick(e, {
|
||||
modalVariant: 'example_project',
|
||||
dropdownMenuEvent: 'example-project',
|
||||
modalVariant: 'blank_latex',
|
||||
dropdownMenuEvent: 'blank-project-latex',
|
||||
})
|
||||
}
|
||||
>
|
||||
{t('example_project')}
|
||||
{t('blank_latex_project')}
|
||||
</DropdownItem>
|
||||
</li>
|
||||
<li role="none">
|
||||
<DropdownItem
|
||||
onClick={e =>
|
||||
handleModalMenuClick(e, {
|
||||
modalVariant: 'example_quarto',
|
||||
dropdownMenuEvent: 'example-project-quarto',
|
||||
})
|
||||
}
|
||||
>
|
||||
{t('example_quarto_project')}
|
||||
</DropdownItem>
|
||||
</li>
|
||||
<li role="none">
|
||||
<DropdownItem
|
||||
onClick={e =>
|
||||
handleModalMenuClick(e, {
|
||||
modalVariant: 'example_latex',
|
||||
dropdownMenuEvent: 'example-project-latex',
|
||||
})
|
||||
}
|
||||
>
|
||||
{t('example_latex_project')}
|
||||
</DropdownItem>
|
||||
</li>
|
||||
<li role="none">
|
||||
|
||||
+11
-2
@@ -5,9 +5,14 @@ import { Tag } from '../../../../../../app/src/Features/Tags/types'
|
||||
type BlankProjectModalProps = {
|
||||
onHide: () => void
|
||||
initialTags?: Tag[]
|
||||
template?: string
|
||||
}
|
||||
|
||||
function BlankProjectModal({ onHide, initialTags }: BlankProjectModalProps) {
|
||||
function BlankProjectModal({
|
||||
onHide,
|
||||
initialTags,
|
||||
template = 'blank_quarto',
|
||||
}: BlankProjectModalProps) {
|
||||
return (
|
||||
<OLModal
|
||||
show
|
||||
@@ -16,7 +21,11 @@ function BlankProjectModal({ onHide, initialTags }: BlankProjectModalProps) {
|
||||
id="blank-project-modal"
|
||||
backdrop="static"
|
||||
>
|
||||
<ModalContentNewProjectForm onCancel={onHide} initialTags={initialTags} />
|
||||
<ModalContentNewProjectForm
|
||||
onCancel={onHide}
|
||||
template={template}
|
||||
initialTags={initialTags}
|
||||
/>
|
||||
</OLModal>
|
||||
)
|
||||
}
|
||||
|
||||
+3
-1
@@ -5,11 +5,13 @@ import { Tag } from '../../../../../../app/src/Features/Tags/types'
|
||||
type ExampleProjectModalProps = {
|
||||
onHide: () => void
|
||||
initialTags?: Tag[]
|
||||
template?: string
|
||||
}
|
||||
|
||||
function ExampleProjectModal({
|
||||
onHide,
|
||||
initialTags,
|
||||
template = 'example_latex',
|
||||
}: ExampleProjectModalProps) {
|
||||
return (
|
||||
<OLModal
|
||||
@@ -21,7 +23,7 @@ function ExampleProjectModal({
|
||||
>
|
||||
<ModalContentNewProjectForm
|
||||
onCancel={onHide}
|
||||
template="example"
|
||||
template={template}
|
||||
initialTags={initialTags}
|
||||
/>
|
||||
</OLModal>
|
||||
|
||||
+36
-6
@@ -11,8 +11,10 @@ const UploadProjectModal = lazy(() => import('./upload-project-modal'))
|
||||
const ImportDocumentModal = lazy(() => import('./import-document-modal'))
|
||||
|
||||
export type NewProjectButtonModalVariant =
|
||||
| 'blank_project'
|
||||
| 'example_project'
|
||||
| 'blank_quarto'
|
||||
| 'blank_latex'
|
||||
| 'example_quarto'
|
||||
| 'example_latex'
|
||||
| 'upload_project'
|
||||
| 'import_from_github'
|
||||
| 'import_docx'
|
||||
@@ -50,10 +52,38 @@ function NewProjectButtonModal({
|
||||
)
|
||||
|
||||
switch (modal) {
|
||||
case 'blank_project':
|
||||
return <BlankProjectModal onHide={onHide} initialTags={initialTags} />
|
||||
case 'example_project':
|
||||
return <ExampleProjectModal onHide={onHide} initialTags={initialTags} />
|
||||
case 'blank_quarto':
|
||||
return (
|
||||
<BlankProjectModal
|
||||
onHide={onHide}
|
||||
initialTags={initialTags}
|
||||
template="blank_quarto"
|
||||
/>
|
||||
)
|
||||
case 'blank_latex':
|
||||
return (
|
||||
<BlankProjectModal
|
||||
onHide={onHide}
|
||||
initialTags={initialTags}
|
||||
template="blank_latex"
|
||||
/>
|
||||
)
|
||||
case 'example_quarto':
|
||||
return (
|
||||
<ExampleProjectModal
|
||||
onHide={onHide}
|
||||
initialTags={initialTags}
|
||||
template="example_quarto"
|
||||
/>
|
||||
)
|
||||
case 'example_latex':
|
||||
return (
|
||||
<ExampleProjectModal
|
||||
onHide={onHide}
|
||||
initialTags={initialTags}
|
||||
template="example_latex"
|
||||
/>
|
||||
)
|
||||
case 'upload_project':
|
||||
return (
|
||||
<Suspense fallback={<FullSizeLoadingSpinner delay={500} />}>
|
||||
|
||||
+38
-4
@@ -113,22 +113,56 @@ function WelcomeMessageCreateNewProjectDropdown({
|
||||
<DropdownItem
|
||||
as="button"
|
||||
onClick={e =>
|
||||
handleDropdownItemClick(e, 'blank_project', 'blank-project')
|
||||
handleDropdownItemClick(
|
||||
e,
|
||||
'blank_quarto',
|
||||
'blank-project-quarto'
|
||||
)
|
||||
}
|
||||
tabIndex={-1}
|
||||
>
|
||||
{t('blank_project')}
|
||||
{t('blank_quarto_project')}
|
||||
</DropdownItem>
|
||||
</li>
|
||||
<li role="none">
|
||||
<DropdownItem
|
||||
as="button"
|
||||
onClick={e =>
|
||||
handleDropdownItemClick(e, 'example_project', 'example-project')
|
||||
handleDropdownItemClick(e, 'blank_latex', 'blank-project-latex')
|
||||
}
|
||||
tabIndex={-1}
|
||||
>
|
||||
{t('example_project')}
|
||||
{t('blank_latex_project')}
|
||||
</DropdownItem>
|
||||
</li>
|
||||
<li role="none">
|
||||
<DropdownItem
|
||||
as="button"
|
||||
onClick={e =>
|
||||
handleDropdownItemClick(
|
||||
e,
|
||||
'example_quarto',
|
||||
'example-project-quarto'
|
||||
)
|
||||
}
|
||||
tabIndex={-1}
|
||||
>
|
||||
{t('example_quarto_project')}
|
||||
</DropdownItem>
|
||||
</li>
|
||||
<li role="none">
|
||||
<DropdownItem
|
||||
as="button"
|
||||
onClick={e =>
|
||||
handleDropdownItemClick(
|
||||
e,
|
||||
'example_latex',
|
||||
'example-project-latex'
|
||||
)
|
||||
}
|
||||
tabIndex={-1}
|
||||
>
|
||||
{t('example_latex_project')}
|
||||
</DropdownItem>
|
||||
</li>
|
||||
<li role="none">
|
||||
|
||||
@@ -292,7 +292,9 @@
|
||||
"billing": "Billing",
|
||||
"billing_period_sentence_case": "Billing period",
|
||||
"binary_history_error": "Preview not available for this file type",
|
||||
"blank_latex_project": "Blank LaTeX project",
|
||||
"blank_project": "Blank project",
|
||||
"blank_quarto_project": "Blank Quarto project",
|
||||
"blocked_filename": "This file name is blocked.",
|
||||
"blog": "Blog",
|
||||
"bold": "Bold",
|
||||
@@ -837,7 +839,9 @@
|
||||
"everything_in_group_standard_plus": "Everything in Standard group, plus…",
|
||||
"everything_in_standard_plus": "Everything in Standard, plus…",
|
||||
"example": "Example",
|
||||
"example_latex_project": "Example LaTeX project",
|
||||
"example_project": "Example project",
|
||||
"example_quarto_project": "Example Quarto project",
|
||||
"examples": "Examples",
|
||||
"examples_lowercase": "examples",
|
||||
"examples_to_help_you_learn": "Examples to help you learn how to use powerful LaTeX packages and techniques.",
|
||||
|
||||
Reference in New Issue
Block a user