Skip to content

Commit 34da326

Browse files
committed
Add vue.js job openings to aside
1 parent 074d28d commit 34da326

File tree

3 files changed

+111
-1
lines changed

3 files changed

+111
-1
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<script lang="ts">
2+
// shared data across instances so we load only once
3+
const base = `https://vuejobs.com/api/postings`
4+
let openings = $ref([])
5+
</script>
6+
7+
<script setup lang="ts">
8+
import { onMounted, onUnmounted } from 'vue'
9+
import { useData } from 'vitepress'
10+
const { frontmatter } = useData()
11+
12+
let vuejobs = $ref<HTMLElement>()
13+
let visible = $ref(false)
14+
15+
onMounted(async () => {
16+
// only render when entering view
17+
const observer = new IntersectionObserver(
18+
(entries) => {
19+
if (entries[0].isIntersecting) {
20+
visible = true
21+
observer.disconnect()
22+
}
23+
},
24+
{ rootMargin: '0px 0px 300px 0px' }
25+
)
26+
observer.observe(vuejobs)
27+
onUnmounted(() => observer.disconnect())
28+
29+
// load data
30+
if (!openings.length) {
31+
openings = await (await fetch(`${base}`)).json()
32+
}
33+
})
34+
</script>
35+
36+
<template>
37+
<div v-if="frontmatter.vuejobs !== false" ref="vuejobs">
38+
<div class="vuejobs-container" v-if="openings.length">
39+
<div class="vj-item" v-for="(job, n) in openings" :key="n">
40+
<p>
41+
<a class="vj-job-title" :href="job.link" target="_blank">
42+
{{ job.title }}
43+
<svg
44+
xmlns="http://www.w3.org/2000/svg"
45+
aria-hidden="true"
46+
focusable="false"
47+
height="24px"
48+
viewBox="0 0 24 24"
49+
width="24px"
50+
class="vt-link-icon"
51+
>
52+
<path d="M0 0h24v24H0V0z" fill="none"></path>
53+
<path
54+
d="M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5H9z"
55+
></path>
56+
</svg>
57+
</a>
58+
</p>
59+
<p>
60+
<a class="vj-job-info" :href="job.link" target="_blank">
61+
{{ job.company }}
62+
<span v-if="job.salary">·</span>
63+
{{ job.salary }}
64+
<span>·</span>
65+
{{ job.location }}
66+
</a>
67+
</p>
68+
</div>
69+
</div>
70+
</div>
71+
</template>
72+
73+
<style scoped>
74+
.vuejobs-container {
75+
background-color: var(--vt-c-bg-soft);
76+
padding: 5px 15px;
77+
border-radius: 2px;
78+
}
79+
.vj-item {
80+
padding: 10px 0 10px 0;
81+
border-bottom: 1px solid var(--vt-c-divider-light);
82+
display: flex;
83+
flex-direction: column;
84+
}
85+
.vj-item:last-child {
86+
border-bottom: none;
87+
}
88+
.vuejobs-container p,
89+
.vuejobs-container a {
90+
line-height: 16px;
91+
transition: color 0.3s ease;
92+
display: inline-block;
93+
}
94+
.vuejobs-container a:hover {
95+
color: var(--vt-c-brand);
96+
}
97+
.vj-job-title {
98+
font-size: 12px;
99+
color: var(--vt-c-text-1);
100+
}
101+
.vj-job-info {
102+
font-size: 11px;
103+
color: var(--vt-c-text-2);
104+
margin-top: 2px;
105+
line-height: 12px;
106+
}
107+
</style>

.vitepress/theme/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@ import {
99
filterHeadersByPreference
1010
} from './components/preferences'
1111
import SponsorsAside from './components/SponsorsAside.vue'
12+
import VueJobs from './components/VueJobs.vue'
1213

1314
export default Object.assign({}, VPTheme, {
1415
Layout: () => {
1516
// @ts-ignore
1617
return h(VPTheme.Layout, null, {
1718
banner: () => h(Banner),
1819
'sidebar-top': () => h(PreferenceSwitch),
19-
'aside-mid': () => h(SponsorsAside)
20+
'aside-mid': () => h(SponsorsAside),
21+
'aside-bottom': () => h(VueJobs)
2022
})
2123
},
2224
enhanceApp({ app }: { app: App }) {

src/sponsor/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ sidebar: false
33
ads: false
44
editLink: false
55
sponsors: false
6+
vuejobs: false
67
---
78

89
<script setup>

0 commit comments

Comments
 (0)