diff --git a/src/components/editor.js b/src/components/editor.js
index 3a47ee5..b35630c 100644
--- a/src/components/editor.js
+++ b/src/components/editor.js
@@ -1,12 +1,9 @@
import fs from 'socket:fs'
import path from 'socket:path'
-import { lookup } from 'socket:mime'
import * as monaco from 'monaco-editor'
import Tonic from '@socketsupply/tonic'
-import { resizePNG } from '../lib/icon.js'
-
function rgbaToHex (rgbaString) {
const rgbaValues = rgbaString.match(/\d+/g)
@@ -216,7 +213,7 @@ class AppEditor extends Tonic {
return
}
- coTerminal.info(`Settings file updated.`)
+ coTerminal.info('Settings file updated.')
app.activatePreviewWindows()
}
diff --git a/src/components/image-preview.js b/src/components/image-preview.js
deleted file mode 100644
index fec9aca..0000000
--- a/src/components/image-preview.js
+++ /dev/null
@@ -1,132 +0,0 @@
-import fs from 'socket:fs'
-import path from 'socket:path'
-
-import Tonic from '@socketsupply/tonic'
-
-import * as ini from '../lib/ini.js'
-
-class AppImagePreview extends Tonic {
- async click (e) {
- const el = Tonic.match(e.target, '[data-event]')
- if (!el) return
-
- const { event, value } = el.dataset
-
- const pickerOpts = {
- types: [
- {
- description: 'Images',
- accept: {
- 'image/*': ['.png']
- }
- }
- ],
- excludeAcceptAllOption: true,
- multiple: false
- }
-
- if (event === 'size') {
- const [fileHandle] = await window.showOpenFilePicker(pickerOpts)
-
- /* const kFileSystemHandleFullName = Object
- .getOwnPropertySymbols(data)
- .find(s => s.description === 'kFileSystemHandleFullName')
- const pathToFile = fileHandle[kFileSystemHandleFullName]
- */
-
- const file = fileHandle.getFile()
- const buf = await file.arrayBuffer()
-
- if (value === 'all') {
- const imagePreview = this.querySelector('.image-preview')
- const blob = new Blob([buf], { type: 'image/png' })
- const url = URL.createObjectURL(blob)
- ;[...imagePreview.querySelectorAll('img')].forEach(img => (img.src = url))
- return
- }
-
- const blob = await resizePNG(buf, parseInt(value))
-
- el.src = URL.createObjectURL(blob)
- }
- }
-
- show () {
- this.classList.add('show')
- }
-
- hide () {
- this.classList.remove('show')
- }
-
- async load (projectNode) {
- this.state.pathToFile = projectNode.id
- this.reRender()
- }
-
- async render () {
- const app = this.props.parent
- const settings = app.state.settings
- const currentProject = app.state.currentProject
-
- let src = ''
-
- if (!currentProject) return this.html``
-
- const cwd = currentProject?.id
-
- try {
- const pathToConfigFile = path.join(cwd, 'socket.ini')
- src = await fs.promises.readFile(pathToConfigFile, 'utf8')
- } catch (err) {
- const notifications = document.querySelector('#notifications')
- notifications?.create({
- type: 'error',
- title: 'Error',
- message: err.message
- })
- }
-
- const getSizes = platform => ini
- .get(src, platform, 'icon_sizes')
- .replace(/"/g, '')
- .split(' ')
- .map(pair => {
- let { 0: size, 1: scale } = pair.split('@')
- scale = parseInt(scale)
-
- const src = this.state.pathToFile.replace(path.HOME, '/user/home')
- const scaled = size * scale
-
- return this.html`
-
-

-
-
- `
- })
-
- return this.html`
-
-
Icon Preview
- Update
-
-
-
MacOS
-
${getSizes('mac')}
-
-
iOS
-
${getSizes('ios')}
-
-
Linux
-
${getSizes('linux')}
-
-
Windows
-
${getSizes('win')}
-
- `
- }
-}
-
-export { AppImagePreview }
-export default AppImagePreview
diff --git a/src/components/project.js b/src/components/project.js
index f3d9eb7..e2a5fe8 100644
--- a/src/components/project.js
+++ b/src/components/project.js
@@ -35,7 +35,7 @@ async function cp (srcDir, destDir) {
const destPath = path.join(destDir, file.name)
if (file.isDirectory()) {
- await copyDirectory(srcPath, destPath)
+ await cp(srcPath, destPath)
} else {
await fs.promises.copyFile(srcPath, destPath, fs.constants.COPYFILE_FICLONE)
}
@@ -462,7 +462,6 @@ class AppProject extends Tonic {
async onSelection (node, isToggle) {
if (!isToggle) {
-
const projectNode = this.getProjectNode(node)
// Check if the project has changed, refresh the props component
@@ -476,10 +475,20 @@ class AppProject extends Tonic {
this.state.currentProject = projectNode.id
+ const coImagePreview = document.querySelector('view-image-preview')
+ const coHome = document.querySelector('view-home')
+
+ coImagePreview.hide()
+ coHome.hide()
+
+ if (projectNode.id === 'home') {
+ coHome.show()
+ return
+ }
+
// Check if this is an image type that we can present
const ext = path.extname(node.id)
const type = await lookup(ext.slice(1))
- const coImagePreview = document.querySelector('app-image-preview')
if (type.length) {
if (/image/.test(type[0].mime)) {
@@ -489,8 +498,6 @@ class AppProject extends Tonic {
}
}
- coImagePreview.hide()
-
// Load the code editor
const coEditor = document.querySelector('app-editor')
coEditor.loadProjectNode(node)
@@ -568,12 +575,24 @@ class AppProject extends Tonic {
async load () {
const oldState = this.state.tree
+ const oldChild = this.getNodeByProperty('id', 'home', oldState)
const tree = {
id: 'root',
children: []
}
+ tree.children.push({
+ id: 'home',
+ parent: tree,
+ selected: oldChild?.selected ?? 0,
+ state: oldChild?.state ?? 0,
+ isDirectory: false,
+ icon: 'home-icon',
+ label: 'Home',
+ children: []
+ })
+
const readDir = async (dirPath, parent) => {
let entries = []
@@ -627,8 +646,6 @@ class AppProject extends Tonic {
}
}
- const app = document.querySelector('app-view')
-
try {
await readDir(path.join(path.DATA, 'projects'), tree)
this.state.tree = tree
diff --git a/src/components/properties.js b/src/components/properties.js
index 05edeb0..b08972d 100644
--- a/src/components/properties.js
+++ b/src/components/properties.js
@@ -4,13 +4,9 @@ import path from 'socket:path'
import { exec } from 'socket:child_process'
import { Encryption, sha256 } from 'socket:network'
-import * as ini from '../lib/ini.js'
+import Config from '../lib/config.js'
class AppProperties extends Tonic {
- constructor () {
- super()
- }
-
async change (e) {
const el = Tonic.match(e.target, '[data-event]')
if (!el) return
@@ -21,7 +17,29 @@ class AppProperties extends Tonic {
const notifications = document.querySelector('#notifications')
const editor = document.querySelector('app-editor')
const project = document.querySelector('app-project')
+ const config = new Config(app.currentProject?.id)
+
+ //
+ // if the user changes the project link, we need to update the project.
+ // projects are keyed on the bundle id, so get the bundle id from the
+ // config, then update the sharedSecret, then await configt the network.
+ //
+ if (event === 'project-link') {
+ if (!config) return
+
+ let bundleId = await config.get('meta', 'bundle_identifier')
+ if (bundleId) bundleId = bundleId.replace(/"/g, '')
+
+ const { data: dataBundle } = await app.db.projects.get(bundleId)
+ dataBundle.sharedSecret = el.value
+ await app.db.projects.put(bundleId, dataBundle)
+ await app.initNetwork()
+ }
+
+ //
+ // when the user wants to toggle one of the preview windows they have configured
+ //
if (event === 'preview') {
const pathToSettingsFile = path.join(path.DATA, 'projects', 'settings.json')
const previewWindow = app.state.settings.previewWindows.find(o => o.title === value)
@@ -59,13 +77,11 @@ class AppProperties extends Tonic {
}
}
+ //
+ // When the user wants to make a change to the one of the properties in the await config file
+ //
if (event === 'property') {
- const node = project.getNodeByProperty('id', 'socket.ini')
- node.data = ini.set(node.data, section, el.id, el.value)
-
- const dest = path.join(app.state.cwd, node.id)
- await fs.promises.writeFile(dest, node.data)
-
+ await config.set(section, el.id, el.value)
editor.loadProjectNode(node)
notifications?.create({
@@ -77,14 +93,17 @@ class AppProperties extends Tonic {
}
async click (e) {
+ const elCopy = Tonic.match(e.target, '[symbol-id="copy-icon"]')
+
+ if (elCopy) {
+ navigator.clipboard.writeText('union://' + elCopy.nextElementSibling.value)
+ return
+ }
+
const el = Tonic.match(e.target, '[data-event]')
if (!el) return
- const { event, propertyValue } = el.dataset
-
- if (event === 'copy-link') {
- navigator.clipboard.writeText(el.value)
- }
+ const { event } = el.dataset
if (event === 'publish') {
const coDialogPublish = document.querySelector('dialog-publish')
@@ -98,27 +117,9 @@ class AppProperties extends Tonic {
}
async render () {
- let src = ''
-
const app = this.props.parent
const settings = app.state.settings
- const currentProject = app.state.currentProject
- const cwd = currentProject?.id
-
- if (currentProject) {
- try {
- const pathToConfigFile = path.join(cwd, 'socket.ini')
- src = await fs.promises.readFile(pathToConfigFile, 'utf8')
- } catch (err) {
- const notifications = document.querySelector('#notifications')
- notifications?.create({
- type: 'error',
- title: 'Error',
- message: err.message
- })
- }
- }
-
+ const config = new Config(settings.currentProject?.id)
const previewWindows = []
if (settings?.previewWindows) {
@@ -143,10 +144,11 @@ class AppProperties extends Tonic {
}
}
- let bundleId = ini.get(src, 'meta', 'bundle_identifier')
+ let bundleId = await config.get('meta', 'bundle_identifier')
if (bundleId) bundleId = bundleId.replace(/"/g, '')
let sharedSecret = ''
+ const cwd = app.state.currentProject?.id
const { data: hasBundle } = await app.db.projects.has(bundleId)
@@ -175,7 +177,7 @@ class AppProperties extends Tonic {
clusterId,
subclusterId,
sharedKey,
- sharedSecret // TODO(@heapwolf): encrypt sharedSecret via initial global password
+ sharedSecret // TODO(@heapwolf): encrypt sharedSecret via await configtial global password
})
//
@@ -189,13 +191,13 @@ class AppProperties extends Tonic {
if (cwd) {
//
- // If there is a current project, check if its been git initialized.
+ // If there is a current project, check if its been git await configtialized.
//
try {
await fs.promises.stat(path.join(cwd, '.git'))
} catch (err) {
try {
- gitStatus = await exec('git init', { cwd })
+ gitStatus = await exec('git await configt', { cwd })
} catch (err) {
gitStatus.stderr = err.message
}
@@ -256,27 +258,27 @@ class AppProperties extends Tonic {
id="application"
label="Desktop Features"
>
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/publish.js b/src/components/publish.js
index 3d33215..8449b1d 100644
--- a/src/components/publish.js
+++ b/src/components/publish.js
@@ -1,12 +1,11 @@
import fs from 'socket:fs'
import path from 'socket:path'
-import { Encryption } from 'socket:network'
-import { spawn, exec } from 'socket:child_process'
+import { exec } from 'socket:child_process'
import Tonic from '@socketsupply/tonic'
import { TonicDialog } from '@socketsupply/components/dialog'
-import * as ini from '../lib/ini.js'
+import Config from '../lib/config.js'
export class DialogPublish extends TonicDialog {
click (e) {
@@ -25,23 +24,8 @@ export class DialogPublish extends TonicDialog {
const currentProject = app.state.currentProject
if (!currentProject) return
- let src
-
- try {
- const fp = path.join(currentProject.id, 'socket.ini')
- src = await fs.promises.readFile(fp, 'utf8')
- } catch (err) {
- const notifications = document.querySelector('#notifications')
- notifications?.create({
- type: 'error',
- title: 'Error',
- message: err.message
- })
-
- return
- }
-
- let bundleId = ini.get(src, 'meta', 'bundle_identifier')
+ 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)
@@ -54,11 +38,10 @@ export class DialogPublish extends TonicDialog {
async publish (type, value) {
const app = this.props.parent
- const settings = app.state.settings
const dataProject = await this.getProject()
const opts = {
-
+ // TODO(@heapwolf): probably chain with previousId
}
const subcluster = app.socket.subclusters.get(dataProject.subclusterId)
@@ -193,7 +176,7 @@ export class DialogPublish extends TonicDialog {
// Just publish the diff
//
try {
- output = await exec(`git format-patch -1 HEAD --stdout`, { cwd })
+ output = await exec('git format-patch -1 HEAD --stdout', { cwd })
} catch (err) {
output.stderr = err.message
}
diff --git a/src/components/sprite.js b/src/components/sprite.js
index 59a281b..7586d21 100644
--- a/src/components/sprite.js
+++ b/src/components/sprite.js
@@ -22,6 +22,22 @@ class AppSprite extends Tonic {
c-4.8,0.7-7.8,3.9-7.8,9.6v35.8C17.5,94.6,20.5,97.7,26.8,97.7z M33.1,28.7c0-12.3,7.9-18.8,17-18.8s17,6.5,17,18.8V42h-34V28.7z"/>
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/subscribe.js b/src/components/subscribe.js
index 7ce76aa..f60240f 100644
--- a/src/components/subscribe.js
+++ b/src/components/subscribe.js
@@ -12,6 +12,10 @@ export class DialogSubscribe extends TonicDialog {
await this.reRender()
}
+ async click (e) {
+ // TODO(@heapwolf): create project entry, call initNetwork
+ }
+
async render () {
return this.html`
@@ -19,16 +23,9 @@ export class DialogSubscribe extends TonicDialog {
- Enter the unique shared secret for the project you want to subscribe to.
+ Enter the unique link for the project you want to subscribe to.
-
-
-
div,
-section {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- overflow: hidden;
-}
-
-section {
- top: 22px;
-}
-
label.title {
position: absolute;
top: 0;
@@ -162,12 +148,6 @@ label.title {
white-space: nowrap;
}
-section.render {
- padding: 10%;
- text-align: center;
- overflow: auto;
-}
-
main-component {
position: absolute;
top: 38px;
@@ -184,7 +164,7 @@ header {
app-view > header {
display: none;
- grid-template-columns: 1fr 34px 250px 34px 1fr;
+ grid-template-columns: 1fr 280px 34px 34px 1fr;
gap: 12px;
grid-template-rows: auto;
align-content: center;
@@ -196,6 +176,22 @@ app-view > header {
right: 0;
}
+
+app-view > header .build-controls {
+ position: relative;
+}
+
+app-view > header .build-controls tonic-button {
+ position: absolute;
+ top: 4px;
+ left: 12px;
+ z-index: 1;
+}
+
+app-view > header .build-controls tonic-select select {
+ text-indent: 26px;
+}
+
#split-main {
top: 0px;
border-top: 1px solid var(--tonic-border);
diff --git a/src/css/preview.css b/src/css/preview.css
deleted file mode 100644
index eb3d3de..0000000
--- a/src/css/preview.css
+++ /dev/null
@@ -1,53 +0,0 @@
-app-preview {
- position: absolute;
- top: 0; bottom: 0; left: 0; right: 0;
- background: var(--tonic-background);
-}
-
-app-preview .container {
- position: absolute;
- top: 0px; bottom: 0px; left: 0px; right: 0px;
-}
-
-app-preview .device {
- position: relative;
- height: 100%;
- border: 1px solid var(--tonic-border);
- overflow: hidden;
-}
-
-app-preview .device iframe {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- height: 100%;
- width: 100%;
-}
-
-/* Source: https://github.com/kylebshr/ScreenCorners */
-
-app-preview .device[device="ios"] {
- aspect-ratio: 9 / 19.5;
- border-radius: 39px;
- margin: 60px;
-}
-
-app-preview .device[device="ipad"] {
- aspect-ratio: 3 / 4;
- border-radius: 18px;
- margin: 60px;
-}
-
-app-preview .device[device="darwin"] {
- aspect-ratio: initial;
- border-radius: 12px;
- position: absolute;
- top: 60px;
- border-top: 1px solid var(--tonic-border);
- left: 60px;
- right: 60px;
- bottom: 60px;
- height: unset;
-}
diff --git a/src/css/view-home.css b/src/css/view-home.css
new file mode 100644
index 0000000..c36b9e1
--- /dev/null
+++ b/src/css/view-home.css
@@ -0,0 +1,59 @@
+view-home {
+ display: none;
+ grid-template-rows: auto 1fr;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: -1;
+ opacity: 0;
+ background: var(--tonic-background);
+ padding: 6%;
+}
+
+view-home.show {
+ display: grid;
+ z-index: 40;
+ opacity: 1;
+}
+
+view-home h1 {
+ font-family: var(--tonic-body);
+ text-transform: uppercase;
+ font-size: 38px;
+ margin-top: 0;
+ font-weight: 100;
+}
+
+view-home h1 b {
+ font-family: var(--tonic-header);
+ text-transform: uppercase;
+ font-size: 38px;
+ font-weight: 900;
+}
+
+view-home section {
+ position: relative;
+}
+
+view-home section.hero {
+ height: 80px;
+}
+
+view-home tonic-tabs {
+ margin-left: -6px;
+}
+
+view-home tonic-tab a {
+ padding: 6px 10px;
+ border-radius: 4px;
+ text-decoration: none;
+ text-transform: uppercase;
+ color: var(--tonic-primary);
+}
+
+view-home tonic-tab a[aria-selected="true"] {
+ background: var(--tonic-accent);
+ color: white;
+}
diff --git a/src/css/image-preview.css b/src/css/view-image-preview.css
similarity index 75%
rename from src/css/image-preview.css
rename to src/css/view-image-preview.css
index 8f8d5eb..1c76c84 100644
--- a/src/css/image-preview.css
+++ b/src/css/view-image-preview.css
@@ -1,4 +1,4 @@
-app-image-preview {
+view-image-preview {
position: absolute;
top: 0; bottom: 0; left: 0; right: 0;
overflow: auto;
@@ -15,12 +15,12 @@ app-image-preview {
padding: 10%;
}
-app-image-preview.show {
+view-image-preview.show {
opacity: 1;
z-index: 30;
}
-app-image-preview .top {
+view-image-preview .top {
display: grid;
justify-content: center;
align-items: center;
@@ -28,10 +28,10 @@ app-image-preview .top {
margin-bottom: 100px;
}
-app-image-preview .bottom {
+view-image-preview .bottom {
}
-app-image-preview .bottom h2 {
+view-image-preview .bottom h2 {
border-bottom: 1px solid var(--tonic-info);
font-size: 14px;
text-transform: uppercase;
@@ -39,7 +39,7 @@ app-image-preview .bottom h2 {
color: var(--tonic-info);
}
-app-image-preview .bottom .icon-grid {
+view-image-preview .bottom .icon-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
padding: 60px 0;
@@ -48,33 +48,33 @@ app-image-preview .bottom .icon-grid {
justify-content: center;
}
-app-image-preview tonic-button {
+view-image-preview tonic-button {
margin: auto;
}
-app-image-preview h1 {
+view-image-preview h1 {
color: var(--tonic-border);
font-size: 28px;
font-family: var(--tonic-body);
}
-app-image-preview img {
+view-image-preview img {
margin: auto;
}
-app-image-preview .size {
+view-image-preview .size {
display: grid;
justify-content: center;
align-items: center;
}
-app-image-preview .size label {
+view-image-preview .size label {
text-align: center;
display: inline-block;
margin-top: 10px;
color: var(--tonic-primary);
}
-app-image-preview .size icon {
+view-image-preview .size icon {
cursor: pointer;
}
diff --git a/src/index.html b/src/index.html
index 6527a7a..6b235c9 100644
--- a/src/index.html
+++ b/src/index.html
@@ -15,18 +15,20 @@
object-src 'none';
"
>
-
-
-
-
-
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/src/index.js b/src/index.js
index c0392e0..4df0217 100644
--- a/src/index.js
+++ b/src/index.js
@@ -12,12 +12,14 @@ import components from '@socketsupply/components'
import Database from './db/index.js'
+import { ViewHome } from './views/home.js'
+import { ViewImagePreview } from './views/image-preview.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 { AppImagePreview } from './components/image-preview.js'
import { DialogPublish } from './components/publish.js'
import { DialogSubscribe } from './components/subscribe.js'
@@ -53,7 +55,7 @@ class AppView extends Tonic {
// if the user currently has the config file open in the editor...
if (currentProject.label === 'settings.json' && currentProject.parent.id === 'root') {
- const coEditor = document.querySelctor('app-editor')
+ const coEditor = document.querySelector('app-editor')
try {
coEditor.value = JSON.stringify(this.state.settings, null, 2)
@@ -511,6 +513,7 @@ class AppView extends Tonic {
;
File:
+ Save: s + CommandOrControl
New Project: n + CommandOrControl
Add Shared Project: G + CommandOrControl
---
@@ -540,7 +543,8 @@ class AppView extends Tonic {
;
Build & Run:
- Evaluate Editor Source: r + CommandOrControl + Shift
+ Evaluate Source: r + CommandOrControl + Shift
+ Toggle Realtime Preview: k + CommandOrControl + Shift
---
Android: s + CommandOrControl
iOS: s + CommandOrControl
@@ -679,18 +683,22 @@ class AppView extends Tonic {