diff --git a/src/components/editor.js b/src/components/editor.js index 4f27a39..a6f3eed 100644 --- a/src/components/editor.js +++ b/src/components/editor.js @@ -263,6 +263,7 @@ class AppEditor extends Tonic { const coTerminal = document.querySelector('app-terminal') const coProperties = document.querySelector('app-properties') const coTabs = document.querySelector('editor-tabs') + const coEditor = document.querySelector('app-editor') if (!coTabs.tab) return @@ -278,13 +279,11 @@ class AppEditor extends Tonic { } coTerminal.info('Settings file updated.') + coEditor.refreshColors() app.activatePreviewWindows() } - clearTimeout(this.debouncePropertiesRerender) - this.debouncePropertiesRerender = setTimeout(() => { - coProperties.reRender() - }, 512) + coProperties.reRender() try { await fs.promises.writeFile(coTabs.tab.path, value) @@ -364,7 +363,7 @@ class AppEditor extends Tonic { { token: 'variable.predefined', foreground: '4864AA' }, { token: 'variable.parameter', foreground: '9CDCFE' }, { token: 'constant', foreground: '569CD6' }, - { token: 'comment', foreground: '338c32' }, + { token: 'comment', foreground: colors.secondary }, { token: 'number', foreground: colors.accent }, { token: 'number.hex', foreground: '5BB498' }, { token: 'regexp', foreground: 'B46695' }, diff --git a/src/components/git-status.js b/src/components/git-status.js new file mode 100644 index 0000000..ee91d26 --- /dev/null +++ b/src/components/git-status.js @@ -0,0 +1,49 @@ +import Tonic from '@socketsupply/tonic' +import { exec } from 'socket:child_process' + +// TODO(@heapwolf): this should be a component +class GitStatus extends Tonic { + async render () { + const app = this.props.app + const currentProject = app.state.currentProject + + const { data: dataProject } = await app.db.projects.get(currentProject.projectId) + + let gitStatus = { stdout: '', stderr: '' } + + // + // Try to get the status of the project to tell the user what + // has changed and help them decide if they should publish. + // + try { + gitStatus = await exec('git status --porcelain', { cwd: dataProject.path }) + } catch (err) { + gitStatus.stderr = err.message + } + + if (gitStatus?.stderr.includes('command not found')) { + return this.html` + Git is not installed and is required to use this program. + + ` + } + + return this.html` +

Git Integration

+ ${gitStatus.stderr || gitStatus.stdout} + ` + } +} + +export default GitStatus +export { GitStatus } diff --git a/src/components/patch-requests.js b/src/components/patch-requests.js new file mode 100644 index 0000000..7d41eec --- /dev/null +++ b/src/components/patch-requests.js @@ -0,0 +1,46 @@ +import Tonic from '@socketsupply/tonic' +import { exec } from 'socket:child_process' + +class PatchRequests extends Tonic { + async render () { + const app = this.props.app + + const { data: dataPatches } = await app.db.patches.readAll() + + let patches = [] + + for (const [patchId, patch] of dataPatches.entries()) { + patches.push(this.html` + + + + + + ${patch.author} + ${patch.date} + ${patch.parent} + ${patch.message} + + `) + } + + return this.html` +

Patch Requests

+ + + + + + + + + + ${patches} + +
ActionsAuthorDateParentCommit Message
+ ` + } +} + +export default PatchRequests +export { PatchRequests } diff --git a/src/components/project.js b/src/components/project.js index bdc54d1..19e5013 100644 --- a/src/components/project.js +++ b/src/components/project.js @@ -334,7 +334,7 @@ class AppProject extends Tonic { if (!node) this.getNodeFromElement(el.parentElement) if (!node) return - if (node.nonMovable && !node.type === 'project') return + if (node.nonMovable && node.type !== 'project') return const container = el.querySelector('.label') @@ -726,6 +726,7 @@ class AppProject extends Tonic { selected: oldChild?.selected ?? 0, state: oldChild?.state ?? 0, id: project.path, + bundleId: project.bundleId, projectId, label: project.label, isDirectory: false, @@ -735,6 +736,11 @@ class AppProject extends Tonic { children: [] } + if (!this.props.parent.state.currentProject) { + this.props.parent.state.currentProject = node + this.props.parent.reloadPreviewWindows() + } + tree.children.push(node) if (project.path) { diff --git a/src/components/properties.js b/src/components/properties.js index f5f7a7c..1fd671a 100644 --- a/src/components/properties.js +++ b/src/components/properties.js @@ -6,38 +6,6 @@ import process from 'socket:process' import Config from '../lib/config.js' class AppProperties extends Tonic { - async saveSettingsFile () { - const app = this.props.parent - const currentProject = app.state.currentProject - const pathToSettingsFile = path.join(path.DATA, 'projects', 'settings.json') - const coTabs = document.querySelector('editor-tabs') - const coEditor = document.querySelector('app-editor') - - // if the user currently has the config file open in the editor... - if (coTabs.tab?.isRootSettingsFile) { - try { - coEditor.value = JSON.stringify(app.state.settings, null, 2) - } catch (err) { - return notifications.create({ - type: 'error', - title: 'Unable to save config file', - message: err.message - }) - } - } - - try { - const str = JSON.stringify(app.state.settings) - await fs.promises.writeFile(pathToSettingsFile, str) - } catch (err) { - return notifications?.create({ - type: 'error', - title: 'Error', - message: 'Unable to update settings' - }) - } - } - async change (e) { const el = Tonic.match(e.target, '[data-event]') if (!el) return @@ -60,7 +28,7 @@ class AppProperties extends Tonic { previewWindow.active = !previewWindow.active } - await this.saveSettingsFile() + await app.saveSettingsFile() app.activatePreviewWindows() } diff --git a/src/components/publish.js b/src/components/publish.js index 42228ad..5fc9341 100644 --- a/src/components/publish.js +++ b/src/components/publish.js @@ -19,26 +19,10 @@ export class DialogPublish extends TonicDialog { } } - async getProject () { - const app = this.props.parent - const currentProject = app.state.currentProject - if (!currentProject) return - - let config = new Config(currentProject.id) - let bundleId = await config.get('meta', 'bundle_identifier') - bundleId = bundleId.replace(/"/g, '') - - const { data: hasProject } = await app.db.projects.has(bundleId) - - if (hasProject) { - const { data: dataProject } = await app.db.projects.get(bundleId) - return dataProject - } - } - async publish (type, value) { const app = this.props.parent - const dataProject = await this.getProject() + const currentProject = app.state.currentProject + const { data: dataProject } = await app.db.projects.get(currentProject.bundleId) const opts = { // TODO(@heapwolf): probably chain with previousId @@ -197,8 +181,8 @@ export class DialogPublish extends TonicDialog { this.publish('patch', Buffer.from(output.stdout)) // into the background } - const coProperties = document.querySelector('app-properties') - coProperties.reRender() + const coProjectSummary = document.querySelector('view-project-summary') + coProjectSummary.reRender() } return this.html` diff --git a/src/css/component-patch-requests.css b/src/css/component-patch-requests.css new file mode 100644 index 0000000..6307c06 --- /dev/null +++ b/src/css/component-patch-requests.css @@ -0,0 +1,31 @@ +patch-requests table { + font-family: var(--tonic-monospace); + width: 100%; +} + +patch-requests table thead { + text-align: left; +} + +patch-requests table tr th { + height: 40px; + border-bottom: 1px solid var(--tonic-border); + color: var(--tonic-medium, #999); + font-weight: 500; + font: 12px/14px var(--tonic-subheader, 'Arial', sans-serif); + text-transform: uppercase; + letter-spacing: 1px; +} + +patch-requests table td { + padding: 8px 0px; + border-bottom: 1px solid var(--tonic-border); +} + +patch-requests table td { + min-width: 120px; +} + +patch-requests table tr:last-of-type td { + border-bottom: none; +} diff --git a/src/css/theme.css b/src/css/theme.css index d1593fd..f3e12f5 100644 --- a/src/css/theme.css +++ b/src/css/theme.css @@ -17,7 +17,7 @@ body { --tonic-window: rgba(255, 255, 255, 1); --tonic-accent: rgba(56, 185, 255, 1); --tonic-primary: rgba(54, 57, 61, 1); - --tonic-secondary: rgba(232, 232, 228, 1); + --tonic-secondary: rgba(190, 190, 190, 1); --tonic-light: rgba(153, 157, 160, 1); --tonic-medium: rgba(153, 157, 160, 1); --tonic-shadow: rgba(150, 150, 150, 0.25); @@ -47,7 +47,7 @@ body { --tonic-window: rgba(46, 46, 46, 1); --tonic-accent: rgba(56, 185, 255, 1); --tonic-primary: rgba(255, 255, 255, 1); - --tonic-secondary: rgba(120, 120, 120, 1); + --tonic-secondary: rgba(93, 93, 93, 1); --tonic-medium: rgba(153, 157, 160, 1); --tonic-dark: rgba(28, 28, 28, 1); --tonic-shadow: rgba(0, 0, 0, 0.3); diff --git a/src/css/view-project-summary.css b/src/css/view-project-summary.css index 6d03537..e2b6f3a 100644 --- a/src/css/view-project-summary.css +++ b/src/css/view-project-summary.css @@ -12,6 +12,13 @@ view-project-summary.show { z-index: 30; } +view-project-summary h2 { + font-size: 20px; + text-transform: uppercase; + color: var(--tonic-info); + font-weight: 100; +} + view-project-summary header span { width: 100%; text-align: center; @@ -42,7 +49,7 @@ view-project-summary .sharing { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 20px; - grid-template-rows: auto auto 1fr; + grid-template-rows: auto auto auto 1fr; align-items: end; } @@ -62,7 +69,12 @@ view-project-summary #publish { grid-area: 2 / 4; } -view-project-summary view-git-status { +view-project-summary git-status { grid-area: 3 / span 4; align-self: start; } + +view-project-summary patch-requests { + grid-area: 4 / span 4; + align-self: start; +} diff --git a/src/index.html b/src/index.html index 0595cc7..d1cbffd 100644 --- a/src/index.html +++ b/src/index.html @@ -23,6 +23,7 @@ + diff --git a/src/index.js b/src/index.js index 8c91dc6..1a26393 100644 --- a/src/index.js +++ b/src/index.js @@ -16,11 +16,13 @@ import { ViewHome } from './views/home.js' import { ViewImagePreview } from './views/image-preview.js' import { ViewProjectSummary } from './views/project-summary.js' +import { AppEditor } from './components/editor.js' +import { GitStatus } from './components/git-status.js' +import { PatchRequests } from './components/patch-requests.js' import { AppTerminal } from './components/terminal.js' import { AppProject } from './components/project.js' import { AppProperties } from './components/properties.js' import { AppSprite } from './components/sprite.js' -import { AppEditor } from './components/editor.js' import { DialogConfirm } from './components/confirm.js' import { DialogPublish } from './components/publish.js' import { DialogSubscribe } from './components/subscribe.js' @@ -163,7 +165,7 @@ class AppView extends Tonic { zoom: this.state.zoom[index] || '1' }).toString() - let currentProjectPath = this.getCurrentProjectPath() + let currentProjectPath = this.getCurrentProjectPath() if (!currentProjectPath) return const opts = { @@ -432,7 +434,38 @@ class AppView extends Tonic { const coProperties = document.querySelector('app-properties') this.state.settings.previewMode = !this.state.settings.previewMode - coProperties.saveSettingsFile() + this.saveSettingsFile() + } + + async saveSettingsFile () { + const currentProject = this.state.currentProject + const pathToSettingsFile = path.join(path.DATA, 'settings.json') + const coTabs = document.querySelector('editor-tabs') + const coEditor = document.querySelector('app-editor') + + // if the user currently has the config file open in the editor... + if (coTabs.tab?.isRootSettingsFile) { + try { + coEditor.value = JSON.stringify(this.state.settings, null, 2) + } catch (err) { + return notifications.create({ + type: 'error', + title: 'Unable to save config file', + message: err.message + }) + } + } + + try { + const str = JSON.stringify(this.state.settings) + await fs.promises.writeFile(pathToSettingsFile, str) + } catch (err) { + return notifications?.create({ + type: 'error', + title: 'Error', + message: 'Unable to update settings' + }) + } } // @@ -783,6 +816,8 @@ window.onload = () => { Tonic.add(AppSprite) Tonic.add(AppTerminal) Tonic.add(AppView) + Tonic.add(GitStatus) + Tonic.add(PatchRequests) Tonic.add(DialogConfirm) Tonic.add(DialogPublish) Tonic.add(DialogSubscribe) diff --git a/src/views/project-summary.js b/src/views/project-summary.js index 09532f2..9d8eac9 100644 --- a/src/views/project-summary.js +++ b/src/views/project-summary.js @@ -1,51 +1,6 @@ import Tonic from '@socketsupply/tonic' -import { exec } from 'socket:child_process' import { Encryption, sha256 } from 'socket:network' -class ViewGitStatus extends Tonic { - async render () { - const app = this.props.app - const currentProject = app.state.currentProject - - const { data: dataProject } = await app.db.projects.get(currentProject.projectId) - - let gitStatus = { stdout: '', stderr: '' } - - // - // Try to get the status of the project to tell the user what - // has changed and help them decide if they should publish. - // - try { - gitStatus = await exec('git status --porcelain', { cwd: dataProject.path }) - } catch (err) { - gitStatus.stderr = err.message - } - - if (gitStatus?.stderr.includes('command not found')) { - return this.html` - Git is not installed and is required to use this program. - - ` - } - - return this.html` - ${gitStatus.stderr || gitStatus.stdout} - ` - } -} - -Tonic.add(ViewGitStatus) - class ViewProjectSummary extends Tonic { show () { this.classList.add('show') @@ -163,10 +118,13 @@ class ViewProjectSummary extends Tonic { data-event="publish" width="100%" class="pull-right" - >Publish + >Commit & Publish + + + - - + + ` }