worldwideweb 0.0.20 → 0.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,291 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { app, BrowserWindow, Menu, ipcMain, session } = require('electron')
4
+ const path = require('path')
5
+
6
+ let mainWindow
7
+
8
+ function createWindow() {
9
+ mainWindow = new BrowserWindow({
10
+ width: 1200,
11
+ height: 800,
12
+ webPreferences: {
13
+ nodeIntegration: false,
14
+ contextIsolation: true,
15
+ preload: path.join(__dirname, 'preload.js')
16
+ },
17
+ titleBarStyle: 'hidden',
18
+ titleBarOverlay: {
19
+ color: '#16213e',
20
+ symbolColor: '#eee',
21
+ height: 40
22
+ }
23
+ })
24
+
25
+ // Load the jsonos browser shell
26
+ mainWindow.loadFile(path.join(__dirname, 'browser.html'))
27
+
28
+ // Set up content type handling for RDF/JSON-LD
29
+ session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
30
+ const contentType = details.responseHeaders['content-type'] ||
31
+ details.responseHeaders['Content-Type'] || []
32
+
33
+ // Log content types for debugging
34
+ if (contentType.some(ct => ct.includes('turtle') || ct.includes('json'))) {
35
+ console.log(`[jsonos] Content-Type: ${contentType} for ${details.url}`)
36
+ }
37
+
38
+ callback({ responseHeaders: details.responseHeaders })
39
+ })
40
+
41
+ const mainMenu = Menu.buildFromTemplate(menuTemplate)
42
+ Menu.setApplicationMenu(mainMenu)
43
+ }
44
+
45
+ const menuTemplate = [
46
+ {
47
+ label: 'File',
48
+ submenu: [
49
+ {
50
+ label: 'New Window',
51
+ accelerator: 'CmdOrCtrl+N',
52
+ click() {
53
+ createWindow()
54
+ }
55
+ },
56
+ {
57
+ label: 'Open Location',
58
+ accelerator: 'CmdOrCtrl+L',
59
+ click(item, focusedWindow) {
60
+ if (focusedWindow) {
61
+ focusedWindow.webContents.executeJavaScript(`
62
+ document.getElementById('url-bar').focus();
63
+ document.getElementById('url-bar').select();
64
+ `)
65
+ }
66
+ }
67
+ },
68
+ { type: 'separator' },
69
+ {
70
+ label: 'Exit',
71
+ accelerator: 'CmdOrCtrl+Q',
72
+ click() {
73
+ app.quit()
74
+ }
75
+ }
76
+ ]
77
+ },
78
+ {
79
+ label: 'Edit',
80
+ submenu: [
81
+ { role: 'undo' },
82
+ { role: 'redo' },
83
+ { type: 'separator' },
84
+ { role: 'cut' },
85
+ { role: 'copy' },
86
+ { role: 'paste' },
87
+ { role: 'selectAll' }
88
+ ]
89
+ },
90
+ {
91
+ label: 'View',
92
+ submenu: [
93
+ {
94
+ label: 'Rendered View',
95
+ accelerator: 'CmdOrCtrl+1',
96
+ click(item, focusedWindow) {
97
+ if (focusedWindow) {
98
+ focusedWindow.webContents.executeJavaScript(`
99
+ document.querySelector('[data-view="rendered"]').click();
100
+ `)
101
+ }
102
+ }
103
+ },
104
+ {
105
+ label: 'Raw JSON',
106
+ accelerator: 'CmdOrCtrl+2',
107
+ click(item, focusedWindow) {
108
+ if (focusedWindow) {
109
+ focusedWindow.webContents.executeJavaScript(`
110
+ document.querySelector('[data-view="raw"]').click();
111
+ `)
112
+ }
113
+ }
114
+ },
115
+ {
116
+ label: 'Custom View',
117
+ accelerator: 'CmdOrCtrl+3',
118
+ click(item, focusedWindow) {
119
+ if (focusedWindow) {
120
+ focusedWindow.webContents.executeJavaScript(`
121
+ document.querySelector('[data-view="custom"]').click();
122
+ `)
123
+ }
124
+ }
125
+ },
126
+ { type: 'separator' },
127
+ {
128
+ label: 'Toggle Edit Mode',
129
+ accelerator: 'CmdOrCtrl+E',
130
+ click(item, focusedWindow) {
131
+ if (focusedWindow) {
132
+ focusedWindow.webContents.executeJavaScript(`
133
+ jsonos.toggleEditMode();
134
+ `)
135
+ }
136
+ }
137
+ },
138
+ { type: 'separator' },
139
+ { role: 'toggleDevTools' },
140
+ { role: 'togglefullscreen' }
141
+ ]
142
+ },
143
+ {
144
+ label: 'Navigate',
145
+ submenu: [
146
+ {
147
+ label: 'Back',
148
+ accelerator: 'CmdOrCtrl+[',
149
+ click(item, focusedWindow) {
150
+ if (focusedWindow) {
151
+ focusedWindow.webContents.executeJavaScript('jsonos.goBack()')
152
+ }
153
+ }
154
+ },
155
+ {
156
+ label: 'Forward',
157
+ accelerator: 'CmdOrCtrl+]',
158
+ click(item, focusedWindow) {
159
+ if (focusedWindow) {
160
+ focusedWindow.webContents.executeJavaScript('jsonos.goForward()')
161
+ }
162
+ }
163
+ },
164
+ {
165
+ label: 'Reload',
166
+ accelerator: 'CmdOrCtrl+R',
167
+ click(item, focusedWindow) {
168
+ if (focusedWindow) {
169
+ focusedWindow.webContents.executeJavaScript(`
170
+ if (jsonos.currentData && jsonos.currentData['@id']) {
171
+ LION.cache.delete(jsonos.currentData['@id']);
172
+ jsonos.navigateWithoutHistory(jsonos.currentData['@id']);
173
+ }
174
+ `)
175
+ }
176
+ }
177
+ },
178
+ { type: 'separator' },
179
+ {
180
+ label: 'Home',
181
+ accelerator: 'CmdOrCtrl+H',
182
+ click(item, focusedWindow) {
183
+ if (focusedWindow) {
184
+ focusedWindow.webContents.executeJavaScript(`
185
+ jsonos.navigate('https://jsonos.com/');
186
+ `)
187
+ }
188
+ }
189
+ }
190
+ ]
191
+ },
192
+ {
193
+ label: 'Solid',
194
+ submenu: [
195
+ {
196
+ label: 'Login...',
197
+ accelerator: 'CmdOrCtrl+Shift+L',
198
+ click(item, focusedWindow) {
199
+ if (focusedWindow) {
200
+ focusedWindow.webContents.executeJavaScript(`
201
+ document.getElementById('auth-status').click();
202
+ `)
203
+ }
204
+ }
205
+ },
206
+ {
207
+ label: 'My Pod',
208
+ click(item, focusedWindow) {
209
+ // TODO: Navigate to user's pod
210
+ }
211
+ }
212
+ ]
213
+ },
214
+ {
215
+ label: 'Help',
216
+ submenu: [
217
+ {
218
+ label: 'About WorldWideWeb',
219
+ click() {
220
+ const { dialog } = require('electron')
221
+ dialog.showMessageBox({
222
+ type: 'info',
223
+ title: 'About WorldWideWeb',
224
+ message: 'WorldWideWeb - jsonos Edition',
225
+ detail: 'A browser for the decentralized web.\n\n' +
226
+ 'Built with:\n' +
227
+ '• LION (Linked Objects Notation)\n' +
228
+ '• jsonos runtime\n' +
229
+ '• Solid Protocol\n\n' +
230
+ 'Inspired by Tim Berners-Lee\'s original WorldWideWeb browser.'
231
+ })
232
+ }
233
+ },
234
+ {
235
+ label: 'Learn about Solid',
236
+ click() {
237
+ require('electron').shell.openExternal('https://solidproject.org/')
238
+ }
239
+ },
240
+ {
241
+ label: 'Learn about LION',
242
+ click() {
243
+ require('electron').shell.openExternal('https://linkedobjects.org/')
244
+ }
245
+ },
246
+ {
247
+ label: 'Learn about jsonos',
248
+ click() {
249
+ require('electron').shell.openExternal('https://jsonos.com/')
250
+ }
251
+ }
252
+ ]
253
+ }
254
+ ]
255
+
256
+ // macOS specific menu adjustments
257
+ if (process.platform === 'darwin') {
258
+ menuTemplate.unshift({
259
+ label: app.getName(),
260
+ submenu: [
261
+ { role: 'about' },
262
+ { type: 'separator' },
263
+ { role: 'services' },
264
+ { type: 'separator' },
265
+ { role: 'hide' },
266
+ { role: 'hideOthers' },
267
+ { role: 'unhide' },
268
+ { type: 'separator' },
269
+ { role: 'quit' }
270
+ ]
271
+ })
272
+ }
273
+
274
+ app.whenReady().then(createWindow)
275
+
276
+ app.on('window-all-closed', () => {
277
+ if (process.platform !== 'darwin') {
278
+ app.quit()
279
+ }
280
+ })
281
+
282
+ app.on('activate', () => {
283
+ if (BrowserWindow.getAllWindows().length === 0) {
284
+ createWindow()
285
+ }
286
+ })
287
+
288
+ // Handle IPC messages from renderer
289
+ ipcMain.handle('get-app-version', () => {
290
+ return app.getVersion()
291
+ })
@@ -0,0 +1,14 @@
1
+ const { contextBridge, ipcRenderer } = require('electron')
2
+
3
+ // Expose protected methods to renderer
4
+ contextBridge.exposeInMainWorld('electronAPI', {
5
+ getAppVersion: () => ipcRenderer.invoke('get-app-version'),
6
+
7
+ // Platform info
8
+ platform: process.platform,
9
+
10
+ // Solid authentication helpers (to be expanded)
11
+ solid: {
12
+ // Will be populated with Solid auth methods
13
+ }
14
+ })
Binary file
Binary file
package/main.js ADDED
@@ -0,0 +1,168 @@
1
+ import { app, BrowserWindow, Menu } from 'electron';
2
+ import { createServer } from 'javascript-solid-server/src/server.js';
3
+ import { readFileSync } from 'fs';
4
+ import { join, dirname } from 'path';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+
9
+ // Address bar CSS - inspired by solid-docs browser
10
+ const ADDRESS_BAR_CSS = `
11
+ #worldwideweb-nav {
12
+ display: flex;
13
+ align-items: center;
14
+ gap: 12px;
15
+ padding: 12px 20px;
16
+ background: linear-gradient(135deg, #7C3AED 0%, #2563EB 100%);
17
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
18
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
19
+ }
20
+ #worldwideweb-nav label {
21
+ color: rgba(255, 255, 255, 0.9);
22
+ font-size: 14px;
23
+ font-weight: 500;
24
+ }
25
+ #worldwideweb-uri {
26
+ flex: 1;
27
+ min-width: 280px;
28
+ padding: 10px 16px;
29
+ font-size: 14px;
30
+ background: rgba(255, 255, 255, 0.15);
31
+ border: 1px solid rgba(255, 255, 255, 0.3);
32
+ border-radius: 8px;
33
+ color: white;
34
+ outline: none;
35
+ transition: all 0.2s ease;
36
+ }
37
+ #worldwideweb-uri::placeholder {
38
+ color: rgba(255, 255, 255, 0.6);
39
+ }
40
+ #worldwideweb-uri:focus {
41
+ background: rgba(255, 255, 255, 0.25);
42
+ border-color: rgba(255, 255, 255, 0.5);
43
+ }
44
+ #worldwideweb-go {
45
+ padding: 10px 20px;
46
+ background: white;
47
+ color: #7C3AED;
48
+ border: none;
49
+ border-radius: 8px;
50
+ cursor: pointer;
51
+ font-weight: 600;
52
+ font-size: 14px;
53
+ transition: all 0.2s ease;
54
+ }
55
+ #worldwideweb-go:hover {
56
+ background: #f8f8f8;
57
+ transform: translateY(-1px);
58
+ }
59
+ `;
60
+
61
+ // Load config
62
+ let config = { port: 3012, width: 1200, height: 800 };
63
+ try {
64
+ config = JSON.parse(readFileSync(join(__dirname, 'config.json'), 'utf8'));
65
+ } catch (e) {
66
+ console.log('Using default config');
67
+ }
68
+
69
+ const PORT = config.port || 3012;
70
+ let mainWindow;
71
+ let server;
72
+
73
+ async function startJSS() {
74
+ server = createServer({
75
+ mashlib: true,
76
+ mashlibCdn: false,
77
+ root: config.root || join(__dirname, 'data'),
78
+ logger: false
79
+ });
80
+
81
+ await server.listen({ port: PORT, host: 'localhost' });
82
+ console.log(`JSS running at http://localhost:${PORT}`);
83
+ }
84
+
85
+ function createWindow() {
86
+ mainWindow = new BrowserWindow({
87
+ width: config.width || 1200,
88
+ height: config.height || 800,
89
+ webPreferences: {
90
+ nodeIntegration: false,
91
+ contextIsolation: true
92
+ }
93
+ });
94
+
95
+ // Simple menu
96
+ const menu = Menu.buildFromTemplate([
97
+ {
98
+ label: 'WorldWideWeb',
99
+ submenu: [
100
+ { label: 'Home', click: () => mainWindow.loadURL(`http://localhost:${PORT}/`) },
101
+ { type: 'separator' },
102
+ { label: 'Reload', accelerator: 'CmdOrCtrl+R', click: () => mainWindow.reload() },
103
+ { label: 'DevTools', accelerator: 'F12', click: () => mainWindow.webContents.toggleDevTools() },
104
+ { type: 'separator' },
105
+ { label: 'Quit', accelerator: 'CmdOrCtrl+Q', click: () => app.quit() }
106
+ ]
107
+ }
108
+ ]);
109
+ Menu.setApplicationMenu(menu);
110
+
111
+ mainWindow.loadURL(`http://localhost:${PORT}/`);
112
+
113
+ // Inject address bar
114
+ const DEFAULT_URI = 'https://timbl.solidcommunity.net/profile/card#me';
115
+
116
+ mainWindow.webContents.on('did-finish-load', () => {
117
+ mainWindow.webContents.insertCSS(ADDRESS_BAR_CSS);
118
+ mainWindow.webContents.executeJavaScript(`
119
+ if (!document.getElementById('worldwideweb-nav')) {
120
+ const nav = document.createElement('div');
121
+ nav.id = 'worldwideweb-nav';
122
+ nav.innerHTML = \`
123
+ <label>Visiting</label>
124
+ <input type="text" id="worldwideweb-uri" placeholder="Enter a Solid URI..." value="${DEFAULT_URI}" />
125
+ <button id="worldwideweb-go">Go</button>
126
+ \`;
127
+ document.body.insertBefore(nav, document.body.firstChild);
128
+
129
+ const uriInput = document.getElementById('worldwideweb-uri');
130
+ const goBtn = document.getElementById('worldwideweb-go');
131
+
132
+ goBtn.addEventListener('click', () => {
133
+ window.location.href = uriInput.value;
134
+ });
135
+
136
+ uriInput.addEventListener('keyup', (e) => {
137
+ if (e.key === 'Enter') window.location.href = uriInput.value;
138
+ });
139
+
140
+ // Auto-navigate to default URI on first load
141
+ if (window.location.href.endsWith(':${PORT}/') || window.location.href.endsWith(':${PORT}')) {
142
+ setTimeout(() => {
143
+ window.location.href = '${DEFAULT_URI}';
144
+ }, 500);
145
+ }
146
+ }
147
+ `);
148
+ });
149
+
150
+ mainWindow.on('closed', () => { mainWindow = null; });
151
+ }
152
+
153
+ app.whenReady().then(async () => {
154
+ await startJSS();
155
+ createWindow();
156
+ });
157
+
158
+ app.on('window-all-closed', () => {
159
+ if (process.platform !== 'darwin') app.quit();
160
+ });
161
+
162
+ app.on('activate', () => {
163
+ if (mainWindow === null) createWindow();
164
+ });
165
+
166
+ app.on('before-quit', async () => {
167
+ if (server) await server.close();
168
+ });
package/package.json CHANGED
@@ -1,35 +1,29 @@
1
1
  {
2
2
  "name": "worldwideweb",
3
- "version": "0.0.20",
4
- "description": "WorldWideWeb browser in JavaScript",
5
- "main": "main.cjs",
3
+ "version": "0.0.21",
4
+ "description": "WorldWideWeb browser in JavaScript - JSS + mashlib in Electron",
5
+ "main": "main.js",
6
+ "bin": {
7
+ "worldwideweb": "./bin/worldwideweb.js"
8
+ },
9
+ "type": "module",
6
10
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1",
8
- "build": "electron .",
9
11
  "start": "electron ."
10
12
  },
11
- "bin": {
12
- "worldwideweb": "./run.js"
13
- },
14
13
  "repository": {
15
14
  "type": "git",
16
15
  "url": "git+https://github.com/melvincarvalho/worldwideweb.git"
17
16
  },
18
- "keywords": [
19
- "WorldWideWeb",
20
- "Solid"
21
- ],
17
+ "keywords": ["WorldWideWeb", "Solid", "browser", "jss", "mashlib", "electron"],
22
18
  "author": "Melvin Carvalho <melvincarvalho@gmail.com> (https://melvincarvalho.com/#me)",
23
19
  "license": "MIT",
24
20
  "bugs": {
25
21
  "url": "https://github.com/melvincarvalho/worldwideweb/issues"
26
22
  },
27
23
  "homepage": "https://github.com/melvincarvalho/worldwideweb#readme",
28
- "devDependencies": {
29
- "electron": "^24.2.0"
30
- },
31
24
  "dependencies": {
32
- "path": "^0.12.7",
33
- "url": "^0.11.0"
25
+ "electron": "^28.0.0",
26
+ "javascript-solid-server": "^0.0.81",
27
+ "mashlib-jss": "^0.1.1"
34
28
  }
35
29
  }