Skip to content

Commit b2876fd

Browse files
authored
Merge pull request #11 from RustLangES/sidebar
[WEBSITE] Sidebar
2 parents 00c48aa + 0f9a50e commit b2876fd

File tree

10 files changed

+170
-8
lines changed

10 files changed

+170
-8
lines changed

app.vue

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
<script setup>
2-
import Roadmap from './components/Roadmap.vue'
3-
import HeroSection from './layouts/hero.vue'
2+
import { useRoute } from 'vue-router'
3+
4+
const route = useRoute()
5+
const nodeId = route.params.slug
6+
47
const title = 'Hoja de Ruta Definitiva para Aprender Rust: Desde Principiante hasta Experto'
58
const description = `
69
¿Estás listo para dominar uno de los lenguajes de programación más potentes y eficientes? Nuestra hoja de ruta te guiará paso a paso en tu viaje de aprendizaje de Rust, desde los conceptos básicos hasta las técnicas avanzadas. Diseñada para principiantes y desarrolladores experimentados, esta guía exhaustiva te ayudará a construir una sólida base en Rust y a aprovechar al máximo su rendimiento, seguridad y concurrencia.
@@ -9,7 +12,7 @@ Ya sea que desees desarrollar aplicaciones de sistemas, videojuegos, criptomoned
912
`
1013
useHead({
1114
bodyAttrs: {
12-
class: 'bg-orange-200 dark:bg-[#131313]/90 w-screen min-h-screen bg-center bg-fixed dark:bg-kaku dark:bg-cover dark:bg-blend-darken dark:backdrop-blur-xl overflow-x-hidden dark:text-[#e2cea9]'
15+
class: 'bg-orange-200 dark:bg-[#131313]/90 w-screen min-h-screen bg-center bg-fixed dark:bg-kaku dark:bg-cover dark:bg-blend-darken overflow-x-hidden dark:text-[#e2cea9]' + ((nodeId && !route.query.fromClick) ? ' overflow-hidden' : '')
1316
}
1417
})
1518
@@ -31,7 +34,5 @@ Ya sea que desees desarrollar aplicaciones de sistemas, videojuegos, criptomoned
3134
</script>
3235

3336
<template>
34-
<Header />
35-
<HeroSection />
36-
<Roadmap />
37+
<NuxtPage />
3738
</template>

bun.lockb

2.3 KB
Binary file not shown.

components/NodeCard.vue

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup>
22
import Card from './Card.vue'
3+
import { useRouter } from 'vue-router'
34
import { useVueFlow } from '@vue-flow/core'
45
import { Handle, Position } from '@vue-flow/core'
56
@@ -11,6 +12,7 @@
1112
bottom: Position.Bottom,
1213
}
1314
15+
const router = useRouter()
1416
const props = defineProps({
1517
data: Object,
1618
withoutIcon: {
@@ -30,6 +32,7 @@
3032
// TODO: open side content
3133
onNodeClick(({ node }) => {
3234
if (ignoreTypes.includes(node.type)) return
35+
router.push({ path: node.data.path, query: { fromClick: true } })
3336
console.log(node)
3437
})
3538
// TODO: animate all path if have event.node.data.topicLevel.eq()

components/Roadmap.vue

+5-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
const roadmapNodes = ref([
1313
{ id: 'topics', type: 'topics', position: { x: 0, y: -150 }, data: { topicLevel: 'start' } },
1414
...data.value.map(({ title, _path, data: { position, width, sourcePosition, targetPosition, topicLevel, type, align } }) => (
15-
{ id: _path.substring(1).replaceAll('/', "-").replaceAll('_', ''), type, position, width, label: title, data: { align, topicLevel, sourcePosition, targetPosition } }
15+
{ id: _path.substring(1).replaceAll('/', "-").replaceAll('_', ''), type, position, width, label: title, data: { align, topicLevel, sourcePosition, targetPosition, path: _path } }
1616
))
1717
])
1818
@@ -41,7 +41,10 @@
4141
:apply-changes="false"
4242
:nodes-draggable="false"
4343
:edges-updatable="false"
44-
class="min-h-screen min-w-full"
44+
:min-zoom="0.65"
45+
:zoom-on-scroll="false"
46+
:prevent-scrolling="false"
47+
class="min-h-[220vh] min-w-full"
4548
>
4649
<MiniMap
4750
pannable zoomable

index.vue

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<template>
2+
<Header />
3+
<HeroSection />
4+
<Roadmap />
5+
</template>
6+
7+
<script setup>
8+
import Roadmap from '@/components/Roadmap.vue'
9+
import HeroSection from '@/layouts/hero.vue'
10+
</script>

nuxt.config.ts

+11
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,15 @@ Ya sea que desees desarrollar aplicaciones de sistemas, videojuegos, criptomoned
2929
]
3030
}
3131
},
32+
content: {
33+
highlight: {
34+
langs: ['c', 'cpp', 'rs', 'java', 'js', 'cs', 'asm', 'toml', 'console', 'sh', 'bash', "vim"],
35+
// Themes from https://github.com/shikijs/textmate-grammars-themes/tree/main/packages/tm-themes
36+
theme: {
37+
default: 'vitesse-dark',
38+
dark: 'vitesse-dark',
39+
sepia: 'monokai'
40+
}
41+
},
42+
},
3243
})

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
"@vue-flow/core": "^1.33.6",
1616
"@vue-flow/minimap": "^1.4.0",
1717
"nuxt": "^3.11.2",
18+
"v-dropdown": "^3.0.0",
1819
"vue": "^3.4.21",
1920
"vue-router": "^4.3.0"
2021
},
2122
"devDependencies": {
2223
"@nuxtjs/seo": "^2.0.0-rc.10",
2324
"@nuxtjs/tailwindcss": "^6.12.0",
25+
"@tailwindcss/typography": "^0.5.13",
2426
"@unocss/nuxt": "^0.60.0"
2527
},
2628
"trustedDependencies": [

pages/[...slug].vue

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<template>
2+
<Header />
3+
<HeroSection />
4+
<Roadmap />
5+
<Teleport to="body">
6+
<div v-if="content" :class="['fixed top-0 h-screen', sidebarClass]">
7+
<div
8+
class="prose dark:prose-invert max-w-full flex overflow-y-auto overflow-x-hidden h-full w-full flex-col items-center p-4 focus:outline-0 sm:p-6 bg-orange-50 dark:bg-gray-800"
9+
>
10+
<div class="w-full flex flex-row justify-between px-4 pb-2">
11+
<Dropdown
12+
ref="statusDropDown"
13+
:customTriggerClass="['px-4 py-2 border-black border', status.toLowerCase()]"
14+
:border="false"
15+
>
16+
<!-- trigger element -->
17+
<template #trigger>
18+
<button type="button" v-text="status"/>
19+
</template>
20+
21+
<!-- contents display in dropdown -->
22+
<ul class="flex flex-col bg-orange-100 dark:bg-gray-600">
23+
<li
24+
v-for="(s, i) in allStatus"
25+
:key="'status-' + i"
26+
@click="changeStatus(s)"
27+
:class="['px-4 py-2 hover:cursor-pointer border-b border-black hover:bg-orange-50 dark:hover:bg-gray-500', s.toLowerCase()]"
28+
v-text="s"
29+
>
30+
</li>
31+
</ul>
32+
</Dropdown>
33+
<span class="hover:cursor-pointer" @click="closeSidebar">X</span>
34+
</div>
35+
<ContentRenderer :key="content._id" :value="content">
36+
<ContentRendererMarkdown class="flex flex-col w-full m:max-w-[800px] sm:max-w-[600px]" tag="article" :value="content" />
37+
<div class="flex flex-col items-start w-full m:max-w-[800px] sm:max-w-[600px]">
38+
<h4 id="related-content" class="mb-3">
39+
<a href="#related-content">Contenido Extra Relacionado</a>
40+
</h4>
41+
<a
42+
class="gap-x-2 mb-1"
43+
v-for="(link, i) in content.data.externalLinks.sort((a, b) => a.english - b.english)"
44+
:key="i"
45+
:href="link.link"
46+
>
47+
<Card moreTransparency >
48+
<strong v-if="link.english">[Contenido en Ingles]</strong>
49+
{{link.name}}
50+
</Card>
51+
</a>
52+
</div>
53+
</ContentRenderer>
54+
</div>
55+
</div>
56+
</Teleport>
57+
</template>
58+
59+
<script setup lang="ts">
60+
import { useRoute } from 'vue-router'
61+
import { ref, onMounted } from 'vue'
62+
import Roadmap from '@/components/Roadmap.vue'
63+
import HeroSection from '@/layouts/hero.vue'
64+
import Dropdown from 'v-dropdown'
65+
66+
const { $locally } = useNuxtApp()
67+
68+
const allStatus = [ 'Pendiente', 'Leyendo', 'Completado', 'Omitir' ]
69+
const route = useRoute()
70+
const nodeId = route.params.slug
71+
const showSidebar = ref(true)
72+
const content = ref(null)
73+
const statusDropDown = ref(null)
74+
const status = ref($locally.get(nodeId) ?? 'Pendiente')
75+
76+
77+
onMounted(async () => {
78+
if (!nodeId) return
79+
const contentResult = await queryContent(nodeId.join("/")).findOne()
80+
content.value = contentResult
81+
showSidebar.value = contentResult && (route.query.fromClick || false)
82+
})
83+
84+
const closeSidebar = () => {
85+
content.value = null;
86+
document.body.classList.remove('overflow-hidden')
87+
}
88+
const sidebarClass = computed(() => showSidebar.value ? 'right-0 w-screen lg:w-2/4' : 'w-screen')
89+
90+
function changeStatus(val) {
91+
if (val == status.value) return
92+
if (!statusDropDown.value) return
93+
status.value = val
94+
$locally.set(nodeId, val)
95+
statusDropDown.value.close()
96+
}
97+
</script>
98+
99+
<style>
100+
.pendiente::before,
101+
.leyendo::before,
102+
.completado::before,
103+
.omitir::before {
104+
content: '';
105+
margin-right: 5px;
106+
}
107+
108+
.pendiente::before { color: var(--tw-text-gray-950); }
109+
.leyendo::before { color: var(--tw-text-orange-500); }
110+
.completado::before { color: var(--tw-text-green-600); }
111+
.omitir::before { color: var(--tw-text-slate-500); }
112+
113+
.v-dropdown-container.v-dropdown-no-border { border-radius: 0px !important }
114+
</style>

plugins/locally.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export default defineNuxtPlugin(() => {
2+
return {
3+
provide: {
4+
locally: {
5+
get(item) {
6+
return localStorage.getItem(item)
7+
},
8+
9+
set(item, value) {
10+
return localStorage.setItem(item, value)
11+
}
12+
}
13+
}
14+
}
15+
})

tailwind.config.js

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
/** @type {import('tailwindcss').Config} */
22
module.exports = {
3+
plugins: [
4+
require('@tailwindcss/typography'),
5+
],
36
theme: {
47
fontFamily: {
58
"alfa-slab": ["Alfa Slab One", "sans-serif"],

0 commit comments

Comments
 (0)