├── .github └── workflows │ └── build.yaml ├── .gitignore ├── README.md ├── fonts └── Iosevka-regular.ttf ├── images ├── bg.jpg └── icon.png ├── index.html ├── js ├── time.js └── weather.js ├── manifest.json ├── package-lock.json ├── package.json ├── scrot.png ├── shell.nix └── style.css /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Releases 3 | on: 4 | push: 5 | branches: [main] 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout repository 11 | uses: actions/checkout@v4 12 | - name: Set up Node.js 13 | uses: actions/setup-node@v4 14 | with: 15 | node-version: '20' 16 | - name: Install dependencies 17 | run: npm install 18 | - name: Install web-ext 19 | run: npm install --global web-ext 20 | - name: Extract version from manifest.json 21 | id: get_version 22 | run: | 23 | version=$(jq -r '.version' manifest.json) 24 | echo "VERSION=$version" >> $GITHUB_ENV 25 | - name: Inject environment variables into weather.js 26 | run: | 27 | sed -i 's/const key = "";/const key = "${{ secrets.KEY }}";/' js/weather.js 28 | sed -i 's/const latitude = 0;/const latitude = ${{ secrets.LATITUDE }};/' js/weather.js 29 | sed -i 's/const longitude = 0;/const longitude = ${{ secrets.LONGITUDE }};/' js/weather.js 30 | - name: Build and Sign Extension 31 | id: build 32 | env: 33 | FIREFOX_JWT_ISSUER: ${{ secrets.FIREFOX_JWT_ISSUER }} 34 | FIREFOX_JWT_SECRET: ${{ secrets.FIREFOX_JWT_SECRET }} 35 | run: | 36 | web-ext sign \ 37 | --channel=unlisted \ 38 | --api-key=$FIREFOX_JWT_ISSUER \ 39 | --api-secret=$FIREFOX_JWT_SECRET | tee >(cat) | \ 40 | grep "^Generated extension ID:" | \ 41 | xargs -I {} echo "EXTENSION_ID={}" >> $GITHUB_ENV 42 | - name: Prep Artifact 43 | run: | 44 | mv web-ext-artifacts/*.xpi web-ext-artifacts/startpage-${{ env.VERSION }}.xpi 45 | - name: Generate SHA-256 SRI hash for xpi file 46 | id: generate_sri 47 | run: | 48 | SHA256_HASH=$(openssl dgst -sha256 -binary web-ext-artifacts/startpage-${{ env.VERSION }}.xpi | \ 49 | openssl base64 -A) 50 | echo "SRI_HASH=sha256-$SHA256_HASH" >> $GITHUB_ENV 51 | - name: Release 52 | uses: ncipollo/release-action@v1.14.0 53 | with: 54 | tag: ${{ env.VERSION }} 55 | artifacts: web-ext-artifacts/startpage-${{ env.VERSION }}.xpi 56 | allowUpdates: true 57 | replacesArtifacts: true 58 | token: ${{ secrets.GITHUB_TOKEN }} 59 | body: |- 60 | ${{ env.EXTENSION_ID }} 61 | SHA-256: `${{ env.SRI_HASH }}` 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | web-ext-artifacts/ 3 | .web-extension-id 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Startpage 2 | 3 | Flat minimal start page made for elegant look and simple at same time. 4 | there is more than branch every one have a unique ui. 5 | 6 | ![Flat startpage look!](/scrot.png) 7 | 8 | ## Pack as web-ext 9 | 1. Clone the repo 10 | ``` 11 | git clone https://github.com/mahmoudk1000/startpage.git 12 | ``` 13 | 14 | 2. You need to install web--ext tool by runing terminal
15 | ``` 16 | sudo npm install -g web-ext 17 | ``` 18 | 19 | 3. Check Firefox [ext-packing guide](https://extensionworkshop.com/)
20 | 21 | 4. Last step run in terminal in same dir where repo cloned 22 | ``` 23 | web-ext sign --api-key "YOUR_USER_KEY" --api-secret "YOUR_SECRET" 24 | ``` 25 | 26 | ## Weather 27 | For setting up the Weather widget you're going to need an API Key in: https://openweathermap.org/. Once you have your Key you'll need to set yourlatitude and longitude, you can use: https://www.latlong.net/ to get them. Then you just have to fill them in the weather.js in the js folder: 28 | ```js 29 | // Use your own key for the Weather, Get it here: https://openweathermap.org/ 30 | const key = "XXXXXXXXXXXXXXXXXXXXXXXXXXX"; 31 | 32 | setPosition(); 33 | 34 | function setPosition(position) { 35 | // Here you can change your position 36 | // You can use https://www.latlong.net/ to get it! (I use San Francisco as an example) 37 | let latitude = 37.774929; 38 | let longitude = -122.419418; 39 | 40 | getWeather(latitude, longitude); 41 | } 42 | ``` 43 | 44 | 45 | ## Credits 46 | 47 | [migueravila/Bento](https://github.com/migueravila/Bento) For time, date and weather script and weather guide.
48 | [MCotocel/startpage](https://github.com/MCotocel/startpage) For DuckDuckGo search script 49 | -------------------------------------------------------------------------------- /fonts/Iosevka-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudk1000/startpage/c4d4439eb8c5bae9fc4c91f2abcf4744f4e40b6b/fonts/Iosevka-regular.ttf -------------------------------------------------------------------------------- /images/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudk1000/startpage/c4d4439eb8c5bae9fc4c91f2abcf4744f4e40b6b/images/bg.jpg -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudk1000/startpage/c4d4439eb8c5bae9fc4c91f2abcf4744f4e40b6b/images/icon.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | H O M E 8 | 9 | 10 | 11 | 12 |
13 |

The internet is, where knowledge flows freely,
but so does misinformation.

14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
,
23 |
24 |
25 |
26 |
27 | 28 |
29 |
30 |
31 |
32 | 33 |
34 | 51 | 68 | 85 | 102 |
103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /js/time.js: -------------------------------------------------------------------------------- 1 | window.onload = displayClock(); 2 | function displayClock() { 3 | const monthNames = [ 4 | "Jan", 5 | "Feb", 6 | "Mar", 7 | "Apr", 8 | "May", 9 | "Jun", 10 | "Jul", 11 | "Aug", 12 | "Sep", 13 | "Oct", 14 | "Nov", 15 | "Dec", 16 | ]; 17 | const daysOfWeek = [ 18 | 'Sun', 19 | 'Mon', 20 | 'Tues', 21 | 'Wed', 22 | 'Thurs', 23 | 'Fri', 24 | 'Sat' 25 | ]; 26 | 27 | // Set to true to use a 12 hour date format 28 | var format_12hour = false; 29 | 30 | var d = new Date(); 31 | var dn = daysOfWeek[d.getDay()]; 32 | var mm = monthNames[d.getMonth()]; 33 | var dd = d.getDate(); 34 | var min = (mins = ("0" + d.getMinutes()).slice(-2)); 35 | var hh = d.getHours(); 36 | var ampm = ""; 37 | var yy = d.getFullYear(); 38 | 39 | if (format_12hour) { 40 | ampm = hh >= 12 ? " PM" : " AM"; 41 | hh = hh % 12; 42 | hh = hh ? hh : 12; //show mod 0 as 12 43 | } 44 | 45 | document.getElementById("hour").innerText = hh; 46 | document.getElementById("separator").innerHTML = " : "; 47 | document.getElementById("minutes").innerText = min + ampm; 48 | 49 | document.getElementById("dow").innerText = dn; 50 | document.getElementById("day").innerText = dd; 51 | document.getElementById("month").innerText = mm; 52 | document.getElementById("year").innerText = yy; 53 | 54 | setTimeout(displayClock, 1000); 55 | } 56 | -------------------------------------------------------------------------------- /js/weather.js: -------------------------------------------------------------------------------- 1 | const key = ""; 2 | const latitude = 0; 3 | const longitude = 0; 4 | 5 | const tempElement = document.querySelector(".temperature-value span"); 6 | 7 | // App data 8 | const weather = {}; 9 | weather.temperature = { 10 | unit: "celsius", 11 | }; 12 | 13 | // Change to 'F' for Fahrenheit 14 | var tempUnit = "C"; 15 | 16 | const KELVIN = 273.15; 17 | 18 | // Set Position function 19 | setPosition(); 20 | 21 | function setPosition(position) { 22 | // Here you can change your position 23 | // You can use https://www.latlong.net/ to get it! (I use San Francisco as an example) 24 | getWeather(latitude, longitude) 25 | } 26 | 27 | // Get the Weather data 28 | function getWeather(latitude, longitude) { 29 | let api = `https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=${key}`; 30 | 31 | console.log(api); 32 | 33 | fetch(api) 34 | .then(function (response) { 35 | let data = response.json(); 36 | return data; 37 | }) 38 | .then(function (data) { 39 | let celsius = Math.floor(data.main.temp - KELVIN); 40 | weather.temperature.value = 41 | tempUnit == "C" ? celsius : (celsius * 9) / 5 + 32; 42 | }) 43 | .then(function () { 44 | displayWeather(); 45 | }); 46 | } 47 | 48 | // Display Weather info 49 | function displayWeather() { 50 | tempElement.innerHTML = `${weather.temperature.value}°${tempUnit}`; 51 | } 52 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "start-page-colors", 4 | "short_name": "start-page-colors", 5 | "version": "3.1.1", 6 | "description": "Minimal start page made for elegant look and simple at same time.", 7 | "author": "mahmoudk1000", 8 | "icons": { 9 | "48": "images/icon.png" 10 | }, 11 | "background": { 12 | "scripts": [ 13 | "js/time.js", 14 | "js/weather.js" 15 | ] 16 | }, 17 | "chrome_url_overrides": { 18 | "newtab": "index.html" 19 | }, 20 | "permissions": [ 21 | "storage", 22 | "tabs", 23 | "sessions" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "web-ext": "^7.11.0" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /scrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudk1000/startpage/c4d4439eb8c5bae9fc4c91f2abcf4744f4e40b6b/scrot.png -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import {} }: 2 | 3 | pkgs.mkShell { 4 | name = "Startpage"; 5 | buildInputs = with pkgs; [ 6 | nodejs 7 | # web-ext 8 | ]; 9 | } 10 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | /* Colors */ 3 | --darkbg: #11171D; 4 | --lightbg: #161D25; 5 | --fg: #E2E8EE; 6 | } 7 | 8 | @font-face { 9 | font-family: Iosevka; 10 | src: url(../fonts/Iosevka-regular.ttf); 11 | } 12 | * { 13 | font-family: Iosevka; 14 | text-decoration: none; 15 | } 16 | 17 | @media only screen and (max-width: 768px) { 18 | .body { 19 | padding: 10px; 20 | } 21 | .header { 22 | flex-direction: column; 23 | text-align: center; 24 | padding: 20px; 25 | } 26 | .header > h1 { 27 | font-size: 18px; 28 | margin-bottom: 10px; 29 | } 30 | .info { 31 | flex-direction: column; 32 | align-items: center; 33 | margin-top: 10px; 34 | } 35 | .clock { 36 | margin-bottom: 10px; 37 | } 38 | .bookmarks { 39 | display: flex; 40 | justify-content: center; 41 | flex-wrap: wrap; 42 | margin-top: 20px; 43 | } 44 | .menu_place { 45 | width: 45%; 46 | margin: 10px; 47 | padding: 15px; 48 | text-align: center; 49 | } 50 | .list { 51 | font-size: 16px; 52 | padding-top: 10px; 53 | } 54 | .menu_name { 55 | margin-bottom: 10px; 56 | } 57 | } 58 | 59 | .body { 60 | background-color: var(--darkbg); 61 | margin: 0; 62 | position: absolute; 63 | top: 50%; 64 | left: 50%; 65 | -ms-transform: translate(-50%, -50%); 66 | transform: translate(-50%, -50%); 67 | } 68 | .header { 69 | color: var(--darkbg); 70 | height: fit-content; 71 | width: 100%; 72 | display: flex; 73 | background-image: linear-gradient(to right, #D7C1ED, #96CDFB, #B5E8E0, #F28FAD); 74 | border-radius: 8px; 75 | align-items: center; 76 | } 77 | .quote { 78 | font-size: 21px; 79 | margin: 1.5%; 80 | } 81 | .header > h1 { 82 | flex: 80%; 83 | } 84 | .header > div { 85 | flex: 20%; 86 | } 87 | .info { 88 | align-items: center; 89 | margin: 1.5%; 90 | } 91 | .clock, 92 | .temp { 93 | display: flex; 94 | justify-content: right; 95 | } 96 | .clock { 97 | font-size: 28px; 98 | align-items: end; 99 | } 100 | .temp { 101 | font-size: 14px; 102 | text-indent: 3px; 103 | align-items: center; 104 | } 105 | .bookmarks { 106 | margin-top: 40px; 107 | justify-content: center; 108 | display: flex; 109 | } 110 | .menu_place { 111 | color: var(--fg); 112 | padding: 15px; 113 | width: 260px; 114 | height: 230px; 115 | justify-content: center; 116 | border-radius: 8px; 117 | margin: 0 10px; 118 | } 119 | .menu_place:first-child { 120 | margin-left: 0; 121 | } 122 | 123 | .menu_place:last-child { 124 | margin-right: 0; 125 | } 126 | .list { 127 | text-align: center; 128 | display: block; 129 | font-size: 26px; 130 | margin-top: 20px; 131 | } 132 | .menu_name { 133 | color: var(--darkbg); 134 | text-align: center; 135 | font-size: 28px; 136 | border-radius: 8px; 137 | padding-top: 7px; 138 | padding-bottom: 7px; 139 | } 140 | .in_list_general { 141 | color: var(--fg); 142 | border-radius: 8px; 143 | height: 40px; 144 | text-align: left; 145 | padding-left: 25px; 146 | } 147 | .in_list_one:hover { 148 | color: #11171D; 149 | background-color: #D7C1ED; 150 | } 151 | .in_list_two:hover { 152 | color: #11171D; 153 | background-color: #96CDFB; 154 | } 155 | .in_list_three:hover { 156 | color: #11171D; 157 | background-color: #B5E8E0; 158 | } 159 | .in_list_four:hover { 160 | color: #11171D; 161 | background-color: #F28FAD; 162 | } 163 | .link_text { 164 | color: var(--fg); 165 | vertical-align: middle; 166 | font-variant: small-caps; 167 | } 168 | --------------------------------------------------------------------------------