Repository navigation
Add Ruby + PostgreSQL quickstart guide #773
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
ba4b880
0718d0a
e68ccf8
5e56bab
0daecdf
b17ec15
30405ab
21d7bc3
41e6346
fe9ecfa
cf1c640
d7dacbf
6239518
e11a3f9
a2a99c4
6475910
fc0fd26
78b6387
35cf355
17d7f5c
c7b0de1
fd87e70
31087d4
d89dc16
9722058
620505c
ec6954e
98f8671
6468dac
f9472b0
12bd048
eaba4c4
788373e
3d3a3da
4dc91f5
cc6da4e
aa9a559
4d74cee
2f2c8a1
2ccc076
d1be22c
f22b0c0
ca849cb
a64e423
f27707b
3f1b065
36df33b
d20282a
d8aae26
b4f8e1a
cffa27d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,20 +2,65 @@ import React, {useState} from "react"; | |
| import quickstarts from "./QuickStartList"; | ||
| import Link from "@docusaurus/Link"; | ||
| import {FaGolang} from "react-icons/fa6"; | ||
| import {FaJava, FaLaptopCode, FaDocker, FaPython, FaCheck, FaArrowRight, FaArrowLeft} from "react-icons/fa"; | ||
| import { | ||
| FaJava, | ||
| FaLaptopCode, | ||
| FaDocker, | ||
| FaPython, | ||
| FaCheck, | ||
| FaArrowRight, | ||
| FaArrowLeft, | ||
| FaGem, | ||
| } from "react-icons/fa"; | ||
| import {TbBrandCSharp} from "react-icons/tb"; | ||
| import {IoLogoJavascript} from "react-icons/io5"; | ||
| import {useColorMode} from "@docusaurus/theme-common"; | ||
| import {useLocation} from "@docusaurus/router"; | ||
|
|
||
| function isVersionAtLeast(version, minimumVersion) { | ||
| const versionParts = version.split(".").map(Number); | ||
| const minimumParts = minimumVersion.split(".").map(Number); | ||
|
|
||
| if ( | ||
| versionParts.length !== 3 || | ||
| minimumParts.length !== 3 || | ||
| versionParts.some(Number.isNaN) || | ||
| minimumParts.some(Number.isNaN) | ||
| ) { | ||
| return false; | ||
| } | ||
|
|
||
| for (let index = 0; index < 3; index++) { | ||
| if (versionParts[index] > minimumParts[index]) { | ||
| return true; | ||
| } | ||
|
|
||
| if (versionParts[index] < minimumParts[index]) { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| export default function QuickstartFilter({defaultLanguage = null}) { | ||
| const {colorMode} = useColorMode(); | ||
| const {pathname} = useLocation(); | ||
| const isDark = colorMode === "dark"; | ||
|
|
||
| const versionMatch = pathname.match(/\/docs\/(\d+\.\d+\.\d+)\//); | ||
| const supportsRubyQuickstarts = | ||
| !versionMatch || isVersionAtLeast(versionMatch[1], "4.0.0"); | ||
|
|
||
| const [currentStep, setCurrentStep] = useState(defaultLanguage ? 2 : 1); | ||
| const [language, setLanguage] = useState(defaultLanguage); | ||
| const [server, setServer] = useState(null); | ||
|
|
||
| const filteredQuickstarts = quickstarts.filter((app) => { | ||
| if (app.language === "Ruby" && !supportsRubyQuickstarts) { | ||
| return false; | ||
| } | ||
|
|
||
| return ( | ||
| (!language || app.language === language) && | ||
| (!server || app.server === server) | ||
|
|
@@ -30,14 +75,39 @@ export default function QuickstartFilter({defaultLanguage = null}) { | |
| {name: "C#", icon: <TbBrandCSharp size={24} />, color: "#512BD4"}, | ||
| ]; | ||
|
|
||
| if (supportsRubyQuickstarts) { | ||
| languages.push({name: "Ruby", icon: <FaGem size={24} />, color: "#CC342D"}); | ||
| } | ||
|
|
||
| const servers = [ | ||
| {name: "Local", icon: <FaLaptopCode size={24} />, description: "Run directly on your machine"}, | ||
| {name: "Docker", icon: <FaDocker size={24} />, description: "Run in a Docker container"}, | ||
| { | ||
| name: "Local", | ||
| icon: <FaLaptopCode size={24} />, | ||
| description: "Run directly on your machine", | ||
| }, | ||
| { | ||
| name: "Docker", | ||
| icon: <FaDocker size={24} />, | ||
| description: "Run in a Docker container", | ||
| }, | ||
| ]; | ||
|
|
||
| const steps = [ | ||
| {id: 1, label: "Language", icon: languages.find(l => l.name === language)?.icon || null}, | ||
| {id: 2, label: "Environment", icon: server === "Docker" ? <FaDocker size={16} /> : server === "Local" ? <FaLaptopCode size={16} /> : null}, | ||
| { | ||
| id: 1, | ||
| label: "Language", | ||
| icon: languages.find((l) => l.name === language)?.icon || null, | ||
| }, | ||
| { | ||
| id: 2, | ||
| label: "Environment", | ||
| icon: | ||
| server === "Docker" ? ( | ||
| <FaDocker size={16} /> | ||
| ) : server === "Local" ? ( | ||
| <FaLaptopCode size={16} /> | ||
| ) : null, | ||
| }, | ||
| {id: 3, label: "Quickstart", icon: null}, | ||
| ]; | ||
|
|
||
|
|
@@ -67,7 +137,7 @@ export default function QuickstartFilter({defaultLanguage = null}) { | |
| }; | ||
|
|
||
| return ( | ||
| <div className={`quickstart-wizard ${isDark ? 'dark' : 'light'}`}> | ||
| <div className={`quickstart-wizard ${isDark ? "dark" : "light"}`}> | ||
| <style>{` | ||
| .quickstart-wizard { | ||
| margin-top: 1.5rem; | ||
|
|
@@ -366,20 +436,32 @@ export default function QuickstartFilter({defaultLanguage = null}) { | |
| <div className="wizard-stepper"> | ||
| {steps.map((step, idx) => ( | ||
| <React.Fragment key={step.id}> | ||
| <div className={`wizard-step ${currentStep === step.id ? 'active' : ''} ${currentStep > step.id ? 'completed' : ''}`}> | ||
| <div | ||
| className={`wizard-step ${ | ||
| currentStep === step.id ? "active" : "" | ||
| } ${currentStep > step.id ? "completed" : ""}`} | ||
| > | ||
| <div className="wizard-step-icon"> | ||
| {currentStep > step.id ? <FaCheck size={12} /> : step.id} | ||
| </div> | ||
| <span>{step.label}</span> | ||
| {currentStep > step.id && step.id === 1 && language && ( | ||
| <span style={{color: '#ff914d', marginLeft: '0.25rem'}}>({language})</span> | ||
| <span style={{color: "#ff914d", marginLeft: "0.25rem"}}> | ||
| ({language}) | ||
| </span> | ||
| )} | ||
| {currentStep > step.id && step.id === 2 && server && ( | ||
| <span style={{color: '#ff914d', marginLeft: '0.25rem'}}>({server})</span> | ||
| <span style={{color: "#ff914d", marginLeft: "0.25rem"}}> | ||
| ({server}) | ||
| </span> | ||
| )} | ||
| </div> | ||
| {idx < steps.length - 1 && ( | ||
| <div className={`wizard-step-connector ${currentStep > step.id ? 'completed' : ''}`} /> | ||
| <div | ||
| className={`wizard-step-connector ${ | ||
| currentStep > step.id ? "completed" : "" | ||
| }`} | ||
| /> | ||
| )} | ||
| </React.Fragment> | ||
| ))} | ||
|
|
@@ -391,18 +473,30 @@ export default function QuickstartFilter({defaultLanguage = null}) { | |
| {currentStep === 1 && ( | ||
| <> | ||
| <h3 className="wizard-title">Select your language</h3> | ||
| <p className="wizard-subtitle">Choose the programming language for your application</p> | ||
| <p className="wizard-subtitle"> | ||
| Choose the programming language for your application | ||
| </p> | ||
| <div className="wizard-options"> | ||
| {languages.map((lang) => ( | ||
| <button | ||
|
Nsanjayboruds marked this conversation as resolved.
|
||
| key={lang.name} | ||
| className={`wizard-option ${language === lang.name ? 'selected' : ''}`} | ||
| type="button" | ||
| role="radio" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| aria-checked={language === lang.name} | ||
| className={`wizard-option ${ | ||
| language === lang.name ? "selected" : "" | ||
| }`} | ||
| onClick={() => handleLanguageSelect(lang.name)} | ||
| > | ||
| <div className="wizard-option-radio"> | ||
| {language === lang.name && <FaCheck size={10} color="#fff" />} | ||
| {language === lang.name && ( | ||
| <FaCheck size={10} color="#fff" /> | ||
| )} | ||
| </div> | ||
| <div className="wizard-option-icon" style={{color: lang.color}}> | ||
| <div | ||
| className="wizard-option-icon" | ||
| style={{color: lang.color}} | ||
| > | ||
| {lang.icon} | ||
| </div> | ||
| <span className="wizard-option-label">{lang.name}</span> | ||
|
|
@@ -416,30 +510,61 @@ export default function QuickstartFilter({defaultLanguage = null}) { | |
| {currentStep === 2 && ( | ||
| <> | ||
| <h3 className="wizard-title">Select your environment</h3> | ||
| <p className="wizard-subtitle">Choose where you want to run the application server</p> | ||
| <div className="wizard-options" style={{gridTemplateColumns: 'repeat(auto-fill, minmax(220px, 1fr))'}}> | ||
| <p className="wizard-subtitle"> | ||
| Choose where you want to run the application server | ||
| </p> | ||
| <div | ||
| className="wizard-options" | ||
| style={{ | ||
| gridTemplateColumns: "repeat(auto-fill, minmax(220px, 1fr))", | ||
| }} | ||
| > | ||
| {servers.map((srv) => ( | ||
| <button | ||
| key={srv.name} | ||
| className={`wizard-option ${server === srv.name ? 'selected' : ''}`} | ||
| type="button" | ||
| role="radio" | ||
| aria-checked={server === srv.name} | ||
| className={`wizard-option ${ | ||
| server === srv.name ? "selected" : "" | ||
| }`} | ||
| onClick={() => handleServerSelect(srv.name)} | ||
| style={{flexDirection: 'column', alignItems: 'flex-start', gap: '0.5rem'}} | ||
| style={{ | ||
| flexDirection: "column", | ||
| alignItems: "flex-start", | ||
| gap: "0.5rem", | ||
| }} | ||
| > | ||
| <div style={{display: 'flex', alignItems: 'center', gap: '0.75rem', width: '100%'}}> | ||
| <div | ||
| style={{ | ||
| display: "flex", | ||
| alignItems: "center", | ||
| gap: "0.75rem", | ||
| width: "100%", | ||
| }} | ||
| > | ||
| <div className="wizard-option-radio"> | ||
| {server === srv.name && <FaCheck size={10} color="#fff" />} | ||
| </div> | ||
| <div className="wizard-option-icon"> | ||
| {srv.icon} | ||
| {server === srv.name && ( | ||
| <FaCheck size={10} color="#fff" /> | ||
| )} | ||
| </div> | ||
| <div className="wizard-option-icon">{srv.icon}</div> | ||
| <span className="wizard-option-label">{srv.name}</span> | ||
| </div> | ||
| <p className="wizard-option-desc" style={{marginLeft: '3.5rem'}}>{srv.description}</p> | ||
| <p | ||
| className="wizard-option-desc" | ||
| style={{marginLeft: "3.5rem"}} | ||
| > | ||
| {srv.description} | ||
| </p> | ||
| </button> | ||
| ))} | ||
| </div> | ||
| <div className="wizard-actions"> | ||
| <button className="wizard-btn wizard-btn-secondary" onClick={goBack}> | ||
| <button | ||
| className="wizard-btn wizard-btn-secondary" | ||
| onClick={goBack} | ||
| > | ||
| <FaArrowLeft size={12} /> Back | ||
| </button> | ||
| </div> | ||
|
|
@@ -451,11 +576,15 @@ export default function QuickstartFilter({defaultLanguage = null}) { | |
| <> | ||
| <div className="wizard-selection-summary"> | ||
| <span className="wizard-selection-tag"> | ||
| {languages.find(l => l.name === language)?.icon} | ||
| {languages.find((l) => l.name === language)?.icon} | ||
| {language} | ||
| </span> | ||
| <span className="wizard-selection-tag"> | ||
| {server === "Docker" ? <FaDocker size={14} /> : <FaLaptopCode size={14} />} | ||
| {server === "Docker" ? ( | ||
| <FaDocker size={14} /> | ||
| ) : ( | ||
| <FaLaptopCode size={14} /> | ||
| )} | ||
| {server} | ||
| </span> | ||
| <button className="wizard-reset-btn" onClick={resetSelection}> | ||
|
|
@@ -465,8 +594,10 @@ export default function QuickstartFilter({defaultLanguage = null}) { | |
| <h3 className="wizard-title">β¨ Recommended Quickstarts</h3> | ||
| <p className="wizard-subtitle"> | ||
| {filteredQuickstarts.length > 0 | ||
| ? `Found ${filteredQuickstarts.length} quickstart${filteredQuickstarts.length > 1 ? 's' : ''} for ${language} with ${server}` | ||
| : 'No quickstarts available for this selection'} | ||
| ? `Found ${filteredQuickstarts.length} quickstart${ | ||
| filteredQuickstarts.length > 1 ? "s" : "" | ||
| } for ${language} with ${server}` | ||
| : "No quickstarts available for this selection"} | ||
| </p> | ||
| <div className="wizard-results"> | ||
| {filteredQuickstarts.map((app, idx) => ( | ||
|
|
@@ -480,7 +611,10 @@ export default function QuickstartFilter({defaultLanguage = null}) { | |
| ))} | ||
| </div> | ||
| <div className="wizard-actions"> | ||
| <button className="wizard-btn wizard-btn-secondary" onClick={goBack}> | ||
| <button | ||
| className="wizard-btn wizard-btn-secondary" | ||
| onClick={goBack} | ||
| > | ||
| <FaArrowLeft size={12} /> Back | ||
| </button> | ||
| </div> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This hand-rolls a semver parser plus a URL regex to work out which docs version is active, and then hard-codes
app.language === "Ruby"as a special case in a shared component. The next language that's v4-only will need anotherifhere.Docusaurus already exposes the active version (
useActiveDocContext/useDocsVersionfrom@docusaurus/plugin-content-docs/client). A cleaner shape: add an optionalminVersion: "4.0.0"(orversions: [...]) field to the two Ruby entries inQuickStartList.js, and filter on that generically. ThenisVersionAtLeastand the Ruby-specific branches at L60 and L78 go away.Separately, about 130 of the 164 added lines in this file are Prettier reformatting of code this PR doesn't otherwise touch (quote style, line wrapping). That makes the real change hard to review and creates conflicts for anyone else editing the wizard. Please revert the formatting-only hunks and keep the diff to the functional change.