Skip to content

Commit c10964c

Browse files
committed
Jobs Board Section
1 parent ceffb0f commit c10964c

File tree

9 files changed

+677
-3
lines changed

9 files changed

+677
-3
lines changed

src/_includes/components/button.njk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
{% set bg_class = "bg-pycon-lime hover:bg-pycon-lime/90" %}
44
{% set text_class = "text-black" %}
55
{% else %}
6-
{% set bg_class = "bg-transparent border-pycon-lime" %}
7-
{% set text_class = "text-pycon-lime" %}
6+
{% set bg_class = "bg-pycon-purple hover:bg-pycon-purple/90" %}
7+
{% set text_class = "text-black" %}
88
{% endif %}
99

1010
<a

src/_includes/components/dropdown.njk

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{% macro renderDropdown(question) %}
2+
<div class="space-y-4">
3+
<div class="bg-white shadow-lg rounded-md overflow-hidden">
4+
<button
5+
class="w-full text-left p-4 font-semibold text-lg flex justify-between items-center relative overflow-hidden group hover:bg-[#8385F2] hover:text-white focus:outline-none transition-colors duration-300"
6+
onclick="
7+
const answer = this.nextElementSibling;
8+
const icon = this.querySelector('svg');
9+
answer.classList.toggle('hidden');
10+
icon.classList.toggle('rotate-180');
11+
12+
if (!answer.classList.contains('hidden')) {
13+
this.classList.add('bg-[#8385F2]', 'text-white');
14+
} else {
15+
this.classList.remove('bg-[#8385F2]', 'text-white');
16+
}
17+
"
18+
>
19+
<span class="relative z-10">{{ question }}</span>
20+
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 transition-transform duration-300 relative z-10 text-gray-800" fill="none" viewBox="0 0 24 24" stroke="currentColor">
21+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
22+
</svg>
23+
</button>
24+
<div class="hidden p-2 text-black border-t text-justify border-gray-200">
25+
{{ caller() }}
26+
</div>
27+
</div>
28+
</div>
29+
{% endmacro %}

src/_includes/navbar.njk

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@
77
</a>
88
<ul class="flex items-center justify-center w-full gap-8 relative mb-0">
99
{% set menuItems = [
10+
{
11+
"name": "About",
12+
"hasSubmenu": true,
13+
"submenu": [
14+
{"name": "FAQ's", "link": "about/faqs"},
15+
{"name": "Jobs Board", "link": "about/job/"}
16+
]
17+
},
1018
{
1119
"name": "CFP",
1220
"link": "cfp",

src/about/faqs.njk

Lines changed: 346 additions & 0 deletions
Large diffs are not rendered by default.

src/about/job/guidelines.njk

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
---
2+
title: Job Board - Rules and Guildelines
3+
description: PyCon India 2025 Job Board
4+
layout: base.njk
5+
---
6+
7+
<div class="w-full h-auto bg-pycon-blue -mb-24 px-[6%] flex flex-col md:flex-row">
8+
<div class="pt-32 pb-8 md:pb-32 w-full lg:w-[70%]">
9+
<div class="black-han-sans-regular font-normal text-3xl md:text-5xl md:text-center text-[#FFFFFF] text-center lg:text-left">
10+
Job Board - Rules and Guidelines
11+
</div>
12+
</div>
13+
<div class="lg:w-[30%] w-[80%] lg:mt-60 flex items-center justify-center mx-auto">
14+
<img src="{{ env.baseUrl }}img/assets/notepad.svg" alt="Guide" class="w-[40%] lg:w-[60%] transition-transform duration-100" style="animation: floating 2s ease-in-out infinite;">
15+
<img src="{{ env.baseUrl }}img/assets/book-stars.svg" alt="Guide" class="w-[40%] lg:w-[60%] transition-transform duration-100" style="animation: floating 2s ease-in-out infinite;">
16+
</div>
17+
</div>
18+
19+
20+
<div class="main-container pt-16 md:pt-48 bg-lavender w-full h-auto px-[6%]">
21+
<div class="pb-40 md:pb-60 lg:pb-[20%] w-full text-justify lg:w-[70%]">
22+
<div class="text-md lg:text-xl font-light">
23+
<div class="pt-8">
24+
<p class="text-2xl font-bold flex items-center"><span><img src="{{ env.baseUrl }}img/assets/square-lime.svg" alt="Bullet Icon" class="w-5 mr-2"></span>Job Submission & Approval:</p>
25+
<ul class="list-none pt-4 space-y-4">
26+
<li class="flex">
27+
<img src="{{ env.baseUrl }}img/assets/circle-purple.svg" alt="Bullet Icon" class="w-4 h-4 mr-2 mt-2">
28+
<span>We do not impose any restrictions on the industry/technology of the submitted jobs. Any jobs that are helpful to the community are welcome.</span>
29+
</li>
30+
<li class="flex">
31+
<img src="{{ env.baseUrl }}img/assets/circle-purple.svg" alt="Bullet Icon" class="w-4 h-4 mr-2 mt-2">
32+
<span>After successful job submission, each job will undergo a verification process by the PyCon India 2025 team to ensure there are no spam postings.</span>
33+
</li>
34+
<li class="flex">
35+
<img src="{{ env.baseUrl }}img/assets/circle-purple.svg" alt="Bullet Icon" class="w-4 h-4 mr-2 mt-2">
36+
<span>The approval process may take approximately 2-3 hours.</span>
37+
</li>
38+
<li class="flex">
39+
<img src="{{ env.baseUrl }}img/assets/circle-purple.svg" alt="Bullet Icon" class="w-4 h-4 mr-2 mt-2">
40+
<span>Approved jobs will be made visible on the job board once they pass the verification process.</span>
41+
</li>
42+
<li class="flex">
43+
<img src="{{ env.baseUrl }}img/assets/circle-purple.svg" alt="Bullet Icon" class="w-4 h-4 mr-2 mt-1">
44+
<span>Submissions that do not meet the guidelines may be rejected.</span>
45+
</li>
46+
</ul>
47+
</div>
48+
49+
<div class="pt-8">
50+
<p class="text-2xl font-bold flex items-center"><span><img src="{{ env.baseUrl }}img/assets/square-lime.svg" alt="Bullet Icon" class="w-5 mr-2"></span>Job Posts Order:</p>
51+
<ul class="list-none pt-4 space-y-4">
52+
<li class="flex">
53+
<img src="{{ env.baseUrl }}img/assets/circle-purple.svg" alt="Bullet Icon" class="w-4 h-4 mr-2 mt-2">
54+
<span>Job posts are sorted based on the timestamp they are submitted. The first job submitted will be visible first, followed by subsequent submissions in chronological order.</span>
55+
</li>
56+
</ul>
57+
</div>
58+
59+
<div class="pt-8">
60+
<p class="text-2xl font-bold flex items-center"><span><img src="{{ env.baseUrl }}img/assets/square-lime.svg" alt="Bullet Icon" class="w-5 mr-2"></span>Transparency:</p>
61+
<ul class="list-none pt-4 space-y-4">
62+
<li class="flex">
63+
<img src="{{ env.baseUrl }}img/assets/circle-purple.svg" alt="Bullet Icon" class="w-4 h-4 mr-2 mt-2">
64+
<span>After successful job submission, each job will undergo a verification process by the PyCon India 2025 team to ensure there are no spam postings.</span>
65+
</li>
66+
<li class="flex">
67+
<img src="{{ env.baseUrl }}img/assets/circle-purple.svg" alt="Bullet Icon" class="w-4 h-4 mr-2 mt-2">
68+
<span>Job seekers and companies are encouraged to communicate directly with each other for job-related inquiries, applications, and hiring decisions.</span>
69+
</li>
70+
</ul>
71+
</div>
72+
73+
<div class="pt-8">
74+
<p class="text-2xl font-bold flex items-center"><span><img src="{{ env.baseUrl }}img/assets/square-lime.svg" alt="Bullet Icon" class="w-5 mr-2"></span>Content Moderation:</p>
75+
<ul class="list-none pt-4 space-y-4">
76+
<li class="flex">
77+
<img src="{{ env.baseUrl }}img/assets/circle-purple.svg" alt="Bullet Icon" class="w-4 h-4 mr-2 mt-2">
78+
<span>PyCon India 2025 reserves the right to moderate and remove job posts that violate submission guidelines or community standards.</span>
79+
</li>
80+
<li class="flex">
81+
<img src="{{ env.baseUrl }}img/assets/circle-purple.svg" alt="Bullet Icon" class="w-4 h-4 mr-2 mt-2">
82+
<span>Users are encouraged to report any inappropriate content or issues with job posts for review to our team at <a href="mailto:[email protected]" target="_blank" rel="noopener noreferrer" class="underline">[email protected]</a>.</span>
83+
</li>
84+
</ul>
85+
</div>
86+
87+
<div class="pt-8">
88+
<p class="text-2xl font-bold flex items-center"><span><img src="{{ env.baseUrl }}img/assets/square-lime.svg" alt="Bullet Icon" class="w-5 mr-2"></span>Respect and Inclusivity:</p>
89+
<ul class="list-none pt-4 space-y-4">
90+
<li class="flex">
91+
<img src="{{ env.baseUrl }}img/assets/circle-purple.svg" alt="Bullet Icon" class="w-4 h-4 mr-2 mt-2">
92+
<span>Users are expected to maintain a respectful and inclusive environment when interacting with job listings or other users on the platform.</span>
93+
</li>
94+
<li class="flex">
95+
<img src="{{ env.baseUrl }}img/assets/circle-purple.svg" alt="Bullet Icon" class="w-4 h-4 mr-2 mt-2">
96+
<span>Any kind of disrespectful, discriminatory, or offensive behavior against any party will not be tolerated.</span>
97+
</li>
98+
<li class="flex">
99+
<img src="{{ env.baseUrl }}img/assets/circle-purple.svg" alt="Bullet Icon" class="w-4 h-4 mr-2 mt-2">
100+
<span>Please make sure to follow PyCon India's <a href="{{ env.baseUrl }}coc/guidelines" class="underline text-pycon-blue">Code of Conduct</a>.</span>
101+
</li>
102+
<li class="flex">
103+
<img src="{{ env.baseUrl }}img/assets/circle-purple.svg" alt="Bullet Icon" class="w-4 h-4 mr-2 mt-2">
104+
<span>If you feel unsafe during any of the interactions, or feel like someone is violating the rules, please <a href="{{ env.baseUrl }}coc/reporting" class="underline text-pycon-blue">report the incident to the CoC Workgroup</a>.</span>
105+
</li>
106+
</ul>
107+
</div>
108+
</div>
109+
</div>
110+
</div>

src/about/job/job.njk

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
---
2+
title: Job Board - Pycon India 2025
3+
description: PyCon India 2025 Job Board
4+
layout: base.njk
5+
---
6+
7+
{% from "components/flat-card.njk" import flatCard %}
8+
{% from "components/button.njk" import button %}
9+
10+
<div class="w-full h-auto bg-pycon-blue px-[6%] pb-32 flex flex-col md:flex-row">
11+
<div class="pt-32 pb-8 md:pb-32 w-full lg:w-[70%]">
12+
<div class="black-han-sans-regular font-normal text-4xl md:text-5xl md:text-center text-[#FFFFFF] text-center lg:text-left">
13+
Job Board
14+
</div>
15+
<div class="pt-10 font-light text-lg md:text-2xl md:text-center text-white text-center lg:text-left">
16+
<p class="mb-0">Submit your job posting <a href="https://docs.google.com/forms/d/e/1FAIpQLSce8d2wOm976llzPUlF3NXzfx4K7zPamnxHSGWup1HDKMA-3g/viewform?usp=dialog" target="_blank" rel="noopener noreferrer" class="underline">here</a></p>
17+
<p>Check out the <a href="{{ env.baseUrl }}about/job/guidelines/" class="underline">rules and guidelines</a> </p>
18+
</div>
19+
</div>
20+
<div class="lg:w-[30%] w-[80%] lg:mt-40 flex items-center justify-center mx-auto">
21+
<img src="/img/assets/abstract-obj.svg" alt="Guide" class="w-[40%] lg:w-[60%] transition-transform duration-100" style="animation: floating 2s ease-in-out infinite;">
22+
<img src="/img/assets/star-lime-vector.svg" alt="Guide" class="w-[10%] lg:w-[10%] transition-transform duration-100" style="animation: floating 2s ease-in-out infinite;">
23+
</div>
24+
</div>
25+
26+
<div class="job-container bg-lavender w-full h-auto -pt-20 px-[6%] pb-72 md:pb-40 relative">
27+
<div id="job-postings-grid" class="flex flex-wrap -mt-24 -mx-4">
28+
<div class="w-full lg:w-1/3 px-4 flex flex-col gap-8" id="column-0"></div>
29+
<div class="w-full pt-8 lg:pt-16 lg:w-1/3 px-4 flex flex-col gap-8" id="column-1"></div>
30+
<div class="w-full pt-8 lg:pt-0 lg:w-1/3 px-4 flex flex-col gap-8" id="column-2"></div>
31+
</div>
32+
</div>
33+
34+
<script>
35+
document.addEventListener("DOMContentLoaded", async () => {
36+
const baseUrl = "{{ env.baseUrl }}";
37+
38+
const SPREADSHEET_ID = "1oyMFGGKmR6u5JVpd691iYD_6TuDi3pbvyaajAZfGkGw";
39+
const URL = `https://docs.google.com/spreadsheets/d/${SPREADSHEET_ID}/gviz/tq?tqx=out:json`;
40+
41+
const columnIds = ["column-0", "column-1", "column-2"];
42+
const columns = columnIds.map((id) => document.getElementById(id));
43+
44+
columns[0].innerHTML = '<p class="text-white">Loading job postings...</p>';
45+
46+
const renderJobCard = (job_post, index) => {
47+
const bg_color = (index % 2 === 1) ? 'bg-pycon-lime' : 'bg-pycon-purple';
48+
const button_color = bg_color === "bg-pycon-purple" ? "bg-pycon-lime" : "bg-pycon-purple";
49+
50+
return `
51+
<div class="relative group w-full max-w-full border border-black ${bg_color} p-8">
52+
<div class="text-3xl font-semibold">${job_post.title}</div>
53+
<div class="pt-4">
54+
<span class="text-2xl">
55+
<a href="${job_post.company_website}" target="_blank" class="underline">
56+
${job_post.company}
57+
</a>
58+
</span>
59+
<p class="pt-8 flex items-center gap-x-2 mb-0">
60+
<i class="fa-solid fa-briefcase text-xl text-[#475569]"></i>
61+
<span>${job_post.job_type}</span>
62+
<i class="fa-solid fa-location-dot text-xl text-[#475569]"></i>
63+
<span>${job_post.location}</span>
64+
</p>
65+
</div>
66+
<div class="pt-2 text-gray-700">
67+
<p class="text-justify">${job_post.description}</p>
68+
</div>
69+
<div class="pt-4">
70+
<a
71+
href="${job_post.link_to_apply || '#'}"
72+
target="_blank"
73+
class="group no-underline inline-flex items-center gap-2 px-4 py-2 ${
74+
bg_color === 'bg-pycon-purple' ? 'bg-pycon-lime hover:bg-pycon-lime/90' : 'bg-pycon-purple hover:bg-pycon-purple/90'
75+
} rounded-full border border-black hover:-translate-y-0.5 hover:shadow-md transition-all duration-300 focus:outline-2 focus:outline-offset-2"
76+
>
77+
<span class="font-['Acid_Grotesk'] text-lg ${
78+
bg_color === 'bg-pycon-purple' ? 'text-black' : 'text-black'
79+
} leading-relaxed whitespace-nowrap group-hover:-translate-x-1 transition-transform duration-200">
80+
Apply
81+
</span>
82+
<div class="flex justify-center items-center w-8 h-8 bg-white rounded-full border border-black group-hover:rotate-40 transition-transform duration-300">
83+
<img src="${baseUrl}img/assets/arrow-vector.svg" alt="Arrow" class="w-4 h-3 group-hover:scale-110 transition-transform duration-300" />
84+
</div>
85+
</a>
86+
</div>
87+
</div>
88+
`;
89+
};
90+
91+
try {
92+
const response = await fetch(URL);
93+
const text = await response.text();
94+
95+
const jsonString = text.substring(47).slice(0, -2);
96+
const json = JSON.parse(jsonString);
97+
const rows = json.table.rows;
98+
99+
const ensureHttps = (url) => {
100+
if (!/^https?:\/\//.test(url)) {
101+
return `https://${url}`;
102+
}
103+
return url;
104+
};
105+
106+
const isValidUrl = (url) => {
107+
const pattern = /^(https?:\/\/)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}(:\d+)?(\/.*)?$/;
108+
return pattern.test(url);
109+
};
110+
111+
const jobPostings = rows.map((row) => ({
112+
title: row.c[1]?.v || "No title",
113+
company: row.c[2]?.v || "Unknown",
114+
company_website: row.c[3]?.v || "#",
115+
job_type: row.c[4]?.v || "N/A",
116+
location: row.c[5]?.v || "Unknown",
117+
description: row.c[6]?.v || "No description available",
118+
link_to_apply: row.c[7]?.v || "#",
119+
}))
120+
.filter((job_post) =>
121+
isValidUrl(job_post.company_website) &&
122+
isValidUrl(job_post.link_to_apply)
123+
);
124+
125+
columns[0].innerHTML = "";
126+
127+
if (jobPostings.length === 0) {
128+
columns[0].innerHTML = `
129+
<p class="text-white">
130+
No available jobs at the moment. Please check back later.
131+
</p>`;
132+
} else {
133+
jobPostings.forEach((job_post, index) => {
134+
const columnIndex = index % 3;
135+
if (columns[columnIndex]) {
136+
columns[columnIndex].innerHTML += renderJobCard(job_post, index);
137+
}
138+
});
139+
}
140+
} catch (error) {
141+
console.error("Error fetching job data:", error);
142+
columns.forEach((col) => {
143+
col.innerHTML = '<p class="text-red-500 text-center">Failed to load job postings. Please try again later.</p>';
144+
});
145+
}
146+
});
147+
</script>
Lines changed: 15 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)