diff --git a/apps/web/src/app/[lang]/components/home-page-section/comparison/i18n/comparison.i18n.de.json b/apps/web/src/app/[lang]/components/home-page-section/comparison/i18n/comparison.i18n.de.json index b12a4dc..e3f9dab 100644 --- a/apps/web/src/app/[lang]/components/home-page-section/comparison/i18n/comparison.i18n.de.json +++ b/apps/web/src/app/[lang]/components/home-page-section/comparison/i18n/comparison.i18n.de.json @@ -8,6 +8,18 @@ "scibly": "scibly" }, "rows": [ + { + "kind": "learner", + "label": "Onboarding", + "legacy": "Checkliste in Tabelle oder PDF", + "scibly": "Geführtes Onboarding mit Fortschritt und Rückfragen, das mit jedem Teammitglied besser wird." + }, + { + "kind": "import", + "label": "Wissenstransfer", + "legacy": "Wissen geht mit dem Mitarbeiter", + "scibly": "Wissen wird kontinuierlich gesichert" + }, { "kind": "import", "label": "Kurserstellung", diff --git a/apps/web/src/app/[lang]/components/home-page-section/comparison/i18n/comparison.i18n.en.json b/apps/web/src/app/[lang]/components/home-page-section/comparison/i18n/comparison.i18n.en.json index a7c7435..361abc8 100644 --- a/apps/web/src/app/[lang]/components/home-page-section/comparison/i18n/comparison.i18n.en.json +++ b/apps/web/src/app/[lang]/components/home-page-section/comparison/i18n/comparison.i18n.en.json @@ -8,6 +8,18 @@ "scibly": "scibly" }, "rows": [ + { + "kind": "learner", + "label": "Onboarding", + "legacy": "Checklist in a spreadsheet or PDF", + "scibly": "Guided onboarding with progress and questions that improves with every team member." + }, + { + "kind": "import", + "label": "Knowledge Transfer", + "legacy": "Knowledge leaves with the employee", + "scibly": "Knowledge is captured continuously" + }, { "kind": "import", "label": "Content Creation", diff --git a/apps/web/src/app/[lang]/components/home-page-section/cta/calendly-embed.tsx b/apps/web/src/app/[lang]/components/home-page-section/cta/calendly-embed.tsx index 49f3721..4dcfe12 100644 --- a/apps/web/src/app/[lang]/components/home-page-section/cta/calendly-embed.tsx +++ b/apps/web/src/app/[lang]/components/home-page-section/cta/calendly-embed.tsx @@ -5,7 +5,7 @@ import { useCallback, useState } from "react"; const CALENDLY_CSS = "https://assets.calendly.com/assets/external/widget.css"; const CALENDLY_JS = "https://assets.calendly.com/assets/external/widget.js"; -const DEFAULT_DEMO_URL = "https://calendly.com/felix-kuennecke/scibly-demo"; +const CALENDLY_DEMO_URL = "https://calendly.com/felix-kuennecke/scibly-demo"; declare global { interface Window { @@ -24,13 +24,13 @@ function ensureCalendlyStylesheet() { document.head.appendChild(link); } -export function useCalendlyPopup(url: string = DEFAULT_DEMO_URL) { +export function useCalendlyPopup() { const [scriptReady, setScriptReady] = useState(false); const openCalendly = useCallback(() => { if (!window.Calendly) return; - window.Calendly.initPopupWidget({ url }); - }, [url]); + window.Calendly.initPopupWidget({ url: CALENDLY_DEMO_URL }); + }, []); // Stylesheet is injected when the lazyOnload script arrives: after the // landing page's own bytes, but before any human can click — injecting at diff --git a/apps/web/src/app/[lang]/components/home-page-section/cta/cta.tsx b/apps/web/src/app/[lang]/components/home-page-section/cta/cta.tsx index 88a6563..b9f6a40 100644 --- a/apps/web/src/app/[lang]/components/home-page-section/cta/cta.tsx +++ b/apps/web/src/app/[lang]/components/home-page-section/cta/cta.tsx @@ -21,7 +21,6 @@ import { type CtaDictionary } from "./i18n/cta.types"; interface CtaSectionProps { t: CtaDictionary; - calendlyUrl?: string; } const FLOATING_CHAPTERS: Array<{ @@ -55,11 +54,10 @@ const FLOATING_CHAPTERS: Array<{ }, ]; -export function CtaSection({ t, calendlyUrl }: CtaSectionProps) { +export function CtaSection({ t }: CtaSectionProps) { const params = useParams(); const locale = typeof params.lang === "string" ? params.lang : "de"; - const { openCalendly, scriptReady, calendlyScript } = - useCalendlyPopup(calendlyUrl); + const { openCalendly, scriptReady, calendlyScript } = useCalendlyPopup(); useEffect(() => { if (window.location.hash !== "#cta-section") return; diff --git a/apps/web/src/app/[lang]/components/home-page-section/cta/i18n/cta.i18n.de.json b/apps/web/src/app/[lang]/components/home-page-section/cta/i18n/cta.i18n.de.json index afb6168..97b478a 100644 --- a/apps/web/src/app/[lang]/components/home-page-section/cta/i18n/cta.i18n.de.json +++ b/apps/web/src/app/[lang]/components/home-page-section/cta/i18n/cta.i18n.de.json @@ -1,7 +1,7 @@ { "cta": { - "eyebrow": "Bereit, Corporate Learning neu zu denken?", - "title": "Der erste Kurs geht auf uns. Jetzt anfragen und diese Woche noch live gehen.", + "eyebrow": "Bereit, Wissenstransfer neu zu denken?", + "title": "Bereit, Wissen besser zu teilen und neue Mitarbeiter schneller einzuarbeiten?", "button": "Demo anfordern", "hint": "Unverbindlich · Wir melden uns persönlich" } diff --git a/apps/web/src/app/[lang]/components/home-page-section/cta/i18n/cta.i18n.en.json b/apps/web/src/app/[lang]/components/home-page-section/cta/i18n/cta.i18n.en.json index 7ab7020..35e3eb7 100644 --- a/apps/web/src/app/[lang]/components/home-page-section/cta/i18n/cta.i18n.en.json +++ b/apps/web/src/app/[lang]/components/home-page-section/cta/i18n/cta.i18n.en.json @@ -1,7 +1,7 @@ { "cta": { - "eyebrow": "Ready to rethink corporate learning?", - "title": "Your first course is on us. Request a demo and go live this week.", + "eyebrow": "Ready to rethink knowledge transfer?", + "title": "Ready to share knowledge better and onboard new hires faster?", "button": "Request demo", "hint": "No commitment · We'll reach out personally" } diff --git a/apps/web/src/app/[lang]/components/home-page-section/faq/faq.tsx b/apps/web/src/app/[lang]/components/home-page-section/faq/faq.tsx index 7a7cba9..fd91ef2 100644 --- a/apps/web/src/app/[lang]/components/home-page-section/faq/faq.tsx +++ b/apps/web/src/app/[lang]/components/home-page-section/faq/faq.tsx @@ -9,20 +9,10 @@ import { MarketingSection, MarketingSectionHeader, } from "@/app/[lang]/components/marketing-section-content"; -import { type PillarId } from "@/app/[lang]/components/marketing-tokens"; import { FaqList } from "@/components/faq/faq-list"; import { type FaqDictionary } from "./i18n/faq.types"; -const FAQ_CHAPTERS = new Map([ - ["lms-migration", "import"], - ["ai-analytics", "analytics"], - ["customize-ai-courses", "byoai"], - ["microlearning", "learner"], - ["flow-of-work", "channels"], - ["bring-your-own-ai", "byoai"], -]); - const FAQ_INDENTS = [ "top-[16%] left-[4%] hidden xl:block", "right-[4%] bottom-[22%] hidden xl:block", @@ -68,12 +58,7 @@ export function FaqSection({ t, locale }: FaqSectionProps) { className="lg:sticky lg:top-[120px]" /> - + ); } diff --git a/apps/web/src/app/[lang]/components/home-page-section/faq/i18n/faq.i18n.de.json b/apps/web/src/app/[lang]/components/home-page-section/faq/i18n/faq.i18n.de.json index e99d90d..bbe31bb 100644 --- a/apps/web/src/app/[lang]/components/home-page-section/faq/i18n/faq.i18n.de.json +++ b/apps/web/src/app/[lang]/components/home-page-section/faq/i18n/faq.i18n.de.json @@ -5,39 +5,29 @@ "subtitle": "Hier sind einige der am häufigsten gestellten Fragen. Falls du weitere Fragen hast, wende dich gerne an team@scibly.com.", "questions": [ { - "id": "lms-migration", - "q": "Wie aufwendig ist der Wechsel von einem bestehenden LMS?", - "a": "Sehr gering. Du lädst deine bestehenden Inhalte einfach hoch und die KI erstellt daraus automatisch strukturierte, interaktive Mikrolektionen. Statt einer reinen Migration entsteht so mit minimalem Aufwand ein echtes Qualitätsupgrade deiner Lerninhalte." + "id": "what-is-scibly", + "q": "Was ist Scibly?", + "a": "Scibly macht Wissen aus den Köpfen eurer Experten für das ganze Unternehmen zugänglich. Aus bestehendem Wissen entstehen automatisch aktuelle Dokumentationen und Kurse sowie rollenbasierte Onboarding-Programme. So wird Wissen besser verteilt und neue Mitarbeitende schneller eingearbeitet." }, { - "id": "ai-analytics", - "q": "Wie unterscheiden sich die KI Analysen von einem klassischen LMS?", - "a": "Neben dem Lernfortschritt siehst du, bei welchen Themen Wissenslücken entstehen. Du kannst Fragen in Alltagssprache stellen und erhältst konkrete Auswertungen auf Themenebene." + "id": "how-does-scibly-work", + "q": "Wie funktioniert Scibly?", + "a": "Scibly führt geführte Interviews mit euren Fachleuten und erschließt Wissen aus Quellen wie Slack, Code Reviews, Tickets und Dokumenten. Daraus entsteht eine Wissensbasis mit Quellenangaben, aus der sich Kurse und rollenbasierte Onboardings erstellen lassen. Zusätzlich können neue Teammitglieder direkt im Onboarding Fragen stellen und Feedback geben, wodurch sich das Onboarding automatisiert kontinuierlich verbessert." }, { "id": "data-security", - "q": "Wie sicher sind meine Unternehmensdaten?", - "a": "Alle Daten werden DSGVO konform in der EU verarbeitet und verschlüsselt gespeichert. Deine Inhalte werden niemals für das Training von KI Modellen verwendet. Das ist für uns keine Option, keine Grauzone. Hast du spezifische Sicherheitsanforderungen? Meld dich einfach, wir gehen sie gerne mit dir durch." + "q": "Wie sicher sind meine Daten?", + "a": "Scibly ist DSGVO-konform und nutzt ausschließlich in der EU gehostete Modelle. Deine Daten werden weder für das Training von KI-Modellen verwendet noch an Dritte weitergegeben und sind sowohl bei der Übertragung als auch bei der Speicherung verschlüsselt. Für maximale Kontrolle kannst du Scibly außerdem selbst hosten, denn Scibly ist Open Source." }, { - "id": "customize-ai-courses", - "q": "Kann ich KI generierte Kurse anpassen?", - "a": "Ja. Die KI erstellt einen fundierten Erstentwurf, den du im interaktiven Editor vollständig anpassen kannst, von Inhalten über Struktur bis hin zu eigenen Medien." + "id": "getting-started", + "q": "Wie schnell sind wir startklar?", + "a": "Nachdem Scibly mit bestehenden Tools wie Slack, GitHub oder Notion verbunden wurde, beginnt die Wissensextraktion automatisch. Aus dem gewonnenen Wissen lassen sich zusätzlich mit unserem KI-Agenten innerhalb weniger Minuten interaktive Kurse und Onboardings erstellen." }, { - "id": "microlearning", - "q": "Was bedeutet Microlearning bei euch?", - "a": "Wir setzen auf kurze, interaktive Lerneinheiten von 2-3 Minuten. So kann dein Team Lernen leichter in den Arbeitsalltag integrieren und Inhalte regelmäßig auffrischen." - }, - { - "id": "flow-of-work", - "q": "Wie unterstützt scibly Lernen im Arbeitsfluss?", - "a": "Neben klassischen Kursen bringt scibly Lernen dorthin, wo dein Team ohnehin arbeitet, zum Beispiel in Slack oder Microsoft Teams. Mikrolektionen und Quizfragen lassen sich dort ohne zusätzlichen Login absolvieren." - }, - { - "id": "bring-your-own-ai", - "q": "Kann ich eigene KI Modelle nutzen?", - "a": "Ja. Du kannst neben den bereitgestellten Modellen auch freigegebene, unternehmensinterne KI Modelle in scibly integrieren." + "id": "open-source", + "q": "Ist Scibly Open Source?", + "a": "Scibly ist Open Core: Der Großteil des Codes steht unter AGPLv3 auf GitHub, nur einzelne Enterprise-Funktionen sind davon ausgenommen. Du kannst das Repository klonen, den Stack auf deiner eigenen Infrastruktur starten und Scibly selbst hosten." } ] } diff --git a/apps/web/src/app/[lang]/components/home-page-section/faq/i18n/faq.i18n.en.json b/apps/web/src/app/[lang]/components/home-page-section/faq/i18n/faq.i18n.en.json index b32c75f..b77f022 100644 --- a/apps/web/src/app/[lang]/components/home-page-section/faq/i18n/faq.i18n.en.json +++ b/apps/web/src/app/[lang]/components/home-page-section/faq/i18n/faq.i18n.en.json @@ -5,39 +5,29 @@ "subtitle": "Here are some of our most frequently asked questions. If you have any other questions, feel free to reach out to us at team@scibly.com.", "questions": [ { - "id": "lms-migration", - "q": "How difficult is it to switch from an existing LMS?", - "a": "Very effortless. You simply upload your existing content, and the AI automatically turns it into structured, interactive micro lessons. Instead of a mere migration, you get a direct quality upgrade of your learning content with minimal effort." + "id": "what-is-scibly", + "q": "What is Scibly?", + "a": "Scibly makes the knowledge inside your experts' heads accessible to the entire company. Existing knowledge automatically becomes up-to-date documentation and courses as well as role-based onboarding programs. Knowledge spreads further and new hires get up to speed faster." }, { - "id": "ai-analytics", - "q": "How do your AI analytics differ from a traditional LMS?", - "a": "Instead of just measuring progress, our analytics show where knowledge gaps actually exist. You can ask questions in natural language and receive concrete insights at the topic level." + "id": "how-does-scibly-work", + "q": "How does Scibly work?", + "a": "Scibly runs guided interviews with your experts and taps knowledge from sources like Slack, code reviews, tickets and documents. That builds a knowledge base with cited sources, from which courses and role-based onboardings are created. New team members can also ask questions and give feedback right inside the onboarding, so it keeps improving automatically." }, { "id": "data-security", - "q": "How secure is our company data?", - "a": "All data is processed in compliance with GDPR in the EU and stored encrypted. Your content is never used to train AI models. That's not an option for us, not a grey area. Have specific security requirements? Just reach out, we're happy to go through them with you." + "q": "How secure is my data?", + "a": "Scibly is GDPR compliant and uses only models hosted in the EU. Your data is never used to train AI models nor passed on to third parties, and it is encrypted both in transit and at rest. For maximum control you can also self-host Scibly, because Scibly is open source." }, { - "id": "customize-ai-courses", - "q": "Can I customize AI generated courses?", - "a": "Yes. The AI creates a solid first draft that you can fully customize in the interactive editor, from content and structure to your own media." + "id": "getting-started", + "q": "How quickly can we get started?", + "a": "Once Scibly is connected to your existing tools like Slack, GitHub or Notion, knowledge extraction starts automatically. From the knowledge gathered, our AI agent additionally creates interactive courses and onboardings within minutes." }, { - "id": "microlearning", - "q": "What exactly does microlearning mean?", - "a": "We focus on short, interactive learning units of 2-3 minutes. This format integrates seamlessly into the daily workflow and ensures demonstrably better knowledge retention." - }, - { - "id": "flow-of-work", - "q": "How does scibly support Learning in the Flow of Work?", - "a": "In addition to traditional courses, scibly brings learning to where your team already works, for example in Slack or Microsoft Teams. Micro lessons and quizzes can be completed directly there without additional logins. This way, knowledge is continuously expanded and refreshed in the workflow without replacing existing training formats." - }, - { - "id": "bring-your-own-ai", - "q": "Can I use my own AI models?", - "a": "Yes. While other platforms only allow their own models or those from well known proprietary providers, we additionally support Bring Your Own AI. This means you can seamlessly integrate and use your existing, company internal AI tools and models in scibly." + "id": "open-source", + "q": "Is Scibly open source?", + "a": "Scibly is open core: most of the code is on GitHub under AGPLv3, with only a few enterprise features excluded. You can clone the repository, boot the stack on your own infrastructure and self-host Scibly." } ] } diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/knowledge-sources/artifacts-canvas.tsx b/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/artifacts-canvas.tsx similarity index 97% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/knowledge-sources/artifacts-canvas.tsx rename to apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/artifacts-canvas.tsx index 4f0af94..c00b5a7 100644 --- a/apps/web/src/app/[lang]/onboarding-offboarding/components/knowledge-sources/artifacts-canvas.tsx +++ b/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/artifacts-canvas.tsx @@ -3,19 +3,19 @@ import { GitPullRequest, Ticket } from "lucide-react"; import { CORRECT_KEY } from "@/app/[lang]/components/marketing-tokens"; import { BrandLogo } from "@/components/brand-logo"; -import { type ArtifactsCopy } from "../../i18n/onboarding-offboarding.types"; import { enter, FAINT, HAIRLINE, MUTED } from "../mock/mock-theme"; import { MockWindow } from "../mock/mock-window"; import { MockWindowBar } from "../mock/mock-window-bar"; import { CapturedChip } from "./captured-chip"; import { CardCanvas } from "./card-canvas"; +import { type ArtifactsDictionary } from "./i18n/knowledge-sources.types"; import { SLACK_TONE, WORK_TONE } from "./knowledge-sources-tones"; export function ArtifactsCanvas({ t, capturedLabel, }: { - t: ArtifactsCopy; + t: ArtifactsDictionary; capturedLabel: string; }) { return ( diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/knowledge-sources/captured-chip.tsx b/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/captured-chip.tsx similarity index 100% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/knowledge-sources/captured-chip.tsx rename to apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/captured-chip.tsx diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/knowledge-sources/card-canvas.tsx b/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/card-canvas.tsx similarity index 100% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/knowledge-sources/card-canvas.tsx rename to apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/card-canvas.tsx diff --git a/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/i18n/knowledge-sources.i18n.de.json b/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/i18n/knowledge-sources.i18n.de.json new file mode 100644 index 0000000..5b35a6d --- /dev/null +++ b/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/i18n/knowledge-sources.i18n.de.json @@ -0,0 +1,50 @@ +{ + "knowledgeSources": { + "eyebrow": "Wissenstransfer mit Scibly", + "title": "Undokumentiertes Expertenwissen wird erfasst und für alle zugänglich und lernbar gemacht.", + "subtitle": "Das wertvollste Wissen steht in keinem Dokument. Es steckt in den Köpfen der Experten und geht mit ihnen. Scibly hält es fest, bevor es verloren geht.", + "capturedLabel": "Erfasst", + "interview": { + "title": "Interviews", + "description": "Dokumentationen halten fest, wie etwas funktioniert. Scibly fragt nach dem Rest: Ausnahmen, Faustregeln, Gründe hinter Entscheidungen.", + "timer": "14:32", + "aiName": "Scibly KI", + "listeningLabel": "Hört zu …", + "question": "Du hast Payment-Retries erwähnt. Was passiert bei einem Timeout?" + }, + "artifacts": { + "title": "Die tägliche Arbeit liefert den Beleg", + "description": "Scibly extrahiert Wissen aus Slack-Nachrichten, Code-Reviews, Tickets und Docs und speichert jede Erkenntnis mit ihrer Quelle.", + "slackChannel": "#it-support", + "slackTime": "09:41", + "slackAuthor": "Mia", + "slackText": "Nie doppelt retryen, das übernimmt das Gateway.", + "codeFile": "payments/client.ts", + "codeReview": "Review", + "codeRemoved": "await retry(book, 3)", + "codeAdded": "await book()", + "codeComment": "Das Gateway retryt schon serverseitig.", + "ticketId": "INFRA-482", + "ticketStatus": "Gelöst", + "ticketTitle": "Doppelte Buchung nach Timeout", + "ticketCause": "Ursache: Client-Retry nach Timeout" + }, + "lesson": { + "title": "Mehr als nur Wissensextraktion", + "description": "Das extrahierte Wissen wird nicht nur zentral gespeichert, sondern kann mit nur einem Knopfdruck automatisch in interaktive Lerneinheiten verwandelt werden.", + "lessonEyebrow": "Lektion 4 von 9", + "lessonTitle": "Payment-Retries richtig behandeln", + "quizQuestion": "Ein Request läuft in einen Timeout. Was jetzt?", + "quizOptionWrong": "Sofort neu buchen", + "quizOptionRight": "Buchungsstatus prüfen, nicht retryen", + "derivedLabel": "Daraus generiert" + }, + "knowledge": { + "eyebrow": "Wissensbasis", + "title": "Payment-Retries", + "fact1": "Retries übernimmt ausschließlich das Gateway.", + "fact2": "Ein Timeout heißt nicht abgebrochen.", + "verifiedLabel": "3 Quellen · verifiziert" + } + } +} diff --git a/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/i18n/knowledge-sources.i18n.en.json b/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/i18n/knowledge-sources.i18n.en.json new file mode 100644 index 0000000..a5407bf --- /dev/null +++ b/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/i18n/knowledge-sources.i18n.en.json @@ -0,0 +1,50 @@ +{ + "knowledgeSources": { + "eyebrow": "Knowledge transfer with Scibly", + "title": "Undocumented expertise gets captured and made accessible and learnable for everyone.", + "subtitle": "The most valuable knowledge is written down nowhere. It sits in your experts' heads and leaves with them. Scibly captures it before it is lost.", + "capturedLabel": "Captured", + "interview": { + "title": "Interviews", + "description": "Documentation records how something works. Scibly asks about the rest: the exceptions, the rules of thumb, the reasons behind decisions.", + "timer": "14:32", + "aiName": "Scibly AI", + "listeningLabel": "Listening…", + "question": "You mentioned payment retries. What happens on a timeout?" + }, + "artifacts": { + "title": "Everyday work supplies the evidence", + "description": "Scibly extracts knowledge from Slack messages, code reviews, tickets, and docs, and stores every insight with its source.", + "slackChannel": "#it-support", + "slackTime": "09:41", + "slackAuthor": "Mia", + "slackText": "Never retry twice, the gateway already does.", + "codeFile": "payments/client.ts", + "codeReview": "Review", + "codeRemoved": "await retry(book, 3)", + "codeAdded": "await book()", + "codeComment": "The gateway already retries server-side.", + "ticketId": "INFRA-482", + "ticketStatus": "Resolved", + "ticketTitle": "Duplicate booking after timeout", + "ticketCause": "Cause: client retry after timeout" + }, + "lesson": { + "title": "More than knowledge extraction", + "description": "The extracted knowledge is not just stored centrally, it can be turned into interactive learning units automatically, at the push of a button.", + "lessonEyebrow": "Lesson 4 of 9", + "lessonTitle": "Handling payment retries", + "quizQuestion": "A request hits a timeout. Now what?", + "quizOptionWrong": "Book again right away", + "quizOptionRight": "Check the booking status, don't retry", + "derivedLabel": "Generated from it" + }, + "knowledge": { + "eyebrow": "Knowledge base", + "title": "Payment retries", + "fact1": "Retries are handled by the gateway only.", + "fact2": "A timeout doesn't mean cancelled.", + "verifiedLabel": "3 sources · verified" + } + } +} diff --git a/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/i18n/knowledge-sources.types.ts b/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/i18n/knowledge-sources.types.ts new file mode 100644 index 0000000..ecd69bd --- /dev/null +++ b/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/i18n/knowledge-sources.types.ts @@ -0,0 +1,56 @@ +export type InterviewDictionary = { + title: string; + description: string; + timer: string; + aiName: string; + listeningLabel: string; + question: string; +}; + +export type ArtifactsDictionary = { + title: string; + description: string; + slackChannel: string; + slackTime: string; + slackAuthor: string; + slackText: string; + codeFile: string; + codeReview: string; + codeRemoved: string; + codeAdded: string; + codeComment: string; + ticketId: string; + ticketStatus: string; + ticketTitle: string; + ticketCause: string; +}; + +export type KnowledgeDictionary = { + eyebrow: string; + title: string; + fact1: string; + fact2: string; + verifiedLabel: string; +}; + +export type LessonDictionary = { + title: string; + derivedLabel: string; + description: string; + lessonEyebrow: string; + lessonTitle: string; + quizQuestion: string; + quizOptionWrong: string; + quizOptionRight: string; +}; + +export type KnowledgeSourcesDictionary = { + eyebrow: string; + title: string; + subtitle: string; + capturedLabel: string; + interview: InterviewDictionary; + artifacts: ArtifactsDictionary; + knowledge: KnowledgeDictionary; + lesson: LessonDictionary; +}; diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/knowledge-sources/interview-canvas.tsx b/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/interview-canvas.tsx similarity index 94% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/knowledge-sources/interview-canvas.tsx rename to apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/interview-canvas.tsx index 27f0994..02dd12d 100644 --- a/apps/web/src/app/[lang]/onboarding-offboarding/components/knowledge-sources/interview-canvas.tsx +++ b/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/interview-canvas.tsx @@ -3,13 +3,13 @@ import { Mic, X } from "lucide-react"; import { PRODUCT_INK } from "@/app/[lang]/components/marketing-tokens"; import { SciblyMark } from "@/components/brand-logo"; -import { type InterviewCopy } from "../../i18n/onboarding-offboarding.types"; import { enter } from "../mock/mock-theme"; +import { type InterviewDictionary } from "./i18n/knowledge-sources.types"; import { INTERVIEW_TONE } from "./knowledge-sources-tones"; const WAVEFORM_HEIGHTS = [5, 10, 14, 8, 12, 6, 9]; -export function InterviewCanvas({ t }: { t: InterviewCopy }) { +export function InterviewCanvas({ t }: { t: InterviewDictionary }) { return (
(0.15); const cards = [ diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/knowledge-sources/knowledge-sources-tones.ts b/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/knowledge-sources-tones.ts similarity index 100% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/knowledge-sources/knowledge-sources-tones.ts rename to apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/knowledge-sources-tones.ts diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/knowledge-sources/lesson-canvas.tsx b/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/lesson-canvas.tsx similarity index 97% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/knowledge-sources/lesson-canvas.tsx rename to apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/lesson-canvas.tsx index ce70585..8f82a7d 100644 --- a/apps/web/src/app/[lang]/onboarding-offboarding/components/knowledge-sources/lesson-canvas.tsx +++ b/apps/web/src/app/[lang]/components/home-page-section/knowledge-sources/lesson-canvas.tsx @@ -10,15 +10,15 @@ import { import { CORRECT_KEY, tint } from "@/app/[lang]/components/marketing-tokens"; import { BrandLogo } from "@/components/brand-logo"; -import { - type KnowledgeCopy, - type LessonCopy, -} from "../../i18n/onboarding-offboarding.types"; import { MockQuizCard } from "../mock/mock-quiz-card"; import { enter, FAINT, MUTED } from "../mock/mock-theme"; import { MockWindow } from "../mock/mock-window"; import { MockWindowBar } from "../mock/mock-window-bar"; import { CardCanvas } from "./card-canvas"; +import { + type KnowledgeDictionary, + type LessonDictionary, +} from "./i18n/knowledge-sources.types"; import { INTERVIEW_TONE, LESSON_TONE, @@ -30,8 +30,8 @@ export function LessonCanvas({ knowledge, t, }: { - knowledge: KnowledgeCopy; - t: LessonCopy; + knowledge: KnowledgeDictionary; + t: LessonDictionary; }) { const facts = [ { diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/mock/mock-ground-fade.tsx b/apps/web/src/app/[lang]/components/home-page-section/mock/mock-ground-fade.tsx similarity index 100% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/mock/mock-ground-fade.tsx rename to apps/web/src/app/[lang]/components/home-page-section/mock/mock-ground-fade.tsx diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/mock/mock-quiz-card.tsx b/apps/web/src/app/[lang]/components/home-page-section/mock/mock-quiz-card.tsx similarity index 100% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/mock/mock-quiz-card.tsx rename to apps/web/src/app/[lang]/components/home-page-section/mock/mock-quiz-card.tsx diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/mock/mock-theme.ts b/apps/web/src/app/[lang]/components/home-page-section/mock/mock-theme.ts similarity index 100% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/mock/mock-theme.ts rename to apps/web/src/app/[lang]/components/home-page-section/mock/mock-theme.ts diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/mock/mock-window-bar.tsx b/apps/web/src/app/[lang]/components/home-page-section/mock/mock-window-bar.tsx similarity index 100% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/mock/mock-window-bar.tsx rename to apps/web/src/app/[lang]/components/home-page-section/mock/mock-window-bar.tsx diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/mock/mock-window.tsx b/apps/web/src/app/[lang]/components/home-page-section/mock/mock-window.tsx similarity index 100% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/mock/mock-window.tsx rename to apps/web/src/app/[lang]/components/home-page-section/mock/mock-window.tsx diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/onboarding-flow/checklist-mock.tsx b/apps/web/src/app/[lang]/components/home-page-section/onboarding-flow/checklist-mock.tsx similarity index 92% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/onboarding-flow/checklist-mock.tsx rename to apps/web/src/app/[lang]/components/home-page-section/onboarding-flow/checklist-mock.tsx index 3389a8e..6c5bf33 100644 --- a/apps/web/src/app/[lang]/onboarding-offboarding/components/onboarding-flow/checklist-mock.tsx +++ b/apps/web/src/app/[lang]/components/home-page-section/onboarding-flow/checklist-mock.tsx @@ -2,12 +2,12 @@ import { Check, ListChecks } from "lucide-react"; import { CORRECT_KEY } from "@/app/[lang]/components/marketing-tokens"; -import { type ChecklistCopy } from "../../i18n/onboarding-offboarding.types"; import { enter, FAINT, HAIRLINE, MUTED } from "../mock/mock-theme"; import { MockWindow } from "../mock/mock-window"; import { FlowMockBar } from "./flow-mock-bar"; +import { type ChecklistDictionary } from "./i18n/onboarding-flow.types"; -function numberStepsAcrossGroups(groups: ChecklistCopy["groups"]) { +function numberStepsAcrossGroups(groups: ChecklistDictionary["groups"]) { let stepsBefore = 0; return groups.map((group) => { const items = group.items.map((item, index) => ({ @@ -19,7 +19,7 @@ function numberStepsAcrossGroups(groups: ChecklistCopy["groups"]) { }); } -export function ChecklistMock({ t }: { t: ChecklistCopy }) { +export function ChecklistMock({ t }: { t: ChecklistDictionary }) { const groups = numberStepsAcrossGroups(t.groups); return ( diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/onboarding-flow/course-mock.tsx b/apps/web/src/app/[lang]/components/home-page-section/onboarding-flow/course-mock.tsx similarity index 92% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/onboarding-flow/course-mock.tsx rename to apps/web/src/app/[lang]/components/home-page-section/onboarding-flow/course-mock.tsx index 93a745e..c0beaf6 100644 --- a/apps/web/src/app/[lang]/onboarding-offboarding/components/onboarding-flow/course-mock.tsx +++ b/apps/web/src/app/[lang]/components/home-page-section/onboarding-flow/course-mock.tsx @@ -2,14 +2,14 @@ import { GraduationCap } from "lucide-react"; import { tint } from "@/app/[lang]/components/marketing-tokens"; -import { type CourseCopy } from "../../i18n/onboarding-offboarding.types"; import { MockQuizCard } from "../mock/mock-quiz-card"; import { enter, MUTED } from "../mock/mock-theme"; import { MockWindow } from "../mock/mock-window"; import { FlowMockBar } from "./flow-mock-bar"; +import { type CourseDictionary } from "./i18n/onboarding-flow.types"; import { FLOW_TONE } from "./onboarding-flow-tone"; -export function CourseMock({ t }: { t: CourseCopy }) { +export function CourseMock({ t }: { t: CourseDictionary }) { return ( (0.12); return ( diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/onboarding-flow/onboarding-flow-tone.ts b/apps/web/src/app/[lang]/components/home-page-section/onboarding-flow/onboarding-flow-tone.ts similarity index 100% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/onboarding-flow/onboarding-flow-tone.ts rename to apps/web/src/app/[lang]/components/home-page-section/onboarding-flow/onboarding-flow-tone.ts diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/onboarding-flow/progress-mock.tsx b/apps/web/src/app/[lang]/components/home-page-section/onboarding-flow/progress-mock.tsx similarity index 94% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/onboarding-flow/progress-mock.tsx rename to apps/web/src/app/[lang]/components/home-page-section/onboarding-flow/progress-mock.tsx index 8bff51e..5a84b9b 100644 --- a/apps/web/src/app/[lang]/onboarding-offboarding/components/onboarding-flow/progress-mock.tsx +++ b/apps/web/src/app/[lang]/components/home-page-section/onboarding-flow/progress-mock.tsx @@ -2,13 +2,13 @@ import { ChartNoAxesColumn } from "lucide-react"; import { CORRECT_KEY } from "@/app/[lang]/components/marketing-tokens"; -import { type ProgressCopy } from "../../i18n/onboarding-offboarding.types"; import { enter, HAIRLINE, MUTED } from "../mock/mock-theme"; import { MockWindow } from "../mock/mock-window"; import { FlowMockBar } from "./flow-mock-bar"; +import { type ProgressDictionary } from "./i18n/onboarding-flow.types"; import { FLOW_TONE } from "./onboarding-flow-tone"; -export function ProgressMock({ t }: { t: ProgressCopy }) { +export function ProgressMock({ t }: { t: ProgressDictionary }) { return ( (0.25); // The section is in view long before the stats are, so the counters get their own later threshold. const { ref: statsRef, inView: statsInView } = @@ -36,8 +36,9 @@ export function ProblemNumbersSection({ t }: { t: ProblemNumbersCopy }) { title={t.title} /> -
-
+
+ {/* Mobile drops the hanging indent so the body shares the stats' left edge. */} +
-
-

- {t.problemLabel} -

-

- {t.problemBody} -

-
+

+ {t.problemLabel} +

+

+ {t.problemBody} +

{t.stats.map((stat) => ( -
+
{stat.label} diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/problem-numbers/sliding-number.test.tsx b/apps/web/src/app/[lang]/components/home-page-section/problem-numbers/sliding-number.test.tsx similarity index 100% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/problem-numbers/sliding-number.test.tsx rename to apps/web/src/app/[lang]/components/home-page-section/problem-numbers/sliding-number.test.tsx diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/components/problem-numbers/sliding-number.tsx b/apps/web/src/app/[lang]/components/home-page-section/problem-numbers/sliding-number.tsx similarity index 100% rename from apps/web/src/app/[lang]/onboarding-offboarding/components/problem-numbers/sliding-number.tsx rename to apps/web/src/app/[lang]/components/home-page-section/problem-numbers/sliding-number.tsx diff --git a/apps/web/src/app/[lang]/components/home-page-section/quality-proof/i18n/quality-proof.i18n.de.json b/apps/web/src/app/[lang]/components/home-page-section/quality-proof/i18n/quality-proof.i18n.de.json deleted file mode 100644 index 237ef73..0000000 --- a/apps/web/src/app/[lang]/components/home-page-section/quality-proof/i18n/quality-proof.i18n.de.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "qualityProof": { - "eyebrow": "Vom Wissen zum freigegebenen Kurs", - "title": "Mehr als nur ein Prompt", - "subtitle": "Scibly verbindet deine Inhalte mit Lernwissenschaft, überprüfbaren Quellen und der Erfahrung deines Teams.", - "inputLabel": "Startpunkt", - "inputTitle": "Dein Wissen", - "sourceSamples": [ - "Compliance Handbuch.pdf", - "Onboarding Wiki · Confluence" - ], - "inputs": [ - { - "label": "Bestehendes Wissen", - "detail": "Richtlinien, Handbücher & internes Wissen" - }, - { - "label": "Realer Kontext", - "detail": "Zielgruppe & reale Arbeitssituationen" - } - ], - "coreLabel": "Der Scibly Qualitätskern", - "qualityLayers": [ - { - "title": "Didaktisch aufgebaut", - "body": "Struktur, Beispiele und Wiederholung folgen bewährter Lernwissenschaft." - }, - { - "title": "Bis zur Quelle belegbar", - "body": "Jede Aussage bleibt mit ihrem Ursprung verbunden.", - "proof": { - "kind": "source", - "label": "Handbuch · §4.2 Datenverarbeitung" - } - }, - { - "title": "Von Menschen gesteuert", - "body": "Dein Team bestimmt Inhalt, Ton und Tiefe.", - "proof": { - "kind": "reviewers", - "label": "Vor Veröffentlichung von 3 Experten geprüft" - } - } - ], - "output": { - "label": "Ergebnis", - "title": "Ein Kurs für den Arbeitsalltag", - "body": "Didaktisch fundiert, fachlich geprüft und sofort einsetzbar.", - "status": "Von deinem Team freigegeben" - }, - "differentiation": { - "title": "Warum nicht einfach ChatGPT?", - "body": "Was Unternehmen brauchen, endet nicht beim Prompt. Erst Didaktik, Qualitätssicherung, Zusammenarbeit und Freigaben machen aus KI-generierten Inhalten professionelle Weiterbildung. Genau dafür wurde Scibly entwickelt." - }, - "cta": { - "notebook": { - "eyebrow": "Direkt ausprobieren", - "title": "Als Autor:in erleben.", - "body": "Teste das Notebook und sieh selbst, wie aus Wissen ein fertiger Kurs entsteht.", - "label": "Autoren-Demo öffnen" - }, - "course": { - "eyebrow": "Fertigen Kurs ansehen", - "title": "Als Lernende:r erleben.", - "body": "Durchlaufe einen veröffentlichten Kurs genau so, wie es dein Team erleben würde.", - "label": "Lern-Demo öffnen" - } - } - } -} diff --git a/apps/web/src/app/[lang]/components/home-page-section/quality-proof/i18n/quality-proof.i18n.en.json b/apps/web/src/app/[lang]/components/home-page-section/quality-proof/i18n/quality-proof.i18n.en.json deleted file mode 100644 index da118c3..0000000 --- a/apps/web/src/app/[lang]/components/home-page-section/quality-proof/i18n/quality-proof.i18n.en.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "qualityProof": { - "eyebrow": "From knowledge to approved course", - "title": "More than just a prompt", - "subtitle": "Scibly combines your content with learning science, verifiable sources, and your team’s experience.", - "inputLabel": "Starting point", - "inputTitle": "Your knowledge", - "sourceSamples": [ - "Compliance handbook.pdf", - "Onboarding wiki · Confluence" - ], - "inputs": [ - { - "label": "Existing knowledge", - "detail": "Policies, handbooks & internal expertise" - }, - { - "label": "Real context", - "detail": "Audience & real work situations" - } - ], - "coreLabel": "The Scibly quality core", - "qualityLayers": [ - { - "title": "Instructionally designed", - "body": "Structure, examples, and repetition follow proven learning science." - }, - { - "title": "Traceable to the source", - "body": "Every statement stays connected to its origin.", - "proof": { - "kind": "source", - "label": "Handbook · §4.2 Data handling" - } - }, - { - "title": "Directed by people", - "body": "Your team controls content, tone, and depth.", - "proof": { - "kind": "reviewers", - "label": "Reviewed by 3 experts before publish" - } - } - ], - "output": { - "label": "Result", - "title": "A course built for everyday work", - "body": "Instructionally grounded, subject matter reviewed, and ready to use.", - "status": "Approved by your team" - }, - "differentiation": { - "title": "Why not just use ChatGPT?", - "body": "What companies need doesn’t end at the prompt. Only instructional design, quality assurance, collaboration, and approvals turn AI-generated content into professional training. That’s exactly what Scibly was built for." - }, - "cta": { - "notebook": { - "eyebrow": "Try it now", - "title": "Experience it as an author.", - "body": "Try the notebook and see how knowledge becomes a finished course.", - "label": "Open author demo" - }, - "course": { - "eyebrow": "See a finished course", - "title": "Experience it as a learner.", - "body": "Go through a published course exactly as your team would experience it.", - "label": "Open learner demo" - } - } - } -} diff --git a/apps/web/src/app/[lang]/components/home-page-section/quality-proof/i18n/quality-proof.types.ts b/apps/web/src/app/[lang]/components/home-page-section/quality-proof/i18n/quality-proof.types.ts deleted file mode 100644 index f81d98c..0000000 --- a/apps/web/src/app/[lang]/components/home-page-section/quality-proof/i18n/quality-proof.types.ts +++ /dev/null @@ -1,52 +0,0 @@ -export type QualityProofInput = { - label: string; - detail: string; -}; - -export type QualityProof = { - kind: string; - label: string; -}; - -export type QualityProofLayer = { - title: string; - body: string; - proof?: QualityProof; -}; - -export type QualityProofDictionary = { - eyebrow: string; - title: string; - subtitle: string; - inputLabel: string; - inputTitle: string; - - sourceSamples: string[]; - inputs: QualityProofInput[]; - coreLabel: string; - qualityLayers: QualityProofLayer[]; - output: { - label: string; - title: string; - body: string; - status: string; - }; - differentiation: { - title: string; - body: string; - }; - cta: { - notebook: { - eyebrow: string; - title: string; - body: string; - label: string; - }; - course: { - eyebrow: string; - title: string; - body: string; - label: string; - }; - }; -}; diff --git a/apps/web/src/app/[lang]/components/home-page-section/quality-proof/quality-proof.tsx b/apps/web/src/app/[lang]/components/home-page-section/quality-proof/quality-proof.tsx deleted file mode 100644 index cb1b026..0000000 --- a/apps/web/src/app/[lang]/components/home-page-section/quality-proof/quality-proof.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import { CYBER_SAFETY_COURSE_ID } from "@scibly/course-content/cyber-safety"; -import { type Locale } from "@scibly/i18n/constants"; -import { marketingCourseHref, marketingDemoHref } from "@scibly/routes"; -import { - actionClass, - eyebrowClass, - primaryActionClass, - subtitleClass, -} from "@scibly/ui/design-language"; -import { cn } from "@scibly/ui/utils"; -import { GraduationCap, Play } from "lucide-react"; -import { type ReactNode } from "react"; - -import { - MarketingSection, - MarketingSectionHeader, -} from "@/app/[lang]/components/marketing-section-content"; - -import { type QualityProofDictionary } from "./i18n/quality-proof.types"; -import { QualitySystemMap } from "./quality-system-map"; - -interface QualityProofSectionProps { - t: QualityProofDictionary; - locale: Locale; -} - -const RULE_COLOR = "#e6eaf5"; - -export function QualityProofSection({ t, locale }: QualityProofSectionProps) { - return ( - - - -
- -
- -
- -
-

- {t.differentiation.title} -

-

- {t.differentiation.body} -

-
- -
- - - {t.cta.notebook.label} - - } - /> - - - - {t.cta.course.label} - - } - /> -
- - ); -} - -function ClosingCard({ - id, - lip, - t, - action, -}: { - id: string; - lip: string; - t: { eyebrow: string; title: string; body: string }; - action: ReactNode; -}) { - return ( -
-

{t.eyebrow}

-

- {t.title} -

-

- {t.body} -

- {action} -
- ); -} diff --git a/apps/web/src/app/[lang]/components/home-page-section/quality-proof/quality-system-map.tsx b/apps/web/src/app/[lang]/components/home-page-section/quality-proof/quality-system-map.tsx deleted file mode 100644 index 254b343..0000000 --- a/apps/web/src/app/[lang]/components/home-page-section/quality-proof/quality-system-map.tsx +++ /dev/null @@ -1,211 +0,0 @@ -import { cn } from "@scibly/ui/utils"; -import { Check, Link2 } from "lucide-react"; - -import { - lipShadow, - type Pillar, - PILLARS, - tint, -} from "@/app/[lang]/components/marketing-tokens"; - -import { - type QualityProof, - type QualityProofDictionary, -} from "./i18n/quality-proof.types"; - -interface QualitySystemMapProps { - t: QualityProofDictionary; -} - -const LAYER_TONES = [PILLARS.import, PILLARS.learner, PILLARS.analytics]; - -const OUTPUT_TONE = PILLARS.byoai; - -const smallLabelClass = "text-[11.5px] font-semibold text-ink-soft"; - -const cardTitleClass = - "m-0 text-[clamp(17px,1.6vw,19.5px)] leading-[1.25] font-semibold tracking-[-0.014em] text-ink"; - -const cardBodyClass = - "mt-[7px] mb-0 max-w-[44ch] text-[14.5px] leading-[1.55] text-pretty text-ink-soft"; - -const proofChipClass = - "mt-[5px] inline-flex items-center gap-2 self-start rounded-[9px] bg-[#d3f7ab] py-[7px] pr-3 pl-2.5 shadow-[0_2px_0_0_#a3e163]"; - -const proofChipLabelClass = "text-[12.5px] font-semibold text-[#376e00]"; - -const reviewerTints = [...LAYER_TONES] - .reverse() - .map(({ lipColor }) => lipColor); - -type Rung = { - badge?: string; - label?: string; - title: string; - body: string; - proof?: QualityProof; - tone: Pillar; -}; - -export function QualitySystemMap({ t }: QualitySystemMapProps) { - const rungs: Rung[] = [ - ...t.qualityLayers.map((layer, index) => ({ - badge: String(index + 1), - title: layer.title, - body: layer.body, - proof: layer.proof, - tone: LAYER_TONES[index % LAYER_TONES.length], - })), - { - label: t.output.label, - title: t.output.title, - body: t.output.body, - proof: { kind: "approved" as const, label: t.output.status }, - tone: OUTPUT_TONE, - }, - ]; - - return ( -
-
-

{t.inputLabel}

- - {/* Paper stack: two sample documents peeking out from under the real card */} -
- {t.sourceSamples.map((sample, index) => ( -
-
- {sample} -
-
- ))} - -
    - {t.inputs.map((input) => ( -
  • -
    - {input.label} -
    -
    - {input.detail} -
    -
  • - ))} -
-
-
- -
-

{t.coreLabel}

- -
    - {rungs.map(({ badge, label, title, body, proof, tone }, index) => { - const next = rungs[index + 1]; - - return ( -
  1. -
    - - {badge ?? } - - - {/* Rail into the next rung; bleeds over the list gap to meet it */} - {next ? ( - - ) : null} -
    - -
    - {label ? ( - - {label} - - ) : null} -

    {title}

    -

    {body}

    - - {proof ? : null} -
    -
  2. - ); - })} -
-
-
- ); -} - -function ProofMark({ proof }: { proof: QualityProof }) { - if (proof.kind === "reviewers") { - return ( -
-
- {reviewerTints.map((color, index) => ( - 0 && "-ml-2", - )} - style={{ backgroundColor: color }} - /> - ))} -
- - {proof.label} - -
- ); - } - - return ( - - {proof.kind === "approved" ? ( - - ) : ( - - )} - {proof.label} - - ); -} diff --git a/apps/web/src/app/[lang]/components/navbar.tsx b/apps/web/src/app/[lang]/components/navbar.tsx index d944151..c094481 100644 --- a/apps/web/src/app/[lang]/components/navbar.tsx +++ b/apps/web/src/app/[lang]/components/navbar.tsx @@ -139,7 +139,7 @@ export function Navbar({ t }: NavbarProps) { ), )} > -
+
{t.signIn} @@ -358,6 +358,12 @@ export function Navbar({ t }: NavbarProps) { ) : null} ))} + + {t.signIn} +
-
-
-
-
-
+ /> ); } diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/i18n/onboarding-offboarding.i18n.de.json b/apps/web/src/app/[lang]/onboarding-offboarding/i18n/onboarding-offboarding.i18n.de.json deleted file mode 100644 index da52c51..0000000 --- a/apps/web/src/app/[lang]/onboarding-offboarding/i18n/onboarding-offboarding.i18n.de.json +++ /dev/null @@ -1,250 +0,0 @@ -{ - "onboardingOffboarding": { - "meta": { - "title": "Onboarding & Offboarding Software | Scibly", - "description": "Onboarding-Kurs einmal erstellen, mit einem Klick jeder neuen Person zuweisen. Wissen von ausscheidenden Mitarbeitenden als Kurs festhalten, statt zu verlieren. Scibly für Onboarding & Offboarding.", - "keywords": [ - "Onboarding Software", - "Offboarding Software", - "Mitarbeiter Onboarding LMS", - "Wissenstransfer Software", - "Wissen sichern beim Austritt" - ] - }, - "hero": { - "headline": "Besserer Wissenstransfer", - "subheadline": "Bewahre das wertvolle Wissen deines Teams, indem du es mit Scibly erfasst, weitergibst und aufbewahrst.", - "ctaLabel": "Demo anfordern" - }, - "featureShowcaseHeader": { - "eyebrow": "Für den gesamten Mitarbeiterzyklus gebaut", - "title": "Eine Plattform, vom ersten bis zum letzten Tag.", - "subtitle": "Ein Ort, um Onboarding aufzubauen, austretendes Wissen festzuhalten und beides prüfungssicher zu dokumentieren." - }, - "comparisonRows": [ - { - "kind": "learner", - "label": "Onboarding", - "legacy": "Checkliste in Tabelle oder PDF", - "scibly": "Geführtes Onboarding mit Fortschritt und Rückfragen, das mit jedem Teammitglied besser wird." - }, - { - "kind": "import", - "label": "Wissenstransfer", - "legacy": "Wissen geht mit dem Mitarbeiter", - "scibly": "Wissen wird kontinuierlich gesichert" - } - ], - "knowledgeSources": { - "eyebrow": "Wissenstransfer mit Scibly", - "title": "Undokumentiertes Expertenwissen wird erfasst und für alle zugänglich und lernbar gemacht.", - "subtitle": "Das wertvollste Wissen steht in keinem Dokument. Es steckt in den Köpfen der Experten und geht mit ihnen. Scibly hält es fest, bevor es verloren geht.", - "capturedLabel": "Erfasst", - "interview": { - "title": "Interviews", - "description": "Dokumentationen halten fest, wie etwas funktioniert. Scibly fragt nach dem Rest: Ausnahmen, Faustregeln, Gründe hinter Entscheidungen.", - "timer": "14:32", - "aiName": "Scibly KI", - "listeningLabel": "Hört zu …", - "question": "Du hast Payment-Retries erwähnt. Was passiert bei einem Timeout?" - }, - "artifacts": { - "title": "Die tägliche Arbeit liefert den Beleg", - "description": "Scibly extrahiert Wissen aus Slack-Nachrichten, Code-Reviews, Tickets und Docs und speichert jede Erkenntnis mit ihrer Quelle.", - "slackChannel": "#it-support", - "slackTime": "09:41", - "slackAuthor": "Mia", - "slackText": "Nie doppelt retryen, das übernimmt das Gateway.", - "codeFile": "payments/client.ts", - "codeReview": "Review", - "codeRemoved": "await retry(book, 3)", - "codeAdded": "await book()", - "codeComment": "Das Gateway retryt schon serverseitig.", - "ticketId": "INFRA-482", - "ticketStatus": "Gelöst", - "ticketTitle": "Doppelte Buchung nach Timeout", - "ticketCause": "Ursache: Client-Retry nach Timeout" - }, - "lesson": { - "title": "Mehr als nur Wissensextraktion", - "description": "Das extrahierte Wissen wird nicht nur zentral gespeichert, sondern kann mit nur einem Knopfdruck automatisch in interaktive Lerneinheiten verwandelt werden.", - "lessonEyebrow": "Lektion 4 von 9", - "lessonTitle": "Payment-Retries richtig behandeln", - "quizQuestion": "Ein Request läuft in einen Timeout. Was jetzt?", - "quizOptionWrong": "Sofort neu buchen", - "quizOptionRight": "Buchungsstatus prüfen, nicht retryen", - "derivedLabel": "Daraus generiert" - }, - "knowledge": { - "eyebrow": "Wissensbasis", - "title": "Payment-Retries", - "fact1": "Retries übernimmt ausschließlich das Gateway.", - "fact2": "Ein Timeout heißt nicht abgebrochen.", - "verifiedLabel": "3 Quellen · verifiziert" - } - }, - "problemNumbers": { - "eyebrow": "Das Problem in Zahlen", - "title": "Verlässt ein Mitarbeiter das Unternehmen, geht sein Wissen mit ihm.", - "problemLabel": "Das Problem", - "problemBody": "Jeder Mitarbeiter, der geht, nimmt undokumentiertes Wissen mit: die Ausnahmen, die Faustregeln, die Gründe hinter Entscheidungen. Was bleibt, sind längere Einarbeitung, wiederholte Fehler und Fragen, die niemand mehr beantworten kann.", - "stats": [ - { - "value": "31 Mrd. $", - "label": "Kosten durch Wissensverlust pro Jahr" - }, - { - "value": "92 %", - "label": "der Unternehmen sichern das Wissen ausscheidender Mitarbeiter nicht systematisch" - }, - { - "value": "3–6 Monate", - "label": "bis neue Mitarbeiter auf dem Produktivitätsniveau ihrer Kollegen arbeiten" - }, - { - "value": "50–200 %", - "label": "eines Jahresgehalts kostet es, eine Stelle neu zu besetzen" - } - ] - }, - "onboardingFlow": { - "eyebrow": "Onboarding mit Scibly", - "title": "Der schnellste Weg zur Produktivität", - "subtitle": "Struktur, Fortschritt, Rückfragen und Kontext an einem Ort. Vom Zugang am ersten Tag bis zum Verständnis dafür, wie Dinge im Unternehmen funktionieren und warum sie so gehandhabt werden.", - "checklist": { - "title": "Strukturierte Onboarding-Liste", - "description": "Jeder Schritt steht fest, mit Ansprechpartner, Frist und allen Informationen, die dazugehören. Niemand muss raten, was als Nächstes kommt.", - "windowTitle": "Onboarding · Vertrieb", - "stepCount": "12 Schritte", - "groups": [ - { - "label": "Vor dem ersten Tag", - "items": [ - { - "label": "Laptop und Zugänge bestellt", - "meta": "IT", - "done": true - }, - { - "label": "Arbeitsplatz eingerichtet", - "meta": "Office", - "done": true - } - ] - }, - { - "label": "Tag 1", - "items": [ - { - "label": "Willkommen im Team", - "meta": "Mia", - "done": true - }, - { - "label": "VPN und SSO einrichten", - "meta": "IT · bis 17:00", - "done": false - } - ] - }, - { - "label": "Woche 1", - "items": [ - { - "label": "Kurs: Sicherheitsrichtlinie", - "meta": "8 Lektionen", - "done": false - } - ] - } - ] - }, - "progress": { - "title": "Fortschritt wird getrackt", - "description": "Team Leads und Admins haben jederzeit den Überblick über den Stand des Onboardings und erkennen direkt, wenn jemand Unterstützung benötigt.", - "windowTitle": "Team-Übersicht · Vertrieb", - "assignedLabel": "3 im Onboarding", - "people": [ - { - "name": "Lena M.", - "initials": "LM", - "status": "12 von 12 Schritten", - "progress": 100 - }, - { - "name": "Jonas B.", - "initials": "JB", - "status": "5 von 12 Schritten", - "progress": 42 - }, - { - "name": "Aylin K.", - "initials": "AK", - "status": "0 von 12 Schritten", - "progress": 0 - } - ] - }, - "questions": { - "title": "Rückfragen und Feedback", - "description": "Neue Mitarbeiter können direkt im Onboarding Flow Fragen zu einzelnen Schritten stellen oder festhalten, was noch unklar ist. So verbessert sich das Onboarding mit jedem neuen Teammitglied.", - "windowTitle": "Schritt 4 · VPN einrichten", - "learnerName": "Jonas", - "learnerInitials": "JB", - "question": "Wo finde ich den VPN-Zugang für macOS?", - "aiName": "Scibly KI", - "answer": "Im Self-Service-Portal unter Geräte. Die IT gibt den Antrag automatisch frei.", - "feedbackLabel": "Feedback", - "feedbackText": "Der Schritt sagt nicht, wo der Zugang liegt.", - "improvedLabel": "Schritt ergänzt" - }, - "course": { - "title": "Kurse statt Schritt-für-Schritt-Anleitung", - "description": "Scibly erklärt nicht nur, was zu tun ist, sondern warum. Neue Mitarbeiter verstehen die Werkzeuge und Entscheidungen des Unternehmens, statt eine Anleitung abzuarbeiten.", - "lessonEyebrow": "Lektion 2 von 8", - "lessonTitle": "Warum Angebote zuerst ins CRM gehen", - "whyLabel": "Warum", - "whyText": "Ohne CRM-Eintrag fehlt der Forecast, und das Team sieht nicht, welche Deals wirklich laufen.", - "quizQuestion": "Ein Kunde sagt am Telefon zu. Was zuerst?", - "quizOptionWrong": "Vertrag direkt rausschicken", - "quizOptionRight": "Deal im CRM anlegen, dann Vertrag" - } - }, - "cta": { - "eyebrow": "Bereit, Wissenstransfer neu zu denken?", - "title": "Bereit, Wissen besser zu teilen und neue Mitarbeiter schneller einzuarbeiten?", - "button": "Demo anfordern", - "hint": "Unverbindlich · Wir melden uns persönlich" - }, - "faq": { - "title": "Häufige Fragen", - "questions": [ - { - "id": "what-is-scibly", - "q": "Was ist Scibly?", - "a": "Scibly macht Wissen aus den Köpfen eurer Experten für das ganze Unternehmen zugänglich. Aus bestehendem Wissen entstehen automatisch aktuelle Dokumentationen und Kurse sowie rollenbasierte Onboarding-Programme. So wird Wissen besser verteilt und neue Mitarbeitende schneller eingearbeitet." - }, - { - "id": "how-does-scibly-work", - "q": "Wie funktioniert Scibly?", - "a": "Scibly führt geführte Interviews mit euren Fachleuten und erschließt Wissen aus Quellen wie Slack, Code Reviews, Tickets und Dokumenten. Daraus entsteht eine Wissensbasis mit Quellenangaben, aus der sich Kurse und rollenbasierte Onboardings erstellen lassen. Zusätzlich können neue Teammitglieder direkt im Onboarding Fragen stellen und Feedback geben, wodurch sich das Onboarding automatisiert kontinuierlich verbessert." - }, - { - "id": "data-security", - "q": "Wie sicher sind meine Daten?", - "a": "Scibly ist DSGVO-konform und nutzt ausschließlich in der EU gehostete Modelle. Deine Daten werden weder für das Training von KI-Modellen verwendet noch an Dritte weitergegeben und sind sowohl bei der Übertragung als auch bei der Speicherung verschlüsselt. Für maximale Kontrolle kannst du Scibly außerdem selbst hosten, denn Scibly ist Open Source." - }, - { - "id": "getting-started", - "q": "Wie schnell sind wir startklar?", - "a": "Nachdem Scibly mit bestehenden Tools wie Slack, GitHub oder Notion verbunden wurde, beginnt die Wissensextraktion automatisch. Aus dem gewonnenen Wissen lassen sich zusätzlich mit unserem KI-Agenten innerhalb weniger Minuten interaktive Kurse und Onboardings erstellen." - }, - { - "id": "open-source", - "q": "Ist Scibly Open Source?", - "a": "Scibly ist Open Core: Der Großteil des Codes steht unter AGPLv3 auf GitHub, nur einzelne Enterprise-Funktionen sind davon ausgenommen. Du kannst das Repository klonen, den Stack auf deiner eigenen Infrastruktur starten und Scibly selbst hosten." - } - ] - } - } -} diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/i18n/onboarding-offboarding.i18n.en.json b/apps/web/src/app/[lang]/onboarding-offboarding/i18n/onboarding-offboarding.i18n.en.json deleted file mode 100644 index aa38f67..0000000 --- a/apps/web/src/app/[lang]/onboarding-offboarding/i18n/onboarding-offboarding.i18n.en.json +++ /dev/null @@ -1,250 +0,0 @@ -{ - "onboardingOffboarding": { - "meta": { - "title": "Onboarding & Offboarding Software | Scibly", - "description": "Build onboarding once, assign it to every new hire in one click. Capture a departing expert's knowledge as a course, not a lost handover. Scibly for onboarding & offboarding.", - "keywords": [ - "onboarding software", - "offboarding software", - "employee onboarding LMS", - "knowledge transfer software", - "exit knowledge capture" - ] - }, - "hero": { - "headline": "Better Knowledge Transfer", - "subheadline": "Preserve your team’s most valuable knowledge by capturing, transferring, and retaining it with Scibly.", - "ctaLabel": "Request demo" - }, - "featureShowcaseHeader": { - "eyebrow": "Built for the full employee lifecycle", - "title": "The same platform, from first day to last.", - "subtitle": "One place to build onboarding, capture outgoing knowledge, and keep both audit-ready." - }, - "comparisonRows": [ - { - "kind": "learner", - "label": "Onboarding", - "legacy": "Checklist in a spreadsheet or PDF", - "scibly": "Guided onboarding with progress and questions that improves with every team member." - }, - { - "kind": "import", - "label": "Knowledge Transfer", - "legacy": "Knowledge leaves with the employee", - "scibly": "Knowledge is captured continuously" - } - ], - "knowledgeSources": { - "eyebrow": "Knowledge transfer with Scibly", - "title": "Undocumented expertise gets captured and made accessible and learnable for everyone.", - "subtitle": "The most valuable knowledge is written down nowhere. It sits in your experts' heads and leaves with them. Scibly captures it before it is lost.", - "capturedLabel": "Captured", - "interview": { - "title": "Interviews", - "description": "Documentation records how something works. Scibly asks about the rest: the exceptions, the rules of thumb, the reasons behind decisions.", - "timer": "14:32", - "aiName": "Scibly AI", - "listeningLabel": "Listening…", - "question": "You mentioned payment retries. What happens on a timeout?" - }, - "artifacts": { - "title": "Everyday work supplies the evidence", - "description": "Scibly extracts knowledge from Slack messages, code reviews, tickets, and docs, and stores every insight with its source.", - "slackChannel": "#it-support", - "slackTime": "09:41", - "slackAuthor": "Mia", - "slackText": "Never retry twice, the gateway already does.", - "codeFile": "payments/client.ts", - "codeReview": "Review", - "codeRemoved": "await retry(book, 3)", - "codeAdded": "await book()", - "codeComment": "The gateway already retries server-side.", - "ticketId": "INFRA-482", - "ticketStatus": "Resolved", - "ticketTitle": "Duplicate booking after timeout", - "ticketCause": "Cause: client retry after timeout" - }, - "lesson": { - "title": "More than knowledge extraction", - "description": "The extracted knowledge is not just stored centrally, it can be turned into interactive learning units automatically, at the push of a button.", - "lessonEyebrow": "Lesson 4 of 9", - "lessonTitle": "Handling payment retries", - "quizQuestion": "A request hits a timeout. Now what?", - "quizOptionWrong": "Book again right away", - "quizOptionRight": "Check the booking status, don't retry", - "derivedLabel": "Generated from it" - }, - "knowledge": { - "eyebrow": "Knowledge base", - "title": "Payment retries", - "fact1": "Retries are handled by the gateway only.", - "fact2": "A timeout doesn't mean cancelled.", - "verifiedLabel": "3 sources · verified" - } - }, - "problemNumbers": { - "eyebrow": "The problem in numbers", - "title": "When an employee leaves the company, their knowledge leaves with them.", - "problemLabel": "The problem", - "problemBody": "Every employee who leaves takes undocumented knowledge with them: the exceptions, the rules of thumb, the reasons behind decisions. What stays behind is longer ramp-up, repeated mistakes, and questions nobody can answer any more.", - "stats": [ - { - "value": "$31B", - "label": "annual cost of knowledge loss" - }, - { - "value": "92%", - "label": "of organizations do not consistently capture knowledge from departing employees" - }, - { - "value": "3–6 months", - "label": "until new hires reach the productivity of their peers" - }, - { - "value": "50–200%", - "label": "of annual salary is the cost of replacing a single employee" - } - ] - }, - "onboardingFlow": { - "eyebrow": "Onboarding with Scibly", - "title": "The fastest path to productivity", - "subtitle": "Structure, progress, questions and context in one place. From day-one access to understanding how things work in the company and why they are done that way.", - "checklist": { - "title": "A structured onboarding list", - "description": "Every step is defined, with an owner, a deadline and all the information that belongs to it. Nobody has to guess what comes next.", - "windowTitle": "Onboarding · Sales", - "stepCount": "12 steps", - "groups": [ - { - "label": "Before day one", - "items": [ - { - "label": "Laptop and accounts ordered", - "meta": "IT", - "done": true - }, - { - "label": "Desk set up", - "meta": "Office", - "done": true - } - ] - }, - { - "label": "Day 1", - "items": [ - { - "label": "Welcome to the team", - "meta": "Mia", - "done": true - }, - { - "label": "Set up VPN and SSO", - "meta": "IT · by 5pm", - "done": false - } - ] - }, - { - "label": "Week 1", - "items": [ - { - "label": "Course: security policy", - "meta": "8 lessons", - "done": false - } - ] - } - ] - }, - "progress": { - "title": "Progress is tracked", - "description": "Team leads and admins have a complete view of onboarding progress at any time, and see immediately when someone needs support.", - "windowTitle": "Team overview · Sales", - "assignedLabel": "3 onboarding", - "people": [ - { - "name": "Lena M.", - "initials": "LM", - "status": "12 of 12 steps", - "progress": 100 - }, - { - "name": "Jonas B.", - "initials": "JB", - "status": "5 of 12 steps", - "progress": 42 - }, - { - "name": "Aylin K.", - "initials": "AK", - "status": "0 of 12 steps", - "progress": 0 - } - ] - }, - "questions": { - "title": "Questions and feedback", - "description": "New hires can ask questions about individual steps right inside the onboarding flow, or note down what is still unclear. That way onboarding improves with every new team member.", - "windowTitle": "Step 4 · Set up VPN", - "learnerName": "Jonas", - "learnerInitials": "JB", - "question": "Where do I find the macOS VPN profile?", - "aiName": "Scibly AI", - "answer": "In the self-service portal under Devices. IT approves the request automatically.", - "feedbackLabel": "Feedback", - "feedbackText": "The step doesn't say where the profile lives.", - "improvedLabel": "Step updated" - }, - "course": { - "title": "Courses, not a step-by-step manual", - "description": "Scibly explains not just what to do but why. New hires understand the company's tools and decisions instead of working through a checklist blind.", - "lessonEyebrow": "Lesson 2 of 8", - "lessonTitle": "Why deals go into the CRM first", - "whyLabel": "Why", - "whyText": "Without a CRM entry the forecast is wrong, and the team cannot see which deals are actually live.", - "quizQuestion": "A customer says yes on the phone. What first?", - "quizOptionWrong": "Send the contract right away", - "quizOptionRight": "Create the deal in the CRM, then the contract" - } - }, - "cta": { - "eyebrow": "Ready to rethink knowledge transfer?", - "title": "Ready to share knowledge better and onboard new hires faster?", - "button": "Request demo", - "hint": "No commitment · We'll reach out personally" - }, - "faq": { - "title": "Frequently asked questions", - "questions": [ - { - "id": "what-is-scibly", - "q": "What is Scibly?", - "a": "Scibly makes the knowledge inside your experts' heads accessible to the entire company. Existing knowledge automatically becomes up-to-date documentation and courses as well as role-based onboarding programs. Knowledge spreads further and new hires get up to speed faster." - }, - { - "id": "how-does-scibly-work", - "q": "How does Scibly work?", - "a": "Scibly runs guided interviews with your experts and taps knowledge from sources like Slack, code reviews, tickets and documents. That builds a knowledge base with cited sources, from which courses and role-based onboardings are created. New team members can also ask questions and give feedback right inside the onboarding, so it keeps improving automatically." - }, - { - "id": "data-security", - "q": "How secure is my data?", - "a": "Scibly is GDPR compliant and uses only models hosted in the EU. Your data is never used to train AI models nor passed on to third parties, and it is encrypted both in transit and at rest. For maximum control you can also self-host Scibly, because Scibly is open source." - }, - { - "id": "getting-started", - "q": "How quickly can we get started?", - "a": "Once Scibly is connected to your existing tools like Slack, GitHub or Notion, knowledge extraction starts automatically. From the knowledge gathered, our AI agent additionally creates interactive courses and onboardings within minutes." - }, - { - "id": "open-source", - "q": "Is Scibly open source?", - "a": "Scibly is open core: most of the code is on GitHub under AGPLv3, with only a few enterprise features excluded. You can clone the repository, boot the stack on your own infrastructure and self-host Scibly." - } - ] - } - } -} diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/i18n/onboarding-offboarding.types.ts b/apps/web/src/app/[lang]/onboarding-offboarding/i18n/onboarding-offboarding.types.ts deleted file mode 100644 index 19fdb0e..0000000 --- a/apps/web/src/app/[lang]/onboarding-offboarding/i18n/onboarding-offboarding.types.ts +++ /dev/null @@ -1,141 +0,0 @@ -import type { ComparisonDictionary } from "@/app/[lang]/components/home-page-section/comparison/i18n/comparison.types"; -import type { CtaDictionary } from "@/app/[lang]/components/home-page-section/cta/i18n/cta.types"; -import type { FaqItem } from "@/components/faq/faq-list"; - -export type OnboardingOffboardingPage = { - meta: { title: string; description: string; keywords: string[] }; - hero: { - headline: string; - subheadline: string; - ctaLabel: string; - }; - featureShowcaseHeader: { - eyebrow: string; - title: string; - subtitle: string; - }; - comparisonRows: ComparisonDictionary["table"]["rows"]; - knowledgeSources: { - eyebrow: string; - title: string; - subtitle: string; - capturedLabel: string; - interview: { - title: string; - description: string; - timer: string; - aiName: string; - listeningLabel: string; - question: string; - }; - artifacts: { - title: string; - description: string; - slackChannel: string; - slackTime: string; - slackAuthor: string; - slackText: string; - codeFile: string; - codeReview: string; - codeRemoved: string; - codeAdded: string; - codeComment: string; - ticketId: string; - ticketStatus: string; - ticketTitle: string; - ticketCause: string; - }; - knowledge: { - eyebrow: string; - title: string; - fact1: string; - fact2: string; - verifiedLabel: string; - }; - lesson: { - title: string; - derivedLabel: string; - description: string; - lessonEyebrow: string; - lessonTitle: string; - quizQuestion: string; - quizOptionWrong: string; - quizOptionRight: string; - }; - }; - problemNumbers: { - eyebrow: string; - title: string; - problemLabel: string; - problemBody: string; - stats: { value: string; label: string }[]; - }; - onboardingFlow: { - eyebrow: string; - title: string; - subtitle: string; - checklist: { - title: string; - description: string; - windowTitle: string; - stepCount: string; - groups: { - label: string; - items: { label: string; meta: string; done: boolean }[]; - }[]; - }; - progress: { - title: string; - description: string; - windowTitle: string; - assignedLabel: string; - people: { - name: string; - initials: string; - status: string; - progress: number; - }[]; - }; - questions: { - title: string; - description: string; - windowTitle: string; - learnerName: string; - learnerInitials: string; - question: string; - aiName: string; - answer: string; - feedbackLabel: string; - feedbackText: string; - improvedLabel: string; - }; - course: { - title: string; - description: string; - lessonEyebrow: string; - lessonTitle: string; - whyLabel: string; - whyText: string; - quizQuestion: string; - quizOptionWrong: string; - quizOptionRight: string; - }; - }; - cta: CtaDictionary; - faq: { title: string; questions: FaqItem[] }; -}; - -export type KnowledgeSourcesCopy = - OnboardingOffboardingPage["knowledgeSources"]; -export type InterviewCopy = KnowledgeSourcesCopy["interview"]; -export type ArtifactsCopy = KnowledgeSourcesCopy["artifacts"]; -export type KnowledgeCopy = KnowledgeSourcesCopy["knowledge"]; -export type LessonCopy = KnowledgeSourcesCopy["lesson"]; - -export type ProblemNumbersCopy = OnboardingOffboardingPage["problemNumbers"]; - -export type OnboardingFlowCopy = OnboardingOffboardingPage["onboardingFlow"]; -export type ChecklistCopy = OnboardingFlowCopy["checklist"]; -export type ProgressCopy = OnboardingFlowCopy["progress"]; -export type QuestionsCopy = OnboardingFlowCopy["questions"]; -export type CourseCopy = OnboardingFlowCopy["course"]; diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/onboarding-offboarding-view.tsx b/apps/web/src/app/[lang]/onboarding-offboarding/onboarding-offboarding-view.tsx deleted file mode 100644 index ccd9861..0000000 --- a/apps/web/src/app/[lang]/onboarding-offboarding/onboarding-offboarding-view.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import type { Locale } from "@scibly/i18n/constants"; - -import dynamic from "next/dynamic"; - -import { FaqJsonLd } from "@/components/faq/faq-json-ld"; -import { getFullDictionary } from "@/i18n/dictionaries"; - -import { ComparisonSection } from "../components/home-page-section/comparison/comparison"; -import { CtaSection } from "../components/home-page-section/cta/cta"; -import { HeroComplianceStrip } from "../components/home-page-section/hero/hero-compliance-strip"; -import { UseCaseFaq } from "../use-cases/components/use-case-faq"; -import { UseCaseHero } from "../use-cases/components/use-case-hero"; -import { KnowledgeSourcesSection } from "./components/knowledge-sources/knowledge-sources-section"; -import { OnboardingFlowSection } from "./components/onboarding-flow/onboarding-flow-section"; -import { ProblemNumbersSection } from "./components/problem-numbers/problem-numbers-section"; - -const FeatureShowcase = dynamic(() => - import("../components/home-page-section/feature-showcase").then( - (m) => m.FeatureShowcase, - ), -); -const OpenSourceSection = dynamic(() => - import("../components/home-page-section/open-source/open-source").then( - (m) => m.OpenSourceSection, - ), -); -const ComplianceSection = dynamic(() => - import("../components/home-page-section/compliance/compliance").then( - (m) => m.ComplianceSection, - ), -); - -export async function OnboardingOffboardingView({ lang }: { lang: Locale }) { - const dict = await getFullDictionary(lang); - const content = dict.onboardingOffboarding; - - return ( -
- - - - - - - - - - - - -
- ); -} diff --git a/apps/web/src/app/[lang]/onboarding-offboarding/page.tsx b/apps/web/src/app/[lang]/onboarding-offboarding/page.tsx deleted file mode 100644 index cdb9bec..0000000 --- a/apps/web/src/app/[lang]/onboarding-offboarding/page.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import type { Locale } from "@scibly/i18n/constants"; -import type { Metadata } from "next"; - -import { constructMetadata } from "@scibly/lib"; - -import { getFullDictionary } from "@/i18n/dictionaries"; -import { buildLocaleAlternates } from "@/lib/metadata"; - -import { OnboardingOffboardingView } from "./onboarding-offboarding-view"; - -export async function generateMetadata(props: { - params: Promise<{ lang: Locale }>; -}): Promise { - const { lang } = await props.params; - const dict = await getFullDictionary(lang); - const content = dict.onboardingOffboarding; - const { canonicalUrl, languages } = buildLocaleAlternates( - "/onboarding-offboarding", - lang, - ); - - return { - ...constructMetadata({ - fullTitle: content.meta.title, - description: content.meta.description, - url: canonicalUrl, - keywords: content.meta.keywords, - locale: lang, - }), - alternates: { canonical: canonicalUrl, languages }, - }; -} - -export default async function OnboardingOffboardingPage(props: { - params: Promise<{ lang: Locale }>; -}) { - const { lang } = await props.params; - return ; -} diff --git a/apps/web/src/app/[lang]/page.tsx b/apps/web/src/app/[lang]/page.tsx index 769fc80..aa5fa01 100644 --- a/apps/web/src/app/[lang]/page.tsx +++ b/apps/web/src/app/[lang]/page.tsx @@ -5,6 +5,7 @@ import { routes } from "@scibly/routes"; import { type Metadata } from "next"; import dynamic from "next/dynamic"; +import { FaqJsonLd } from "@/components/faq/faq-json-ld"; import { getFullDictionary } from "@/i18n/dictionaries"; import { buildLocaleAlternates } from "@/lib/metadata"; @@ -14,7 +15,9 @@ import { FounderSection } from "./components/home-page-section/founder/founder"; import { Hero } from "./components/home-page-section/hero/hero"; import { HeroComplianceStrip } from "./components/home-page-section/hero/hero-compliance-strip"; import { HeroVideo } from "./components/home-page-section/hero/hero-video"; -import { QualityProofSection } from "./components/home-page-section/quality-proof/quality-proof"; +import { KnowledgeSourcesSection } from "./components/home-page-section/knowledge-sources/knowledge-sources-section"; +import { OnboardingFlowSection } from "./components/home-page-section/onboarding-flow/onboarding-flow-section"; +import { ProblemNumbersSection } from "./components/home-page-section/problem-numbers/problem-numbers-section"; const FeatureShowcase = dynamic(() => import("./components/home-page-section/feature-showcase").then( @@ -83,12 +86,15 @@ export default async function Home(props: { type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(organizationJsonLd) }} /> + - + + + diff --git a/apps/web/src/app/[lang]/use-cases/components/use-case-faq.tsx b/apps/web/src/app/[lang]/use-cases/components/use-case-faq.tsx index ba7a28f..d6f7189 100644 --- a/apps/web/src/app/[lang]/use-cases/components/use-case-faq.tsx +++ b/apps/web/src/app/[lang]/use-cases/components/use-case-faq.tsx @@ -1,7 +1,7 @@ "use client"; import type { Locale } from "@scibly/i18n/constants"; -import type { FaqContext, FaqItem } from "@/components/faq/faq-list"; +import type { FaqItem } from "@/components/faq/faq-list"; import { MarketingSection, @@ -14,7 +14,6 @@ interface UseCaseFaqProps { questions: FaqItem[]; useCaseKey: string; locale: Locale; - context?: FaqContext; } export function UseCaseFaq({ @@ -22,7 +21,6 @@ export function UseCaseFaq({ questions, useCaseKey, locale, - context = "use-case", }: UseCaseFaqProps) { return ( diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx index a0fd754..a6550b9 100644 --- a/apps/web/src/app/layout.tsx +++ b/apps/web/src/app/layout.tsx @@ -37,6 +37,8 @@ export default async function RootLayout( return ( before hydration. */ + suppressHydrationWarning > diff --git a/apps/web/src/app/sitemap.ts b/apps/web/src/app/sitemap.ts index 4e6f163..0d63035 100644 --- a/apps/web/src/app/sitemap.ts +++ b/apps/web/src/app/sitemap.ts @@ -187,24 +187,6 @@ export default async function sitemap(): Promise { }); }); - // Unlinked from the rest of the site, so the sitemap is a crawler's only way in. - locales.forEach((locale) => { - sitemapEntries.push({ - url: withLocale(routes.web.base.home + "onboarding-offboarding", locale), - alternates: { - languages: Object.fromEntries( - locales.map((l) => [ - l, - withLocale(routes.web.base.home + "onboarding-offboarding", l), - ]), - ), - }, - lastModified: new Date(), - changeFrequency: "monthly", - priority: 0.75, - }); - }); - locales.forEach((locale) => { sitemapEntries.push({ url: withLocale(routes.web.legal.impressum, locale), diff --git a/apps/web/src/components/faq/faq-list.tsx b/apps/web/src/components/faq/faq-list.tsx index e9177f4..57ff853 100644 --- a/apps/web/src/components/faq/faq-list.tsx +++ b/apps/web/src/components/faq/faq-list.tsx @@ -13,7 +13,6 @@ import { cn } from "@scibly/ui/utils"; import { MessageCircleQuestion, Plus } from "lucide-react"; import { useState } from "react"; -import { CHAPTER_ICONS } from "@/app/[lang]/components/marketing-chapter-icons"; import { lipShadow, type PillarId, @@ -29,7 +28,7 @@ export type FaqItem = { a: string; }; -export type FaqContext = "homepage" | "use-case" | "landing-page"; +export type FaqContext = "homepage" | "use-case"; const CHAPTER_CYCLE: PillarId[] = [ "import", @@ -64,8 +63,6 @@ type FaqListProps = { questions: FaqItem[]; locale: Locale; context: FaqContext; - - chapters?: Map; useCaseKey?: string; className?: string; }; @@ -74,7 +71,6 @@ export function FaqList({ questions, locale, context, - chapters, useCaseKey, className, }: FaqListProps) { @@ -96,10 +92,8 @@ export function FaqList({ }} > {questions.map((item, index) => { - const chapter = chapters?.get(item.id); const { softColor, lipColor, accentColor } = - PILLARS[chapter ?? CHAPTER_CYCLE[index % CHAPTER_CYCLE.length]]; - const Icon = chapter ? CHAPTER_ICONS[chapter] : MessageCircleQuestion; + PILLARS[CHAPTER_CYCLE[index % CHAPTER_CYCLE.length]]; const isOpen = openId === item.id; return ( @@ -175,7 +169,7 @@ export function FaqList({ }} aria-hidden > - + {item.q} diff --git a/apps/web/src/i18n/types.ts b/apps/web/src/i18n/types.ts index 77c93bc..dc6f0e4 100644 --- a/apps/web/src/i18n/types.ts +++ b/apps/web/src/i18n/types.ts @@ -6,13 +6,14 @@ import { type FaqDictionary } from "@/app/[lang]/components/home-page-section/fa import { type FeatureShowcaseDictionary } from "@/app/[lang]/components/home-page-section/feature-showcase/i18n/feature-showcase.types"; import { type FounderDictionary } from "@/app/[lang]/components/home-page-section/founder/i18n/founder.types"; import { type HeroDictionary } from "@/app/[lang]/components/home-page-section/hero/i18n/hero.types"; +import { type KnowledgeSourcesDictionary } from "@/app/[lang]/components/home-page-section/knowledge-sources/i18n/knowledge-sources.types"; +import { type OnboardingFlowDictionary } from "@/app/[lang]/components/home-page-section/onboarding-flow/i18n/onboarding-flow.types"; import { type OpenSourceDictionary } from "@/app/[lang]/components/home-page-section/open-source/i18n/open-source.types"; -import { type QualityProofDictionary } from "@/app/[lang]/components/home-page-section/quality-proof/i18n/quality-proof.types"; +import { type ProblemNumbersDictionary } from "@/app/[lang]/components/home-page-section/problem-numbers/i18n/problem-numbers.types"; import { type AppRoutesPage } from "@/app/[lang]/i18n/app-routes.types"; import { type BlogPage } from "@/app/[lang]/i18n/blog.types"; import { type HomePage } from "@/app/[lang]/i18n/home.types"; import { type LegalPage } from "@/app/[lang]/i18n/legal.types"; -import { type OnboardingOffboardingPage } from "@/app/[lang]/onboarding-offboarding/i18n/onboarding-offboarding.types"; export type Dictionary = { page: { @@ -23,14 +24,15 @@ export type Dictionary = { cta: CtaDictionary; hero: HeroDictionary; faq: FaqDictionary; - qualityProof: QualityProofDictionary; comparison: ComparisonDictionary; featureShowcase: FeatureShowcaseDictionary; compliance: ComplianceDictionary; demoTour: DemoTourDictionary; founder: FounderDictionary; openSource: OpenSourceDictionary; - onboardingOffboarding: OnboardingOffboardingPage; + knowledgeSources: KnowledgeSourcesDictionary; + problemNumbers: ProblemNumbersDictionary; + onboardingFlow: OnboardingFlowDictionary; }; }; diff --git a/apps/web/src/styles/marketing-base.css b/apps/web/src/styles/marketing-base.css index 1df6a44..7f29657 100644 --- a/apps/web/src/styles/marketing-base.css +++ b/apps/web/src/styles/marketing-base.css @@ -5,13 +5,23 @@ */ html { - scroll-behavior: smooth; /* Anchor targets clear the floating navbar instead of sliding under it. */ scroll-padding-top: 100px; } +/* + * Smooth scrolling only for in-page anchor navigation. Applying it to + * unconditionally makes WebKit animate scroll *restoration* on reload, so the + * viewport glides across tiles that have not been rasterised yet and the page + * looks cut off for a second on phones. `:focus-within` is true after an + * anchor click (the link has focus) and false during load/restore. + */ +html:focus-within { + scroll-behavior: smooth; +} + @media (prefers-reduced-motion: reduce) { - html { + html:focus-within { scroll-behavior: auto; } }