60 Commits
0.1 ... master

Author SHA1 Message Date
Abdelrhman Nile
97a194d962 Update README.md 2021-11-12 06:50:17 +00:00
AbdelrhmanNile
53d8f1f6b3 fixing some colors 2021-11-12 08:45:23 +02:00
Abdelrhman Nile
246a28e493 Update README.md 2021-11-10 18:37:22 +00:00
AbdelrhmanNile
6ca2898a50 README 2021-11-10 20:35:24 +02:00
AbdelrhmanNile
05df302ecd README 2021-11-10 20:29:51 +02:00
AbdelrhmanNile
26320c5909 changing color palette to onedark, replacing bing with brave search engine, changing timezone and weather location 2021-11-10 20:18:01 +02:00
Deepjyoti Barman
8cad9b0d21 Add theming ability for various aspects of the startpage
Add support for theming varisou aspects of the page all from the
config.

Thanks to @benjih for the PR.
2021-04-24 19:27:31 +05:30
Deepjyoti Barman
3661f92c15 Remove an unnecessary value in config 2021-04-24 18:57:14 +05:30
Deepjyoti Barman
a12b03ad6b Add function to update the autocomplete highlight color 2021-04-24 18:33:02 +05:30
Benji Hooper
94894c7e6f Include additional configuration for the line divider and the weather 2021-04-16 22:33:07 +01:00
Benji Hooper
8b7e59ca50 Make some background colors and text colors configurable through new style configuration object 2021-04-16 17:51:17 +01:00
Deepjyoti Barman
dc818bd2b5 Add styling for the title if it will be a link as well
The title in the cards are now optionally clickable. If the `url`
attribute is passed to the square in the config then the title will be
clickable and will open that particular `url`.

If not `url` is passed, it will be a plain old heading without any
link.
2020-11-30 13:25:28 +05:30
Deepjyoti Barman
53198646bb Add ability to pass URL for the card title 2020-11-30 13:23:39 +05:30
Deepjyoti Barman
a4794fd83d Bump version to 0.2 2020-09-17 12:05:08 +05:30
Deepjyoti Barman
f07ac80030 Make the settings button optional
The settings button will now be optional and will be enabled through the
config. If it is disabled, it will not be shown in the page.

By default, it is disabled, since adding it might ruin the look of the
startpage for a lot of users.
2020-09-17 11:41:06 +05:30
Deepjyoti Barman
a401ff0b46 Resize the cog icon and change it's look
The cog icon looked too large before and the way it looked wasn't too
good. Updated the icons SVG and changed its size.
2020-09-17 11:12:47 +05:30
Deepjyoti Barman
8011f7c029 Move new changes to the scss file
Move the new code for the settings cog to the scss file rather than the
css directoly and then let scss fill the css file.
2020-09-17 11:05:41 +05:30
Deepjyoti Barman
20802593b3 Merge pull request #29 from reesericci/patch-1
Settings improvements
2020-09-17 11:03:47 +05:30
Reese
75013e7211 remove style attribute 2020-09-15 10:27:57 -05:00
Reese
217fbe8229 set css for cog
migrate from style attribute
2020-09-15 10:27:45 -05:00
Deepjyoti Barman
b31d84c68a Add top margin for the squares
The squares kind of stick to the top when there is more than one row of
them. This is fixed by adding a top margin to all the squares.
2020-09-15 20:45:31 +05:30
Reese
719be38d48 Merge branch 'master' into patch-1 2020-09-14 09:13:43 -05:00
Reese
7f888c0724 cleaning up if statement
resolving comment by @deepjyoti30`
2020-09-14 08:45:35 -05:00
Deepjyoti Barman
c536886eb9 Add support for keybinding for settings
The settings menu will now be shown if the ctrl+, is pressed. This fixes
the issue of no way to get Settings if the search bar is hidden.
2020-09-14 18:16:35 +05:30
reesericci
1b9133db1b quick patch, make things simpler 2020-09-09 18:25:58 -05:00
reesericci
561e7cf491 Make gear cog work with closing settings. 2020-09-09 18:13:40 -05:00
reesericci
19827e2957 Add settings cog (for real) 2020-09-09 12:54:02 -05:00
Reese
4069f27750 Settings cog
Add settings cog with onclick. Icon from materialdesignicons.com
2020-09-09 07:59:46 -05:00
Reese
ed05c47d99 Add --settings as a valid query
--setting is kinda weird so I made --settings a valid query.
2020-09-09 07:27:12 -05:00
Deepjyoti Barman
d9ca19ada6 Fix bug with autocomplete showing same option more than once
Autocomplete menu had a bug that showed the same item more than once as
the user kept on typing. The issue is now fixed since the way the items
are closed is reworked and is solidly working all right.
2020-08-28 13:39:39 +05:30
Deepjyoti Barman
b3c301e27a Update README to point to the Wiki
The guides are moved from the README to the Wiki now with the README
pointing to everything in the wiki.
2020-08-28 12:26:18 +05:30
deepjyoti30
0e83664295 Add a new field message to config.json
The greeting message can now be set to a custom static message.

The field in the config required is `message` and it needs to be a
string. If the string is not empty, it will be shown instead of the
default greet message.

In order to disbale it, the field needs to be omitted or set to an empty
string like `""`.
2020-08-10 15:56:25 +05:30
deepjyoti30
aaf8b63af6 Fix a bug related to arrow keys on suggestions 2020-08-10 15:35:15 +05:30
deepjyoti30
45e624e907 Fix a bug related to overlay of the suggestions
The suggestions div has a certain amount of padding that create a div
kind of object when the entered content doesn't match anything, however
this was creating an issue for the settings page.

Fixed that bug by hiding that div when the settings page is opened
2020-08-10 15:31:31 +05:30
deepjyoti30
350caf0022 Made some visual changes but need to work on some searches occuring more than once. 2020-07-08 21:39:51 +05:30
deepjyoti30
41852129a6 Fixed the issue with the click not opening the shortcut. 2020-07-05 13:47:50 +05:30
deepjyoti30
cbfddba907 Init autocomplete. Still needs some testing and fixes. 2020-07-04 22:42:45 +05:30
deepjyoti30
8366d2e714 Merge branch 'master' of github.com:deepjyoti30/startpage 2020-07-04 18:37:55 +05:30
Deepjyoti Barman
c9e18a56c8 Merge pull request #25 from reesericci/patch-1
Remove the broken AMO link.
2020-07-04 18:27:59 +05:30
Reese
34acddedaa Remove the broken AMO link. 2020-07-04 07:54:33 -05:00
deepjyoti30
8a94d6d112 Typo in README. 2020-06-06 12:29:35 +05:30
deepjyoti30
d56530b744 Removed temporary changes used to test on localhost. 2020-06-06 12:23:53 +05:30
deepjyoti30
0d3ec6be71 Formatted the collapsable part properly. 2020-06-05 20:36:53 +05:30
deepjyoti30
467f2e9ae0 Added instructions to customize the squares. 2020-06-05 20:26:34 +05:30
deepjyoti30
bad263d5b1 Merge branch 'master' of github.com:deepjyoti30/startpage 2020-06-05 20:10:30 +05:30
deepjyoti30
a7a4d6ce08 Added support to change colors of each block. 2020-06-05 20:09:33 +05:30
deepjyoti30
4b521b5a60 Added utility to see if passed color is valid. 2020-06-05 19:13:43 +05:30
Deepjyoti Barman
21fb6ec091 Merge pull request #21 from dannyherstell/master
add Ecosia as searchengine
2020-05-26 12:07:19 +05:30
Danny Herstell
d09cb3971b add Ecosia as searchengine
extend version to semver 0.1.1
2020-05-25 22:01:10 +02:00
deepjyoti30
ffe3e6da5c Added support for timezone. 2020-05-20 16:35:41 +05:30
Deepjyoti Barman
0d0e8c03dd Merge pull request #17 from MatiasFI/patch-1
Margin fix in case the squares are  below each other
2020-05-19 11:55:26 +05:30
Matias
105cf985e6 Update main.css 2020-05-18 22:17:39 +03:00
Deepjyoti Barman
3cb54d7509 Merge pull request #11 from reesericci/patch-1
Why build & sign for firefox
2020-05-16 20:27:49 +05:30
Reese
193d326ed0 Why build & sign for firefox 2020-05-16 09:56:14 -05:00
Deepjyoti Barman
abdf70864e Merge pull request #10 from reesericci/patch-1
Grammar fix
2020-05-16 20:19:49 +05:30
Reese
3240609a7f Grammar 2020-05-16 09:47:30 -05:00
deepjyoti30
929d3aab9b Updated README with Wiki link. 2020-05-16 20:13:04 +05:30
deepjyoti30
c0bd3d78d5 Updated README with add on status on mozilla store. 2020-05-16 20:02:58 +05:30
deepjyoti30
41f465ad94 Added a line before kofi part. 2020-05-16 13:14:00 +05:30
deepjyoti30
4f618a96b6 Updated README with changes. 2020-05-16 13:12:11 +05:30
9 changed files with 646 additions and 132 deletions

View File

@@ -1,51 +1,7 @@
# Minimal Startpage
my fork of [this](https://github.com/deepjyoti30/startpage/) start page
Just another minimal startpage for browsers.
<img src=".github/startpage.gif">
## How to Use
- Clone the repo
```console
git clone https://github.com/deepjyoti30/startpage
```
Alternately, you can download and extract from the browser.
### Chrome
- On chrome, open extensions from the tool menu or open it from [chrome://extensions](chrome://extensions).
- Click on load unpacked, navigate to the directory where you cloned the repo and select it.
### Firefox (temporary)
- Open ```about:debugging``` from your Firefox browser.
- Click on This Firefox and select ```Load Temporary Add On...```
- Open the cloned repo directory and select any file there (preferrably ```manifest.json```)
- It should be installed.
## Upcoming
Will be availabe on Firefox and Chrome add on stores in a while.
I thought I would work on adding a settings page that would handle the updating the settings but I'm just way to bored and honestly I've come to realize I hate GUI's (I mean I've always loved CLI based apps). Anyway, the extension can still be used and I'm sure the crowd I aimed this extension at knows how to edit a ```json``` file, for the time being I'll just let you guys install it and use it and edit the settings from the ```config```.
## Settings
You can edit the settings by writing ```--setting``` in the search bar and clicking enter.
A JSON editor will open up where you can make the changes.
| Name | Supported Values | Default | Description |
| ---- | ----- | ------- | ------ |
| searchEngine | \<DuckDuckGo \| Google \| Bing \|Yahoo\> | DuckDuckGo | Search Engine to use for searching from the bar |
| user | string | Deepjyoti (That's my name) | Name of the user to use on the welcome message |
| disableMessage | \<false \| true\> | false | Hide the Welcome message |
| disableDate | \<false \| true\> | false | Hide the date |
| disableSearchBar | \<false \| true\> | false | Hide the search bar |
| disable24Hour | \<false \| true\> | true | Disable 24 hour clock and show time in 12 hour format |
| disableWeather | \<false \| true\> | true | Disable the weather beside the date |
| weatherConf | Object (Check default for child keys) | {"location": "Pune India","unit": "fah"}| Configuration for the weather, location and unit etc. In "unit", "fah" is short for Fahrenheit and "cel" for Celcius, however the whole word can also be passed. |
| squares | Object of arrays | Check [config.json](https://github.com/deepjyoti30/startpage/blob/master/config.json) for default values | Values and Names of shortcuts for the cards. |
i just changed the color palette to onedark,
you will find the documentations and everything on the original repo
# SCREENSHOTS
<img src = "https://i.imgur.com/s5T9dKK.png">
<img src = "https://i.imgur.com/wJagxIv.png">

View File

@@ -1,19 +1,25 @@
{
"squares": [
{ "name": "media", "links": [
{ "name": "media",
"color": "#61afef",
"links": [
{ "name": "Spotify", "url": "https://open.spotify.com/" },
{ "name": "YoutubeMusic", "url": "https://music.youtube.com/" },
{ "name": "Netflix", "url": "https://netflix.com" },
{ "name": "Youtube", "url": "https://youtube.com" }
]
},
{ "name": "work", "links": [
{ "name": "work",
"color": "#e06c75",
"links": [
{ "name": "Github", "url": "https://github.com" },
{ "name": "Heroku", "url": "http://heroku.com/" },
{ "name": "localhost", "url": "http://localhost:8000/" }
]
},
{ "name": "social", "links": [
{ "name": "social",
"color": "#e5c07b",
"links": [
{ "name": "Reddit", "url": "https://reddit.com" },
{ "name": "Unixporn Love", "url": "https://deepjyoti30.github.io/unixporn-love/" },
{ "name": "r/unixporn", "url": "https://www.reddit.com/r/unixporn/" },
@@ -21,7 +27,9 @@
]
},
{
"name": "Others", "links": [
"name": "Others",
"color": "#98c379",
"links": [
{"name": "Material Colors", "url": "http://materialuicolors.co/"},
{"name": "Gmail", "url": "http://gmail.com/"},
{"name": "neo4j Local", "url": "http://localhost:7474/"},
@@ -29,15 +37,29 @@
]
}
],
"searchEngine":"DuckDuckGo",
"user": "Deepjyoti",
"searchEngine":"Brave",
"user": "Pirate",
"disableMessage": false,
"disableDate": false,
"disableSearchBar": false,
"disable24Hour": false,
"disableWeather": true,
"disable24Hour": true,
"disableWeather": false,
"timeZone": "Africa/Cairo",
"weatherConf": {
"location": "Pune India",
"location": "Giza Egypt",
"unit": "cel"
},
"settingsIcon": false,
"style": {
"backgroundColor": "#282c34",
"messageColor": "#fff",
"dateColor": "#c8ccd4",
"lineColor": "#fff",
"weatherColor": "#c8ccd4",
"searchColor": "#c8ccd4",
"searchBackgroundColor": "#1e222a",
"squareColor": "#abb2bf",
"squareBackgroundColor": "#1e222a",
"autocompleteHighlightBackgroundColor": "#3e4451"
}
}

View File

@@ -32,9 +32,11 @@ body {
width: 50%;
margin: 0 auto 50px auto;
height: 45px;
padding-top: 35px; }
.main #search-bar input {
height: inherit;
padding-top: 35px;
position: relative;
display: inline-block; }
.main #search-bar #search-bar-input {
height: 50px;
width: 100%;
background: #2e2e2e;
box-shadow: none;
@@ -44,10 +46,38 @@ body {
outline: none;
padding: 7px 14px;
font-size: 18px;
color: #fff; }
.main #search-bar input:focus {
color: #fff;
box-sizing: border-box; }
.main #search-bar #search-bar-input:focus {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); }
.main #search-bar .autocomplete-items-container {
position: absolute;
top: 100%;
left: 0;
right: 0;
z-index: 99;
border-radius: 6px;
background: #2e2e2e;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); }
.main #search-bar .autocomplete-items-container .autocomplete-item {
width: 100%;
background: #2e2e2e;
box-shadow: none;
border: none;
text-align: center;
outline: none;
padding: 7px 14px;
font-size: 18px;
color: #fff;
box-sizing: border-box;
z-index: -1;
cursor: pointer; }
.main #search-bar .autocomplete-items-container .autocomplete-item:hover {
background: #3b3b3b; }
.main #search-bar .autocomplete-items-container .autocomplete-active {
background: #353535; }
@media only screen and (max-width: 791px) {
.main #search-bar {
width: 65%; } }
@@ -63,10 +93,14 @@ body {
background: #2e2e2e;
padding: 15px 15px;
border-radius: 6px;
min-height: 150px; }
min-height: 150px;
margin-top: 10px; }
.main #other-content .sqr h4 {
font-size: 18px;
margin: 15px; }
.main #other-content .sqr h4 a {
color: inherit;
font-size: inherit; }
.main #other-content .sqr:hover {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); }
@@ -103,7 +137,7 @@ body {
.settings-modal {
display: none;
position: fixed;
z-index: 1;
z-index: 3;
width: 80vw;
height: 80vh;
overflow: auto;
@@ -122,3 +156,16 @@ body {
color: black;
text-decoration: none;
cursor: pointer; }
#settings-cog {
width: 23px;
height: 23px;
position: absolute;
bottom: 25px;
right: 25px;
transition: 2s ease-in;
display: none; }
#settings-cog:hover .cog {
fill: white;
stroke: white;
transition: 2s ease-in; }

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>startpage</title>
<title>New Tab</title>
<!--Json Editor-->
<link rel="stylesheet" href="css/jsoneditor.min.css" type="text/css">
<!--Custom CSS-->
@@ -30,14 +30,22 @@
</div>
<div id="search-bar">
<input id="search-bar-input"></input>
<div class="autocomplete-items-container">
</div>
</div>
<div id="other-content">
</div>
<svg id="settings-cog" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-settings" viewBox="0 0 24 24" stroke-width="1.5" stroke="#607D8B" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z"/>
<path class="cog" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<circle cx="12" cy="12" r="3" />
</svg>
</div>
<!--JSON Editor-->
<script src="js/jsoneditor.min.js"></script>
<!--Custom JS-->
<script src="js/settings.js"></script>
<script src="js/autocomplete.js"></script>
<script src="js/main.js"></script>
</body>
</html>
</html>

118
js/autocomplete.js Normal file
View File

@@ -0,0 +1,118 @@
function autocomplete(inp, passedValues, style) {
var currentFocus;
/*execute a function when someone writes in the text field:*/
inp.addEventListener("input", function(e) {
var item, val = this.value;
var parentContainer = document.getElementsByClassName('autocomplete-items-container')[0];
/*close any already open lists of autocompleted values*/
closeAllLists();
if (!val) {
parentContainer.style.paddingBottom = "0";
return false;
}
currentFocus = -1;
// Update some values of the parent container
parentContainer.setAttribute("id", this.id + "-autocomplete-list");
parentContainer.style.paddingBottom = "1rem";
if(style["searchBackgroundColor"]) {
parentContainer.style.backgroundColor = style["searchBackgroundColor"];
}
/*for each item in the array...*/
Object.keys(passedValues).forEach((el, i, arr) => {
/*check if the item starts with the same letters as the text field value:*/
if (arr[i].toLowerCase().includes(val.toLowerCase())) {
/*create a DIV element for each matching element:*/
item = document.createElement("DIV");
item.setAttribute("class", "autocomplete-item");
// Add the url as an attribute
item.setAttribute('url', passedValues[el]);
if(style["searchBackgroundColor"]) {
item.style.backgroundColor = style["searchBackgroundColor"];
}
if(style["searchColor"]) {
item.style.color = style["searchColor"];
}
/*make the matching letters bold:*/
item.innerHTML = "<strong>" + arr[i].substr(0, val.length) + "</strong>";
item.innerHTML += arr[i].substr(val.length);
/*insert a input field that will hold the current array item's value:*/
item.innerHTML += "<input type='hidden' value='" + arr[i] + "'>";
/*execute a function when someone clicks on the item value (DIV element):*/
item.addEventListener("click", function(e) {
/*insert the value for the autocomplete text field:*/
inp.value = this.getElementsByTagName("input")[0].value;
/*close the list of autocompleted values,
(or any other open lists of autocompleted values:*/
closeAllLists();
});
parentContainer.appendChild(item);
}
})
});
/*execute a function presses a key on the keyboard:*/
inp.addEventListener("keydown", function(e) {
var x = document.getElementById(this.id + "-autocomplete-list");
if (x) x = x.getElementsByTagName("div");
if (e.keyCode == 40) {
/*If the arrow DOWN key is pressed,
increase the currentFocus variable:*/
currentFocus++;
/*and and make the current item more visible:*/
addActive(x);
}
else if (e.keyCode == 38) {
/*If the arrow UP key is pressed,
decrease the currentFocus variable:*/
currentFocus--;
/*and and make the current item more visible:*/
addActive(x);
}
else if (e.keyCode == 13) {
/*If the ENTER key is pressed, prevent the form from being submitted,*/
if (currentFocus > -1) {
e.preventDefault();
/*and simulate a click on the "active" item:*/
if (x) window.location = x[0].getAttribute('url');
}
}
});
function addActive(x) {
/*a function to classify an item as "active":*/
if (!x) return false;
/*start by removing the "active" class on all items:*/
removeActive(x);
if (currentFocus >= x.length) currentFocus = 0;
if (currentFocus < 0) currentFocus = (x.length - 1);
/*add class "autocomplete-active":*/
x[currentFocus].classList.add("autocomplete-active");
}
function removeActive(x) {
/*a function to remove the "active" class from all autocomplete items:*/
for (var i = 0; i < x.length; i++) {
x[i].classList.remove("autocomplete-active");
}
}
function closeAllLists(elmnt) {
/*close all autocomplete lists in the document,
except the one passed as an argument:*/
document.getElementsByClassName("autocomplete-items-container")[0].innerHTML = "";
}
/*execute a function when someone clicks in the document:*/
document.addEventListener("click", function (e) {
closeAllLists(e.target);
});
}

View File

@@ -1,7 +1,10 @@
window.onload = function() {
this.initBody()
this.initBody();
this.listenForSettings();
}
debug = false; // Enable while testing on local
searchBarDivId = "search-bar"
searchBarId = "search-bar-input"
messageDivId = "message"
@@ -10,6 +13,7 @@ dateId = "date-text"
weatherId = "weather-text"
lineId = "line"
messageId = "message-text"
timeZ = undefined
otherContentId = "other-content"
userName = ""
disable24Hour = false;
@@ -29,20 +33,29 @@ bgClassContainer = [
searchEngines = {
"Google": "https://www.google.com/search?q=",
"DuckDuckGo": "https://duckduckgo.com/?q=",
"Bing": "https://www.bing.com/search?q=",
"Yahoo": "https://search.yahoo.com/search?p="
"Brave": "https://search.brave.com/search?q=",
"Yahoo": "https://search.yahoo.com/search?p=",
"Ecosia": "https://www.ecosia.org/search?q="
}
validWeatherUnit = [
"fah", "cel"
]
validQuickLinks = {}
function initBody() {
/**
* Function called when the body is loaded.
*
*
* Do everything like adding an event listener to
* other things.
*/
// If running on local, just read the conf
if (debug) {
readJSON("config.json");
return;
}
// Read the json file
BROWSER.storage.sync.get(result => {
Object.keys(result).length == 0 ? readJSON("config.json") : parseAndCreate(result)
@@ -58,18 +71,23 @@ function initSearchBar(jsonData) {
searchEngine = "Google"
}
searchUrl = this.searchEngines[searchEngine]
document.getElementById(searchBarId).placeholder = `Search something on ${searchEngine}`
document.getElementById(searchBarId).placeholder = `${searchEngine} Search`
document.getElementById(searchBarId).addEventListener("keypress", (event) => {
if (event.key != 'Enter') return
// Open google with the search results.
// Do whatever the user wants to do
query = document.getElementById(searchBarId).value
if (query == "--setting") {
// Open settings
if (query == "--setting" || query == "--settings") {
showSettings()
document.getElementById(searchBarId).value = ""
// Remove the autocomplete boxes
document.getElementById("search-bar-input-autocomplete-list").style.display = "none";
return
}
// If not others, then it's probably a search
query = query.replace(/\ /g, "+")
document.location = searchUrl + query
})
@@ -78,7 +96,7 @@ function initSearchBar(jsonData) {
function buildMsg() {
/**
* Build a nice message for the user.
*
*
* Following is how the message would be decided.
* 0 - 5:59 : It's too late, take some sleep
* 6 - 8:59 : You're up early
@@ -108,12 +126,34 @@ function buildMsg() {
return ""
}
function handleMessage(userName) {
/**
* Handle the creation of the message
*
* Build the message based on the time of the day.
* If the message is null then add just the username
* Else, add the username before the message.
*/
var builtMsg = buildMsg()
builtMsg == "" ?
builtMsg = `Hello ${userName}` : builtMsg = `Hey ${userName}, ${builtMsg}!`
return builtMsg;
}
function updateTime() {
/**
* Get the current time and date and return it.
*/
currentDate = new Date()
finalDate = currentDate.toLocaleString(undefined, {day:'numeric', month:'short', hour:'numeric', minute:'numeric',hour12:disable24Hour})
options = {
day: 'numeric',
month: 'short',
hour: 'numeric',
minute: 'numeric',
hour12: disable24Hour,
timeZone: timeZ
}
finalDate = currentDate.toLocaleString(undefined, options)
document.getElementById(dateId).textContent = finalDate
}
@@ -124,16 +164,6 @@ function updateTimeHook() {
}, 30 * 1000)
}
function getFahrenheit(inCelcius) {
return Math.floor((inCelcius * 9 / 5) + 32)
}
function indexUppercase(unformatted) {
return unformatted.split(" ").map(w => {
return w[0].toUpperCase() + w.substring(1)
}).join(" ")
}
function updateWeather(weatherConfig) {
/**
* Get the weather using the location passed by the user using
@@ -143,7 +173,7 @@ function updateWeather(weatherConfig) {
userLocation = weatherConfig["location"].replace(/\ /g, ",")
passedUnit = weatherConfig["unit"]
unit = validWeatherUnit.includes(passedUnit.substring(0, 3)) ?
passedUnit : "cel"
passedUnit : "cel"
fetchUrl = apiUrl + `?q=${userLocation}&appid=${appId}&units=metric`
@@ -154,16 +184,12 @@ function updateWeather(weatherConfig) {
weatherType = jsonData["weather"][0]["main"]
temp = !unit.includes("cel") ?
getFahrenheit(temp) + "&deg;F" : temp + "&deg;C"
getFahrenheit(temp) + "&deg;F" : temp + "&deg;C"
weatherText = temp + ", " + indexUppercase(weatherType)
document.getElementById(weatherId).innerHTML = weatherText
})
}
function inRange(number, min, max) {
return (number >= min && number <= max)
}
function readJSON(fileName) {
// Load the data of the passed file.
fetch(fileName)
@@ -175,6 +201,8 @@ function readJSON(fileName) {
}
function saveSettings(settings) {
if (debug) return;
BROWSER.storage.sync.set(settings)
}
@@ -184,13 +212,22 @@ function parseAndCreate(jsonData) {
*/
this.userName = jsonData["user"]
// Build a message for the user
builtMsg = buildMsg()
builtMsg == "" ?
builtMsg = `Hello ${this.userName}` : builtMsg = `Hey ${this.userName}, ${builtMsg}!`
// Enable the settings button if it is enabled
if (jsonData["settingsIcon"]) enableCog();
// If the user has not passed any custom message
if (Object.keys(jsonData).includes("message") &&
typeof(jsonData["message"]) == "string" &&
jsonData["message"] != "")
builtMsg = jsonData["message"]
else
builtMsg = this.handleMessage(this.userName);
document.getElementById(messageId).textContent = builtMsg
// Check if 24 hour is disabled
disable24Hour = jsonData["disable24Hour"]
timeZ = jsonData["timeZone"]
timeZ = isValidTimeZone(timeZ) ? timeZ : undefined
// Check if welcome message is supposed to be disabled
if (jsonData["disableMessage"])
document.getElementById(messageDivId).style.display = "none"
@@ -219,34 +256,91 @@ function parseAndCreate(jsonData) {
sqr = createSqr(element, index)
document.getElementById(otherContentId).appendChild(sqr)
})
// Apply styling if present
if (jsonData["style"]) {
styleData = jsonData["style"]
if (styleData["backgroundColor"]) {
document.body.style.backgroundColor = styleData["backgroundColor"]
}
if (styleData["messageColor"]) {
document.getElementById(messageId).style.color = styleData["messageColor"]
}
if (styleData["dateColor"]) {
document.getElementById(dateId).style.color = styleData["dateColor"]
}
if (styleData["lineColor"]) {
document.getElementById(lineId).style.color = styleData["lineColor"]
}
if (styleData["weatherColor"]) {
document.getElementById(weatherId).style.color = styleData["weatherColor"]
}
if (styleData["searchColor"]) {
document.getElementById(searchBarId).style.color = styleData["searchColor"]
}
if (styleData["searchBackgroundColor"]) {
document.getElementById(searchBarId).style.backgroundColor = styleData["searchBackgroundColor"]
autocompleteBackgroundColor = styleData["searchBackgroundColor"]
}
if (styleData["searchPlaceholderColor"]) {
document.getElementById(searchBarId).classList.add(createPlaceholderStyleClass(styleData["searchPlaceholderColor"]));
}
if (styleData["autocompleteHighlightBackgroundColor"]) {
addAutocompleteStyleClass(styleData["autocompleteHighlightBackgroundColor"]);
}
if (styleData["squareBackgroundColor"]) {
elements = document.getElementsByClassName("sqr")
var i;
for (i = 0; i < elements.length; i++) {
elements[i].style.backgroundColor = styleData["squareBackgroundColor"]
}
}
if (styleData["squareColor"]) {
elements = document.querySelectorAll(".sqr a")
var i;
for (i = 0; i < elements.length; i++) {
elements[i].style.color = styleData["squareColor"]
}
}
}
// Extract the quicklinks from the sqrs
extractQuickLinks(sqrs, jsonData["style"]);
}
function createSqr(sqrData, index) {
// Create a new square division with the passed element
name = sqrData["name"]
links = sqrData["links"]
name = sqrData["name"];
link = sqrData["url"];
links = sqrData["links"];
color = sqrData["color"];
// Sometimes, the user might not have set a value for the color,
// in which case it will be undefined.
colorValid = (color == undefined) ? false : isColorValid(color);
div = document.createElement("div")
cls = document.createAttribute("class")
div.setAttributeNode(cls)
div.classList.add("sqr")
if (index > bgClassContainer.length - 1)
customClass = "media"
if (colorValid)
customClass = createClass(color);
else if (index > bgClassContainer.length - 1)
customClass = 'media';
else
customClass = bgClassContainer[index]
div.classList.add(customClass)
customClass = bgClassContainer[index];
h4 = document.createElement("h4")
h4.textContent = name
div.classList.add(customClass);
h4 = getTitle(name, link);
div.appendChild(h4)
links.forEach(element => {
aName = element["name"]
aHref = element["url"]
a = document.createElement("a")
attrHref = document.createAttribute("href")
attrHref.value = aHref
@@ -258,4 +352,200 @@ function createSqr(sqrData, index) {
})
return div
}
}
function getTitle(titleContent, linkHref=null) {
/**
* Create the title for the sqr card.
*
* The card will be optionally clicable and will open
* a new link.
*
* If the link is not passed in the config then the title
* will not be clickable.
*/
h4 = document.createElement("h4");
if (!linkHref) {
h4.textContent = titleContent;
return h4;
}
// If the link is passed, create a nested child
a = document.createElement("a");
a.setAttribute("href", linkHref);
a.textContent = titleContent;
h4.appendChild(a);
return h4;
}
// Utility functions
function isValidTimeZone(tz) {
if (!Intl || !Intl.DateTimeFormat().resolvedOptions().timeZone) {
throw 'Time zones are not available in this environment';
}
try {
Intl.DateTimeFormat(undefined, {timeZone: tz});
return true;
}
catch (ex) {
return false;
}
}
function getFahrenheit(inCelcius) {
return Math.floor((inCelcius * 9 / 5) + 32)
}
function indexUppercase(unformatted) {
return unformatted.split(" ").map(w => {
return w[0].toUpperCase() + w.substring(1)
}).join(" ")
}
function inRange(number, min, max) {
return (number >= min && number <= max)
}
function isColorValid(color) {
/**
* Check if the passed color is valid.
*
* Currently supports only css color names
* or hex colors having 3 or 6 characters.
*/
// Check CSS match
let defaultStyles = new Option().style;
defaultStyles.color = color
if (defaultStyles.color == color) return true;
// In case the above failed, check if it's a hex
return /^#([0-9A-F]{3}){1,2}$/i.test(color);
}
function createClass(color) {
/**
* Create a new class in a style and add it to
* the head.
*
* I did check other alternatives since adding something like
* this in the innerHTML is not a preferred way to go,
* especially since I'm building this as an extension,
* however, there's no other way.
*
* Since I also want to add hover effects, there seriously
* is no other way to do that without adding a style or using
* a library (cannot/don't want to do that because this is an extension).
*/
var style = document.createElement('style');
const newClassName = `bg-${Math.random().toString(36).substring(7)}`;
style.type = 'text/css';
style.innerHTML = `.${newClassName} h4 {color: ${color} !important;} .${newClassName} a:hover {color: ${color} !important;}`;
document.getElementsByTagName('head')[0].appendChild(style);
return newClassName;
}
function createPlaceholderStyleClass(color) {
/**
* Create a new class with for placeholder styling.
*
* This is pretty much a continuation of what has done preivously
* in the createClass function.
*/
var style = document.createElement('style');
const newClassName = `bg-${Math.random().toString(36).substring(7)}`;
style.type = 'text/css';
style.innerHTML = `::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
color: ${color} !important;
opacity: 1; /* Firefox */
}
:-ms-input-placeholder { /* Internet Explorer 10-11 */
color: ${color} !important;
}
::-ms-input-placeholder { /* Microsoft Edge */color: ${color} !important;}`;
document.getElementsByTagName('head')[0].appendChild(style);
return newClassName;
}
function addAutocompleteStyleClass(color) {
/**
* Add some colors for the autocomplete classes in order to
* keep. We need to add styles for :hover property so it is
* easier to just inject some CSS.
*/
var style = document.createElement("style");
style.type = "text/css";
style.innerHTML = `
.autocomplete-item:hover {
background: ${color} !important;
}
.autocomplete-active {
background: ${color} !important;
}
`;
document.getElementsByTagName('head')[0].appendChild(style);
}
function extractQuickLinks(passedSqrs, style) {
/**
* Extract the quicklinks passed in the config
*
* Cache the quicklinks passed by the user in the config JSON
* so that they can be used as a shortcut called from the
* search bar.
*/
passedSqrs.forEach(linksContainer => {
linksContainer.links.forEach(linkObject => this.validQuickLinks[linkObject.name] = linkObject.url);
});
// Start the autocomplete
autocomplete(document.getElementById("search-bar-input"), this.validQuickLinks, style);
}
// Listen to key click
function listenForSettings() {
document.onkeyup = event => {
// Show the settings if ctrl and , is pressed
if (event.ctrlKey && event.which == 188)
showSettings();
}
}
// Handle the settings cog
function enableCog() {
/**
* Enable the settings cog.
*
* It will be disabled by default, however, if the user
* wishes to enable it through the config, it will be shown.
*
* Once shown, we need to add some event listeners to it as
* well so it works the right way.
*/
settingsCogElement = document.getElementById("settings-cog");
// Unhide it
settingsCogElement.style.display = "block";
// Add event listener
settingsCogElement.onclick = function() {
editor = showSettings()
// Add an onclick listener to hide settings if the button is clicked
// again.
settingsCogElement.onclick = () => {
hideSettings(editor);
}
}
}

View File

@@ -29,13 +29,26 @@ function showSettings() {
loadJson(editor)
closeBtn.onclick = () => {
modalEl.style.display = "none"
// Get the updated JSON
updatedJson = editor.get()
BROWSER.storage.sync.set(updatedJson)
document.getElementById(jsonContainer).innerHTML = ""
location.reload()
hideSettings(editor);
}
return editor
}
function hideSettings(editor) {
/**
* Hide the settings.
*
* This function is to be called when the settings window
* is supposed to be hidden, This will automatically
* handle saving the updated settings to the localstorage.
*/
modalEl.style.display = "none"
// Get the updated JSON
updatedJson = editor.get()
BROWSER.storage.sync.set(updatedJson)
document.getElementById(jsonContainer).innerHTML = ""
location.reload()
}
async function loadJson(editor) {
@@ -47,7 +60,7 @@ async function loadJson(editor) {
// Populate the editor
editor.set(result)
})
}
};
function detectBrowser() {
// Firefox
@@ -56,5 +69,5 @@ function detectBrowser() {
else if (!!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime))
BROWSER = chrome
return BROWSER
}
return BROWSER;
};

View File

@@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "minimal-startpage",
"short_name": "minimal-startpage",
"version": "0.1",
"version": "0.2",
"description": "Overrides the browsers newtab page with a custom startpage.",
"author": "deepjyoti30",

View File

@@ -1,12 +1,12 @@
$background: #212121;
$foreground: #fff;
$background: #282c34;
$foreground: #abb2bf;
@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
$media: #4DD0E1;
$work: #F06292;
$social: #FFF176;
$others: #81C784;
$funky: #4DB6AC;
$purple: #9575CD;
$media: #61afef;
$work: #e06c75;
$social: #e5c07b;
$others: #98c379;
$funky: #56b6c2;
$purple: #c678dd;
$upvoty: #FF8A65;
$indigo: #7986CB;
$foxxy: #A1887F;
@@ -61,9 +61,12 @@ body {
margin: 0 auto 50px auto;
height: 45px;
padding-top: 35px;
position: relative;
display: inline-block;
input {
height: inherit;
#search-bar-input {
height: 50px;
width: 100%;
background: lighten($background, 5);
box-shadow: none;
@@ -74,12 +77,47 @@ body {
padding: 7px 14px;
font-size: 18px;
color: $foreground;
box-sizing: border-box;
&:focus {
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
}
}
.autocomplete-items-container {
position: absolute;
top: 100%;
left: 0;
right: 0;
z-index: 99;
border-radius: 6px;
background: lighten($background, 5);
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
.autocomplete-item {
width: 100%;
background: lighten($background, 5);
box-shadow: none;
border: none;
text-align: center;
outline: none;
padding: 7px 14px;
font-size: 18px;
color: $foreground;
box-sizing: border-box;
z-index: -1;
cursor: pointer;
&:hover {
background: lighten($background, 10);
}
}
.autocomplete-active {
background: lighten($background, 8);
}
}
@media only screen and (max-width: 791px) {
@@ -101,10 +139,16 @@ body {
padding: 15px 15px;
border-radius: 6px;
min-height: 150px;
margin-top: 10px;
h4 {
font-size: 18px;
margin: 15px;
a {
color: inherit;
font-size: inherit;
}
}
&:hover {
@@ -144,7 +188,7 @@ body {
h4, a:hover {
color: $social;
}
}
.others {
@@ -188,7 +232,7 @@ body {
.settings-modal {
display: none;
position: fixed;
z-index: 1;
z-index: 3;
width: 80vw;
height: 80vh;
overflow: auto;
@@ -213,4 +257,20 @@ body {
cursor: pointer;
}
}
}
}
#settings-cog {
width: 23px;
height: 23px;
position: absolute;
bottom: 25px;
right: 25px;
transition: 2s ease-in;
display: none;
&:hover .cog {
fill: white;
stroke: white;
transition: 2s ease-in;
}
}