Dynamically incorporate Lever jobs on the home page and on blog pages for teams

I think this should be fairly straightforward to style up and make pretty.

Fixes #3
This commit is contained in:
R Tyler Croy 2019-11-23 12:39:35 -08:00
parent 69b9b0972a
commit ac06e47130
No known key found for this signature in database
GPG Key ID: E5C92681BEF6CEA2
7 changed files with 176 additions and 35 deletions

13
_data/teams.yml Normal file
View File

@ -0,0 +1,13 @@
#
# This data file has some metadata about the teams and is a critical part of
# plumbing jobs into team's blog posts
---
ios:
# the category in Lever
lever: 'iOS'
android:
lever: 'Android'
datascience:
lever: 'Data Science - San Francisco'

View File

@ -1 +1,2 @@
<script type="text/javascript" src="{{ "/assets/js/main.js" | relative_url }}"></script>
<script type="text/javascript" src="{{ "/assets/js/jobs.js" | relative_url }}"></script>

View File

@ -25,41 +25,32 @@ layout: default
</div>
<div class="section-split__item">
<ul class="card-grid card-grid-sm">
<li class="card theme-{{ theme | default: "midnight" }}">
<div class="card__body">
<h5 class="clamp-2">
<a href="#" class="stretched-link link-text-color">Senior Web Developer Full stack, Front-end focused</a>
</h5>
<p class="m-0 fs-md monospace text-truncate">San Francisco, CA</p>
</div>
</li>
<li class="card theme-{{ theme | default: "midnight" }}">
<div class="card__body">
<h5 class="clamp-2">
<a href="#" class="stretched-link link-text-color">Senior Web Developer Full stack, Front-end focused</a>
</h5>
<p class="m-0 fs-md monospace text-truncate">San Francisco, CA</p>
</div>
</li>
<li class="card theme-{{ theme | default: "midnight" }}">
<div class="card__body">
<h5 class="clamp-2">
<a href="#" class="stretched-link link-text-color">Senior Web Developer Full stack, Front-end focused</a>
</h5>
<p class="m-0 fs-md monospace text-truncate">San Francisco, CA</p>
</div>
</li>
<li class="card theme-{{ theme | default: "midnight" }}">
<div class="card__body">
<h5 class="clamp-2">
<a href="#" class="stretched-link link-text-color">Senior Web Developer Full stack, Front-end focused</a>
</h5>
<p class="m-0 fs-md monospace text-truncate">San Francisco, CA</p>
</div>
</li>
<noscript>
<p>
We normally fill in the jobs here with JavaScript.
</p>
<p>
We think it's cool that you have disabled JavaScript to view this page,
but you might be missing out :)
</p>
</noscript>
<ul class="card-grid card-grid-sm" id="jobs">
</ul>
<script type="text/javascript">
<!--
/*
* Only attempt to load the jobs after the page has loaded and
* our external script is present
*/
window.onload = () =>{
// Six is about the right number of cards that will fit into this spot
renderJobs(document.getElementById('jobs'), null, 6);
};
-->
</script>
</div>
</div>
</section>

View File

@ -18,9 +18,22 @@ layout: default
</p>
</header>
<ul class="card-grid card-grid-sm" id="jobs">
</ul>
<div itemprop="articleBody">
{{ content }}
</div>
<a href="{{ page.url | relative_url }}" hidden></a>
</article>
{%- if page.team and site.data.teams[page.team] -%}
<script type="text/javascript">
<!--
window.onload = () =>{
renderJobs(document.getElementById('jobs'), "{{ site.data.teams[page.team].lever }}", 3);
};
-->
</script>
{%- endif -%}

View File

@ -4,7 +4,7 @@ title: Calculating Customer Lifetime Revenue
author: bclearly
tags:
- ltv
team: data-science
team: datascience
---
Why LTR? (Lifetime Revenue)

View File

@ -5,7 +5,7 @@ author: siweiz
tags:
- machinelearning
- deeplearning
team: data-science
team: datascience
---
How much data do you need to train a seq2seq model? Lets say that you want to translate sentences from one language to another. You probably need a bigger dataset to translate longer sentences than if you wanted to translate shorter ones. How does the need for data grow as the sentence length increases?

123
assets/js/jobs.js Normal file
View File

@ -0,0 +1,123 @@
/*
* This JavaScript file was hand-crafted by a developer who doesn't normally
* write JavaScript and should not be considered indicative of how Scribd's
* proper web engineers write JavaScript.
*
* With that disclaimer out of the way...
*
* This file handles the fetching of jobs from Lever such that they can be
* dynamically inserted into different parts of the tech blog
*/
/*
* This API will return an list of departments which must then be filtered
* through to find the .postings under each
*/
const API_URL = 'https://api.lever.co/v0/postings/scribd?group=department&mode=json'
/*
* Everybody loves globals, this will make sure we don't hit the API more than
* we need to.
*/
window.jobsCache = {};
window.jobsFetched = false;
/**
* Fetch the jobs from the Lever API and cache them into a page-wide global
*
* This will always return a Promise, even when the cache is hit
*/
function fetchJobs() {
if (window.jobsFetched) {
// Whoa there cowboy, only hit their API once per page
return Promise.resolve(window.jobsCache);
}
return fetch(API_URL)
.then(async (response) => {
const departments = await response.json();
/*
* Since this is the tech blog, we're only pulling a couple of
* departments
*/
departments
.filter(d => ['Engineering', 'Data Science', 'Design'].includes(d.title))
.forEach((department) => {
department.postings.forEach((posting) => {
const team = posting.categories.team;
if (!window.jobsCache[team]) {
window.jobsCache[team] = [];
}
window.jobsCache[team].push(posting);
});
});
window.jobsFetched = true;
return window.jobsCache;
})
.catch((err) => {
console.error(`Failed to fetch the jobs from Lever, ruh roh ${err}`);
});
}
/**
* Render the available jobs into the given element
*
* team is an optional parameter and will filter the results to just that team.
* Send null to receive all engineering jobs
*
* Use the randomLimit parameter to receive a random slice of the jobs limited
* to the number passed through
*/
function renderJobs(elem, team, randomLimit) {
if (!elem) {
console.error("Cannot renderJobs() to an empty element");
return;
}
fetchJobs().then((jobs) => {
let toRender = (team ? jobs[team] : Object.values(jobs).flat());
/*
* Sometimes we won't have any jobs for a team
*/
if (!toRender) {
return;
}
if (randomLimit) {
shuffleArray(toRender);
toRender = toRender.slice(0, randomLimit);
}
toRender.forEach((job) => {
const li = document.createElement('li');
li.className = 'card theme-midnight';
li.innerHTML = `
<div class="card__body">
<h5 class="clamp-2">
<a href="${job.applyUrl}" class="stretched-link link-text-color">${job.text}</a>
</h5>
<p class="m-0 fs-md monospace text-truncate">${job.categories.location}</p>
</div>
`;
elem.appendChild(li);
});
});
}
/*
* Nice shuffle method courtesy of https://stackoverflow.com/a/12646864
*/
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}