From 142a478a6aa9e0a1576dd4909cd30cef06caa4c0 Mon Sep 17 00:00:00 2001 From: Bashynx Date: Sun, 9 Nov 2025 21:24:34 +0100 Subject: [PATCH] Add the theme --- .gitmodules | 0 themes/openalt | 1 - themes/openalt/.gitignore | 2 + themes/openalt/LICENSE | 21 ++ themes/openalt/README.md | 135 +++++++++ themes/openalt/layout/_partial/article.ejs | 26 ++ themes/openalt/layout/_partial/date.ejs | 11 + themes/openalt/layout/_partial/feed.ejs | 11 + .../layout/_partial/index/feed_preview.ejs | 22 ++ .../layout/_partial/index/main_event.ejs | 13 + .../layout/_partial/index/partners.ejs | 18 ++ themes/openalt/layout/_partial/post_event.ejs | 9 + themes/openalt/layout/_partial/post_feed.ejs | 20 ++ themes/openalt/layout/archive.ejs | 11 + themes/openalt/layout/category.ejs | 1 + themes/openalt/layout/index.ejs | 5 + themes/openalt/layout/layout.ejs | 90 ++++++ themes/openalt/layout/page.ejs | 1 + themes/openalt/layout/post.ejs | 1 + themes/openalt/layout/tag.ejs | 1 + themes/openalt/source/css/style.css | 265 ++++++++++++++++++ 21 files changed, 663 insertions(+), 1 deletion(-) create mode 100644 .gitmodules delete mode 160000 themes/openalt create mode 100644 themes/openalt/.gitignore create mode 100644 themes/openalt/LICENSE create mode 100644 themes/openalt/README.md create mode 100644 themes/openalt/layout/_partial/article.ejs create mode 100644 themes/openalt/layout/_partial/date.ejs create mode 100644 themes/openalt/layout/_partial/feed.ejs create mode 100644 themes/openalt/layout/_partial/index/feed_preview.ejs create mode 100644 themes/openalt/layout/_partial/index/main_event.ejs create mode 100644 themes/openalt/layout/_partial/index/partners.ejs create mode 100644 themes/openalt/layout/_partial/post_event.ejs create mode 100644 themes/openalt/layout/_partial/post_feed.ejs create mode 100644 themes/openalt/layout/archive.ejs create mode 100644 themes/openalt/layout/category.ejs create mode 100644 themes/openalt/layout/index.ejs create mode 100644 themes/openalt/layout/layout.ejs create mode 100644 themes/openalt/layout/page.ejs create mode 100644 themes/openalt/layout/post.ejs create mode 100644 themes/openalt/layout/tag.ejs create mode 100644 themes/openalt/source/css/style.css diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e69de29 diff --git a/themes/openalt b/themes/openalt deleted file mode 160000 index aa354ad..0000000 --- a/themes/openalt +++ /dev/null @@ -1 +0,0 @@ -Subproject commit aa354ad7324fdd2861a94cbc9febfa3136b3d69c diff --git a/themes/openalt/.gitignore b/themes/openalt/.gitignore new file mode 100644 index 0000000..5b823bf --- /dev/null +++ b/themes/openalt/.gitignore @@ -0,0 +1,2 @@ +_config.yml + diff --git a/themes/openalt/LICENSE b/themes/openalt/LICENSE new file mode 100644 index 0000000..b3ff301 --- /dev/null +++ b/themes/openalt/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 The Hackman Club + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/themes/openalt/README.md b/themes/openalt/README.md new file mode 100644 index 0000000..94c4f08 --- /dev/null +++ b/themes/openalt/README.md @@ -0,0 +1,135 @@ +# Tapestry Theme + +Tapestry is a Hexo theme designed for tumblr style gallery blog feed. + +I am using this theme for a [personal blog](https://blog.bashynx.com/), or you can check the [official theme preview](https://tapestry.demo.bashynx.dev/). + +--- + +## 1. Installation + +1. Clone the theme into your Hexo project: + +```bash +cd your-hexo-project +git clone https://github.com/HackmanClub/tapestry.git themes/tapestry +``` + +1. Set the theme in Hexo’s main `_config.yml`: + +```yaml +theme: tapestry +``` + +1. Install dependencies: + +```bash +npm install sharp +``` + +--- + +## 2. Configuration + +The theme uses its own `_config.yml` inside `themes/tapestry/`. You will need to copy / rename `_EXAMPLE_config.yml` as a starting point: + +```bash +cp themes/tapestry/_EXAMPLE_config.yml themes/tapestry/_config.yml +``` + +### Important Sections + +#### Site Settings + +- `avatar`, `banner`, `favicon`: paths to your images. +- `primary_color`: main color for your theme. +- `tag_border`: add borders around tags. +- `sidebar`: show or hide the sidebar. +- `scarves`: enable or disable scarves links. + +#### Scarves + +Scarf links appear at the top right. You can use an image or FontAwesome icon: + +```yaml +scarf: + - url: tags/baking + image: images/assets/scarves/scarf.png + icon: false + enable: true + alt: Example + - url: tags/photo + image: false + icon: fa-solid fa-heart + enable: true + alt: Example +``` + +- `url` – link target +- `image` – path to scarf image +- `icon` – FontAwesome icon class +- `enable` – show/hide scarf +- `alt` – accessibility text + +#### Social Links + +Add or remove social links easily: + +```yaml +social: + - url: https://www.instagram.com/ + icon: fab fa-instagram + enable: true +``` + +--- + +### Sidebar Menu + +Configure links in the sidebar: + +```yaml +sidebar_menu: + - enable: true + name: Home + url: / + - enable: true + name: Get Hexo + url: https://hexo.io/docs/setup +``` + +- `enable` – show/hide +- `name` – link text +- `url` – destination + +--- + +## 3. Using Thumbnails + +- Put post images in `source/images/` +- The theme generates thumbnails automatically in `source/thumbnails/` +- Use `small-` or `large-` in templates depending on your layout. + +Example in a template: + +```ejs +<% if (post.photos && post.photos.length) { %> + <%- post.title %> +<% } %> +``` + +> ⚠️ Only shows image if `post.photos` exists. + +--- + +## 4. Running Locally + +Start a local Hexo server to preview: + +```bash +hexo clean +hexo s +``` + +- Visit `http://localhost:4000` +- Changes in templates or CSS are reflected immediately. diff --git a/themes/openalt/layout/_partial/article.ejs b/themes/openalt/layout/_partial/article.ejs new file mode 100644 index 0000000..be5f99c --- /dev/null +++ b/themes/openalt/layout/_partial/article.ejs @@ -0,0 +1,26 @@ +
+
+
+

<%= page.title || "Untitled" %>

+ <% if(page.photos && page.photos.length) { %> +
+ <%- page.title || "> +
+ <% } %> +

<%= page.description %>

+ <%- include('date', { date: page.date.toISOString() }) %> +
+
+ <%- page.content %> +
+ +
+
\ No newline at end of file diff --git a/themes/openalt/layout/_partial/date.ejs b/themes/openalt/layout/_partial/date.ejs new file mode 100644 index 0000000..e40c646 --- /dev/null +++ b/themes/openalt/layout/_partial/date.ejs @@ -0,0 +1,11 @@ +
+ <% + const posted = new Date(date); + const now = new Date(); + const year = 365 * 24 * 60 * 60 * 1000; + const format = (now - posted) < year ? + { day: 'numeric', month: 'long', hour: 'numeric', minute: 'numeric', hour12: true } : + { day: 'numeric', month: 'long', year: 'numeric', hour: 'numeric', minute: 'numeric', hour12: true }; + %> + <%= posted.toLocaleString('en-US', format ) %> +
\ No newline at end of file diff --git a/themes/openalt/layout/_partial/feed.ejs b/themes/openalt/layout/_partial/feed.ejs new file mode 100644 index 0000000..cafd56d --- /dev/null +++ b/themes/openalt/layout/_partial/feed.ejs @@ -0,0 +1,11 @@ +
+ <% page.posts.forEach(function(post) { %> + <%- include('post_feed', { post: post }) %> + <% }); %> + + +
\ No newline at end of file diff --git a/themes/openalt/layout/_partial/index/feed_preview.ejs b/themes/openalt/layout/_partial/index/feed_preview.ejs new file mode 100644 index 0000000..8d3aca9 --- /dev/null +++ b/themes/openalt/layout/_partial/index/feed_preview.ejs @@ -0,0 +1,22 @@ +
+ +
+ <% counter = 3 %> + <% page.posts.forEach(function(post) { %> + <% if (counter != 0) { %> + <% isEvent = false %> + <% post.tags.data.forEach(function(tag) { %> + <% if (tag.name == "Events") { %> + <% isEvent = true %> + <% } %> + <% }); %> + + <% if (isEvent == false) { %> + <%- include('./../post_feed', { post: post }) %> + <% counter = counter - 1 %> + <% } %> + <% } %> + <% }); %> +
+ +
\ No newline at end of file diff --git a/themes/openalt/layout/_partial/index/main_event.ejs b/themes/openalt/layout/_partial/index/main_event.ejs new file mode 100644 index 0000000..5044174 --- /dev/null +++ b/themes/openalt/layout/_partial/index/main_event.ejs @@ -0,0 +1,13 @@ +
+ + <% counter = false %> + <% page.posts.forEach(function(post) { %> + <% post.tags.data.forEach(function(tag) { %> + <% if ( (tag.name == "Events") && (counter == false) ) { %> + <%- include('./../post_event', { post: post }) %> + <% counter = true %> + <% } %> + <% }); %> + <% }); %> + +
\ No newline at end of file diff --git a/themes/openalt/layout/_partial/index/partners.ejs b/themes/openalt/layout/_partial/index/partners.ejs new file mode 100644 index 0000000..fe257a5 --- /dev/null +++ b/themes/openalt/layout/_partial/index/partners.ejs @@ -0,0 +1,18 @@ +
+ +
+

Brought to you by:

+
+ +
+
    + <% site.data.partners.forEach(function(partner) { %> +
  • + + <%= partner.name %> + +
  • + <% }); %> +
+
+
\ No newline at end of file diff --git a/themes/openalt/layout/_partial/post_event.ejs b/themes/openalt/layout/_partial/post_event.ejs new file mode 100644 index 0000000..1315314 --- /dev/null +++ b/themes/openalt/layout/_partial/post_event.ejs @@ -0,0 +1,9 @@ +
+ <%=  post.title || " style="max-height: 250px" width="300px" /> + +

<%= post.title || "Untitled" %>

+ +
+ <%- post.content %> +
+
diff --git a/themes/openalt/layout/_partial/post_feed.ejs b/themes/openalt/layout/_partial/post_feed.ejs new file mode 100644 index 0000000..c4636d8 --- /dev/null +++ b/themes/openalt/layout/_partial/post_feed.ejs @@ -0,0 +1,20 @@ + +
+ <% if(post.photos && post.photos.length) { %> +
+ + <%- post.title || 'Untitled' %> + +
+ <% } %> +
+

<%= post.title || "Untitled" %>

+ <%- include('date', { date: post.date.toISOString() }) %>
+

<%= post.description %>

+
+ <% post.tags.data.forEach(function(tag) { %> + #<%= tag.name %> + <% }); %> +
+
+
\ No newline at end of file diff --git a/themes/openalt/layout/archive.ejs b/themes/openalt/layout/archive.ejs new file mode 100644 index 0000000..aa17ac4 --- /dev/null +++ b/themes/openalt/layout/archive.ejs @@ -0,0 +1,11 @@ +
+ <% site.posts.sort('-date').forEach(function(post) { %> + <%- include('_partial/post_feed', { post: post }) %> + <% }); %> + + +
\ No newline at end of file diff --git a/themes/openalt/layout/category.ejs b/themes/openalt/layout/category.ejs new file mode 100644 index 0000000..5a7de68 --- /dev/null +++ b/themes/openalt/layout/category.ejs @@ -0,0 +1 @@ +<%- include("_partial/feed", { item: page.posts.sort('-date') }) %> \ No newline at end of file diff --git a/themes/openalt/layout/index.ejs b/themes/openalt/layout/index.ejs new file mode 100644 index 0000000..803122b --- /dev/null +++ b/themes/openalt/layout/index.ejs @@ -0,0 +1,5 @@ +<%- include("_partial/index/main_event", { item: site.posts.sort('-date') }) %> + +<%- include("_partial/index/feed_preview", { item: site.posts.sort('-date') }) %> + +<%- include("_partial/index/partners") %> \ No newline at end of file diff --git a/themes/openalt/layout/layout.ejs b/themes/openalt/layout/layout.ejs new file mode 100644 index 0000000..b191f8e --- /dev/null +++ b/themes/openalt/layout/layout.ejs @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + <%= config.title %> + + + + + +
+ +
+
+ +
+ <%- body %> +
+ + + +
+ + diff --git a/themes/openalt/layout/page.ejs b/themes/openalt/layout/page.ejs new file mode 100644 index 0000000..0b8fd7f --- /dev/null +++ b/themes/openalt/layout/page.ejs @@ -0,0 +1 @@ +<%- include("_partial/article", { page: page }) %> \ No newline at end of file diff --git a/themes/openalt/layout/post.ejs b/themes/openalt/layout/post.ejs new file mode 100644 index 0000000..0b8fd7f --- /dev/null +++ b/themes/openalt/layout/post.ejs @@ -0,0 +1 @@ +<%- include("_partial/article", { page: page }) %> \ No newline at end of file diff --git a/themes/openalt/layout/tag.ejs b/themes/openalt/layout/tag.ejs new file mode 100644 index 0000000..5a7de68 --- /dev/null +++ b/themes/openalt/layout/tag.ejs @@ -0,0 +1 @@ +<%- include("_partial/feed", { item: page.posts.sort('-date') }) %> \ No newline at end of file diff --git a/themes/openalt/source/css/style.css b/themes/openalt/source/css/style.css new file mode 100644 index 0000000..a233974 --- /dev/null +++ b/themes/openalt/source/css/style.css @@ -0,0 +1,265 @@ +body { + font-family: "Open Sans"; + margin: auto; + font-size: 14px; + background-color: #0D1117; +} + +h1, h2, h3, h4 { + padding: 0; + margin: 0; + font-weight: lighter; + color: #0D1117; +} + +h1 { + font-size: 25px; + line-height: 30px; + text-align: center; +} + +h2 { + font-size: 22px; + line-height: 25px; +} + +h3 { + font-size: 18px; + line-height: 22px; +} + +h4 { + font-size: 15px; + line-height: 18px; + font-style: italic; +} + +a { + text-decoration: none; + color: #0D1117; +} + +/* Definition of small fonted text, example: footer */ +.smoll { + font-size: 12px !important; + line-height: 12px; +} + +/* Topbar header section */ +.topbar { + position: sticky; + margin: 0; + top: 0; + width: 100%; + box-shadow:0 .125rem .25rem rgba(255,255,255,0.075) !important; +} + +.topbar-header { + width: 150px; +} + +/* Topbar menu section */ +nav { + width: 80%; + list-style: none; + display: flex; + margin: 0 auto; + padding: 0; +} + +nav a { + padding: 15px 10px; + font-size: 15px; + align-content: center; + color: #dcdcdf; +} + +/* Footer */ +.footer { + color: #dcdcdf !important; + text-align: center; + margin-top: 5px; +} + +.footer a { + color: #dcdcdf !important; +} + +/* Footer - Social */ +.social { + justify-content: center; + margin: 0.5em 0 0 auto; + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; +} + +.social-icon a { + padding: 8px; + box-sizing: border-box; + display:inline-block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + font-size: 19px; + transition: color 0.3s; +} + +.social-icon img { + width: 15px !important; + height: 15px !important; + border-radius: 50%; +} + +/* Posts */ +main { + width: 80%; + margin: 30px auto 0 auto; +} + +.narrow_view{ + width: 70%; + margin: 0 auto; +} + +.post { + padding: 1em; + background-color: #dcdcdf; + border-radius: 10px; + box-sizing: border-box; + margin-bottom: 16px; +} + +/* Images */ +img { + max-width: 100%; + height: auto; + display: block; + border-radius: 10px; + opacity: 1; + transition: all 1s; +} + +img:hover { + opacity: 0.95; +} + +/* Post */ +.post-header { + line-height: 100%; + color:#0D1117; +} + +.date { + color: #0D1117; + font-style: italic; +} + +iframe { + width: 100%; + height: auto; + aspect-ratio: 16 / 9; +} + +/* Post - Top section */ +.article { + font-size: 35px !important; + line-height: 40px !important; + padding-bottom: 15px; +} + +.page-date{ + text-align: right !important; +} + +.page-divider { + margin-top: 1em; + border-top: 1px solid #0D1117; +} + +/* Post - Tags */ +.tags { + text-align: right; + margin-bottom: 0em; +} + +.tags a { + color: #6c6f72 !important; + border-radius: 5px; + padding: 0.25em; +} + +.tags a:hover { + color: #9fa5aa !important; +} + +/* Section info */ +section { + margin-bottom: 20px; +} + +.section-title h1{ + color: #dcdcdf; + margin: 20px auto; +} + +/* Events */ +.event-wrapper { + text-align: center; + margin: 75px auto 100px auto; +} +.event .event-wrapper h1, +.event .event-wrapper h2, +.event .event-wrapper h3, +.event .event-wrapper h4, +.event .event-wrapper a , +.event .event-wrapper p { + color: #dcdcdf; + padding-bottom: 5px; +} + +.event-wrapper h1{ + font-size: 35px; + line-height: 40px; + font-style: normal; +} + +.event-wrapper img{ + vertical-align: middle; + margin:0 auto 25px auto; +} + +/* Feed Preview */ + +.feed_preview { + display: flex; + flex-wrap: wrap; + gap: 1.25%; +} + +.feed_preview .post { + width: 32.5%; +} + + +/* Partners */ + +.partners { + display: flex; + flex-wrap: wrap; + gap: 1rem; + list-style: none; + padding: 0; + margin: 0 auto; +} + +.partners li { + width: 300px; + text-align: center; + margin: auto; +} + +.partners img { + width: 300px; +} \ No newline at end of file