Tagebuch: Dashboard

Ein neues Projekt muss her. Diesmal geht’s um ein persönliches Dashboard/Startseite, ähnlich wie Momentum oder Hero Panel.

Außer unendlich vielen Ideen und einem frisch aufgesetzten GitHub Repository ist noch nicht viel passiert. In der README habe ich meine Motivation, Ideen und einen groben Plan aufgeschrieben.

Angelehnt an die anderen Tagebuch-Threads soll die Entwicklung von Anfang an öffentlich stattfinden. Das eigentliche Tagebuch ist Teil des Repositories, ich werde den Stand aber auch hier (re-)posten.


The journey begins :rocket:

With zero practical TypeScript experience, I’ve had some issues setting up the project, despite using a boilerplate. To get started, I’ve migrated three common JS components from my other app (button, link, icon). I’ve checked some best practices and popular Typescript/React projects, trying to do it the right way™ (e.g. correct types).

I’m really looking forward to experiencing the praised improvement over vanilla JavaScript. My IDE of choice, IntelliJ IDEA, supports TypeScript types for popular projects, so I’ve already got a good IntelliSense even without TypeScript .

The CI pipeline is on and the project is already live (not much is going on, though).

I had to make a decision: what responsive behavior should the dashboard grid follow? There are multiple approaches:

  1. Hero Panel uses pixel-perfect sizings and breaks at 700px into 1x1 widgets. This makes the widgets always look good, as they are fixed-sized. However, the content is simply cut above the breakpoint if it does not fit into the viewport. Also, I prefer seeing more content than a 1x1 widget in mobile view.

  2. Use a masonry layout. This approach makes sure to place all widgets optimally at all breakpoints. This is great for content where the order doesn’t matter. However, on a dashboard I don’t want my widgets to move around auto-magically.

  3. Let the user define the layout for each breakpoint. Meh, too much work for the user.

  4. Make the widgets fluid and break into a single column at 767px (example). Also add a max width to prevent over-stretching the content.

I think that #4 is the best trade-off.

I’ve implemented a simple Dashboard using CSS Grid. The user may define the number of columns and rows and assign a relative width and height for each widget. In the future, this should be configurable within the UI (drag and drop), but for a MVP this is enough.

I’ve implemented the first, very basic widget: Text Widget. It just displays fixed text, nothing fancy. Maybe it can be extended to support some basic formatting options in the future.

Most work happened under the hood. I’ve cleaned up the code and tried to establish a good framework to build upon.

Now there’s support for color themes! I’ve used CSS variables, so it’s easy to switch values at runtime (try out the preview button). There’s also a new shiny favicon, based on Font Awesome 5. Finally, I’ve introduced React’s error boundaries so the app doesn’t crash if a single widget throws any error.

War ich froh als ich damals var und calc in css entdeckt hatte. Vor allem wie einfach damit themes möglich sind. In scss hab ich sowas immer eher schlecht als recht umgesetzt bekommen. Die CSS Variablen haben da schon nen netten Vorteil dadurch dass die von Natur aus cascadierend :slight_smile:

Auf Arbeit müssen wir IE11 unterstützen, deswegen hatte ich bisher noch keine CSS Variablen eingesetzt. Privat achte ich auch einigermaßen auf die Browserabdeckung, aber die Alternativen für dynamische Themes waren einfach zu bescheiden.

Vor allem was cool ist, ist das du einfach abhängig von einem State Werte überschreiben kannst. Hab es mir gerade sehr einfach gemacht.

Ich hab den tollen animierten Border vom Material-Ui nachgebaut (also im Prinzip eine komponente die von 0% breite auf 100% breite wächst und einen Border hat). Jetzt wollte ich, dass der die selbe Farbe wie die textfarbe hat. Diese verändert sich aber z.b. bei Hover. Also definiere ich an der Stelle einfach die Textfarbe neu:

.NavItem:focus, .NavItem:hover {
  --text-color: var(--color-selected);

  color: var(--color-selected);
  transition: 0.2s;

und schon sind alle Kindelemente in der gewünschten Farbe. Und auch wirklich nur für diesen einen Zusand :slight_smile:

I haven’t made much functional progress in the last month as I’ve been mainly working on my other project: Tip of the Day. It is relevant to the dashboard, though, as I wish to connect both projects. The idea is to have a widget which displays a random tip every day (e.g. “country of the day”). I’ve also made some progress under the hood and made the text widget editable (the content is not stored yet, though).

There is a new widget for showing the current date and time. Additionally, the state is now persisted across the sessions. Under the hood I’ve added redux-observable to manage side effects and I’ve played around with the new React Hooks.

The first step for GUI-based dashboard customization is done: the widgets are now draggable/resizeable. The widget selection is still fixed, though, so I should implement a widget drawer soon.

I’ve also added a new Search widget. Right now the DuckDuckGo search engine is hard-coded, but in the future there will be a list of pre-defined providers and also the possibility to define a custom website.

Finally, I’ve replaced most of my (S)CSS files with a Functional CSS approach. I’ve used Tailwind CSS, one of the most popular utility-first CSS frameworks. I really enjoy it so far :slight_smile:

Notice: The state data is stored in the Local Storage, so you might have to clear it if you have opened the website in the past. This won’t be necessary when the project is out of the work-in-progress state of course.