Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show images in documentation #10205

Merged
merged 42 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
1f8817a
Selection formatting toolbar
kazcw May 16, 2024
04b85ac
Merge remote-tracking branch 'origin/develop' into wip/kw/selection-f…
kazcw May 22, 2024
9ae2e19
Icons
kazcw May 22, 2024
f0c9856
Review
kazcw May 22, 2024
44d37fd
Fix bold+italic rendering
kazcw May 22, 2024
03cad1a
Preparing for top bar
kazcw May 24, 2024
703fc0f
Top bar
kazcw May 24, 2024
d857068
Merge remote-tracking branch 'origin/develop' into wip/kw/format-bar
kazcw May 24, 2024
4e229cb
Introduce APIs for Markdown formatting bar UI; use new APIs to simplify
kazcw May 24, 2024
dba482f
Clean up
kazcw May 24, 2024
86fa101
Refactor
kazcw May 24, 2024
80001b1
Refactor
kazcw May 24, 2024
b7a87ab
Lint
kazcw May 24, 2024
368794d
Clean up
kazcw May 24, 2024
a597aee
Merge remote-tracking branch 'origin/develop' into wip/kw/format-bar
kazcw May 24, 2024
e3c3def
Lint
kazcw May 24, 2024
2e4b7ca
Merge remote-tracking branch 'origin/develop' into wip/kw/format-bar
kazcw May 24, 2024
c329bd2
Merge remote-tracking branch 'origin/develop' into wip/kw/format-bar
kazcw May 24, 2024
d23acac
Limit smallest heading style to match the levels shown in the formatt…
kazcw May 24, 2024
e902f1c
Fix block quotes
kazcw May 24, 2024
6935465
Close menu on click
kazcw May 24, 2024
ecd1e01
Merge remote-tracking branch 'origin/develop' into wip/kw/format-bar
kazcw Jun 3, 2024
d328f76
Buffer updates
kazcw Jun 3, 2024
6741fce
Fix logical merge conflict
kazcw Jun 3, 2024
ecc96b4
Fix close button location
kazcw Jun 3, 2024
461e9f9
Review
kazcw Jun 4, 2024
152421d
Update tests
kazcw Jun 4, 2024
cdff55a
Fix
kazcw Jun 4, 2024
284e094
Fix
kazcw Jun 4, 2024
b6e321e
fix
kazcw Jun 4, 2024
da9e235
Merge remote-tracking branch 'origin/develop' into wip/kw/format-bar
kazcw Jun 5, 2024
0953e65
Update Lexical
kazcw Jun 4, 2024
fa8de14
Reorganize
kazcw Jun 5, 2024
5afaa45
Fix bug
kazcw Jun 5, 2024
1c70aea
Merge remote-tracking branch 'origin/develop' into wip/kw/format-bar
kazcw Jun 5, 2024
99fe686
Move some logic out of GraphEditor
kazcw Jun 5, 2024
1f4a2c9
projectStore provides projectRoot
kazcw Jun 6, 2024
ddd9e31
Documentation images
kazcw Jun 6, 2024
11d6df4
lint
kazcw Jun 6, 2024
3f53dcb
Merge remote-tracking branch 'origin/develop' into wip/kw/doc-images
kazcw Jun 7, 2024
ac26ee4
Review
kazcw Jun 7, 2024
9b9d9a9
CHANGELOG
kazcw Jun 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/gui2/e2e/locate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export const addNewNodeButton = componentLocator('PlusButton')
export const componentBrowser = componentLocator('ComponentBrowser')
export const nodeOutputPort = componentLocator('outputPortHoverArea')
export const smallPlusButton = componentLocator('SmallPlusButton')
export const lexicalContent = componentLocator('LexicalContent')

export function componentBrowserEntry(
page: Locator | Page,
Expand All @@ -127,6 +128,10 @@ export function componentBrowserEntryByLabel(page: Locator | Page, label: string
return componentBrowserEntry(page).filter({ has: page.getByText(label) })
}

export function rightDock(page: Page) {
return page.getByTestId('rightDock')
}

export const navBreadcrumb = componentLocator('NavBreadcrumb')
export const componentBrowserInput = componentLocator('ComponentEditor')
export const jsonVisualization = componentLocator('JSONVisualization')
Expand Down
9 changes: 5 additions & 4 deletions app/gui2/e2e/rightDock.spec.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { expect, test } from 'playwright/test'
import * as actions from './actions'
import { CONTROL_KEY } from './keyboard'
import * as locate from './locate'

test('Main method documentation', async ({ page }) => {
await actions.goToGraph(page)

// Documentation panel hotkey opens right-dock.
await expect(page.getByTestId('rightDock')).not.toBeVisible()
await expect(locate.rightDock(page)).not.toBeVisible()
await page.keyboard.press(`${CONTROL_KEY}+D`)
await expect(page.getByTestId('rightDock')).toBeVisible()
await expect(locate.rightDock(page)).toBeVisible()

// Right-dock displays main method documentation.
await expect(page.getByTestId('rightDock')).toHaveText('The main method')
await expect(locate.lexicalContent(locate.rightDock(page))).toHaveText('The main method')

// Documentation hotkey closes right-dock.p
await page.keyboard.press(`${CONTROL_KEY}+D`)
await expect(page.getByTestId('rightDock')).not.toBeVisible()
await expect(locate.rightDock(page)).not.toBeVisible()
})
4 changes: 1 addition & 3 deletions app/gui2/mock/MockFSWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ watchEffect(async (onCleanup) => {
const prefixLength = props.prefix?.length ?? 0
const directory = maybeDirectory
const ls = await projectStore.lsRpcConnection
const maybeProjectRoot = (await projectStore.contentRoots).find(
(root) => root.type === 'Project',
)?.id
const maybeProjectRoot = await projectStore.projectRootId
if (!maybeProjectRoot) return
const projectRoot = maybeProjectRoot
async function walkFiles(
Expand Down
17 changes: 9 additions & 8 deletions app/gui2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,14 @@
"@babel/parser": "^7.22.16",
"@fast-check/vitest": "^0.0.8",
"@floating-ui/vue": "^1.0.6",
"@lexical/code": "^0.15.0",
"@lexical/link": "^0.15.0",
"@lexical/list": "^0.15.0",
"@lexical/markdown": "^0.15.0",
"@lexical/plain-text": "^0.15.0",
"@lexical/rich-text": "^0.15.0",
"@lexical/table": "^0.15.0",
"@lexical/code": "^0.16.0",
"@lexical/link": "^0.16.0",
"@lexical/list": "^0.16.0",
"@lexical/markdown": "^0.16.0",
"@lexical/plain-text": "^0.16.0",
"@lexical/rich-text": "^0.16.0",
"@lexical/table": "^0.16.0",
"@lexical/utils": "^0.16.0",
"@lezer/common": "^1.1.0",
"@lezer/highlight": "^1.1.6",
"@noble/hashes": "^1.3.2",
Expand All @@ -67,7 +68,7 @@
"hash-sum": "^2.0.0",
"install": "^0.13.0",
"isomorphic-ws": "^5.0.0",
"lexical": "^0.15.0",
"lexical": "^0.16.0",
"lib0": "^0.2.85",
"magic-string": "^0.30.3",
"murmurhash": "^2.0.1",
Expand Down
76 changes: 76 additions & 0 deletions app/gui2/src/components/DockPanel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<script setup lang="ts">
import ResizeHandles from '@/components/ResizeHandles.vue'
import SvgButton from '@/components/SvgButton.vue'
import { useResizeObserver } from '@/composables/events'
import { Rect } from '@/util/data/rect'
import { Vec2 } from '@/util/data/vec2'
import { computed, ref } from 'vue'

const rootElement = ref<HTMLElement>()

const show = defineModel<boolean>('show', { required: true })
const size = defineModel<number | undefined>('size')

const computedSize = useResizeObserver(rootElement)
const computedBounds = computed(() => new Rect(Vec2.Zero, computedSize.value))

const style = computed(() => {
return {
width: size.value != null ? `${size.value}px` : undefined,
}
})
</script>

<template>
<Transition name="rightDock">
<div v-if="show" ref="rootElement" class="DockPanel rightDock" :style="style">
<div class="scrollArea">
<slot />
</div>
<SvgButton name="close" class="closeButton button" @click.stop="show = false" />
<ResizeHandles left :modelValue="computedBounds" @update:modelValue="size = $event.width" />
</div>
</Transition>
</template>

<style scoped>
.DockPanel {
position: absolute;
top: 46px;
bottom: 0;
width: var(--right-dock-default-width);
right: 0;
border-radius: 7px 0 0;
background-color: rgba(255, 255, 255, 0.35);
backdrop-filter: var(--blur-app-bg);
padding: 4px 12px 0 0;
}
.rightDock-enter-active,
.rightDock-leave-active {
transition: left 0.25s ease;
/* Prevent absolutely-positioned children (such as the close button) from bypassing the show/hide animation. */
overflow-x: clip;
}
.rightDock-enter-from,
.rightDock-leave-to {
width: 0;
}
.rightDock .scrollArea {
width: 100%;
height: 100%;
overflow-y: auto;
padding-left: 6px;
}

.rightDock .closeButton {
position: absolute;
top: 4px;
right: 28px;
color: red;
opacity: 0.3;

&:hover {
opacity: 0.6;
}
}
</style>
79 changes: 79 additions & 0 deletions app/gui2/src/components/DocumentationEditor.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<script setup lang="ts">
import MarkdownEditor from '@/components/MarkdownEditor.vue'
import { fetcherUrlTransformer } from '@/components/MarkdownEditor/imageUrlTransformer'
import { useProjectStore } from '@/stores/project'
import type { Path, Uuid } from 'shared/languageServerTypes'
import { Err, Ok, mapOk, withContext, type Result } from 'shared/util/data/result'

const documentation = defineModel<string>({ required: true })

const projectStore = useProjectStore()
const { transformImageUrl } = useDocumentationImages(
projectStore.projectRootId,
projectStore.readFileBinary,
)

function useDocumentationImages(
projectRootId: Promise<Uuid | undefined>,
readFileBinary: (path: Path) => Promise<Result<Blob>>,
) {
async function urlToPath(url: string): Promise<Result<Path> | undefined> {
if (url.includes('//')) {
// Not a relative URL, custom fetching not needed.
return undefined
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, inside paths, double / is treated as single /, at least on Linuxes. Maybe check for : presence?

Copy link
Contributor Author

@kazcw kazcw Jun 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll use the URL API.

} else {
return relativeUrlToPath(url)
}
}

async function relativeUrlToPath(url: string): Promise<Result<Path>> {
const rootId = await projectRootId
if (!rootId) {
return Err('Cannot find project root.')
}
if (url.startsWith('/')) {
// Relative to project root.
return Ok({ rootId, segments: url.slice(1).split('/') })
} else {
// Relative to current module.
const segments = url.split('/')
if (segments[0] === '..') {
return Ok({ rootId, segments: segments.slice(1) })
} else {
return Ok({ rootId, segments: ['src', ...segments] })
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We assume we're in src module. Let's put the current module's path somewhere (graph store?) so once we implement opening modules, this part will continue working.

}

function pathUniqueId(path: Path) {
return path.rootId + ':' + path.segments.join('/')
}

function pathDebugRepr(path: Path) {
return pathUniqueId(path)
}

const transformImageUrl = fetcherUrlTransformer(
async (url: string) => {
const path = await urlToPath(url)
if (!path) return
return withContext(
() => `Locating documentation image (${url})`,
() => mapOk(path, (path) => ({ location: path, uniqueId: pathUniqueId(path) })),
)
},
async (path) => {
return withContext(
() => `Loading documentation image (${pathDebugRepr(path)})`,
async () => await readFileBinary(path),
)
},
)

return { transformImageUrl }
}
</script>

<template>
<MarkdownEditor v-model="documentation" :transformImageUrl="transformImageUrl" />
</template>
2 changes: 1 addition & 1 deletion app/gui2/src/components/ExtendedMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const toggleDocumentationEditorShortcut = documentationEditorBindings.bindings.t
margin: 4px;
}

.ExtendedMenu :deep(.DropdownMenuContent) {
:deep(.DropdownMenuContent) {
width: 250px;
margin-top: 2px;
padding: 4px;
Expand Down
Loading
Loading