├── .eslintrc.json ├── .gitignore ├── .webflowrc.js ├── README.md ├── components ├── Chart.js └── index.js ├── devlink ├── AboutHero.d.ts ├── AboutHero.js ├── AboutHero.module.css ├── AboutInformation.d.ts ├── AboutInformation.js ├── AboutInformation.module.css ├── Brands.d.ts ├── Brands.js ├── Brands.module.css ├── Cta.d.ts ├── Cta.js ├── Cta.module.css ├── Details.d.ts ├── Details.js ├── Details.module.css ├── Features.d.ts ├── Features.js ├── Features.module.css ├── Footer.d.ts ├── Footer.js ├── Footer.module.css ├── Hero.d.ts ├── Hero.js ├── Hero.module.css ├── JobListing.d.ts ├── JobListing.js ├── JobListing.module.css ├── Navbar.d.ts ├── Navbar.js ├── Navbar.module.css ├── Newnav.d.ts ├── Newnav.js ├── Newnav.module.css ├── PageHeading.d.ts ├── PageHeading.js ├── PageHeading.module.css ├── Pricing.d.ts ├── Pricing.js ├── Pricing.module.css ├── PricingGrid.d.ts ├── PricingGrid.js ├── PricingGrid.module.css ├── Stats.d.ts ├── Stats.js ├── Stats.module.css ├── _Builtin │ ├── BackgroundVideo.d.ts │ ├── BackgroundVideo.js │ ├── Basic.d.ts │ ├── Basic.js │ ├── Dropdown.d.ts │ ├── Dropdown.js │ ├── Facebook.d.ts │ ├── Facebook.js │ ├── Form.d.ts │ ├── Form.js │ ├── Map.d.ts │ ├── Map.js │ ├── Navbar.d.ts │ ├── Navbar.js │ ├── Slider.d.ts │ ├── Slider.js │ ├── Tabs.d.ts │ ├── Tabs.js │ ├── Twitter.d.ts │ ├── Twitter.js │ ├── Typography.d.ts │ ├── Typography.js │ ├── Video.d.ts │ ├── Video.js │ ├── YouTubeVideo.d.ts │ ├── YouTubeVideo.js │ ├── index.d.ts │ └── index.js ├── devlink.d.ts ├── devlink.js ├── global.css ├── index.d.ts ├── index.js ├── interactions.d.ts ├── interactions.js ├── types.d.ts ├── types.js ├── utils.d.ts └── utils.js ├── fetchJob.js ├── next.config.js ├── package-lock.json ├── package.json ├── pages ├── _app.tsx ├── _document.tsx ├── about.tsx ├── api │ ├── jobs.js │ └── jobs │ │ ├── [id].js │ │ └── featured.js ├── index.tsx ├── jobs.tsx └── jobs │ └── [id].jsx ├── public ├── favicon.ico ├── next.svg └── vercel.svg ├── styles ├── Home.module.css └── globals.css └── tsconfig.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | *.env 31 | .webflowrc.json 32 | 33 | # vercel 34 | .vercel 35 | 36 | # typescript 37 | *.tsbuildinfo 38 | next-env.d.ts 39 | -------------------------------------------------------------------------------- /.webflowrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | host: "https://api.webflow.com", 3 | rootDir: "./devlink", 4 | siteId: process.env.WF_SITE_ID, 5 | authToken: process.env.WF_SITE_TOKEN, // An environment variable is recommended for this field. 6 | cssModules: true, 7 | }; 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) and developed using [Webflow](https://webflow.com) and [DevLink](https://webflow.com/devlink). 2 | 3 | ## Webflow Cloneable 4 | 5 | You can clone the Webflow project used with this Next JS project at: 6 | 7 | [https://webflow.com/made-in-webflow/website/job-board-dl](https://webflow.com/made-in-webflow/website/job-board-dl) 8 | 9 | Make a copy, and then download this repo and connect the two using DevLink. 10 | 11 | Here's a Loom video to walk you through the process: 12 | 13 | [https://www.loom.com/share/ea21f62201df4e60a1f92524a28f810e](https://www.loom.com/share/ea21f62201df4e60a1f92524a28f810e) 14 | 15 | You can also view [our DevLink documentation](https://docs.developers.webflow.com/docs/devlink-documentation-and-usage-guide) to learn more about all the options, features, and supported elements. 16 | 17 | ## Getting Started 18 | 19 | To get started, run the development server: 20 | 21 | ```bash 22 | npm run dev 23 | # or 24 | yarn dev 25 | # or 26 | pnpm dev 27 | ``` 28 | 29 | ## Live site 30 | 31 | Open [http://localhost:3000](http://localhost:3000) with your browser to view the site. 32 | 33 | ## Backend and environment variables 34 | 35 | We created a light weight backend to serve up the content from Airtable. In order for this to work, you'll need to get a copy of [the Airtable](https://airtable.com/shr7X55pL1X4yDXq7), generate a [personal access token](https://airtable.com/developers/web/guides/personal-access-tokens) in Airtable (I used the scopes `data.records:read` and `schema.records.read`) and then in the root of your project create a `.env` file locally with the lines: 36 | 37 | ``` 38 | JOBS_KEY=YOURPERSONALACCESSTOKENHERE 39 | AIRTABLE_BASE_ID=YOURPERSONALAIRTABLEBASID 40 | WF_SITE_ID=YOURPERSONALWEBFLOWSITEID 41 | WF_SITE_TOKEN=YOURPERSONALWEBFLOWSITETOKEN 42 | ``` 43 | 44 | Here you can add: 45 | 46 | - Your Airtable API key 47 | - The ID of your Airtable base 48 | - Your Webflow API key 49 | - Your Webflow Site ID 50 | 51 | Once you've added these to your `.env` file, this project should function as expected. -------------------------------------------------------------------------------- /components/Chart.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js"; 3 | import { Pie } from "react-chartjs-2"; 4 | 5 | ChartJS.register(ArcElement, Tooltip, Legend); 6 | 7 | const data = { 8 | labels: ["More than 7 days", "Less than a week"], 9 | datasets: [ 10 | { 11 | label: "% of open roles", 12 | data: [15, 85], 13 | backgroundColor: ["rgba(153, 102, 255, 0.2)", "rgba(54, 162, 235, 0.2)"], 14 | borderColor: ["rgba(153, 102, 255, 1)", "rgba(54, 162, 235, 1)"], 15 | borderWidth: 1, 16 | }, 17 | ], 18 | }; 19 | 20 | export function Chart() { 21 | return ( 22 |
29 |
30 | 31 |
32 |
33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /components/index.js: -------------------------------------------------------------------------------- 1 | export * from "./Chart"; 2 | -------------------------------------------------------------------------------- /devlink/AboutHero.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | declare function AboutHero(props: { 4 | as?: React.ElementType; 5 | }): React.JSX.Element; 6 | -------------------------------------------------------------------------------- /devlink/AboutHero.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import * as _Builtin from "./_Builtin"; 3 | import * as _utils from "./utils"; 4 | import _styles from "./AboutHero.module.css"; 5 | 6 | export function AboutHero({ as: _Component = _Builtin.Section }) { 7 | return ( 8 | <_Component className={_utils.cx(_styles, "section", "hero")} tag="section"> 9 | <_Builtin.Container className={_utils.cx(_styles, "container")} tag="div"> 10 | <_Builtin.Block className={_utils.cx(_styles, "two-columns")} tag="div"> 11 | <_Builtin.Block 12 | className={_utils.cx(_styles, "hero-content-wrapper")} 13 | id={_utils.cx( 14 | _styles, 15 | "w-node-e99518a0-9081-2bc9-a4b2-c23fb0c1b414-b0c1b411" 16 | )} 17 | tag="div" 18 | > 19 | <_Builtin.Heading 20 | className={_utils.cx(_styles, "hero-heading")} 21 | tag="h1" 22 | > 23 | {"About us"} 24 | 25 | <_Builtin.Paragraph 26 | className={_utils.cx(_styles, "hero-paragraph")} 27 | > 28 | { 29 | "Discover the Future of Development at the Visual Developers Job Board - Where Talent Meets Opportunity." 30 | } 31 | 32 | 33 | <_Builtin.Block 34 | className={_utils.cx(_styles, "hero-image-wrapper")} 35 | id={_utils.cx( 36 | _styles, 37 | "w-node-e99518a0-9081-2bc9-a4b2-c23fb0c1b419-b0c1b411" 38 | )} 39 | tag="div" 40 | > 41 | <_Builtin.Image 42 | className={_utils.cx(_styles, "hero-image")} 43 | loading="lazy" 44 | width="auto" 45 | height="auto" 46 | src="https://uploads-ssl.webflow.com/644d71f7a83e2ea6946fafd7/644ea5920aef435a232ffdfc_Other%2021.png" 47 | /> 48 | 49 | 50 | 51 | 52 | ); 53 | } 54 | -------------------------------------------------------------------------------- /devlink/AboutHero.module.css: -------------------------------------------------------------------------------- 1 | .section { 2 | padding-top: 5em; 3 | padding-bottom: 5em; 4 | } 5 | 6 | .section.hero { 7 | position: relative; 8 | min-height: 600px; 9 | background-color: var(--clrPrimary600-aeaf7110); 10 | color: var(--clrNeutral100-f9191126); 11 | } 12 | 13 | .section.title { 14 | background-color: var(--clrPrimary400-6c00fdf1); 15 | color: var(--clrPrimary999-b0a60ce1); 16 | } 17 | 18 | .section.pricing-gradient { 19 | background-image: radial-gradient(circle farthest-corner at 50% 100%, var(--clrPrimary400-6c00fdf1), var(--clrPrimary999-b0a60ce1) 73%); 20 | color: var(--clrNeutral100-f9191126); 21 | } 22 | 23 | .section.pricing { 24 | position: relative; 25 | padding-top: 5em; 26 | color: hsla(329.9999999999999, 0.00%, 100.00%, 1.00); 27 | text-align: center; 28 | } 29 | 30 | .clr-secondary-400 { 31 | background-color: var(--clrSecondary400-685c3959); 32 | } 33 | 34 | .clr-primary-400 { 35 | background-color: var(--clrPrimary400-6c00fdf1); 36 | } 37 | 38 | .section.features { 39 | color: var(--clrPrimary600-aeaf7110); 40 | } 41 | 42 | .container { 43 | width: 100%; 44 | max-width: 1200px; 45 | margin-right: auto; 46 | margin-left: auto; 47 | padding-right: 1em; 48 | padding-left: 1em; 49 | } 50 | 51 | @media screen and (max-width: 767px) { 52 | .container { 53 | padding-right: 1.5em; 54 | padding-left: 1.5em; 55 | } 56 | } 57 | 58 | .container.nav { 59 | display: flex; 60 | justify-content: space-between; 61 | align-items: center; 62 | } 63 | 64 | .container.narrow { 65 | max-width: 720px; 66 | } 67 | 68 | .container.rel { 69 | position: relative; 70 | z-index: 2; 71 | } 72 | 73 | .center { 74 | text-align: center; 75 | } 76 | 77 | .two-columns { 78 | display: grid; 79 | padding-left: 0px; 80 | grid-auto-columns: 1fr; 81 | grid-column-gap: 1.5rem; 82 | grid-row-gap: 1.5rem; 83 | grid-template-columns: 1fr 1fr; 84 | grid-template-rows: auto; 85 | } 86 | 87 | @media screen and (max-width: 767px) { 88 | .two-columns { 89 | grid-template-columns: 1fr; 90 | } 91 | } 92 | 93 | .two-columns.narrow { 94 | max-width: 960px; 95 | margin: 3em auto; 96 | } 97 | 98 | .hero-content-wrapper { 99 | display: flex; 100 | flex-direction: column; 101 | flex-wrap: nowrap; 102 | align-items: flex-start; 103 | grid-row-gap: 1.2em; 104 | } 105 | 106 | .hero-heading { 107 | margin-top: 0px; 108 | margin-bottom: 0px; 109 | 110 | font-family: 'Playfair Display'; 111 | font-size: 5rem; 112 | line-height: 1; 113 | font-weight: 700; 114 | text-align: left; 115 | -webkit-text-stroke-color: var(--clrPrimary600-aeaf7110); 116 | } 117 | 118 | @media screen and (max-width: 991px) { 119 | .hero-heading { 120 | font-size: 5rem; 121 | } 122 | } 123 | 124 | @media screen and (max-width: 479px) { 125 | .hero-heading { 126 | line-height: 1; 127 | } 128 | } 129 | 130 | @media screen and (max-width: 767px) { 131 | .hero-heading { 132 | font-size: 14vw; 133 | } 134 | } 135 | 136 | .hero-paragraph { 137 | max-width: 60ch; 138 | margin-bottom: 0.5em; 139 | font-size: 1.2rem; 140 | } 141 | 142 | .hero-image { 143 | width: 100%; 144 | height: 100%; 145 | object-fit: contain; 146 | } 147 | 148 | #w-node-e99518a0-9081-2bc9-a4b2-c23fb0c1b414-b0c1b411 { 149 | grid-column-start: span 1; 150 | grid-column-end: span 1; 151 | grid-row-start: span 1; 152 | grid-row-end: span 1; 153 | align-self: center; 154 | } 155 | #w-node-e99518a0-9081-2bc9-a4b2-c23fb0c1b419-b0c1b411 { 156 | grid-column-start: span 1; 157 | grid-column-end: span 1; 158 | grid-row-start: span 1; 159 | grid-row-end: span 1; 160 | } -------------------------------------------------------------------------------- /devlink/AboutInformation.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | declare function AboutInformation(props: { 4 | as?: React.ElementType; 5 | }): React.JSX.Element; 6 | -------------------------------------------------------------------------------- /devlink/AboutInformation.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import * as _Builtin from "./_Builtin"; 3 | import * as _utils from "./utils"; 4 | import _styles from "./AboutInformation.module.css"; 5 | 6 | export function AboutInformation({ as: _Component = _Builtin.Section }) { 7 | return ( 8 | <_Component className={_utils.cx(_styles, "section")} tag="div"> 9 | <_Builtin.Container 10 | className={_utils.cx(_styles, "container", "narrow")} 11 | tag="div" 12 | > 13 | <_Builtin.RichText tag="div"> 14 | <_Builtin.Paragraph> 15 | { 16 | "The Visual Developers Job Board was created with a simple mission: to bridge the gap between the most talented developers in the Webflow, no-code, and traditional development spaces and the forward-thinking companies that need their expertise. Our platform offers a curated selection of high-quality job listings from innovative organizations that understand the importance of blending creativity and technical acumen. We're more than just a job board - we're a community that fosters growth and collaboration, helping our users unlock their true potential and reshape the digital landscape. Join us today and be a part of the revolution in modern development." 17 | } 18 | 19 | <_Builtin.Paragraph> 20 | { 21 | "In an ever-evolving technological landscape, the Visual Developers Job Board was born out of a passion for driving innovation and embracing the transformative potential of modern development techniques. We recognized the need for a dedicated platform that caters to Webflow, no-code, and traditional developers, as well as the companies that rely on their unique skillsets. Our commitment to fostering a vibrant community, centered around knowledge-sharing and collaboration, is what sets us apart. We exist to empower developers by providing them with the tools, resources, and opportunities needed to excel, while helping companies discover exceptional talent to bring their visionary projects to life. Together, we're building a more connected, creative, and technologically advanced future." 22 | } 23 | 24 | 25 | 26 | 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /devlink/AboutInformation.module.css: -------------------------------------------------------------------------------- 1 | .section { 2 | padding-top: 5em; 3 | padding-bottom: 5em; 4 | } 5 | 6 | .section.hero { 7 | position: relative; 8 | min-height: 600px; 9 | background-color: var(--clrPrimary600-aeaf7110); 10 | color: var(--clrNeutral100-f9191126); 11 | } 12 | 13 | .section.title { 14 | background-color: var(--clrPrimary400-6c00fdf1); 15 | color: var(--clrPrimary999-b0a60ce1); 16 | } 17 | 18 | .section.pricing-gradient { 19 | background-image: radial-gradient(circle farthest-corner at 50% 100%, var(--clrPrimary400-6c00fdf1), var(--clrPrimary999-b0a60ce1) 73%); 20 | color: var(--clrNeutral100-f9191126); 21 | } 22 | 23 | .section.pricing { 24 | position: relative; 25 | padding-top: 5em; 26 | color: hsla(329.9999999999999, 0.00%, 100.00%, 1.00); 27 | text-align: center; 28 | } 29 | 30 | .clr-secondary-400 { 31 | background-color: var(--clrSecondary400-685c3959); 32 | } 33 | 34 | .clr-primary-400 { 35 | background-color: var(--clrPrimary400-6c00fdf1); 36 | } 37 | 38 | .section.features { 39 | color: var(--clrPrimary600-aeaf7110); 40 | } 41 | 42 | .container { 43 | width: 100%; 44 | max-width: 1200px; 45 | margin-right: auto; 46 | margin-left: auto; 47 | padding-right: 1em; 48 | padding-left: 1em; 49 | } 50 | 51 | @media screen and (max-width: 767px) { 52 | .container { 53 | padding-right: 1.5em; 54 | padding-left: 1.5em; 55 | } 56 | } 57 | 58 | .container.nav { 59 | display: flex; 60 | justify-content: space-between; 61 | align-items: center; 62 | } 63 | 64 | .container.narrow { 65 | max-width: 720px; 66 | } 67 | 68 | .container.rel { 69 | position: relative; 70 | z-index: 2; 71 | } 72 | 73 | .center { 74 | text-align: center; 75 | } -------------------------------------------------------------------------------- /devlink/Brands.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | declare function Brands(props: { as?: React.ElementType }): React.JSX.Element; 4 | -------------------------------------------------------------------------------- /devlink/Brands.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import * as _Builtin from "./_Builtin"; 3 | import * as _utils from "./utils"; 4 | import _styles from "./Brands.module.css"; 5 | 6 | export function Brands({ as: _Component = _Builtin.Section }) { 7 | return ( 8 | <_Component className={_utils.cx(_styles, "section")} tag="section"> 9 | <_Builtin.Container className={_utils.cx(_styles, "container")} tag="div"> 10 | <_Builtin.Heading 11 | className={_utils.cx(_styles, "brand-heading")} 12 | tag="h2" 13 | > 14 | {"Trusted by brands around the world"} 15 | 16 | <_Builtin.Block className={_utils.cx(_styles, "logo-row")} tag="div"> 17 | <_Builtin.Block 18 | className={_utils.cx(_styles, "logo-wrapper")} 19 | id={_utils.cx( 20 | _styles, 21 | "w-node-b77115e0-1822-f0f7-10e0-565207c3febe-07c3feb9" 22 | )} 23 | tag="div" 24 | > 25 | <_Builtin.Image 26 | className={_utils.cx(_styles, "logo")} 27 | id={_utils.cx( 28 | _styles, 29 | "w-node-b77115e0-1822-f0f7-10e0-565207c3febf-07c3feb9" 30 | )} 31 | loading="lazy" 32 | width="auto" 33 | height="auto" 34 | src="https://uploads-ssl.webflow.com/644d71f7a83e2ea6946fafd7/644eaaf30704eaa87b2ce740_logo1.svg" 35 | /> 36 | 37 | <_Builtin.Block 38 | className={_utils.cx(_styles, "logo-wrapper")} 39 | id={_utils.cx( 40 | _styles, 41 | "w-node-b77115e0-1822-f0f7-10e0-565207c3fec0-07c3feb9" 42 | )} 43 | tag="div" 44 | > 45 | <_Builtin.Image 46 | className={_utils.cx(_styles, "logo")} 47 | loading="lazy" 48 | width="auto" 49 | height="auto" 50 | src="https://uploads-ssl.webflow.com/644d71f7a83e2ea6946fafd7/644eaaf349fbba209f989dd9_logo2.svg" 51 | /> 52 | 53 | <_Builtin.Block 54 | className={_utils.cx(_styles, "logo-wrapper")} 55 | id={_utils.cx( 56 | _styles, 57 | "w-node-b77115e0-1822-f0f7-10e0-565207c3fec2-07c3feb9" 58 | )} 59 | tag="div" 60 | > 61 | <_Builtin.Image 62 | className={_utils.cx(_styles, "logo")} 63 | id={_utils.cx( 64 | _styles, 65 | "w-node-b77115e0-1822-f0f7-10e0-565207c3fec3-07c3feb9" 66 | )} 67 | loading="lazy" 68 | width="auto" 69 | height="auto" 70 | src="https://uploads-ssl.webflow.com/644d71f7a83e2ea6946fafd7/644eaaf34c163508f9a43e72_logo3.svg" 71 | /> 72 | 73 | <_Builtin.Block 74 | className={_utils.cx(_styles, "logo-wrapper")} 75 | id={_utils.cx( 76 | _styles, 77 | "w-node-b77115e0-1822-f0f7-10e0-565207c3fec4-07c3feb9" 78 | )} 79 | tag="div" 80 | > 81 | <_Builtin.Image 82 | className={_utils.cx(_styles, "logo")} 83 | loading="lazy" 84 | width="auto" 85 | height="auto" 86 | src="https://uploads-ssl.webflow.com/644d71f7a83e2ea6946fafd7/644eaaf3e4f01820ea833689_logo5.svg" 87 | /> 88 | 89 | <_Builtin.Block 90 | className={_utils.cx(_styles, "logo-wrapper")} 91 | id={_utils.cx( 92 | _styles, 93 | "w-node-b77115e0-1822-f0f7-10e0-565207c3fec6-07c3feb9" 94 | )} 95 | tag="div" 96 | > 97 | <_Builtin.Image 98 | className={_utils.cx(_styles, "logo")} 99 | loading="lazy" 100 | width="auto" 101 | height="auto" 102 | src="https://uploads-ssl.webflow.com/644d71f7a83e2ea6946fafd7/644eaaf3c76d49471f3602f3_logo4.svg" 103 | /> 104 | 105 | 106 | 107 | 108 | ); 109 | } 110 | -------------------------------------------------------------------------------- /devlink/Brands.module.css: -------------------------------------------------------------------------------- 1 | .section { 2 | padding-top: 5em; 3 | padding-bottom: 5em; 4 | } 5 | 6 | .section.hero { 7 | position: relative; 8 | min-height: 600px; 9 | background-color: var(--clrPrimary600-aeaf7110); 10 | color: var(--clrNeutral100-f9191126); 11 | } 12 | 13 | .section.title { 14 | background-color: var(--clrPrimary400-6c00fdf1); 15 | color: var(--clrPrimary999-b0a60ce1); 16 | } 17 | 18 | .section.pricing-gradient { 19 | background-image: radial-gradient(circle farthest-corner at 50% 100%, var(--clrPrimary400-6c00fdf1), var(--clrPrimary999-b0a60ce1) 73%); 20 | color: var(--clrNeutral100-f9191126); 21 | } 22 | 23 | .section.pricing { 24 | position: relative; 25 | padding-top: 5em; 26 | color: hsla(329.9999999999999, 0.00%, 100.00%, 1.00); 27 | text-align: center; 28 | } 29 | 30 | .clr-secondary-400 { 31 | background-color: var(--clrSecondary400-685c3959); 32 | } 33 | 34 | .clr-primary-400 { 35 | background-color: var(--clrPrimary400-6c00fdf1); 36 | } 37 | 38 | .section.features { 39 | color: var(--clrPrimary600-aeaf7110); 40 | } 41 | 42 | .container { 43 | width: 100%; 44 | max-width: 1200px; 45 | margin-right: auto; 46 | margin-left: auto; 47 | padding-right: 1em; 48 | padding-left: 1em; 49 | } 50 | 51 | @media screen and (max-width: 767px) { 52 | .container { 53 | padding-right: 1.5em; 54 | padding-left: 1.5em; 55 | } 56 | } 57 | 58 | .container.nav { 59 | display: flex; 60 | justify-content: space-between; 61 | align-items: center; 62 | } 63 | 64 | .container.narrow { 65 | max-width: 720px; 66 | } 67 | 68 | .container.rel { 69 | position: relative; 70 | z-index: 2; 71 | } 72 | 73 | .center { 74 | text-align: center; 75 | } 76 | 77 | .brand-heading { 78 | margin-bottom: 2em; 79 | color: var(--clrPrimary600-aeaf7110); 80 | text-align: center; 81 | } 82 | 83 | .logo-row { 84 | display: flex; 85 | grid-auto-columns: 1fr; 86 | grid-column-gap: 4em; 87 | grid-template-columns: 1fr 1fr 1fr 1fr 1fr; 88 | grid-template-rows: auto; 89 | } 90 | 91 | @media screen and (max-width: 767px) { 92 | .logo-row { 93 | justify-content: center; 94 | flex-wrap: wrap; 95 | align-items: center; 96 | grid-column-gap: 1em; 97 | grid-row-gap: 1em; 98 | } 99 | } 100 | 101 | @media screen and (max-width: 479px) { 102 | .logo-row { 103 | grid-row-gap: 1em; 104 | grid-template-columns: 1fr 1fr 1fr; 105 | } 106 | } 107 | 108 | .logo-wrapper { 109 | color: var(--clrPrimary600-aeaf7110); 110 | } 111 | 112 | @media screen and (max-width: 767px) { 113 | .logo-wrapper { 114 | width: 24%; 115 | } 116 | } 117 | 118 | @media screen and (max-width: 479px) { 119 | .logo-wrapper { 120 | width: 40%; 121 | } 122 | } 123 | 124 | .logo { 125 | width: 100%; 126 | height: 100%; 127 | object-fit: contain; 128 | } 129 | 130 | #w-node-b77115e0-1822-f0f7-10e0-565207c3febe-07c3feb9 { 131 | grid-column-start: span 1; 132 | grid-column-end: span 1; 133 | grid-row-start: span 1; 134 | grid-row-end: span 1; 135 | align-self: center; 136 | } 137 | #w-node-b77115e0-1822-f0f7-10e0-565207c3febf-07c3feb9 { 138 | grid-column-start: span 1; 139 | grid-column-end: span 1; 140 | grid-row-start: span 1; 141 | grid-row-end: span 1; 142 | } 143 | #w-node-b77115e0-1822-f0f7-10e0-565207c3fec0-07c3feb9 { 144 | grid-column-start: span 1; 145 | grid-column-end: span 1; 146 | grid-row-start: span 1; 147 | grid-row-end: span 1; 148 | align-self: center; 149 | } 150 | #w-node-b77115e0-1822-f0f7-10e0-565207c3fec2-07c3feb9 { 151 | grid-column-start: span 1; 152 | grid-column-end: span 1; 153 | grid-row-start: span 1; 154 | grid-row-end: span 1; 155 | align-self: center; 156 | } 157 | #w-node-b77115e0-1822-f0f7-10e0-565207c3fec3-07c3feb9 { 158 | grid-column-start: span 1; 159 | grid-column-end: span 1; 160 | grid-row-start: span 1; 161 | grid-row-end: span 1; 162 | } 163 | #w-node-b77115e0-1822-f0f7-10e0-565207c3fec4-07c3feb9 { 164 | grid-column-start: span 1; 165 | grid-column-end: span 1; 166 | grid-row-start: span 1; 167 | grid-row-end: span 1; 168 | align-self: center; 169 | } 170 | #w-node-b77115e0-1822-f0f7-10e0-565207c3fec6-07c3feb9 { 171 | grid-column-start: span 1; 172 | grid-column-end: span 1; 173 | grid-row-start: span 1; 174 | grid-row-end: span 1; 175 | align-self: center; 176 | } -------------------------------------------------------------------------------- /devlink/Cta.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as Types from "./types"; 3 | 4 | declare function Cta(props: { 5 | as?: React.ElementType; 6 | headingText?: React.ReactNode; 7 | button?: Types.Devlink.RuntimeProps; 8 | }): React.JSX.Element; 9 | -------------------------------------------------------------------------------- /devlink/Cta.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import * as _Builtin from "./_Builtin"; 3 | import * as _utils from "./utils"; 4 | import _styles from "./Cta.module.css"; 5 | 6 | export function Cta({ 7 | as: _Component = _Builtin.Section, 8 | headingText = "Find your next job, today", 9 | button = {}, 10 | }) { 11 | return ( 12 | <_Component className={_utils.cx(_styles, "section")} tag="section"> 13 | <_Builtin.Container 14 | className={_utils.cx(_styles, "container", "center")} 15 | tag="div" 16 | > 17 | <_Builtin.Heading className={_utils.cx(_styles, "mb2")} tag="h2"> 18 | {headingText} 19 | 20 | <_Builtin.Paragraph className={_utils.cx(_styles, "mw-70ch", "mb2")}> 21 | { 22 | "Welcome to the Visual Developers Job Board - your one-stop destination for discovering the most exciting opportunities in Webflow, no-code, and traditional development. Empower your career by connecting with innovative companies that value creativity and technical expertise in equal measure." 23 | } 24 | 25 | <_Builtin.Link 26 | className={_utils.cx(_styles, "button")} 27 | button={true} 28 | options={{ 29 | href: "#", 30 | }} 31 | {...button} 32 | > 33 | {"Get started"} 34 | 35 | 36 | 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /devlink/Cta.module.css: -------------------------------------------------------------------------------- 1 | .section { 2 | padding-top: 5em; 3 | padding-bottom: 5em; 4 | } 5 | 6 | .section.hero { 7 | position: relative; 8 | min-height: 600px; 9 | background-color: var(--clrPrimary600-aeaf7110); 10 | color: var(--clrNeutral100-f9191126); 11 | } 12 | 13 | .section.title { 14 | background-color: var(--clrPrimary400-6c00fdf1); 15 | color: var(--clrPrimary999-b0a60ce1); 16 | } 17 | 18 | .section.pricing-gradient { 19 | background-image: radial-gradient(circle farthest-corner at 50% 100%, var(--clrPrimary400-6c00fdf1), var(--clrPrimary999-b0a60ce1) 73%); 20 | color: var(--clrNeutral100-f9191126); 21 | } 22 | 23 | .section.pricing { 24 | position: relative; 25 | padding-top: 5em; 26 | color: hsla(329.9999999999999, 0.00%, 100.00%, 1.00); 27 | text-align: center; 28 | } 29 | 30 | .clr-secondary-400 { 31 | background-color: var(--clrSecondary400-685c3959); 32 | } 33 | 34 | .clr-primary-400 { 35 | background-color: var(--clrPrimary400-6c00fdf1); 36 | } 37 | 38 | .section.features { 39 | color: var(--clrPrimary600-aeaf7110); 40 | } 41 | 42 | .container { 43 | width: 100%; 44 | max-width: 1200px; 45 | margin-right: auto; 46 | margin-left: auto; 47 | padding-right: 1em; 48 | padding-left: 1em; 49 | } 50 | 51 | @media screen and (max-width: 767px) { 52 | .container { 53 | padding-right: 1.5em; 54 | padding-left: 1.5em; 55 | } 56 | } 57 | 58 | .container.nav { 59 | display: flex; 60 | justify-content: space-between; 61 | align-items: center; 62 | } 63 | 64 | .container.narrow { 65 | max-width: 720px; 66 | } 67 | 68 | .container.rel { 69 | position: relative; 70 | z-index: 2; 71 | } 72 | 73 | .center { 74 | text-align: center; 75 | } 76 | 77 | .mb2 { 78 | margin-bottom: 2rem; 79 | } 80 | 81 | .mw-70ch { 82 | max-width: 70ch; 83 | margin-right: auto; 84 | margin-left: auto; 85 | } 86 | 87 | .button { 88 | padding: 1em 2em; 89 | 90 | border-radius: 2em; 91 | 92 | background-color: hsla(247.6190476190476, 42.28%, 29.22%, 1.00); 93 | 94 | box-shadow: none; 95 | 96 | transition: background-color 200ms ease,color 200ms ease; 97 | 98 | color: hsla(247.05882352941174, 0.00%, 100.00%, 1.00); 99 | font-size: 1.3rem; 100 | font-weight: 700; 101 | } 102 | 103 | .button:hover { 104 | background-color: hsla(196.55172413793105, 54.72%, 79.22%, 1.00); 105 | box-shadow: none; 106 | color: hsla(247.6190476190476, 42.28%, 29.22%, 1.00); 107 | } 108 | 109 | .button:focus { 110 | outline-color: var(--clrPrimary600-aeaf7110); 111 | outline-offset: 0.2rem; 112 | outline-style: solid; 113 | outline-width: 0.2rem; 114 | } 115 | 116 | .button:focus-visible { 117 | outline-color: var(--clrPrimary600-aeaf7110); 118 | outline-offset: 0.2rem; 119 | outline-style: solid; 120 | outline-width: 0.2rem; 121 | } 122 | 123 | .button.secondary { 124 | background-color: var(--clrSecondary400-685c3959); 125 | color: var(--clrPrimary600-aeaf7110); 126 | } 127 | 128 | .button.secondary:hover { 129 | background-color: var(--clrPrimary400-6c00fdf1); 130 | color: var(--clrNeutral100-f9191126); 131 | } 132 | 133 | .button.secondary:focus { 134 | outline-color: var(--clrSecondary400-685c3959); 135 | } 136 | 137 | .button.tertiary { 138 | background-color: var(--clrQuarternary400-68656429); 139 | color: var(--clrPrimary600-aeaf7110); 140 | } 141 | 142 | .button.tertiary:hover { 143 | background-color: var(--clrPrimary600-aeaf7110); 144 | color: var(--clrNeutral100-f9191126); 145 | } 146 | 147 | .button.tertiary:focus { 148 | outline-color: var(--clrQuarternary400-68656429); 149 | } 150 | 151 | .button.small { 152 | padding: 1em 1.5em; 153 | font-size: 1rem; 154 | } 155 | 156 | .button.sign-up { 157 | text-align: center; 158 | } -------------------------------------------------------------------------------- /devlink/Details.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as Types from "./types"; 3 | 4 | declare function Details(props: { 5 | as?: React.ElementType; 6 | company?: React.ReactNode; 7 | location?: React.ReactNode; 8 | category?: React.ReactNode; 9 | description?: React.ReactNode; 10 | benefits?: React.ReactNode; 11 | applyText?: React.ReactNode; 12 | applyLink?: Types.Basic.Link; 13 | }): React.JSX.Element; 14 | -------------------------------------------------------------------------------- /devlink/Details.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import * as _Builtin from "./_Builtin"; 3 | import * as _utils from "./utils"; 4 | import _styles from "./Details.module.css"; 5 | 6 | export function Details({ 7 | as: _Component = _Builtin.Section, 8 | company = "This is some text inside of a div block.", 9 | location = "This is some text inside of a div block.", 10 | category = "category", 11 | description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.", 12 | benefits = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.", 13 | applyText = "Apply now", 14 | 15 | applyLink = { 16 | href: "#", 17 | }, 18 | }) { 19 | return ( 20 | <_Component className={_utils.cx(_styles, "section")} tag="div"> 21 | <_Builtin.Container className={_utils.cx(_styles, "container")} tag="div"> 22 | <_Builtin.Block 23 | className={_utils.cx(_styles, "jobs-page-grid")} 24 | tag="div" 25 | > 26 | <_Builtin.Block 27 | className={_utils.cx(_styles, "job-meta-wrapper")} 28 | id={_utils.cx( 29 | _styles, 30 | "w-node-b5a5ddfd-6cd1-01fb-2140-91ef72d47996-72d47991" 31 | )} 32 | tag="div" 33 | > 34 | <_Builtin.Block 35 | className={_utils.cx(_styles, "job-meta-item")} 36 | tag="div" 37 | > 38 | <_Builtin.Block 39 | className={_utils.cx(_styles, "job-label")} 40 | tag="div" 41 | > 42 | {"Company"} 43 | 44 | <_Builtin.Block tag="div">{company} 45 | 46 | <_Builtin.Block 47 | className={_utils.cx(_styles, "job-meta-item")} 48 | tag="div" 49 | > 50 | <_Builtin.Block 51 | className={_utils.cx(_styles, "job-label")} 52 | tag="div" 53 | > 54 | {"Location"} 55 | 56 | <_Builtin.Block tag="div">{location} 57 | 58 | <_Builtin.Block 59 | className={_utils.cx(_styles, "job-meta-item")} 60 | tag="div" 61 | > 62 | <_Builtin.Block 63 | className={_utils.cx(_styles, "category-chip")} 64 | tag="div" 65 | > 66 | {category} 67 | 68 | 69 | 70 | <_Builtin.Block 71 | id={_utils.cx( 72 | _styles, 73 | "w-node-b5a5ddfd-6cd1-01fb-2140-91ef72d479a4-72d47991" 74 | )} 75 | tag="div" 76 | > 77 | <_Builtin.Heading className={_utils.cx(_styles, "mt0")} tag="h3"> 78 | {"About the role"} 79 | 80 | <_Builtin.Paragraph>{description} 81 | <_Builtin.Heading tag="h3">{"Benefits"} 82 | <_Builtin.Paragraph className={_utils.cx(_styles, "mb2")}> 83 | {benefits} 84 | 85 | <_Builtin.Link 86 | className={_utils.cx(_styles, "button")} 87 | button={true} 88 | options={applyLink} 89 | > 90 | {applyText} 91 | 92 | 93 | 94 | 95 | 96 | ); 97 | } 98 | -------------------------------------------------------------------------------- /devlink/Details.module.css: -------------------------------------------------------------------------------- 1 | .section { 2 | padding-top: 5em; 3 | padding-bottom: 5em; 4 | } 5 | 6 | .section.hero { 7 | position: relative; 8 | min-height: 600px; 9 | background-color: var(--clrPrimary600-aeaf7110); 10 | color: var(--clrNeutral100-f9191126); 11 | } 12 | 13 | .section.title { 14 | background-color: var(--clrPrimary400-6c00fdf1); 15 | color: var(--clrPrimary999-b0a60ce1); 16 | } 17 | 18 | .section.pricing-gradient { 19 | background-image: radial-gradient(circle farthest-corner at 50% 100%, var(--clrPrimary400-6c00fdf1), var(--clrPrimary999-b0a60ce1) 73%); 20 | color: var(--clrNeutral100-f9191126); 21 | } 22 | 23 | .section.pricing { 24 | position: relative; 25 | padding-top: 5em; 26 | color: hsla(329.9999999999999, 0.00%, 100.00%, 1.00); 27 | text-align: center; 28 | } 29 | 30 | .clr-secondary-400 { 31 | background-color: var(--clrSecondary400-685c3959); 32 | } 33 | 34 | .clr-primary-400 { 35 | background-color: var(--clrPrimary400-6c00fdf1); 36 | } 37 | 38 | .section.features { 39 | color: var(--clrPrimary600-aeaf7110); 40 | } 41 | 42 | .container { 43 | width: 100%; 44 | max-width: 1200px; 45 | margin-right: auto; 46 | margin-left: auto; 47 | padding-right: 1em; 48 | padding-left: 1em; 49 | } 50 | 51 | @media screen and (max-width: 767px) { 52 | .container { 53 | padding-right: 1.5em; 54 | padding-left: 1.5em; 55 | } 56 | } 57 | 58 | .container.nav { 59 | display: flex; 60 | justify-content: space-between; 61 | align-items: center; 62 | } 63 | 64 | .container.narrow { 65 | max-width: 720px; 66 | } 67 | 68 | .container.rel { 69 | position: relative; 70 | z-index: 2; 71 | } 72 | 73 | .center { 74 | text-align: center; 75 | } 76 | 77 | .jobs-page-grid { 78 | display: grid; 79 | grid-auto-columns: 1fr; 80 | grid-column-gap: 16px; 81 | grid-row-gap: 16px; 82 | grid-template-columns: 0.5fr 1fr; 83 | grid-template-rows: auto; 84 | } 85 | 86 | @media screen and (max-width: 767px) { 87 | .jobs-page-grid { 88 | grid-template-columns: 1fr; 89 | } 90 | } 91 | 92 | .job-meta-wrapper { 93 | display: flex; 94 | flex-direction: column; 95 | grid-row-gap: 1em; 96 | } 97 | 98 | .job-meta-item { 99 | display: flex; 100 | flex-direction: column; 101 | align-items: flex-start; 102 | } 103 | 104 | .job-label { 105 | font-weight: 700; 106 | } 107 | 108 | .category-chip { 109 | display: block; 110 | padding: 0.1em 1em; 111 | border-radius: 2em; 112 | background-color: var(--clrSecondary400-685c3959); 113 | color: var(--clrPrimary600-aeaf7110); 114 | } 115 | 116 | .mt0 { 117 | margin-top: 0px; 118 | } 119 | 120 | .mb2 { 121 | margin-bottom: 2rem; 122 | } 123 | 124 | .button { 125 | padding: 1em 2em; 126 | 127 | border-radius: 2em; 128 | 129 | background-color: hsla(247.6190476190476, 42.28%, 29.22%, 1.00); 130 | 131 | box-shadow: none; 132 | 133 | transition: background-color 200ms ease,color 200ms ease; 134 | 135 | color: hsla(247.05882352941174, 0.00%, 100.00%, 1.00); 136 | font-size: 1.3rem; 137 | font-weight: 700; 138 | } 139 | 140 | .button:hover { 141 | background-color: hsla(196.55172413793105, 54.72%, 79.22%, 1.00); 142 | box-shadow: none; 143 | color: hsla(247.6190476190476, 42.28%, 29.22%, 1.00); 144 | } 145 | 146 | .button:focus { 147 | outline-color: var(--clrPrimary600-aeaf7110); 148 | outline-offset: 0.2rem; 149 | outline-style: solid; 150 | outline-width: 0.2rem; 151 | } 152 | 153 | .button:focus-visible { 154 | outline-color: var(--clrPrimary600-aeaf7110); 155 | outline-offset: 0.2rem; 156 | outline-style: solid; 157 | outline-width: 0.2rem; 158 | } 159 | 160 | .button.secondary { 161 | background-color: var(--clrSecondary400-685c3959); 162 | color: var(--clrPrimary600-aeaf7110); 163 | } 164 | 165 | .button.secondary:hover { 166 | background-color: var(--clrPrimary400-6c00fdf1); 167 | color: var(--clrNeutral100-f9191126); 168 | } 169 | 170 | .button.secondary:focus { 171 | outline-color: var(--clrSecondary400-685c3959); 172 | } 173 | 174 | .button.tertiary { 175 | background-color: var(--clrQuarternary400-68656429); 176 | color: var(--clrPrimary600-aeaf7110); 177 | } 178 | 179 | .button.tertiary:hover { 180 | background-color: var(--clrPrimary600-aeaf7110); 181 | color: var(--clrNeutral100-f9191126); 182 | } 183 | 184 | .button.tertiary:focus { 185 | outline-color: var(--clrQuarternary400-68656429); 186 | } 187 | 188 | .button.small { 189 | padding: 1em 1.5em; 190 | font-size: 1rem; 191 | } 192 | 193 | .button.sign-up { 194 | text-align: center; 195 | } 196 | 197 | #w-node-b5a5ddfd-6cd1-01fb-2140-91ef72d47996-72d47991 { 198 | grid-column-start: span 1; 199 | grid-column-end: span 1; 200 | grid-row-start: span 1; 201 | grid-row-end: span 1; 202 | } 203 | #w-node-b5a5ddfd-6cd1-01fb-2140-91ef72d479a4-72d47991 { 204 | grid-column-start: span 1; 205 | grid-column-end: span 1; 206 | grid-row-start: span 1; 207 | grid-row-end: span 1; 208 | } -------------------------------------------------------------------------------- /devlink/Features.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | declare function Features(props: { as?: React.ElementType }): React.JSX.Element; 4 | -------------------------------------------------------------------------------- /devlink/Features.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import * as _Builtin from "./_Builtin"; 3 | import * as _utils from "./utils"; 4 | import _styles from "./Features.module.css"; 5 | 6 | export function Features({ as: _Component = _Builtin.Section }) { 7 | return ( 8 | <_Component 9 | className={_utils.cx(_styles, "section", "features")} 10 | tag="section" 11 | > 12 | <_Builtin.Container className={_utils.cx(_styles, "container")} tag="div"> 13 | <_Builtin.Block 14 | className={_utils.cx(_styles, "center", "mb2")} 15 | tag="div" 16 | > 17 | <_Builtin.Heading tag="h2">{"Features"} 18 | <_Builtin.Paragraph> 19 | { 20 | "Unlock the Power of the Visual Developers Job Board - Your Ultimate Resource for Development Opportunities" 21 | } 22 | 23 | 24 | <_Builtin.Block 25 | className={_utils.cx(_styles, "three-columns")} 26 | tag="div" 27 | > 28 | <_Builtin.Block 29 | className={_utils.cx(_styles, "feature-card")} 30 | id={_utils.cx( 31 | _styles, 32 | "w-node-_95e9dcd2-35a4-35c7-cf9c-c5baf1e2c917-f1e2c90f" 33 | )} 34 | tag="div" 35 | > 36 | <_Builtin.Block 37 | className={_utils.cx(_styles, "feature-title-wrapper")} 38 | tag="div" 39 | > 40 | <_Builtin.Image 41 | className={_utils.cx(_styles, "feature-icon")} 42 | loading="lazy" 43 | width="auto" 44 | height="auto" 45 | src="https://uploads-ssl.webflow.com/644d71f7a83e2ea6946fafd7/645407fd9fc7ae328679723e_curated.png" 46 | /> 47 | <_Builtin.Block tag="div"> 48 | {"Curated Job Listings"} 49 | 50 | 51 | <_Builtin.Paragraph className={_utils.cx(_styles, "p-small")}> 52 | { 53 | "Access a diverse range of high-quality job opportunities in Webflow, no-code, and traditional development, hand-picked by our expert team." 54 | } 55 | 56 | 57 | <_Builtin.Block 58 | className={_utils.cx(_styles, "feature-card")} 59 | id={_utils.cx( 60 | _styles, 61 | "w-node-_95e9dcd2-35a4-35c7-cf9c-c5baf1e2c91e-f1e2c90f" 62 | )} 63 | tag="div" 64 | > 65 | <_Builtin.Block 66 | className={_utils.cx(_styles, "feature-title-wrapper")} 67 | tag="div" 68 | > 69 | <_Builtin.Image 70 | className={_utils.cx(_styles, "feature-icon")} 71 | loading="lazy" 72 | width="auto" 73 | height="auto" 74 | src="https://uploads-ssl.webflow.com/644d71f7a83e2ea6946fafd7/645407fe16b9ae509ed7c888_personalized.png" 75 | /> 76 | <_Builtin.Block tag="div"> 77 | {"Personalized Recommendations"} 78 | 79 | 80 | <_Builtin.Paragraph className={_utils.cx(_styles, "p-small")}> 81 | { 82 | "Enjoy a tailored job search experience with customized recommendations based on your unique skills, preferences, and career goals." 83 | } 84 | 85 | 86 | <_Builtin.Block 87 | className={_utils.cx(_styles, "feature-card")} 88 | id={_utils.cx( 89 | _styles, 90 | "w-node-_95e9dcd2-35a4-35c7-cf9c-c5baf1e2c925-f1e2c90f" 91 | )} 92 | tag="div" 93 | > 94 | <_Builtin.Block 95 | className={_utils.cx(_styles, "feature-title-wrapper")} 96 | tag="div" 97 | > 98 | <_Builtin.Image 99 | className={_utils.cx(_styles, "feature-icon")} 100 | loading="lazy" 101 | width="auto" 102 | height="auto" 103 | src="https://uploads-ssl.webflow.com/644d71f7a83e2ea6946fafd7/645407fe73cfb1455881c4f3_exclusive.png" 104 | /> 105 | <_Builtin.Block tag="div"> 106 | {"Exclusive Opportunities"} 107 | 108 | 109 | <_Builtin.Paragraph className={_utils.cx(_styles, "p-small")}> 110 | { 111 | "Stay ahead of the competition with early access to job listings, networking events, and industry insights available only to our community members." 112 | } 113 | 114 | 115 | <_Builtin.Block 116 | className={_utils.cx(_styles, "feature-card")} 117 | id={_utils.cx( 118 | _styles, 119 | "w-node-_95e9dcd2-35a4-35c7-cf9c-c5baf1e2c92c-f1e2c90f" 120 | )} 121 | tag="div" 122 | > 123 | <_Builtin.Block 124 | className={_utils.cx(_styles, "feature-title-wrapper")} 125 | tag="div" 126 | > 127 | <_Builtin.Image 128 | className={_utils.cx(_styles, "feature-icon")} 129 | loading="lazy" 130 | width="auto" 131 | height="auto" 132 | src="https://uploads-ssl.webflow.com/644d71f7a83e2ea6946fafd7/645407feadf27949cb5f8faf_Frame%202.png" 133 | /> 134 | <_Builtin.Block tag="div"> 135 | {"Comprehensive Resources"} 136 | 137 | 138 | <_Builtin.Paragraph className={_utils.cx(_styles, "p-small")}> 139 | { 140 | "Boost your skills and knowledge with our extensive library of articles, tutorials, webinars, and more, designed to help you excel in your career." 141 | } 142 | 143 | 144 | <_Builtin.Block 145 | className={_utils.cx(_styles, "feature-card")} 146 | id={_utils.cx( 147 | _styles, 148 | "w-node-_95e9dcd2-35a4-35c7-cf9c-c5baf1e2c933-f1e2c90f" 149 | )} 150 | tag="div" 151 | > 152 | <_Builtin.Block 153 | className={_utils.cx(_styles, "feature-title-wrapper")} 154 | tag="div" 155 | > 156 | <_Builtin.Image 157 | className={_utils.cx(_styles, "feature-icon")} 158 | loading="lazy" 159 | width="auto" 160 | height="auto" 161 | src="https://uploads-ssl.webflow.com/644d71f7a83e2ea6946fafd7/645407fdd0924e5433d823a2_community.png" 162 | /> 163 | <_Builtin.Block tag="div">{"Community Support"} 164 | 165 | <_Builtin.Paragraph className={_utils.cx(_styles, "p-small")}> 166 | { 167 | "Join a thriving network of like-minded professionals, share your experiences, and collaborate on projects to drive innovation and growth in the development space." 168 | } 169 | 170 | 171 | <_Builtin.Block 172 | className={_utils.cx(_styles, "feature-card")} 173 | id={_utils.cx( 174 | _styles, 175 | "w-node-_95e9dcd2-35a4-35c7-cf9c-c5baf1e2c93a-f1e2c90f" 176 | )} 177 | tag="div" 178 | > 179 | <_Builtin.Block 180 | className={_utils.cx(_styles, "feature-title-wrapper")} 181 | tag="div" 182 | > 183 | <_Builtin.Image 184 | className={_utils.cx(_styles, "feature-icon")} 185 | loading="lazy" 186 | width="auto" 187 | height="auto" 188 | src="https://uploads-ssl.webflow.com/644d71f7a83e2ea6946fafd7/645407fd76c2b16bd34752a1_money.png" 189 | /> 190 | <_Builtin.Block tag="div">{"Flexible Pricing"} 191 | 192 | <_Builtin.Paragraph className={_utils.cx(_styles, "p-small")}> 193 | { 194 | "Choose from a variety of plans to suit your needs, whether you're a job seeker, employer, or student, and get the most out of your Visual Developers Job Board experience." 195 | } 196 | 197 | 198 | 199 | 200 | 201 | ); 202 | } 203 | -------------------------------------------------------------------------------- /devlink/Features.module.css: -------------------------------------------------------------------------------- 1 | .section { 2 | padding-top: 5em; 3 | padding-bottom: 5em; 4 | } 5 | 6 | .section.hero { 7 | position: relative; 8 | min-height: 600px; 9 | background-color: var(--clrPrimary600-aeaf7110); 10 | color: var(--clrNeutral100-f9191126); 11 | } 12 | 13 | .section.title { 14 | background-color: var(--clrPrimary400-6c00fdf1); 15 | color: var(--clrPrimary999-b0a60ce1); 16 | } 17 | 18 | .section.pricing-gradient { 19 | background-image: radial-gradient(circle farthest-corner at 50% 100%, var(--clrPrimary400-6c00fdf1), var(--clrPrimary999-b0a60ce1) 73%); 20 | color: var(--clrNeutral100-f9191126); 21 | } 22 | 23 | .section.pricing { 24 | position: relative; 25 | padding-top: 5em; 26 | color: hsla(329.9999999999999, 0.00%, 100.00%, 1.00); 27 | text-align: center; 28 | } 29 | 30 | .clr-secondary-400 { 31 | background-color: var(--clrSecondary400-685c3959); 32 | } 33 | 34 | .clr-primary-400 { 35 | background-color: var(--clrPrimary400-6c00fdf1); 36 | } 37 | 38 | .section.features { 39 | color: var(--clrPrimary600-aeaf7110); 40 | } 41 | 42 | .container { 43 | width: 100%; 44 | max-width: 1200px; 45 | margin-right: auto; 46 | margin-left: auto; 47 | padding-right: 1em; 48 | padding-left: 1em; 49 | } 50 | 51 | @media screen and (max-width: 767px) { 52 | .container { 53 | padding-right: 1.5em; 54 | padding-left: 1.5em; 55 | } 56 | } 57 | 58 | .container.nav { 59 | display: flex; 60 | justify-content: space-between; 61 | align-items: center; 62 | } 63 | 64 | .container.narrow { 65 | max-width: 720px; 66 | } 67 | 68 | .container.rel { 69 | position: relative; 70 | z-index: 2; 71 | } 72 | 73 | .center { 74 | text-align: center; 75 | } 76 | 77 | .mb2 { 78 | margin-bottom: 2rem; 79 | } 80 | 81 | .three-columns { 82 | display: grid; 83 | grid-auto-columns: 1fr; 84 | grid-column-gap: 1em; 85 | grid-row-gap: 1em; 86 | grid-template-columns: 1fr 1fr 1fr; 87 | grid-template-rows: auto auto; 88 | } 89 | 90 | @media screen and (max-width: 991px) { 91 | .three-columns { 92 | grid-template-columns: 1fr 1fr; 93 | } 94 | } 95 | 96 | @media screen and (max-width: 767px) { 97 | .three-columns { 98 | grid-template-columns: 1fr; 99 | } 100 | } 101 | 102 | .feature-card { 103 | display: flex; 104 | padding: 2em; 105 | flex-direction: column; 106 | grid-row-gap: 1em; 107 | 108 | border-radius: 2em; 109 | 110 | background-color: hsla(210, 13.33%, 94.12%, 0.35); 111 | } 112 | 113 | .feature-title-wrapper { 114 | display: flex; 115 | align-items: center; 116 | grid-column-gap: 1em; 117 | font-weight: 700; 118 | } 119 | 120 | @media screen and (max-width: 479px) { 121 | .feature-title-wrapper { 122 | flex-direction: column; 123 | align-items: flex-start; 124 | grid-row-gap: 1em; 125 | } 126 | } 127 | 128 | .feature-icon { 129 | width: 40px; 130 | } 131 | 132 | .p-small { 133 | font-size: 1rem; 134 | } 135 | 136 | #w-node-_95e9dcd2-35a4-35c7-cf9c-c5baf1e2c917-f1e2c90f { 137 | grid-column-start: span 1; 138 | grid-column-end: span 1; 139 | grid-row-start: span 1; 140 | grid-row-end: span 1; 141 | } 142 | #w-node-_95e9dcd2-35a4-35c7-cf9c-c5baf1e2c91e-f1e2c90f { 143 | grid-column-start: span 1; 144 | grid-column-end: span 1; 145 | grid-row-start: span 1; 146 | grid-row-end: span 1; 147 | } 148 | #w-node-_95e9dcd2-35a4-35c7-cf9c-c5baf1e2c925-f1e2c90f { 149 | grid-column-start: span 1; 150 | grid-column-end: span 1; 151 | grid-row-start: span 1; 152 | grid-row-end: span 1; 153 | } 154 | #w-node-_95e9dcd2-35a4-35c7-cf9c-c5baf1e2c92c-f1e2c90f { 155 | grid-column-start: span 1; 156 | grid-column-end: span 1; 157 | grid-row-start: span 1; 158 | grid-row-end: span 1; 159 | } 160 | #w-node-_95e9dcd2-35a4-35c7-cf9c-c5baf1e2c933-f1e2c90f { 161 | grid-column-start: span 1; 162 | grid-column-end: span 1; 163 | grid-row-start: span 1; 164 | grid-row-end: span 1; 165 | } 166 | #w-node-_95e9dcd2-35a4-35c7-cf9c-c5baf1e2c93a-f1e2c90f { 167 | grid-column-start: span 1; 168 | grid-column-end: span 1; 169 | grid-row-start: span 1; 170 | grid-row-end: span 1; 171 | } -------------------------------------------------------------------------------- /devlink/Footer.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as Types from "./types"; 3 | 4 | declare function Footer(props: { 5 | as?: React.ElementType; 6 | year?: React.ReactNode; 7 | }): React.JSX.Element; 8 | -------------------------------------------------------------------------------- /devlink/Footer.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import * as _Builtin from "./_Builtin"; 3 | import * as _utils from "./utils"; 4 | import _styles from "./Footer.module.css"; 5 | 6 | export function Footer({ as: _Component = _Builtin.Section, year = "XXXX" }) { 7 | return ( 8 | <_Component className={_utils.cx(_styles, "footer")} tag="footer"> 9 | <_Builtin.Container className={_utils.cx(_styles, "container")} tag="div"> 10 | <_Builtin.List 11 | className={_utils.cx(_styles, "footer-list")} 12 | tag="ul" 13 | unstyled={false} 14 | > 15 | <_Builtin.ListItem className={_utils.cx(_styles, "navlist-item")}> 16 | <_Builtin.Link 17 | className={_utils.cx(_styles, "footer-link")} 18 | button={false} 19 | options={{ 20 | href: "/", 21 | }} 22 | > 23 | {"Home"} 24 | 25 | 26 | <_Builtin.ListItem className={_utils.cx(_styles, "navlist-item")}> 27 | <_Builtin.Link 28 | className={_utils.cx(_styles, "footer-link")} 29 | button={false} 30 | options={{ 31 | href: "/about", 32 | }} 33 | > 34 | {"About"} 35 | 36 | 37 | <_Builtin.ListItem className={_utils.cx(_styles, "navlist-item")}> 38 | <_Builtin.Link 39 | className={_utils.cx(_styles, "footer-link")} 40 | button={false} 41 | options={{ 42 | href: "/jobs", 43 | }} 44 | > 45 | {"Jobs"} 46 | 47 | 48 | <_Builtin.ListItem className={_utils.cx(_styles, "navlist-item")}> 49 | <_Builtin.Link 50 | className={_utils.cx(_styles, "footer-link")} 51 | button={false} 52 | options={{ 53 | href: "https://webflow.com", 54 | target: "_blank", 55 | }} 56 | > 57 | {"Webflow"} 58 | 59 | 60 | <_Builtin.ListItem className={_utils.cx(_styles, "navlist-item")}> 61 | <_Builtin.Link 62 | className={_utils.cx(_styles, "footer-link")} 63 | button={false} 64 | options={{ 65 | href: "https://webflow.com/devlink", 66 | target: "_blank", 67 | }} 68 | > 69 | {"DevLink"} 70 | 71 | 72 | 73 | <_Builtin.Block 74 | className={_utils.cx(_styles, "footer-small")} 75 | tag="div" 76 | > 77 | <_Builtin.Block tag="div">{"©"} 78 | <_Builtin.Block tag="div">{year} 79 | <_Builtin.Block tag="div"> 80 | { 81 | "Visual Development Job Board. This is all fake. Content by ChatGPT , built in Webflow using DevLink" 82 | } 83 | 84 | 85 | 86 | 87 | ); 88 | } 89 | -------------------------------------------------------------------------------- /devlink/Footer.module.css: -------------------------------------------------------------------------------- 1 | .footer { 2 | padding-top: 5em; 3 | padding-bottom: 5em; 4 | background-color: var(--clrPrimary600-aeaf7110); 5 | color: var(--clrNeutral100-f9191126); 6 | } 7 | 8 | .container { 9 | width: 100%; 10 | max-width: 1200px; 11 | margin-right: auto; 12 | margin-left: auto; 13 | padding-right: 1em; 14 | padding-left: 1em; 15 | } 16 | 17 | @media screen and (max-width: 767px) { 18 | .container { 19 | padding-right: 1.5em; 20 | padding-left: 1.5em; 21 | } 22 | } 23 | 24 | .container.nav { 25 | display: flex; 26 | justify-content: space-between; 27 | align-items: center; 28 | } 29 | 30 | .container.narrow { 31 | max-width: 720px; 32 | } 33 | 34 | .container.rel { 35 | position: relative; 36 | z-index: 2; 37 | } 38 | 39 | .center { 40 | text-align: center; 41 | } 42 | 43 | .footer-list { 44 | display: flex; 45 | margin-bottom: 2em; 46 | padding-left: 0px; 47 | justify-content: center; 48 | align-items: center; 49 | grid-column-gap: 1em; 50 | 51 | list-style-type: none; 52 | } 53 | 54 | .navlist-item { 55 | margin-bottom: 0em; 56 | } 57 | 58 | .footer-link { 59 | color: var(--clrNeutral100-f9191126); 60 | } 61 | 62 | .footer-link:focus { 63 | border-radius: 0em; 64 | outline-color: var(--clrNeutral100-f9191126); 65 | outline-offset: 0.3rem; 66 | outline-style: solid; 67 | outline-width: 0.2rem; 68 | } 69 | 70 | .footer-link:focus-visible { 71 | outline-color: var(--clrNeutral100-f9191126); 72 | outline-offset: 0.3rem; 73 | outline-style: solid; 74 | outline-width: 0.2rem; 75 | } 76 | 77 | .footer-small { 78 | display: flex; 79 | justify-content: center; 80 | align-items: center; 81 | grid-column-gap: 0.25em; 82 | 83 | font-size: 0.8rem; 84 | text-align: center; 85 | } -------------------------------------------------------------------------------- /devlink/Hero.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as Types from "./types"; 3 | 4 | declare function Hero(props: { 5 | as?: React.ElementType; 6 | buttonText?: React.ReactNode; 7 | buttonLink?: Types.Basic.Link; 8 | }): React.JSX.Element; 9 | -------------------------------------------------------------------------------- /devlink/Hero.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import * as _Builtin from "./_Builtin"; 3 | import * as _utils from "./utils"; 4 | import _styles from "./Hero.module.css"; 5 | 6 | export function Hero({ 7 | as: _Component = _Builtin.Section, 8 | buttonText = "View open roles", 9 | 10 | buttonLink = { 11 | href: "#", 12 | }, 13 | }) { 14 | return ( 15 | <_Component className={_utils.cx(_styles, "section", "hero")} tag="section"> 16 | <_Builtin.Container className={_utils.cx(_styles, "container")} tag="div"> 17 | <_Builtin.Block className={_utils.cx(_styles, "two-columns")} tag="div"> 18 | <_Builtin.Block 19 | className={_utils.cx(_styles, "hero-content-wrapper")} 20 | id={_utils.cx( 21 | _styles, 22 | "w-node-eec4ca81-6ae6-a937-d67c-2a2debaf4e5f-ebaf4e5c" 23 | )} 24 | tag="div" 25 | > 26 | <_Builtin.Heading 27 | className={_utils.cx(_styles, "hero-heading")} 28 | tag="h1" 29 | > 30 | {"Visual"} 31 |
32 | {"Development"} 33 |
34 | {"Job Board"} 35 | 36 | <_Builtin.Paragraph 37 | className={_utils.cx(_styles, "hero-paragraph")} 38 | > 39 | { 40 | "Welcome to the Visual Developers Job Board - your one-stop destination for discovering the most exciting opportunities in Webflow, no-code, and traditional development. Empower your career by connecting with innovative companies that value creativity and technical expertise in equal measure." 41 | } 42 | 43 | <_Builtin.Link 44 | className={_utils.cx(_styles, "button", "secondary")} 45 | button={true} 46 | options={buttonLink} 47 | > 48 | {buttonText} 49 | 50 | 51 | <_Builtin.Block 52 | className={_utils.cx(_styles, "hero-image-wrapper")} 53 | id={_utils.cx( 54 | _styles, 55 | "w-node-eec4ca81-6ae6-a937-d67c-2a2debaf4e6a-ebaf4e5c" 56 | )} 57 | tag="div" 58 | > 59 | <_Builtin.Image 60 | className={_utils.cx(_styles, "hero-image")} 61 | loading="eager" 62 | width="auto" 63 | height="auto" 64 | src="https://uploads-ssl.webflow.com/644d71f7a83e2ea6946fafd7/644ea54b57472ff521fca399_main-object.png" 65 | /> 66 | 67 | 68 | 69 | 70 | ); 71 | } 72 | -------------------------------------------------------------------------------- /devlink/Hero.module.css: -------------------------------------------------------------------------------- 1 | .section { 2 | padding-top: 5em; 3 | padding-bottom: 5em; 4 | } 5 | 6 | .section.hero { 7 | position: relative; 8 | min-height: 600px; 9 | background-color: var(--clrPrimary600-aeaf7110); 10 | color: var(--clrNeutral100-f9191126); 11 | } 12 | 13 | .section.title { 14 | background-color: var(--clrPrimary400-6c00fdf1); 15 | color: var(--clrPrimary999-b0a60ce1); 16 | } 17 | 18 | .section.pricing-gradient { 19 | background-image: radial-gradient(circle farthest-corner at 50% 100%, var(--clrPrimary400-6c00fdf1), var(--clrPrimary999-b0a60ce1) 73%); 20 | color: var(--clrNeutral100-f9191126); 21 | } 22 | 23 | .section.pricing { 24 | position: relative; 25 | padding-top: 5em; 26 | color: hsla(329.9999999999999, 0.00%, 100.00%, 1.00); 27 | text-align: center; 28 | } 29 | 30 | .clr-secondary-400 { 31 | background-color: var(--clrSecondary400-685c3959); 32 | } 33 | 34 | .clr-primary-400 { 35 | background-color: var(--clrPrimary400-6c00fdf1); 36 | } 37 | 38 | .section.features { 39 | color: var(--clrPrimary600-aeaf7110); 40 | } 41 | 42 | .container { 43 | width: 100%; 44 | max-width: 1200px; 45 | margin-right: auto; 46 | margin-left: auto; 47 | padding-right: 1em; 48 | padding-left: 1em; 49 | } 50 | 51 | @media screen and (max-width: 767px) { 52 | .container { 53 | padding-right: 1.5em; 54 | padding-left: 1.5em; 55 | } 56 | } 57 | 58 | .container.nav { 59 | display: flex; 60 | justify-content: space-between; 61 | align-items: center; 62 | } 63 | 64 | .container.narrow { 65 | max-width: 720px; 66 | } 67 | 68 | .container.rel { 69 | position: relative; 70 | z-index: 2; 71 | } 72 | 73 | .center { 74 | text-align: center; 75 | } 76 | 77 | .two-columns { 78 | display: grid; 79 | padding-left: 0px; 80 | grid-auto-columns: 1fr; 81 | grid-column-gap: 1.5rem; 82 | grid-row-gap: 1.5rem; 83 | grid-template-columns: 1fr 1fr; 84 | grid-template-rows: auto; 85 | } 86 | 87 | @media screen and (max-width: 767px) { 88 | .two-columns { 89 | grid-template-columns: 1fr; 90 | } 91 | } 92 | 93 | .two-columns.narrow { 94 | max-width: 960px; 95 | margin: 3em auto; 96 | } 97 | 98 | .hero-content-wrapper { 99 | display: flex; 100 | flex-direction: column; 101 | flex-wrap: nowrap; 102 | align-items: flex-start; 103 | grid-row-gap: 1.2em; 104 | } 105 | 106 | .hero-heading { 107 | margin-top: 0px; 108 | margin-bottom: 0px; 109 | 110 | font-family: 'Playfair Display'; 111 | font-size: 5rem; 112 | line-height: 1; 113 | font-weight: 700; 114 | text-align: left; 115 | -webkit-text-stroke-color: var(--clrPrimary600-aeaf7110); 116 | } 117 | 118 | @media screen and (max-width: 991px) { 119 | .hero-heading { 120 | font-size: 5rem; 121 | } 122 | } 123 | 124 | @media screen and (max-width: 479px) { 125 | .hero-heading { 126 | line-height: 1; 127 | } 128 | } 129 | 130 | @media screen and (max-width: 767px) { 131 | .hero-heading { 132 | font-size: 14vw; 133 | } 134 | } 135 | 136 | .hero-paragraph { 137 | max-width: 60ch; 138 | margin-bottom: 0.5em; 139 | font-size: 1.2rem; 140 | } 141 | 142 | .button { 143 | padding: 1em 2em; 144 | 145 | border-radius: 2em; 146 | 147 | background-color: hsla(247.6190476190476, 42.28%, 29.22%, 1.00); 148 | 149 | box-shadow: none; 150 | 151 | transition: background-color 200ms ease,color 200ms ease; 152 | 153 | color: hsla(247.05882352941174, 0.00%, 100.00%, 1.00); 154 | font-size: 1.3rem; 155 | font-weight: 700; 156 | } 157 | 158 | .button:hover { 159 | background-color: hsla(196.55172413793105, 54.72%, 79.22%, 1.00); 160 | box-shadow: none; 161 | color: hsla(247.6190476190476, 42.28%, 29.22%, 1.00); 162 | } 163 | 164 | .button:focus { 165 | outline-color: var(--clrPrimary600-aeaf7110); 166 | outline-offset: 0.2rem; 167 | outline-style: solid; 168 | outline-width: 0.2rem; 169 | } 170 | 171 | .button:focus-visible { 172 | outline-color: var(--clrPrimary600-aeaf7110); 173 | outline-offset: 0.2rem; 174 | outline-style: solid; 175 | outline-width: 0.2rem; 176 | } 177 | 178 | .button.secondary { 179 | background-color: var(--clrSecondary400-685c3959); 180 | color: var(--clrPrimary600-aeaf7110); 181 | } 182 | 183 | .button.secondary:hover { 184 | background-color: var(--clrPrimary400-6c00fdf1); 185 | color: var(--clrNeutral100-f9191126); 186 | } 187 | 188 | .button.secondary:focus { 189 | outline-color: var(--clrSecondary400-685c3959); 190 | } 191 | 192 | .button.tertiary { 193 | background-color: var(--clrQuarternary400-68656429); 194 | color: var(--clrPrimary600-aeaf7110); 195 | } 196 | 197 | .button.tertiary:hover { 198 | background-color: var(--clrPrimary600-aeaf7110); 199 | color: var(--clrNeutral100-f9191126); 200 | } 201 | 202 | .button.tertiary:focus { 203 | outline-color: var(--clrQuarternary400-68656429); 204 | } 205 | 206 | .button.small { 207 | padding: 1em 1.5em; 208 | font-size: 1rem; 209 | } 210 | 211 | .button.sign-up { 212 | text-align: center; 213 | } 214 | 215 | .hero-image { 216 | width: 100%; 217 | height: 100%; 218 | object-fit: contain; 219 | } 220 | 221 | #w-node-eec4ca81-6ae6-a937-d67c-2a2debaf4e5f-ebaf4e5c { 222 | grid-column-start: span 1; 223 | grid-column-end: span 1; 224 | grid-row-start: span 1; 225 | grid-row-end: span 1; 226 | align-self: center; 227 | } 228 | #w-node-eec4ca81-6ae6-a937-d67c-2a2debaf4e6a-ebaf4e5c { 229 | grid-column-start: span 1; 230 | grid-column-end: span 1; 231 | grid-row-start: span 1; 232 | grid-row-end: span 1; 233 | } -------------------------------------------------------------------------------- /devlink/JobListing.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as Types from "./types"; 3 | 4 | declare function JobListing(props: { 5 | as?: React.ElementType; 6 | companyName?: React.ReactNode; 7 | listingName?: React.ReactNode; 8 | location?: React.ReactNode; 9 | applyText?: React.ReactNode; 10 | applyLink?: Types.Basic.Link; 11 | learnText?: React.ReactNode; 12 | learnLink?: Types.Basic.Link; 13 | }): React.JSX.Element; 14 | -------------------------------------------------------------------------------- /devlink/JobListing.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import * as _Builtin from "./_Builtin"; 3 | import * as _utils from "./utils"; 4 | import _styles from "./JobListing.module.css"; 5 | 6 | export function JobListing({ 7 | as: _Component = _Builtin.Block, 8 | companyName = "Company name", 9 | listingName = "This is some text inside of a div block.", 10 | location = "Location", 11 | applyText = "Apply now", 12 | 13 | applyLink = { 14 | href: "#", 15 | }, 16 | 17 | learnText = "Learn more", 18 | 19 | learnLink = { 20 | href: "#", 21 | }, 22 | }) { 23 | return ( 24 | <_Component className={_utils.cx(_styles, "job-listing")} tag="div"> 25 | <_Builtin.Block tag="div"> 26 | <_Builtin.Block tag="div">{companyName} 27 | <_Builtin.Block 28 | className={_utils.cx(_styles, "listing-name")} 29 | tag="div" 30 | > 31 | {listingName} 32 | 33 | <_Builtin.Block tag="div">{location} 34 | 35 | <_Builtin.Block 36 | className={_utils.cx(_styles, "buttons-wrapper")} 37 | id={_utils.cx( 38 | _styles, 39 | "w-node-_7f42fc01-bdea-9976-acc3-ac76a91ba330-a91ba328" 40 | )} 41 | tag="div" 42 | > 43 | <_Builtin.Link 44 | className={_utils.cx(_styles, "button", "small")} 45 | id={_utils.cx( 46 | _styles, 47 | "w-node-_7f42fc01-bdea-9976-acc3-ac76a91ba331-a91ba328" 48 | )} 49 | button={true} 50 | options={learnLink} 51 | > 52 | {learnText} 53 | 54 | <_Builtin.Link 55 | className={_utils.cx(_styles, "button", "small", "tertiary")} 56 | button={true} 57 | options={applyLink} 58 | > 59 | {applyText} 60 | 61 | 62 | 63 | ); 64 | } 65 | -------------------------------------------------------------------------------- /devlink/JobListing.module.css: -------------------------------------------------------------------------------- 1 | .job-listing { 2 | display: grid; 3 | margin-bottom: 2em; 4 | padding: 1.5em; 5 | flex-direction: column; 6 | grid-auto-columns: 1fr; 7 | grid-column-gap: 16px; 8 | grid-row-gap: 0.25em; 9 | grid-template-columns: 1fr 0.5fr; 10 | grid-template-rows: auto; 11 | 12 | border-radius: 1em; 13 | 14 | background-color: hsla(248.5714285714286, 74.84%, 68.82%, 0.15); 15 | 16 | color: var(--clrPrimary600-aeaf7110); 17 | } 18 | 19 | @media screen and (max-width: 991px) { 20 | .job-listing { 21 | grid-row-gap: 1em; 22 | grid-template-columns: 1fr; 23 | } 24 | } 25 | 26 | .listing-name { 27 | font-size: 1.5rem; 28 | font-weight: 700; 29 | } 30 | 31 | .buttons-wrapper { 32 | display: flex; 33 | grid-column-gap: 1em; 34 | } 35 | 36 | @media screen and (max-width: 479px) { 37 | .buttons-wrapper { 38 | flex-direction: column; 39 | grid-row-gap: 1em; 40 | } 41 | } 42 | 43 | .button { 44 | padding: 1em 2em; 45 | 46 | border-radius: 2em; 47 | 48 | background-color: hsla(247.6190476190476, 42.28%, 29.22%, 1.00); 49 | 50 | box-shadow: none; 51 | 52 | transition: background-color 200ms ease,color 200ms ease; 53 | 54 | color: hsla(247.05882352941174, 0.00%, 100.00%, 1.00); 55 | font-size: 1.3rem; 56 | font-weight: 700; 57 | } 58 | 59 | .button:hover { 60 | background-color: hsla(196.55172413793105, 54.72%, 79.22%, 1.00); 61 | box-shadow: none; 62 | color: hsla(247.6190476190476, 42.28%, 29.22%, 1.00); 63 | } 64 | 65 | .button:focus { 66 | outline-color: var(--clrPrimary600-aeaf7110); 67 | outline-offset: 0.2rem; 68 | outline-style: solid; 69 | outline-width: 0.2rem; 70 | } 71 | 72 | .button:focus-visible { 73 | outline-color: var(--clrPrimary600-aeaf7110); 74 | outline-offset: 0.2rem; 75 | outline-style: solid; 76 | outline-width: 0.2rem; 77 | } 78 | 79 | .button.secondary { 80 | background-color: var(--clrSecondary400-685c3959); 81 | color: var(--clrPrimary600-aeaf7110); 82 | } 83 | 84 | .button.secondary:hover { 85 | background-color: var(--clrPrimary400-6c00fdf1); 86 | color: var(--clrNeutral100-f9191126); 87 | } 88 | 89 | .button.secondary:focus { 90 | outline-color: var(--clrSecondary400-685c3959); 91 | } 92 | 93 | .button.tertiary { 94 | background-color: var(--clrQuarternary400-68656429); 95 | color: var(--clrPrimary600-aeaf7110); 96 | } 97 | 98 | .button.tertiary:hover { 99 | background-color: var(--clrPrimary600-aeaf7110); 100 | color: var(--clrNeutral100-f9191126); 101 | } 102 | 103 | .button.tertiary:focus { 104 | outline-color: var(--clrQuarternary400-68656429); 105 | } 106 | 107 | .button.small { 108 | padding: 1em 1.5em; 109 | font-size: 1rem; 110 | } 111 | 112 | .button.sign-up { 113 | text-align: center; 114 | } 115 | 116 | #w-node-_7f42fc01-bdea-9976-acc3-ac76a91ba330-a91ba328 { 117 | grid-column-start: span 1; 118 | grid-column-end: span 1; 119 | grid-row-start: span 1; 120 | grid-row-end: span 1; 121 | justify-self: end; 122 | align-self: center; 123 | } 124 | #w-node-_7f42fc01-bdea-9976-acc3-ac76a91ba331-a91ba328 { 125 | grid-column-start: span 1; 126 | grid-column-end: span 1; 127 | grid-row-start: span 1; 128 | grid-row-end: span 1; 129 | } 130 | @media screen and (max-width: 991px) { 131 | #w-node-_7f42fc01-bdea-9976-acc3-ac76a91ba330-a91ba328 { 132 | justify-self: start; 133 | } 134 | } -------------------------------------------------------------------------------- /devlink/Navbar.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as Types from "./types"; 3 | 4 | declare function Navbar(props: { 5 | as?: React.ElementType; 6 | homeText?: React.ReactNode; 7 | homeLink?: Types.Basic.Link; 8 | aboutText?: React.ReactNode; 9 | aboutLink?: Types.Basic.Link; 10 | jobsText?: React.ReactNode; 11 | jobsLink?: Types.Basic.Link; 12 | brandLink?: Types.Basic.Link; 13 | }): React.JSX.Element; 14 | -------------------------------------------------------------------------------- /devlink/Navbar.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import * as _Builtin from "./_Builtin"; 3 | import * as _utils from "./utils"; 4 | import _styles from "./Navbar.module.css"; 5 | 6 | export function Navbar({ 7 | as: _Component = _Builtin.NavbarWrapper, 8 | homeText = "Home", 9 | 10 | homeLink = { 11 | href: "#", 12 | }, 13 | 14 | aboutText = "About", 15 | 16 | aboutLink = { 17 | href: "#", 18 | }, 19 | 20 | jobsText = "Jobs", 21 | 22 | jobsLink = { 23 | href: "#", 24 | }, 25 | 26 | brandLink = { 27 | href: "#", 28 | }, 29 | }) { 30 | return ( 31 | <_Component 32 | className={_utils.cx(_styles, "navbar")} 33 | tag="div" 34 | config={{ 35 | animation: "default", 36 | collapse: "medium", 37 | docHeight: false, 38 | duration: 400, 39 | easing: "ease", 40 | easing2: "ease", 41 | noScroll: false, 42 | }} 43 | > 44 | <_Builtin.Block 45 | className={_utils.cx(_styles, "container", "nav")} 46 | tag="div" 47 | > 48 | <_Builtin.NavbarBrand 49 | className={_utils.cx(_styles, "brand")} 50 | options={brandLink} 51 | > 52 | <_Builtin.Image 53 | className={_utils.cx(_styles, "brand-image")} 54 | loading="lazy" 55 | width="auto" 56 | height="auto" 57 | src="https://uploads-ssl.webflow.com/644d71f7a83e2ea6946fafd7/644ea5920aef435a232ffdfc_Other%2021.png" 58 | /> 59 | 60 | <_Builtin.NavbarMenu 61 | className={_utils.cx(_styles, "navmenu")} 62 | tag="nav" 63 | role="navigation" 64 | > 65 | <_Builtin.NavbarLink 66 | className={_utils.cx(_styles, "navlink")} 67 | options={homeLink} 68 | > 69 | {homeText} 70 | 71 | <_Builtin.NavbarLink 72 | className={_utils.cx(_styles, "navlink")} 73 | options={aboutLink} 74 | > 75 | {aboutText} 76 | 77 | <_Builtin.NavbarLink 78 | className={_utils.cx(_styles, "navlink")} 79 | options={jobsLink} 80 | > 81 | {jobsText} 82 | 83 | <_Builtin.NavbarLink 84 | className={_utils.cx(_styles, "navlink", "nav-button")} 85 | options={{ 86 | href: "#", 87 | }} 88 | > 89 | {"Post a job"} 90 | 91 | 92 | <_Builtin.NavbarButton tag="div"> 93 | <_Builtin.Icon 94 | widget={{ 95 | type: "icon", 96 | icon: "nav-menu", 97 | }} 98 | /> 99 | 100 | 101 | 102 | ); 103 | } 104 | -------------------------------------------------------------------------------- /devlink/Navbar.module.css: -------------------------------------------------------------------------------- 1 | .navbar { 2 | padding-top: 1em; 3 | padding-bottom: 1em; 4 | background-color: var(--clrPrimary600-aeaf7110); 5 | color: var(--clrNeutral100-f9191126); 6 | } 7 | 8 | .container { 9 | width: 100%; 10 | max-width: 1200px; 11 | margin-right: auto; 12 | margin-left: auto; 13 | padding-right: 1em; 14 | padding-left: 1em; 15 | } 16 | 17 | @media screen and (max-width: 767px) { 18 | .container { 19 | padding-right: 1.5em; 20 | padding-left: 1.5em; 21 | } 22 | } 23 | 24 | .container.nav { 25 | display: flex; 26 | justify-content: space-between; 27 | align-items: center; 28 | } 29 | 30 | .container.narrow { 31 | max-width: 720px; 32 | } 33 | 34 | .container.rel { 35 | position: relative; 36 | z-index: 2; 37 | } 38 | 39 | .center { 40 | text-align: center; 41 | } 42 | 43 | .brand { 44 | font-family: 'Playfair Display'; 45 | color: var(--clrNeutral100-f9191126); 46 | font-size: 2rem; 47 | font-weight: 700; 48 | } 49 | 50 | .brand:focus { 51 | border-radius: 0.3em; 52 | outline-color: var(--clrNeutral100-f9191126); 53 | outline-offset: 0.3rem; 54 | outline-style: solid; 55 | outline-width: 0.2rem; 56 | } 57 | 58 | .brand-image { 59 | width: 120px; 60 | height: 93px; 61 | } 62 | 63 | .navmenu { 64 | display: flex; 65 | justify-content: flex-end; 66 | } 67 | 68 | @media screen and (max-width: 991px) { 69 | .navmenu { 70 | padding: 2rem; 71 | background-color: var(--clrPrimary600-aeaf7110); 72 | } 73 | } 74 | 75 | @media screen and (max-width: 767px) { 76 | .navmenu { 77 | flex-direction: column; 78 | align-items: center; 79 | } 80 | } 81 | 82 | .navlink { 83 | padding: 1em 0.5em; 84 | 85 | box-shadow: inset 0 0 0 0 var(--clrSecondary400-685c3959); 86 | 87 | transition: color 200ms ease,box-shadow 200ms ease; 88 | 89 | color: var(--clrNeutral100-f9191126); 90 | font-size: 1.2rem; 91 | font-weight: 600; 92 | } 93 | 94 | .navlink:hover { 95 | box-shadow: inset 0 -5px 0 0 var(--clrSecondary400-685c3959); 96 | color: var(--clrSecondary400-685c3959); 97 | } 98 | 99 | .navlink:focus { 100 | border-radius: 0em; 101 | outline-color: var(--clrNeutral100-f9191126); 102 | outline-offset: 0.3rem; 103 | outline-style: solid; 104 | outline-width: 0.2rem; 105 | } 106 | 107 | .navlink:focus-visible { 108 | outline-color: var(--clrNeutral100-f9191126); 109 | outline-offset: 0.3rem; 110 | outline-style: solid; 111 | outline-width: 0.2rem; 112 | } 113 | 114 | .navlink:global(.w--current) { 115 | color: var(--clrNeutral100-f9191126); 116 | } 117 | 118 | .navlink:global(.w--current):hover { 119 | color: var(--clrSecondary400-685c3959); 120 | } 121 | 122 | @media screen and (max-width: 767px) { 123 | .navlink { 124 | text-align: center; 125 | } 126 | } 127 | 128 | .navlink.nav-button { 129 | padding-right: 2em; 130 | padding-left: 2em; 131 | 132 | border-radius: 2em; 133 | 134 | background-color: var(--clrQuarternary400-68656429); 135 | 136 | box-shadow: none; 137 | 138 | transition-property: none; 139 | 140 | color: var(--clrPrimary600-aeaf7110); 141 | } 142 | 143 | .navlink.nav-button:hover { 144 | background-color: var(--clrSecondary400-685c3959); 145 | color: var(--clrPrimary600-aeaf7110); 146 | } 147 | 148 | .navlink.nav-button:focus { 149 | outline-color: var(--clrQuarternary400-68656429); 150 | } -------------------------------------------------------------------------------- /devlink/Newnav.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as Types from "./types"; 3 | 4 | declare function Newnav(props: { 5 | as?: React.ElementType; 6 | brandLink?: Types.Basic.Link; 7 | homeText?: React.ReactNode; 8 | homeLink?: Types.Basic.Link; 9 | aboutText?: React.ReactNode; 10 | aboutLink?: Types.Basic.Link; 11 | jobsText?: React.ReactNode; 12 | jobsLink?: Types.Basic.Link; 13 | postText?: React.ReactNode; 14 | postLink?: Types.Basic.Link; 15 | postJob?: Types.Devlink.RuntimeProps; 16 | }): React.JSX.Element; 17 | -------------------------------------------------------------------------------- /devlink/Newnav.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import * as _Builtin from "./_Builtin"; 3 | import * as _utils from "./utils"; 4 | import _styles from "./Newnav.module.css"; 5 | 6 | export function Newnav({ 7 | as: _Component = _Builtin.NavbarWrapper, 8 | 9 | brandLink = { 10 | href: "#", 11 | }, 12 | 13 | homeText = "Home", 14 | 15 | homeLink = { 16 | href: "#", 17 | }, 18 | 19 | aboutText = "About", 20 | 21 | aboutLink = { 22 | href: "#", 23 | }, 24 | 25 | jobsText = "Jobs", 26 | 27 | jobsLink = { 28 | href: "#", 29 | }, 30 | 31 | postText = "Post a job", 32 | 33 | postLink = { 34 | href: "#", 35 | }, 36 | 37 | postJob = {}, 38 | }) { 39 | return ( 40 | <_Component 41 | className={_utils.cx(_styles, "navbar")} 42 | tag="div" 43 | config={{ 44 | animation: "default", 45 | collapse: "medium", 46 | docHeight: false, 47 | duration: 400, 48 | easing: "ease", 49 | easing2: "ease", 50 | noScroll: false, 51 | }} 52 | > 53 | <_Builtin.Block 54 | className={_utils.cx(_styles, "container", "nav")} 55 | tag="div" 56 | > 57 | <_Builtin.NavbarBrand 58 | className={_utils.cx(_styles, "brand")} 59 | options={brandLink} 60 | > 61 | <_Builtin.Image 62 | className={_utils.cx(_styles, "brand-image")} 63 | loading="lazy" 64 | width="auto" 65 | height="auto" 66 | src="https://uploads-ssl.webflow.com/644d71f7a83e2ea6946fafd7/644ea5920aef435a232ffdfc_Other%2021.png" 67 | /> 68 | 69 | <_Builtin.NavbarMenu 70 | className={_utils.cx(_styles, "navmenu")} 71 | tag="nav" 72 | role="navigation" 73 | > 74 | <_Builtin.List 75 | className={_utils.cx(_styles, "navlist")} 76 | tag="ul" 77 | unstyled={false} 78 | > 79 | <_Builtin.ListItem className={_utils.cx(_styles, "navlist-item")}> 80 | <_Builtin.NavbarLink 81 | className={_utils.cx(_styles, "navlink")} 82 | options={homeLink} 83 | > 84 | {homeText} 85 | 86 | 87 | <_Builtin.ListItem className={_utils.cx(_styles, "navlist-item")}> 88 | <_Builtin.NavbarLink 89 | className={_utils.cx(_styles, "navlink")} 90 | options={aboutLink} 91 | > 92 | {aboutText} 93 | 94 | 95 | <_Builtin.ListItem className={_utils.cx(_styles, "navlist-item")}> 96 | <_Builtin.NavbarLink 97 | className={_utils.cx(_styles, "navlink")} 98 | options={jobsLink} 99 | > 100 | {jobsText} 101 | 102 | 103 | <_Builtin.ListItem className={_utils.cx(_styles, "navlist-item")}> 104 | <_Builtin.NavbarLink 105 | className={_utils.cx(_styles, "navlink", "nav-button")} 106 | options={postLink} 107 | {...postJob} 108 | > 109 | {postText} 110 | 111 | 112 | 113 | 114 | <_Builtin.NavbarButton 115 | className={_utils.cx(_styles, "hamburger")} 116 | tag="div" 117 | > 118 | <_Builtin.Icon 119 | widget={{ 120 | type: "icon", 121 | icon: "nav-menu", 122 | }} 123 | /> 124 | 125 | 126 | 127 | ); 128 | } 129 | -------------------------------------------------------------------------------- /devlink/Newnav.module.css: -------------------------------------------------------------------------------- 1 | .navbar { 2 | padding-top: 1em; 3 | padding-bottom: 1em; 4 | background-color: var(--clrPrimary600-aeaf7110); 5 | color: var(--clrNeutral100-f9191126); 6 | } 7 | 8 | .container { 9 | width: 100%; 10 | max-width: 1200px; 11 | margin-right: auto; 12 | margin-left: auto; 13 | padding-right: 1em; 14 | padding-left: 1em; 15 | } 16 | 17 | @media screen and (max-width: 767px) { 18 | .container { 19 | padding-right: 1.5em; 20 | padding-left: 1.5em; 21 | } 22 | } 23 | 24 | .container.nav { 25 | display: flex; 26 | justify-content: space-between; 27 | align-items: center; 28 | } 29 | 30 | .container.narrow { 31 | max-width: 720px; 32 | } 33 | 34 | .container.rel { 35 | position: relative; 36 | z-index: 2; 37 | } 38 | 39 | .center { 40 | text-align: center; 41 | } 42 | 43 | .brand { 44 | font-family: 'Playfair Display'; 45 | color: var(--clrNeutral100-f9191126); 46 | font-size: 2rem; 47 | font-weight: 700; 48 | } 49 | 50 | .brand:focus { 51 | border-radius: 0.3em; 52 | outline-color: var(--clrNeutral100-f9191126); 53 | outline-offset: 0.3rem; 54 | outline-style: solid; 55 | outline-width: 0.2rem; 56 | } 57 | 58 | .brand-image { 59 | width: 120px; 60 | height: 93px; 61 | } 62 | 63 | .navmenu { 64 | display: flex; 65 | justify-content: flex-end; 66 | } 67 | 68 | @media screen and (max-width: 991px) { 69 | .navmenu { 70 | padding: 2rem; 71 | background-color: var(--clrPrimary600-aeaf7110); 72 | } 73 | } 74 | 75 | @media screen and (max-width: 767px) { 76 | .navmenu { 77 | flex-direction: column; 78 | align-items: center; 79 | } 80 | } 81 | 82 | .navlist { 83 | display: flex; 84 | margin-top: 0px; 85 | margin-bottom: 0px; 86 | padding-left: 0px; 87 | grid-column-gap: 1em; 88 | 89 | list-style-type: none; 90 | } 91 | 92 | @media screen and (max-width: 991px) { 93 | .navlist { 94 | flex-direction: column; 95 | align-items: center; 96 | } 97 | } 98 | 99 | .navlist-item { 100 | margin-bottom: 0em; 101 | } 102 | 103 | .navlink { 104 | padding: 1em 0.5em; 105 | 106 | box-shadow: inset 0 0 0 0 var(--clrSecondary400-685c3959); 107 | 108 | transition: color 200ms ease,box-shadow 200ms ease; 109 | 110 | color: var(--clrNeutral100-f9191126); 111 | font-size: 1.2rem; 112 | font-weight: 600; 113 | } 114 | 115 | .navlink:hover { 116 | box-shadow: inset 0 -5px 0 0 var(--clrSecondary400-685c3959); 117 | color: var(--clrSecondary400-685c3959); 118 | } 119 | 120 | .navlink:focus { 121 | border-radius: 0em; 122 | outline-color: var(--clrNeutral100-f9191126); 123 | outline-offset: 0.3rem; 124 | outline-style: solid; 125 | outline-width: 0.2rem; 126 | } 127 | 128 | .navlink:focus-visible { 129 | outline-color: var(--clrNeutral100-f9191126); 130 | outline-offset: 0.3rem; 131 | outline-style: solid; 132 | outline-width: 0.2rem; 133 | } 134 | 135 | .navlink:global(.w--current) { 136 | color: var(--clrNeutral100-f9191126); 137 | } 138 | 139 | .navlink:global(.w--current):hover { 140 | color: var(--clrSecondary400-685c3959); 141 | } 142 | 143 | @media screen and (max-width: 767px) { 144 | .navlink { 145 | text-align: center; 146 | } 147 | } 148 | 149 | .navlink.nav-button { 150 | padding-right: 2em; 151 | padding-left: 2em; 152 | 153 | border-radius: 2em; 154 | 155 | background-color: var(--clrQuarternary400-68656429); 156 | 157 | box-shadow: none; 158 | 159 | transition-property: none; 160 | 161 | color: var(--clrPrimary600-aeaf7110); 162 | } 163 | 164 | .navlink.nav-button:hover { 165 | background-color: var(--clrSecondary400-685c3959); 166 | color: var(--clrPrimary600-aeaf7110); 167 | } 168 | 169 | .navlink.nav-button:focus { 170 | outline-color: var(--clrQuarternary400-68656429); 171 | } 172 | 173 | @media screen and (max-width: 991px) { 174 | .hamburger { 175 | background-color: var(--clrPrimary600-aeaf7110); 176 | font-size: 2.5rem; 177 | } 178 | } 179 | 180 | @media screen and (max-width: 991px) { 181 | .hamburger:global(.w--open) { 182 | background-color: var(--clrPrimary400-6c00fdf1); 183 | color: var(--clrPrimary600-aeaf7110); 184 | } 185 | } -------------------------------------------------------------------------------- /devlink/PageHeading.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as Types from "./types"; 3 | 4 | declare function PageHeading(props: { 5 | as?: React.ElementType; 6 | headingText?: React.ReactNode; 7 | }): React.JSX.Element; 8 | -------------------------------------------------------------------------------- /devlink/PageHeading.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import * as _Builtin from "./_Builtin"; 3 | import * as _utils from "./utils"; 4 | import _styles from "./PageHeading.module.css"; 5 | 6 | export function PageHeading({ 7 | as: _Component = _Builtin.Section, 8 | headingText = "Heading", 9 | }) { 10 | return ( 11 | <_Component className={_utils.cx(_styles, "section", "title")} tag="div"> 12 | <_Builtin.Container className={_utils.cx(_styles, "container")} tag="div"> 13 | <_Builtin.Heading 14 | className={_utils.cx(_styles, "title-heading")} 15 | tag="h1" 16 | > 17 | {headingText} 18 | 19 | 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /devlink/PageHeading.module.css: -------------------------------------------------------------------------------- 1 | .section { 2 | padding-top: 5em; 3 | padding-bottom: 5em; 4 | } 5 | 6 | .section.hero { 7 | position: relative; 8 | min-height: 600px; 9 | background-color: var(--clrPrimary600-aeaf7110); 10 | color: var(--clrNeutral100-f9191126); 11 | } 12 | 13 | .section.title { 14 | background-color: var(--clrPrimary400-6c00fdf1); 15 | color: var(--clrPrimary999-b0a60ce1); 16 | } 17 | 18 | .section.pricing-gradient { 19 | background-image: radial-gradient(circle farthest-corner at 50% 100%, var(--clrPrimary400-6c00fdf1), var(--clrPrimary999-b0a60ce1) 73%); 20 | color: var(--clrNeutral100-f9191126); 21 | } 22 | 23 | .section.pricing { 24 | position: relative; 25 | padding-top: 5em; 26 | color: hsla(329.9999999999999, 0.00%, 100.00%, 1.00); 27 | text-align: center; 28 | } 29 | 30 | .clr-secondary-400 { 31 | background-color: var(--clrSecondary400-685c3959); 32 | } 33 | 34 | .clr-primary-400 { 35 | background-color: var(--clrPrimary400-6c00fdf1); 36 | } 37 | 38 | .section.features { 39 | color: var(--clrPrimary600-aeaf7110); 40 | } 41 | 42 | .container { 43 | width: 100%; 44 | max-width: 1200px; 45 | margin-right: auto; 46 | margin-left: auto; 47 | padding-right: 1em; 48 | padding-left: 1em; 49 | } 50 | 51 | @media screen and (max-width: 767px) { 52 | .container { 53 | padding-right: 1.5em; 54 | padding-left: 1.5em; 55 | } 56 | } 57 | 58 | .container.nav { 59 | display: flex; 60 | justify-content: space-between; 61 | align-items: center; 62 | } 63 | 64 | .container.narrow { 65 | max-width: 720px; 66 | } 67 | 68 | .container.rel { 69 | position: relative; 70 | z-index: 2; 71 | } 72 | 73 | .center { 74 | text-align: center; 75 | } -------------------------------------------------------------------------------- /devlink/Pricing.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as Types from "./types"; 3 | 4 | declare function Pricing(props: { 5 | as?: React.ElementType; 6 | employerPrice?: React.ReactNode; 7 | pricingBottom?: Types.Devlink.Slot; 8 | applicantPricing?: React.ReactNode; 9 | }): React.JSX.Element; 10 | -------------------------------------------------------------------------------- /devlink/Pricing.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import * as _Builtin from "./_Builtin"; 3 | import * as _interactions from "./interactions"; 4 | import * as _utils from "./utils"; 5 | import _styles from "./Pricing.module.css"; 6 | 7 | const _interactionsData = JSON.parse( 8 | '{"events":{"e":{"id":"e","name":"","animationType":"preset","eventTypeId":"SCROLL_INTO_VIEW","action":{"id":"","actionTypeId":"SLIDE_EFFECT","instant":false,"config":{"actionListId":"slideInBottom","autoStopEventId":"e-2"}},"mediaQueries":["main","medium","small","tiny"],"target":{"id":"3fb202a6-7504-b84c-fbff-e674556ba402","appliesTo":"ELEMENT","styleBlockIds":[]},"targets":[{"id":"3fb202a6-7504-b84c-fbff-e674556ba402","appliesTo":"ELEMENT","styleBlockIds":[]}],"config":{"loop":false,"playInReverse":false,"scrollOffsetValue":35,"scrollOffsetUnit":"%","delay":0,"direction":"BOTTOM","effectIn":true},"createdOn":1684527451652}},"actionLists":{"slideInBottom":{"id":"slideInBottom","useFirstGroupAsInitialState":true,"actionItemGroups":[{"actionItems":[{"actionTypeId":"STYLE_OPACITY","config":{"delay":0,"duration":0,"target":{"id":"N/A","appliesTo":"TRIGGER_ELEMENT","useEventTarget":true},"value":0}}]},{"actionItems":[{"actionTypeId":"TRANSFORM_MOVE","config":{"delay":0,"duration":0,"target":{"id":"N/A","appliesTo":"TRIGGER_ELEMENT","useEventTarget":true},"xValue":0,"yValue":100,"xUnit":"PX","yUnit":"PX","zUnit":"PX"}}]},{"actionItems":[{"actionTypeId":"TRANSFORM_MOVE","config":{"delay":0,"easing":"outQuart","duration":1000,"target":{"id":"N/A","appliesTo":"TRIGGER_ELEMENT","useEventTarget":true},"xValue":0,"yValue":0,"xUnit":"PX","yUnit":"PX","zUnit":"PX"}},{"actionTypeId":"STYLE_OPACITY","config":{"delay":0,"easing":"outQuart","duration":1000,"target":{"id":"N/A","appliesTo":"TRIGGER_ELEMENT","useEventTarget":true},"value":1}}]}]}},"site":{"mediaQueries":[{"key":"main","min":992,"max":10000},{"key":"medium","min":768,"max":991},{"key":"small","min":480,"max":767},{"key":"tiny","min":0,"max":479}]}}' 9 | ); 10 | 11 | export function Pricing({ 12 | as: _Component = _Builtin.Section, 13 | employerPrice = "$99", 14 | pricingBottom, 15 | applicantPricing = "$9", 16 | }) { 17 | _interactions.useInteractions(_interactionsData, _styles); 18 | 19 | return ( 20 | <_Component 21 | className={_utils.cx(_styles, "section", "pricing")} 22 | tag="section" 23 | > 24 | <_Builtin.Block 25 | className={_utils.cx(_styles, "radial-gradient")} 26 | tag="div" 27 | /> 28 | <_Builtin.Container 29 | className={_utils.cx(_styles, "container", "rel")} 30 | tag="div" 31 | > 32 | <_Builtin.Heading tag="h2"> 33 | {"Find the right price for you"} 34 | 35 | <_Builtin.Paragraph className={_utils.cx(_styles, "mw-70ch")}> 36 | { 37 | "Explore our flexible pricing options designed to meet the diverse needs of both job seekers and employers. Unlock the full potential of the Visual Developers Job Board and invest in your future success with our affordable and value-driven plans." 38 | } 39 | 40 | 41 | <_Builtin.Container 42 | className={_utils.cx(_styles, "container", "rel")} 43 | tag="div" 44 | > 45 | <_Builtin.Block 46 | className={_utils.cx(_styles, "two-columns", "narrow")} 47 | tag="div" 48 | > 49 | <_Builtin.Block 50 | className={_utils.cx(_styles, "pricing-card-large")} 51 | id={_utils.cx( 52 | _styles, 53 | "w-node-_3fb202a6-7504-b84c-fbff-e674556ba3c8-556ba3bf" 54 | )} 55 | tag="div" 56 | > 57 | <_Builtin.Block 58 | className={_utils.cx(_styles, "pricing-tag")} 59 | tag="div" 60 | > 61 | {"Employers"} 62 | 63 | <_Builtin.Block 64 | className={_utils.cx(_styles, "price-text-wrapper")} 65 | tag="div" 66 | > 67 | <_Builtin.Block className={_utils.cx(_styles, "price")} tag="div"> 68 | {employerPrice} 69 | 70 | <_Builtin.Block tag="div">{"/month"} 71 | 72 | <_Builtin.Paragraph className={_utils.cx(_styles, "p-small")}> 73 | { 74 | "Our Employers Plan is tailored to provide maximum visibility and engagement for your job listings, ensuring you reach the most talented and qualified candidates in the development community." 75 | } 76 | 77 | <_Builtin.List 78 | className={_utils.cx(_styles, "pricing-list")} 79 | tag="ul" 80 | unstyled={false} 81 | > 82 | <_Builtin.ListItem> 83 | { 84 | "Priority placement of your job listings, resulting in increased visibility" 85 | } 86 | 87 | <_Builtin.ListItem> 88 | {"Customizable job posts with your company logo and branding"} 89 | 90 | <_Builtin.ListItem> 91 | { 92 | "Access to our curated pool of highly skilled Webflow, no-code, and traditional developers" 93 | } 94 | 95 | <_Builtin.ListItem> 96 | { 97 | "Analytics dashboard to track the performance of your job listings" 98 | } 99 | 100 | <_Builtin.ListItem> 101 | { 102 | "Dedicated account manager for personalized support and guidance" 103 | } 104 | 105 | <_Builtin.ListItem> 106 | { 107 | "Social media promotion of your job posts to extend your reach" 108 | } 109 | 110 | <_Builtin.ListItem> 111 | {"Unlimited job edits and updates during the listing period"} 112 | 113 | <_Builtin.ListItem> 114 | {"Discounted bulk pricing for multiple job listings"} 115 | 116 | 117 | <_Builtin.Link 118 | className={_utils.cx(_styles, "button", "sign-up")} 119 | button={true} 120 | options={{ 121 | href: "#", 122 | }} 123 | > 124 | {"Sign up"} 125 | 126 | 127 | <_Builtin.Block 128 | className={_utils.cx(_styles, "pricing-card-large")} 129 | id={_utils.cx( 130 | _styles, 131 | "w-node-_3fb202a6-7504-b84c-fbff-e674556ba3e5-556ba3bf" 132 | )} 133 | tag="div" 134 | > 135 | <_Builtin.Block 136 | className={_utils.cx(_styles, "pricing-tag")} 137 | tag="div" 138 | > 139 | {"Applicants"} 140 | 141 | <_Builtin.Block 142 | className={_utils.cx(_styles, "price-text-wrapper")} 143 | tag="div" 144 | > 145 | <_Builtin.Block className={_utils.cx(_styles, "price")} tag="div"> 146 | {applicantPricing} 147 | 148 | <_Builtin.Block tag="div">{"/month"} 149 | 150 | <_Builtin.Paragraph className={_utils.cx(_styles, "p-small")}> 151 | { 152 | "Our Applicants Plan is designed to give you a competitive edge in your job search, connecting you with exclusive opportunities and resources to accelerate your career in development." 153 | } 154 | 155 | <_Builtin.List 156 | className={_utils.cx(_styles, "pricing-list")} 157 | tag="ul" 158 | unstyled={false} 159 | > 160 | <_Builtin.ListItem> 161 | { 162 | "Early access to the latest job listings before they're publicly available" 163 | } 164 | 165 | <_Builtin.ListItem> 166 | { 167 | "Personalized job recommendations based on your skills and preferences" 168 | } 169 | 170 | <_Builtin.ListItem> 171 | { 172 | "Access to a library of resources, including tutorials, articles, and webinars to enhance your skills" 173 | } 174 | 175 | <_Builtin.ListItem> 176 | { 177 | "Profile optimization tips to help you stand out from the crowd" 178 | } 179 | 180 | <_Builtin.ListItem> 181 | { 182 | "Customizable job alerts to ensure you never miss a relevant opportunity" 183 | } 184 | 185 | <_Builtin.ListItem> 186 | { 187 | "Networking opportunities with fellow developers and industry professionals" 188 | } 189 | 190 | <_Builtin.ListItem> 191 | { 192 | "Priority support from our dedicated team to assist with your job search" 193 | } 194 | 195 | <_Builtin.ListItem> 196 | { 197 | "Exclusive discounts on relevant tools, courses, and events to support your professional growth" 198 | } 199 | 200 | 201 | <_Builtin.Link 202 | className={_utils.cx(_styles, "button", "sign-up")} 203 | button={true} 204 | options={{ 205 | href: "#", 206 | }} 207 | > 208 | {"Sign up"} 209 | 210 | 211 | 212 | <_Builtin.Block 213 | className={_utils.cx(_styles, "pricing-bottom")} 214 | data-w-id="3fb202a6-7504-b84c-fbff-e674556ba402" 215 | tag="div" 216 | > 217 | {pricingBottom} 218 | 219 | 220 | 221 | ); 222 | } 223 | -------------------------------------------------------------------------------- /devlink/Pricing.module.css: -------------------------------------------------------------------------------- 1 | .section { 2 | padding-top: 5em; 3 | padding-bottom: 5em; 4 | } 5 | 6 | .section.hero { 7 | position: relative; 8 | min-height: 600px; 9 | background-color: var(--clrPrimary600-aeaf7110); 10 | color: var(--clrNeutral100-f9191126); 11 | } 12 | 13 | .section.title { 14 | background-color: var(--clrPrimary400-6c00fdf1); 15 | color: var(--clrPrimary999-b0a60ce1); 16 | } 17 | 18 | .section.pricing-gradient { 19 | background-image: radial-gradient(circle farthest-corner at 50% 100%, var(--clrPrimary400-6c00fdf1), var(--clrPrimary999-b0a60ce1) 73%); 20 | color: var(--clrNeutral100-f9191126); 21 | } 22 | 23 | .section.pricing { 24 | position: relative; 25 | padding-top: 5em; 26 | color: hsla(329.9999999999999, 0.00%, 100.00%, 1.00); 27 | text-align: center; 28 | } 29 | 30 | .clr-secondary-400 { 31 | background-color: var(--clrSecondary400-685c3959); 32 | } 33 | 34 | .clr-primary-400 { 35 | background-color: var(--clrPrimary400-6c00fdf1); 36 | } 37 | 38 | .section.features { 39 | color: var(--clrPrimary600-aeaf7110); 40 | } 41 | 42 | .radial-gradient { 43 | position: absolute; 44 | left: 0%; 45 | top: 0%; 46 | right: 0%; 47 | bottom: 0%; 48 | z-index: 0; 49 | 50 | height: 60%; 51 | padding-top: 5em; 52 | 53 | background-image: radial-gradient(circle farthest-side at 50% 140%, var(--clrPrimary400-6c00fdf1), var(--clrPrimary600-aeaf7110) 59%, var(--clrPrimary999-b0a60ce1)); 54 | 55 | color: var(--clrNeutral100-f9191126); 56 | text-align: center; 57 | } 58 | 59 | .container { 60 | width: 100%; 61 | max-width: 1200px; 62 | margin-right: auto; 63 | margin-left: auto; 64 | padding-right: 1em; 65 | padding-left: 1em; 66 | } 67 | 68 | @media screen and (max-width: 767px) { 69 | .container { 70 | padding-right: 1.5em; 71 | padding-left: 1.5em; 72 | } 73 | } 74 | 75 | .container.nav { 76 | display: flex; 77 | justify-content: space-between; 78 | align-items: center; 79 | } 80 | 81 | .container.narrow { 82 | max-width: 720px; 83 | } 84 | 85 | .container.rel { 86 | position: relative; 87 | z-index: 2; 88 | } 89 | 90 | .center { 91 | text-align: center; 92 | } 93 | 94 | .mw-70ch { 95 | max-width: 70ch; 96 | margin-right: auto; 97 | margin-left: auto; 98 | } 99 | 100 | .mb2 { 101 | margin-bottom: 2rem; 102 | } 103 | 104 | .two-columns { 105 | display: grid; 106 | padding-left: 0px; 107 | grid-auto-columns: 1fr; 108 | grid-column-gap: 1.5rem; 109 | grid-row-gap: 1.5rem; 110 | grid-template-columns: 1fr 1fr; 111 | grid-template-rows: auto; 112 | } 113 | 114 | @media screen and (max-width: 767px) { 115 | .two-columns { 116 | grid-template-columns: 1fr; 117 | } 118 | } 119 | 120 | .two-columns.narrow { 121 | max-width: 960px; 122 | margin: 3em auto; 123 | } 124 | 125 | .pricing-card-large { 126 | display: flex; 127 | padding: 2em; 128 | flex-direction: column; 129 | grid-row-gap: 1em; 130 | 131 | border-radius: 2em; 132 | 133 | background-color: hsla(210, 0.00%, 100.00%, 1.00); 134 | 135 | box-shadow: 0 1px 11px 5px hsla(243.75, 43.24%, 14.51%, 0.32); 136 | 137 | color: var(--clrNeutral900-23d5b0c0); 138 | text-align: left; 139 | } 140 | 141 | @media screen and (max-width: 767px) { 142 | .pricing-card-large { 143 | margin-top: 0em; 144 | } 145 | } 146 | 147 | .pricing-tag { 148 | color: var(--clrPrimary600-aeaf7110); 149 | font-weight: 600; 150 | } 151 | 152 | .price-text-wrapper { 153 | display: flex; 154 | align-items: flex-end; 155 | } 156 | 157 | .price { 158 | font-size: 3rem; 159 | line-height: 1; 160 | font-weight: 700; 161 | } 162 | 163 | .p-small { 164 | font-size: 1rem; 165 | } 166 | 167 | .pricing-list { 168 | font-size: 0.9rem; 169 | } 170 | 171 | .button { 172 | padding: 1em 2em; 173 | 174 | border-radius: 2em; 175 | 176 | background-color: hsla(247.6190476190476, 42.28%, 29.22%, 1.00); 177 | 178 | box-shadow: none; 179 | 180 | transition: background-color 200ms ease,color 200ms ease; 181 | 182 | color: hsla(247.05882352941174, 0.00%, 100.00%, 1.00); 183 | font-size: 1.3rem; 184 | font-weight: 700; 185 | } 186 | 187 | .button:hover { 188 | background-color: hsla(196.55172413793105, 54.72%, 79.22%, 1.00); 189 | box-shadow: none; 190 | color: hsla(247.6190476190476, 42.28%, 29.22%, 1.00); 191 | } 192 | 193 | .button:focus { 194 | outline-color: var(--clrPrimary600-aeaf7110); 195 | outline-offset: 0.2rem; 196 | outline-style: solid; 197 | outline-width: 0.2rem; 198 | } 199 | 200 | .button:focus-visible { 201 | outline-color: var(--clrPrimary600-aeaf7110); 202 | outline-offset: 0.2rem; 203 | outline-style: solid; 204 | outline-width: 0.2rem; 205 | } 206 | 207 | .button.secondary { 208 | background-color: var(--clrSecondary400-685c3959); 209 | color: var(--clrPrimary600-aeaf7110); 210 | } 211 | 212 | .button.secondary:hover { 213 | background-color: var(--clrPrimary400-6c00fdf1); 214 | color: var(--clrNeutral100-f9191126); 215 | } 216 | 217 | .button.secondary:focus { 218 | outline-color: var(--clrSecondary400-685c3959); 219 | } 220 | 221 | .button.tertiary { 222 | background-color: var(--clrQuarternary400-68656429); 223 | color: var(--clrPrimary600-aeaf7110); 224 | } 225 | 226 | .button.tertiary:hover { 227 | background-color: var(--clrPrimary600-aeaf7110); 228 | color: var(--clrNeutral100-f9191126); 229 | } 230 | 231 | .button.tertiary:focus { 232 | outline-color: var(--clrQuarternary400-68656429); 233 | } 234 | 235 | .button.small { 236 | padding: 1em 1.5em; 237 | font-size: 1rem; 238 | } 239 | 240 | .button.sign-up { 241 | text-align: center; 242 | } 243 | 244 | .pricing-bottom { 245 | max-width: 960px; 246 | margin-right: auto; 247 | margin-left: auto; 248 | padding: 2em; 249 | 250 | border: 1px solid var(--clrNuetral500-69afe2ca); 251 | border-radius: 2em; 252 | } 253 | 254 | #w-node-_3fb202a6-7504-b84c-fbff-e674556ba3c8-556ba3bf { 255 | grid-column-start: span 1; 256 | grid-column-end: span 1; 257 | grid-row-start: span 1; 258 | grid-row-end: span 1; 259 | } 260 | #w-node-_3fb202a6-7504-b84c-fbff-e674556ba3e5-556ba3bf { 261 | grid-column-start: span 1; 262 | grid-column-end: span 1; 263 | grid-row-start: span 1; 264 | grid-row-end: span 1; 265 | } -------------------------------------------------------------------------------- /devlink/PricingGrid.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as Types from "./types"; 3 | 4 | declare function PricingGrid(props: { 5 | as?: React.ElementType; 6 | pricingHeading?: React.ReactNode; 7 | }): React.JSX.Element; 8 | -------------------------------------------------------------------------------- /devlink/PricingGrid.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import * as _Builtin from "./_Builtin"; 3 | import * as _utils from "./utils"; 4 | import _styles from "./PricingGrid.module.css"; 5 | 6 | export function PricingGrid({ 7 | as: _Component = _Builtin.Block, 8 | pricingHeading = "Student plans", 9 | }) { 10 | return ( 11 | <_Component className={_utils.cx(_styles, "pricing-bottom-grid")} tag="div"> 12 | <_Builtin.Block 13 | id={_utils.cx( 14 | _styles, 15 | "w-node-_05a0cdfd-5b52-43c7-186d-fe226e527f86-6e527f85" 16 | )} 17 | tag="div" 18 | > 19 | <_Builtin.Heading tag="h3">{pricingHeading} 20 | <_Builtin.Paragraph className={_utils.cx(_styles, "p-small")}> 21 | { 22 | "Discover our Student Plan, specially designed to support the next generation of developers by providing exclusive resources, opportunities, and discounts tailored to your educational journey." 23 | } 24 | 25 | 26 | <_Builtin.Block 27 | id={_utils.cx( 28 | _styles, 29 | "w-node-_05a0cdfd-5b52-43c7-186d-fe226e527f8b-6e527f85" 30 | )} 31 | tag="div" 32 | > 33 | <_Builtin.Link 34 | className={_utils.cx(_styles, "button", "tertiary")} 35 | button={true} 36 | options={{ 37 | href: "#", 38 | }} 39 | > 40 | {"Get started"} 41 | 42 | 43 | 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /devlink/PricingGrid.module.css: -------------------------------------------------------------------------------- 1 | .pricing-bottom-grid { 2 | display: grid; 3 | padding-left: 0px; 4 | grid-auto-columns: 1fr; 5 | grid-column-gap: 1.5rem; 6 | grid-row-gap: 1.5rem; 7 | grid-template-columns: 1.75fr 1fr; 8 | grid-template-rows: auto; 9 | 10 | color: var(--clrNeutral900-23d5b0c0); 11 | text-align: left; 12 | } 13 | 14 | @media screen and (max-width: 767px) { 15 | .pricing-bottom-grid { 16 | grid-template-columns: 1fr; 17 | } 18 | } 19 | 20 | .pricing-bottom-grid.narrow { 21 | max-width: 960px; 22 | margin: 3em auto; 23 | } 24 | 25 | .p-small { 26 | font-size: 1rem; 27 | } 28 | 29 | .button { 30 | padding: 1em 2em; 31 | 32 | border-radius: 2em; 33 | 34 | background-color: hsla(247.6190476190476, 42.28%, 29.22%, 1.00); 35 | 36 | box-shadow: none; 37 | 38 | transition: background-color 200ms ease,color 200ms ease; 39 | 40 | color: hsla(247.05882352941174, 0.00%, 100.00%, 1.00); 41 | font-size: 1.3rem; 42 | font-weight: 700; 43 | } 44 | 45 | .button:hover { 46 | background-color: hsla(196.55172413793105, 54.72%, 79.22%, 1.00); 47 | box-shadow: none; 48 | color: hsla(247.6190476190476, 42.28%, 29.22%, 1.00); 49 | } 50 | 51 | .button:focus { 52 | outline-color: var(--clrPrimary600-aeaf7110); 53 | outline-offset: 0.2rem; 54 | outline-style: solid; 55 | outline-width: 0.2rem; 56 | } 57 | 58 | .button:focus-visible { 59 | outline-color: var(--clrPrimary600-aeaf7110); 60 | outline-offset: 0.2rem; 61 | outline-style: solid; 62 | outline-width: 0.2rem; 63 | } 64 | 65 | .button.secondary { 66 | background-color: var(--clrSecondary400-685c3959); 67 | color: var(--clrPrimary600-aeaf7110); 68 | } 69 | 70 | .button.secondary:hover { 71 | background-color: var(--clrPrimary400-6c00fdf1); 72 | color: var(--clrNeutral100-f9191126); 73 | } 74 | 75 | .button.secondary:focus { 76 | outline-color: var(--clrSecondary400-685c3959); 77 | } 78 | 79 | .button.tertiary { 80 | background-color: var(--clrQuarternary400-68656429); 81 | color: var(--clrPrimary600-aeaf7110); 82 | } 83 | 84 | .button.tertiary:hover { 85 | background-color: var(--clrPrimary600-aeaf7110); 86 | color: var(--clrNeutral100-f9191126); 87 | } 88 | 89 | .button.tertiary:focus { 90 | outline-color: var(--clrQuarternary400-68656429); 91 | } 92 | 93 | .button.small { 94 | padding: 1em 1.5em; 95 | font-size: 1rem; 96 | } 97 | 98 | .button.sign-up { 99 | text-align: center; 100 | } 101 | 102 | #w-node-_05a0cdfd-5b52-43c7-186d-fe226e527f86-6e527f85 { 103 | grid-column-start: span 1; 104 | grid-column-end: span 1; 105 | grid-row-start: span 1; 106 | grid-row-end: span 1; 107 | align-self: center; 108 | } 109 | #w-node-_05a0cdfd-5b52-43c7-186d-fe226e527f8b-6e527f85 { 110 | grid-column-start: span 1; 111 | grid-column-end: span 1; 112 | grid-row-start: span 1; 113 | grid-row-end: span 1; 114 | justify-self: end; 115 | align-self: center; 116 | } 117 | @media screen and (max-width: 767px) { 118 | #w-node-_05a0cdfd-5b52-43c7-186d-fe226e527f8b-6e527f85 { 119 | justify-self: start; 120 | } 121 | } -------------------------------------------------------------------------------- /devlink/Stats.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as Types from "./types"; 3 | 4 | declare function Stats(props: { 5 | as?: React.ElementType; 6 | chart?: Types.Devlink.Slot; 7 | }): React.JSX.Element; 8 | -------------------------------------------------------------------------------- /devlink/Stats.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import * as _Builtin from "./_Builtin"; 3 | import * as _utils from "./utils"; 4 | import _styles from "./Stats.module.css"; 5 | 6 | export function Stats({ as: _Component = _Builtin.Section, chart }) { 7 | return ( 8 | <_Component className={_utils.cx(_styles, "section")} tag="section"> 9 | <_Builtin.Container className={_utils.cx(_styles, "container")} tag="div"> 10 | <_Builtin.Heading className={_utils.cx(_styles, "tl-heading")} tag="h2"> 11 | {"Average time to fill an open role"} 12 | 13 | <_Builtin.Block 14 | className={_utils.cx(_styles, "timeline-grid")} 15 | tag="div" 16 | > 17 | <_Builtin.Block 18 | className={_utils.cx(_styles, "tl-card")} 19 | id={_utils.cx( 20 | _styles, 21 | "w-node-_13e882f5-b194-bda1-60df-b8cbb049f2ee-b049f2e9" 22 | )} 23 | tag="div" 24 | > 25 | <_Builtin.Block 26 | className={_utils.cx(_styles, "tl-line-wrapper")} 27 | tag="div" 28 | > 29 | <_Builtin.Block tag="div">{"•"} 30 | <_Builtin.Block tag="div">{"Day 1"} 31 | <_Builtin.Block 32 | className={_utils.cx(_styles, "tl-line")} 33 | tag="div" 34 | /> 35 | 36 | <_Builtin.Block tag="div"> 37 | <_Builtin.Block 38 | className={_utils.cx(_styles, "tl-title")} 39 | tag="div" 40 | > 41 | {"Post your open role"} 42 | 43 | <_Builtin.Paragraph className={_utils.cx(_styles, "tl-summary")}> 44 | { 45 | "Streamline your hiring process by quickly posting your open roles on our platform, reaching a vast network of highly skilled Webflow, no-code, and traditional developers." 46 | } 47 | 48 | 49 | 50 | <_Builtin.Block 51 | className={_utils.cx(_styles, "tl-card")} 52 | id={_utils.cx( 53 | _styles, 54 | "w-node-_13e882f5-b194-bda1-60df-b8cbb049f2fa-b049f2e9" 55 | )} 56 | tag="div" 57 | > 58 | <_Builtin.Block 59 | className={_utils.cx(_styles, "tl-line-wrapper")} 60 | tag="div" 61 | > 62 | <_Builtin.Block tag="div">{"•"} 63 | <_Builtin.Block tag="div">{"Days 2 - 4"} 64 | <_Builtin.Block 65 | className={_utils.cx(_styles, "tl-line")} 66 | tag="div" 67 | /> 68 | 69 | <_Builtin.Block tag="div"> 70 | <_Builtin.Block 71 | className={_utils.cx(_styles, "tl-title")} 72 | tag="div" 73 | > 74 | {"Review incoming applicants"} 75 | 76 | <_Builtin.Paragraph className={_utils.cx(_styles, "tl-summary")}> 77 | { 78 | "Save time and effort by conveniently reviewing all incoming applications in one place, facilitated by our intuitive interface and applicant sorting features." 79 | } 80 | 81 | 82 | 83 | <_Builtin.Block 84 | className={_utils.cx(_styles, "tl-card")} 85 | id={_utils.cx( 86 | _styles, 87 | "w-node-_13e882f5-b194-bda1-60df-b8cbb049f306-b049f2e9" 88 | )} 89 | tag="div" 90 | > 91 | <_Builtin.Block 92 | className={_utils.cx(_styles, "tl-line-wrapper")} 93 | tag="div" 94 | > 95 | <_Builtin.Block tag="div">{"•"} 96 | <_Builtin.Block tag="div">{"Day 5"} 97 | <_Builtin.Block 98 | className={_utils.cx(_styles, "tl-line")} 99 | tag="div" 100 | /> 101 | 102 | <_Builtin.Block tag="div"> 103 | <_Builtin.Block 104 | className={_utils.cx(_styles, "tl-title")} 105 | tag="div" 106 | > 107 | {"Set up interview times"} 108 | 109 | <_Builtin.Paragraph className={_utils.cx(_styles, "tl-summary")}> 110 | { 111 | "Take advantage of our integrated scheduling tool to effortlessly set up interviews, ensuring a smooth and efficient selection process that respects everyone's time." 112 | } 113 | 114 | 115 | 116 | <_Builtin.Block 117 | className={_utils.cx(_styles, "tl-card")} 118 | id={_utils.cx( 119 | _styles, 120 | "w-node-_13e882f5-b194-bda1-60df-b8cbb049f312-b049f2e9" 121 | )} 122 | tag="div" 123 | > 124 | <_Builtin.Block 125 | className={_utils.cx(_styles, "tl-line-wrapper")} 126 | tag="div" 127 | > 128 | <_Builtin.Block tag="div">{"•"} 129 | <_Builtin.Block tag="div">{"Day 7"} 130 | <_Builtin.Block 131 | className={_utils.cx(_styles, "tl-line")} 132 | tag="div" 133 | /> 134 | 135 | <_Builtin.Block tag="div"> 136 | <_Builtin.Block 137 | className={_utils.cx(_styles, "tl-title")} 138 | tag="div" 139 | > 140 | {"Send out an offer"} 141 | 142 | <_Builtin.Paragraph className={_utils.cx(_styles, "tl-summary")}> 143 | { 144 | "Once you've found your ideal candidate, our platform makes it easy to send out an offer, accelerating the hiring timeline and helping you build your dream team faster." 145 | } 146 | 147 | 148 | 149 | 150 | <_Builtin.Heading className={_utils.cx(_styles, "tl-heading")} tag="h2"> 151 | {"Average time to hire visual"} 152 | 153 | <_Builtin.Block tag="div">{chart} 154 | 155 | 156 | ); 157 | } 158 | -------------------------------------------------------------------------------- /devlink/Stats.module.css: -------------------------------------------------------------------------------- 1 | .section { 2 | padding-top: 5em; 3 | padding-bottom: 5em; 4 | } 5 | 6 | .section.hero { 7 | position: relative; 8 | min-height: 600px; 9 | background-color: var(--clrPrimary600-aeaf7110); 10 | color: var(--clrNeutral100-f9191126); 11 | } 12 | 13 | .section.title { 14 | background-color: var(--clrPrimary400-6c00fdf1); 15 | color: var(--clrPrimary999-b0a60ce1); 16 | } 17 | 18 | .section.pricing-gradient { 19 | background-image: radial-gradient(circle farthest-corner at 50% 100%, var(--clrPrimary400-6c00fdf1), var(--clrPrimary999-b0a60ce1) 73%); 20 | color: var(--clrNeutral100-f9191126); 21 | } 22 | 23 | .section.pricing { 24 | position: relative; 25 | padding-top: 5em; 26 | color: hsla(329.9999999999999, 0.00%, 100.00%, 1.00); 27 | text-align: center; 28 | } 29 | 30 | .clr-secondary-400 { 31 | background-color: var(--clrSecondary400-685c3959); 32 | } 33 | 34 | .clr-primary-400 { 35 | background-color: var(--clrPrimary400-6c00fdf1); 36 | } 37 | 38 | .section.features { 39 | color: var(--clrPrimary600-aeaf7110); 40 | } 41 | 42 | .container { 43 | width: 100%; 44 | max-width: 1200px; 45 | margin-right: auto; 46 | margin-left: auto; 47 | padding-right: 1em; 48 | padding-left: 1em; 49 | } 50 | 51 | @media screen and (max-width: 767px) { 52 | .container { 53 | padding-right: 1.5em; 54 | padding-left: 1.5em; 55 | } 56 | } 57 | 58 | .container.nav { 59 | display: flex; 60 | justify-content: space-between; 61 | align-items: center; 62 | } 63 | 64 | .container.narrow { 65 | max-width: 720px; 66 | } 67 | 68 | .container.rel { 69 | position: relative; 70 | z-index: 2; 71 | } 72 | 73 | .center { 74 | text-align: center; 75 | } 76 | 77 | .tl-heading { 78 | margin-bottom: 2em; 79 | } 80 | 81 | .timeline-grid { 82 | display: grid; 83 | margin-bottom: 2em; 84 | grid-auto-columns: 1fr; 85 | grid-column-gap: 16px; 86 | grid-row-gap: 16px; 87 | grid-template-columns: 1fr 1fr 1fr 1fr; 88 | grid-template-rows: auto; 89 | } 90 | 91 | @media screen and (max-width: 767px) { 92 | .timeline-grid { 93 | grid-template-columns: 1fr 1fr; 94 | } 95 | } 96 | 97 | @media screen and (max-width: 479px) { 98 | .timeline-grid { 99 | grid-template-columns: 1fr; 100 | } 101 | } 102 | 103 | .tl-line-wrapper { 104 | display: flex; 105 | margin-bottom: 1em; 106 | align-items: center; 107 | grid-column-gap: 1em; 108 | 109 | color: var(--clrPrimary600-aeaf7110); 110 | font-size: 0.9rem; 111 | font-weight: 700; 112 | } 113 | 114 | .tl-line { 115 | height: 1px; 116 | flex: 1; 117 | border-top: 1px solid var(--clrPrimary600-aeaf7110); 118 | } 119 | 120 | .tl-title { 121 | margin-bottom: 1em; 122 | font-weight: 700; 123 | } 124 | 125 | .tl-summary { 126 | font-size: 1rem; 127 | } 128 | 129 | #w-node-_13e882f5-b194-bda1-60df-b8cbb049f2ee-b049f2e9 { 130 | grid-column-start: span 1; 131 | grid-column-end: span 1; 132 | grid-row-start: span 1; 133 | grid-row-end: span 1; 134 | } 135 | #w-node-_13e882f5-b194-bda1-60df-b8cbb049f2fa-b049f2e9 { 136 | grid-column-start: span 1; 137 | grid-column-end: span 1; 138 | grid-row-start: span 1; 139 | grid-row-end: span 1; 140 | } 141 | #w-node-_13e882f5-b194-bda1-60df-b8cbb049f306-b049f2e9 { 142 | grid-column-start: span 1; 143 | grid-column-end: span 1; 144 | grid-row-start: span 1; 145 | grid-row-end: span 1; 146 | } 147 | #w-node-_13e882f5-b194-bda1-60df-b8cbb049f312-b049f2e9 { 148 | grid-column-start: span 1; 149 | grid-column-end: span 1; 150 | grid-row-start: span 1; 151 | grid-row-end: span 1; 152 | } -------------------------------------------------------------------------------- /devlink/_Builtin/BackgroundVideo.d.ts: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | declare type BackgroundVideoWrapperProps = { 3 | tag?: keyof HTMLElementTagNameMap; 4 | className?: string; 5 | sources?: string[]; 6 | posterImage?: ""; 7 | autoPlay?: boolean; 8 | loop?: boolean; 9 | children?: React.ReactElement; 10 | }; 11 | export declare const BackgroundVideoWrapper: ({ 12 | tag, 13 | className, 14 | autoPlay, 15 | loop, 16 | sources, 17 | posterImage, 18 | children, 19 | }: BackgroundVideoWrapperProps) => JSX.Element; 20 | declare type BackgroundVideoPlayPauseButtonProps = { 21 | className?: string; 22 | children: React.ReactElement< 23 | | BackgroundVideoPlayPauseButtonPlayingProps 24 | | BackgroundVideoPlayPauseButtonPausedProps 25 | >[]; 26 | }; 27 | export declare const BackgroundVideoPlayPauseButton: ({ 28 | children, 29 | className, 30 | }: BackgroundVideoPlayPauseButtonProps) => JSX.Element; 31 | declare type BackgroundVideoPlayPauseButtonPlayingProps = { 32 | children: React.ReactNode; 33 | }; 34 | export declare const BackgroundVideoPlayPauseButtonPlaying: ({ 35 | children, 36 | }: BackgroundVideoPlayPauseButtonPlayingProps) => JSX.Element; 37 | declare type BackgroundVideoPlayPauseButtonPausedProps = { 38 | children: React.ReactNode; 39 | }; 40 | export declare const BackgroundVideoPlayPauseButtonPaused: ({ 41 | children, 42 | }: BackgroundVideoPlayPauseButtonPausedProps) => JSX.Element; 43 | export {}; 44 | -------------------------------------------------------------------------------- /devlink/_Builtin/BackgroundVideo.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { cj, debounce } from "../utils"; 3 | const BgVideoContext = React.createContext({ 4 | isPlaying: true, 5 | togglePlay: () => {}, 6 | }); 7 | export const BackgroundVideoWrapper = ({ 8 | tag = "div", 9 | className = "", 10 | autoPlay = true, 11 | loop = true, 12 | sources = [], 13 | posterImage = "", 14 | children, 15 | }) => { 16 | const [isPlaying, setIsPlaying] = React.useState(autoPlay); 17 | const video = React.useRef(null); 18 | const togglePlay = debounce(() => { 19 | setIsPlaying(!isPlaying); 20 | if (!video?.current) return; 21 | if (video.current.paused) { 22 | video.current.play(); 23 | } else { 24 | video.current.pause(); 25 | } 26 | }); 27 | return ( 28 | 29 | {React.createElement( 30 | tag, 31 | { 32 | className: cj( 33 | className, 34 | "w-background-video", 35 | "w-background-video-atom" 36 | ), 37 | }, 38 | 54 | )} 55 | {children} 56 | 57 | ); 58 | }; 59 | export const BackgroundVideoPlayPauseButton = ({ children, className }) => { 60 | const { togglePlay } = React.useContext(BgVideoContext); 61 | return ( 62 |
63 | 74 |
75 | ); 76 | }; 77 | export const BackgroundVideoPlayPauseButtonPlaying = ({ children }) => { 78 | const { isPlaying } = React.useContext(BgVideoContext); 79 | return ; 80 | }; 81 | export const BackgroundVideoPlayPauseButtonPaused = ({ children }) => { 82 | const { isPlaying } = React.useContext(BgVideoContext); 83 | return ; 84 | }; 85 | -------------------------------------------------------------------------------- /devlink/_Builtin/Basic.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as utils from "../utils"; 3 | export function Block({ tag = "div", ...props }) { 4 | return React.createElement(tag, props); 5 | } 6 | export function Span(props) { 7 | return ; 8 | } 9 | export function Blockquote(props) { 10 | return
; 11 | } 12 | export const Link = function Link({ 13 | options = { href: "#" }, 14 | className = "", 15 | button = false, 16 | ...props 17 | }) { 18 | if (button) className += " w-button"; 19 | const { href, target, preload = "none" } = options; 20 | const shouldRenderResource = 21 | preload !== "none" && typeof href === "string" && !href.startsWith("#"); 22 | return ( 23 | <> 24 | 25 | {shouldRenderResource && } 26 | 27 | ); 28 | }; 29 | export function List({ 30 | tag = "ul", 31 | unstyled = true, 32 | className = "", 33 | ...props 34 | }) { 35 | return React.createElement(tag, { 36 | role: "list", 37 | className: className + (unstyled ? " w-list-unstyled" : ""), 38 | ...props, 39 | }); 40 | } 41 | export function ListItem(props) { 42 | return React.createElement("li", props); 43 | } 44 | export function Image(props) { 45 | return React.createElement("img", props); 46 | } 47 | export function Section({ tag = "section", ...props }) { 48 | return React.createElement(tag, props); 49 | } 50 | export const Container = React.forwardRef(function Container( 51 | { tag = "div", className = "", ...props }, 52 | ref 53 | ) { 54 | return React.createElement(tag, { 55 | className: className + " w-container", 56 | ref, 57 | ...props, 58 | }); 59 | }); 60 | export function HtmlEmbed({ 61 | tag = "div", 62 | className = "", 63 | value = "", 64 | ...props 65 | }) { 66 | return React.createElement(tag, { 67 | className: className + " w-embed", 68 | dangerouslySetInnerHTML: { __html: utils.removeUnescaped(value) }, 69 | ...props, 70 | }); 71 | } 72 | export function Grid({ tag = "div", className = "", ...props }) { 73 | return React.createElement(tag, { 74 | className: className + " w-layout-grid", 75 | ...props, 76 | }); 77 | } 78 | export function Icon({ widget, className = "", ...props }) { 79 | return React.createElement("div", { 80 | className: className + ` w-icon-${widget.icon}`, 81 | ...props, 82 | }); 83 | } 84 | export function Column({ 85 | tag = "div", 86 | className = "", 87 | columnClasses = "", 88 | ...props 89 | }) { 90 | return React.createElement(tag, { 91 | className: className + " w-col " + columnClasses, 92 | ...props, 93 | }); 94 | } 95 | const transformWidths = (width, index) => { 96 | const widths = width?.split("|") ?? []; 97 | return widths.length > 1 ? widths[index] : width; 98 | }; 99 | const columnClass = (width, key) => { 100 | if (/stack$/.test(width)) return "w-col-stack"; 101 | if (/main$/.test(key)) return `w-col-${width}`; 102 | return `w-col-${key}-${width}`; 103 | }; 104 | export function Row({ tag = "div", className = "", grid, children, ...props }) { 105 | return React.createElement( 106 | tag, 107 | { className: className + " w-row", ...props }, 108 | grid 109 | ? React.Children.map(children, (child, index) => { 110 | if (child && typeof child === "object" && child.type !== Column) 111 | return child; 112 | const columnClasses = Object.entries(grid.cols ?? {}).reduce( 113 | (acc, [key, value]) => { 114 | const width = transformWidths( 115 | value === "custom" ? "6|6" : value, 116 | index 117 | ); 118 | acc.add(width ? columnClass(width, key) : ""); 119 | return acc; 120 | }, 121 | new Set() 122 | ); 123 | return React.cloneElement(child, { 124 | // @ts-ignore 125 | columnClasses: [...columnClasses].join(" "), 126 | ...child.props, 127 | }); 128 | }) 129 | : children 130 | ); 131 | } 132 | export function NotSupported({ _atom = "" }) { 133 | return
{`This builtin is not currently supported: ${_atom}`}
; 134 | } 135 | -------------------------------------------------------------------------------- /devlink/_Builtin/Dropdown.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { LinkProps } from "./Basic"; 3 | declare type DropdownProps = React.PropsWithChildren<{ 4 | tag?: keyof HTMLElementTagNameMap; 5 | className?: string; 6 | }>; 7 | declare type DropdownWrapperProps = DropdownProps & { 8 | children: React.ReactElement; 9 | }; 10 | export declare function DropdownWrapper( 11 | props: DropdownWrapperProps 12 | ): JSX.Element; 13 | declare type DropdownToggleProps = DropdownProps; 14 | export declare function DropdownToggle({ 15 | tag, 16 | className, 17 | ...props 18 | }: DropdownToggleProps): React.DOMElement< 19 | { 20 | "aria-haspopup": string; 21 | "aria-expanded": boolean; 22 | className: string; 23 | onClick: () => void; 24 | children?: React.ReactNode; 25 | }, 26 | Element 27 | >; 28 | declare type DropdownListProps = DropdownProps & { 29 | children: 30 | | React.ReactElement 31 | | React.ReactElement[]; 32 | }; 33 | export declare function DropdownList({ 34 | tag, 35 | className, 36 | ...props 37 | }: DropdownListProps): React.DOMElement< 38 | { 39 | className: string; 40 | children: React.ReactNode & 41 | ( 42 | | React.ReactElement< 43 | DropdownLinkProps, 44 | string | React.JSXElementConstructor 45 | > 46 | | React.ReactElement< 47 | DropdownLinkProps, 48 | string | React.JSXElementConstructor 49 | >[] 50 | ); 51 | }, 52 | Element 53 | >; 54 | declare type DropdownLinkProps = DropdownProps & LinkProps; 55 | export declare function DropdownLink({ 56 | className, 57 | ...props 58 | }: DropdownLinkProps): React.FunctionComponentElement< 59 | import("./Basic").ElementProps<"a"> & { 60 | options?: 61 | | { 62 | href: string; 63 | target?: "_self" | "_blank" | undefined; 64 | preload?: "none" | "prerender" | "prefetch" | undefined; 65 | } 66 | | undefined; 67 | className?: string | undefined; 68 | button?: boolean | undefined; 69 | } 70 | >; 71 | export {}; 72 | -------------------------------------------------------------------------------- /devlink/_Builtin/Dropdown.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { useIXEvent } from "../interactions"; 3 | import { cj, useClickOut } from "../utils"; 4 | import { Link } from "./Basic"; 5 | import { NavbarContext } from "./Navbar"; 6 | const DropdownContext = React.createContext({ 7 | root: undefined, 8 | isOpen: false, 9 | toggleOpen: () => {}, 10 | }); 11 | export function DropdownWrapper(props) { 12 | const root = React.useRef(null); 13 | const [isOpen, setIsOpen] = React.useState(false); 14 | const toggleOpen = () => setIsOpen((isOpen) => !isOpen); 15 | const closeDropdown = React.useCallback(() => setIsOpen(false), [setIsOpen]); 16 | useClickOut(root, closeDropdown); 17 | useIXEvent(root.current, isOpen); 18 | return ( 19 | 20 | 21 | 22 | ); 23 | } 24 | function Dropdown({ tag = "div", className = "", ...props }) { 25 | const { root } = React.useContext(DropdownContext); 26 | const { isOpen: isNavbarOpen } = React.useContext(NavbarContext); 27 | return React.createElement(tag, { 28 | ...props, 29 | ref: root, 30 | className: cj( 31 | className, 32 | "w-dropdown", 33 | isNavbarOpen && "w--nav-dropdown-open" 34 | ), 35 | }); 36 | } 37 | export function DropdownToggle({ tag = "div", className = "", ...props }) { 38 | const { isOpen, toggleOpen } = React.useContext(DropdownContext); 39 | const { isOpen: isNavbarOpen } = React.useContext(NavbarContext); 40 | return React.createElement(tag, { 41 | ...props, 42 | "aria-haspopup": "menu", 43 | "aria-expanded": isOpen, 44 | className: cj( 45 | className, 46 | "w-dropdown-toggle", 47 | isNavbarOpen && "w--nav-dropdown-toggle-open" 48 | ), 49 | onClick: toggleOpen, 50 | }); 51 | } 52 | export function DropdownList({ tag = "nav", className = "", ...props }) { 53 | const { isOpen } = React.useContext(DropdownContext); 54 | const { isOpen: isNavbarOpen } = React.useContext(NavbarContext); 55 | return React.createElement(tag, { 56 | ...props, 57 | className: cj( 58 | className, 59 | "w-dropdown-list", 60 | isOpen && "w--open", 61 | isNavbarOpen && "w--nav-dropdown-list-open" 62 | ), 63 | }); 64 | } 65 | export function DropdownLink({ className = "", ...props }) { 66 | const { isOpen: isNavbarOpen } = React.useContext(NavbarContext); 67 | return React.createElement(Link, { 68 | ...props, 69 | className: cj( 70 | className, 71 | "w-dropdown-link", 72 | isNavbarOpen && "w--nav-link-open" 73 | ), 74 | }); 75 | } 76 | -------------------------------------------------------------------------------- /devlink/_Builtin/Facebook.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | declare type FacebookProps = React.PropsWithChildren<{ 3 | className?: string; 4 | layout?: string; 5 | width?: number; 6 | height?: number; 7 | url?: string; 8 | locale?: string; 9 | }>; 10 | export declare function Facebook({ 11 | className, 12 | layout, 13 | width, 14 | height, 15 | url, 16 | locale, 17 | ...props 18 | }: FacebookProps): JSX.Element; 19 | export {}; 20 | -------------------------------------------------------------------------------- /devlink/_Builtin/Facebook.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { isUrl } from "../utils"; 3 | export function Facebook({ 4 | className = "", 5 | layout = "standard", 6 | width = 250, 7 | height = 50, 8 | url = "https://facebook.com/webflow", 9 | locale = "en_US", 10 | ...props 11 | }) { 12 | if (!isUrl(url)) { 13 | url = "https://facebook.com/webflow"; 14 | } 15 | if (!/^http/.test(url)) { 16 | url = "http://" + url; 17 | } 18 | const params = { 19 | href: url, 20 | layout: layout, 21 | locale: locale, 22 | action: "like", 23 | show_faces: "false", 24 | share: "false", 25 | }; 26 | const queryParams = Object.keys(params).map( 27 | (key) => `${key}=${encodeURIComponent(params[key])}` 28 | ); 29 | const frameSrc = `https://www.facebook.com/plugins/like.php?${queryParams.join( 30 | "&" 31 | )}`; 32 | return ( 33 |
34 | 39 |
40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /devlink/_Builtin/Form.d.ts: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Props } from "./Basic"; 3 | declare type FormState = "normal" | "success" | "error"; 4 | declare type FormWrapperProps = Props<"div"> & { 5 | state?: FormState; 6 | children: React.ReactElement< 7 | typeof FormForm | typeof FormSuccessMessage | typeof FormErrorMessage 8 | >[]; 9 | }; 10 | declare global { 11 | interface Window { 12 | grecaptcha: any; 13 | } 14 | } 15 | export declare function FormWrapper({ 16 | className, 17 | state: initialState, 18 | onSubmit, 19 | children, 20 | ...props 21 | }: FormWrapperProps): any; 22 | declare type FormSelect = { 23 | options: Array<{ 24 | v: string; 25 | t: string; 26 | }>; 27 | }; 28 | declare type FormProps = Props; 29 | export declare function FormForm(props: FormProps<"form">): any; 30 | export declare function FormBlockLabel(props: FormProps<"label">): any; 31 | declare type FormInputProps = React.InputHTMLAttributes & { 32 | inputType?: string; 33 | }; 34 | export declare function FormTextInput({ 35 | className, 36 | ...props 37 | }: FormInputProps): any; 38 | declare type FormTextAreaProps = React.InputHTMLAttributes; 39 | export declare function FormTextarea({ 40 | className, 41 | ...props 42 | }: FormTextAreaProps): any; 43 | export declare function FormInlineLabel({ 44 | className, 45 | ...props 46 | }: FormProps<"span">): any; 47 | export declare function FormCheckboxWrapper({ 48 | className, 49 | ...props 50 | }: FormProps<"label">): any; 51 | export declare function FormRadioWrapper({ 52 | className, 53 | ...props 54 | }: FormProps<"label">): any; 55 | export declare function FormCheckboxInput({ 56 | className, 57 | checked, 58 | ...props 59 | }: FormInputProps): any; 60 | export declare function FormRadioInput({ 61 | className, 62 | inputType, 63 | ...props 64 | }: FormInputProps): any; 65 | declare type FileUploadWrapperProps = Props<"div"> & { 66 | maxSize?: number; 67 | }; 68 | export declare function FormFileUploadWrapper({ 69 | maxSize, 70 | ...props 71 | }: FileUploadWrapperProps): any; 72 | export declare function _FormFileUploadWrapper({ 73 | className, 74 | ...props 75 | }: FileUploadWrapperProps): any; 76 | export declare function FormFileUploadDefault({ 77 | className, 78 | ...props 79 | }: FormProps<"div">): any; 80 | export declare function FormFileUploadInput({ 81 | className, 82 | ...props 83 | }: FormInputProps): any; 84 | export declare function FormFileUploadLabel({ 85 | className, 86 | ...props 87 | }: FormProps<"label">): any; 88 | export declare function FormFileUploadText({ 89 | className, 90 | ...props 91 | }: FormProps<"div">): any; 92 | export declare function FormFileUploadInfo({ 93 | className, 94 | ...props 95 | }: FormProps<"div">): any; 96 | export declare function FormFileUploadUploading({ 97 | className, 98 | ...props 99 | }: FormProps<"div">): any; 100 | export declare function FormFileUploadUploadingBtn({ 101 | className, 102 | ...props 103 | }: FormProps<"div">): any; 104 | export declare function FormFileUploadUploadingIcon({ 105 | className, 106 | ...props 107 | }: FormProps<"div">): any; 108 | export declare function FormFileUploadSuccess({ 109 | className, 110 | ...props 111 | }: FormProps<"div">): any; 112 | export declare function FormFileUploadFile({ 113 | className, 114 | ...props 115 | }: FormProps<"div">): any; 116 | export declare function FormFileUploadFileName({ 117 | className, 118 | ...props 119 | }: FormProps<"div">): any; 120 | export declare function FormFileUploadRemoveLink({ 121 | className, 122 | ...props 123 | }: FormProps<"div">): any; 124 | export declare function FormFileUploadError({ 125 | className, 126 | ...props 127 | }: FormProps<"div">): any; 128 | declare type FormErrorMessageProps = HTMLDivElement & { 129 | errors: { 130 | SIZE_ERROR: string; 131 | TYPE_ERROR: string; 132 | GENERIC_ERROR: string; 133 | }; 134 | }; 135 | export declare function FormFileUploadErrorMsg({ 136 | errors, 137 | className, 138 | ...props 139 | }: FormErrorMessageProps): any; 140 | export declare function FormButton({ 141 | className, 142 | value, 143 | ...props 144 | }: FormInputProps): any; 145 | export declare function SearchForm(props: FormProps<"form">): any; 146 | export declare function SearchInput({ 147 | className, 148 | ...props 149 | }: FormInputProps): any; 150 | export declare function SearchButton({ 151 | value, 152 | className, 153 | ...props 154 | }: FormInputProps): any; 155 | export declare function FormSuccessMessage({ 156 | className, 157 | ...props 158 | }: Props<"div">): any; 159 | export declare function FormErrorMessage({ 160 | className, 161 | ...props 162 | }: Props<"div">): any; 163 | export declare function FormSelect({ 164 | options, 165 | className, 166 | ...props 167 | }: FormProps<"select"> & FormSelect): any; 168 | declare type FormReCaptchaProps = { 169 | siteKey: string; 170 | theme?: "light" | "dark"; 171 | size?: "compact" | "normal" | "invisible"; 172 | }; 173 | export declare function FormReCaptcha({ 174 | siteKey, 175 | theme, 176 | size, 177 | }: FormReCaptchaProps): JSX.Element; 178 | export {}; 179 | -------------------------------------------------------------------------------- /devlink/_Builtin/Map.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | declare global { 3 | interface Window { 4 | google: { 5 | maps: any; 6 | }; 7 | } 8 | } 9 | declare type MapWidgetProps = { 10 | className?: string; 11 | apiKey: string; 12 | zoom?: number; 13 | latlng?: string; 14 | mapStyle?: "roadmap" | "satellite" | "hybrid" | "terrain"; 15 | tooltip?: string; 16 | title?: string; 17 | enableScroll?: boolean; 18 | enableTouch?: boolean; 19 | }; 20 | export declare function MapWidget({ 21 | apiKey, 22 | mapStyle, 23 | zoom, 24 | latlng, 25 | tooltip, 26 | title, 27 | enableScroll, 28 | enableTouch, 29 | className, 30 | ...props 31 | }: MapWidgetProps): JSX.Element; 32 | export default Map; 33 | -------------------------------------------------------------------------------- /devlink/_Builtin/Map.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef } from "react"; 2 | import { cj, loadScript } from "../utils"; 3 | function buildTitle(title, tooltip) { 4 | let markerTitle = "Map pin"; 5 | if (title && tooltip) { 6 | markerTitle = `Map pin on ${title} showing location of ${tooltip}`; 7 | } else if (title && !tooltip) { 8 | markerTitle = `Map pin on ${title}`; 9 | } else if (!title && tooltip) { 10 | markerTitle = `Map pin showing location of ${tooltip}`; 11 | } 12 | return markerTitle; 13 | } 14 | export function MapWidget({ 15 | apiKey = "", 16 | mapStyle = "roadmap", 17 | zoom = 12, 18 | latlng = "51.511214,-0.119824", 19 | tooltip = "", 20 | title = "", 21 | enableScroll = true, 22 | enableTouch = true, 23 | className = "", 24 | ...props 25 | }) { 26 | const mapRef = useRef(null); 27 | useEffect(() => { 28 | const loadMap = () => { 29 | if (!mapRef.current) return; 30 | if (!window?.google?.maps) return; 31 | const { Map, Marker, InfoWindow } = window.google.maps; 32 | const coords = latlng.split(","); 33 | const center = { lat: parseFloat(coords[0]), lng: parseFloat(coords[1]) }; 34 | const map = new Map(mapRef.current, { 35 | zoom, 36 | center, 37 | mapTypeId: mapStyle, 38 | mapTypeControl: false, 39 | panControl: false, 40 | streetViewControl: false, 41 | draggable: enableTouch, 42 | scrollwheel: enableScroll, 43 | zoomControl: true, 44 | }); 45 | const marker = new Marker({ 46 | draggable: false, 47 | position: center, 48 | title: buildTitle(title, tooltip), 49 | map, 50 | }); 51 | if (tooltip) { 52 | new InfoWindow({ 53 | disableAutoPan: true, 54 | content: tooltip, 55 | position: center, 56 | }).open({ anchor: marker, map }); 57 | } 58 | window.google.maps.event.addListener(marker, "click", function () { 59 | window.open(`https://maps.google.com/?z=${zoom}&daddr=${latlng}`); 60 | }); 61 | }; 62 | loadScript( 63 | `https://maps.googleapis.com/maps/api/js?v=3.52.5&key=${apiKey}`, 64 | { 65 | cacheRegex: /maps\.googleapis\.com\/maps\/api\/js\?v=3\.52\.5\&key=/gi, 66 | } 67 | ).then(loadMap); 68 | }, [ 69 | apiKey, 70 | mapStyle, 71 | zoom, 72 | latlng, 73 | tooltip, 74 | title, 75 | enableScroll, 76 | enableTouch, 77 | mapRef, 78 | ]); 79 | return ( 80 |
86 | ); 87 | } 88 | export default Map; 89 | -------------------------------------------------------------------------------- /devlink/_Builtin/Navbar.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { EASING_FUNCTIONS } from "../utils"; 3 | import { LinkProps, ContainerProps } from "./Basic"; 4 | declare const BREAKPOINTS: { 5 | medium: number; 6 | small: number; 7 | tiny: number; 8 | }; 9 | declare type NavbarConfig = { 10 | animation: string; 11 | collapse: keyof typeof BREAKPOINTS; 12 | docHeight: boolean; 13 | duration: number; 14 | easing: keyof typeof EASING_FUNCTIONS; 15 | easing2: keyof typeof EASING_FUNCTIONS; 16 | noScroll: boolean; 17 | }; 18 | export declare const NavbarContext: React.Context< 19 | NavbarConfig & { 20 | animDirect: -1 | 1; 21 | animOver: boolean; 22 | getBodyHeight: () => number | void; 23 | getOverlayHeight: () => number | void; 24 | isOpen: boolean; 25 | menu: React.MutableRefObject; 26 | root: React.MutableRefObject; 27 | toggleOpen: () => void; 28 | navbarMounted: boolean; 29 | } 30 | >; 31 | declare type NavbarChildrenType = 32 | | NavbarContainerProps 33 | | NavbarBrandProps 34 | | NavbarMenuProps 35 | | NavbarButtonProps; 36 | declare type NavbarProps = { 37 | tag: React.ElementType; 38 | config: NavbarConfig; 39 | className?: string; 40 | children?: 41 | | React.ReactElement[] 42 | | React.ReactElement; 43 | }; 44 | export declare function NavbarWrapper(props: NavbarProps): JSX.Element; 45 | declare type NavbarContainerProps = ContainerProps & { 46 | toggleOpen: () => void; 47 | isOpen: boolean; 48 | children: React.ReactNode; 49 | }; 50 | export declare function NavbarContainer({ 51 | children, 52 | ...props 53 | }: NavbarContainerProps): JSX.Element; 54 | declare type NavbarBrandProps = LinkProps; 55 | export declare function NavbarBrand({ 56 | className, 57 | ...props 58 | }: NavbarBrandProps): JSX.Element; 59 | declare type NavbarMenuProps = React.PropsWithChildren<{ 60 | tag?: React.ElementType; 61 | className?: string; 62 | isOpen?: boolean; 63 | }>; 64 | export declare function NavbarMenu({ 65 | tag, 66 | className, 67 | ...props 68 | }: NavbarMenuProps): React.ReactElement< 69 | any, 70 | string | React.JSXElementConstructor 71 | >; 72 | declare type NavbarLinkProps = LinkProps; 73 | export declare function NavbarLink({ 74 | className, 75 | ...props 76 | }: NavbarLinkProps): JSX.Element; 77 | declare type NavbarButtonProps = React.PropsWithChildren<{ 78 | tag?: React.ElementType; 79 | className?: string; 80 | }>; 81 | export declare function NavbarButton({ 82 | tag, 83 | className, 84 | ...props 85 | }: NavbarButtonProps): React.ReactElement< 86 | any, 87 | string | React.JSXElementConstructor 88 | >; 89 | export {}; 90 | -------------------------------------------------------------------------------- /devlink/_Builtin/Navbar.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | EASING_FUNCTIONS, 4 | cj, 5 | debounce, 6 | extractElement, 7 | isServer, 8 | useLayoutEffect, 9 | useResizeObserver, 10 | } from "../utils"; 11 | import { Link, Container } from "./Basic"; 12 | const BREAKPOINTS = { 13 | medium: 991, 14 | small: 767, 15 | tiny: 479, 16 | }; 17 | export const NavbarContext = React.createContext({ 18 | animDirect: 1, 19 | animOver: false, 20 | animation: "animation", 21 | collapse: "medium", 22 | docHeight: false, 23 | duration: 400, 24 | easing2: "ease", 25 | easing: "ease", 26 | getBodyHeight: () => {}, 27 | getOverlayHeight: () => {}, 28 | isOpen: false, 29 | noScroll: false, 30 | toggleOpen: () => {}, 31 | navbarMounted: false, 32 | menu: undefined, 33 | root: undefined, 34 | }); 35 | function getAnimationKeyframes({ axis = "Y", start, end }) { 36 | const t = `translate${axis}`; 37 | return [{ transform: `${t}(${start}px)` }, { transform: `${t}(${end}px)` }]; 38 | } 39 | export function NavbarWrapper(props) { 40 | const { animation, docHeight, easing, easing2, duration, noScroll } = 41 | props.config; 42 | const root = React.useRef(null); 43 | const menu = React.useRef(null); 44 | const animOver = /^over/.test(animation); 45 | const animDirect = /left$/.test(animation) ? -1 : 1; 46 | const getBodyHeight = React.useCallback(() => { 47 | if (isServer) return; 48 | return docHeight 49 | ? document.documentElement.scrollHeight 50 | : document.body.scrollHeight; 51 | }, [docHeight]); 52 | const getOverlayHeight = React.useCallback(() => { 53 | if (isServer || !root.current) return; 54 | let height = getBodyHeight(); 55 | if (!height) return; 56 | const style = getComputedStyle(root.current); 57 | if (!animOver && style.position !== "fixed") { 58 | height -= root.current.offsetHeight; 59 | } 60 | return height; 61 | }, [animOver, getBodyHeight]); 62 | const getOffsetHeight = React.useCallback(() => { 63 | if (!root.current || !menu.current) return 0; 64 | return root.current.offsetHeight + menu.current.offsetHeight; 65 | }, []); 66 | const [isOpen, setIsOpen] = React.useState(false); 67 | const toggleOpen = debounce(() => { 68 | if (!menu.current) return; 69 | // menu is open and should be closed 70 | if (isOpen) { 71 | const keyframes = animOver 72 | ? getAnimationKeyframes({ 73 | axis: "X", 74 | start: 0, 75 | end: animDirect * menu.current.offsetWidth, 76 | }) 77 | : getAnimationKeyframes({ start: 0, end: -getOffsetHeight() }); 78 | const anim = menu.current.animate(keyframes, { 79 | easing: EASING_FUNCTIONS[easing2] ?? "ease", 80 | duration, 81 | fill: "forwards", 82 | }); 83 | anim.onfinish = () => { 84 | setIsOpen(!isOpen); 85 | }; 86 | return; 87 | } 88 | setIsOpen(!isOpen); 89 | }); 90 | useLayoutEffect(() => { 91 | if (!menu.current) return; 92 | // menu is closed and will open, but the animation only runs when isOpen is true 93 | if (isOpen) { 94 | const keyframes = animOver 95 | ? getAnimationKeyframes({ 96 | axis: "X", 97 | start: animDirect * menu.current.offsetWidth, 98 | end: 0, 99 | }) 100 | : getAnimationKeyframes({ start: -getOffsetHeight(), end: 0 }); 101 | menu.current.animate(keyframes, { 102 | easing: EASING_FUNCTIONS[easing] ?? "ease", 103 | duration, 104 | fill: "forwards", 105 | }); 106 | } 107 | }, [ 108 | animDirect, 109 | animOver, 110 | duration, 111 | easing, 112 | getBodyHeight, 113 | getOffsetHeight, 114 | isOpen, 115 | ]); 116 | // if the menu is opened and noScroll === false prevent scrolling 117 | useLayoutEffect(() => { 118 | if (isOpen && noScroll) { 119 | document.body.style.overflowY = "hidden"; 120 | } else { 121 | document.body.style.overflowY = ""; 122 | } 123 | return () => { 124 | document.body.style.overflowY = ""; 125 | }; 126 | }, [isOpen, noScroll]); 127 | // Closes menu when the window is resized 128 | const closeOnResize = React.useCallback(() => setIsOpen(false), [setIsOpen]); 129 | useResizeObserver(root, closeOnResize); 130 | return ( 131 | 145 | 146 | 147 | ); 148 | } 149 | /** 150 | * Navbar menu gets appended to the overlay when it's open. 151 | * This function extracts the child menu when that's the case. 152 | * */ 153 | const maybeExtractChildMenu = (children, isOpen) => { 154 | if (!isOpen) return { childMenu: null, rest: children }; 155 | const { extracted, tree } = extractElement( 156 | React.Children.toArray(children), 157 | NavbarMenu 158 | ); 159 | return { childMenu: extracted, rest: tree }; 160 | }; 161 | function Navbar({ tag = "div", className = "", children, config, ...props }) { 162 | const { root, collapse } = React.useContext(NavbarContext); 163 | const [shouldExtractMenu, setShouldExtractMenu] = React.useState(true); 164 | const extractMenuCallback = React.useCallback( 165 | (entry) => 166 | setShouldExtractMenu(entry.contentRect.width <= BREAKPOINTS[collapse]), 167 | [setShouldExtractMenu] 168 | ); 169 | const bodyRef = React.useRef( 170 | typeof document !== "undefined" ? document.body : null 171 | ); 172 | useResizeObserver(bodyRef, extractMenuCallback); 173 | const { childMenu, rest } = React.useMemo( 174 | () => maybeExtractChildMenu(children, shouldExtractMenu), 175 | [children, shouldExtractMenu] 176 | ); 177 | return React.createElement( 178 | tag, 179 | { 180 | ...props, 181 | className: cj(className, "w-nav"), 182 | "data-collapse": config.collapse, 183 | "data-animation": config.animation, 184 | ref: root, 185 | }, 186 | <> 187 | {rest} 188 | {childMenu} 189 | 190 | ); 191 | } 192 | function NavbarOverlay({ children }) { 193 | const { isOpen, getOverlayHeight, toggleOpen } = 194 | React.useContext(NavbarContext); 195 | const overlayToggleOpen = React.useCallback( 196 | (e) => { 197 | // prevent link clicks to close the overlay 198 | if (e.target === e.currentTarget) { 199 | toggleOpen(); 200 | } 201 | }, 202 | [toggleOpen] 203 | ); 204 | return ( 205 |
215 | {children} 216 |
217 | ); 218 | } 219 | export function NavbarContainer({ children, ...props }) { 220 | const ref = React.useRef(null); 221 | const { isOpen } = React.useContext(NavbarContext); 222 | const updateLinkStyles = React.useCallback( 223 | (entry) => { 224 | const { maxWidth: containerMaxWidth } = getComputedStyle(entry.target); 225 | document 226 | .querySelectorAll(".w-nav-menu>.w-dropdown,.w-nav-menu>.w-nav-link") 227 | .forEach((node) => { 228 | if (!(node instanceof HTMLElement)) return; 229 | if (!isOpen) { 230 | node.style.maxWidth = ""; 231 | return; 232 | } 233 | const { maxWidth } = getComputedStyle(node); 234 | node.style.maxWidth = 235 | !maxWidth || maxWidth === "none" ? containerMaxWidth : ""; 236 | }); 237 | }, 238 | [isOpen] 239 | ); 240 | useResizeObserver(ref, updateLinkStyles); 241 | return ( 242 | 243 | {children} 244 | 245 | ); 246 | } 247 | export function NavbarBrand({ className = "", ...props }) { 248 | return ; 249 | } 250 | export function NavbarMenu({ tag = "nav", className = "", ...props }) { 251 | const { getBodyHeight, animOver, isOpen, menu } = 252 | React.useContext(NavbarContext); 253 | return React.createElement(tag, { 254 | ...props, 255 | className: cj(className, "w-nav-menu"), 256 | ...(isOpen ? { "data-nav-menu-open": "" } : {}), 257 | style: animOver ? { height: getBodyHeight() } : {}, 258 | ref: menu, 259 | }); 260 | } 261 | export function NavbarLink({ className = "", ...props }) { 262 | const { isOpen } = React.useContext(NavbarContext); 263 | return ( 264 | 268 | ); 269 | } 270 | export function NavbarButton({ tag = "div", className = "", ...props }) { 271 | const { isOpen, toggleOpen } = React.useContext(NavbarContext); 272 | return React.createElement(tag, { 273 | ...props, 274 | "aria-label": "menu", 275 | "aria-expanded": isOpen ? "true" : "false", 276 | "aria-haspopup": "menu", 277 | "aria-controls": "w-nav-overlay", 278 | role: "button", 279 | tabIndex: 0, 280 | className: cj(className, "w-nav-button", isOpen && "w--open"), 281 | onClick: toggleOpen, 282 | }); 283 | } 284 | -------------------------------------------------------------------------------- /devlink/_Builtin/Slider.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { EASING_FUNCTIONS } from "../utils"; 3 | declare type SliderConfig = { 4 | navSpacing: number; 5 | navShadow: boolean; 6 | autoplay: boolean; 7 | delay: number; 8 | iconArrows: boolean; 9 | animation: "slide" | "cross" | "outin" | "fade" | "over"; 10 | navNumbers: boolean; 11 | easing: keyof typeof EASING_FUNCTIONS; 12 | navRound: boolean; 13 | hideArrows: boolean; 14 | disableSwipe: boolean; 15 | duration: number; 16 | infinite: boolean; 17 | autoMax: number; 18 | navInvert: boolean; 19 | }; 20 | declare type SlideState = { 21 | current: number; 22 | previous: number; 23 | }; 24 | export declare const SliderContext: React.Context< 25 | SliderConfig & { 26 | slideAmount: number; 27 | setSlideAmount: React.Dispatch>; 28 | slide: SlideState; 29 | setCurrentSlide: (current: number) => void; 30 | goToNextSlide: () => void; 31 | goToPreviousSlide: () => void; 32 | isAutoplayPaused: boolean; 33 | setAutoplayPause: React.Dispatch>; 34 | } 35 | >; 36 | declare type SliderChildrenType = 37 | | SliderSlideProps 38 | | SliderArrowProps 39 | | SliderNavProps 40 | | SliderMaskProps; 41 | declare type SliderWrapperProps = SliderConfig & { 42 | className?: string; 43 | children?: 44 | | React.ReactElement[] 45 | | React.ReactElement; 46 | }; 47 | export declare function SliderWrapper({ 48 | className, 49 | ...props 50 | }: SliderWrapperProps): JSX.Element; 51 | declare type SliderMaskProps = React.PropsWithChildren<{ 52 | className?: string; 53 | }>; 54 | export declare function SliderMask({ 55 | className, 56 | children, 57 | ...props 58 | }: SliderMaskProps): JSX.Element; 59 | declare type SliderSlideProps = React.PropsWithChildren<{ 60 | style?: React.CSSProperties; 61 | tag?: string; 62 | className?: string; 63 | index: number; 64 | }>; 65 | export declare function SliderSlide({ 66 | tag, 67 | className, 68 | style, 69 | index, 70 | ...props 71 | }: SliderSlideProps): React.DOMElement< 72 | { 73 | className: string; 74 | style: {}; 75 | "aria-label": string; 76 | role: string; 77 | ref: (node: any) => void; 78 | "aria-hidden": string; 79 | children?: React.ReactNode; 80 | }, 81 | any 82 | >; 83 | declare type SliderArrowProps = React.PropsWithChildren<{ 84 | className?: string; 85 | dir: "left" | "right"; 86 | }>; 87 | export declare function SliderArrow({ 88 | className, 89 | dir, 90 | children, 91 | ...props 92 | }: SliderArrowProps): JSX.Element; 93 | declare type SliderNavProps = { 94 | className?: string; 95 | }; 96 | export declare function SliderNav({ 97 | className, 98 | ...props 99 | }: SliderNavProps): JSX.Element; 100 | export {}; 101 | -------------------------------------------------------------------------------- /devlink/_Builtin/Tabs.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { EASING_FUNCTIONS } from "../utils"; 3 | import { Props } from "./Basic"; 4 | declare type TabsWrapperProps = Props< 5 | "div", 6 | { 7 | current: string; 8 | easing: keyof typeof EASING_FUNCTIONS; 9 | fadeIn: number; 10 | fadeOut: number; 11 | children?: 12 | | React.ReactElement[] 13 | | React.ReactElement; 14 | } 15 | >; 16 | export declare function TabsWrapper({ 17 | className, 18 | fadeIn, 19 | fadeOut, 20 | easing, 21 | current: initialCurrent, 22 | ...props 23 | }: TabsWrapperProps): JSX.Element; 24 | declare type TabsMenuProps = { 25 | tag?: React.ElementType; 26 | className?: string; 27 | children?: React.ReactElement[]; 28 | }; 29 | export declare function TabsMenu({ 30 | tag, 31 | className, 32 | ...props 33 | }: TabsMenuProps): React.ReactElement< 34 | any, 35 | string | React.JSXElementConstructor 36 | >; 37 | declare type TabsLinkProps = Props< 38 | "a", 39 | { 40 | "data-w-tab": string; 41 | } 42 | >; 43 | export declare function TabsLink({ 44 | className, 45 | ...props 46 | }: TabsLinkProps): JSX.Element; 47 | declare type TabsContentProps = { 48 | tag?: React.ElementType; 49 | className?: string; 50 | children?: 51 | | React.ReactElement[] 52 | | React.ReactElement; 53 | }; 54 | export declare function TabsContent({ 55 | tag, 56 | className, 57 | ...props 58 | }: TabsContentProps): React.ReactElement< 59 | any, 60 | string | React.JSXElementConstructor 61 | >; 62 | declare type TabsPaneProps = React.PropsWithChildren<{ 63 | tag?: React.ElementType; 64 | className?: string; 65 | "data-w-tab": string; 66 | }>; 67 | export declare function TabsPane({ 68 | tag, 69 | className, 70 | ...props 71 | }: TabsPaneProps): React.ReactElement< 72 | any, 73 | string | React.JSXElementConstructor 74 | >; 75 | export {}; 76 | -------------------------------------------------------------------------------- /devlink/_Builtin/Tabs.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { triggerIXEvent } from "../interactions"; 3 | import { cj, debounce, EASING_FUNCTIONS, useLayoutEffect } from "../utils"; 4 | const tabsContext = React.createContext({ 5 | current: "", 6 | onTabClick: () => {}, 7 | onLinkKeyDown: () => {}, 8 | }); 9 | export function TabsWrapper({ 10 | className = "", 11 | fadeIn, 12 | fadeOut, 13 | easing, 14 | current: initialCurrent, 15 | ...props 16 | }) { 17 | const [current, setCurrent] = React.useState(""); 18 | const changeTab = React.useCallback( 19 | (next) => { 20 | const currentTab = document.querySelector( 21 | `.w-tab-pane[data-w-tab="${current}"]` 22 | ); 23 | const nextTab = document.querySelector( 24 | `.w-tab-pane[data-w-tab="${next}"]` 25 | ); 26 | const easingFn = EASING_FUNCTIONS[easing] ?? "ease"; 27 | const animation = currentTab?.animate([{ opacity: 1 }, { opacity: 0 }], { 28 | duration: fadeOut, 29 | fill: "forwards", 30 | easing: easingFn, 31 | }); 32 | if (animation) { 33 | animation.onfinish = () => { 34 | setCurrent(next); 35 | nextTab?.animate([{ opacity: 0 }, { opacity: 1 }], { 36 | duration: fadeIn, 37 | fill: "forwards", 38 | easing: easingFn, 39 | }); 40 | }; 41 | } else { 42 | setCurrent(next); 43 | } 44 | }, 45 | [current, easing, fadeIn, fadeOut] 46 | ); 47 | // Trigger first tab change manually 48 | const firstRender = React.useRef(true); 49 | useLayoutEffect(() => { 50 | if (!firstRender.current) return; 51 | firstRender.current = false; 52 | setTimeout(() => { 53 | changeTab(initialCurrent); 54 | }, 1); 55 | }, [changeTab, initialCurrent]); 56 | const onTabClick = debounce(changeTab); 57 | const onLinkKeyDown = debounce((event) => { 58 | event.preventDefault(); 59 | const currentTab = document.querySelector( 60 | `.w-tab-pane[data-w-tab="${current}"]` 61 | ); 62 | const allTabs = document.querySelectorAll(".w-tab-pane"); 63 | const firstTab = allTabs[0]; 64 | const lastTab = allTabs[allTabs.length - 1]; 65 | const nextTab = (() => { 66 | switch (event.key) { 67 | case "ArrowUp": 68 | case "ArrowLeft": 69 | return currentTab.previousElementSibling ?? lastTab; 70 | case "ArrowDown": 71 | case "ArrowRight": 72 | return currentTab.nextElementSibling ?? firstTab; 73 | case "Home": 74 | return firstTab; 75 | case "End": 76 | return lastTab; 77 | } 78 | })(); 79 | if (nextTab) changeTab(nextTab.getAttribute("data-w-tab")); 80 | }); 81 | return ( 82 | 83 |
84 | 85 | ); 86 | } 87 | export function TabsMenu({ tag = "div", className = "", ...props }) { 88 | return React.createElement(tag, { 89 | ...props, 90 | className: cj(className, "w-tab-menu"), 91 | role: "tablist", 92 | }); 93 | } 94 | export function TabsLink({ className = "", ...props }) { 95 | const { current, onTabClick, onLinkKeyDown } = React.useContext(tabsContext); 96 | const isCurrent = current === props["data-w-tab"]; 97 | const ref = React.useCallback( 98 | (node) => { 99 | if (!node) return; 100 | triggerIXEvent(node, isCurrent); 101 | }, 102 | [isCurrent] 103 | ); 104 | return ( 105 | onTabClick(props["data-w-tab"])} 114 | onKeyDown={onLinkKeyDown} 115 | role="tab" 116 | tabIndex={isCurrent ? 0 : -1} 117 | aria-selected={isCurrent} 118 | aria-controls={props["data-w-tab"]} 119 | /> 120 | ); 121 | } 122 | export function TabsContent({ tag = "div", className = "", ...props }) { 123 | return React.createElement(tag, { 124 | ...props, 125 | className: cj(className, "w-tab-content"), 126 | }); 127 | } 128 | export function TabsPane({ tag = "div", className = "", ...props }) { 129 | const { current } = React.useContext(tabsContext); 130 | const isCurrent = current === props["data-w-tab"]; 131 | return React.createElement(tag, { 132 | ...props, 133 | className: cj(className, "w-tab-pane", isCurrent && "w--tab-active"), 134 | role: "tabpanel", 135 | "aria-labelledby": props["data-w-tab"], 136 | }); 137 | } 138 | -------------------------------------------------------------------------------- /devlink/_Builtin/Twitter.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | declare type TwitterSize = "m" | "l"; 3 | declare type TwitterMode = "follow" | "tweet"; 4 | declare type TwitterProps = React.PropsWithChildren<{ 5 | className?: string; 6 | mode?: TwitterMode; 7 | url?: string; 8 | text?: string; 9 | size?: TwitterSize; 10 | }>; 11 | declare global { 12 | interface Window { 13 | twttr: any; 14 | } 15 | } 16 | export declare function Twitter({ 17 | className, 18 | url, 19 | mode, 20 | size, 21 | text, 22 | ...props 23 | }: TwitterProps): JSX.Element; 24 | export {}; 25 | -------------------------------------------------------------------------------- /devlink/_Builtin/Twitter.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { isUrl, loadScript } from "../utils"; 3 | const modeDict = { 4 | follow: "createFollowButton", 5 | tweet: "createShareButton", 6 | }; 7 | const sizeDict = { 8 | m: "medium", 9 | l: "large", 10 | }; 11 | export function Twitter({ 12 | className = "", 13 | url = "https://webflow.com", 14 | mode = "tweet", 15 | size = "m", 16 | text = "Check out this site", 17 | ...props 18 | }) { 19 | const ref = React.useRef(null); 20 | if (!isUrl(url)) { 21 | if (mode === "tweet") { 22 | url = "https://webflow.com/"; 23 | } else if (mode === "follow") { 24 | url = "webflow"; 25 | } 26 | } 27 | React.useEffect(() => { 28 | let isComponentMounted = true; 29 | loadScript("https://platform.twitter.com/widgets.js").then(() => { 30 | if (isComponentMounted) { 31 | if (window.twttr) { 32 | const twitterButtonOption = window.twttr.widgets[modeDict[mode]]; 33 | if (twitterButtonOption) { 34 | twitterButtonOption(url, ref?.current, { 35 | size: sizeDict[size], 36 | text, 37 | }); 38 | } 39 | } 40 | } 41 | }); 42 | return () => { 43 | isComponentMounted = false; 44 | }; 45 | }, []); 46 | return ( 47 |
52 | ); 53 | } 54 | -------------------------------------------------------------------------------- /devlink/_Builtin/Typography.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | export function Heading({ tag = "h1", ...props }) { 3 | return React.createElement(tag, props); 4 | } 5 | export function Paragraph(props) { 6 | return React.createElement("p", props); 7 | } 8 | export function Emphasized(props) { 9 | return ; 10 | } 11 | export function Strong(props) { 12 | return React.createElement("strong", props); 13 | } 14 | export function Figure({ className = "", figure, ...props }) { 15 | const { type, align } = figure; 16 | if (align) { 17 | className += `w-richtext-align-${align} `; 18 | } 19 | if (type) { 20 | className += `w-richtext-align-${type} `; 21 | } 22 | return
; 23 | } 24 | export function Figcaption(props) { 25 | return
; 26 | } 27 | export function Subscript(props) { 28 | return ; 29 | } 30 | export function Superscript(props) { 31 | return ; 32 | } 33 | export function RichText({ tag = "div", className = "", ...props }) { 34 | return React.createElement(tag, { 35 | className: className + " w-richtext", 36 | ...props, 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /devlink/_Builtin/Video.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Embed } from "../types"; 3 | declare type VideoProps = { 4 | className?: string; 5 | options: Embed.Video; 6 | }; 7 | export declare function Video({ 8 | className, 9 | options, 10 | ...props 11 | }: VideoProps): JSX.Element; 12 | export {}; 13 | -------------------------------------------------------------------------------- /devlink/_Builtin/Video.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { cj } from "../utils"; 3 | const getAspectRatio = ({ width, height }) => 4 | height && width ? height / width : 0; 5 | export function Video({ 6 | className = "", 7 | options = { height: 0, width: 0, title: "", url: "" }, 8 | ...props 9 | }) { 10 | const { height, title, url, width } = options; 11 | return ( 12 |
17 |