From 2d89dcddf6e7f36e15e91cdc96f0859e92605978 Mon Sep 17 00:00:00 2001 From: Raven Scott Date: Thu, 26 Sep 2024 18:13:47 -0400 Subject: [PATCH] Add menu system built using MD --- .gitignore | 2 +- app.js | 119 ++++++++++++++------------------------------ default.menu.md | 8 +++ views/about.ejs | 16 +++--- views/blog-post.ejs | 14 ++---- views/contact.ejs | 16 +++--- views/index.ejs | 61 +++++------------------ 7 files changed, 77 insertions(+), 159 deletions(-) create mode 100644 default.menu.md diff --git a/.gitignore b/.gitignore index 8d5295a..b0a338e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ node_modules package-lock.json .env - +menu.md \ No newline at end of file diff --git a/app.js b/app.js index 1c9bad1..0ca6db3 100644 --- a/app.js +++ b/app.js @@ -28,6 +28,31 @@ app.use(express.urlencoded({ extended: false })); // Serve static files (CSS, Images) app.use(express.static(path.join(__dirname, 'public'))); +// Function to load menu items from the markdown file +function loadMenuItems() { + const menuFile = path.join(__dirname, 'menu.md'); + const content = fs.readFileSync(menuFile, 'utf-8'); + + const menuItems = []; + const titleRegex = //g; + const urlRegex = //g; + + let titleMatch; + let urlMatch; + + while ((titleMatch = titleRegex.exec(content)) && (urlMatch = urlRegex.exec(content))) { + menuItems.push({ + title: titleMatch[1], + url: urlMatch[1] + }); + } + + return menuItems; +} + +// Load the menu once and make it available to all routes +const menuItems = loadMenuItems(); + // Function to load and parse markdown files and extract lead function loadMarkdownWithLead(file) { const markdownContent = fs.readFileSync(path.join(__dirname, 'markdown', file), 'utf-8'); @@ -54,11 +79,6 @@ function titleToSlug(title) { .replace(/\s+/g, '-'); } -// Function to convert a slug back into a readable title -function slugToTitle(slug) { - return slug.replace(/-/g, ' '); -} - // Function to load all blog posts with pagination and search support function getAllBlogPosts(page = 1, postsPerPage = 5, searchQuery = '') { let blogFiles = fs.readdirSync(path.join(__dirname, 'markdown')).filter(file => file.endsWith('.md')); @@ -117,11 +137,11 @@ app.get('/', (req, res) => { currentPage: page, totalPages, searchQuery, // Pass search query to the view - noResults // Pass this flag to indicate no results found + noResults, // Pass this flag to indicate no results found + menuItems // Pass the menu items to the view }); }); - // About Route (Load markdown and render using EJS) app.get('/about', (req, res) => { const aboutMarkdownFile = path.join(__dirname, 'me', 'about.md'); @@ -136,72 +156,19 @@ app.get('/about', (req, res) => { res.render('about', { title: `About ${process.env.OWNER_NAME}`, - content: aboutContentHtml + content: aboutContentHtml, + menuItems // Pass the menu items to the view }); }); }); -// Display the Request a Quote form +// Contact Route (Render the contact form) app.get('/contact', (req, res) => { - res.render('contact', { title: `Contact ${process.env.OWNER_NAME}`, msg: undefined }); -}); - -// Handle contact form submission -app.post('/contact', async (req, res) => { - const { name, email, subject, message, 'g-recaptcha-response': captchaToken } = req.body; - - if (!name || !email || !subject || !message) { - return res.render('contact', { title: `Contact ${process.env.OWNER_NAME}`, msg: 'All fields are required.' }); - } - - const captchaSecret = process.env.CAPTCHA_SECRET_KEY; - const captchaVerifyUrl = `https://www.google.com/recaptcha/api/siteverify?secret=${captchaSecret}&response=${captchaToken}`; - - try { - const captchaResponse = await axios.post(captchaVerifyUrl); - if (!captchaResponse.data.success) { - return res.render('contact', { title: `Contact ${process.env.OWNER_NAME}`, msg: 'Captcha verification failed. Please try again.' }); - } - - const output = ` -

You have a new contact request from ${name}.

-

Contact Details

- -

Message

-

${message}

- `; - - let transporter = nodemailer.createTransport({ - host: process.env.SMTP_HOST, - port: process.env.SMTP_PORT, - secure: false, - auth: { - user: process.env.EMAIL_USER, - pass: process.env.EMAIL_PASS, - }, - tls: { rejectUnauthorized: false }, - }); - - let mailOptions = { - from: `"${name}" <${process.env.RECEIVER_EMAIL}>`, - to: process.env.RECEIVER_EMAIL, - subject: subject, - html: output, - }; - - transporter.sendMail(mailOptions, (error, info) => { - if (error) { - return res.render('contact', { title: `Contact ${process.env.OWNER_NAME}`, msg: 'An error occurred. Please try again.' }); - } - return res.render('contact', { title: `Contact ${process.env.OWNER_NAME}`, msg: 'Your message has been sent successfully!' }); - }); - } catch (error) { - return res.render('contact', { title: `Contact ${process.env.OWNER_NAME}`, msg: 'An error occurred while verifying CAPTCHA. Please try again.' }); - } + res.render('contact', { + title: `Contact ${process.env.OWNER_NAME}`, + msg: undefined, + menuItems // Pass the menu items to the view + }); }); // Blog Post Route @@ -223,14 +190,14 @@ app.get('/blog/:slug', (req, res) => { content: contentHtml, lead, description, // Pass the description to the view - blogPosts + blogPosts, + menuItems // Pass the menu items to the view }); } else { res.redirect('/'); } }); - // Sitemap Route app.get('/sitemap.xml', (req, res) => { const hostname = req.headers.host || 'http://localhost'; @@ -318,19 +285,9 @@ app.get('/rss', (req, res) => { res.send(rssFeed); }); -// Create a URL object from the environment variable -const blog_URL = new URL(process.env.BLOG_URL); - -// Extract just the hostname (e.g., blog.raven-scott.fyi) -const hostname = blog_URL.hostname; - // Global 404 handler for unmatched routes app.use((req, res) => { - if (req.hostname === hostname) { - res.redirect(process.env.HOST_URL); - } else { - res.redirect('/'); - } + res.redirect('/'); }); // Server Listening diff --git a/default.menu.md b/default.menu.md new file mode 100644 index 0000000..5d7af46 --- /dev/null +++ b/default.menu.md @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/views/about.ejs b/views/about.ejs index 92d6ba3..9c13469 100644 --- a/views/about.ejs +++ b/views/about.ejs @@ -23,7 +23,7 @@ - +