Back
batch / webOS / part-4
  • 4/5

Presentation

Video

Play in FigmaRemix In Figma

1/--

Loading PDFโ€ฆ
Web
Intermediate
30 Min

Create Your First App

SerenityUX

Aye there mate, welcome to the forth Jam in this Batch. We're quite impressed by your resilience. Surely you're a bit impressed with yourself as well.

Our first app is going to be a text-based app where you can create little text-based posts about yourself or whatever you'd like to post about. Your app is going to look totally different from mine, so prepare to get your creative thinking cap on and begin your first app.

Content Selection

You could make the theme of your blog/article app about whatever you'd like! For example, you could use this as a place to store reviews of/notes about your favorite restaurants, cafes, recipes, books, etc.

HAVE FUN WITH THIS! IT'S YOURRRR app ON YOUR personalOS! Do whatever you'd like.

Outline:

  1. Adding App to Desktop
  2. Making App Icon Tappable
  3. Making our App Window
  4. Making Our First App
  5. Additional Challenges

Adding App to Desktop

Alrighty, so let's go into our body tag and create a div beneath the menu bar (hey, pro tip btw, you can collapse your divs to make your code more readable for cases like this by tapping the dropdown button next to the code line number of a div)

  <div id="desktopApps" style="padding-top: 64px; padding-left: 16px;">
    <p>Name Of Your App</p>
  </div>

Note: I added some padding on the top and left to give the application icons some breathing room and to make sure it was not covered by the top-bar.

Here's what my code looks like

<body style="font-family: Noto Sans, system-ui, sans-serif; height: 100vh; background-image: url(./beautifulImage.png); background-size: cover; background-repeat: no-repeat; margin: 0px;">
	<div class="window" id="welcome" style="top: calc(50% - 90px); left: calc(50% - 180px);">
		(window content)
	</div>
	<div style="position: absolute; window: 100%; display: flex; backdrop-filter: blur(10px); background-color: rgba(0, 0, 0, 0.125); color: #fff; justify-content: space-between; gap: 32px;">
		(topbar content)
	</div>
	<div id="desktopApps" style="padding-top: 64px; padding-left: 16px;">
		<p>Hacker Notes</p>
	</div>
</body>

Add Your Icon

Create an Icon

My app is going to be called Hacker Notes.

Note: Want to also name your app Hacker Notes? Ha, no you cannot because you're not doing a workshop, you're doing a JAM and JAMS require that you do-ya-own-thingโ„ข.

I took a photo of a friend's notebook (note from Thomas's "friend", Sahiti: "WHY MY NOTEBOOK?!") to use as the icon for the app.

notebook image

Take your own image that fits your app and send it to your computer using email or AirDrop and then drag it into Replit (just as we did for the background). Make sure the file format is .png or .jpg (otherwise find an online file converter).

You can also you can icon you create or find online. I really don't mind, this is your operating system after all and you're the chief designing, so you make the call pal.

Use Your Icon

Create an image tag, and apply some styles of your choice! I customized the width, height, border-radius, and added a drop-shadow.

It's also probably a good idea to wrap your icon in a div so we can later tap on that icon to open the window.

Here's what my code looks like:

  <div id="desktopApps" style="padding-top: 64px;">
    <div style="text-align: center; padding: 16px; filter: drop-shadow(0 0 8px black); width: fit-content">
      <img src="./notebook.png" style="width: 64px; height: 64px; border-radius: 16px;">
      <p style="margin: 0px; color: #fff; ">Notes</p>
    </div>
  </div>

Note: PLEASE DO NOT COPY THIS CODE! Do your own app and style your icon in your own way. Want to make all the icons circles, go for it (increase that border-radius)!

Here's what my icon is currently looking like inside my application

Icon in my personalOS

Currently when we tap on the icon... nothing happens. Let's select the icon when we tap on it!

Making App Icon Tappable

Alright let's break this into parts.

  1. Store what icon is selected
  2. We need a way to communicate to the user whether the icon is selected or not selected
  3. We need a way to change the icon's appearance to show that it is selected
  4. We also need a way to change the appearance when deselected (tapped that second time)

Store the State of the Selected Icon

Let's begin by storing what the selected icon is (by default, this will be undefined because there is no selected icon).

For that we will use a... you guessed it... variable

var selectedIcon = undefined

(p.s. this is JavaScript code, so it's in our JavaScript file)

Lovely, now let's make a function for changing the visual appearance of the icon. I challenge you to give it some thought & think hmmm "how can I change the style of an icon without using in-line styles".

Solution

Communicate whether an icon is selected

We're going to this using classes!

Let's make a class for a selected icon. For testing purposes, you can go ahead and add the class to your icon div like so:

<div class="selected" styles="(styles)">
	(content)
</div>

Here's what I added in my css file. Please DON'T TAKE THIS CODE. Communicate that it is selected in your own way. This may be through a curvy underline, a rounding of the corners, a green background, etc whatever you'd like!

Programmatically Adding/Removing a Class

Poke around this geeksforgeeks site on classes and see if you can programmatically add a class to an element

Solution

Let's go ahead and add some style properties for when the icon is selected.

function selectIcon(element) {
  element.classList.add("selected");
  selectedIcon = element
} 

& now try implementing a function for deselecting an icon

Solution for Deselecting Icon function

When I first introduced JavaScript, I described it as the logic of your program.

I think we've already worked with if else statements, but just in case you were lost, here's a brief introduction.

If else statements check if a certain condition is true in which case a certain block of code runs & if that condition is not true a different block of code runs.

Try to write an if-then statement inside a handleIconTap function that selects the item if it's not selected, but deselects it if it is already selected.

Your code may look a little like this:

function handleIconTap(element) {
  if (condition) {
    functionA(element)
  } else {
    functionB(element)
  }
}

Hint: element.classList.contains("selected") exists and returns a Boolean value (either True or False)

Solution Handling Icon Tap

Making our App Window

Copying & customizing the old window

We can basically copy the code from our other window and remove the content.

Once we copy that code, change the id to "theNameOfYourApp" (actually make it the name of your app). Then inside the div that contains the content of your app, you may want to adjust the height and width. You can also change the header text.

Here's what my code looks like (keep in mind if you copy this code it will probably break your site because it should have significantly different styling than what is here)

(don't copy)

  <div class="window" id="notes" style="top: calc(50% - 240px); left: calc(50% - 260px); ">
    <div class="windowheader" id="notesheader">
      <div class="closebutton" id="notesclose">
      </div>

      <p class="headertext">Notes</p>
      <div style="width: 16px; margin-right: 6x; height: 16px;"></div>
    </div>
    <div style="background-color: #fff; margin: 6px; border-radius: 12px; width: 520px; height: 480px; padding: 16px;">
      <p>Hacker Notes</p>
    </div>
  </div>

Making our App Draggable

Also make sure to run in your script.js file the code

dragElement(document.querySelector("#notes"))

just as you did with your other window.

Boommmm, we have our second window!

Now we're able to move it around, but we cannot yet close it.

Draggable

Making our App Closable

Let's look at the code we implemented for the welcome screen

var welcomeScreen = document.querySelector("#welcome")

var notesScreenClose = document.querySelector("#welcomeclose")

notesScreenClose.addEventListener("click", () => closeWindow(welcomeScreen));

Now try editing your HTML code id (for the close button) and write a new set of code for making this screen closable

Solution For Closing The Window

make the window closable

Soo... this is quite annoying... repeating code that is...

When you repeat code, that's a good sign you should make it a function. Try turning it into a function and calling said function

Solution For Closable Window Function

Making Our Window Closed By Default

This is quite simple! Just add the display: none; style property inline to your notes div.

closed by default

Making our Rise To The Top

You'll notice on that last gif that when we tap on the notes window, it doesn't rise on top of the welcome screen.

When we tap on a window, we should make it rise to the top. We can do this using the z-index style property.

If you're feeling quite confident, try implementing this feature on your own! Otherwise, go through the notes below

Defining the largest index

We need to store the largest index so we can know what value we need to set the tapped on window to. We want the window we tap on to have an index greater than the one previously tapped on.

var biggestIndex = 1;

I initialized it at 1. You can initialize the variable at any value you'd like to initialize it at.

Checking for a Tap on the window

We need a function to make the window listen for the user to click on it (we call this "mousedown"). When the user taps on the window, we then run the will run some block of code (handleWindowTap) to move it to the top

function addWindowTapHandling(element) {
  element.addEventListener("mousedown", () =>
    handleWindowTap(element)
  )
}

Making the Window to the Top On Move on Tap

We're now lifting the window up to the top by incrementing the biggestIndex and setting the zIndex to that new biggestIndex

function handleWindowTap(element) {
  biggestIndex++;  // Increment biggestIndex by 1
  element.style.zIndex = biggestIndex;
}

Making Window Move To Top On Open

Awesome, we want to make it so when we open the window, it moves straight to the top immediately.

function openWindow(element) {
  element.style.display = "flex";
  biggestIndex++;  // Increment biggestIndex by 1
  element.style.zIndex = biggestIndex;
}

Protecting The Top Bar

An issue we encounter is that eventually the window goes on top of the topBar. To counter that, let's identify the top bar and then increment it's value each time we increment the window

<div id="top"
    style="(styles)">
</div

(in HTML)

var topBar = document.querySelector("#top")

function openWindow(element) {
  element.style.display = "flex";
  biggestIndex++;  // Increment biggestIndex by 1
  element.style.zIndex = biggestIndex;
  topBar.style.zIndex = biggestIndex + 1;
}

function handleWindowTap(element) {
  biggestIndex++;  // Increment biggestIndex by 1
  element.style.zIndex = biggestIndex;
  topBar.style.zIndex = biggestIndex + 1;
  deselectIcon(selectedIcon)
}

(in JavaScript)

Celebrate it works

Awesome! Now we're able to tap on our windows and see them ov

overlapping fixed

Putting All Of This Into One Function to Initialize a Window

We're writing a bunch of functions to initialize the window, I challenge you to try putting it all into one window. This isn't necessary, but it will just be helpful later on.

Solution

Calling Our Function

Make sure you call the function you create to ensure your window functions properly initializeWindow("notes")

Making Our First App

The time has come young one. You're going to make the first app for your OS. It's going to be a text-based app about whatever you'd like. Mine will be my "Hacker Notes," but maybe yours will be your "Hiking Notes" or your "Favorite Recipes," or your "Random Inspirational Quotes."

It's totally up to you. There's only one app you cannot make (& that is Hacker Notes). You need to do your ownnnn thinggg my friend! Don't be a follower, be a leader!!!

Making Initial View

The initial view for my site will be introducing the concept of Hacker Notes. If you would like, you can make an initial view that represents your site well. I changed the font, added some text, and just generally had fun with it. I encourage you to do the same (& add your own unique style with images, awesome styles, etc).

initial screen

Adding Content Selection

Having one piece of content on your app is sort of boring. We should make it so the user can select between multiple pieces of content.

Creating a side bar, bottom bar, top bar, or whatever you'd like

You need a space to store your content selection options. I put this in a side bar. You can put this in whatever you'd like.

side bar added

I encourage you to create something other than a sidebar to display your content selection options. Get creative, and be unique.

Here are the steps I took to create this sidebar.

  1. Wrapped my text content inside of a div
  2. Created a div inside of the window content div
  3. Made the window content div use display: flex; and flex-direction: row;
  4. Added some padding and some margin
  5. Styled the sidebar to make it look nice and added the first entry (with a name and date)

If you're stuck and want to see my code, take a look (but please don't copy and paste)

  <div class="window" id="notes" style="top: calc(50% - 240px); display: none; left: calc(50% - 260px); ">
    <div class="windowheader" id="notesheader">
      <div class="closebutton" id="notesclose">
      </div>

      <p class="headertext">Notes</p>
      <div style="width: 16px; margin-right: 6x; height: 16px;"></div>
    </div>
    <div
      style="background-color: #fff; margin: 6px; border-radius: 12px; width: 520px; height: 480px; padding: 16px; font-family: Courier; display: flex;">
      <div style="background-color: #F9F9F9; width: 520px; margin-right: 16px; padding: 16px; border-radius: 16px;">
        <p style="margin: 0px;">Welcome</p>
        <p style="font-size: 12px; margin: 0px;">06/28/2023</p>
      </div>

      <div style="overflow-y: scroll;">
        <p contenteditable="True">
          <span contenteditable="true">Welcome to <strong>Hacker Notes</strong>
            </br>
            </br>
            <img src="https://cloud-pc8imajxj-hack-club-bot.vercel.app/0img_0837.jpg"
              style="width: 96px; border-radius: 16px" />
            </br>
            </br>

            This is a place where I store my thoughts as they come to mind. What exactly will you find when browsing
            through
            these notes? As I <del>once said</del> <ins>always say</ins>
          </span>
        <blockquote
          style="background-color: #F9F9F9; margin-top: 16x; margin-bottom: 16px; margin-left: 0px; margin-right: 0px; padding: 16px; border-radius: 16px;"
          contenteditable="true">
          <i>Time Will Tell
            </br>
            ~ Thomas
          </i>
        </blockquote>
        <span contenteditable="true">
          I suppose you may see a bit of content about technology. Perhaps some insights regarding recent projects.
          Maybe
          even some thoughts regarding nature & tea? Go and find out!
        </span>
        </p>
      </div>
    </div>
  </div>

Storing Our Content in JS

We're going to be storing our content in a JavaScript array of objects. What data you'll have inside of each object will vary depending on what you're making.

For example, your objects may have a property of music if your app will display different songs for piece of content selected.

An object is a collection of properties (or smaller pieces of data)

{
	title: "Welcome",
	date: "06/28/2023",
	content: `(a bunch of html content in my case)`
}

title for example is a property and "Welcome" is the value of that property.

Note: I used `` instead of " " to ensure that the quotations inside of my html code would not prematurely end the string

Storing our content

We don't want to hard code the content, rather we want the content to be programmatically added to the screen so we can easily change it.

Let's begin by commenting out our HTML code and pasting it into our Java Script object. We'll have an object for each post.

var content = [
  {
    title: "Welcome",
    date: "06/28/2023",
    content: `
              <p contenteditable="True">
          <span contenteditable="true">Welcome to <strong>Hacker Notes</strong>
            </br>
            </br>
            <img src="https://cloud-pc8imajxj-hack-club-bot.vercel.app/0img_0837.jpg"
              style="width: 96px; border-radius: 16px" />
            </br>
            </br>

            This is a place where I store my thoughts as they come to mind. What exactly will you find when browsing
            through
            these notes? As I <del>once said</del> <ins>always say</ins>
          </span>
        <blockquote
          style="background-color: #F9F9F9; margin-top: 16x; margin-bottom: 16px; margin-left: 0px; margin-right: 0px; padding: 16px; border-radius: 16px;"
          contenteditable="true">
          <i>Time Will Tell
            </br>
            ~ Thomas
          </i>
        </blockquote>
        <span contenteditable="true">
          I suppose you may see a bit of content about technology. Perhaps some insights regarding recent projects.
          Maybe
          even some thoughts regarding nature & tea? Go and find out!
        </span>
        </p>
      `
  }
]

(p.s. we're creating an object which is a group of properties and placing that object in an array which is a list of values)

When we refresh the page, our notes page should now have no content.

Programmatically displaying our content

Let's make a function for setting the content.

We need to 1) get where we are placing the content (and make that place identifiable), 2) get the content, and then 3) place the content where it needs to go.

Try implementing it on your own, and if you get lost check the solution below:

Solution (keep in mind I added an id onto the div where the note content goes)

Programmatically Populating our content selector

Currently our content selector is hard coded, but we want this to be dynamic so that it can respond to additional notes being added to the array.

Let's take all of the content out of our sidebar in HTML (because we no longer need to hard code it in)

We need to create a function that accepts the parameter of index (we can use the index of the item to identify it because the index (its spot in the array) is unique)

function addToSideBar(index) {
	(code goes here)
}

Try implementing it on your own, and if you get stuck consult the help below.

  1. We need to get the div where we are placing the content by placing an id on it and then storing it using a querySelector

var sidebar = document.querySelector("#sidebar");

  1. We then need to get the note content from our index

var note = content[index];

note: index is being given to use by our for loop and we're using that index to select the piece of content

  1. We then need to create a new div using the document.createElement function and pass it in the element type of "div" (where we'll be storing our listening inside of)

var newDiv = document.createElement("div");

  1. We need to set the content of this new div we created using the innerHTML property
  newDiv.innerHTML = `
    <p style="margin: 0px;">
      ${note.title}
    </p>
    <p style="font-size: 12px; margin: 0px;">
      ${note.date}
    </p>
  `;
  1. We need to add an event listener to check if it has been tapped (& in which case we'll programmatically set the content)
newDiv.addEventListener("click", function() {
    setNotesContent(index);
  });
  1. & last but not least we need to append it to our div
  sidebar.appendChild(newDiv);
  1. & then finally we need to loop through the function to ensure it is done for every object in the array
for (let i = 0; i < content.length; i++) {
  addToSideBar(i)
}

(a for loop runs a segment of code a given number of times and passes in a number that increments each time the code segment runs)

Woooo, it's working!!! wow correctly displays content

btw if you got confused, here's the complete set of code

Creating Content to Select

I am going to create a sample

Creating content is now quite easy. It actually doesn't involve any code, you can just add it to the array of content & it just automagically works!

Here's how I added to my array of objects (notice now there are two objects in the JavaScript array):

var content = [
  {
    title: "Welcome",
    date: "06/28/2023",
    content: `
              <p contenteditable="True">
          <span contenteditable="true">Welcome to <strong>Hacker Notes</strong>
            </br>
            </br>
            <img src="https://cloud-pc8imajxj-hack-club-bot.vercel.app/0img_0837.jpg"
              style="width: 96px; border-radius: 16px" />
            </br>
            </br>

            This is a place where I store my thoughts as they come to mind. What exactly will you find when browsing
            through
            these notes? As I <del>once said</del> <ins>always say</ins>
          </span>
        <blockquote
          style="background-color: #F9F9F9; margin-top: 16x; margin-bottom: 16px; margin-left: 0px; margin-right: 0px; padding: 16px; border-radius: 16px;"
          contenteditable="true">
          <i>Time Will Tell
            </br>
            ~ Thomas
          </i>
        </blockquote>
        <span contenteditable="true">
          I suppose you may see a bit of content about technology. Perhaps some insights regarding recent projects.
          Maybe
          even some thoughts regarding nature & tea? Go and find out!
        </span>
        </p>
      `
  },
    {
    title: "Sample Text",
    date: "06/28/2023",
    content: `
              <p contenteditable="True">
          Here's some sample text
        </p>
      `
  }
]

Content Selection

WAHOOOOOOOOOOOOO

OUR FIRST APP IS COMPLETE EXCEPT HA NO IT'S NOT!

You saw this coming...

ADDITIONAL CHALLENGE TIMEEEEE

Additional Challenges

Pick some challenges that seem fun & add them to your App

  1. Add a really unique background color and color for your text
  2. Make the top bar of the application change depending on the notes currently open
  3. Make some awesome content for your site
  4. Fix the bug where the menu gets trapped in the top bar when you pull it up too far (either by limiting how far you can pull it up or by making it possible to click through the top bar)

Celebrate

I am so proud of you. I really did not think you would make it this far...

Next time you'll build your own App (based on your own idea). It's going to be a lot of fun. I'm sure you're a bit tired.

Take some rest & return back ready to CONQUER THE WORLDDDD (& build an awesome App that will be fully determined by your own interests for your OS).

(Seriously though, great job!)

Author

SerenityUX
Message on Slack

Resources

Outline

  • Adding App to Desktop