-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Playground Editor V2: Multi-file, ES modules, NPM Support #17175
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
Merged
Merged
Changes from all commits
Commits
Show all changes
58 commits
Select commit
Hold shift + click to select a range
cc05848
add multi file support
knervous dce8f07
prebuild check for built dependencies
knervous 4d800f3
option for standalone and @dev deps
knervous 720e447
rm unused function
knervous 2059917
try with preflight commands
knervous 3731550
try public path
knervous eb5a0c0
output
knervous e245b98
monaco worker names
knervous 100bcf1
update build with chunks
knervous 6259faa
try base
knervous 4b314ce
rename
knervous 1051846
readd
knervous 14e8605
upgrade monaco, use scrollelement to get closer to vscode, real lexer…
knervous f6c6115
scroll state memory persistence, support for fx/glsl/wgsl files, tab …
knervous a518dc3
link follow enabled with cmd/ctrl click and scroll sync
knervous 54af9bb
add divider
knervous 5f5bc60
touch support for scroll
knervous a3268ad
split monacoManager into separate services, turn text block into a ru…
knervous 9abf07f
cleanup
knervous 1ee51f3
npm export dirs working
knervous 4f2855d
ata fixes, path fixes
knervous f816077
support for pinning versions and local package links
knervous de96d98
neuter package.json and downstream bjs ATA
knervous bc51b69
fix ensuring exports for v1 snippets, language change hydration
knervous dcc334c
create custom engine and compatibility entrypoints
knervous 4e8d585
merge master and update for dispose lifecycle and caching workers
knervous 6dc884a
merge in master, implement download esm service
knervous b056dca
esbuild bundle in download and fix rename file
knervous 284bd5f
add local file revision tools, unify theme and style with dialogs
knervous 1a6993d
local hash session support
knervous ea8d310
rm built pg bundle
knervous 7412442
cleanup before merge request
knervous 1f9d9e4
more cleanup
knervous 8084c09
format and start fixing tests
knervous ed7ab33
selector for editor
knervous 7ed2335
restore default PG code with comments, update test and safe b64 encod…
knervous 36bd733
b64 safety
knervous c045b60
remove ts worker singleton wrapper
knervous 11fec81
vercel
knervous 907de03
change
knervous 00948fa
change for deploy
knervous 35049eb
change
knervous 0e10882
schema
knervous 38912b4
root
knervous 5efd4bb
cors creds
knervous 1f4ed13
clean up scrolling, event listeners, logic for create/duplicate
knervous ef77e4b
implement file explorer
knervous ecadbab
merge master
knervous 53d1541
vscode icons + styling + merge upstream
knervous a886b8e
extra semi
knervous 425522e
consolidate snippet type definitions, versioning, add v2 handling to …
knervous fa16cdc
likely cyclic dependency
knervous 84139c7
add search activity panel
knervous de2829a
styling and shortcuts, formatting
knervous 8e3ee54
key handler qualifier for search, styling in search pane, local npm m…
knervous dfe95b4
local resolution in runner
knervous b5110b0
skip WS file ambient module declarations for ts
knervous 84c718f
Merge branch 'master' into pgv2
deltakosh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
173 changes: 173 additions & 0 deletions
173
packages/tools/playground/src/components/editor/activityBarComponent.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
/* eslint-disable jsdoc/require-jsdoc */ | ||
// activityBarComponent.tsx | ||
import * as React from "react"; | ||
import type { GlobalState } from "../../globalState"; | ||
import HistoryIcon from "./icons/history.svg"; | ||
import FilesIcon from "./icons/files.svg"; | ||
import SearchIcon from "./icons/search.svg"; | ||
import { FileDialog } from "./fileDialog"; | ||
import { LocalSessionDialog } from "./localSessionDialog"; | ||
import { Utilities } from "../../tools/utilities"; | ||
import { Icon } from "./iconComponent"; | ||
|
||
type DialogKind = "create" | "rename" | "duplicate"; | ||
type DialogState = { | ||
open: boolean; | ||
type: DialogKind | null; | ||
title: string; | ||
initialValue: string; | ||
targetPath?: string; | ||
}; | ||
|
||
export type ActivityBarHandle = { | ||
openCreateDialog: (suggestedName?: string) => void; | ||
openRenameDialog: (targetPath: string, initialDisplay?: string) => void; | ||
openDuplicateDialog: (targetPath: string, suggestedName?: string) => void; | ||
toggleSessionDialog: () => void; | ||
}; | ||
|
||
interface IActivityBarProps { | ||
globalState: GlobalState; | ||
|
||
// Monaco owns mutations | ||
onConfirmFileDialog: (type: DialogKind, filename: string, targetPath?: string) => void; | ||
|
||
// Lifted layout state | ||
explorerOpen: boolean; | ||
onToggleExplorer: () => void; | ||
|
||
sessionOpen: boolean; | ||
onToggleSession: () => void; | ||
|
||
searchOpen: boolean; | ||
onToggleSearch: () => void; | ||
} | ||
|
||
export const ActivityBar = React.forwardRef<ActivityBarHandle, IActivityBarProps>(function activityBar( | ||
{ globalState, onConfirmFileDialog, explorerOpen, onToggleExplorer, sessionOpen, onToggleSession, searchOpen, onToggleSearch }, | ||
ref | ||
) { | ||
const [theme, setTheme] = React.useState<"dark" | "light">(() => (Utilities.ReadStringFromStore("theme", "Light") === "Dark" ? "dark" : "light")); | ||
|
||
const [fileDialog, setFileDialog] = React.useState<DialogState>({ | ||
open: false, | ||
type: null, | ||
title: "", | ||
initialValue: "", | ||
}); | ||
|
||
// helpers | ||
const toDisplay = (path: string) => path.replace(/^\/?src\//, ""); | ||
const toInternal = (displayPath: string) => (displayPath?.startsWith("/") ? displayPath.slice(1) : displayPath || ""); | ||
const defaultNewFileName = (): string => { | ||
const isTS = globalState.language !== "JS"; | ||
const base = isTS ? "new.ts" : "new.js"; | ||
let idx = 0; | ||
let candidate = base; | ||
const files = globalState.files || {}; | ||
while (Object.prototype.hasOwnProperty.call(files, toInternal(candidate))) { | ||
idx++; | ||
const parts = base.split("."); | ||
const ext = parts.pop(); | ||
candidate = `${parts.join(".")}${idx}.${ext}`; | ||
} | ||
return candidate; | ||
}; | ||
const defaultDuplicateName = (path: string): string => { | ||
const baseFull = path.replace(/\.(\w+)$/, ""); | ||
const ext = (path.match(/\.(\w+)$/) || ["", ""])[1]; | ||
let i = 1; | ||
let candidate = `${baseFull}.copy${i}${ext ? "." + ext : ""}`; | ||
const files = globalState.files || {}; | ||
while (Object.prototype.hasOwnProperty.call(files, candidate)) { | ||
i++; | ||
candidate = `${baseFull}.copy${i}${ext ? "." + ext : ""}`; | ||
} | ||
return toDisplay(candidate); | ||
}; | ||
|
||
// imperative API | ||
React.useImperativeHandle(ref, () => ({ | ||
openCreateDialog: (suggestedName?: string) => { | ||
setFileDialog({ open: true, type: "create", title: "New file", initialValue: suggestedName ?? defaultNewFileName() }); | ||
}, | ||
openRenameDialog: (targetPath: string, initialDisplay?: string) => { | ||
setFileDialog({ | ||
open: true, | ||
type: "rename", | ||
title: "Rename file", | ||
initialValue: initialDisplay ?? toDisplay(targetPath), | ||
targetPath, | ||
}); | ||
}, | ||
openDuplicateDialog: (targetPath: string, suggestedName?: string) => { | ||
setFileDialog({ | ||
open: true, | ||
type: "duplicate", | ||
title: "Duplicate file", | ||
initialValue: suggestedName ?? defaultDuplicateName(targetPath), | ||
targetPath, | ||
}); | ||
}, | ||
toggleSessionDialog: () => onToggleSession(), | ||
})); | ||
|
||
// theme sync | ||
React.useEffect(() => { | ||
const updateTheme = () => { | ||
setTheme(Utilities.ReadStringFromStore("theme", "Light") === "Dark" ? "dark" : "light"); | ||
}; | ||
globalState.onThemeChangedObservable.add(updateTheme); | ||
return () => { | ||
globalState.onThemeChangedObservable.removeCallback(updateTheme); | ||
}; | ||
}, [globalState]); | ||
|
||
// dialog handlers | ||
const closeFileDialog = () => setFileDialog({ open: false, type: null, title: "", initialValue: "" }); | ||
const confirmFileDialog = (filename: string) => { | ||
if (!fileDialog.type) { | ||
return; | ||
} | ||
onConfirmFileDialog(fileDialog.type, filename, fileDialog.targetPath); | ||
closeFileDialog(); | ||
}; | ||
|
||
return ( | ||
<div className={`pg-activity-bar-col pg-theme-${theme}`}> | ||
{/* Vertical Activity Bar (far left) */} | ||
<div className="pg-activity-bar"> | ||
<button className={`pg-activity-item ${explorerOpen ? "active" : ""}`} onClick={onToggleExplorer} title="Explorer"> | ||
<Icon size={20}> | ||
<FilesIcon /> | ||
</Icon> | ||
</button> | ||
<button className={`pg-activity-item ${searchOpen ? "active" : ""}`} onClick={onToggleSearch} title="Search"> | ||
<Icon size={20}> | ||
<SearchIcon /> | ||
</Icon> | ||
</button> | ||
<button className={`pg-activity-item ${sessionOpen ? "active" : ""}`} onClick={onToggleSession} title="Session"> | ||
<Icon size={24}> | ||
<HistoryIcon /> | ||
</Icon> | ||
</button> | ||
</div> | ||
|
||
{/* File Dialog */} | ||
<FileDialog | ||
globalState={globalState} | ||
isOpen={fileDialog.open} | ||
title={fileDialog.title} | ||
initialValue={fileDialog.initialValue} | ||
placeholder="Enter filename..." | ||
submitLabel={fileDialog.type === "rename" ? "Rename" : fileDialog.type === "duplicate" ? "Duplicate" : "Create"} | ||
onConfirm={confirmFileDialog} | ||
onCancel={closeFileDialog} | ||
/> | ||
|
||
{/* Local Session Dialog */} | ||
<LocalSessionDialog onCancel={onToggleSession} isOpen={sessionOpen} globalState={globalState} /> | ||
</div> | ||
); | ||
}); |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.