Compare commits
4 Commits
1fbf1dcaa2
...
255e5c3307
| Author | SHA1 | Date | |
|---|---|---|---|
| 255e5c3307 | |||
| 99bb31fd8a | |||
| 030bb68000 | |||
| 16cf39a088 |
32
README.md
32
README.md
@@ -1,11 +1,29 @@
|
|||||||
# Astro + Svelte Example
|
# Guía del Proyecto
|
||||||
|
|
||||||
```sh
|
Para poder desarrollar el proyecto, vamos a trabajar con astro, esto nos permite de forma más o menos fácil programar una página web con un buen SEO y un buen rendimiento.
|
||||||
npm create astro@latest -- --template framework-svelte
|
También usaremos bootstrap 5 para ayudarnos a decorar, fuentes de google fonts y alguna otra librería.
|
||||||
|
|
||||||
|
Para empezar el proyecto hay que [instalar nodejs](https://nodejs.org/en)
|
||||||
|
|
||||||
|
Luego clonamos el proyecto:
|
||||||
|
```bash
|
||||||
|
git clone https://git.h4ckdata.es/h4ckx0r/webSostenible.git
|
||||||
```
|
```
|
||||||
|
|
||||||
[](https://stackblitz.com/github/withastro/astro/tree/latest/examples/framework-svelte)
|
Y luego en la carpeta raiz del proyecto ejecutamos:
|
||||||
[](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/framework-svelte)
|
```bash
|
||||||
[](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/framework-svelte/devcontainer.json)
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
This example showcases Astro working with [Svelte](https://svelte.dev/).
|
Podemos usar el siguiente comando para iniciar la web para desarrollar:
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Y si queremos poder acceder también desde el movil o desde otro dispositivo en la red:
|
||||||
|
```bash
|
||||||
|
npm run devhost
|
||||||
|
```
|
||||||
|
|
||||||
|
Para subir una actualización al servidor público hay que en el `package.json` modificar la versión a una un poco más alta y luego hacer un pull.
|
||||||
|
El servidor de git se encargará de compilar la página y subirla al hosting.
|
||||||
@@ -6,4 +6,5 @@ import mdx from '@astrojs/mdx';
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Enable Svelte to support Svelte components.
|
// Enable Svelte to support Svelte components.
|
||||||
integrations: [mdx()],
|
integrations: [mdx()],
|
||||||
|
site: "https://ecobjetivos.h4ckdata.es"
|
||||||
});
|
});
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "websostenible",
|
"name": "websostenible",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.0.6",
|
"version": "0.1.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "astro dev",
|
"dev": "astro dev",
|
||||||
"devhost": "astro dev --host",
|
"devhost": "astro dev --host",
|
||||||
|
|||||||
@@ -1,51 +1,45 @@
|
|||||||
---
|
---
|
||||||
import { Image } from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
|
const { home, posts, proyectos } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<main>
|
<nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
|
||||||
<nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
|
<div class="container">
|
||||||
<div class="container">
|
<a class="navbar-brand d-flex align-items-center" href={home ? home : "/"}>
|
||||||
<a
|
<Image
|
||||||
class="navbar-brand d-flex align-items-center"
|
src="/imgs/logo.png"
|
||||||
href="#"
|
alt="Logo Ecobjetivos"
|
||||||
>
|
class="me-2 biglogo"
|
||||||
<Image
|
height="25"
|
||||||
src="/imgs/logo.png"
|
width="25"
|
||||||
alt="Logo Ecobjetivos"
|
/>
|
||||||
class="me-2 biglogo"
|
  Ecobjetivos
|
||||||
height="25"
|
</a>
|
||||||
width="25"
|
<button
|
||||||
/>
|
class="navbar-toggler"
|
||||||
  Ecobjetivos
|
type="button"
|
||||||
</a>
|
data-bs-toggle="collapse"
|
||||||
<button
|
data-bs-target="#navbarNav"
|
||||||
class="navbar-toggler"
|
aria-controls="navbarNav"
|
||||||
type="button"
|
aria-expanded="false"
|
||||||
data-bs-toggle="collapse"
|
aria-label="Toggle navigation"
|
||||||
data-bs-target="#navbarNav"
|
>
|
||||||
aria-controls="navbarNav"
|
<span class="navbar-toggler-icon"></span>
|
||||||
aria-expanded="false"
|
</button>
|
||||||
aria-label="Toggle navigation"
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
>
|
<ul class="navbar-nav ms-auto">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<li class="nav-item">
|
||||||
</button>
|
<a type="button" class="nav-link btn btn-light" href={posts ? posts : "#posts"}>Posts</a>
|
||||||
<div class="collapse navbar-collapse" id="navbarNav">
|
</li>
|
||||||
<ul class="navbar-nav ms-auto">
|
<li class="nav-item">
|
||||||
<li class="nav-item">
|
<a type="button" class="nav-link btn btn-light" href={proyectos ? proyectos : "#proyectos"}
|
||||||
<a type="button" class="nav-link btn btn-light" href="#posts"
|
>Proyectos</a
|
||||||
>Posts</a
|
>
|
||||||
>
|
</li>
|
||||||
</li>
|
</ul>
|
||||||
<li class="nav-item">
|
|
||||||
<a type="button" class="nav-link btn btn-light" href="#proyectos"
|
|
||||||
>Proyectos</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</div>
|
||||||
</main>
|
</nav>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.biglogo {
|
.biglogo {
|
||||||
|
|||||||
28
src/components/PostsRelacionados.astro
Normal file
28
src/components/PostsRelacionados.astro
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
const { currentPost } = Astro.props;
|
||||||
|
|
||||||
|
// Aquí deberías implementar la lógica para obtener posts relacionados
|
||||||
|
// Por ejemplo, basándote en categorías, tags, o algún otro criterio
|
||||||
|
const relatedPosts = [{ title: "Prueba", excerpt: "Prueba", url: "Prueba" }];
|
||||||
|
---
|
||||||
|
|
||||||
|
<section class="related-posts mt-5">
|
||||||
|
<h2>Posts Relacionados</h2>
|
||||||
|
<div class="row">
|
||||||
|
{
|
||||||
|
relatedPosts.map((post) => (
|
||||||
|
<div class="col-md-4 mb-4">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">{post.title}</h5>
|
||||||
|
<p class="card-text">{post.excerpt}</p>
|
||||||
|
<a href={post.url} class="btn btn-primary">
|
||||||
|
Leer más
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@@ -1,19 +1,198 @@
|
|||||||
---
|
---
|
||||||
const { titulo } = Astro.props;
|
// src/layouts/PostLayout.astro
|
||||||
|
import { getHeadings } from '../utils/getHeadings'; // Asumimos que crearemos esta utilidad
|
||||||
|
import RelatedPosts from '../components/PostsRelacionados.astro'; // Componente para posts relacionados
|
||||||
|
import Navbar from '../components/Navbar.astro';
|
||||||
|
|
||||||
|
const { frontmatter, content } = Astro.props;
|
||||||
|
const headings = getHeadings(content);
|
||||||
|
|
||||||
|
const description = frontmatter.descripcion;
|
||||||
|
|
||||||
|
// URLs para compartir en redes sociales
|
||||||
|
const shareUrl = new URL(Astro.url.pathname, Astro.site).toString();
|
||||||
|
const facebookShareUrl = `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(shareUrl)}`;
|
||||||
|
const twitterShareUrl = `https://twitter.com/intent/tweet?url=${encodeURIComponent(shareUrl)}&text=${encodeURIComponent(frontmatter.title)}`;
|
||||||
|
const linkedinShareUrl = `https://www.linkedin.com/shareArticle?mini=true&url=${encodeURIComponent(shareUrl)}&title=${encodeURIComponent(frontmatter.title)}`;
|
||||||
---
|
---
|
||||||
|
|
||||||
<html lang="es">
|
<html lang="es">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
<title>{frontmatter.title} - Ecobjetivos</title>
|
||||||
<title>EcoFuturo</title>
|
<meta name="description" content={description}>
|
||||||
</head>
|
<link rel="canonical" href={new URL(Astro.url.pathname, Astro.site).toString()}>
|
||||||
<body>
|
|
||||||
<main>
|
<!-- Open Graph / Facebook -->
|
||||||
<h1>{titulo}</h1>
|
<meta property="og:type" content="article">
|
||||||
<slot/>
|
<meta property="og:url" content={Astro.url}>
|
||||||
</main>
|
<meta property="og:title" content={frontmatter.title}>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
|
<meta property="og:description" content={description}>
|
||||||
</body>
|
<meta property="og:image" content={frontmatter.image && new URL(frontmatter.image, Astro.site)}>
|
||||||
</html>
|
|
||||||
|
<!-- Twitter -->
|
||||||
|
<meta property="twitter:card" content="summary_large_image">
|
||||||
|
<meta property="twitter:url" content={Astro.url}>
|
||||||
|
<meta property="twitter:title" content={frontmatter.title}>
|
||||||
|
<meta property="twitter:description" content={description}>
|
||||||
|
<meta property="twitter:image" content={frontmatter.image && new URL(frontmatter.image, Astro.site)}>
|
||||||
|
|
||||||
|
<!-- Structured Data for Google -->
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "BlogPosting",
|
||||||
|
"headline": "${frontmatter.titulo}",
|
||||||
|
"image": "${frontmatter.imagen && new URL(frontmatter.imagen, Astro.site)}",
|
||||||
|
"datePublished": "${frontmatter.fecha}",
|
||||||
|
"dateModified": "${frontmatter.lastModified || frontmatter.fecha}",
|
||||||
|
"author": {
|
||||||
|
"@type": "Person",
|
||||||
|
"name": "${frontmatter.autor}"
|
||||||
|
},
|
||||||
|
"publisher": {
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": "Ecobjetivos",
|
||||||
|
"logo": {
|
||||||
|
"@type": "ImageObject",
|
||||||
|
"url": "${new URL('/logo.png', Astro.site)}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "${description}"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Arial', sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.post-header {
|
||||||
|
background-color: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
padding: 2rem 0;
|
||||||
|
}
|
||||||
|
.post-content {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
.post-content img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
}
|
||||||
|
.post-meta {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
blockquote {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border-left: 5px solid #4CAF50;
|
||||||
|
padding: 1rem;
|
||||||
|
margin: 1rem 0;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.table-of-contents {
|
||||||
|
background-color: #f3f3f3;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
.table-of-contents ul {
|
||||||
|
list-style-type: none;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
.table-of-contents ul ul {
|
||||||
|
padding-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-of-contents {
|
||||||
|
background-color: #f3f3f3;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
.table-of-contents ul {
|
||||||
|
list-style-type: none;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
.table-of-contents ul ul {
|
||||||
|
padding-left: 1rem;
|
||||||
|
}
|
||||||
|
.table-of-contents a {
|
||||||
|
color: #333;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.table-of-contents a:hover {
|
||||||
|
color: #4CAF50;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<Navbar posts="/" proyectos="/" />
|
||||||
|
|
||||||
|
<header class="post-header">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="display-4">{frontmatter.title}</h1>
|
||||||
|
<p class="post-meta">
|
||||||
|
<i class="fas fa-calendar-alt"></i> {new Date(frontmatter.fecha).toLocaleDateString('es-ES', {year: 'numeric', month: 'long', day: 'numeric'})}
|
||||||
|
|
|
||||||
|
<i class="fas fa-user"></i> {frontmatter.autor}
|
||||||
|
{frontmatter.lastModified && (
|
||||||
|
<> |
|
||||||
|
<i class="fas fa-edit"></i> Última actualización: {new Date(frontmatter.lastModified).toLocaleDateString('es-ES', {year: 'numeric', month: 'long', day: 'numeric'})}</>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<article class="post-content">
|
||||||
|
<slot />
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-4">
|
||||||
|
<aside class="sticky-top" style="top: 2rem;">
|
||||||
|
<div class="table-of-contents">
|
||||||
|
<h4>Contenido</h4>
|
||||||
|
<ul>
|
||||||
|
{headings.map(heading => (
|
||||||
|
<li style={`margin-left: ${(heading.depth - 1) * 1}rem`}>
|
||||||
|
<a href={`#${heading.slug}`}>{heading.text}</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">Sobre el autor</h5>
|
||||||
|
<p class="card-text">{frontmatter.authorBio}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">Compartir</h5>
|
||||||
|
<a href={facebookShareUrl} target="_blank" rel="noopener noreferrer" class="btn btn-primary me-2"><i class="fab fa-facebook-f"></i></a>
|
||||||
|
<a href={twitterShareUrl} target="_blank" rel="noopener noreferrer" class="btn btn-info me-2"><i class="fab fa-twitter"></i></a>
|
||||||
|
<a href={linkedinShareUrl} target="_blank" rel="noopener noreferrer" class="btn btn-secondary"><i class="fab fa-linkedin-in"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<RelatedPosts currentPost={frontmatter} />
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="bg-dark text-white py-4">
|
||||||
|
<!-- ... (contenido del footer) ... -->
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
// Component Imports
|
// Component Imports
|
||||||
import ListadoPostsHorizontal from "../components/ListadoPostsHorizontal.astro";
|
import ListadoPostsHorizontal from "../components/ListadoPostsHorizontal.astro";
|
||||||
import Navbar from "../components/Navbar.astro";
|
import Navbar from "../components/Navbar.astro";
|
||||||
|
import { Image } from "astro:assets";
|
||||||
|
|
||||||
const animateOnScroll = `
|
const animateOnScroll = `
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
@@ -44,7 +45,7 @@ const animateOnScroll = `
|
|||||||
<title>Ecobjetivos</title>
|
<title>Ecobjetivos</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<Navbar />
|
<Navbar/>
|
||||||
<header class="header-bg text-white">
|
<header class="header-bg text-white">
|
||||||
<div class="container text-center">
|
<div class="container text-center">
|
||||||
<h1
|
<h1
|
||||||
@@ -80,10 +81,14 @@ const animateOnScroll = `
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 animate-on-scroll">
|
<div class="col-md-6 animate-on-scroll">
|
||||||
<div
|
<div class="text-white p-5 text-center">
|
||||||
class=" text-white p-5 text-center"
|
<Image
|
||||||
>
|
src="/imgs/17Objetivos.png"
|
||||||
<img src="../../public/imgs/17Objetivos.png" alt="" class="img-thumbnail .img-fluid">
|
alt=""
|
||||||
|
class="img-thumbnail .img-fluid"
|
||||||
|
width="730"
|
||||||
|
height="450"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -156,20 +161,21 @@ const animateOnScroll = `
|
|||||||
</h2>
|
</h2>
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
{
|
{
|
||||||
[1, 2, 3, 4, 5, 6].map((num) => (
|
[1, 2, 3, 4, 5, 6].map((num) => (
|
||||||
<div class="col-md-4 animate-on-scroll">
|
<div class="col-md-4 animate-on-scroll">
|
||||||
<div class="bg-light p-4 text-center">
|
<div class="bg-light p-4 text-center">
|
||||||
<img
|
<Image
|
||||||
src={`../../public/imgs/imgimp${num}.jpg`}
|
src={`/imgs/imgimp${num}.jpg`}
|
||||||
alt={`Imagen de impacto ${num}`}
|
alt={`Imagen de impacto ${num}`}
|
||||||
class="img-fluid img-fit"
|
class="img-fluid img-fit"
|
||||||
/>
|
width="10"
|
||||||
|
height="10"
|
||||||
</div>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))
|
</div>
|
||||||
|
))
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -193,7 +199,7 @@ const animateOnScroll = `
|
|||||||
<div class="col-md-6 mb-4 animate-on-scroll">
|
<div class="col-md-6 mb-4 animate-on-scroll">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">
|
<h5 class="card-title" aria-label="Proyecto">
|
||||||
Proyecto {num}
|
Proyecto {num}
|
||||||
</h5>
|
</h5>
|
||||||
<p class="card-text">
|
<p class="card-text">
|
||||||
@@ -265,7 +271,7 @@ const animateOnScroll = `
|
|||||||
<style is:global>
|
<style is:global>
|
||||||
@import url("https://fonts.googleapis.com/css2?family=Inter+Tight:ital@0;1&display=swap");
|
@import url("https://fonts.googleapis.com/css2?family=Inter+Tight:ital@0;1&display=swap");
|
||||||
@import url("https://fonts.googleapis.com/css2?family=Londrina+Sketch&display=swap");
|
@import url("https://fonts.googleapis.com/css2?family=Londrina+Sketch&display=swap");
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
h2,
|
h2,
|
||||||
h3,
|
h3,
|
||||||
@@ -300,11 +306,10 @@ const animateOnScroll = `
|
|||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.img-fit{
|
.img-fit {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
14
src/utils/getHeadings.js
Normal file
14
src/utils/getHeadings.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export function getHeadings(content) {
|
||||||
|
const headingRegex = /^(#{1,6})\s+(.+)$/gm;
|
||||||
|
const headings = [];
|
||||||
|
let match;
|
||||||
|
|
||||||
|
while ((match = headingRegex.exec(content)) !== null) {
|
||||||
|
const depth = match[1].length;
|
||||||
|
const text = match[2];
|
||||||
|
const slug = text.toLowerCase().replace(/[^\w]+/g, '-');
|
||||||
|
headings.push({ depth, text, slug });
|
||||||
|
}
|
||||||
|
|
||||||
|
return headings;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user