diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index e90fcce..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,4 +0,0 @@ -# These are supported funding model platforms - -patreon: "100" -liberapay: hundredrabbits diff --git a/.nojekyll b/.nojekyll deleted file mode 100644 index 8b13789..0000000 --- a/.nojekyll +++ /dev/null @@ -1 +0,0 @@ - diff --git a/cli b/cli new file mode 100644 index 0000000..ce2b16d Binary files /dev/null and b/cli differ diff --git a/examples/basics/io.lisp b/examples/basics/io.lisp new file mode 100644 index 0000000..4eeb500 --- /dev/null +++ b/examples/basics/io.lisp @@ -0,0 +1,2 @@ +(open "/home/dakedres/pictures/elex-hiram.png") +(export "png" 1.0 "test") \ No newline at end of file diff --git a/logo.grid b/logo.grid new file mode 100644 index 0000000..5dc5a27 --- /dev/null +++ b/logo.grid @@ -0,0 +1,125 @@ +{ + "settings": { + "size": { + "width": 615, + "height": 480 + } + }, + "layers": [ + [ + { + "type": "line", + "vertices": [ + { + "x": -90, + "y": 60 + }, + { + "x": -75, + "y": -135 + } + ] + }, + { + "type": "arc_r", + "vertices": [ + { + "x": -60, + "y": -15 + }, + { + "x": -60, + "y": -15 + }, + { + "x": -180, + "y": 75 + } + ] + }, + { + "type": "arc_c", + "vertices": [ + { + "x": -90, + "y": 135 + }, + { + "x": -180, + "y": 75 + } + ] + }, + { + "type": "line", + "vertices": [ + { + "x": 30, + "y": 45 + }, + { + "x": -90, + "y": 60 + } + ] + }, + { + "type": "arc_r", + "vertices": [ + { + "x": 30, + "y": 45 + }, + { + "x": -60, + "y": -15 + } + ] + }, + { + "type": "arc_c", + "vertices": [ + { + "x": 30, + "y": 45 + }, + { + "x": -90, + "y": 135 + } + ] + } + ], + [], + [] + ], + "styles": [ + { + "thickness": 4, + "strokeLinecap": "round", + "strokeLinejoin": "round", + "color": "#0a0a0a", + "fill": "none", + "mirror_style": 0, + "transform": "rotate(45)" + }, + { + "thickness": 15, + "strokeLinecap": "round", + "strokeLinejoin": "round", + "color": "#4a4a4a", + "fill": "none", + "mirror_style": 0, + "transform": "rotate(45)" + }, + { + "thickness": 15, + "strokeLinecap": "round", + "strokeLinejoin": "round", + "color": "#6a6a6a", + "fill": "none", + "mirror_style": 0, + "transform": "rotate(45)" + } + ] +} \ No newline at end of file diff --git a/logo.svg b/logo.svg new file mode 100644 index 0000000..4043147 --- /dev/null +++ b/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/open.sh b/open.sh index 13f8b75..0fc64a6 100755 --- a/open.sh +++ b/open.sh @@ -1,4 +1,3 @@ -localhost . -p 1616 & $(command -v ungoogled-chromium ||\ -command -v chromium ||\ -command -v chrome) --new-window --app="http://localhost:1616/src/browser/index.html" \ No newline at end of file + command -v chromium ||\ + command -v chrome) --new-window --app="file://$PWD/src/browser/index.html" \ No newline at end of file diff --git a/src/browser/Device.js b/src/browser/Device.js new file mode 100644 index 0000000..095f89a --- /dev/null +++ b/src/browser/Device.js @@ -0,0 +1,50 @@ +import * as store from './Store.js' + +const noWorkingDirWarning = "Please open a directory to allow file saving." + +function Device() { + this.init = async () => { + await store.Init() + window.cwd = await store.Get('directory') + } + + this.cd = async () => { + window.cwd = await window.showDirectoryPicker() + await store.Set('directory', window.cwd) + } + + this.entries = async () => { + let pool = new Map() + + for await (let [ , e ] of window.cwd.entries()) { + if(e instanceof FileSystemFileHandle) { + pool.set(e.name, e) + } + } + + return pool + } + + this.create = async (sPath) => { + return window.cwd.getFileHandle(sPath, { create: true }) + } + + this.open = async (hFile) => { + if(!window.cwd) { + return new Blob([ noWorkingDirWarning ], { type: "text/plain" }) + } + + return hFile.getFile() + } + + this.write = async (hFile, sContent) => { + if(!window.cwd) { + throw new Error("Unable to save file: no working directory") + } + + let s = await hFile.createWritable() + .catch(console.error) + await s.write(sContent) + await s.close() + } +} \ No newline at end of file diff --git a/src/browser/Source.js b/src/browser/Source.js index 1d1ef8f..696bf9a 100644 --- a/src/browser/Source.js +++ b/src/browser/Source.js @@ -1,97 +1,42 @@ function Source (client) { - this.cache = {} + this.cwd = null - this.install = () => { - } + this.install = () => { + } - this.start = () => { - this.new() - } + this.start = () => { + } - this.new = () => { - console.log('Source', 'New file..') - this.cache = {} - } + // I/O - this.open = (ext, callback, store = false) => { - console.log('Source', 'Open file..') - const input = document.createElement('input') - input.type = 'file' - input.onchange = (e) => { - const file = e.target.files[0] - if (file.name.indexOf('.' + ext) < 0) { console.warn('Source', `Skipped ${file.name}`); return } - this.read(file, callback, store) - } - input.click() - } + this.read = (file, callback, store = false) => { + if(!this.cwd) { + openCwd() + } - this.load = (ext, callback) => { - console.log('Source', 'Load files..') - const input = document.createElement('input') - input.type = 'file' - input.setAttribute('multiple', 'multiple') - input.onchange = (e) => { - for (const file of e.target.files) { - if (file.name.indexOf('.' + ext) < 0) { console.warn('Source', `Skipped ${file.name}`); continue } - this.read(file, this.store) - } - } - input.click() - } + + } - this.store = (file, content) => { - console.info('Source', 'Stored ' + file.name) - this.cache[file.name] = content - } + this.write = (name, ext, content, type, settings = 'charset=utf-8') => { - this.save = (name, content, type = 'text/plain', callback) => { - this.saveAs(name, content, type, callback) - } + } - this.saveAs = (name, ext, content, type = 'text/plain', callback) => { - console.log('Source', 'Save new file..') - this.write(name, ext, content, type, callback) - } + function timestamp (d = new Date(), e = new Date(d)) { + return `${arvelie()}-${neralie()}` + } - // I/O + function arvelie (date = new Date()) { + const start = new Date(date.getFullYear(), 0, 0) + const diff = (date - start) + ((start.getTimezoneOffset() - date.getTimezoneOffset()) * 60 * 1000) + const doty = Math.floor(diff / 86400000) - 1 + const y = date.getFullYear().toString().substr(2, 2) + const m = doty === 364 || doty === 365 ? '+' : String.fromCharCode(97 + Math.floor(doty / 14)).toUpperCase() + const d = `${(doty === 365 ? 1 : doty === 366 ? 2 : (doty % 14)) + 1}`.padStart(2, '0') + return `${y}${m}${d}` + } - this.read = (file, callback, store = false) => { - const reader = new FileReader() - reader.onload = (event) => { - const res = event.target.result - if (callback) { callback(file, res) } - if (store) { this.store(file, res) } - } - reader.readAsText(file, 'UTF-8') - } - - this.write = (name, ext, content, type, settings = 'charset=utf-8') => { - const link = document.createElement('a') - link.setAttribute('download', `${name}-${timestamp()}.${ext}`) - if (type === 'image/png' || type === 'image/jpeg') { - link.setAttribute('href', content) - } else { - link.setAttribute('href', 'data:' + type + ';' + settings + ',' + encodeURIComponent(content)) - } - link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window })) - } - - function timestamp (d = new Date(), e = new Date(d)) { - return `${arvelie()}-${neralie()}` - } - - function arvelie (date = new Date()) { - const start = new Date(date.getFullYear(), 0, 0) - const diff = (date - start) + ((start.getTimezoneOffset() - date.getTimezoneOffset()) * 60 * 1000) - const doty = Math.floor(diff / 86400000) - 1 - const y = date.getFullYear().toString().substr(2, 2) - const m = doty === 364 || doty === 365 ? '+' : String.fromCharCode(97 + Math.floor(doty / 14)).toUpperCase() - const d = `${(doty === 365 ? 1 : doty === 366 ? 2 : (doty % 14)) + 1}`.padStart(2, '0') - return `${y}${m}${d}` - } - - function neralie (d = new Date(), e = new Date(d)) { - const ms = e - d.setHours(0, 0, 0, 0) - return (ms / 8640 / 10000).toFixed(6).substr(2, 6) - } + function neralie (d = new Date(), e = new Date(d)) { + const ms = e - d.setHours(0, 0, 0, 0) + return (ms / 8640 / 10000).toFixed(6).substr(2, 6) + } } diff --git a/src/browser/Store.js b/src/browser/Store.js new file mode 100644 index 0000000..b0bcbc8 --- /dev/null +++ b/src/browser/Store.js @@ -0,0 +1,47 @@ +function Store(objectStoreName) { + const transact = () => { + return this.db + .transaction(objectStoreName, "readwrite") + .objectStore(objectStoreName) + } + + this.Get = (key) => { + return promisify( + transact().get(key) + ) + } + + this.Set = (key, value) => { + return promisify( + transact().put(value, key) + ) + } + + return this +} + +Store.Open = async (dbName, objectStoreName) => { + let store = new Store(objectStoreName) + const request = indexedDB.open(dbName, 2) + + request.onupgradeneeded = (event) => { + const db = event.target.result + const objectStore = db.createObjectStore(objectStoreName) + + objectStore.createIndex('value', 'value', { unique: false }) + } + + store.db = await promisify(request) + return store +} + +function promisify(request) { + return new Promise((resolve, reject) => { + request.onsuccess = (event) => { + resolve(request.result) + } + request.onerror = (event) => { + reject(request.error) + } + }) +} \ No newline at end of file diff --git a/src/browser/index.html b/src/browser/index.html index 2b39764..7b74182 100644 --- a/src/browser/index.html +++ b/src/browser/index.html @@ -9,6 +9,7 @@ + @@ -29,8 +30,12 @@ const client = new Client() client.install(document.body) -window.addEventListener('load', () => { - client.start() +window.addEventListener('load', () => { + Store.Open("lonin", "lonin") + .then(store => { + window.store = store + client.start() + }) }) diff --git a/test.png b/test.png new file mode 100644 index 0000000..2855abb Binary files /dev/null and b/test.png differ diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..f03ef67 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,63 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@napi-rs/canvas-android-arm64@0.1.52": + version "0.1.52" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.52.tgz#b0383c98d004e9f02ca71a8c2d68a49284b7f215" + integrity sha512-x/K471KbASPVh5mfBUxokza66J0FNIlOgMNANWAf5C8HiATb487KecEhSkUQvvTS3WLYC9uSqIPHFgwF+tir3w== + +"@napi-rs/canvas-darwin-arm64@0.1.52": + version "0.1.52" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.52.tgz#6f06e38d2ff12b4e8cb7dec593aa271d29cf41d5" + integrity sha512-4OgVRD7TW02q5Q7lWLLjT+pYJ9ZHkQUTBOuXbPQ5wB0Wnh3RIq/aMY6thoXDZDzdR5vV3a5TUtbZUJ0aqLq3NA== + +"@napi-rs/canvas-darwin-x64@0.1.52": + version "0.1.52" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.52.tgz#f3269e7dbda9f6f2f0245aae44df4a8ac9940574" + integrity sha512-3fgeGJ3j2X6Mtmn0QYf3iA+A6y1ePnsayakc2emEokzf03ErrPczONw3vjnTQo53JLPMzEnfPGAffdktU/ssPA== + +"@napi-rs/canvas-linux-arm-gnueabihf@0.1.52": + version "0.1.52" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.52.tgz#711d82f0d86d8d1570b4fd93bc0017490be552ff" + integrity sha512-aaDEEK5XwHUrPt0q4SR8l7Va0vtn50KmSs+itxP+o7RNk3Nuch8fINHOXyhMyhwNYgv1tfiJVyHsJhD0E6lXGA== + +"@napi-rs/canvas-linux-arm64-gnu@0.1.52": + version "0.1.52" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.52.tgz#fd59f5064cec550b01bd20e42e35886531dbd88a" + integrity sha512-tzuwM7Amt5mkrp4csQjYWkFzwFdiCm7RNdJ5usX8syzKSXmozqWzLHjzo/2ozdSQNUy6wyzRrxkG4Rh6g0OpOA== + +"@napi-rs/canvas-linux-arm64-musl@0.1.52": + version "0.1.52" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.52.tgz#cf097920b93c610c9b69305c7522d14cb2e970a3" + integrity sha512-HQCtJlDT0dFp3uUZVzZOZ1VLMO7lbLRc548MjMxPpojit2ZdGopFzJ8jDSr4iszHrTO1SM1AxPaCM3pRvCAtjw== + +"@napi-rs/canvas-linux-x64-gnu@0.1.52": + version "0.1.52" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.52.tgz#9a4e6b5d392d8f83477dbbb2067dc0e50785edbb" + integrity sha512-z5sBEw0PVWPH/MIQL8hOR8C3YYVlu8lqtRUcYajigMfXAhbMiNqDWTjuIWGMz3nIydDjZmn8KTxw/D4a0HFPqQ== + +"@napi-rs/canvas-linux-x64-musl@0.1.52": + version "0.1.52" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.52.tgz#10a035304876c8b75474c169208de29d05553165" + integrity sha512-G1+JdWFhHLyHhULJS51xTEhB7EL0ZiAUQwQaRi4/w75OOYDQ91O+o4miaxDHiV0hZuxBhHtZU6ftV2Zl3RMguw== + +"@napi-rs/canvas-win32-x64-msvc@0.1.52": + version "0.1.52" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.52.tgz#b9b4d71e8c06b65f838b6caf4e6c44b46fe5b16e" + integrity sha512-hMI626VsCC/wv29qHF78N7TSG+auatOp08DHln0Zdif5y1NJ14NU/rNUhzlTW8Zc6ssw+AMDJ3KKYYWYYg1aoA== + +"@napi-rs/canvas@^0.1.41": + version "0.1.52" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas/-/canvas-0.1.52.tgz#49c3a27c9243ffa5b21ba6368155aad6252e180c" + integrity sha512-xeW9EghZLDPZuqWJ4l1+eG3ld0i9J7SpV2zlgi34MPt/FE9K2XWGCfnLr0gHGOBkcI3YOVhI13I0HqRAkMPdVw== + optionalDependencies: + "@napi-rs/canvas-android-arm64" "0.1.52" + "@napi-rs/canvas-darwin-arm64" "0.1.52" + "@napi-rs/canvas-darwin-x64" "0.1.52" + "@napi-rs/canvas-linux-arm-gnueabihf" "0.1.52" + "@napi-rs/canvas-linux-arm64-gnu" "0.1.52" + "@napi-rs/canvas-linux-arm64-musl" "0.1.52" + "@napi-rs/canvas-linux-x64-gnu" "0.1.52" + "@napi-rs/canvas-linux-x64-musl" "0.1.52" + "@napi-rs/canvas-win32-x64-msvc" "0.1.52"