mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-09-02 22:02:39 +02:00
Add advertisement page
This commit is contained in:
227
src/components/AdvertiseForm.tsx
Normal file
227
src/components/AdvertiseForm.tsx
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { CheckIcon } from './ReactIcons/CheckIcon.tsx';
|
||||||
|
import { pageProgressMessage } from '../stores/page.ts';
|
||||||
|
import { httpPost } from '../lib/http.ts';
|
||||||
|
|
||||||
|
type InputProps = {
|
||||||
|
label: string;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
value: string;
|
||||||
|
onChange: (
|
||||||
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||||
|
) => void;
|
||||||
|
required?: boolean;
|
||||||
|
rows?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
function Input(props: InputProps) {
|
||||||
|
const { label, name, type, value, onChange, required, rows } = props;
|
||||||
|
return (
|
||||||
|
<div className="mb-4">
|
||||||
|
<label htmlFor={name} className="block text-sm font-medium text-gray-700">
|
||||||
|
{label} {required && <span className="text-red-500">*</span>}
|
||||||
|
</label>
|
||||||
|
{type === 'textarea' ? (
|
||||||
|
<textarea
|
||||||
|
placeholder={label}
|
||||||
|
id={name}
|
||||||
|
name={name}
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
rows={rows}
|
||||||
|
className="mt-1 block w-full rounded-md border border-gray-300 p-2 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
|
||||||
|
autoComplete="off"
|
||||||
|
data-1p-ignore=""
|
||||||
|
data-form-type="other"
|
||||||
|
data-lpignore="true"
|
||||||
|
></textarea>
|
||||||
|
) : (
|
||||||
|
<input
|
||||||
|
type={type}
|
||||||
|
id={name}
|
||||||
|
placeholder={label}
|
||||||
|
name={name}
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
required={required}
|
||||||
|
className="mt-1 block w-full rounded-md border border-gray-300 p-2 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
|
||||||
|
autoComplete="off"
|
||||||
|
data-1p-ignore=""
|
||||||
|
data-form-type="other"
|
||||||
|
data-lpignore="true"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AdvertiseForm() {
|
||||||
|
const [status, setStatus] = useState<'submitting' | 'submitted'>();
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
firstName: '',
|
||||||
|
lastName: '',
|
||||||
|
title: '',
|
||||||
|
company: '',
|
||||||
|
email: '',
|
||||||
|
phone: '',
|
||||||
|
message: '',
|
||||||
|
updates: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleInputChange = (
|
||||||
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||||
|
) => {
|
||||||
|
const { name, value, type, checked } = e.target as any;
|
||||||
|
setFormData({
|
||||||
|
...formData,
|
||||||
|
[name]: type === 'checkbox' ? checked : value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
async function handleSubmit(e: React.FormEvent) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
pageProgressMessage.set('Please wait');
|
||||||
|
|
||||||
|
// Placeholder function to send data
|
||||||
|
console.log('Form data:', formData);
|
||||||
|
|
||||||
|
const { response, error } = await httpPost(
|
||||||
|
`${import.meta.env.PUBLIC_API_URL}/v1-advertise`,
|
||||||
|
formData,
|
||||||
|
);
|
||||||
|
if (!response || error) {
|
||||||
|
pageProgressMessage.set('');
|
||||||
|
setError(error?.message || 'Something went wrong. Please try again.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setStatus('submitted');
|
||||||
|
pageProgressMessage.set('');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status === 'submitted') {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center rounded-md border bg-gray-50 p-12 text-center">
|
||||||
|
<CheckIcon additionalClasses="h-12 w-12 text-green-500 mb-5" />
|
||||||
|
<h2 className="text-balance text-xl font-semibold text-gray-900">
|
||||||
|
Thank you for your interest in advertising with roadmap.sh
|
||||||
|
</h2>
|
||||||
|
<p className="mt-2 text-sm text-gray-500">
|
||||||
|
We will get back to you soon.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2 className="mb-5 text-balance text-2xl font-bold">
|
||||||
|
Ready to learn more? Fill out the form below to get started!
|
||||||
|
</h2>
|
||||||
|
{error && (
|
||||||
|
<div className="relative mb-4 rounded border border-red-400 bg-red-100 px-4 py-3 text-red-700">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<form className="mb-5" onSubmit={handleSubmit}>
|
||||||
|
<div className="grid gap-0 sm:grid-cols-2 sm:gap-4">
|
||||||
|
<Input
|
||||||
|
label="First Name"
|
||||||
|
name="firstName"
|
||||||
|
type="text"
|
||||||
|
value={formData.firstName}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
label="Last Name"
|
||||||
|
name="lastName"
|
||||||
|
type="text"
|
||||||
|
value={formData.lastName}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid gap-0 sm:grid-cols-2 sm:gap-4">
|
||||||
|
<Input
|
||||||
|
label="Title"
|
||||||
|
name="title"
|
||||||
|
type="text"
|
||||||
|
value={formData.title}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label="Company"
|
||||||
|
name="company"
|
||||||
|
type="text"
|
||||||
|
value={formData.company}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid gap-0 sm:grid-cols-2 sm:gap-4">
|
||||||
|
<Input
|
||||||
|
label="Email"
|
||||||
|
name="email"
|
||||||
|
type="email"
|
||||||
|
value={formData.email}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label="Phone"
|
||||||
|
name="phone"
|
||||||
|
type="tel"
|
||||||
|
value={formData.phone}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label="Message (Optional)"
|
||||||
|
name="message"
|
||||||
|
type="textarea"
|
||||||
|
value={formData.message}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
rows={4}
|
||||||
|
/>
|
||||||
|
<div className="mb-4 flex items-start">
|
||||||
|
<div className="flex h-5 items-center">
|
||||||
|
<input
|
||||||
|
id="updates"
|
||||||
|
name="updates"
|
||||||
|
type="checkbox"
|
||||||
|
checked={formData.updates}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="ml-3 text-sm">
|
||||||
|
<label htmlFor="updates" className="font-medium text-gray-700">
|
||||||
|
I want to receive occasional updates about new products or
|
||||||
|
advertising opportunities with roadmap.sh
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="flex justify-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
|
||||||
|
>
|
||||||
|
Send
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@@ -35,8 +35,8 @@ import Icon from './AstroIcon.astro';
|
|||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class='flex flex-col justify-between gap-12 sm:flex-row'>
|
<div class='flex flex-col justify-between gap-8 lg:gap-2 lg:flex-row'>
|
||||||
<div class='max-w-[365px]'>
|
<div class='max-w-[425px]'>
|
||||||
<p class='text-md flex items-center'>
|
<p class='text-md flex items-center'>
|
||||||
<a
|
<a
|
||||||
class='inline-flex items-center text-lg font-medium text-white transition-colors hover:text-gray-400'
|
class='inline-flex items-center text-lg font-medium text-white transition-colors hover:text-gray-400'
|
||||||
@@ -56,7 +56,7 @@ import Icon from './AstroIcon.astro';
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<p class='my-4 text-slate-300/60'>
|
<p class='my-4 text-slate-300/60'>
|
||||||
Community created roadmaps, articles, resources and journeys to help
|
Community created roadmaps, best practices, projects, articles, resources and journeys to help
|
||||||
you choose your path and grow in your career.
|
you choose your path and grow in your career.
|
||||||
</p>
|
</p>
|
||||||
<div class='text-sm text-gray-400'>
|
<div class='text-sm text-gray-400'>
|
||||||
@@ -67,6 +67,8 @@ import Icon from './AstroIcon.astro';
|
|||||||
<span class='mx-1.5'>·</span>
|
<span class='mx-1.5'>·</span>
|
||||||
<a href='/privacy' class='hover:text-white'>Privacy</a>
|
<a href='/privacy' class='hover:text-white'>Privacy</a>
|
||||||
<span class='mx-1.5'>·</span>
|
<span class='mx-1.5'>·</span>
|
||||||
|
<a href='/advertise' class='hover:text-white'>Advertise</a>
|
||||||
|
<span class='mx-1.5'>·</span>
|
||||||
<a
|
<a
|
||||||
aria-label='Write us an email'
|
aria-label='Write us an email'
|
||||||
href='mailto:info@roadmap.sh'
|
href='mailto:info@roadmap.sh'
|
||||||
@@ -97,20 +99,19 @@ import Icon from './AstroIcon.astro';
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class='max-w-[365px] text-left sm:text-right'>
|
<div class='max-w-[340px] text-left lg:text-right'>
|
||||||
<a href='https://thenewstack.io' target='_blank'>
|
<a href='https://thenewstack.io' target='_blank'>
|
||||||
<img
|
<img
|
||||||
src='/images/tns-sm.png'
|
src='/images/tns-sm.png'
|
||||||
alt='ThewNewStack'
|
alt='ThewNewStack'
|
||||||
class='my-1.5 mr-auto sm:ml-auto sm:mr-0'
|
class='my-1.5 mr-auto lg:ml-auto lg:mr-0'
|
||||||
width='200'
|
width='200'
|
||||||
height='24.8'
|
height='24.8'
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
<p class='my-4 text-slate-300/60'>
|
<p class='my-4 text-slate-300/60'>
|
||||||
The leading DevOps resource for Kubernetes, cloud-native computing,
|
The top DevOps resource for Kubernetes, cloud-native computing, and large-scale development and deployment.
|
||||||
and the latest in at-scale development, deployment, and management.
|
|
||||||
</p>
|
</p>
|
||||||
<div class='text-sm text-gray-400'>
|
<div class='text-sm text-gray-400'>
|
||||||
<p>
|
<p>
|
||||||
|
@@ -62,6 +62,12 @@ const links = [
|
|||||||
Icon: Shirt,
|
Icon: Shirt,
|
||||||
isExternal: true,
|
isExternal: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
link: '/advertise',
|
||||||
|
label: 'Advertise',
|
||||||
|
description: 'Promote your product or service',
|
||||||
|
Icon: Menu,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export function NavigationDropdown() {
|
export function NavigationDropdown() {
|
||||||
|
39
src/pages/advertise.astro
Normal file
39
src/pages/advertise.astro
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||||
|
import { getRepositoryRank } from '../lib/github.ts';
|
||||||
|
import { AdvertiseForm } from '../components/AdvertiseForm';
|
||||||
|
---
|
||||||
|
|
||||||
|
<BaseLayout title='About roadmap.sh' permalink={'/about'}>
|
||||||
|
<div class='bg-white py-8 sm:py-20'>
|
||||||
|
<div class='container'>
|
||||||
|
<div class='mb-2 sm:mb-8 flex items-center'>
|
||||||
|
<div>
|
||||||
|
<h1 class='mb-0 sm:mb-3 text-2xl font-bold sm:text-4xl'>
|
||||||
|
Advertise with roadmap.sh
|
||||||
|
</h1>
|
||||||
|
<p class='text-lg sm:text-xl text-gray-500'>
|
||||||
|
The best way to reach developers
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class='mb-5'>
|
||||||
|
With hundreds of thousands of monthly visitors and over 1 million
|
||||||
|
registered users, roadmap.sh is the resource developers choose to skill
|
||||||
|
up and advance their careers. This community effort creates guides and
|
||||||
|
educational content where developers can choose their path to success.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class='mb-4 sm:mb-9'>
|
||||||
|
<span class='font-bold'>roadmap.sh</span> also provides opportunities to
|
||||||
|
advertise to developers where your message stands out on our platform to
|
||||||
|
generate valuable results. Do more with your budget and achieve your marketing
|
||||||
|
goals by targeting your ideal segments of our developer audience. Don’t wait
|
||||||
|
to get your message in front of aspirational developers.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<AdvertiseForm client:load />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BaseLayout>
|
Reference in New Issue
Block a user