some tweaks

main
Antonio De Lucreziis 2 years ago
parent 0896799b34
commit 58b6b6ed18

@ -0,0 +1,9 @@
{
"printWidth": 120,
"singleQuote": true,
"quoteProps": "consistent",
"tabWidth": 4,
"semi": false,
"arrowParens": "avoid",
"proseWrap": "always"
}

@ -1 +1 @@
# ReplIt Clone
# ReplIt Clone

@ -1,23 +1,12 @@
import { useSignal, signal, useComputed, batch, effect } from '@preact/signals'
import { useSignal, signal, useComputed, batch, effect, Signal } from '@preact/signals'
import clsx from 'clsx'
import { TreeView, EXAMPLE_TREE } from '@/client/components/TreeView.jsx'
import { TreeView } from '@/client/components/TreeView.jsx'
import { Editor } from '@/client/components/Editor.jsx'
import clsx from 'clsx'
import { useEffect, useState } from 'preact/hooks'
import { fetchJson } from '../utils.js'
import { useEffect } from 'preact/hooks'
import { Terminal } from './Terminal.jsx'
function ensurePrefix(s, prefix) {
return s.slice(0, prefix.length) === prefix ? s : prefix + s
}
function stripPrefix(s, prefix) {
return s.slice(0, prefix.length) === prefix ? s.slice(prefix.length) : s
}
function clamp(min, value, max) {
return Math.max(min, Math.min(value, max))
}
import { clamp, fetchJson, stripPrefix } from '@/client/utils.js'
export const Ide = ({}) => {
const ws = useSignal(null)
@ -38,16 +27,8 @@ export const Ide = ({}) => {
const activeTab = useSignal(null)
const tabs = useSignal([
// {
// id: '/project/main.c',
// content: signal('...main.c...'),
// },
// {
// id: '/project/data.csv',
// content: signal('...data.csv...'),
// },
])
/** @type {Signal<{ id: string, content: Signal<string> }[]>} */
const tabs = useSignal([])
const activePath = useComputed(() => {
if (activeTab.value === null) return null
@ -61,15 +42,6 @@ export const Ide = ({}) => {
return tabs.value[activeTab.value].content
})
effect(() => {
const path = activePath.value
const contentSig = activeContent.value
if (contentSig === null || path === null) return
console.log(path, contentSig.value)
})
return (
<div class="ide">
<div class="sidebar">
@ -161,27 +133,44 @@ export const Ide = ({}) => {
<button class="icon">
<div class="material-symbols-outlined">terminal</div>
</button>
<button
class="run"
onClick={() => {
console.log('Running file:', activePath.value)
if (!activePath.value) return
<div class="popup-region run-style">
<div class="region">
<button class="compound">
<span
class="part"
onClick={() => {
console.log('Running file:', activePath.value)
if (!activePath.value) return
const fullPath = '/project' + activePath.value
const fullPath = '/project' + activePath.value
if (fullPath.endsWith('.sh')) {
ws.value.send(`sh ${fullPath}\n`)
return
}
if (fullPath.endsWith('.js')) {
ws.value.send(`node ${fullPath}\n`)
return
}
}}
>
<div class="material-symbols-outlined">play_arrow</div>
Run File
</button>
if (fullPath.endsWith('.sh')) {
ws.value.send(`sh ${fullPath}\n`)
return
}
if (fullPath.endsWith('.js')) {
ws.value.send(`node ${fullPath}\n`)
return
}
}}
>
Run
</span>
<span class="part">
<span class="material-symbols-outlined">keyboard_arrow_down</span>
</span>
</button>
</div>
<div class="popup anchor-mode-1">
<div class="menu">
<div class="item">Run</div>
<div class="item">Debug</div>
<div class="item">Test</div>
<div class="item">Profile</div>
<div class="item">Bench</div>
</div>
</div>
</div>
</div>
</div>
<div class="tabbed-editor">

@ -40,6 +40,7 @@ export const Terminal = memo(({ ws }) => {
<div
class="terminal"
ref={el => {
if (!el) return
console.log('Starting terminal...')
term.open(el)

@ -1,31 +1,5 @@
import { useSignal } from '@preact/signals'
import clsx from 'clsx'
import { useEffect, useState } from 'preact/hooks'
export const EXAMPLE_TREE = {
type: 'root',
children: [
{
type: 'folder',
name: 'bin/',
children: [
{
type: 'file',
name: 'a.out',
},
],
},
{
type: 'file',
name: 'main.c',
},
{
type: 'file',
name: 'data.csv',
},
],
}
const flattenTree = (node, depth = 0, path = []) => {
if (node.type === 'root') {
return node.children.flatMap(entry => flattenTree(entry, depth, []))
@ -127,11 +101,6 @@ const TreeViewNode = ({ listDir, actionOpenFile, node, depth, path }) => {
}
}
const ICONS = {
['folder']: 'folder',
['file']: 'description',
}
export const TreeView = ({ listDir, actionOpenFile, rootPath }) => {
return (
<div class="tree-view">

@ -45,18 +45,13 @@ export class FitAddon implements ITerminalAddon {
// Force a full render
if (this._terminal.rows !== dims.rows || this._terminal.cols !== dims.cols) {
// core._renderCoordinator.clear()
this._terminal.resize(dims.cols, dims.rows)
this._terminal.resize(dims.cols | 0, dims.rows | 0)
}
}
public proposeDimensions(): ITerminalDimensions | undefined {
if (!this._terminal) {
return undefined
}
if (!this._terminal.element.parentElement) {
return undefined
}
if (!this._terminal) return undefined
if (!this._terminal.element) return undefined
const dimEl = this._terminal.element.closest('[xterm-dimensions]') ?? this._terminal.element.parentElement

@ -117,8 +117,6 @@ input[type='submit'],
[role='button'] {
appearance: none;
outline: none;
border: 1px solid #d9d9d9;
background: #fff;
display: grid;
place-content: center;
@ -128,13 +126,20 @@ input[type='submit'],
font-size: 15px;
font-weight: 500;
color: var(--fg, #333);
background: var(--bg, #fff);
border: var(--brd, 1px solid #d9d9d9);
box-shadow: var(--shadow, 0 0.125rem 0.125rem 0 #00000008);
&:hover {
background: var(--bg-hover, #f8f8f8);
}
padding: 0.25rem 0.5rem;
gap: 0.25rem;
border-radius: 0.25rem;
box-shadow: 0 0.125rem 0.125rem 0 #00000008;
min-height: 1.75rem;
cursor: pointer;
@ -143,43 +148,120 @@ input[type='submit'],
padding-left: 0.125rem;
}
&:hover {
background: #f8f8f8;
}
&.icon {
padding: 0.25rem;
aspect-ratio: 1 / 1;
}
&.run {
background: hsl(120, 35%, 46%);
border-color: hsl(120, 38%, 41%);
color: #fff;
&.flat {
--bg: none;
--bg-hover: #0002;
--brd: none;
.material-symbols-outlined {
font-variation-settings: 'FILL' 1, 'wght' 300, 'GRAD' 0, 'opsz' 20;
min-height: auto;
box-shadow: none;
&.icon {
padding: 0;
}
}
box-shadow: 0 0.125rem 0.2rem 0 hsla(120, 40%, 53%, 0.37);
&.compound {
padding: 0;
gap: 0;
&:hover {
background: hsl(120, 35%, 51%);
> .part {
display: grid;
place-content: center;
padding: 0.25rem 0.5rem;
background: var(--bg);
&:not(:last-child) {
border-right: var(--brd);
}
&:hover {
background: var(--bg-hover);
}
&:has(> .material-symbols-outlined:first-child) {
padding-left: 0.25rem;
}
&:has(> .material-symbols-outlined:last-child) {
padding-right: 0.25rem;
}
}
}
}
&.flat {
min-height: auto;
border: none;
background: none;
box-shadow: none;
.run-style {
--fg: #fff;
&.icon {
padding: 0;
--bg: hsl(120, 35%, 46%);
--bg-hover: hsl(120, 35%, 51%);
--brd: 1px solid hsl(120, 38%, 41%);
--shadow: 0 0.125rem 0.2rem 0 hsla(120, 40%, 53%, 0.37);
.material-symbols-outlined {
font-variation-settings: 'FILL' 1, 'wght' 300, 'GRAD' 0, 'opsz' 20;
}
}
.popup-region {
position: relative;
display: grid;
> .region {
display: grid;
}
> .popup {
position: absolute;
background: #fff;
border: 1px solid #d9d9d9;
border-radius: 0.35rem;
box-shadow: 0 0.125rem 0.25rem 0 #00000030;
overflow: clip;
z-index: 1000;
&.anchor-mode-1 {
top: calc(100% + 0.25rem);
right: 0;
}
}
}
.menu {
display: grid;
grid-auto-flow: row;
font-size: 15px;
font-weight: 500;
border: var(--brd, 1px solid #d9d9d9);
> .item {
display: grid;
padding: 0.25rem 0.5rem;
cursor: pointer;
color: var(--fg, #333);
background: var(--bg, #fff);
&:not(:last-child) {
border-bottom: var(--brd);
}
&:hover {
background: #0002;
background: var(--bg-hover, #00000006);
}
}
}
@ -533,7 +615,7 @@ input[type='submit'],
> .status {
border-top: 1px solid #d9d9d9;
padding: 0.125rem 0.25rem;
padding: 0.25rem 0.25rem;
display: flex;
flex-direction: row;

@ -19,3 +19,11 @@ export function useEventListener(target, event, handler, deps = []) {
}
}, deps)
}
export function stripPrefix(s, prefix) {
return s.slice(0, prefix.length) === prefix ? s.slice(prefix.length) : s
}
export function clamp(min, value, max) {
return Math.max(min, Math.min(value, max))
}