Build log: Making a frame-less news desktop app

Jacob David C. Cunningham
11 min readMay 14, 2020

Technology: ReactJS/Electron/NewsAPI

Repo: GitHub

What was built

This is not what I planned at all, just ran into problems, state issues primarily, but the base part works eg. a frameless/transparent app. The slides are supposed to well slide…

Please note: this API is not free, you can develop with it but eventually you will have to pay or it will stop working I did not realize that.

Useful tips

  • do not develop against a live API especially one that costs money — copy a response and store that as a mock value. NewsAPI is free for developers but capped to 500 req/day.
  • plan your states eg. Alabama, Washington, etc…

Please note: it was coincidental the first article in the news for today in top headlines had Trump in it, I didn’t choose that.

End result

Partial failure, dumb state problems.

Initial thoughts

I have this super neat image/idea in my head. You have this news app that is transparent, so you see an image, then the content under it(basic title/paragraph) and a next slider with settings(gear icon). Maybe it will be more “glass like” for the case of backgrounds being hard to read. But it’s possible! I just looked it up, Electron can do frameless windows.

What do I want this for? A way to tell me if the world ended or not in the morning. The interface just seemed neat when I thought about it.

Here’s a concept sketch. This is a simple thing to build, if you can build an interface/use an API/create a background webworker thing so it refreshes at a given time.

Note: it’s not tied to the task bar, I just envision using it right above the taskbar as a small window

Thankfully this NewsAPI has a developer tier with 500 request limit per day which is plenty for me, I just want to know like “were nukes launched?” or “did the economy collapse”, etc… I have this TTS bot that reads Hacker News to me in the morning as part of my alarm to wake me from the dead(sleep).

The build

This should be straight forward, the only thing is I just have to “turn it on” eg. set Electron to be frame-less and I saw that it is possible.

Steps

  • get API for NewsAPI
  • build interface with sliding transition/fade(opacity)
  • add webworker to self update in the mornings
  • deploy in Electron

Looks like I need to put an attribute, that’s cool, I’ll put that at the bottom always visible. I am concerned with “how good” NewsAPI is, I don’t know if it would be as good as say NPR or something but hey it’s a start and easy to use/consume. After I build this thing I’ll probably lose interest anyway as I’m not a huge news junkie(I bury my head in the sand like an Ostrich).

I will note I’m slightly distracted(cooking) but starting at 6:26 PM a little more tired today than usual but I feel it, I can produce this excrement of an app.

First API call

Oh man this is good, this is perfect/just what I was looking for. It has a title, image and body. I’ll probably apply a personal filter on top of what’s most interesting. Not quite sure how yet, I want to pull the top headlines but may want a specific filter/see certain things first or maybe by some source. From the API response structure there’s no sort of “tags” or something… but the sources you could sort with by basic string matching/filtering with a desired array output.

The interface

So… one thing I’m aware of by this point is the separation of state so that a little re-render in a child does not affect the parent’s state. The parent will call the API once(or a very few number of times) and the UI will change without calling the API multiple times(that would be bad, counts against the 500 limit). You should only call when the worker calls it(next morning) or you hit refresh on the interface.

7:23 PM

This is really easy to make so I’m going to get it done. I’ve done all the requirements before in other projects. The trick is will it be a piece of crap eg. the styling/animations/state management.

I have not used styled components yet but this BEM CSS class attribute pattern here is not really great… it’s not really important here since the app is so simple but you know, best practices.

Just thinking stuff through

500px seems like a good width(smallest Chrome can condense to in non-responsive mode). Hmm… I think 400x500 is an interesting resolution.

I am super burnt with a headache but I’m going to deploy this. Oh yeah, I suppose there should be a reader but this is supposed to just be a quick glance.

Haha guess who. Guess I can’t specify the size of the image. I saw some lag loading it. Yeah it’s over 1MB hmm.

8:04 PM oh yeah… I’ll need two articles to cycle through.

Side note… I don’t want a pre-loader per image, they all have to be ready. I have fiber so I’m not concerned. I’ll just have a central spinner show up, then all of them will appear/be ready(slide interface renders). It is “dumb” since I may not even click through the 20 images… but ehh… EHHH…. EHHHHH. This is me trying to make a rock absorb blood. Oh yeah I’m just going to use Roboto too.

That was great… got stuck in a useEffect loop while using the API… probably a hundred requests right there LOL boom! Of course I could use mocks or set my own API but hey. Sometimes you gotta get burnt.

8:33 PM alright getting into it

8:58 PM hmm it dawns on me, making a slider is not “very easy” as in you have to pre-render the other slides and then do a loop that destroys/feeds itself. We’ll see how far I get with that. PlainJS I could do it fine it’s the react state management part… I don’t know maybe it’s easy we’ll see.

9:18 PM Dumb problem importing font, have done it several times before.

I’m concerned this won’t look like how I imagine it, the “glass/transparent” like look. I’m not much of a designer.

Prototyping in background… my background wallpaper changes on my desktop so I don’t know how well this will look. The text has text-shadow in case. This layout is not attractive I realize that.

9:44 PM Oof I am burnt… is today the day? I keep thinking, I would laugh if I just died, like pathetic, evolution says no. This headache with pain behind the right eye damn… but I’ve just not been sleeping well last couple of days own fault. Also I’ve been staring at monitors like 24/7. I want to take PTO, but it’s weird… since WFH already.

Pulling out that song to get through this. I want this thing, it’s simple. I want it for tomorrow morning, compliment my coffee. “Chinese put up front meanwhile secretly developing ICBM rockets” *sip* like oh that’s nice, next news slide. Disclaimer: that’s a joke.

9:56 PM continuing

I think at minimum I have to render 3(one on left/one on right) depending on which direction you go. Then you need an array cycler to manage the state/hit the ends start over.

10:18 PM

Interesting, what is a function that will return the number before and after it with regards to bounds of an array. This is a time when I gotta pull up JSFiddle or some JS sandbox and write a function on the side. I should put guards for empty stuff… but this is a public API “it’ll never be empty” ha… ha… This is not going to be clean, I’m running out of time and I gotta finish this prototype.

There’s probably some simpler/cleaner way to do this, I also did not test all conditions just start, middle, end.

ehh… gotta grind that Leet Code “accidentally” solve an injected problem from a FAANG company ha jk

I may be getting second wind which is a bad thing… since I need to sleep well today(not free).

Ooh tiny mistake the array above should start at 0. Pretty much this sub-array will be used to pull the matching objects from the array of objects to be rendered. So now I just take that function and drop it into my app.

What is this **** man… set… The… STATE!!! haha

Quick update, this is essentially re-inventing something that already exists… I could have just used slick carousel or something. Yeah… I don’t know, not sure why I didn’t realize that right away(bad foresight). Granted I wasn’t really trying to just dump carousel in here. Yes my slider will be crappier. It’s mostly the aesthetic(lack of) I was after, I had this “3d-like glass hologram” thing in my mind but alas… I’m limited by the technology of my time(drawing stick figures in black/white).

This brings back memories of my front end job. The ones on the left/right won’t be visible, I just kept them on for the screenshot.

11:04 PM

Ooh… what’s also nasty is the react state update… hmm. I may be doing some faking with css… the DOM will actually disappear after slide/fade back in after updates.

Ha check it out, there’s undo/forward in the dom inspector, interesting.

The ol’ Ctrl + Y and Z

Oh man this state is super F’d lol, what is happening, how does it even shift down.

heh

Oh one of my translates was Y and not X ha.

11:37 PM oh no I’m losing state, am I solid or a liquid?! Expecting end of array but getting -1 I see, that’s what testing is for. Oh no it’s because I took out the returns/values overwriting in the getNextArticleIndex

Ooh… it was a bad idea to use the “toggle” of “same class” through setState as when you try to move left again the render isn’t called since state technically didn’t change…

12:58 AM

Well that was pretty bad, my power supply actually shat the bed. Luckily I had another desktop I could steel the power supply from that one, the watt output is almost the same, just it’s a bit big for the case. Lucky me no data loss.

So right now I’m fighting a dumb state/conflict issue where the 3 slides(array) has to update but also get the “slide-left” class applied to them, so the new slides move left… it’s bad, problematic… this is another thing I’m not good at yet is decoupling UI states from logic states.

The one positive thing about that is all my tabs are just blown away. Since that chrome extension tab manager app I have planned(to tie into the cross platform app) is not finished yet… well, blank slate.

Currently trying to deny state render given condition, anti-pattern but I’ve seen it done before. But I think that was with class-based components hmm…

Well I’m going to have to move past this, I can cycle through the articles… I just don’t have the pretty slides… I’ll have to work out that state clash issue.

The Electron part

Since I’m out of time, I’m going to just do the install of Electron, then steal the main.js file from my cross-platform-app and it should work. It just maps to a build folder from React, I’ll probably have to change the path a little. This is what you get for not planning.

I like how when you get desperate you just strip out all the luxury and get something built.

So yeah all I had to do was run:

$npm init

$npm install electron --save-dev

$npm install electron-packager --save-dev

The init specifies the name of the Electron app.

Make the main.js file

I’m going to build the current reactjs code so I can inject in the Electron build. This is an example from the cross-platform-app how it binds/maps to the static build of reactjs from Electron.

The electron-packager lines in the package.json come from here.

Oh and in the reactjs package.json you need to specify the “homepage” entry to be just “.”

Huh… this time it didn’t work says Not allowed to load local resource: hmm. Nvm I had a nested folder inside reactjs unlike the cross-platform-app.

Omg I’m so close! But I can’t move the window lol… it’s possible though.

I took that blurry shot Sony Nex-5n mmm

The text will need work, it is hard to read despite being “cool”.

Moveable by a CSS class but have to apply it to body so hover on image works I think

Oh crap I lost the hover/show arrows… probably related to that webkit class I applied.

Usable… needs design tweaks

I think this is fine for now, it’s kind of ugly though… you’re inclined to drag the image, not the body…

So I’m just going to actually tie the refresh event to pull from the API and pull all the articles. There’s no image preload, no transitions, it sucks… but I can use it later today.

Still it’s cool I’m glad this is possible the frameless/transparent window. I’ll finish this and then record a new short video… but it’s petty much going to function the same but not be using the stored local data.

Oh dang there’s an error condition too where the article has no image hmm. I’ll add a basic image check for now, that’s the most important thing aside from the content itself I suppose or title. Tried to squeeze in a basic setInterval auto clicker but the state is wrong again ugh.

I’ll just package this real quick so I run it off an .exe

Update 05/16/2020

Well I spent some extensive time getting a slider to work in ReactJS. I still have not quite gotten it down yet, this is the closest one. When I applied this code to the actual news slider… it was problematic, I think because the photos have to load/get rendered as they’re getting re-painted vs. the simple div with a letter in the middle in the sandbox example above. So… as someone that was checking out my code thought/assumed initially that I was just sliding the entire slide. I will do that. I’ll render all 20 slides or whatever in a row where you only see one snippet at a time and then the react state updates as you click on left/right by sliding the row left/right.

That’s the idea anyway…. we’ll see if it works. I’m quickly losing interest in this, I mean state management is something I have to get down. And I guess I’m bad at ReactJS at this time where I can just build it in plainJS but the state management in ReactJS is not coinciding with my intent.

Yeah I don’t want it to re-render just slide… move over.

Yeah this is super ugly… a slider should be infinitely going not have ends. But if I was to shuffle the array I would again run into the problem of collision between the sliding state and the array state. This is literally just increase/decreasing a translate percentage applied to each slide, it should have been to the global parent container but it works fine. Anyway it’s supposed to be automatic/running in the background so personally it’s fine for me/not bothering me if it starts over until it self-refreshes.

Wow setInterval is super screwed up if you leave it running long enough. I’ll just use a web worker as I made one before.

I did not factor in manual override sliding so you can have the edge case of timer is at 8 second and you just moved forward so instead of waiting another 10 seconds before sliding forward, it will slide forward in 2 seconds.

Hahaha…. I don’t know what’s happening anymore. A state variable I set is still empty whether I globally access it or pass it in as a parameter. I guess it’s my web worker making the component refresh or something… I don’t know.

--

--