Skip to main content

Overwriting Property Types in TypeScript

· 14 min read

the library in the morgan museum, new york The Morgan Library Museum in New York. Photo by Silviu Alexandru Avram

TypeScript is a great alternative to JavaScript if you feel the need for that extra safety net of strong typing. Most of the tyme, TS is pretty straightforward, as we are familiar with strong type languages like Java. However, when we do require a tiny bit of dynamic type magic, things can stop being straightforward, and we can end up being very creative. But when we actually get the job done and even improve on the result, we realise how strong TS can be, and we are super thankful for its existence.

In this article, we are going to touch concepts like TypeScript as a language in general, but also Generics and some TS utilities that are available globally. Solving the problem below helped me understand TS better, and I hope it helps you as well. Let's begin.

The Use Case

The JS code below is the one that required some creativity from my part, when improving Typescript types for downshift. For simplicity, I removed some React specific details, since they are not relevant to the topic.

function getToggleButtonProps({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
} = {}) {
function toggleButtonHandleClick() {
dispatch({
type: stateChangeTypes.ToggleButtonClick,
})
}
const toggleButtonProps = {
[refKey]: handleRefs(ref, toggleButtonNode => {
toggleButtonRef.current = toggleButtonNode
}),
'aria-controls': elementIds.menuId,
'aria-expanded': latestState.isOpen,
id: elementIds.toggleButtonId,
tabIndex: -1,
}

if (!rest.disabled) {
if (isReactNative || isReactNativeWeb) {
toggleButtonProps.onPress = callAllEventHandlers(
onPress,
toggleButtonHandleClick,
)
} else {
toggleButtonProps.onClick = callAllEventHandlers(
onPress,
toggleButtonHandleClick,
)
}
}

return {
...toggleButtonProps,
...rest,
}
}

Our function, getToggleProps, receives some props as an Object, which is destructured directly.

  • we are using an empty object as default parameter (= {}), otherwise our destructuring will fail for undefined. Extra safety.
  • we are grabbing a few properties from the object, such as onPress, onClick, ref and refKey, as we are using them in our function.
  • we are using a prop without grabbing it from the object, rest.disabled.
  • we are returning our computed props as toggleButtonProps, along with rest, which are the rest of the props we did not change. We bundled them together by object spreading and returned them.

The Goal

Since this function is written in JS, in order to convert it to TS, or at least provide TS types for it, we need to define the types for both the function parameter and the function return value. The function's purpose is to return attributes that are going to be applied to a HTML button element, but not always. It could be a React Native button as well, or a custom React button component from any UI Library. Consequently, our types requirements are the following:

  1. The parameter should accept HTML button props, in the case of an HTML button, or any custom UI component that also accepts HTMP button props.
  2. The parameter should accept refKey, a string prop used for those rare cases where the component we are passing toggleButtonProps to has a different name for the ref prop, for instance innerRef.
  3. The parameter should also accept an optional onPress, in case we are in the context of React Native.
  4. The parameter should also accept any prop that needs to end up on the element, by being passed through with the rest object.
  5. The return value needs to return the props that are being computed and guaranteed to be returned in toggleButtonProps: aria-controls, aria-expanded, id and tabIndex.
  6. The return value needs to optionally return either onClick or onPress, depending on whether we are on React Native or not.
  7. The return value needs to return those props from #4 that could be anything, but we should also include their type in the return type.
  8. In case there is a type overlap between a prop from the parameter and the one from the return value, the parameter prop type wins.
  9. We cannot do anything for refKey, since that can be any string, with a 'ref' default, so the most we could do here is an optional ref prop.

Implementation

Let's nail the easy static types first, then we will work towards the dynamic override aprt.

HTML Button Props

The parameter should accept HTML button props, in the case of an HTML button, or any custom UI component that also accepts HTMP button props.

For this first part, the implementation is really simple, we just need to make the parameter accept HTMLButtonProps.

function getToggleButtonProps({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: React.HTMLProps<HTMLButtonElement> = {}) {
// implementation
}

The generic-based React.HTMLProps<HTMLButtonElement> is a great way to achieve our goal, since it will return all the props that could end up on an HTML button. And all of them are marked as optional.

Very easy so far, but there's one problem. TypeScript will complain about refKey, since the prop is not part of React.HTMLProps<HTMLButtonElement>. And there's also onPress. That's not part of the HTML Button either, since it's a prop specific to React Native. Let's fix that.

The refKey Prop

The parameter should accept refKey, a string prop used for those rare cases where the component we are passing toggleButtonProps to has a different name for the ref prop, for instance innerRef.

In order to fix our code, we can just add the two props with a type intersection, like so:

function getToggleButtonProps({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: React.HTMLProps<HTMLButtonElement> & {
refKey?: string
} = {}) {
// implementation
}

Done! Now the props are the intersection between the button props and the ref type we just created, the only thing we need to accept is onPress.

The onPress Prop

The parameter should also accept an optional onPress, in case we are in the context of React Native.

The most obvious fix would be to add onPress to the type we just created to support the refs.

function getToggleButtonProps({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: React.HTMLProps<HTMLButtonElement> & {
refKey?: string
onPress?: (event: React.BaseSyntheticEvent) => void
} = {}) {
// implementation
}

For simplicity, we are using React.BaseSyntheticEvent, which is goint to be a common interface for both web and native event handler props in React, since we don't plan to also import React Native types.

The errors are gone and we handled the first 3 use cases, which is great. Since we may want to support other functions as well, not just for toggle buttons, we may want to split the above type into several, which could be used independently. Also, we may want to extend these types, so we should consider using interfaces instead of types. Consequently, our code will become:

interface GetPropsWithRefKey {
refKey?: string
}

interface GetToggleButtonProps
extends React.HTMLProps<HTMLButtonElement>,
GetPropsWithRefKey {
onPress?: (event: React.BaseSyntheticEvent) => void
}

function getToggleButtonProps({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: GetToggleButtonProps = {}) {
// implementation
}

Now the refKey part is abstracted away in GetPropsWithRefKey, and can be used by other functions, while the button specific types are bundled together in GetToggleButtonProps, along with the refKey part, through extension.

Pass-through Props

The parameter should also accept any prop that needs to end up on the element, by being passed through with the rest object.

Now comes the hard part. We want to accept anything else the user may need to pass through our function, but still keep our previous GetToggleButtonProps definition for the props. Since we have no idea what the user is going to pass in addition to the types we already defined, we will use a generic type, which we will intersect with GetToggleButtonProps, such that it will include stuff from both. Let's actually write it down:

function getToggleButtonProps<Rest>({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: GetToggleButtonProps & Rest = {}) {
// implementation
}

Rest can be anything, and it does not have to be specified directly when calling the function. For example, this call will be considered correct:

function onClick() {
console.log('clicked')
}

const toggleProps = getToggleButtonProps({onClick, foo: 'bar'})

onClick is part of the GetToggleButtonProps interface, while the foo string property is part of the Rest, and, according to the function implementation, it will be passed directly to the return value. The Rest generic will be super valuable when defining the return value type, as we shall see in a moment.

Guaranteed Returned Props

The return value needs to return the props that are being computed and guaranteed to be returned in toggleButtonProps: aria-controls, aria-expanded, id and tabIndex.

Of course, this part is the easy one, and we will create an interface that defines the props above and their types, according to the implementation.

function getToggleButtonProps<Rest>({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: GetToggleButtonProps & Rest = {}): {
'aria-controls': string
'aria-expanded': boolean
id: string
tabIndex: -1
} {
// implementation
}

Each property is defined as non-optional, since it is guaranteed that we are returning it in the returned object. We can also be super specific with our types, for instance tabIndex is -1 instead of number, as we are going to always return -1, while the other properties are dynamic.

Optional Event Handler Props

The return value needs to optionally return either onClick or onPress, depending on whether we are on React Native or not.

Let's also add the couple of optional handler props and also abstract the whole return value prop into an interface.

interface GetPropsWithRefKey {
refKey?: string
}

interface GetToggleButtonProps
extends React.HTMLProps<HTMLButtonElement>,
GetPropsWithRefKey {
onPress?: (event: React.BaseSyntheticEvent) => void
}

interface GetToggleButtonReturnValue {
'aria-controls': string
'aria-expanded': boolean
id: string
onPress?: (event: ReactNative.GestureResponderEvent) => void
onClick?: React.MouseEventHandler
tabIndex: -1
}

function getToggleButtonProps<Rest>({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: GetToggleButtonProps & Rest = {}): GetToggleButtonReturnValue {
// implementation
}

Looks great! We now have interfaces for both the function parameter and the return value. We are almost at the finish line.

Rest in the Return Value

The return value needs to return those props from #4 that could be anything, but we should also include their type in the return type.

Now it's time to use again the Rest generic we defined previously, and include it in the return value, since it contains the pass-through props. We will use the intersection here, again.

function getToggleButtonProps<Rest>({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: GetToggleButtonProps & Rest = {}): GetToggleButtonReturnValue & Rest {
// implementation
}

Now, everything extra that is passed as rest will be reflected in the type for the return value.

TypeScript VSCode snippet reflecting the rest prop being present in the return value

We just crossed the finish line with half a leg.

Prop Overrides

In case there is a type overlap between a prop from the parameter and the one from the return value, the parameter prop type wins.

Suppose that we want to make our toggle button focusable and add it to the tab order of the page. We will need to pass tabIndex as 0, or any other positive value (big anti pattern, but you can). With our current type definitions, if we pass tabIndex: 0 as a prop to the function, the return value type of tabIndex will stay as -1, since that's what we defined in the GetToggleButtonReturnValue interface.

TypeScript VSCode snippet reflecting the tabIndex prop type being -1 though it has the value 0

Sure, we can just make the type to be number and move on, but that's not what we are actually returning by default. And it's not just about the tabIndex. We can have, for instance, another prop returned by default, such as aria-haspopup, with a listbox default value. But what if the user needs to display the popped out menu as a modal? They would need to pass aria-haspopup: 'dialog' to the function, and the return type for aria-haspopup should reflect the parameter type.

For this reason, we need to create a type that overrides the type we define by default for the props that are passed as parameter and have a different type. Of course, this is not required if those props passed as parameter are destructured away from rest, and in this case we can keep our own type, as the value won't be overriden by pass-through. It's not the case for tabIndex, so we need to override the type here. And the type definition I found to solve the issue is the following, from this thread:

type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U

Whoa, whoa, what? Ok, let's try to remember what we want to achieve. If we pass a prop with the same name as the function parameter, then it should override the type from GetToggleButtonReturnValue.

Let's consider GetToggleButtonReturnValue to be T and Rest to be U. Overwriting T with U means picking from T only the prop types that are not common between T and U. We exclude from T the props from U, which means there will be no common props as a result of this exclusion, and then we pick these exact props from T. Finally, we intersect these non-common props with U, giving us back the common props (if any), but this time with the types from U. Remember, U is Rest, our pass-through props type.

Consequently, our return type will become:

type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U

function getToggleButtonProps<Rest>({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: GetToggleButtonProps & Rest = {}): Overwrite<
GetToggleButtonReturnValue,
Rest
> {
// implementation
}

And voilà, the result:

TypeScript VSCode snippet reflecting the tabIndex prop type being number in the returned value due to type override

Also important to point out, due to the current type of the parameter GetToggleButtonProps & Rest, you cannot pass just any type to the properties that are statically defined, such as tabIndex, onClick, refKey and the others. Passing a number for the onClick prop will fail since it's clearly defined in the React.HTMLProps<HTMLButtonElement> as a function with certain parameter types. You could pass tabIndex as 0 due tot the fact that it's a number type in the React.HTMLProps<HTMLButtonElement>, even though we made it -1 in our return type, as a result of our function implementation.

The Ref Prop

We cannot do anything for refKey, since that can be any string, with a 'ref' default, so the most we could do here is an optional ref prop.

This is going to be our only limitation. Passing a custom string as a refKey will not reflect a property with the key as that string value in the return type. There is no way (that I know) to get the string value from an object key and use that as a key in a type. Consequently:

TypeScript VSCode snippet reflecting the customInnerRef string value for refKey not ending in the return type

There's no customInnerRef property in the return value, just the ref optional property that is going to be passed by default, in case we don't pass any value for refKey (refKey = 'ref',).

Conclusion

In this post, we went through defining static types for a function's paramater and return value, as well as allowing dynamic types to override previously defined static types, where such a case was needed. We also defined an initial set of expectations, starting from a working example, then we went through the use cases one by one and altered the solution accordingly. We also saw a few usages of TS helper types, such as Pick, Exclude and others.

Improving the Types in Downshift was a great experience, as there were quite a few use cases to consider for the getter prop functions. I found the experience so useful that I considered to write in detail about it, and I hope you will find it useful in some way as well.

Malta 2023

· 8 min read

view of the valetta harbour entry Photo by Silviu Alexandru Avram

Who would have thought that Malta during August is so hot and humid? If you voted "not Silviu", congratulations, 10 points to Gryffindor.

I can't say Malta was on my bucket list this year, or for the next few years. But hey, I could say the same for Perugia and Oslo, and look how that went. For lack of better words, 2023 has been spontaneous in terms of travelling. And it's only just September.

But back to the island in question. For such a small place, Malta is packed with things to do. Wondering through narrow streets in the old towns of Valletta and Mdina? Checked. Eating seafood on the waterfront of Marsaxlokk? Checked. Going for a boat ride to ... anywhere, really? Not checked, but you always need a reason to come back, right? Well, I don't know, it may be so, since I never got to see the Last Supper and I've been to Milan three times already. The 4th time's a charm, as they say.

But back to the island in question, again. We only got to see a handful of places, true, but the trip was really short to begin with. And that wasn't actually the worst part. Who would have thought that Malta during August is so hot and humid? If you voted "not Silviu", congratulations, 10 points to Gryffindor.

And, just like that, my list has ran out of complaints.

Valletta

The old city is just so beautiful, authentic and unique. I had a feeling that the whole scenery there just fits the place perfectly. The only other city where I had this same feeling is Venice. There was nothing out of place, the hustle and bustle seemed so natural, and it was so easy to blend in. I felt that everyone had something to do no matter what their purpose or personality. There were sights to see, ice cream to eat, Starbucks to enjoy, speciality coffee shops to enjoy arrogantly, stores to shop, restaurants to eat out and bars to drink. We did most of these things, as there was no more free space in our bags to buy and pack anything extra.

Valletta Sea ViewValletta Street
valletta sea viewvalletta street

First things first. The entrance to the old city is spectacular. The Triton Fountain, followed by the City Gate, is Valletta's way of saying that it was worth the effort. And it's not just all mouth and no trousers. Once inside the city, you feel like you're in another world in another century. As I already mentioned above, it felt unique, and that everything blends in with the island. Our hotel was just between the city gate and the main attaction, St. John's Co-Cathedral. Sadly, we had to postpone going inside, since there was a queue already in front of the church when we arrived, and melting in the sun waiting was a bit extreme for us. From the outside, though, the cathedral is imposing, but it is said that the interior is way better. Top of the list for the next trip, I guess.

What the city lacks is the amount of trees and shade, given the general lack of real estate. Consequently, the Upper and Lower Barrakka Gardens feel like a couple of oases on the outskirts of the desert. There are some larger parks near the old city as well, like the Mall or the Argotti Botanic Gardens, just in case you need more greenery. There are, of course, more sites to visit in Valletta, but we tried not to rush for a full day of attractions, given the fact that we also planned to visit Mdina during the second part of the day. What definitely won our hearts was the Valletta architecture, with warm honey limestone buildings boasting ornamental balconies known as gallarija.

Upper Barrakka GardensThe Triton Fountain
upper barrakka gardenstriton fountain

I strongly recommend a couple of places to go while in Valletta. Firstly, if you enjoy cocktails as much as me, definitely check out Kamy Cocktail Bar, and try some of their own trademark cocktails. The standard ones are not that impressive, or maybe my Margarita is just out of this world. The owner of place is a proud Liverpool fan and has a good taste in music, apart from the fact that he knows his cocktails. And secondly, if you're in love with coffe like myself, try Coffee Circus Lisboa, for great speciality coffee and Pasteis de Nata. Their cold brew is fantastic. The Pasteis, I've had better, but only in Lisbon. Which reminds me of my upcoming Lisbon trip, and I'm going to be all over those cakes.

Mdina and Rabat

Famous for the castle, the narrow streets and the blue door on Instagram, Mdina is a must see. The nearby Rabat is also quite nice, as it shares the narrow streets theme with its fortified neighbour. We explored the cities during the second part of the first day and it was just so much better outside. I believe the air is not as humid there, otherwise I cannot explain why it felt significantly better than the capital. The towns are also a short ride by bus from Valletta, plus there is always the cab option. The buses have air con, and the Ubers are not expensive at all, which helps a lot if your itinerary involves a lot of moving around.

Mdina Street ViewMdina Blue Door
mdina street viewmdina blue door

The famous blue door is not the only picturesque spot in Mdina. There are other colorful doors as well. And the buildings are also well maintained and tastefully built. It's the kind of place where James Bond would get away from his job with Madelaine. Just go through the gate with the Aston, drive casually by St. Paul's Cathedral, park outside the house near Wesgha Ta' Sant' Agata, grab ice cream, and enjoy life. Speaking of the cathedral, we happened across a wedding there, and we waited to see the bride as it brings good fortune.

The Three Cities and Marsaxlokk

The second day was hotter than the first, so we made the obvious decision and went for a walk to the Three Cities. Vittoriosa, Senglea and Cospicua are also a must see while in Malta, and they are only a short bus ride away from the capital, just across the Valletta harbour. We got off in Cospicua and went by foot towards Senglea until we reached its northern end and the Safe Heaven Gardens. There are quite a few scenic spots here, where we could admire Valletta in all its splendor. Senglea is particularly beautiful and has a romantic gateaway kind of vibe, with small boutique hotels, restaurants by the waterfront filled with boats, big and small, old and new.

The third city, Vittoriosa, is actually the peninsula next to Senglea, boasting the impressive Fort St. Angelo, the fortified city of Birgu and its harbour full of luxury yacths and super boats. The walk was very relaxing, and if the weather would have been cooler, I think it would have been absolotely perfect. Not sure if I mentioned this, but maybe not go to Malta in the summer. We went for a coffee break at the Cafe Riche and then ordered a Bolt to Marsaxlokk.

Senglea HarbourMarsaxlokk Harbour
boats in the senglea harbourboats in the marsaxlokk harbour

This small fishing town on the Western Malta coast is a great place to go for dinner and enjoy a fish or a seafood course right next to the sea. The harbour offers great views, but this time it's mostly filled with fishing boats rather than luxury yachts. There is also one of those big LNG ships anchored here, and it's quite visible from the shore. It's the first time I've seen one in real life, and I immediately recognised it, due to its recent popularity. As the sun set, we went for dinner, then took a walk to the beach, and in the end waited for the bus to Valletta and called it a day.

Final Thoughts

Malta is a great place and I am super happy to have been there. Without a doubt it deserves at least one more visit, since it has so much more to offer. There's also the Blue Grotto, the town of Zurrieq, the catamaran ride to the Blue Lagoon, the megalithic temples and the list continues. Apart from the weather in the summer, there was absolutely no inconvenience whatsoever, there is always something to do, somewhere to go, public transport is great and overall it's not very expensive. Definitely a place worth checking out, by all means.

Oslo 2023

· 7 min read

oslo opera, photo by silviu alexandru avram Photo by Silviu Alexandru Avram

  • Q: Do you know what is better than the current trip?
  • A: The next one.

It's a very catchy slogan by Delta, used in the commercial you are required to watch before the movie starts on the flight. The annoying part is that you have to view it every time a movie starts. The good part is that they are right.

My US trip was coming to an end and I was actually glad to be returning home, after almost 3 weeks of being spoiled by the American Dream. Snap back to reality, Marshall.

That being said, the magical date of the 1st of May was inching closer, and it's very common to celebrate it while on a trip. The most popular way is to do it is a trip to the seaside, but I was never a big fan of that. Instead, I am a big fan of city breaks, and even though I was expecting most people to chose the seaside or the mountains for their mini vacation, I also expected that the plane tickets to be sold out by that time. Still, it was worth a try, so I checked Skyscanner and, to my surprise, there were quite a few options with very good plane ticket prices, the best being Bologna and Oslo.

Both were places I've never been before, so that got me quite excited. But which one to pick? Sure, Bologna was going to be quite a sure shot, as Italy is always a good idea, as I've been there so many times and it never disappointed.

On the other hand, I've never been to a Northern country, not even Denmark. Consequently, the drive to try something new won, and we picked Oslo as the winner, bought tickets, and breathed easier, knowing that our 1st of May already planned for.

Oslo by foot

I prefer walking when I'm on a trip, and Oslo was not going to be any different. The city is very convenient for walking, with wide sidewalks, coffe shops , quite a few parks, and a waterfront. The waterfront areas are very sought-out places in Oslo, both for walks, but also for living. There are quite a few of neighbourhoods that were placed directly next to the water. Some areas also had construction sites going on, with new apartment buildings about to rise tall.

As you would expect, these neighbourhoods have a very modern feel, with contemporary style apartment buildings and offices, underground parking spaces and restaurants on the first floor. I would probably not choose to live in these kinds of places, as they seem to me quite soulless, but that's just me. On the other hand, I do appreciate the architectural style of modern apartments next to water canals, like a Venice built in the 21st century. Or Hamburg, even though it has its own unique architectural flavour, which I found quite impressive.

Oslo OperaOslo Canal View
oslo operaoslo canal view

One such place is Tjuvholmen, and Tjuvholmen has quite a lot to offer. It has canals with parking space for boats. It has the modern apartments and offices, some still in construction. It has a museum. And it has one restaurant that serves great Norwegian salmon courses, from sushi to grilled. The restaurant is called, well, The Salmon. You wouldn't want to make any mistake when going there. We surely did not, as the food was amazing. They know their salmon very well, so if you're a fan, this should be a non-negotiable stop.

Another neighbourhood is Sorenaga, just behind the Oslo Opera building. It's a very nice place for a walk during sunset and enjoy the sea view at the same time. Turning around and going on the 162, there's the Microsoft building. Hello, dear employer. Turning left and going back towards the Opera house, we went through Oslo's office district, which, unlike most such districts in other cities, this one was conveniently placed next to the city center. The modern neighbourhood theme continues here as well, with a focus on office spaces, even though there were many apartment buildings as well. The perfect place if you feel like living right next to your office and and have your commute in your pijamas.

SørengautstikkerenOslo City Center
Sørengautstikkerenoslo center

Of course, there's also the city center, with quite a large number of bars, usually packed in the evening. Overall, it's your usual European city center, with an abundance of choices for walking, shopping and drinking. I particularly enjoyed the street leading up to the Royal Palace, Karl Johans Street, with Norwegian flags hanging everywhere from the buildings, left and right. I did not enter the palace, but did walk through the surrounding gardens and admired the various statues and monuments placed there.

Continuing towards the Northeast, through the Uranienborg, a very upmarket neighbourhood, there's Vigeland Park. Not surprisingly, I found the park to be quite unusual, given the sculptures laying around, showing different human feelings and stages of life. These sculptures are impressive, not doubt, but they may not be everyone's cup of tea, as they show things like people crawling on top of each other and screaming parents throwing away their toddlers. Life is beautiful, but it's not all raindows and unicorns, and the Vigeland sculptures serve as a artistic reminder of that.

Oslo Museums

Even though we visited Oslo in May, the weather was totally not exactly May-ish. It rained quite a bit, and the evenings became pretty chilly. Consequently, we considered going to enjoy some of Oslo's museums, and, fortunately, there is no shortage of that. The first pick was The Norwegian Museum of Cultural History. It's the Norwegian equivalent of our own Muzeul Satului in Bucharest, displaying a large number of buildings that made up rural Norway. The building collection includes living houses, churches, stables and grain depots. In addition to the buildings, there is also an exhibition with religious objects, clothes, furniture and decorations.

Also very impressive is the Fram museum. No, it's not the polar bear, but it's probably one of the most interesting museums I've ever been to, as it includes the actual Fram exploration ship. The whole museum is actually build around the ship, which is restored beautifully on the outside and you can also check it out on the inside, with living quarters, cabins, kitchen, the main gathering hall and storage areas. It is probably the most important museum to visit in Oslo, as I don't believe there are many like it.

Fram MuseumMuseum of Cultural History
the fram museummuseum of cultural history

On the more convetional side of museums, we went to the National Museum, which includes a very impressive collection overall, not just works of Munch. It include a large amount of paintings, architecture and design objects, and it's definitely worth its ticket money. Of course, there is also the Munch museum, but, unfortunately, we could not fit it in our itinerary, given the short stay. Next time it should be number one on the list.

Final Thoughts

Overall, it has been a very short trip, but, to be honest, it was enough. Sure, Norway is definitely a place where I would return, but next time it might be more about nature and less about city breaking. I'm super happy with the trip, since it was something different and quite refreshing from my usual Italian city breaks. If you are looking for salmon special, definitely check out Oslo, and with that bad joke, it's time to end. Happy travels!

Seattle 2023

· 8 min read

seattle waterfront, photo by silviu alexandru avram Photo by Silviu Alexandru Avram

We're back in Seattle, baby, and this time we're spending a full week here, not just some silly 3 business trip days. And the best part is: it's only vacation. A full week in tech heaven #2, the land of Amazon, Microsoft and, of course, Starbucks. I just wish I packed un umbrella.

Ballard

Ballard neighbourhood was going to be my home for the week, and a change of scenery from Jersey City was to be expected. No more skyscrapers. No brownstones. Only houses, and lawns, and gardens, and more houses. And that presented a great opportunity to continue my burger-and-fries-burning morning runs, which, by now, turned from optional to necessity.

Situated on a hilly landscape, with Shilshole Bay to the west, Ballard is a nice and cosy place to live. I explored it quite a bit, reaching its outskirts with long runs and walks: the bay to the west, Whitman School and Golden Gardens to the morth, Carl S. English Jr. Botanical Garden to the south and Woodland Park to the east. The neighbourhood is a low density residential area, with many great looking houses. Most of them had thoughtfully arranged gardens in front, and none were identical. Because of the rainy temperate climate, the place is a greenery, with an abundance of cherry trees, magnolias, shrubbery, flowers and even succulent plants, where the soil became rocky.

Ballard HouseBallard Cherry Trees
ballard houseballard cherry trees

In Ballard downtown I found a few places to enjoy a coffee or lunch out, even though the area is pretty small. There was no queue at the local Salt&Straw, to my surprise. Unfortunately, after I had my double scoop cone, I immediately understood why. It wasn't really like the one I had in LA or San Diego, or maybe gelato tastes better in California. I don't know. It was not all negative though, as I discovered a very good tea place, Miro Tea, and, most importantly, a local bakery, Tall Grass Bakery. As a result, mornings became very sweet.

Outside the center, there is also Ballard Coffee Co. with pretty decent coffee, and Un Bien, a Caribbean Restaurant, which is not really a restaurant, more like a counter to order food from, and a couple of wood benches where you could choose to "dine in". But the food was absolutely amazing. I ordered a Caribbean Burrito and only half of it was enough to make me feel full, which is not something that happens often. Also great is Mainstay Provisions for coffee, and The Dish, a classic American Diner but with a Central America twist to it. Blueberry pancakes with butter and maple syrup? Yes, please!

Outside Ballard

Even though I was expecting to rent a car in order to get around, I found that public transport is actually good enough, both for going to the airport and for moving between the downtown and back home. However, most of the time, I chose to walk between Ballard and other objectives, especially when going back, since there was no need to rush.

Carl S. English Botanical GardenDiscovery Park
carl s. english botanical gardendiscovery park

One of the places I enjoyed most is Discovery Park, which is bordering Ballard to the South, next to the coast. In order to reach it, I walked through the Carl English Botanical Garden and, since the weather was pleasant and the garden quite nice, I spent some extra time strolling its quiet alleys. Continuing the journey, I crossed Salmon Bay by Ballard Locks, then the train tracks by a suspended bridge, and headed through the woods towards Discovery Park. I was fortunate enough to pass through woodlands when, inevitably, it started to rain. Eventually, I reached the park and went for a very long and chaotic walk until I reached the coast. It stopped raining, for the moment, but the wind made it impossible to relax for more than 2 consecutive minutes. Nevertheless, the coast is a sight to see, with Mount Olympus in the background, and the lake in between. Equally beautiful is the West Point Lighthouse, which was used, as I later found out, as the logo for the Lighthouse Roasters coffee shop in Fremont.

Speaking of Fremont, I crossed it a few times on my way from Downtown or when I went to visit the University of Washington campus. The neighbourhood is pretty similar to Ballard, althouth a bit more hilly. Right next to it, there's Woodland Park and, at the end of it, there's Green Lake. The park itself is, as its name suggests, a stretch of woodland, without much human intervention, except some alleys. The lake is pretty big, big enough to be used as practice by rowing teams. I popped up just in time for such a session, and it was great to watch them train while the coach was providing motivation using a loud tone.

West Point LighthouseUniversity of Washington Building
west-point-lighthouseuniversity of washigton building

After a long walk westward through Wallingford, I eventually reached University District and the University of Washington campus. I was curious to see the difference between it and the Columbia campus back in NYC. Not surprinsingly, this campus was bigger, with plenty of space for buildings, dormitories and parks. Luckily, the cherry trees theme continued here as well, and I bet I was not the only imposter in the campus taking pictures. I made a relaxing round tour of the campus, decided I was too cool for school, and headed back to Ballard via the 45th Street.

Other places worth mentioning are the Myrtle Edwards and the Centennial Parks, both on the coast of Elliot Bay, and the Volunteer Park, where Bruce Lee is buried. Finally, there's Snoqualmie, where we went for a short road trip to the Snoqualmie Falls, a pretty popular stop outside Seattle for both locals and tourists.

Downtown

Honestly, Seattle Downtown was my least favorite part of the city, but I enjoyed a few places nevertheless. Of course, there's the number one attraction, the Space Needle, but I have already been there in 2019, so this time I went straight for the museums. They are, without doubt, worthy of visit, as they display impressive art collections. My first visit was to the Chihuly Garden and Glass Museum, and it was a blast. The colorful glass works are trully remarkable, and the level of detail for every piece of art is incredible. Luckily, I arrived just in time for a live demonstration, where a couple of artists were creating a glass in front of an audience. It wasn't a Margarita glass, but very good looking nonetheless.

The Chihuly Garden and Glass MuseumThe Seattle Great Wheel
the chihuly garden and glass museumthe seattle great wheel

My second visit was to the Museum of Pop Culture, which features collections from so many areas that makes pop culture, such as rap music, horror movies, indie video games and rock bands. The horror movies section was pretty cool, since it contained props from many popular movies, such as the axe from the Shining and the Alien costume from, well, the Alien movie.

Last museum for me, but not least, was the Seattle Art Museum, with the good old established array of pieces such as paintings, pottery and sculptures, from different locations and time periods. My favorite piece was a painting from 1882 by Cleveland Rocknell, the Smokey Sunrise, Astoria Harbor. Probably the first painting, so far, that I wanted to look at for more than 2 minutes.

Smokey Sunrise, Astoria Harbor, by Cleveland Rocknell
smokey sunrise, astoria harbor, by cleveland rocknell

Apart from the museums, there isn't much of Downtown that stuck into memory. Sure, there's the Pike Market, with the first Starbucks, and its queue that really made me how much did I really want the same cold brew that I could order from any other Starbucks that wasn't crowded. Talking about Starbucks, I discovered the Starbucks Oleato Iced Cortado, and though I was skepticap about the use of olive oil, it was one of the best drinks I ever had. Going back to the sights, there's also the Cal Anderson Park, one of the few small parks of Downtown. The area around the park is actually nice to go for a stroll, and Analog Coffee is a very good place to stop for a short break with a non-Starbucks Cortado.

Final Thoughts

And that's all, folks. The end of my almost three week trip to the US. It was one of the best trips I took so far, with hundreds of kilometers walked or ran, many fascinating museums and parks visited, tens of cold brews, hopefully not as many burgers and donuts, and, most importantly, the feeling of being happy.

I'm happy to have chosen Seattle for this trip, and I'm considering coming back, but next time I will bring some hiking gear with me, since I'm thinking to try some trails. Looking forward to that, soon!

New York 2023

· 13 min read

view over manhattan from the empire state building, photo by silviu alexandru avram Photo by Silviu Alexandru Avram

New York City. The big apple. Jay-Z's city that never sleeps. Batman's Gotham. Spiderman's home. Call it whatever you like, everyone knows what you are talking about. It's #1 most popular city for filming movies, topping the likes of Los Angeles, Paris and London.

Needless to say, I arrived in NYC with big expectations. And I was still blown away.

Jersey City

My trip started in Jersey City, across the Hudson, where my friends are based. The trip from JFK took forever, but alas, I finally arrived at the World Trade Center, and then took the Path train to Jersey. After "checking in", we went for a walk to the Hudson River waterfront, overlooking Manhattan. Describing the skyline is just impossible, I just could not believe I was actually there, staring at it from across the river. It was late in the evening, or at least that's how I felt it was after the long flight. It was my opportunity to just pause and indulge the view. Right in front of my eyes, the World Trade Center. To the left, in the distance, the Empire State Building. The Hudson Yards, recently built, also to the left. Helicopters everywhere. Like in the movies, but better.

As for Jersey City, I found it to be quite a cosy place, especially the hip downtown, filled with coffee places, craft beer bars and restaurants. It featured many 19th century brownstone houses which suited the place very well, along with small shops and a few parks. The place was quite packed after working hours, and there was always a queue at the ice cream place (ugh...).

Manhattan SkylineJersey City Skyline
manhattan skylinejersey city skyline

On the waterfront, however, there was a different architectural story, as the brownstones were replaced by the all-too-familiar tall apartment and huge office buildings, the Goldman Sachs being the most impressive. Right next to it, there was the Colgate Clock. Familiar words everywhere, really.

The best decision of my life was to pack my running equipment, as it helped me discover Jersey City even better, not only its downtown and waterfront. I ran all the way to the Liberty State Park, then along the boardwalk, then closer and closer to Ellis Island, where I took a break and admired the country's unmistakeable icon, the Statue of Libery.

On another occasion I also went north of Jersey City, towards Hoboken, and reached the Hoboken train station and the Hoboken waterfront. From there, the Hudson Yards and the Empire State Building were closer across the river, so I could take a better look. This Hoboken part of town seemed to me less impressive and more impersonal than Jersey City, but the train station's exterior was very pleasant to the eye. Unfortunately, I did not make it to Hoboken downtown, where I was told there are plenty of coffee shops as well.

One thing's for sure: when possible, I'll always pack the running shoes.

Lower Manhattan

It seems pretty hard to divide the trip by time, so I'd rather split it by location, starting with Lower Manhattan. It's famous for taking a cruise to the Statue of Liberty and posing beneath the Wall Street Bull. There's also Wall Street itself, the stock exchange, and plenty of gigantic office buildings, hence it's name, the Financial District. At the intersection of Wall Street, Beaver Street and Pearl Street, I came across a building that looked stragely familiar and realised I was looking at the real life location of the Continental hotel from John Wick. On Broadway, betwen the buildings, the Trinity Church is making an impression. Squeezed between so many sky scrapers, it does stand out with its beautiful Gothic Revival style exterior, stained glass windows and peaceful cemetery with cherry trees and lots of flowers.

Equally impressive is the World Trace Center subway station, both from the inside and the outside. It was designed by the Spanish architect Santiago Calatrava and features white ribs that interlock high above the ground. Next to the station there's the 9/11 memorial, featuring a museum, a huge pool and a plaza. Next to them is One World Trade Center, the tallest building in New York. It's one of the buildings to visit for the panoramic view of the city, along with the Empire State Building and the Rockefeller Center. Spoiler alert: I chose Blair Waldorf's favorite.

The 9/11 MemorialTrinity Church
the 9/11 memorialtrinity church

Of course, I should also mention the Brooklyn Bridge, probably the most crowded bridge to cross on foot. Even with the crowds, the bridge offers a delightful walking opportunity, with its neo-Gothic towers, steel cables and pleasant views over both Manhattan and Brooklyn. I turned around just before reaching Brooklyn, as I decided to continue my walk back to Manhattan towards Canal Street, and postpone Brooklyn for another trip. On top of the Dumbo view point, I also have the Brooklyn Botanical Garden in Prospect Park on my future visiting list. Anyway, back to Manhattan.

I got off the bridge and turned right towards Chinatown and Little Italy. I took Center Street and went towards Canal Street. On my right I came across an array of what it appear to be government buildings, with imposing entrances. Later, I discovered that the buildings were actually the Supreme Court and the Courthouse. I continued my walk north, reached Canal Street and wandered a bit through Chinatown and Little Italy, before deciding to change course and head towards Soho and, of course, Noho.

Brooklyn BridgeWorld Trade Center
brooklyn bridgeworld trade center

Both Soho and Noho offer a stark change of scenery from Canal Street, with a lovely combination of shops, designer boutiques, chic restaurants and the New York University buildings. Right next to the NYU buildings we passed through Washington Square Park, which was always packed, given its location. On the day I arrived there with my friends, we took some pictures by the Washington Square Arch and we continued to move northward, towards my friend's favorite building in New York, the Flatiron Building.

Middle Manhattan

Probably the part of Manhattan I walked through the most, since my daily walks involved walking from the WTC to Central Park and then returning back either to the WTC or any other Path station. I mentioned the Flatiron Building, but unfortuantely I found it under construction, so there was not much to see. On the other hand, the Madison Square Park area offers a selection of equally magical places, and #1 is, of course, the Harry Potter store. I went to the shop at least 3 times and I was close to buying Severus' wand, but I did not like the wand stands and decided to postpone my purchase until I figure out where to place the wand in my home.

Equally magical is Shake Shack, and the Madison Square Park location has tables outside, right in the park. Double Smoke Shack, regular fries, 6 chicken bites and a laaaarge Fifty Fifty. 2000 calories and 0 regrets. And that's the magical part about New York which I liked: wherever I was, there was always something good to drink or to eat. Just out of any subway, there's a Starbucks. A Dunkin right next to it. A Chick-Fill-A on the corner. Or a Shake Shack. Popeyes? Yes. I cannot think of anything more magical than that, besides Disney. Two weeks getting high on Vanilla Sweet Cream Nitro Cold Brews, Boston Cream Doughnuts and Double Smoke Shacks. I hope, dear reader, that you're not hungry when reading these lines.

Empire State ViewNew York Public Library
empire state viewpublic library

A few streets to the north of Madison Square Park, there's the 34th street, with the Empire State Building, the Macy's store and The Morgan Library & Museum. I did mention that I climbed on top of Blair's favorite building, the Empire State, which is what I recommend going for first, given its position and history. It offers jaw-dropping Manhattan views both to the north and to the south, and every view is just breathtaking. I went to the Empire State Building alone, but at the Morgan Museum I went with my friends, since they booked a visiting slot during an evening. Morgan's collection is impressive, filled with pieces from all around the world, exquisite furniture, many many books, one of them being the Gutenberg Bible, one of the few available out there.

It's probably worth mentioning that most of the time I chose the 5th Avenue to go north, given its popularit and my hopes of seeing Taylor Swift. Other avenues are nice as well, such as the Madison Avenue, especially upwards from around 55th street. And the 9th Avenue. Other places that I really enjoyed in this part of Manhattan are the Grand Central Terminal, where John Wick was filmed (and others, of course), the New York Public Library where I took some pretty nice pictures, St. Patrick's Cathedral, MoMa, Whitney Museum, Chelsea Market, Hudson Yards. I think it's my favorite part of Manhattan, given the number of places I visited.

Manhattan West Office BuildingsHudson Yards
manhattan west office buildingshudson yards

Last, but not least, there are three more places worth mentioning in Central Manhattan. Firstly, there's The High Line, a former New York Central Railroad that got repurposed into a elevated linear park featuring a beautiful trail between the equally good looking buildings. It can be quite crowded sometimes, but it's still a great feeling to go for a stroll and enjoy the views, especially at sunset. Secondly, there's Times Square, and even though many considered to be an overrated spot with nothing particularly exciting about it, it's still a must go for the commercial light show, and for the John Wick filming location. And thirdly, the Eugene O'Neill Theatre, where my friend bought tickets for the Book of Mormon. It was the first musical experience for me, and I think it was the best experience I had in New York, to be honest. I did not know what to expect at all, and the show was incredible. If anyone has a todo list for New York, they should add a Broadway show right at the to. Period.

The High LineManhattan Street View
the high linestreet view

Upper Manhattan

It's not geographically accurate, but I will call Upper Manhattan to be the part from Columbus Circle to the Columbia University Campus, since the latter is the most northern point that I explored in Manhattan.

My favorite place here is, undoubtedly, Central park. Even though it was the beginning of spring, the park still offered pretty landscapes, with enough greenery to almost forget that you are in the middle of the concrete jungle. Greenery aside, the magnolias and the cherry trees stole the show, as they were in full bloom and everyone was competing for the best photos. My Central Park objective was to reach the Bethesda Terrace, another John Wick film set. Luckily, I spent a lot of time in the park, from north to south, visiting places like Belvedere Castle and Cherry Hill.

Central ParkColumbus Circle
central-parkcolumbus circle

To the west of Central Park, my friend and I visited the Columbia University Campus, and just in time too, as the students there were taking graduation pictures. We blended in perfectly, given the fact that we look studenty ourselves and spent most of the time taking pictures as well. It was a refreshing experience to visit a US university campus and compare to what I've seen in movies. After the photo shoot was over, we descendend through Morningside Park, grabbed coffee from a nearby Starbucks on the road and went back to Central Park to continue taking photos, this time with squirrels.

To the east of Central Park is another area that was on top of my list, given its movies reference: the Upper East Side. The place seemed to me exactly as I'd expected: fancy. The shops are there. The hotels are there. The restaurants. The boutiques. Needless to say, I enjoyed the walks very much.

Lincoln Plaza9th Avenue View
lincoln plaza9th avenue view

Also on the East Side, on the outskirts of Central Park, there's the Metropolitan Museum, where you probably need to spend a few days in order to fully experience it. I managed only 4 hours, I felt I was in a constant hurry, and missed many of its offerings. I went from Ancient Egypt, Rome and Greece, to Muslim Central and Far East Asia, early United States and everything in between. Some of my highlights include the Egyptian ruins (yes, actual ruins in the museum) and the American rooms arranged in the American History corner. But, to be honest, the whole collection is something to see. Being already familiar with art pieces from the ancient Mediterranean cultures, from many other European museums, the American and Asian parts from the MET impressed me the most.

Final Thoughts

There are also other places that I have been and are not covered in the lines above, like the Rockefeller Center or Little Island. But if decide to write about every single place or experience that impressed me in New York, I would never finish this article, ever.

Without a shadow of a doubt, I can say that I love New York City, and that it was one of my best ideas to spend 10 days and enjoy it as much as possible. It's #1 on my favorite cities in the world, and I have a feeling that it will stay there.

It also helped that my hosts were absolutely amazing, I could not have hoped for better ones.

I was quite sad to leave, even though my holiday was far from ending. It was time to change the scenery a bit. Next stop: Seattle.

Perugia 2023

· 10 min read

a field of daffodils near the lake trasimeno, photo by silviu alexandru avram Photo by Silviu Alexandru Avram

It was a lovely day of spring, on the 19th of March to be exact. I am a very big fan of the lazy Sunday concept, but somehow I always manage to ruin it in a spectacular fashion. And this one was no exception. It was a great day for science and productivity in general, or at least that's how I felt. As I closed my laptop after finishing a PR for downshift, I took a last sip of my Starbucks matcha tea latte and decided to check the horoscope (skyscanner.net).

Fueled by the warm sensation of accomplishment, I submitted a search for all the flights in the remainder of March, without any specific destination. And just like that, the stars aligned, the planets made love, and the horoscope whispered that I should book a flight to Perugia, from the 26th to the 30th, for a total price of 40 bucks.

Intriguing, I know. The horoscope gave me the answer I was looking for, but I had to find my own answers to questions like ... what is Perugia anyway? So after a bit of google google guess what I found out. Perugia is a lovely city in the middle of Italy, the capital of the Umbria region, at equal distance between Florence and Rome, two beautiful cities that I enjoyed very much in the past.

And this wasn't the best part. Right next to Perugia there is this big lake called Trasimeno. And if you enjoyed history in school as much as I did, you may remember about a certain battle of Lake Trasimene, where the Romans got their butts kicked by Hannibal's Celtic mercenaries. A bit of history always works well with coffee and tiramisu, if you ask me.

Oh, and there's also this other town near Perugia called Assisi, full of big churches and with a castle, a bit of a mix of Sighisoara and Brasov.

It was looking good so far, as far as I saw it. Plenty of stuff to do for a 4 day trip. First 2 days aperol spritzing in Perugia, one day for a Lake Trasimeno bike ride, and one last lazy day for church visits and lazy walks. To be sure about everything, I checked the second horoscope (booking.com) and Mercury was generous there as well. Found a decent apartment close to the train station, booked everything and I was all set for one of my spontaneous Italian trip.

Perugia Day #1

I passed trough a few small airports in my life, but San Francesco airport is on another level. It's like a small train station. The airplane pulls up right next to the airport. Because it's most likely to be the only plane in the airport at the time. You just hop off and walk inside, go through the immigration room, and directly outside. If it's your first time there and you're looking for an obvious way to get a bus into town, you're in the wrong place. It became immediately obvious that renting a car would have been a good idea.

That aside, we got to Perugia by bus eventually, and while the apartment was getting ready, we made for the city center. Not ideal when you have bags, but we were excited to walk the city for the first time and not take public transport just yet. And it's not a long walk, 25 minutes max. As we realised that the walk was more like a climb and we also had the bags with us, public transport suddenly sounded like the better alternative.

So there we were in the city center, which was the only place with people. We found nobody on our way there, and we started wondering if the town is dead or if there was a holiday. Once in the center, we went for Piazza IV Novembre and visited the National Gallery in Palazzo dei Priori. The place looked good on the outside, but the gallery itself was a bit disappointing. Do you know those weird medival religious paintings usesd to make memes out of? Yep, that was the place.

As the tour was over, we left our bags at the apartment and went back to the center to do some exploring and content creation for the gram. This time, we used a public transport called the Minimetro, which is an automatic train cabin that serves a few stops, including the city center and the train station. Never used anything like it before, it was actually very exciting!

Cloudy skies over PerugiaChurch of Sant'Ercolano
cloudy sky over perugiachurch of sant&#39;ercolano

We found Terrazza del Mercato with a gorgeous view of Umbria and the mountains to the East. Great place to sip your aperol and enjoy the graphics of life. We also found a few places to eat, obviously, and the most important were the O Sole Mio pizzeria and the Lick gelato place. Top tip: if you go to Italy, always, always, locate the take away pizza place conveniently situated, where you can enjoy a few slices of great pizza and a beer. Italian restaurands are very (VERY) picky about their time of serving lunch and dinner, so if you're caught off hours, the pizza place is your ultimate salvation. It saved us 4 times in total, with great pizza, arancini and Ichnusa. And I'm not even slighly mad about that.

Perugia Day #2

Still hungry for instagram content, as the first day was not very productive, we went full on exploring the next day, even though the rainy weather was better fit for sensual bachata. We found some very good places such as the Garducci Gardens, the Acquedotto Medievale, the Chiesa di San Michele Arcangelo, and the Chiesa di Sant'Agostino.

In order to be able to walk, visit and take pictures, good coffee plays an important part, and the Pinturicchio Cafe did not disappoint. Caffee Arco was fine as well, but did not compare.

Overall, it was a good day for visiting and content creation. We felt that we saw enough of Perugia and we were satisfied about it. The next day was supposed to be sunny, which was necessary to achieve our next objective.

Lago Trasimeno

After a short train ride we were in the town of Passignano sul Trasimeno, the starting point of what was supposed to be our Trasimeno lake bike ride. We rented the bikes and off we went, towards the almost middle point of the journey, Castiglione del Lago. According to Google Maps, we had enough time to perform a full circle around the lake in our time frame of 7 hours, lunch and cofee stops included. Consequently, we started our journey full of optimism and joy, like Gaius Flaminius and his friends.

As we got closer to a checkpoint, namely Campo del Sole, lunch hour was drawing to a close, so we decided to abandon the main road, and head over to the town of Tuoro sul Trasimeno and have something to eat. We were the only people in the town when we arrived, along with a couple of others, probably the mayor and some people at the local bar. Everything else looked deserted and closed. Eventually, we found one open restaurant, Osteria dell'Accademia, which had really good food and service, with the best bread I had for a while. Coperto well spent.

Silviu riding a bike near Lago TrasimenoSunset over Lago Trasimeno
silviu on a bike near trasimenosunset over lago trasimeno

Back on the road, we resumed the journey, with a few stops along the way, one of which was a field of daffodils. No, not your usual Instagram rapeseed photos, this was with actual daffodils. Glorious. Eventually, we arrived in Castiglione at about 16:30, 4 hours after leaving Passignano. Unfortunately, we did not visit the town, as it required us to leave the bikes and climb, because, obviously, the town was on a steep hill. Climbing would not have been a problem, but as we were doing the math, it would have been impossible to go round the lake and reach the end point by 19:30, the time we had to return the bikes.

Either Italian Google Maps tricked us, or we were just outrageously slow, because it turned out that the actual time it took us to reach a certain point by bike was two times the one estimated by Italian Google. And on that bombshell, we had to abandon the original plan of doing a full circle around the lake and go back the way we came. Italian Google clearly said it would take 1 hour to get back. It took us 2, like the priest.

With a bit of disappointment and much hunger, we dined in Passignano and got the (last) train back to Perugia. It was not all negative though. The weather was great, we took many pictures, and no army ambushed us along the way.

Assisi

The third and final stop of the trip was the town of Assisi, a few kilometers from Perugia. There isn't much to tell about the town, to be honest. Just your usual medieval town full of churches and a castle on top of a hill. The weather, this time, sucked big time. There were gusts of wind that reminded me of the Grozavesti intersection.

Assisi CastleView from Assisi
assisi castleview from assisi

On the (brief) bright side, the churches were very beautiful, especially the main one, Basilica of San Francesco d'Assisi. Apart from them and the view point near the castle, the town was cute, but it did not blow our hats off. The wind did that.

Final Thoughts

Overall, I enjoyed the trip, the towns of Assisi and Perugia are definitely worth visiting. Also, if you plan to go to Lago Trasimeno and intend to do a full circle, make sure you are really fast, or maybe stop for the night along the way. I'd go woth the second option, as a romantic stop at a hotel with a lake view is probably a good idea.

If I would do it all over again, I would also rent a car, and buy accomodation in multiple places: two nights in Perugia, one in Assisi, one or two at the lake, and so on. You would probably get more out of the Umbria trip like that, instead of having your accomodation in a single place and take trains and buses to the other points of interest. Just make sure to heed advice #1: pizza place that is conveniently situated.

Allora, that's all folks. Wrapping this one and will publish it. It has been a productive Sunday, on the 2nd of April, I am pretty happy about everything, to be honest. Hmm, I wonder what the horoscope has to say about it.

My 2022 in Review

· 14 min read

silviu on a mountain trail, overlooking the Bucegi mountains, photo by oana vasilescu Photo by Oana Vasilescu

I started to write this post with an outlook of 2022's events, then decided against it. I will only say that 2022 also brought some good news and that we should just focus on the things that we can control.

I think that tracking past year's accomplishments serve a better purpose than listing new year's resolutions.

They give us a better sense of where we are at this point in time, what are we happy about, what we want to improve, how far we I with our objectives, and other such vectors that form the big picture of life. Past year events have happened, are easier to be measured, to receive follow-ups, to be celebrated and to be analyzed.

As I was writing this post, it occured to me that 2022 was, personally, a year full of events and achievements worth mentioning. Here they are:

Building this Blog

My first most obvious achievement is, incidentally, this very blog. I started the year by keeping a journal and writing once every few days. Shortly afterwards, few days became more days and I found it increasingly difficult to keep track of everything. And when I was actually writing down my thoughts, I was mostly focusing on specific events, rather than the overall picture. Consequently, it occured to me that I might be better off with keeping a blog with posts about topics rather than a journal.

This realisation occured to me back in the summer, and it took me until November to kickstart the blog creation process. I published it, along with my first post, on December 13th, and it felt quite a piece of work. A piece of work which is completely documented in the very same blog post, Building this Blog.

Setting up the blog made me very happy once I managed to publish it online. And eager to write some more posts.

Switching Roles

I started 2022 with a new role at Bolt. I was excited to help the company build its Design System and create the ReactJS implementation for its components. I loved the enthusiasm of delivering solid building blocks for others to use in their applications and improve their user's experience. My team was constantly aiming to provide superior quality in whatever we shipped, and I was very lucky to work together with them.

Unfortunately, 2022's uncertainties left its mark on many things, but Bolt still managed to throw the coolest summer event ever in Estonia, with over 2000 participants. It surpassed all other events that I have been part of until now. Really amazing job!

In spite of the great blast I had working at Bolt, I decided to swith gears and return to Microsoft in December. I will be part of the team that improves the Messaging experience inside Microsoft Teams, a product I contributed to before. One of the main differences is that, this time, the role is based in Bucharest, so no relocation is needed. I am happy to see the product getting better over the years, especially now when most of us work either remotely or in a hybrid schedule. Very excited about what's next!

Interviewing for both these companies is not easy, as their hiring standards are quite high. That being said, buying a leetcode subscription and having a daily slot to solve puzzles and algorithms worked for me very well. It feels tiring after a few weeks, but that's the price to pay in order to work in a company with great people and a healthy culture. So far, I think it's worth paying it.

Reading

I regret that I was not much into reading when I was in school. Even so, from my first salary, back in 2013, I bought the Song of Ice and Fire collection, which was meant to be symbolic. I read the books rather quickly, but it took me until 2018 to actually start reading on a regular basis. Despite the rough start, I realised that 2022 was a great year for my reading habit. Here's my list:

  1. The Picture of Dorian Gray. The novel I started right after finishing Jordan Peterson's 12 Rules for life. After learning to pick my life sufferings for the better outcome, I went straight down the rabbit hole of hedonism. Oscar Wilde's book is not a very long one, but paints a powerful picture of beauty as an end, untouched by the the lust and sin of human nature. The picture had the ability to keep "Prince Charming's" beauty and youth unscathed, but not his conscience, as he tragically discovered.
  2. War and Peace. In contrast to the first book in the list, this one is huge. I was awed by its complexity from the beginning to the end. It's hard not to like War and Peace. I loved everything about it: its story of Russia's elite, the history of the Napoleonic wars, the characters and their struggles in society. All sprinkled with Tolstoy's philosophy.

    Yes! It’s all vanity, it’s all an illusion, everything except that infinite sky.

  3. Lolita. It was not an easy book to read for me. Maybe because I just could not detatch myself from the main subject of the novel, or the protagonist's interests. It's hard not to be impressed by the writing style though, which emphasizes the character's profession and education.
  4. The Plague. If it wasn't the COVID pandemic I would have probably postponed reading this book, but I'm glad that I haven't. Bernard's work and reaction to the events showcase our power of adaptability in times of crisis, even though, at times, it felt a bit cynical. In any case, it was hard for me to blame him.
  5. 1984. Everyone needs to read this book. Period. It's a great way to remind us about the importance of free thinking, free speach and democracy. And how easy could these be exchanged in the name of security and improved quality of life. An exchange that is nothing but a lie.

    Who controls the past controls the future: who controls the present controls the past.

  6. To Kill a Mockingbird. I understand why this is widely read in the United States high school and middle school. The subjects are not uncommon at all, but what is powerful is them being projected through the viewpoint of a child. It's a great way to understand fundamental concepts such as justice, equality and empathy. In my opinion, it's a must read.
  7. The Master and Margarita. The supernatural part of the novel was not something I particularly enjoyed. On the other hand, I did not expect to enjoy the part about Christian philosophy, which was masterfully written.
  8. The Great Gatsby. I am happy to have read the book, as it delivers a conivincing story about the disparity of society, the relations between men and women, and the American way of life in the hedonistic Jazz Age. Nicks's outsider perspective about the events is crucial, I believe, to enjoy every bit of it.
  9. A Hundred Years of Solitude. I love this book. I started to read it on my flight to Lisboa and, during those 4 hours, I was enchanted. The characters were not without flaws, to say the least, but there was something magical about each and every one of them that brought me inside their world. I founded Macondo, fought the Columbian government, kept watch over the family, deciphered the manuscripts and escaped the banana company massacre in their company. I did not expect to like this book when I saw the family tree at its beginning, thinking that it's going to be some kind of a South American soap opera. I was so mistaken.

    (...) the parchments, and that everything written on them was unrepeatable since time immemorial and forever more, because races condemned to one hundred years of solitude did not have a second opportunity on earth.

  10. Letters from a Stoic. I should have started my stoic journey with Seneca's book, not Marcus Aurelius' Meditations. The letters are clearly written for publishing, and it's impossible to tell that they were written 2000 years ago, they feel so contemporary. The desire to think about the meaning of life is not delivered as a strong punch to the face, as in Meditations, but as a friendly pat on the back while you enjoy a relaxing walk on the pristine Mediterranean shore.

Learning

I'm a big fan of studying from online source, such as Frontend Masters, Coursera and Udacity. Unfortunately, I had better years when it comes to learning new skills.

I have finished Kyle Simpson's Deep JavaScript Foundations. It allowed me to explore some JavaScript functions which I had the tendency to only guess how they worked. And his course helps counter exactly this tendency, as understanding the tools we use is fundamental in shipping products that are free of bugs.

Switching gears, I am now in the process of learning accessibility from Marcy Sutton's Testing Accessibility. I know Marcy from 2019, when I attended her Deque talk at CSUN. I love the accessibility part of web development and try to advocate for it as much as possible, and Marcy's training course is packed with useful information and her own experiences while working in the accessibility field.

Open Source

I have updated downshift to support the ARIA 1.2 combobox pattern for both useSelect and useCombobox hooks. This update involved a breaking change version update, but the migration guide should cover the steps needed to make the proper changes on the consumer side. More importantly, I resumed my regular work on the library, with more bug fixes, documentation updates, and future planning.

Traveling

In January I went to Rome for the second time. I liked it very much the first time and there were many places that were still on my list and I did not manage to visit them. Truth be told, my list is far from finished, as Rome has so much to offer. We spent one full day at the Vatican, as it's properly required, and this time I also went to Saint Peter's Basilica, which I somehow managed to avoid during my first trip. It's hard to grasp how big this church is. Incredible.

Tiber River overlooking TrastevereThe Vatican Square
the tiber river overlooking trasteverethe vatican square at dusk

Also incredible are the Baths of Caracalla, and it's difficult for me to understand how the Romans managed to build this magnificent structure 2000 years ago and not keep their city clean in the present. Anyway, what I also liked in Rome is the Trastevere neighbourhood. We went there at sunset and it gave me the feeling of cosy castle setting, with cramped streets, terraces everywhere, candle lights and brick walls.

My next trip took place in, you guessed it, Italy again, but this time in Genoa. I cannot say much about the city itself, it's probably my least favorite so far, but I enjoyed it nonetheless. The highlight of the trip was the town of Portofino, which is probably Instagram heaven. Everything was picture perfect: the pure white boats on the water, the hills covered in greenery, the Castello Brown with its perfect gardens. Just excellent.

Portofino HarborPortofino Hills
a view from the castello brown, overlooking the portofino harborhills of portofino

My third trip involved a bike trail on the Loire Valley in France. I love biking trips. The itinerary is simple: check in at the hotel, visit the town, get up the next day, leave my bags there, hop on the bike and ride to the next destination, while the luggage gets magically transfered to the next hotel. Oh, and did I mention the chateaux on the bike trails? The Loire Valley is famous for them. My favorite ones were Château de l'Islette, Château de Villandry and Château du Rivau.

Chinon CastleMontsoreau Castle
chinon castle seen from a bridgechinon castle seen from a bridge

In July my friends and I went for a relaxing beach trip in Bulgaria's Sunny Beach. It was a perfect combination of sun, food, beach, bachata by the pool, relaxing walks and food. There was a lot of food.

I did mention Bolt's summer 2022 event and this involved a trip to Estonia. The boat ride was absolutely amazing, and I managed to visit a bit of Tallinn and Saaremaa while there. My only complaint is that we did not stay longer, as everything felt a bit on the fast forward. I think I would have enjoyed a full day visiting Saaremaa with a car. Or riding an electric scooter.

Saaremaa BeachTallink Ship
beach with rocks on the shore of saaremaa islandthe tallink ship

My last trip of 2022 was the already mandatory Web Summit conference in Lisboa, which I went to for the third time already. They are nice enough to offer free tickets for active open source contributors, and I was lucky to receive such a ticket. I love Lisboa and it's one of my favorite cities, with great views, very friendly people and Pasteis de Nata. The conference is a great opportunity to learn what's new in tech, climate change, marketing and others.

We also went to Lagos for the second year in a row, as my friend is a fan of surfing, and he convinced me to give it a try. It's not the easiest thing for me to do, but it does feel good when you catch the proper wave.

Monte Agudo in LisboaPortas do Sol in Lisboa
lisboa view from the monte agudo viewpointlisboa view from the porta do sol viewpoint

Hobbies

Because having fun is what it's all about.

Banana BreadMargarita Cocktail
banana breada glass of margarita

There was significant progress in the kitchen this year. The winners are, without a doubt, the banana bread and the margarita cocktail. If my software development career happens to go south, I'm opening a coffee shop that turns into a cocktail bar in the evening, with latino parties all day long. There is simply no other way. Talking about latino parties, I did continue taking bachata and salsa lessons, and I also started to learn salsa on2.

Thanks to my group of friends that enjoy hiking, this year we went on a few trails in the Bucegi and Piatra Craiului mountains. Some of the peaks and trails: Piatra Mare, Piatra Mica (I know, not much imagination), Neamtu, Jepii Mari and Ciucas.

Salsa DancingPiatra Mare hiking trail
silviu dancing salsaview from a trail in the piatra mare mountains

I also continued to go for a run once every two days and to hit gym twice a week. On top of that there were a few snowboarding trips and the occasional basketball game.

Wrap up & Plans for 2023

And that's all, folks. I am very grateful for a past year that was full of events and accomplishments. Many thanks to everyone that were part of my journey!

I am super excited for 2023, and I honestly hope that the overall state of the world will improve. I really think that we need this to happen. As stated in the beginning, I am not a big fan of new year's resolutions, but I do want to continue what I did best during this year. Also, I have a list of new objectives as well, such as to:

  • update Downshift to v8.
  • finish Marcy's course and 2 more Frontend Masters web development courses.
  • read at least 10 books, starting with the current one, Don Quixote.
  • improve to 3 times per week gym schedule.
  • attend at least one dancing congress.
  • visit the south of Spain and New York.
  • revive the Tab Order Testing library I worked at in Adobe.

Thank you for reading this post, I hope you liked it. I wish you a great and fulfilling 2023!

Happy New Year!

Building this Blog

· 26 min read

a heap of logs next to a mountain cabin in the piatra mare mountains, photo by oana vasilescu Photo by Oana Vasilescu

Building a digital blog should not be, theoretically, too hard to accomplish. Expecially now, in 2022, with all the many dedicated platforms and services that have established themselves over time in the digital blogging department.

As someone who does Frontend Development for a living, my list of technical choices is even more generous. I am able, theoretically, to build a web application using just the magic trio of HTML, CSS and JavaScript. Just in case I don't feel like going full vanilla, there are superior levels of abstractions, such as, for example, the ReactJS, tailwindcss and TypeScript combination. Of course, one level of abstraction above, the list continues with the likes of GatsbyJS or NextJS. And just in case I don't want to bother with coding at all, I can go full techless with solutions such as WordPress, MailChimp, Canva, or something equivalent. The last list of services can also provide support for hosting and domain registration, at a cost, obviously.

So, time to choose one technology stack and ... start writing already?

Picking the Tech Stack

The technical solution for this blog is a middle ground between tech skills and convenience. Let's talk about each part.

Github

First and foremost, the source code for the blog needs to live somewhere. Sure, we can keep it safe on a laptop, but what if the device gets damaged, or the code gets accidentally deleted? So much precious information lost, forever. We cannot risk that. It will also be hard to keep track which of the files got updated and need to be published in order for the next blog version to be released. Luckily, we have GitHub to help us with keeping our code safe, versioned and structured for review. The source code for the blog can live happily ever after inside a GitHub code repository. Specifically, this repository.

Docusaurus

The second tech stack choice is docusaurus, which provides us with the infrastructure to build the blog. We can write each blog post as a MDX markdown file that will be transformed automatically into a web page. Docusaurus allows further customisation of the page layout using a technique called swizzling. We can replace or alter different layout components using everyone's favorite library, ReactJS.

All the source code (markdown, react javascript, others) is transformed into production code by docusaurus. This process is called the build process, and its result, the production code, is the blog aplication itself. With great support out of the box for responsiveness, layout, images, tags, code snippets and even interactive code examples, docusaurus does a lot of the heavy lifting and lets me focus on the content.

Netlify

Great, now we can write my blog source code, save it somewhere safe and build the blog from it. Anything else?

Well, turns out that in order to write www.silviuaavram.com in a browser and actually access the blog website, its production code needs to find its way back to the browser. Also, every time the blog receives an update and, as consequence, has the source code changed, the production code needs to be updated as well. Otherwise, we will read an outdated blog, which is totally unacceptable.

Consequently, a computer on the internet needs to be able to download the blog source code from GitHub, build it into production code, and serve the resulting production code to the browser that wants to retrieve it. This magical computer is called a server. When someone requests a link in the browser, this server needs to be found and asked to ... serve ... the website production files. These files will be received by the browser, which will piece them together and show us the blog website.

For these daunting tasks we will choose Netlify, since I had a great experience with their service when hosting the downshift docsite.

GoDaddy

Finally, this server computer needs to be linked to the address www.silviuaavram.com through a service called the Domain Name System. As such, we need to buy the address (domain) silviuaavram.com on the internet and tell Netlify that it belongs to us. In turn, Netlify can provide the actual website content every time someone requests the www.silviuaavram.com. The process of mapping the internet address to the IP address of the Netlify server is done by the internet using the DNS. We will use GoDaddy to buy the silviuaavram.com domain.

And that's all I need, finally let's get to work!

Source Code Setup

There are some standard prerequesites that we need. Most FrontEnd developers already are familiar with them:

  • GitHub account.
  • Installed NodeJS and Git on the laptop.
  • VSCode.

If you don't have these set up, the internet is your friend in order to have them ready.

GitHub

We will create a new GitHub repository called silviuaavram, make it Public, with a node .gitignore file and an MIT license. Afterwards, We will download the repo to our laptop as well, so we can make changes locally and then save them on GitHub once they are done.

We will open VSCode with a terminal, navigate to a place where we want to have the repo, and download it:

git clone git@github.com:silviuaavram/silviuaavram.git

Docusaurus

Second step is to setup docusaurus locally according to the docusaurus documentation. We want to have the initial code generated by docusaurus in the folder we just downloaded from GitHub, so we will run the setup command like this:

npx create-docusaurus@latest silviuaavram classic --typescript
cd silviuaavram
npm start

It will create a standard docusuaurus setup, in the folder silviuaavram, using TypeScript instead of JavaScript for the related source files. After the files get created, we will navigate inside the folder and run the npm start command in order to see how the website looks right now. It will get deployed locally at the address http://localhost:3000.

For now, we want to save the generated files to GitHub, so we will stage all of them, create a commit from the staged files, and push the changes to the remote GitHub repository.

git add -A
git commit -m "docusaurus setup"
git push

If you are unsure about the git-related concepts like commit, push, clone, stage etc. the Internet is, again, your friend.

Final Setup Tweaks

We will remove the package-lock.json file and create, instead, an .npmrc file with the content below, so we don't get the package-lock.json generated again. It is a matter of personal preference not to have one, mostly because there won't be many people working on this blog.

package-lock=false

We already have the .gitignore file generated, but we will also add a line with .docusaurus at the end of it, since this is going to be a directory with generated code, and we don't want to save it on GitHub.

Since I like to format my code automatically as I write it, we will be using the prettier utility, along with a configuration file from kcd-scripts. Only the prettier extension from VSCode is useful, so we will not install prettier for now. But we will install kcd-scripts as a developer dependency.

npm install --save-dev kcd-scripts

And we will also create a prettier.config.js file in the root with the following content:

// this is really only here for editor integrations
module.exports = require('kcd-scripts/prettier')

Now, every time we run the formatting command in VSCode, the code will get formatted according to the formatting rules from kcd-scripts. Great!

Removing the Docs. Defaulting the Blog.

Let's now shave the parts of our app that we don't need. Most of these steps are done according to Docusaurus' official documentation, as it's very well written.

Since we only need the blog part of the application, we are going to delete the support for documentation (docs). In docusaurus.config.js, we will look for the config.presets. Inside it, there is a docs entry, whose value is an object. We will replace the object with false. This should remove the docs part from the website.

Changing the value will result in a strange error displayed in our locally deployed application. To fix the error, we need to add routeBasePath: '/' to the blog object (next to the docs entry). We will also remove the first item in config.themeConfig.navbar.items (the one with type 'doc').

We also need to remove a few files as well. First and foremost, all the content in the src/pages directory should be deleted, since they are related to the docs part of the app. We can clear src/components as well, since these components are used only in the pages we just deleted. Oh, and we also won't need sidebars.js anymore, so we can get rid of that.

These changes should remove all the references to the docs, and the error should be fixed. We also made the blog page as default, so when we navigate to localhost:3000, it will display the blog. Fantastic!

Back in our docusaurus.config.js file, we need to also change the navbar item pointing to the blog to point to '/' instead of '/blog', due to our previous change with routeBasePath. We should also deal with the footer section. This one is really easy, for now, as we will only remove the whole links part, keeping only the style and copyright. The links to social media stuff will be added a bit later in the navigation bar.

So far, the config file should look like this:

docusaurus.config.js
// @ts-check
// Note: type annotations allow type checking and IDEs autocompletion

const lightCodeTheme = require('prism-react-renderer/themes/github')
const darkCodeTheme = require('prism-react-renderer/themes/dracula')

/** @type {import('@docusaurus/types').Config} */
const config = {
title: 'My Site',
tagline: 'Dinosaurs are cool',
url: 'https://your-docusaurus-test-site.com',
baseUrl: '/',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'img/favicon.ico',

// GitHub pages deployment config.
// If you aren't using GitHub pages, you don't need these.
organizationName: 'facebook', // Usually your GitHub org/user name.
projectName: 'docusaurus', // Usually your repo name.

// Even if you don't use internalization, you can use this field to set useful
// metadata like html lang. For example, if your site is Chinese, you may want
// to replace "en" with "zh-Hans".
i18n: {
defaultLocale: 'en',
locales: ['en'],
},

presets: [
[
'classic',
/** @type {import('@docusaurus/preset-classic').Options} */
({
docs: false,
blog: {
routeBasePath: '/',
showReadingTime: true,
// Please change this to your repo.
// Remove this to remove the "edit this page" links.
editUrl:
'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',
},
theme: {
customCss: require.resolve('./src/css/custom.css'),
},
}),
],
],

themeConfig:
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
({
navbar: {
title: 'My Site',
logo: {
alt: 'My Site Logo',
src: 'img/logo.svg',
},
items: [
{to: '/', label: 'Blog', position: 'left'},
{
href: 'https://github.com/facebook/docusaurus',
label: 'GitHub',
position: 'right',
},
],
},
footer: {
style: 'dark',
links: [
{
title: 'Community',
items: [
{
label: 'Stack Overflow',
href: 'https://stackoverflow.com/questions/tagged/docusaurus',
},
{
label: 'Discord',
href: 'https://discordapp.com/invite/docusaurus',
},
{
label: 'Twitter',
href: 'https://twitter.com/docusaurus',
},
],
},
{
title: 'More',
items: [
{
label: 'Blog',
to: '/',
},
{
label: 'GitHub',
href: 'https://github.com/facebook/docusaurus',
},
],
},
],
copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`,
},
prism: {
theme: lightCodeTheme,
darkTheme: darkCodeTheme,
},
}),
}

module.exports = config

Making it Personal

We're in a good spot right now, as we only have the Blog functionality in our app. However, our blog is about Docusaurus, while we actually want to write personal stuff here. Let's apply some cosmetic surgery and make it beautiful.

Back in our beloved docusaurus.config.js file, we will add our own information to the relevant fields.

  • title should be Silviu Alexandru Avram.
  • tagline should be Silviu's personal blog, focused on technology and lifestyle.

    both the title and tagline end up in the HTML file in their appropriate <head> child elements.

  • url is our domain that we just bought from Mr. GoDaddy, https://silviuaavram.com.
  • favicon becomes img/favicon.png.

    The favicon is placed in the Browser tab before the blog title. To create this favicon as a .png file, I used Adobe Illustrator. Guess what's my favorite drink.

  • organizationName should be the GitHub user name, here silviuaavram.
  • projectName should be the repository name, here also silviuaavram.
  • editURl from the blog object should point to our GitHub repository, specifically 'https://github.com/silviuaavram/silviuaavram/tree/main'

    The edit URL is a very handy feature in case anyone wants to edit the content of a blog post directly from the website.

  • colorMode should have it's defaultMode dark, as we want, by default, the website to be shown in the dark color mode. We're so dark right now.

    Color mode can still be switched to ligh from the toggle button in the upper right color of the screen.

  • navBar should have the following changes:
    • title should be, obviously, Silviu Alexandru Avram, which is actually the text content of the upper left link to the home page.
    • logo should be displayed next to the title, and it should be the blog's logo picture.
        logo: {
      alt: 'silviuaavram logo with a tequila glass and blog owner name initials',
      src: 'img/logo.png',
      },

      I used Adobe Ilustrator here as well, in order to create a logo for the website. Both the favicon and the logo files are saved in the static/img folder.

    • the navbar items should contain, on the left side, next to the logo, the links to the Blog and the About pages.
        items: [
      {to: '/', label: 'Blog', position: 'left'},
      {to: '/about', label: 'About', position: 'left'},
      // next items.
    • on the right part of the navbar, before the dark/light mode switch button, I will place the links to all my social media contacts: GitHub, Linkedin, Instagram and Twitter. This part involves a little more work than just adding the information below to the config file. The process is detailed in the next section.
        {
      href: 'https://github.com/silviuaavram',
      label: 'GitHub',
      position: 'right',
      icon: 'github',
      },
      // next items.
    • last, but not least, we will change the copyright text in the footer to include the author's name.

With all these changes done, our config file should look more or less like this:

docusaurus.config.js
// @ts-check
// Note: type annotations allow type checking and IDEs autocompletion

const lightCodeTheme = require('prism-react-renderer/themes/github')
const darkCodeTheme = require('prism-react-renderer/themes/dracula')

/** @type {import('@docusaurus/types').Config} */
const config = {
title: 'Silviu Alexandru Avram',
tagline: `Silviu's personal blog, focused on technology and lifestyle.`,
url: 'https://silviuaavram.com',
baseUrl: '/',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'img/favicon.png',

// GitHub pages deployment config.
// If you aren't using GitHub pages, you don't need these.
organizationName: 'silviuaavram', // Usually your GitHub org/user name.
projectName: 'silviuaavram', // Usually your repo name.

// Even if you don't use internalization, you can use this field to set useful
// metadata like html lang. For example, if your site is Chinese, you may want
// to replace "en" with "zh-Hans".
i18n: {
defaultLocale: 'en',
locales: ['en'],
},

presets: [
[
'classic',
/** @type {import('@docusaurus/preset-classic').Options} */
({
docs: false,
blog: {
routeBasePath: '/',
showReadingTime: true,
// Please change this to your repo.
// Remove this to remove the "edit this page" links.
editUrl: 'https://github.com/silviuaavram/silviuaavram/tree/main',
},
theme: {
customCss: require.resolve('./src/css/custom.css'),
},
}),
],
],

themeConfig:
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
({
colorMode: {
defaultMode: 'dark',
},
navbar: {
title: 'Silviu Alexandru Avram',
logo: {
alt: 'silviuaavram logo with a tequila glass and blog owner name initials',
src: 'img/logo.png',
},
items: [
{to: '/', label: 'Blog', position: 'left'},
{to: '/about', label: 'About', position: 'left'},
{
href: 'https://github.com/silviuaavram',
label: 'GitHub',
position: 'right',
icon: 'github',
},
{
href: 'https://www.linkedin.com/in/silviuaavram',
label: 'LinkedIn',
position: 'right',
icon: 'linkedin',
},
{
href: 'https://www.instagram.com/silviuaavram/',
label: 'Instagram',
position: 'right',
icon: 'instagram',
},
{
href: 'https://twitter.com/silviuaavram',
label: 'Twitter',
position: 'right',
icon: 'twitter',
},
],
},
footer: {
style: 'dark',
copyright: `Copyright © ${new Date().getFullYear()} Silviu Alexandru Avram. Built with Docusaurus.`,
},
prism: {
theme: lightCodeTheme,
darkTheme: darkCodeTheme,
},
}),
}

module.exports = config

To add a link to the author's Twitter account in our blog's navigation bar, we can add the following object to themeConfig.navbar.items in docusaurus.config.js.

  {
href: 'https://twitter.com/silviuaavram',
label: "Silviu's Twitter link",
position: 'right',
icon: 'twitter',
},

By default, if we add an item to the navbar items, it will get shown on our website as link with the Silviu's Twitter link text and an external link icon next to it. That's acceptable, but let's create something thats more sophisticated than that. What we want to show is the actual logo of the social media that we're linking to. I mentioned above that Docusaurus allows the customisation of different parts of the layout and content for the website using a technique called Swizzling, and that's what we're going to do. We are going to Swizzle the navigation component in order to change it according to our needs.

We will run the command below in the terminal for a list of React components that can be swizzled.

npm run swizzle -- --list

In the long list of customizable components, we find NavbarItem/NavbarNavLink that represents the icon link we want to change. That is what we're going to sizzle, my nizzle.

There are 2 ways to swizzle:

  1. wrap the corresponding react component into another component, which makes sense if we want to augment it with our own custom stuff.
  2. eject the component completely, so we can change its default implementation.

We will do the second part, as we want to remove the link text, the ugly icon, and return just our own cool social media icon.

npm run swizzle @docusaurus/theme-classic NavbarItem/NavbarNavLink -- --eject

And confirm that yes, we know what we are doing. We will hit the Enter key slightly harder than usual, to show that we mean business.

Magic! In our src/theme folder we got a generated NavbarItem folder with the NavbarNavLink.js file. The file contains the default implementation for the navigation bar link, which is the element that we want to change if the link is a social media link. Notice that, in our docusaurus.config.js, for each social media element, we are also passing an icon property, which represents information about what icon we want to show for that link.

After skimming the code here and understand what's what, we find the default implementation for the external link. As we expected, it outputs the text via the label (in this case, "Silviu's Twitter link"), and if it's an external link (here it is external) it will show the IconExternalLink component next to it, which outputs the icon with the arrow.

  children: (
<>
{label}
{isExternalLink && (
<IconExternalLink
{...(isDropdownLink && {width: 12, height: 12})}
/>
)}
</>
),

We will change this code and only return a social media icon if, from the configuration file, we identify that the link we want to show is a social media link. Otherwise, we will return the default implementation. In order to be sure that we are dealing with a social media link, we will check its icon prop, since, from the configuration file, we will only pass icon to the social media links. The code becomes:

  children: icon ? (
<SocialMediaIcon type={icon} aria-label={label} className={styles.iconImg} />
) : (
<>
{label}
{isExternalLink && (
<IconExternalLink
{...(isDropdownLink && {width: 12, height: 12})}
/>
)}
</>
),

And we will also create a SocialMediaIcon component like the one below, where each variation will return an SVG output representing the icon tiself:

type SocialMediaIconType = 'twitter' | 'instagram' | 'github' | 'linkedin'

export type SocialMediaIconProps = React.ComponentPropsWithoutRef<'svg'> & {
type: SocialMediaIconType
}

const SocialMediaIconComponent: Record<
SocialMediaIconType,
React.FunctionComponent<React.ComponentPropsWithoutRef<'svg'>>
> = {
github: GitHub,
linkedin: LinkedIn,
twitter: Twitter,
instagram: Instagram,
}

export function SocialMediaIcon({
type,
...rest
}: SocialMediaIconProps): JSX.Element {
const IconComponent = SocialMediaIconComponent[type]

return <IconComponent {...rest} />
}

And one of the icons can be:

export default function GitHub(
props: React.ComponentPropsWithoutRef<'svg'>,
): JSX.Element {
return (
<svg
height="24"
width="24"
viewBox="0 0 32 32"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<title />
<g
data-name="github coding dev developer"
id="github_coding_dev_developer"
>
<path
fill="currentColor"
d="M16,3a13,13,0,0,0-3.46,25.53,1,1,0,1,0,.53-1.92,11,11,0,1,1,7-.4,15.85,15.85,0,0,0-.3-3.92A6.27,6.27,0,0,0,24.68,16a6.42,6.42,0,0,0-1.05-3.87,7.09,7.09,0,0,0-.4-3.36,1,1,0,0,0-1.1-.67,8,8,0,0,0-3.37,1.28A11.35,11.35,0,0,0,16,9a13.09,13.09,0,0,0-3,.43A5.74,5.74,0,0,0,9.62,8.25a1,1,0,0,0-1,.66,7.06,7.06,0,0,0-.37,3.19A7.15,7.15,0,0,0,7.2,16a6.66,6.66,0,0,0,5,6.28,7.43,7.43,0,0,0-.15.79c-1,.06-1.58-.55-2.32-1.48a3.45,3.45,0,0,0-1.94-1.53,1,1,0,0,0-1.15.76A1,1,0,0,0,7.35,22c.16,0,.55.52.77.81a4.74,4.74,0,0,0,3.75,2.25,4.83,4.83,0,0,0,1.3-.18h0a1,1,0,0,0,.29-.14l0,0a.72.72,0,0,0,.18-.21.34.34,0,0,0,.08-.09.85.85,0,0,0,.06-.17,1.52,1.52,0,0,0,.06-.2v0a4.11,4.11,0,0,1,.46-1.91,1,1,0,0,0-.76-1.65A4.6,4.6,0,0,1,9.2,16a4.84,4.84,0,0,1,.87-3,1,1,0,0,0,.24-.83,5,5,0,0,1,0-1.85,3.59,3.59,0,0,1,1.74.92,1,1,0,0,0,1,.23A12.49,12.49,0,0,1,16,11a9.91,9.91,0,0,1,2.65.43,1,1,0,0,0,1-.18,5,5,0,0,1,2-1,4.11,4.11,0,0,1,0,1.91,1.05,1.05,0,0,0,.32,1A4,4,0,0,1,22.68,16a4.29,4.29,0,0,1-4.41,4.46,1,1,0,0,0-.94.65,1,1,0,0,0,.28,1.11c.59.51.5,4,.47,5.36a1,1,0,0,0,.38.81,1,1,0,0,0,.62.21,1.07,1.07,0,0,0,.25,0A13,13,0,0,0,16,3Z"
/>
</g>
</svg>
)
}

The actual SVG code is copied from a website that provides these icons for free. I chose iconfinder.com as the place to get the icons. Many thanks to them!

About Section and Images

Let's begin the creative journey by writing the About page. It's pretty standard across blogs such as ours, since it reveals a bit about the author, their experience, what they enjoy doing etc.

We will create an about.tsx file in the pages directory, with the following content, for now:

import React from 'react'

export default function About() {
return <div>Hello from Silviu!</div>
}

With Docusaurus' magic, when we navigate to localhost:3001/about, or by clicking the About link in the navbar that we just created, we will be greeted by a brand new page created for us automatically, displaying the Hello from Silviu message.

We will structure the About page in multiple sections. Each section will contain one image and one subsection with text paragraphs. Since the page is going to be built fully by us, it means that we are responsible for making it look great on any device. It must look great on a wide computer screen as well as on a small phone display. To achieve this, we will use responsive design techniques, with relative sizes and layout shifts. The styling will be done with a separate CSS file, about.module.css, which will contain the CSS declarations. These declarations will be imported in the .tsx file and applied to the elements that need to be styled, like below:

  // in about.tsx
<section className={`${styles.sectionContent} ${styles.sectionLargerContent}`}>
/* in about.module.css */
.sectionContent {
flex-grow: 1;
}

.sectionLargerContent {
flex-basis: 540px;
}

The layout we want to achieve is the following:

  • on small screens, add both the image and content on the same column.
  • on wide enough screens, move the content and image side by side on separate columns.
  • on all screens, make the image and content sizes dynamic, so they can grow along with the display size.
  • in the cases where we consider that the sections width is large enough, we will prevent the sections from growing, and instead add a dynamic horizontal margin between them and the screen edge, so they stay centered.

After carefully observing how our content looks on different screen widths, we will create the following break points in our app:

  1. up until 640 pixels, we will have only one column, for both images and content, and the column will grow as big as the screen.
  2. between 640 pixels and 1020 pixels, we will keep the same 1-column design, but we will stop it from growing as well. Instead, we will center this column, and add left and right margins to compensate for the rest of the width.
  3. 1020 pixels and 1280 pixels, we will perform a layout shift, and we will move the images and the content sections in separate columns, side by side. We will also let them grow dynamically if there is more space to go around.
  4. at 1280 pixels and above, we will keep the sections with 2 columns, but we will block their width at 1280 pixels, and perform the same horizontal margin like we did on point 2.

The important thing to know here is that we will choose to display responsive images. We will serve different sizes of images for different size of displays, as it is not necesary to send, over the network, a full size image if you are viewing the page on a phone.

For example, this will be the markup for the first author image:

<img
className={`${styles.sectionImage} ${styles.sectionPortraitImage}`}
alt="silviu sitting in front of to the fountain in piazza de ferrari in genoa"
src="/img/pictures/silviu-about-the-author-1800w.jpg"
srcSet="/img/pictures/about-author-400w.jpg 400w, /img/pictures/about-author-600w.jpg 600w, /img/pictures/about-author-800w.jpg 800w, /img/pictures/about-author-1000w.jpg 1000w, /img/pictures/about-author-1200w.jpg 1200w, /img/pictures/about-author-1500w.jpg 1500w, /img/pictures/about-author-1800w.jpg 1800w"
sizes="(max-width: 639px) 100vw, (min-width: 640px) and (max-width: 1019px) 608px, (min-width: 1020px) and (max-width: 1279px) 40vw, (min-width: 1280px) 522px"
/>

Whoa, whoa, whoa! The only thing we can tell from the markup above is the arrogant alt text for the image. But not to worry, here's what's happening. After playing around with the page in the Chrome DevTools' Device Toolbar, we can check what size will our image take depending on the size of the viewport and the layout that's displayed. Consequently, when our image shares the same column with the text content (up until 1020px width), its width varies between 0 and 608 pixels. When it has a separate column from the text content, its width varies between 415 and 522 pixels.

With this data gathered successfully, we will fill the sizes attribute of the <img> element, informing it about its size. By itself, the <img> cannot know this information, since it's oblivious to the css that's going to be apllied to it. So, with the sizes atttribute, we are helping it with this information.

Now, we also need to provide our <img> friend with a multitude of image sizes to choose from, with the help of the srcSet attribute. Our friend is smart enough to do the math, at least, and it will calculate the viewport width, multiply it by the DPI factor of the device, check via the sizes attribute what picture size it needs, and chooses the appropriate one via srcSet. And by appropriate, I mean the smallest one possible without making any compromise in quality.

For example, on a 3x DPI ratio phone with a 390 pixels width screen, it should pick the 1200w picture to display, since the picture itself uses the whole screen horizontally.

We will create, consequently, different picture copies, one for each size. I used Image Resizer since I was pretty happy with the result and the experience for generating the images we need. We will add the downloaded pictures in the static/img/pictures folder.

With the responsive images part dealt with, we can focus on writing and finish the author page. For example, this is the markdown for the header part of the page, with both paragraphs and a picture next to them.

Header Code.
<header>
<article>
<h2>About the author</h2>
<section className={styles.aboutTheAuthor}>
<section>
<p>
Hi, I'm Silviu, and I'm a software engineer 👨‍💻. When I'm not coding, I
spend my time playing basketball 🏀, salsa dancing 🕺 and drinking
cofee ☕️. I also drink coffee when coding, so there's that.
</p>
<p>
I believe that writing is an important way to improve myself and
others. If I write about a particular subject, without someone
explicitly forcing me to do it, it means that I aim to understand that
subject well enough. And I consider it important enough to share it
with someone else. It's the reason why I built this blog, to thing and
write about stuff that is helpful to me and can also be helpful to
others.
</p>
<figure>
<blockquote cite="https://youtu.be/bfDOoADCfkg">
<p>
<i>
Thinking makes you act effectively in the world. Thinking makes
you win the battles you undertake, and those could be battles
for good things. If you can think and speak and write, you are
absolutely deadly. Nothing can get in your way.
</i>
</p>
</blockquote>
<figcaption>
—Jordan Peterson, <cite>The Power of Writing</cite>
</figcaption>
</figure>
</section>
<img
className={styles.authorImage}
alt="silviu sitting in front of to the fountain in piazza de ferrari in genoa"
src="/img/pictures/silviu-about-the-author-1080w.jpg"
srcSet="/img/pictures/silviu-about-the-austyles.articleInContentthor-360w.jpg, /img/pictures/silviu-about-the-author-720w.jpg 2x, /img/pictures/silviu-about-the-author-1080w.jpg 3x"
width={360}
/>
</section>
</article>
</header>

Oh, and if you're interested in the resulting css styles file, here it is:

about.module.css
.mainContainer {
max-width: 640px;
margin: 2rem auto;
width: 100%;
padding: 0 1rem;
text-align: justify;
}

.sectionContainer {
display: flex;
gap: 1.5rem;
flex-wrap: wrap;
}

.sectionImage {
flex-grow: 1;
object-fit: contain;
align-self: start;
min-width: 0;
}

.sectionPortraitImage,
.sectionSmallerContent {
flex-basis: 410px;
}

.sectionLandscapeImage,
.sectionLargerContent {
flex-basis: 550px;
}

.sectionContent {
flex-grow: 1;
}

@media (min-width: 1020px) {
.mainContainer {
max-width: 1280px;
}

.articleInContent {
margin-bottom: 2.5rem;
}

.educationAndInternshipsImage,
.softwareEngineeringMicrosoftImage {
order: 1;
}
}

@media (min-width: 1020px) and (max-width: 1279px) {
.hobbiesContent {
flex-basis: 980px;
}

.hobbiesMargaritaImage,
.hobbiesCapuccinoImage {
order: 1;
}
}

@media (min-width: 1280px) {
.hobbiesContent,
.hobbiesMargaritaImage,
.hobbiesCapuccinoImage {
flex-basis: 400px;
}
}

Writing the Post

In the blog folder, we already have some illustrative examples on how to write posts. We will review and delete them afterwards, since we only want to publish or own stuff. We have 2 options to write the blog post:

  1. Create an .md file directly in the blog folder.
  2. Create a folder containing at least an index.md file.

We will choose the second option since we also want to include the image along with the blog post file. We will name the folder using the format suggested in the illustrative examples, 2022-11-26-building-this-blog. The first part is the date of writing the post, the second is the blog post name, all in kebab case. We will also add the mountain-cabin.jpg image that will be included in the post.

Consequently, this blog post will contain the actual text content, an image that should be illustrative for the post, and some code snippets that are going to be relevant to following along the technical process.

Final Thoughts

And we're done! If you've made it until the end, you're a hero, and the Gryffindor House receives 10 points! We have covered a lot in this post:

  • the technology stack used to create and publish our digital online blog.
  • setting up the Docusaurus template with our own content in order to make the blog about us.
  • techniques for responsive images, accessible icons and components swizzling.
  • writing the About page.
  • writing the actual blog post.

The reason I wrote this blog post is not so much as to give a technical tutorial, although I did try to be as explicit as possible with the process itself. My sincere goal is to encourage everyone to build their own blog and start writing about things you are passionate about. I do want to read all about it!

Good luck!