A fun, easy to use, sticky note web-app.
start with manifest.json
** instructions to save the app to a screen,
create an icon, and work offline.
create this file from terminal
touch manifest.json
A text editor will work
{
"name": "oh-stick!",
"short_name": "notes by jr",
"start_url": "https://sudo-self.github.io/oh-stick/#",
"scope": "./",
"icons": [
{
"src": "APPicon.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "APPicon1.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffd31d",
"background_color": "#333",
"display": "standalone"
}
APPicon.png = Appicon
Oh-stick starts with HTML
touch index.html
link external CSS and JAVA
<link rel=¨stylesheet¨ type=¨text/css¨ href=¨..\[folder_name]\[file_name].css¨><br>
<script src="myscripts.js"></script>
standard is legit in 2024.
Set header with favicon
add
favicon.ico & apple-touch-icon.png
in the root folder
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
next is html body
<h1>Oh-Stick!</h1>
<p id="ts">notes by Jesse</p>
</div>
<div id="form">
<form id="inputForm">
<input
type="text"
class="inputText"
placeholder="Title"
id="new-note-title-input"
autocomplete="off"
required
autofocus
/><br><br>
<input
class="inputText"
type="text"
placeholder="Note Content"
id="new-note-body-input"
autocomplete="off"
required
/>
<button type="submit" class="btn">
🧲
</button>
</form>
</div>
</html>
Emoji as a button to stick note.
The favicon you can create from scratch.
A good quality starting image is key.
Javascript makes up the function of the notes.
touch script.js
Set or modify alerts as needed.
if ("serviceWorker" in navigator) {
// register service worker
navigator.serviceWorker.register("service-worker.js");
}
var itemList = document.getElementById("notes");
itemList.addEventListener("click", removeItem);
let count = Number(window.localStorage.getItem("count"));
if (!count) {
window.localStorage.setItem("count", "0");
}
console.log(count);
let createNote = (noteTitle, noteBody) => {
if (count > 0) {
document.getElementById("no-notes").className = "hidden";
}
var li = document.createElement("li");
var a = document.createElement("a");
var h2 = document.createElement("h2");
var p = document.createElement("p");
var ul = document.getElementById("notes");
let xButton = document.createElement("button");
xButton.classList.add("delete");
let xText = document.createTextNode("X");
let h2TN = document.createTextNode(noteTitle);
let pTN = document.createTextNode(noteBody);
h2.appendChild(h2TN);
p.appendChild(pTN);
xButton.appendChild(xText);
a.appendChild(h2);
a.appendChild(xButton);
a.appendChild(p);
a.setAttribute("href", "#");
li.appendChild(a);
ul.appendChild(li);
};
let createNoteFromInput = (e) => {
e.preventDefault();
var noteTitle = document.getElementById("new-note-title-input").value;
var noteBody = document.getElementById("new-note-body-input").value;
document.getElementById("new-note-title-input").value = "";
document.getElementById("new-note-body-input").value = "";
console.log("yes");
if (!noteTitle || !noteBody) {
alert("Both Title and body of the note must be provided");
return;
}
count += 1;
window.localStorage.setItem("count", count);
while (window.localStorage.getItem(noteTitle)) {
noteTitle = noteTitle + " - 1";
}
window.localStorage.setItem(noteTitle, noteBody);
createNote(noteTitle, noteBody);
};
function removeItem(e) {
//console.log('2');
if (e.target.classList.contains("delete")) {
console.log(e);
if (
confirm(
'Remove adhesive from "' +
e.target.previousElementSibling.innerText +
'" stick?'
)
) {
//grab the parent
// console.log(e.target.previousSibling.data);
var li = e.target.parentElement.parentElement;
itemList.removeChild(li);
count -= 1;
window.localStorage.setItem("count", count);
window.localStorage.removeItem(e.target.previousElementSibling.innerText);
if (count < 1) {
document.getElementById("no-notes").className = "";
}
}
}
}
for (i = 0; i < count + 1; i++) {
console.log(window.localStorage.key(i));
let noteTitle = window.localStorage.key(i);
let noteBody = window.localStorage.getItem(noteTitle);
if (noteTitle !== "count" && noteTitle) {
createNote(noteTitle, noteBody);
}
}
document
.getElementById("inputForm")
.addEventListener("submit", createNoteFromInput, false);
style.css
strong foundations can scale vertically
.json adds wrapper versatility.
touch style.css
* {
margin: 0;
padding: 0;
}
body {
font-family: arial, sans-serif;
font-size: 100%;
margin: 3em;
background: #333;
color: #fff;
}
#heading {
position: sticky;
top: 0;
background-color: #333;
z-index: 7;
padding: 15px 0px;
margin-left: 15px;
}
#no-notes {
padding: 100px 0px;
text-align: center;
}
#ts {
color: #9085c4;
}
.inputText {
padding: 10px;
border-radius: 5px;
border: 2px solid #9085c4;
width: 30%;
margin: 15px;
outline: none;
}
.hidden {
display: none;
}
.btn {
padding: 10px;
border-radius: 20px;
border: 2px solid #9085c4;
background-color: #333;
color: #333;
cursor: pointer;
outline: none;
-webkit-tap-highlight-color: transparent;
}
.btn:active {
border: 2px solid #333;
box-shadow: inset 0 0 5px #000000;
}
h2,
p {
font-size: 100%;
font-weight: normal;
}
ul,
li {
list-style: none;
}
ul {
overflow: hidden;
padding: 3em 1em;
}
ul li a {
text-decoration: none;
color: #000;
background: #9085c4;
display: block;
height: 10em;
width: 10em;
padding: 1em;
box-shadow: 5px 5px 7px rgba(33, 33, 33, 0.7);
}
ul li {
margin: 1em;
float: left;
position: relative;
}
ul li h2 {
font-size: 1.2rem;
font-weight: bold;
padding-bottom: 10px;
}
ul li p {
font-family: "Reenie Beanie", cursive;
font-size: 1.1rem;
}
.delete {
float: right;
position: absolute;
top: 0;
right: 0;
width: 30px;
height: 30px;
background-color: red;
border: 4px double white;
font-weight: bold;
cursor: pointer;
}
ul li a {
transform: rotate(-6deg);
-moz-transform: rotate(-6deg);
cursor: default;
}
ul li:nth-child(even) a {
transform: rotate(4deg);
-moz-transform: rotate(4deg);
position: relative;
top: 5px;
background: #ff5733;
}
ul li:nth-child(3n) a {
transform: rotate(-3deg);
-moz-transform: rotate(-3deg);
position: relative;
top: -5px;
background: #77d8d8;
}
ul li:nth-child(5n) a {
transform: rotate(5deg);
-moz-transform: rotate(5deg);
position: relative;
top: -10px;
}
ul li a:hover,
ul li a:focus {
box-shadow: 10px 10px 7px rgba(0, 0, 0, 0.7);
-moz-box-shadow: 10px 10px 7px rgba(0, 0, 0, 0.7);
transform: scale(1.25);
-moz-transform: scale(1.25);
position: relative;
z-index: 5;
}
ol {
text-align: center;
}
ol li {
display: inline;
padding-right: 1em;
}
ol li a {
color: #fff;
}
@media only screen and (max-width: 600px) {
body {
margin-top: 1em;
}
#new-note-title-input,
#new-note-body-input {
display: block;
width: 90%;
margin-left: 0px;
}
#heading {
margin-left: 0px;
}
.btn {
margin-left: 0px;
}
}
A static.yml will work to publish a workflow.
The workflow is essential for wrapping to PWA to APK. with GH-Pages you now have a URL for manifest.json
https://sudo-self.github.io/oh-stick/ manifest.json HERE
static.yml
name: Deploy static content to Pages
on:
push:
branches: ["main"]
tab
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: '.'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
Now The App is live online.
https://sudo-self.github.io/oh-stick/
- index.html
- style.css
- script.js
- ""
- "" <----website---->
<---webapp----->
- liscense.txt
- README.md (project explanation)
<----TWA---->
- manifest.json (for PWA to APK or IPA)
See the Pen Oh-stick! by sudo-self (@sudo-self) on CodePen.
All the way to a signed android APK with a wrapper.
sticky reminders
https://oh-stick.JesseJesse.com
See the Pen
Oh-stick! by sudo-self (@sudo-self)
on CodePen.
Top comments (0)