Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/little-pianos-poke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"openscript-ch-website": patch
---

Add formation page
124 changes: 124 additions & 0 deletions src/components/Timeline.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
---
type Props = {
elements: {
text: string;
title: string;
}[];
shortSpine?: boolean;
};

const { elements, shortSpine = false } = Astro.props;

const spineHeight = shortSpine ? "100%" : "calc(100% + var(--size-height-divider) + (2 * var(--size-gutter-massive)))";
const displayTriangle = shortSpine ? "none" : "absolute";
---

<div class="timeline">
<ol>
{
elements.map((element) => (
<li>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For more flexibility, maybe we should add a <TimelineEntry> component and use it here via <slot>. For example I already wish to add a date or year, but I would have to change the props of the Timeline component.

<h6>{element.title}</h6>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we shouldn't use h6 here, because of the following reasons:

  • There is a gap in the hierarchy of chapters (e.g. no h5 is used), what is semantically incorrect.
  • Chapter should be used in the context of an article, but here it's inside a list.

I suggest to use a <div class="title">.

<p>{element.text}</p>
</li>
))
}
</ol>
</div>

<style define:vars={{ spineHeight, displayTriangle }}>
.timeline {
position: relative;
}

h6 {
margin-top: 0;
}

p {
font-size: 15px;
}

ol {
list-style: none;
margin: 0;
padding: 0;

display: flex;
flex-direction: column;
gap: var(--timeline-gap);
}

/* spine of the timeline */
.timeline::before {
content: "";
width: 4px;
height: var(--spineHeight);
position: absolute;
left: 50%;
transform: translateX(-50%);
background-color: var(--color-primary);
z-index: 3; /* above potential dividers */
}

li {
display: flex;
flex-direction: column;
box-sizing: border-box;
padding: 1rem;
background: var(--color-overlay);
width: 45%;
box-shadow: 0px 15px 30px -15px rgba(0, 0, 0, 0.5);
}

li::after {
content: "";
width: 20px;
height: 20px;
border-radius: 50%;
border-width: 4px;
border-style: solid;
border-color: var(--color-primary);
background: var(--color-white);
position: absolute;
left: 50%;
transform: translateX(-50%);
z-index: 5; /* above spine */
}

@media screen and (min-width: 1025px) {
ol li:nth-child(even) {
align-self: flex-end;
}
}

@media screen and (max-width: 1025px) {
li::after {
left: 90%;
}

.timeline::before {
left: 90%;
}

.timeline::after {
content: "";
width: 20px;
aspect-ratio: 1;
clip-path: polygon(0 0, 50% 100%, 100% 0);
background-color: var(--color-primary);
left: calc(90% - 10px);
bottom: calc(-1 * (5px + var(--size-height-divider) + (2 * var(--size-gutter-massive))));
position: var(--displayTriangle);
z-index: 3; /* above potential dividers */
}

li {
width: 85%;
}

li:not(:last-child) {
margin-bottom: 4rem;
}
}
</style>
17 changes: 17 additions & 0 deletions src/content.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,22 @@ const galleriesCollection = defineCollection({
),
});

const formationCollection = defineCollection({
loader: i18nContentLoader({ pattern: "**/[^_]*.yaml", base: "./src/content/formation" }),
schema: extendI18nLoaderSchema(
z.object({
items: localized(
z.array(
z.object({
title: z.string(),
text: z.string(),
}),
),
),
}),
),
});

export const collections = {
navigation: navigationCollection,
pages: pagesCollection,
Expand All @@ -148,4 +164,5 @@ export const collections = {
technologies: technologiesCollection,
team: teamCollection,
galleries: galleriesCollection,
formation: formationCollection,
};
15 changes: 15 additions & 0 deletions src/content/formation/evolution.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
items:
de:
- title: Lorem
text: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
- title: Lorem
text: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
- title: Lorem
text: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
en:
- title: Lorem
text: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
- title: Lorem
text: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
- title: Lorem
text: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
11 changes: 11 additions & 0 deletions src/content/formation/founding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
items:
de:
- title: Web-Domain
text: Bereits am 24. April 2007 wurde die Domain openscript.ch registriert.
- title: Handelsregistereintrag
text: Seit dem 23. Januar 2020 sind wir im Handelsregister eingetragen.
en:
- title: Web Domain
text: The domain openscript.ch was already registered on April 24, 2007.
- title: Commercial Register Entry
text: We have been registered in the commercial register since January 23, 2020.
15 changes: 15 additions & 0 deletions src/content/formation/office.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
items:
de:
- title: Lorem
text: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
- title: Lorem
text: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
- title: Lorem
text: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
en:
- title: Lorem
text: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
- title: Lorem
text: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
- title: Lorem
text: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
34 changes: 34 additions & 0 deletions src/content/pages/de/past/formation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,37 @@
path: entstehung
title: Entstehung
---

import FormationSection from "../../../../layouts/sections/FormationSection.astro";
import Divider from "../../../../components/Divider.astro";

<FormationSection class="spotlight" key="founding">
<h2 name="title">Gründung</h2>

Obwohl die Idee und der Name schon einige Zeit zuvor existierten, wurde die Firma offiziell im Januar 2020 von Robin gegründet. Bald nach der Gründung ist Diego als zweiten Mitgründer dazugestossen. Fortan arbeiteten die beiden daran, die ersten Softwareprojekte umzusetzen.

</FormationSection>

<Divider firstSegmentColor="var(--color-white)" fixAntialiasingBottom />

<FormationSection class="white-background" key="office">
<h2 name="title">Büro und Mitarbeiter</h2>

Zuerst dachten wir, dass wir einfach von zu Hause aus arbeiten. Doch als wir davon erfuhren, dass in Oerlikon das ehemalige Swissôtel in eine WG für Studenten und Startups umgewandelt wird, haben wir uns sofort beworben und Glück gehabt. Die Geschichte kann [hier](https://www.srf.ch/news/schweiz/mit-rund-300-mitbewohnern-dieser-ehemalige-hotelturm-wird-zur-mega-wg) nachgelesen werden. Somit hatten wir von Februar 2021 bis Ende Jahr unser erstes Büro mitten in Oerlikon.

Dabei haben wir festgestellt, dass es uns sehr hilft, wenn wir uns regelmässig persönlich austauschen können. Deshalb haben wir uns entschieden, auch nach der Zwischennutzung des Swissôtels ein Büro zu mieten. Schnell haben wir ein passendes Büro in Glattbrugg gefunden, welches wir seit Anfang 2022 nutzen.

In der Zwischenzeit sind auch weitere Mitarbeiter zu uns gestossen, welche uns bei der Umsetzung unserer Projekte unterstützen.

</FormationSection>

<Divider firstSegmentColor="var(--color-white)" flipVertical fixAntialiasingTop />

<FormationSection class="dark-background" key="evolution" last>
<h2 name="title">Entwicklung</h2>

Seither haben wir uns stetig weiterentwickelt und neue Projekte realisiert, die unsere Vision und Mission unterstützen. Wir freuen uns auf die kommenden Herausforderungen und Chancen, die vor uns liegen.

Möchtest du auch Teil unserer Reise werden? Schau dir unsere [Jobs-Seite](../zukunft/jobs) an oder nimm Kontakt auf, falls du dein Projekt mit uns umsetzen möchtest!

</FormationSection>
35 changes: 35 additions & 0 deletions src/content/pages/en/past/formation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,38 @@
path: formation
title: Formation
---


import FormationSection from "../../../../layouts/sections/FormationSection.astro";
import Divider from "../../../../components/Divider.astro";

<FormationSection class="spotlight" key="founding">
<h2 name="title">Founding</h2>

Although the idea and name had existed for some time before, the company was officially founded by Robin in January 2020. Shortly after the founding, Diego joined as the second co-founder. From then on, the two worked together to implement the first software projects.

</FormationSection>

<Divider firstSegmentColor="var(--color-white)" fixAntialiasingBottom />

<FormationSection class="white-background" key="office">
<h2 name="title">Office and employees</h2>

At first, we thought we would simply work from home. But when we learned that the former Swissôtel in Oerlikon was being converted into shared accommodation for students and startups, we applied immediately and were lucky. The story can be read [here](https://www.srf.ch/news/schweiz/mit-rund-300-mitbewohnern-dieser-ehemalige-hotelturm-wird-zur-mega-wg). Thus, we had our first office in the heart of Oerlikon from February 2021 until the end of the year.

In doing so, we realized that it helps us greatly when we can exchange ideas in person regularly. Therefore, we decided to rent an office even after the interim use of the Swissôtel. We quickly found a suitable office in Glattbrugg, which we have been using since early 2022.

In the meantime, additional employees have joined us, supporting us in the implementation of our projects.

</FormationSection>

<Divider firstSegmentColor="var(--color-white)" flipVertical fixAntialiasingTop />

<FormationSection class="dark-background" key="evolution" last>
<h2 name="title">Evolution</h2>

Since then, we have continuously evolved and realized new projects that support our vision and mission. We look forward to the upcoming challenges and opportunities that lie ahead.

Would you like to become part of our journey? Check out our [jobs page](../future/jobs) or get in touch if you want to realize your project with us!

</FormationSection>
1 change: 1 addition & 0 deletions src/layouts/Shell.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
--color-background: #ede9df;
--color-black: #231f20;
--color-white: #fbfffb;
--color-overlay: #f7f9f3;

--size-gutter: 1rem;
--size-gutter-big: 2rem;
Expand Down
49 changes: 49 additions & 0 deletions src/layouts/sections/FormationSection.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
import { currentLocale } from "astro-nanostores-i18n:runtime";
import Timeline from "../../components/Timeline.astro";
import { getCollection } from "astro:content";

type Props = {
key: string;
class?: string;
last?: boolean;
};

const { key, class: className, last } = Astro.props;

const locale = currentLocale.get();

const timelineCollection = await getCollection("formation", (entry) => entry.data.locale === locale);

const formationData = timelineCollection
.filter((t) => t.id.includes(key))
.flatMap((t) => {
if (Array.isArray(t.data.items)) {
return t.data.items.map((item) => ({ ...item }));
}
return [];
});
---

<section class:list={[className]}>
<div>
<slot name="title" />
<slot />
</div>
Comment on lines +29 to +32
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The additional slot doesn't seem to be necessary.

Suggested change
<div>
<slot name="title" />
<slot />
</div>
<div>
<slot />
</div>

<Timeline elements={formationData} shortSpine={last} />
</section>

<style>
section {
display: grid;
column-gap: 1.5rem;
grid-template-columns: 60% 40%;
}

@media screen and (max-width: 1025px) {
section {
grid-template-columns: 100%;
row-gap: 1rem;
}
}
</style>