diff --git a/.github/workflows/integrate.yml b/.github/workflows/integrate.yml
index dde5de7..ed64761 100644
--- a/.github/workflows/integrate.yml
+++ b/.github/workflows/integrate.yml
@@ -1,4 +1,4 @@
-name: Build Test
+name: build
on:
push:
@@ -9,7 +9,7 @@ on:
branches: [ main ]
jobs:
- test_pull_request:
+ test_build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
diff --git a/README.md b/README.md
index cd8be59..3f6e192 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,17 @@
+# DEV NOTE:
+
+Hey! It's been a long while since I last updated Random Browser. It's currently December 23th 2023, v2.0.0 is finally out, or at least, it'll be soon.
+
+Since the first line of code, Random Browser was just an experiment and I didn't even plan to update it...
+
+But here we are, Random Browser's last release is out.
+
+This version of Random Browser won't receive new features, just small bug fixes (if any).
+
+Note how I said "this version", though. I've been planning to migrate the entire projet to a different framework or programming language.
+
+We'll see...
+
Random Browser
@@ -40,7 +54,7 @@ Once everything is installed, build the typescript code:
```bash
yarn build
```
-**NOTE: typescript is not listed as a dependency in package.json. It should be installed globally on your computer, if not, you can install it globally or in the cloned repository.**
+
And **you're done**! Now run:
```bash
@@ -75,7 +89,6 @@ Once everything is installed, build the typescript code:
```bash
yarn build
```
-**NOTE: typescript is not listed as a dependency in package.json. It should be installed globally on your computer, if not, you can install it globally or in the cloned repository.**
Now, you have to run the project from the command line before packaging, just run:
@@ -87,7 +100,7 @@ When you do that, the public folder (where all resources for views are) will be
> If something goes wrong, you can copy the folder manually. Just copy **./src/public/** to **./build/**
-Once this is done and the browser's window is now open, you can close the browser and finally package the app:
+Once this is done and the browser's window is open, you can close the browser and finally package the app:
For Windows:
```bash
@@ -107,10 +120,10 @@ yarn pack-mac
When that's finished, you should see a folder named **dist**, inside of it you can find executable.
## Contributing setup
-Sorry, this setup is not documented yet and neither is the project's code. You can follow the [development setup](#development-setup), just make sure to follow these rules:
+> **** Currently the project's code is not so well documented as I'd like. I'll be working on documenting everything better so contributors can more easily understand what the code is doing. If you'd like to contribute, I'm glad having your help on this project, just know that it may be a little confusing for now.
-- **USE** Yarn
-- Make sure to exclude any file that shouldn't be uploaded to github.
+
+Before you can get to contributing, please read the `contributing` file.
# License
Random Browser by YisusGaming is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
diff --git a/changelog.txt b/changelog.txt
new file mode 100644
index 0000000..be0130d
--- /dev/null
+++ b/changelog.txt
@@ -0,0 +1,12 @@
+[2.0.0] => {
+ Features => {
+ [DONE] Custom App Frame.
+ [DONE] New Tab System.
+ [DONE] Initial App Loader.
+ [DONE] Download Progress Bar.
+ [DELAYED->v3.0.0] New Settings Menu.
+ }
+ Fixes => {
+ [DONE] Fixed Random Browser's Page Link.
+ }
+}
diff --git a/package.json b/package.json
index 95f2be6..5af8913 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"private": true,
"name": "random-browser",
"productName": "Random Browser",
- "version": "1.2.2",
+ "version": "2.0.0",
"description": "Just a random browser...",
"main": "build/index.js",
"scripts": {
@@ -10,9 +10,7 @@
"build": "tsc",
"start:dev": "nodemon build/index.js",
"build:dev": "tsc -w",
- "pack-mac": "electron-packager . --overwrite --platform=darwin --arch=x64 --icon=assets/icons/icon.icns --prune=true --out=dist",
- "pack-win": "electron-packager . random-browser --overwrite --asar=false --platform=win32 --arch=ia32 --icon=assets/icons/icon.ico --prune=true --out=dist --version-string.CompanyName=YisusGaming --version-string.FileDescription=\"Just a random browser...\" --version-string.ProductName=\"Random Browser\"",
- "pack-linux": "electron-packager . random-browser --overwrite --asar=false --platform=linux --arch=x64 --icon=assets/icons/1024x1024.png --prune=true --out=dist"
+ "pack-win": "electron-packager . random-browser --overwrite --asar=false --platform=win32 --arch=ia32 --icon=assets/icons/icon.ico --prune=true --out=dist --version-string.CompanyName=YisusGaming --version-string.FileDescription=\"Just a random browser...\" --version-string.ProductName=\"Random Browser\""
},
"repository": "https://github.com/YisusGaming/random-browser",
"author": "YisusGaming",
@@ -22,6 +20,7 @@
},
"devDependencies": {
"electron-packager": "^17.1.1",
- "nodemon": "^2.0.20"
+ "nodemon": "^2.0.20",
+ "typescript": "^4.9.5"
}
}
diff --git a/src/config/app.json b/src/config/app.json
index 11f88d2..63cb415 100644
--- a/src/config/app.json
+++ b/src/config/app.json
@@ -1,3 +1,3 @@
{
- "version": "v1.2.2"
+ "version": "v2.0.0"
}
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
index d189c6e..79890e0 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,68 +1,100 @@
-import { app, BrowserWindow, ipcMain, Menu, MenuItemConstructorOptions } from 'electron';
+import { app, BrowserWindow, ipcMain, Menu } from 'electron';
+import Logger from './logs/Logger.js';
+import TabManager from './tabs/TabManager.js';
import configs from './config/app.json';
import './config/user.json';
import fs from 'fs';
import path from 'path';
-const publicPath = path.join(__dirname, 'public');
+// Instance of the logger class for future console logs.
+// Also exports the instance for use in other files
+// without the need to reinstance the class again.
+export const logger = new Logger(configs.version);
+
+export const publicPath = path.join(__dirname, 'public');
const userConfigPath = path.join(__dirname, 'config', 'user.json');
-console.log(`Looking for user's configs in ${userConfigPath}`);
+// console.log(`Looking for user's configs in ${userConfigPath}`);
+logger.logMessage(`Looking for user's configs in ${userConfigPath}`);
let main : BrowserWindow;
-let searchWin : BrowserWindow;
+let tabModal : BrowserWindow;
let backgroundSelect : BrowserWindow;
+let appLoader : BrowserWindow;
app.on('ready', () => {
+ logger.logMessage(`App is ready.`);
+ spawnAppLoader();
main = new BrowserWindow({
title: 'Random Browser - Loading...',
webPreferences: {
nodeIntegration: true,
contextIsolation: false
},
+ frame: false,
show: false
});
+ // ! Make sure to set the application menu to null in production.
Menu.setApplicationMenu(null);
main.loadFile(path.join(publicPath, 'index.html'));
main.on('ready-to-show', () => {
+ logger.logMessage(`Main window ready to show.`);
main.show();
- main.maximize();
+ // ! Make sure to destoy appLoader in production.
+ appLoader.destroy();
const rawConfig = fs.readFileSync(userConfigPath, { encoding: 'utf-8' });
const configs = JSON.parse(rawConfig);
main.webContents.send('update-background', configs.background);
});
- main.on('close', () => {
- if (backgroundSelect != null) {
- try {
- backgroundSelect.close();
- } catch(err) {
- console.log(`[FAILED] close background select window [->] ${err}.`);
- }
- }
- });
});
-function searchWindow(url: string) {
- searchWin = new BrowserWindow({
- title: `Searching ${url}...`,
- minimizable: false
- });
- searchWin.loadURL(url);
+/**
+ * Works as a *bridge* or *gateway* that allows communication with main's webCotents.
+ * @param event The event that will be send to main via `webContents.send`
+ *
+ * @throws {EvalError} if the string passed as event is empty.
+ */
+export function mainWindowGateway(event: string, ...args: any[]): void {
+ logger.tempLogMessage(`Main Gateway used, event: ${event}`);
+ if (event.trim() == '') throw new EvalError("Event cannot be empty.");
+
+ main.webContents.send(event, args);
+}
- const menuTemplate: Array = [
- {
- label: 'Refresh',
- role: 'reload'
+function spawnAppLoader() {
+ logger.logMessage("App loader spawned.");
+ appLoader = new BrowserWindow({
+ webPreferences: {
+ nodeIntegration: true,
+ contextIsolation: false
},
- {
- label: 'Inspect',
- role: 'toggleDevTools'
- }
- ]
+ title: 'Random Browser - Loading...',
+ frame: false,
+ closable: false,
+ maximizable: false,
+ resizable: false,
+ height: 400,
+ width: 320
+ });
+ appLoader.loadFile(path.join(publicPath, 'loader.html'));
+ appLoader.on('closed', () => {
+ logger.logMessage("App loader closed.");
+ main.flashFrame(true);
+ });
+}
- searchWin.setMenu(Menu.buildFromTemplate(menuTemplate));
+/**
+ * Createsa a Tab and builds it.
+ * Tabs will show up once they're built.
+ */
+export function spawnTab(url: string) {
+ tabModal = TabManager.createTab(url, main).build();
}
+/**
+ * Spawns a Browser Window for the user to select a custom
+ * background.
+ */
function selectBackground() {
backgroundSelect = new BrowserWindow({
title: "Change Browser's Background",
@@ -71,26 +103,49 @@ function selectBackground() {
contextIsolation: false
},
minimizable: false,
- maximizable: false
+ maximizable: false,
+ parent: main
});
backgroundSelect.setMenu(null);
backgroundSelect.loadFile(path.join(publicPath, 'background.html'));
}
-/* IPC */
+ipcMain.on('minimize-main', (event) => {
+ // Minimize the main window
+ main.minimize();
+});
+
+ipcMain.on('maximize-main', (event) => {
+ // Maximize the main window
+ main.maximize();
+});
+
+ipcMain.on('close-main', (event) => {
+ // Close the main window
+ main.close();
+});
+
+ipcMain.on('open-tab', (event, tabId: number) => {
+ TabManager.openTab(tabId);
+});
+
+ipcMain.on('tab-deleted', (event, tabId: number) => {
+ TabManager.deleteTab(tabId);
+});
+
ipcMain.on('new-search', (event, search: string) => {
if (search.trim() == '') return;
if (/[*.*]/g.test(search)) {
if (search.startsWith('https://') || search.startsWith('http://')) {
- searchWindow(search);
+ spawnTab(search);
return;
}
- searchWindow(`https://${search}`);
+ spawnTab(`https://${search}`);
return;
}
- searchWindow(`https://google.com/search?q=${search}`);
+ spawnTab(`https://google.com/search?q=${search}`);
});
ipcMain.on('new-background-image', (event) => {
@@ -126,4 +181,8 @@ ipcMain.on('clear-background', (event) => {
backgroundSelect.close();
main.webContents.send('update-background', '');
main.loadFile(path.join(publicPath, 'index.html'));
-});
\ No newline at end of file
+});
+
+ipcMain.on('minimize-apploader', (event) => {
+ appLoader.minimize();
+});
diff --git a/src/logs/Logger.ts b/src/logs/Logger.ts
new file mode 100644
index 0000000..aebc4a7
--- /dev/null
+++ b/src/logs/Logger.ts
@@ -0,0 +1,54 @@
+/**
+ * The logger class.
+ * @since v2.0.0
+ *
+ * Prints messages to `stdout` and `stderr`.
+ */
+export default class Logger {
+ private browserVersion: string;
+
+ /**
+ * @param browserVersion Random Browser's current version allocated in `app.json`
+ */
+ constructor(browserVersion: string) {
+ this.browserVersion = browserVersion;
+ }
+
+ /**
+ * Prints a message to the `stdout`.
+ */
+ logMessage(msg: string): void {
+ console.log(`[LOG:${this.browserVersion}] => ${msg}`);
+ }
+
+ /**
+ * Prints a message to the `stdout` with a label
+ * saying it should be removed before the app
+ * gets to production.
+ */
+ tempLogMessage(msg: string): void {
+ console.log(`The following log is temporal and should be removed before production.\n[TEMPORAL LOG:${this.browserVersion}] => ${msg}`);
+ }
+
+ /**
+ * Prints a warning to the `stderr`.
+ */
+ logWarning(warn: string): void {
+ console.warn(`[WARNING!] => ${warn} | ${this.browserVersion}`);
+ }
+
+ /**
+ * Prints an `string` or an `Error` to `stderr`.
+ */
+ logError(err: string | Error, origin: { file: string }): void {
+ if (typeof err == 'string') {
+ console.error(
+ `[ERR!] => ${err} | ${this.browserVersion} [${origin.file}]`
+ );
+ } else {
+ console.error(
+ `[ERR!] => ${err.name}: ${err.message} | ${this.browserVersion} [${origin.file}]`
+ );
+ }
+ }
+}
diff --git a/src/public/assets/icon/icon.ico b/src/public/assets/icon/icon.ico
new file mode 100644
index 0000000..874fbbd
Binary files /dev/null and b/src/public/assets/icon/icon.ico differ
diff --git a/src/public/css/download.css b/src/public/css/download.css
new file mode 100644
index 0000000..6dc8084
--- /dev/null
+++ b/src/public/css/download.css
@@ -0,0 +1,78 @@
+@import url('https://fonts.googleapis.com/css2?family=Raleway:wght@100;200;300;400;500;600;700&display=swap');
+
+* {
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ position: relative;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ font-family: 'Raleway', sans-serif;
+ background: #202020;
+ color: #ffffff;
+}
+
+.frame {
+ padding: 20px;
+ border: #303030 2px solid;
+ border-radius: 8px;
+}
+
+#download-info {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ text-align: center;
+ align-items: center;
+ margin-bottom: 10px;
+}
+
+.btns {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+button {
+ background: transparent;
+ color: #ffffff;
+ padding: 8px;
+ margin: 0 4px;
+ border-radius: 8px;
+ border: #ffffff 2px solid;
+ cursor: pointer;
+ transition: 250ms;
+}
+
+button#btn-resume {
+ border-color: #101060;
+}
+
+button#btn-resume:hover {
+ background: #101060;
+}
+
+button#btn-pause {
+ border-color: #dddd00;
+}
+
+button#btn-pause:hover {
+ background: #dddd00;
+}
+
+button#btn-cancel {
+ border-color: #dd0020;
+}
+
+button#btn-cancel:hover {
+ background: #dd0020;
+}
+
+button:disabled {
+ cursor: not-allowed;
+ opacity: .7;
+}
diff --git a/src/public/css/index.css b/src/public/css/index.css
index 83943b1..14936cf 100644
--- a/src/public/css/index.css
+++ b/src/public/css/index.css
@@ -24,6 +24,92 @@ body:has(:focus) {
height: 100vh;
}
+#tabs-container {
+ -webkit-app-region: no-drag;
+ display: flex;
+ flex-direction: row;
+ grid-area: tabs;
+ width: 70%;
+ overflow-x: scroll;
+}
+
+#tabs-container::-webkit-scrollbar {
+ height: 4px;
+}
+
+#tabs-container::-webkit-scrollbar-thumb {
+ background: white;
+}
+
+.tab {
+ -webkit-app-region: no-drag;
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+ padding: 10px;
+ max-width: 100px;
+ margin: 0 4px;
+ background: #202020;
+ transition: 250ms;
+}
+
+.tab p {
+ cursor: pointer;
+ font-family: 'Raleway', sans-serif;
+}
+
+.tab:has(p:hover) {
+ background: #505050;
+}
+
+.tab button {
+ background: transparent;
+ border: none;
+ color: white;
+ cursor: pointer;
+}
+
+.tab button:hover {
+ color: lightcoral;
+}
+
+.tab button:active {
+ color: red;
+}
+
+.frame {
+ position: fixed;
+ -webkit-app-region: drag;
+ width: 100vw;
+ display: grid;
+ grid-template-columns: 1fr auto;
+ grid-template-areas:
+ "tabs buttons";
+ background: #101010;
+ padding: 8px 0;
+}
+
+.frame #buttons {
+ padding: 0 6px;
+ margin: auto;
+ grid-area: buttons;
+}
+
+.frame #buttons button {
+ font-size: 1.6rem;
+ cursor: pointer;
+ background: transparent;
+ color: #606060;
+ border: none;
+ margin: 0 4px;
+ -webkit-app-region: no-drag;
+ transition: 250ms all;
+}
+
+.frame #buttons button:hover {
+ color: #ffffff;
+}
+
#legend {
font-family: 'Raleway', sans-serif;
font-size: 2.8rem;
@@ -102,31 +188,9 @@ body:has(:focus) {
padding: 5px;
}
-#about-btn {
- position: absolute;
- top: 0;
- left: 0;
- font-size: 2.3rem;
- background: transparent;
- color: #707070;
- text-decoration: none;
- padding: 10px;
- border: none;
- transform-origin: center;
- transition: all 250ms;
-}
-
-#about-btn:hover {
- color: #ffffff;
-}
-
-#about-btn:active {
- color: #000000;
-}
-
#background-btn {
position: absolute;
- top: 0;
+ top: 40px;
right: 0;
font-size: 2.3rem;
background: transparent;
diff --git a/src/public/css/loader.css b/src/public/css/loader.css
new file mode 100644
index 0000000..c046089
--- /dev/null
+++ b/src/public/css/loader.css
@@ -0,0 +1,47 @@
+@import url('https://fonts.googleapis.com/css2?family=Raleway:wght@100;200;300;400;500;600;700&display=swap');
+
+* {
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ position: relative;
+ height: 100vh;
+ width: 100vw;
+ -webkit-app-region: drag;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ font-family: 'Raleway', sans-serif;
+ background: #202020;
+ color: #ffffff;
+}
+
+.button-wrap {
+ position: fixed;
+ padding: 5px;
+ top: 0;
+ left: 0;
+}
+
+.button-wrap button {
+ -webkit-app-region: no-drag;
+ background-color: transparent;
+ color: white;
+ border: 2px solid #505050;
+ padding: 6px;
+ cursor: pointer;
+ transition: 250ms;
+}
+
+.button-wrap button:hover {
+ background: #505050;
+}
+
+img,
+h1,
+p {
+ -webkit-app-region: no-drag;
+}
\ No newline at end of file
diff --git a/src/public/css/user.css b/src/public/css/user.css
deleted file mode 100644
index e69de29..0000000
diff --git a/src/public/download.html b/src/public/download.html
new file mode 100644
index 0000000..655b473
--- /dev/null
+++ b/src/public/download.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+ Downloading...
+
+
+
+