Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fd36de77a | ||
|
|
d259ce5dfa | ||
|
|
e1e91089ca | ||
|
|
080861ed4a | ||
|
|
28c2922b89 | ||
|
|
d2efc6c5c4 | ||
|
|
df125f4e57 | ||
|
|
4957f3c033 | ||
|
|
80048951f8 | ||
|
|
4a18d3150f | ||
|
|
139cd6e6e5 | ||
|
|
3555198ffc | ||
|
|
61bc3ed0bb | ||
|
|
2e60f13c02 | ||
|
|
7506b8c118 | ||
|
|
1818593394 | ||
|
|
4f45da02bf | ||
|
|
21ddf69d5f | ||
|
|
77c74f4cc3 | ||
|
|
458b86c29b | ||
|
|
849615a199 | ||
|
|
143b4bad9e | ||
|
|
4315c6c5ec | ||
|
|
90b416f7fa | ||
|
|
4d7863dcb3 | ||
|
|
2e3c0d0aa4 | ||
|
|
352073869f | ||
|
|
65992126c0 | ||
|
|
c717da0080 | ||
|
|
0a11102c3f |
@@ -12,4 +12,3 @@ GlitchyEditor/MonoDebugger.log
|
||||
GlitchyEditor/Resources/Scripts/*
|
||||
|
||||
.cache
|
||||
generated
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
[submodule "GlitchyEngine/vendor/bon"]
|
||||
path = GlitchyEngine/vendor/bon
|
||||
url = https://github.com/EinScott/bon.git
|
||||
[submodule "GlitchyEngineHelper/vendor/DirectXTK"]
|
||||
path = GlitchyEngineHelper/vendor/DirectXTK
|
||||
url = https://github.com/microsoft/DirectXTK.git
|
||||
[submodule "GlitchyEngine/vendor/box2D"]
|
||||
path = GlitchyEngine/vendor/box2D
|
||||
url = https://github.com/aharabada/box2d-beef.git
|
||||
@@ -31,9 +34,6 @@
|
||||
[submodule "vendor/ImGui.NET"]
|
||||
path = vendor/ImGui.NET
|
||||
url = https://github.com/aharabada/ImGui.NET.git
|
||||
[submodule "GlitchyEngine/vendor/NetHostBeef"]
|
||||
path = GlitchyEngine/vendor/NetHostBeef
|
||||
url = https://github.com/aharabada/NetHostBeef.git
|
||||
[submodule "GlitchyEngine/vendor/Xml-Beef"]
|
||||
path = GlitchyEngine/vendor/Xml-Beef
|
||||
url = https://github.com/aharabada/Xml-Beef.git
|
||||
[submodule "GlitchyEngine/vendor/Ultralight-beef"]
|
||||
path = GlitchyEngine/vendor/Ultralight-beef
|
||||
url = https://github.com/aharabada/Ultralight-beef.git
|
||||
|
||||
@@ -1,36 +1,9 @@
|
||||
FileVersion = 1
|
||||
Locked = ["ImGui"]
|
||||
Projects = {GlitchyEngine = {Path = "GlitchyEngine"}, GlitchLog = {Path = "GlitchLog"}, DirectX = {Path = "GlitchyEngine/vendor/directx/DirectX"}, LodePng = {Path = "vendor/lodepng-beef/lodepng-beef"}, FreeType = {Path = "GlitchyEngine/vendor/freetype"}, cgltf-beef = {Path = "GlitchyEngine/vendor/gltf/cgltf-beef"}, GlitchyEditor = {Path = "GlitchyEditor"}, msdfgen-beef = {Path = "GlitchyEngine/vendor/msdfgen/msdfgen-beef"}, ImGui = {Path = "GlitchyEngine/vendor/imgui/ImGui"}, ImGuiImplDX11 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplDX11"}, ImGuiImplWin32 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplWin32"}, ImGuizmo = {Path = "GlitchyEngine/vendor/imgui/ImGuizmo"}, GlitchyEngineHelper = {Path = "GlitchyEngineHelper"}, bon = {Path = "GlitchyEngine/vendor/bon"}, box2d-beef = {Path = "GlitchyEngine/vendor/box2D"}, "Beef.Linq" = {Path = "GlitchyEngine/vendor/Beef.Linq/src"}, ScriptCore = {Path = "ScriptCore"}, Ultralight = {Path = "GlitchyEngine/vendor/Ultralight-beef"}, EditorUI = {Path = "GlitchyEditor/EditorUI"}}
|
||||
WorkspaceFolders = {GlitchyEngine = ["GlitchyEngine", "GlitchLog", "GlitchyEngineHelper", "ScriptCore"], "GlitchyEngine/Dependencies" = ["cgltf-beef", "DirectX", "FreeType", "ImGui", "ImGuiImplDX11", "ImGuiImplWin32", "ImGuizmo", "LodePng", "msdfgen-beef", "bon", "box2d-beef", "Beef.Linq"], EditorDependencies = ["Ultralight"]}
|
||||
|
||||
[Workspace]
|
||||
StartupProject = "GlitchyEditor"
|
||||
|
||||
[Projects]
|
||||
GlitchyEngine = {Path = "GlitchyEngine"}
|
||||
GlitchLog = {Path = "GlitchLog"}
|
||||
DirectX = {Path = "GlitchyEngine/vendor/directx/DirectX"}
|
||||
LodePng = {Path = "vendor/lodepng-beef/lodepng-beef"}
|
||||
FreeType = {Path = "GlitchyEngine/vendor/freetype"}
|
||||
cgltf-beef = {Path = "GlitchyEngine/vendor/gltf/cgltf-beef"}
|
||||
GlitchyEditor = {Path = "GlitchyEditor"}
|
||||
msdfgen-beef = {Path = "GlitchyEngine/vendor/msdfgen/msdfgen-beef"}
|
||||
ImGui = {Path = "GlitchyEngine/vendor/imgui/ImGui"}
|
||||
ImGuiImplDX11 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplDX11"}
|
||||
ImGuiImplWin32 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplWin32"}
|
||||
ImGuizmo = {Path = "GlitchyEngine/vendor/imgui/ImGuizmo"}
|
||||
GlitchyEngineHelper = {Path = "GlitchyEngineHelper"}
|
||||
bon = {Path = "GlitchyEngine/vendor/bon"}
|
||||
box2d-beef = {Path = "GlitchyEngine/vendor/box2D"}
|
||||
"Beef.Linq" = {Path = "GlitchyEngine/vendor/Beef.Linq/src"}
|
||||
ScriptCore = {Path = "ScriptCore"}
|
||||
NetHostBeef = {Path = "GlitchyEngine/vendor/NetHostBeef/NetHostBeef"}
|
||||
"GlitchyEngine.Test" = {Path = "GlitchyEngine.Test"}
|
||||
Xml-Beef = {Path = "GlitchyEngine/vendor/Xml-Beef"}
|
||||
"GlitchyEngine.Benchmark" = {Path = "GlitchyEngine.Benchmark"}
|
||||
|
||||
[WorkspaceFolders]
|
||||
GlitchyEngine = ["GlitchyEngine", "GlitchLog", "GlitchyEngineHelper", "ScriptCore", "GlitchyEngine.Test", "GlitchyEngine.Benchmark"]
|
||||
"GlitchyEngine/Dependencies" = ["cgltf-beef", "DirectX", "FreeType", "ImGui", "ImGuiImplDX11", "ImGuiImplWin32", "ImGuizmo", "LodePng", "msdfgen-beef", "bon", "box2d-beef", "Beef.Linq", "NetHostBeef", "Xml-Beef"]
|
||||
Beef = ["Beefy2D", "corlib"]
|
||||
|
||||
[Configs.Debug.Win64]
|
||||
AllocStackTraceDepth = 12
|
||||
|
||||
@@ -1,33 +1,18 @@
|
||||
FileVersion = 1
|
||||
Dependencies = {corlib = "*", GlitchLog = "*", GlitchyEngine = "*", Ultralight = "*", EditorUI = "*"}
|
||||
|
||||
[Project]
|
||||
Name = "GlitchyEditor"
|
||||
TargetType = "BeefGUIApplication"
|
||||
StartupObject = "GlitchyEngine.Program"
|
||||
ProcessorMacros = ["GE_EDITOR_IMGUI_DEMO", "GE_GRAPHICS_DX11"]
|
||||
|
||||
[Dependencies]
|
||||
corlib = "*"
|
||||
GlitchLog = "*"
|
||||
GlitchyEngine = "*"
|
||||
Xml-Beef = "*"
|
||||
ImGuiImplDX11 = "*"
|
||||
ImGuiImplWin32 = "*"
|
||||
ImGuizmo = "*"
|
||||
|
||||
[Platform.Windows]
|
||||
IconFile = "$(ProjectDir)/Resources/Textures/GlitchyEngineIcon.ico"
|
||||
ProcessorMacros = ["GE_EDITOR_IMGUI_DEMO"]
|
||||
|
||||
[Configs.Debug.Win64]
|
||||
PostBuildCmds = ["CopyFilesIfNewer(\"$(WorkspaceDir)/bin/vswhere.exe\", \"$(TargetDir)\")"]
|
||||
DebugCommandArguments = "\"D:\\Development\\Git\\SingleStateToOrbit\""
|
||||
PreprocessorMacros = ["DEBUG", "IMGUI"]
|
||||
|
||||
[Configs.Release.Win64]
|
||||
TargetDirectory = "$(BuildDir)/dist"
|
||||
PostBuildCmds = ["CopyFilesIfNewer(\"$(WorkspaceDir)/bin/vswhere.exe\", \"$(TargetDir)\")"]
|
||||
DebugCommandArguments = "\"D:\\Development\\Git\\SingleStateToOrbit\""
|
||||
PreprocessorMacros = ["RELEASE", "IMGUI"]
|
||||
|
||||
[Configs.Paranoid.Win64]
|
||||
PostBuildCmds = ["CopyFilesIfNewer(\"$(WorkspaceDir)/bin/vswhere.exe\", \"$(TargetDir)\")"]
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
*.tsbuildinfo
|
||||
@@ -0,0 +1,13 @@
|
||||
FileVersion = 1
|
||||
|
||||
[Project]
|
||||
Name = "EditorUI"
|
||||
TargetType = "BeefLib"
|
||||
StartupObject = "EditorUI.Program"
|
||||
|
||||
[Configs.Debug.Win64]
|
||||
BuildKind = "StaticLib"
|
||||
BuildCommandsOnCompile = "IfFilesChanged"
|
||||
BuildCommandsOnRun = "IfFilesChanged"
|
||||
PreBuildCmds = ["npm run build:debug"]
|
||||
PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist\")"]
|
||||
@@ -0,0 +1,50 @@
|
||||
# React + TypeScript + Vite
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
|
||||
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
||||
|
||||
- Configure the top-level `parserOptions` property like this:
|
||||
|
||||
```js
|
||||
export default tseslint.config({
|
||||
languageOptions: {
|
||||
// other options...
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
|
||||
- Optionally add `...tseslint.configs.stylisticTypeChecked`
|
||||
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:
|
||||
|
||||
```js
|
||||
// eslint.config.js
|
||||
import react from 'eslint-plugin-react'
|
||||
|
||||
export default tseslint.config({
|
||||
// Set the react version
|
||||
settings: { react: { version: '18.3' } },
|
||||
plugins: {
|
||||
// Add the react plugin
|
||||
react,
|
||||
},
|
||||
rules: {
|
||||
// other rules...
|
||||
// Enable its recommended rules
|
||||
...react.configs.recommended.rules,
|
||||
...react.configs['jsx-runtime'].rules,
|
||||
},
|
||||
})
|
||||
```
|
||||
@@ -0,0 +1,39 @@
|
||||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
import tseslint from 'typescript-eslint'
|
||||
|
||||
export default tseslint.config(
|
||||
{ignores: ['dist']},
|
||||
{
|
||||
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
||||
tsconfigRootDir: import.meta.dirname
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
'react-hooks': reactHooks,
|
||||
'react-refresh': reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...reactHooks.configs.recommended.rules,
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{allowConstantExport: true},
|
||||
],
|
||||
"@typescript-eslint/no-unused-vars": ["warn", {
|
||||
"vars": "all",
|
||||
"args": "all",
|
||||
"caughtErrors": "all",
|
||||
"ignoreRestSiblings": false,
|
||||
"reportUsedIgnorePattern": false
|
||||
}],
|
||||
},
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" type="image/x-icon" href="/src/assets/GlitchyEngineTransparent.png">
|
||||
<title>Glitchy Engine</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "glitchy-editor-ui",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"build:debug": "tsc -b && vite --config vite.config.debug.ts build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@rollup/plugin-typescript": "^12.1.1",
|
||||
"dockview-react": "^1.17.2",
|
||||
"eslint-plugin-react": "^7.37.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"use-immer": "^0.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.11.1",
|
||||
"@types/node": "^22.9.0",
|
||||
"@types/react": "^18.3.10",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@vitejs/plugin-react": "^4.3.2",
|
||||
"eslint": "^9.11.1",
|
||||
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.12",
|
||||
"globals": "^15.9.0",
|
||||
"typescript": "^5.5.3",
|
||||
"typescript-eslint": "^8.7.0",
|
||||
"vite": "^5.4.8",
|
||||
"vite-plugin-eslint": "^1.8.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import './App.css'
|
||||
import MainWindow from "./Windows/MainWindow.tsx";
|
||||
|
||||
export default function App() {
|
||||
return <MainWindow/>;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import {RefObject, useEffect} from "react";
|
||||
|
||||
/**
|
||||
* Calls the specified callback when the user clicks somewhere outside the referenced HTML-Element.
|
||||
* @param ref The element.
|
||||
* @param callback The callback.
|
||||
* @param addEventListener If true, the event listener will be registered.
|
||||
*/
|
||||
export const useClickOutside = (
|
||||
ref: RefObject<HTMLElement | undefined>,
|
||||
callback: () => void,
|
||||
addEventListener = true,
|
||||
) => {
|
||||
useEffect(() => {
|
||||
const handleClick = (event: MouseEvent) => {
|
||||
if (ref.current && !ref.current.contains(event.target as HTMLElement))
|
||||
{
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
if (addEventListener)
|
||||
{
|
||||
document.addEventListener('click', handleClick);
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('click', handleClick);
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import {
|
||||
DockviewReact,
|
||||
DockviewReadyEvent,
|
||||
IDockviewPanelProps,
|
||||
} from 'dockview';
|
||||
import {ChangeEvent, ReactElement, useState} from "react";
|
||||
import EntityHierarchyWindow from "../Windows/EntityHierarchyWindow.tsx";
|
||||
import CursorTestWindow from "../Windows/CursorTestWindow.tsx";
|
||||
|
||||
|
||||
const components = {
|
||||
default: DefaultWindow,
|
||||
entityHierarchy: EntityHierarchyWindow,
|
||||
editPanel: CursorTestWindow
|
||||
};
|
||||
|
||||
function DefaultWindow(props: IDockviewPanelProps<{ myValue: string }>): ReactElement
|
||||
{
|
||||
const [title, setTitle] = useState<string>(props.api.title ?? '');
|
||||
|
||||
const onChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
setTitle(event.target.value);
|
||||
};
|
||||
|
||||
const onClick = () => {
|
||||
props.api.setTitle(title);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: '20px', color: 'white' }}>
|
||||
<div>
|
||||
<span style={{ color: 'grey' }}>{'props.api.title='}</span>
|
||||
<span>{`${props.api.title}`}</span>
|
||||
</div>
|
||||
<input value={title} onChange={onChange} />
|
||||
<button onClick={onClick}>Change</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Dock({ theme } : { theme?: string})
|
||||
{
|
||||
const onReady = (event: DockviewReadyEvent) => {
|
||||
const entityHierarchyPanel = event.api.addPanel({
|
||||
id: 'entity_hierarchy_panel',
|
||||
component: 'entityHierarchy',
|
||||
title: 'Entity Hierarchy'
|
||||
});
|
||||
|
||||
const editPanel = event.api.addPanel({
|
||||
id: 'edit_scene',
|
||||
component: 'editPanel',
|
||||
title: 'Edit',
|
||||
position: { referencePanel: entityHierarchyPanel, direction: "right" }
|
||||
});
|
||||
|
||||
/*const playPanel =*/ event.api.addPanel({
|
||||
id: 'play_scene',
|
||||
component: 'default',
|
||||
title: 'Play',
|
||||
position: { referencePanel: editPanel }
|
||||
});
|
||||
|
||||
/*const propertiesPanel =*/ event.api.addPanel({
|
||||
id: 'properties_panel',
|
||||
component: 'default',
|
||||
title: 'Properties',
|
||||
position: { referencePanel: editPanel, direction: "right" }
|
||||
});
|
||||
|
||||
const logPanel = event.api.addPanel({
|
||||
id: 'log_panel',
|
||||
component: 'default',
|
||||
title: 'Log',
|
||||
position: { direction: "below" }
|
||||
});
|
||||
|
||||
/*const assetBrowserPanel =*/ event.api.addPanel({
|
||||
id: 'asset_browser_panel',
|
||||
component: 'default',
|
||||
title: 'Assets',
|
||||
position: { referencePanel: logPanel }
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<DockviewReact
|
||||
components={components}
|
||||
onReady={onReady}
|
||||
className={`dock ${theme || 'dockview-theme-vs'}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import {MouseEventHandler, ReactElement} from "react";
|
||||
|
||||
export function IconCheckButton({isChecked, iconChecked, iconUnchecked, onClick} : {isChecked: boolean, iconChecked: string, iconUnchecked: string, onClick: MouseEventHandler }) : ReactElement
|
||||
{
|
||||
return (
|
||||
<div onClick={onClick}>
|
||||
<img src={isChecked ? iconChecked : iconUnchecked} alt="" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
.menu-bar
|
||||
{
|
||||
width: 100%;
|
||||
|
||||
background-color: var(--menu-bar-background-color);
|
||||
grid-area: menubar;
|
||||
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
|
||||
list-style: none;
|
||||
|
||||
white-space: nowrap;
|
||||
|
||||
align-items: center;
|
||||
|
||||
--menu-item-height: 1.5em;
|
||||
}
|
||||
|
||||
/* Remove indentation from lists for menu */
|
||||
.menu-bar, .sub-menu {
|
||||
padding-inline-start: 0;
|
||||
}
|
||||
|
||||
.menu-item
|
||||
{
|
||||
/* Doesn't change our position, but does something to it, so that
|
||||
following absolutes are relative to us? */
|
||||
position: relative;
|
||||
height: var(--menu-item-height);
|
||||
}
|
||||
|
||||
.menu-item__content
|
||||
{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.menu-item__hotkey
|
||||
{
|
||||
color: var(--menu-bar-hotkey-color);
|
||||
justify-self: flex-end;
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
/* If menu-item has a submenu, make space for the arrow */
|
||||
.menu-item a:has(+.sub-menu)
|
||||
{
|
||||
padding-right: 1em;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
/* Show arrow for submenus */
|
||||
.menu-item a:has(+.sub-menu)::after
|
||||
{
|
||||
content: "⯆";
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
transition-duration: var(--small-transition-duration);
|
||||
}
|
||||
|
||||
/* If it is a nested submenu, forget the char above and use this one instead! */
|
||||
.sub-menu .menu-item a:has(+.sub-menu)::after
|
||||
{
|
||||
content: "⯈";
|
||||
}
|
||||
|
||||
.menu-item a:has(+.sub-menu.open)::after
|
||||
{
|
||||
rotate: 180deg;
|
||||
}
|
||||
|
||||
.menu-item a
|
||||
{
|
||||
/* Make the a fill the entire width of menu-item */
|
||||
display: block;
|
||||
|
||||
text-decoration: none;
|
||||
color: var(--font-color-primary);
|
||||
|
||||
height: 100%;
|
||||
align-content: center;
|
||||
/*padding: 5px 5px;*/
|
||||
}
|
||||
|
||||
.menu-item a:hover
|
||||
{
|
||||
background-color: var(--menu-bar-background-color-hover);
|
||||
}
|
||||
|
||||
.menu-item a:active
|
||||
{
|
||||
background-color: var(--menu-bar-background-color-click);
|
||||
}
|
||||
|
||||
.sub-menu
|
||||
{
|
||||
min-width: 120px;
|
||||
/* Hide submenu by default */
|
||||
display: none;
|
||||
overflow: visible;
|
||||
overflow-anchor: none;
|
||||
position: fixed;
|
||||
background-color: var(--menu-bar-background-color-click);
|
||||
list-style: none;
|
||||
z-index: 10;
|
||||
height: min-content;
|
||||
}
|
||||
|
||||
/* Show submenu */
|
||||
.sub-menu.open
|
||||
{
|
||||
display: revert;
|
||||
scale: 100% 100%;
|
||||
}
|
||||
|
||||
.sub-menu .menu-item .sub-menu
|
||||
{
|
||||
translate: 0 calc(var(--menu-item-height) * -1);
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.sub-menu li
|
||||
{
|
||||
width: 100%;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import {createContext, PropsWithChildren, useContext, useRef, useState} from "react";
|
||||
|
||||
import "./Menu.css"
|
||||
import {useClickOutside} from "../Callbacks/UseClickOutside.tsx";
|
||||
|
||||
export const OpenMenuContext = createContext<{openMenu: string[], currentParentMenu: string[], onOpenMenu: (clickedMenu: string[]) => void}>({openMenu: [], currentParentMenu: [], onOpenMenu: () => {}});
|
||||
|
||||
export function MenuBar({children}: PropsWithChildren)
|
||||
{
|
||||
const ref = useRef(null);
|
||||
|
||||
const [openMenu, setOpenMenu] = useState<string[]>([]);
|
||||
|
||||
function handleClickOutside()
|
||||
{
|
||||
setOpenMenu([]);
|
||||
}
|
||||
|
||||
useClickOutside(ref, handleClickOutside, openMenu.length > 0);
|
||||
|
||||
function handleOpenSubmenu(clickedMenu: string[])
|
||||
{
|
||||
setOpenMenu(clickedMenu);
|
||||
}
|
||||
|
||||
return (
|
||||
<ul ref={ref} className="menu-bar">
|
||||
<OpenMenuContext.Provider value={{openMenu, currentParentMenu: [], onOpenMenu: handleOpenSubmenu}}>
|
||||
{children}
|
||||
</OpenMenuContext.Provider>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
export function MenuItem({ text, hotkey, onClick, children } : { text: string, hotkey?: string, onClick?: () => void} & PropsWithChildren)
|
||||
{
|
||||
const {openMenu, currentParentMenu, onOpenMenu: setOpenMenu} = useContext(OpenMenuContext);
|
||||
|
||||
const isOpen = openMenu[currentParentMenu.length] == text;
|
||||
|
||||
const hasSubmenu = children !== undefined;
|
||||
|
||||
const currentMenu = [...currentParentMenu, text];
|
||||
|
||||
function handleClick()
|
||||
{
|
||||
if (hasSubmenu)
|
||||
{
|
||||
setOpenMenu(isOpen ? currentParentMenu : currentMenu);
|
||||
}
|
||||
|
||||
if (onClick)
|
||||
{
|
||||
onClick();
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<li className="menu-item">
|
||||
<a href="#" onClick={handleClick}>
|
||||
<div className="menu-item__content">
|
||||
<div>{text}</div>
|
||||
{hotkey && <div className="menu-item__hotkey">{hotkey}</div>}
|
||||
</div>
|
||||
</a>
|
||||
{children && (
|
||||
<ul className={`sub-menu ${isOpen ? "open" : ""}`}>
|
||||
<OpenMenuContext.Provider
|
||||
value={{openMenu, currentParentMenu: currentMenu, onOpenMenu: setOpenMenu}}>
|
||||
{children}
|
||||
</OpenMenuContext.Provider>
|
||||
</ul>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
export function MenuDivider()
|
||||
{
|
||||
return <hr/>;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
.backdrop
|
||||
{
|
||||
position: absolute;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
|
||||
background-color: #00000050;
|
||||
|
||||
z-index: 10;
|
||||
animation: blur-in 1s forwards;
|
||||
}
|
||||
|
||||
@keyframes blur-in {
|
||||
from {
|
||||
backdrop-filter: blur(0px);
|
||||
}
|
||||
to {
|
||||
backdrop-filter: blur(3px);
|
||||
}
|
||||
}
|
||||
|
||||
@property --angle {
|
||||
syntax: "<angle>";
|
||||
initial-value: 0deg;
|
||||
inherits: true;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
--angle: 0deg;
|
||||
}
|
||||
to {
|
||||
--angle: 360deg;
|
||||
}
|
||||
}
|
||||
.card
|
||||
{
|
||||
position: absolute;
|
||||
|
||||
padding: 1em;
|
||||
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
|
||||
translate: -50% -50%;
|
||||
|
||||
margin: auto auto;
|
||||
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
|
||||
background-color: gray;
|
||||
|
||||
border-radius: 30px;
|
||||
|
||||
z-index: 100;
|
||||
transform-style: preserve-3d;
|
||||
|
||||
animation: 3s spin linear infinite;
|
||||
}
|
||||
|
||||
.card::before, .card::after
|
||||
{
|
||||
content: '';
|
||||
|
||||
position: absolute;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
|
||||
translate: -50% -50%;
|
||||
transform: translateZ(-1px);
|
||||
|
||||
padding: 3px;
|
||||
border-radius: 30px;
|
||||
|
||||
z-index: -10;
|
||||
|
||||
background-image: conic-gradient(from var(--angle), #ff4545, #edd056, #00ff99, #006aff, #ff0095, #ff4545);
|
||||
|
||||
}
|
||||
|
||||
.card::before
|
||||
{
|
||||
filter: blur(10px);
|
||||
}
|
||||
|
||||
.content
|
||||
{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import {ReactElement} from "react";
|
||||
|
||||
import "./StartupCard.css"
|
||||
|
||||
export function StartupCard(): ReactElement
|
||||
{
|
||||
return (
|
||||
<div className="backdrop">
|
||||
<div className="card">
|
||||
<div className="content">
|
||||
<h1>Glitchy Engine</h1>
|
||||
<h2>Projects:</h2>
|
||||
<button>Create New</button>
|
||||
<h3>Recent projects:</h3>
|
||||
<ul>
|
||||
<li>Bli</li>
|
||||
<li>Bla</li>
|
||||
<li>Blub</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
//
|
||||
// This file exists so that vite build will only happen, if a file in the src-directory changed
|
||||
//
|
||||
using System;
|
||||
|
||||
namespace EditorUI;
|
||||
|
||||
[AlwaysInclude]
|
||||
struct EditorUIPlaceholder
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import {Entity, EntityId} from "./Entity.ts";
|
||||
|
||||
export interface IEngineGlue
|
||||
{
|
||||
// Titlebar Events
|
||||
handleClickCloseWindow(): void;
|
||||
handleClickMaximizeWindow(): void;
|
||||
handleClickMinimizeWindow(): void;
|
||||
handleHoverCloseWindow(hover: boolean): void;
|
||||
handleHoverMaximizeWindow(hover: boolean): void;
|
||||
handleHoverMinimizeWindow(hover: boolean): void;
|
||||
handleHoverNonClientArea(hover: boolean): void;
|
||||
|
||||
onClickCreateEmptyEntity(): void;
|
||||
setEntityVisibility(entityId: EntityId, isVisible: boolean): void;
|
||||
|
||||
requestEntityHierarchyUpdate(): void;
|
||||
onUpdateEntities?: (entities: Entity[]) => void;
|
||||
}
|
||||
|
||||
function logNotImplemented(functionName: string)
|
||||
{
|
||||
console.log(`${functionName} not implemented.`)
|
||||
}
|
||||
|
||||
class DevEngineGlue implements IEngineGlue {
|
||||
handleClickCloseWindow(): void
|
||||
{
|
||||
logNotImplemented("handleClickCloseWindow");
|
||||
}
|
||||
handleClickMaximizeWindow(): void
|
||||
{
|
||||
logNotImplemented("handleClickMaximizeWindow");
|
||||
}
|
||||
handleClickMinimizeWindow(): void
|
||||
{
|
||||
logNotImplemented("handleClickMinimizeWindow");
|
||||
}
|
||||
handleHoverCloseWindow(hover: boolean): void
|
||||
{
|
||||
logNotImplemented("handleHoverCloseWindow");
|
||||
console.log(`Hover ${hover}`)
|
||||
}
|
||||
handleHoverMaximizeWindow(hover: boolean): void
|
||||
{
|
||||
logNotImplemented("handleHoverMaximizeWindow");
|
||||
console.log(`Hover ${hover}`)
|
||||
}
|
||||
handleHoverMinimizeWindow(hover: boolean): void
|
||||
{
|
||||
logNotImplemented("handleHoverMinimizeWindow");
|
||||
console.log(`Hover ${hover}`)
|
||||
}
|
||||
handleHoverNonClientArea(hover: boolean): void
|
||||
{
|
||||
logNotImplemented("handleHoverNonClientArea");
|
||||
console.log(`Hover ${hover}`)
|
||||
}
|
||||
|
||||
onClickCreateEmptyEntity(): void
|
||||
{
|
||||
logNotImplemented("onClickCreateEmptyEntity");
|
||||
}
|
||||
setEntityVisibility(entityId: EntityId, isVisible: boolean): void
|
||||
{
|
||||
logNotImplemented("onClickCreateEmptyEntity");
|
||||
console.log(`entityId ${entityId} isVisible ${isVisible}`)
|
||||
}
|
||||
|
||||
requestEntityHierarchyUpdate(): void
|
||||
{
|
||||
logNotImplemented("requestEntityHierarchyUpdate");
|
||||
}
|
||||
|
||||
private callFromEngine_updateEntities(entities: Entity[]): void
|
||||
{
|
||||
console.log("Yeah!")
|
||||
|
||||
if (EngineGlue.onUpdateEntities)
|
||||
{
|
||||
EngineGlue.onUpdateEntities(entities);
|
||||
}
|
||||
else
|
||||
{
|
||||
logNotImplemented("onUpdateEntities");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare global
|
||||
{
|
||||
interface Window
|
||||
{
|
||||
EngineGlue: IEngineGlue;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof window.EngineGlue === 'undefined')
|
||||
{
|
||||
window.EngineGlue = new DevEngineGlue();
|
||||
}
|
||||
|
||||
export const EngineGlue: IEngineGlue = window.EngineGlue;
|
||||
@@ -0,0 +1,16 @@
|
||||
export type EntityId = string;
|
||||
|
||||
export class Entity
|
||||
{
|
||||
name: string;
|
||||
id: EntityId;
|
||||
visible: boolean = true;
|
||||
children: EntityId[];
|
||||
|
||||
constructor(name: string, id: EntityId, children: EntityId[] = [])
|
||||
{
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
this.children = children;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
.auto { cursor: auto; }
|
||||
.default { cursor: default; }
|
||||
.none { cursor: none; }
|
||||
.context-menu { cursor: context-menu; }
|
||||
.help { cursor: help; }
|
||||
.pointer { cursor: pointer; }
|
||||
.progress { cursor: progress; }
|
||||
.wait { cursor: wait; }
|
||||
.cell { cursor: cell; }
|
||||
.crosshair { cursor: crosshair; }
|
||||
.text { cursor: text; }
|
||||
.vertical-text { cursor: vertical-text; }
|
||||
.alias { cursor: alias; }
|
||||
.copy { cursor: copy; }
|
||||
.move { cursor: move; }
|
||||
.no-drop { cursor: no-drop; }
|
||||
.not-allowed { cursor: not-allowed; }
|
||||
.all-scroll { cursor: all-scroll; }
|
||||
.col-resize { cursor: col-resize; }
|
||||
.row-resize { cursor: row-resize; }
|
||||
.n-resize { cursor: n-resize; }
|
||||
.e-resize { cursor: e-resize; }
|
||||
.s-resize { cursor: s-resize; }
|
||||
.w-resize { cursor: w-resize; }
|
||||
.ns-resize { cursor: ns-resize; }
|
||||
.ew-resize { cursor: ew-resize; }
|
||||
.ne-resize { cursor: ne-resize; }
|
||||
.nw-resize { cursor: nw-resize; }
|
||||
.se-resize { cursor: se-resize; }
|
||||
.sw-resize { cursor: sw-resize; }
|
||||
.nesw-resize { cursor: nesw-resize; }
|
||||
.nwse-resize { cursor: nwse-resize; }
|
||||
.zoom-in { cursor: zoom-in; }
|
||||
.zoom-out { cursor: zoom-out; }
|
||||
.custom { cursor: url('Normal Select.cur'), auto; }
|
||||
|
||||
|
||||
h1 {
|
||||
color: #f06d06;
|
||||
}
|
||||
|
||||
.cursors {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.cursors div
|
||||
{
|
||||
width: 100px;
|
||||
height: 20px;
|
||||
margin: 5px;
|
||||
background-color: blue;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import {IDockviewPanelProps} from "dockview";
|
||||
|
||||
import "./CursorTestWindow.css"
|
||||
|
||||
export default function CursorTestWindow(props: IDockviewPanelProps)
|
||||
{
|
||||
return (
|
||||
<>
|
||||
<h1>CSS Cursors</h1>
|
||||
|
||||
<div className="cursors">
|
||||
<div className="auto">auto</div>
|
||||
<div className="default">default</div>
|
||||
<div className="none">none</div>
|
||||
<div className="context-menu">context-menu</div>
|
||||
<div className="help">help</div>
|
||||
<div className="pointer">pointer</div>
|
||||
<div className="progress">progress</div>
|
||||
<div className="wait">wait</div>
|
||||
<div className="cell">cell</div>
|
||||
<div className="crosshair">crosshair</div>
|
||||
<div className="text">text</div>
|
||||
<div className="vertical-text">vertical-text</div>
|
||||
<div className="alias">alias</div>
|
||||
<div className="copy">copy</div>
|
||||
<div className="move">move</div>
|
||||
<div className="no-drop">no-drop</div>
|
||||
<div className="not-allowed">not-allowed</div>
|
||||
<div className="all-scroll">all-scroll</div>
|
||||
<div className="col-resize">col-resize</div>
|
||||
<div className="row-resize">row-resize</div>
|
||||
<div className="n-resize">n-resize</div>
|
||||
<div className="s-resize">s-resize</div>
|
||||
<div className="e-resize">e-resize</div>
|
||||
<div className="w-resize">w-resize</div>
|
||||
<div className="ns-resize">ns-resize</div>
|
||||
<div className="ew-resize">ew-resize</div>
|
||||
<div className="ne-resize">ne-resize</div>
|
||||
<div className="nw-resize">nw-resize</div>
|
||||
<div className="se-resize">se-resize</div>
|
||||
<div className="sw-resize">sw-resize</div>
|
||||
<div className="nesw-resize">nesw-resize</div>
|
||||
<div className="nwse-resize">nwse-resize</div>
|
||||
<div className="zoom-in">zoom-in</div>
|
||||
<div className="zoom-out">zoom-out</div>
|
||||
<div className="custom">custom</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
.filterEntities
|
||||
{
|
||||
margin-left: auto;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.tree-view__item
|
||||
{
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tree-view__item__text
|
||||
{
|
||||
margin-right: 1em;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/*li > ul {*/
|
||||
/* margin-left: 10px;*/
|
||||
/*}*/
|
||||
|
||||
.tree-view__item.selected
|
||||
{
|
||||
background-color: var(--tree-view-item-background-color-selected);
|
||||
}
|
||||
|
||||
.tree-view__item:hover
|
||||
{
|
||||
background-color: var(--menu-bar-background-color-hover);
|
||||
}
|
||||
|
||||
.tree-view__item:active
|
||||
{
|
||||
background-color: var(--menu-bar-background-color-click);
|
||||
}
|
||||
|
||||
|
||||
.tree-view__item img
|
||||
{
|
||||
/*display: block;*/
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
filter: invert();
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
import {IDockviewPanelProps} from "dockview";
|
||||
import {MenuBar, MenuItem} from "../Components/Menu.tsx";
|
||||
|
||||
import "./EntityHierarchyWindow.css";
|
||||
import React, {MouseEvent, MouseEventHandler, ReactElement, useEffect, useState} from "react";
|
||||
|
||||
import IconVisible from "../assets/Icons/AntDesign/eye-visible.svg";
|
||||
import IconInvisible from "../assets/Icons/AntDesign/eye-invisible.svg";
|
||||
import {Updater, useImmer} from "use-immer";
|
||||
|
||||
import {EngineGlue} from "../EngineGlue";
|
||||
|
||||
import {enableMapSet} from "immer"
|
||||
import {Entity, EntityId} from "../Entity.ts";
|
||||
import {IconCheckButton} from "../Components/IconCheckButton.tsx";
|
||||
|
||||
enableMapSet()
|
||||
|
||||
type EntityMap = {
|
||||
selectedIds: Set<EntityId>;
|
||||
entities: Map<EntityId, Entity>;
|
||||
//[id: EntityId]: Entity;
|
||||
};
|
||||
|
||||
const entityHierarchy: EntityMap = {
|
||||
selectedIds: new Set<EntityId>(),
|
||||
entities: new Map<EntityId, Entity>([
|
||||
["0", new Entity("Root", "0", ["1", "2"])],
|
||||
["1", new Entity("Entity 1", "1", [])],
|
||||
["2", new Entity("Entity 2", "2", ["3"])],
|
||||
["3", new Entity("Entity 3 in 2", "3", [])]
|
||||
])
|
||||
// // 0 is hardcoded to be the root. The editor must provide this "pseudo"-entity.
|
||||
// 0: new Entity("Root", 0, [1, 2]),
|
||||
// 1: new Entity("Entity 1", 1, []),
|
||||
// 2: new Entity("Entity 2", 2, [3]),
|
||||
// 3: new Entity("Entity 3 in 2", 3, [])
|
||||
};
|
||||
|
||||
export default function EntityHierarchyWindow(props: IDockviewPanelProps)
|
||||
{
|
||||
const [entities, updateEntities] = useImmer(entityHierarchy);
|
||||
const [filterText, setFilterText] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
EngineGlue.onUpdateEntities = (entities: Entity[]) => {
|
||||
updateEntities(draft => {
|
||||
try
|
||||
{
|
||||
for (const entity of entities)
|
||||
{
|
||||
// console.log(`${entity.id}: "${entity.name ?? "deleted"}",
|
||||
// ${entity.visible ? "Visible" : "Invisible"}, ${entity.children.length} Children: [${entity.children}]`)
|
||||
|
||||
if (entity.name === "undefined")
|
||||
{
|
||||
draft.entities.delete(entity.id);
|
||||
//delete draft[entity.id];
|
||||
draft.selectedIds.delete(entity.id);
|
||||
}
|
||||
else
|
||||
{
|
||||
draft.entities.set(entity.id, entity);
|
||||
//draft[entity.id] = entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
console.log(`Failed to update entities: ${e}`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
EngineGlue.requestEntityHierarchyUpdate();
|
||||
|
||||
return () => {
|
||||
delete EngineGlue.onUpdateEntities;
|
||||
};
|
||||
}, [updateEntities]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<EntityMenuBar searchString={filterText} onFilterTextChanged={setFilterText} />
|
||||
<EntityTree items={entities} updateItems={updateEntities} entityFilter={filterText}/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function EntityTreeItem({item, allEntities, updateEntities, showAsTree}: {
|
||||
item: Entity,
|
||||
allEntities: EntityMap, updateEntities: Updater<EntityMap>, showAsTree: boolean}) : ReactElement
|
||||
{
|
||||
//const [isOpen, setOpen] = useState(false);
|
||||
|
||||
const isSelected = allEntities.selectedIds.has(item.id);
|
||||
//const isVisible = allEntities[item.id].visible;
|
||||
|
||||
function handleClick(event: MouseEvent)
|
||||
{
|
||||
console.log("Clicked" + item.name);
|
||||
updateEntities(draft => {
|
||||
if (isSelected)
|
||||
{
|
||||
draft.selectedIds.delete(item.id);
|
||||
}
|
||||
else
|
||||
{
|
||||
draft.selectedIds.add(item.id);
|
||||
}
|
||||
});
|
||||
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
function toggleVisibility(event: MouseEvent)
|
||||
{
|
||||
event.stopPropagation();
|
||||
|
||||
// updateEntities(draft => {
|
||||
// draft[item.id].visible = !draft[item.id].visible;
|
||||
// });
|
||||
|
||||
//event.stopPropagation();
|
||||
}
|
||||
|
||||
return (
|
||||
<li>
|
||||
<div className={"tree-view__item " + (isSelected ? "selected" : "")} onClick={handleClick}>
|
||||
<div className="tree-view__item__text">
|
||||
{item.name}
|
||||
</div>
|
||||
<VisibilityToggle item={item} onClick={toggleVisibility} updateEntities={updateEntities} />
|
||||
</div>
|
||||
|
||||
{
|
||||
showAsTree && item.children.length > 0 &&
|
||||
<ul>
|
||||
{
|
||||
item.children.map((childId) => {
|
||||
const entity = allEntities.entities.get(childId);
|
||||
|
||||
if (entity === undefined)
|
||||
return;
|
||||
|
||||
return <EntityTreeItem key={entity.id} item={entity} allEntities={allEntities} updateEntities={updateEntities} showAsTree={showAsTree}/>;
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
function VisibilityToggle({item, onClick, updateEntities} : {item: Entity, onClick: MouseEventHandler, updateEntities: Updater<EntityMap>}) {
|
||||
function clickHandler(event: MouseEvent)
|
||||
{
|
||||
updateEntities(draft => {
|
||||
const entity = draft.entities.get(item.id)
|
||||
|
||||
if (entity !== undefined)
|
||||
{
|
||||
entity.visible = !entity.visible;
|
||||
EngineGlue.setEntityVisibility(entity.id, entity.visible);
|
||||
}
|
||||
});
|
||||
|
||||
onClick(event);
|
||||
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
return <IconCheckButton isChecked={item.visible} onClick={clickHandler} iconChecked={IconVisible} iconUnchecked={IconInvisible}/>
|
||||
}
|
||||
|
||||
|
||||
|
||||
function EntityTree({items, updateItems, entityFilter}: { items: EntityMap, updateItems: Updater<EntityMap>, entityFilter: string })
|
||||
{
|
||||
const rootEntity = items.entities.get("0");
|
||||
|
||||
if (entityFilter.length == 0)
|
||||
{
|
||||
return (
|
||||
<ul className="tree-view">
|
||||
{
|
||||
rootEntity && rootEntity.children.map((childId) => {
|
||||
const entity = items.entities.get(childId);
|
||||
|
||||
if (entity === undefined)
|
||||
return;
|
||||
|
||||
return <EntityTreeItem key={entity.id} item={entity} allEntities={items} updateEntities={updateItems} showAsTree={true} />;
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (
|
||||
<ul className="tree-view">
|
||||
{
|
||||
Array.from(items.entities).filter(([, entity]) => {
|
||||
return entity.name.indexOf(entityFilter) != -1
|
||||
}).map(([, entity]) => {
|
||||
return <EntityTreeItem key={entity.id} item={entity} allEntities={items}
|
||||
updateEntities={updateItems} showAsTree={false}/>;
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function EntityMenuBar({searchString, onFilterTextChanged}: {
|
||||
searchString: string,
|
||||
onFilterTextChanged: (s: string) => void
|
||||
})
|
||||
{
|
||||
return <MenuBar>
|
||||
<MenuItem text="Create">
|
||||
<MenuItem text="Empty Entity" onClick={window.EngineGlue.onClickCreateEmptyEntity}/>
|
||||
<MenuItem text="Parent Entity">
|
||||
<MenuItem text="Test 1 (lang)">
|
||||
<MenuItem text="Du">
|
||||
<MenuItem text="Übertreibst">
|
||||
<MenuItem text="Völlig"/>
|
||||
<MenuItem text="Du Hund!"/>
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem text="Test 2">
|
||||
<MenuItem text="Ach komm,"/>
|
||||
</MenuItem>
|
||||
<MenuItem text="Test 3">
|
||||
<MenuItem text="Hör auf!"/>
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem text="Child Entity"/>
|
||||
</MenuItem>
|
||||
<MenuItem text="Delete">
|
||||
<MenuItem text="Selected"/>
|
||||
<MenuItem text="All"/>
|
||||
</MenuItem>
|
||||
<MenuItem text="Copy">
|
||||
</MenuItem>
|
||||
<input className="filterEntities" placeholder="Filter entities..." content={searchString}
|
||||
onChange={(e) => onFilterTextChanged(e.target.value)}/>
|
||||
</MenuBar>;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
.jep
|
||||
{
|
||||
display: grid;
|
||||
grid-template-rows: min-content 1fr;
|
||||
grid-template-areas:
|
||||
"titlebar"
|
||||
"dock";
|
||||
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.dock
|
||||
{
|
||||
grid-area: dock;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.title-bar
|
||||
{
|
||||
grid-area: titlebar;
|
||||
|
||||
background-color: var(--menu-bar-background-color);
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
grid-template-areas:
|
||||
"icon title"
|
||||
"icon menubar";
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.title-bar__icon
|
||||
{
|
||||
grid-area: icon;
|
||||
|
||||
aspect-ratio : 1 / 1;
|
||||
height: 100%;
|
||||
|
||||
/*height: 2em;*/
|
||||
/*width: 2em;*/
|
||||
|
||||
background-image: url(/src/assets/GlitchyEngineTransparent.png);
|
||||
background-size: contain;
|
||||
mask: radial-gradient(white 65%, transparent 75%);
|
||||
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.title-bar__title
|
||||
{
|
||||
display: flex;
|
||||
grid-area: title;
|
||||
height: 2em;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.engine-name
|
||||
{
|
||||
font-weight: bold;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.title-bar__button
|
||||
{
|
||||
grid-area: title;
|
||||
height: 100%;
|
||||
width: 47px;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
color: white;
|
||||
}
|
||||
.title-bar__button:hover
|
||||
{
|
||||
background-color: gray;
|
||||
}
|
||||
|
||||
.title-bar__button.minimize
|
||||
{
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.title-bar__button.close:hover
|
||||
{
|
||||
background-color: red;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
import "./MainWindow.css"
|
||||
import Dock from "../Components/Dock.tsx";
|
||||
import {MenuBar, MenuDivider, MenuItem} from "../Components/Menu.tsx";
|
||||
import {ReactElement, useEffect, useRef} from "react";
|
||||
import '../EngineGlue.ts'
|
||||
import {EngineGlue} from "../EngineGlue.ts";
|
||||
import {StartupCard} from "../Components/StartupCard.tsx";
|
||||
|
||||
//something = 'testing';
|
||||
|
||||
export default function MainWindow() {
|
||||
const projectName = "Mein Geiles Projekt";
|
||||
const fileName = "DefaultScene.scene";
|
||||
|
||||
return (
|
||||
<div className="jep">
|
||||
<TitleBar projectName={projectName} fileName={fileName}/>
|
||||
<Dock/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TitleBar({ projectName, fileName } : {projectName: string, fileName: string}): ReactElement
|
||||
{
|
||||
// {false ? "🗗" : "🗖"}
|
||||
return (
|
||||
<div className="title-bar">
|
||||
<div className="title-bar__icon"/>
|
||||
<div className="title-bar__title"
|
||||
onMouseEnter={() => EngineGlue.handleHoverNonClientArea(true)}
|
||||
onMouseLeave={() => EngineGlue.handleHoverNonClientArea(false)}>
|
||||
<div>
|
||||
<span className="engine-name">Glitchy Engine</span> {projectName} - {fileName}
|
||||
</div>
|
||||
|
||||
<button className="title-bar__button minimize"
|
||||
onClick={() => EngineGlue.handleClickMinimizeWindow()}
|
||||
onMouseOver={() => EngineGlue.handleHoverMinimizeWindow(true)}
|
||||
onMouseLeave={() => EngineGlue.handleHoverMinimizeWindow(false)}>🗕</button>
|
||||
<button className="title-bar__button maximize"
|
||||
onClick={() => EngineGlue.handleClickMaximizeWindow()}
|
||||
onMouseOver={() => EngineGlue.handleHoverMaximizeWindow(true)}
|
||||
onMouseLeave={() => EngineGlue.handleHoverMaximizeWindow(false)}>🗖</button>
|
||||
<button className="title-bar__button close"
|
||||
onClick={() => EngineGlue.handleClickCloseWindow()}
|
||||
onMouseOver={() => EngineGlue.handleHoverCloseWindow(true)}
|
||||
onMouseLeave={() => EngineGlue.handleHoverCloseWindow(false)}>🗙</button>
|
||||
</div>
|
||||
<MainMenuBar/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function MainMenuBar(): ReactElement
|
||||
{
|
||||
return (
|
||||
<MenuBar>
|
||||
<MenuItem text="File" onClick={() => {
|
||||
console.log("Test")
|
||||
}}>
|
||||
<MenuItem text="New Scene..." hotkey="Ctrl + N" onClick={() => window.open("file:///index.html")}/>
|
||||
<MenuItem text="Open Scene..." hotkey="Ctrl + O"/>
|
||||
<MenuItem text="Open recent Scene">
|
||||
<MenuItem text="1. Bli"/>
|
||||
<MenuItem text="2. Bla"/>
|
||||
<MenuItem text="3. Blub"/>
|
||||
</MenuItem>
|
||||
<MenuDivider/>
|
||||
<MenuItem text="Save Scene" hotkey="Ctrl + S"/>
|
||||
<MenuItem text="Save Scene as..." hotkey="Ctrl + Shift + S"/>
|
||||
<MenuDivider/>
|
||||
<MenuItem text="Create new Project..."/>
|
||||
<MenuItem text="Open Project..."/>
|
||||
<MenuItem text="Open recent Project">
|
||||
<MenuItem text="1. Bli"/>
|
||||
<MenuItem text="2. Bla"/>
|
||||
<MenuItem text="3. Blub"/>
|
||||
</MenuItem>
|
||||
<MenuDivider/>
|
||||
<MenuItem text="Settings..."/>
|
||||
<MenuDivider/>
|
||||
<MenuItem text="Exit" onClick={EngineGlue.handleClickCloseWindow} />
|
||||
</MenuItem>
|
||||
<MenuItem text="View">
|
||||
<MenuItem text="Asset Browser"/>
|
||||
<MenuItem text="Scene"/>
|
||||
<MenuItem text="Entity Hierarchy"/>
|
||||
<MenuItem text="Game"/>
|
||||
<MenuItem text="Inspector"/>
|
||||
<MenuItem text="Asset Viewer"/>
|
||||
<MenuItem text="Log"/>
|
||||
</MenuItem>
|
||||
<MenuItem text="Tools">
|
||||
<MenuItem text="Reload Script"/>
|
||||
<label>
|
||||
<input type="checkbox"/>
|
||||
Show ImGui Demo
|
||||
</label>
|
||||
</MenuItem>
|
||||
</MenuBar>
|
||||
);
|
||||
}
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#000000" width="800px" height="800px" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon">
|
||||
<path d="M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 0 0 0-51.5zm-63.57-320.64L836 122.88a8 8 0 0 0-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 0 0 0 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 0 0 0 11.31L155.17 889a8 8 0 0 0 11.31 0l712.15-712.12a8 8 0 0 0 0-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 0 0-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 0 1 146.2-106.69L401.31 546.2A112 112 0 0 1 396 512z"/><path d="M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 0 0 227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 0 1-112 112z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,92 @@
|
||||
Copyright (c) 2016 The Inter Project Authors (https://github.com/rsms/inter)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION AND CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -0,0 +1,57 @@
|
||||
/* Variable fonts usage:
|
||||
:root { font-family: "Inter", sans-serif; }
|
||||
@supports (font-variation-settings: normal) {
|
||||
:root { font-family: "InterVariable", sans-serif; font-optical-sizing: auto; }
|
||||
} */
|
||||
@font-face {
|
||||
font-family: InterVariable;
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
src: url("InterVariable.woff2") format("woff2");
|
||||
}
|
||||
@font-face {
|
||||
font-family: InterVariable;
|
||||
font-style: italic;
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
src: url("InterVariable-Italic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
/* static fonts */
|
||||
@font-face { font-family: "Inter"; font-style: normal; font-weight: 100; font-display: swap; src: url("Inter-Thin.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: italic; font-weight: 100; font-display: swap; src: url("Inter-ThinItalic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: normal; font-weight: 200; font-display: swap; src: url("Inter-ExtraLight.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: italic; font-weight: 200; font-display: swap; src: url("Inter-ExtraLightItalic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: normal; font-weight: 300; font-display: swap; src: url("Inter-Light.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: italic; font-weight: 300; font-display: swap; src: url("Inter-LightItalic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: normal; font-weight: 400; font-display: swap; src: url("Inter-Regular.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: italic; font-weight: 400; font-display: swap; src: url("Inter-Italic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: normal; font-weight: 500; font-display: swap; src: url("Inter-Medium.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: italic; font-weight: 500; font-display: swap; src: url("Inter-MediumItalic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: normal; font-weight: 600; font-display: swap; src: url("Inter-SemiBold.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: italic; font-weight: 600; font-display: swap; src: url("Inter-SemiBoldItalic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: normal; font-weight: 700; font-display: swap; src: url("Inter-Bold.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: italic; font-weight: 700; font-display: swap; src: url("Inter-BoldItalic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: normal; font-weight: 800; font-display: swap; src: url("Inter-ExtraBold.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: italic; font-weight: 800; font-display: swap; src: url("Inter-ExtraBoldItalic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: normal; font-weight: 900; font-display: swap; src: url("Inter-Black.woff2") format("woff2"); }
|
||||
@font-face { font-family: "Inter"; font-style: italic; font-weight: 900; font-display: swap; src: url("Inter-BlackItalic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 100; font-display: swap; src: url("InterDisplay-Thin.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 100; font-display: swap; src: url("InterDisplay-ThinItalic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 200; font-display: swap; src: url("InterDisplay-ExtraLight.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 200; font-display: swap; src: url("InterDisplay-ExtraLightItalic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 300; font-display: swap; src: url("InterDisplay-Light.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 300; font-display: swap; src: url("InterDisplay-LightItalic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 400; font-display: swap; src: url("InterDisplay-Regular.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 400; font-display: swap; src: url("InterDisplay-Italic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 500; font-display: swap; src: url("InterDisplay-Medium.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 500; font-display: swap; src: url("InterDisplay-MediumItalic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 600; font-display: swap; src: url("InterDisplay-SemiBold.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 600; font-display: swap; src: url("InterDisplay-SemiBoldItalic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 700; font-display: swap; src: url("InterDisplay-Bold.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 700; font-display: swap; src: url("InterDisplay-BoldItalic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 800; font-display: swap; src: url("InterDisplay-ExtraBold.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 800; font-display: swap; src: url("InterDisplay-ExtraBoldItalic.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 900; font-display: swap; src: url("InterDisplay-Black.woff2") format("woff2"); }
|
||||
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 900; font-display: swap; src: url("InterDisplay-BlackItalic.woff2") format("woff2"); }
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#000000" width="800px" height="800px" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon">
|
||||
<path d="M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 0 0 0-51.5zm-63.57-320.64L836 122.88a8 8 0 0 0-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 0 0 0 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 0 0 0 11.31L155.17 889a8 8 0 0 0 11.31 0l712.15-712.12a8 8 0 0 0 0-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 0 0-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 0 1 146.2-106.69L401.31 546.2A112 112 0 0 1 396 512z"/><path d="M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 0 0 227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 0 1-112 112z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#000000" width="800px" height="800px" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon">
|
||||
<path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 0 0 0 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 741 B |
@@ -0,0 +1,73 @@
|
||||
@import "assets/Fonts/Inter/inter.css";
|
||||
@import '../node_modules/dockview-react/dist/styles/dockview.css';
|
||||
|
||||
*
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
/*cursor: default;*/
|
||||
}
|
||||
|
||||
/* Fix indentation of nested lists */
|
||||
ul, ol {
|
||||
padding-inline-start: 40px;
|
||||
}
|
||||
|
||||
/* Variable Declaration for themes */
|
||||
:root
|
||||
{
|
||||
--font-color-primary: white;
|
||||
|
||||
/* Menu Bar */
|
||||
--menu-bar-background-color: #404040;
|
||||
--menu-bar-background-color-hover: #808080;
|
||||
--menu-bar-background-color-click: #606060;
|
||||
--menu-bar-hotkey-color: #A0A0A0;
|
||||
|
||||
--tree-view-item-background-color-selected: #323275;
|
||||
|
||||
--small-transition-duration: 0.1s;
|
||||
|
||||
--text-box-background-color: #2c2c2c;
|
||||
--text-box-border-color: #a5a5a5;
|
||||
--text-box-border-color-focus: #007acc;
|
||||
--text-box-border-color-disabled: #4e4e4e;
|
||||
}
|
||||
|
||||
:root
|
||||
{
|
||||
font-family: "Inter", sans-serif;
|
||||
|
||||
/* Disable selection by default. But for some reason webkit does it differently than chorme...*/
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
cursor: default;
|
||||
|
||||
color: var(--font-color-primary);
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal)
|
||||
{
|
||||
:root
|
||||
{
|
||||
font-family: "InterVariable", sans-serif; font-optical-sizing: auto;
|
||||
}
|
||||
}
|
||||
|
||||
input[type=text], input
|
||||
{
|
||||
background-color: var(--text-box-background-color);
|
||||
color: var(--font-color-primary);
|
||||
border: 2px solid var(--text-box-border-color);
|
||||
border-radius: 3px;
|
||||
padding: 1px 2px;
|
||||
transition: border-color var(--small-transition-duration);
|
||||
}
|
||||
|
||||
input[type=text]:focus, input:focus
|
||||
{
|
||||
outline: none;
|
||||
border-color: var(--text-box-border-color-focus);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import App from './App.tsx'
|
||||
import './assets/Fonts/Inter/inter.css'
|
||||
import './index.css'
|
||||
import 'dockview/dist/styles/dockview.css';
|
||||
|
||||
// Ultralight 1.4 = Safari 16.4.1 / WebKit 615.1.18.100.1 (March 2023)
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
const isDebug = mode === 'debug'
|
||||
|
||||
return {
|
||||
plugins: [react()],
|
||||
base: "./",
|
||||
build: {
|
||||
target: "es2015",
|
||||
minify: false,
|
||||
terserOptions: undefined,
|
||||
rollupOptions: {
|
||||
preserveModules: true,
|
||||
output: {
|
||||
dir: 'dist',
|
||||
entryFileNames: '[name].js',
|
||||
chunkFileNames: '[name].js',
|
||||
assetFileNames: '[name].[ext]'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,17 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
base: "./",
|
||||
build:
|
||||
{
|
||||
target: "es2015",
|
||||
terserOptions: {
|
||||
mangle: {
|
||||
reserved: ['EngineGlue']
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1 @@
|
||||
https://hg.mozilla.org/mozilla-central/file/tip/widget/windows/res
|
||||
|
After Width: | Height: | Size: 326 B |
|
After Width: | Height: | Size: 326 B |
|
After Width: | Height: | Size: 326 B |
|
After Width: | Height: | Size: 326 B |
|
After Width: | Height: | Size: 326 B |
|
After Width: | Height: | Size: 326 B |
|
After Width: | Height: | Size: 326 B |
|
After Width: | Height: | Size: 326 B |
|
After Width: | Height: | Size: 326 B |
|
After Width: | Height: | Size: 326 B |
|
After Width: | Height: | Size: 326 B |
|
After Width: | Height: | Size: 326 B |
@@ -1,11 +0,0 @@
|
||||
{
|
||||
AssetLoader = null,
|
||||
Config = null,
|
||||
Importer = null,
|
||||
ImporterConfig = null,
|
||||
Processor = null,
|
||||
ProcessorConfig = null,
|
||||
Exporter = null,
|
||||
ExporterConfig = null,
|
||||
AssetHandle = 9434890118063137951
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
Effect = 7757902626263730438,
|
||||
Textures = [],
|
||||
Constants = []
|
||||
}
|
||||