Merge branch 'AngelJumbo:main' into main
@@ -1,2 +1,3 @@
|
||||
*.html
|
||||
thumbnails/
|
||||
*.js
|
||||
@@ -5,10 +5,11 @@ A place where to find gruvbox theme wallpapers.
|
||||
|
||||
1. Fork the project.
|
||||
2. Add the wallpapers that you have in their respective folder.
|
||||
3. For light variants: Place the light-themed wallpapers in a light/ subfolder within the category.
|
||||
3. Make a pull request.
|
||||
|
||||
> [!CAUTION]
|
||||
> - Use files under 25mg
|
||||
> - Use files under 25mb
|
||||
> - Avoid spaces in names
|
||||
|
||||
> [!TIP]
|
||||
@@ -16,6 +17,37 @@ A place where to find gruvbox theme wallpapers.
|
||||
|
||||
I tend to accept any contributions, but let's keep the site with images that match or look good with the gruvbox's color scheme :').
|
||||
|
||||
|
||||
## Nix package
|
||||
|
||||
1. **Use [nix flakes](https://wiki.nixos.org/wiki/Flakes)**:
|
||||
|
||||
2. Add the following to your `flake.nix` file:
|
||||
|
||||
```nix
|
||||
inputs = {
|
||||
gruvbox-wallpapers.url = "github:AngelJumbo/gruvbox-wallpapers";
|
||||
# ...
|
||||
};
|
||||
```
|
||||
|
||||
3. Then, in your Home Manager configuration:
|
||||
|
||||
```nix
|
||||
{
|
||||
inputs,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
home.file = {
|
||||
"path/to/dir" = {
|
||||
source = inputs.gruvbox-wallpapers.packages."${pkgs.stdenv.hostPlatform.system}".default;
|
||||
recursive = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Disclaimer
|
||||
|
||||
Most of the images shared here are community contributions, and their original sources are often unknown. If you are the rightful owner of any image and would like it removed, please contact me by opening an issue. For any use beyond personal scope, I recommend performing a reverse image search to verify the origin.
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
function loadPage(section, page) {
|
||||
let buttons = document.getElementById(section).getElementsByTagName("button");
|
||||
let currSel;
|
||||
for (let i in buttons) {
|
||||
if (buttons[i].classList?.contains("selected")) {
|
||||
if (page - 1 == i) return;
|
||||
else {
|
||||
currSel = buttons[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fetch(section + "_page" + page + ".html")
|
||||
.then((response) => response.text())
|
||||
.then((data) => {
|
||||
document.getElementById(section + "-content").innerHTML = data;
|
||||
if (currSel) {
|
||||
currSel.classList.remove("selected");
|
||||
}
|
||||
document.getElementById(section).getElementsByTagName("button")[page - 1].classList.add("selected");
|
||||
});
|
||||
}
|
||||
|
||||
function activeSection(section) {
|
||||
hideAll();
|
||||
|
||||
const targetSection = document.getElementById(section);
|
||||
targetSection.focus();
|
||||
targetSection.classList.add("selected");
|
||||
setTimeout(() => {
|
||||
targetSection.scrollIntoView({ block: "start", behavior: "smooth" });
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function hideAll() {
|
||||
document.querySelectorAll(".section").forEach((s) => {
|
||||
s.classList.remove("selected");
|
||||
});
|
||||
}
|
||||
const HIDDEN_CLASS = "hidden";
|
||||
|
||||
function hideThemeSwitcher(currentTheme) {
|
||||
if (currentTheme == "dark") {
|
||||
document.getElementById("dark-icon")?.classList.add(HIDDEN_CLASS);
|
||||
document.getElementById("light-icon")?.classList.remove(HIDDEN_CLASS);
|
||||
} else {
|
||||
document.getElementById("light-icon")?.classList.add(HIDDEN_CLASS);
|
||||
document.getElementById("dark-icon")?.classList.remove(HIDDEN_CLASS);
|
||||
}
|
||||
}
|
||||
function setTheme(newTheme) {
|
||||
document.documentElement.style.setProperty("color-scheme", newTheme);
|
||||
hideThemeSwitcher(newTheme);
|
||||
}
|
||||
|
||||
function switchTheme() {
|
||||
setTheme(document.documentElement.style.getPropertyValue("color-scheme")=="dark"?"light":"dark");
|
||||
}
|
||||
|
||||
@@ -26,147 +26,481 @@ generate_thumbnails() {
|
||||
rm -rf thumbnails/*
|
||||
|
||||
# Count total number of images
|
||||
total_images=$(find ./wallpapers -type f | wc -l)
|
||||
total_images=$(find ./wallpapers -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) | wc -l)
|
||||
current_image=0
|
||||
|
||||
for section_dir in ./wallpapers/*; do
|
||||
section_name="${section_dir##*/}"
|
||||
mkdir -p "thumbnails/$section_name"
|
||||
|
||||
# Process dark images (base directory)
|
||||
for img in "$section_dir"/*; do
|
||||
[ -f "$img" ] || continue
|
||||
case "$img" in
|
||||
*.jpg|*.jpeg|*.png|*.JPG|*.JPEG|*.PNG) ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
|
||||
current_image=$((current_image + 1))
|
||||
local img_filename="${img##*/}"
|
||||
local thumbnail="thumbnails/$section_name/$img_filename"
|
||||
echo "($current_image/$total_images): $img -> $thumbnail"
|
||||
convert "$img" -resize 300x300 "$thumbnail"
|
||||
done
|
||||
|
||||
# Process light images if light folder exists
|
||||
if [ -d "$section_dir/light" ]; then
|
||||
mkdir -p "thumbnails/$section_name/light"
|
||||
for img in "$section_dir/light"/*; do
|
||||
[ -f "$img" ] || continue
|
||||
case "$img" in
|
||||
*.jpg|*.jpeg|*.png|*.JPG|*.JPEG|*.PNG) ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
|
||||
current_image=$((current_image + 1))
|
||||
local img_filename="${img##*/}"
|
||||
local thumbnail="thumbnails/$section_name/light/$img_filename"
|
||||
echo "($current_image/$total_images): $img -> $thumbnail"
|
||||
convert "$img" -resize 300x300 "$thumbnail"
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Thumbnail generation complete: $total_images images processed"
|
||||
}
|
||||
|
||||
write_section_header() {
|
||||
echo "write section header ..."
|
||||
echo "<h2 class='s$1 clickable' onclick='activeSection(\"$2\")' >" >>$3
|
||||
echo "$2" | tr a-z A-Z >>$3
|
||||
echo "</h2>" >>$3
|
||||
check_has_light_folder() {
|
||||
local section_dir=$1
|
||||
[ -d "$section_dir/light" ] && echo "true" || echo "false"
|
||||
}
|
||||
|
||||
write_img() {
|
||||
echo "write image ..."
|
||||
# Remove leading './' from path if present
|
||||
local img_path="${1#./}"
|
||||
local section_name=$(echo "$img_path" | cut -d'/' -f2)
|
||||
local img_filename="${1##*/}"
|
||||
|
||||
# Use web-friendly paths (no leading ./)
|
||||
local thumbnail_path="thumbnails/$section_name/$img_filename"
|
||||
|
||||
echo " <a target='_blank' href='$img_path'>
|
||||
<img loading='lazy' src='$thumbnail_path' alt='$img_filename' width='200'></a>" >>$2
|
||||
count_images_in_dir() {
|
||||
local dir=$1
|
||||
find "$dir" -maxdepth 1 -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) | wc -l
|
||||
}
|
||||
|
||||
rm *.html
|
||||
create_section_data() {
|
||||
local section=$1
|
||||
local subdir=$2
|
||||
local maxPerPage=8
|
||||
local has_light=$(check_has_light_folder "$subdir")
|
||||
|
||||
echo "Creating data for section: $section"
|
||||
|
||||
# Create JSON data file for the section
|
||||
local data_file="${section}_data.js"
|
||||
|
||||
cat > "$data_file" << EOF
|
||||
// Data for $section section
|
||||
window.sectionData = window.sectionData || {};
|
||||
window.sectionData['$section'] = {
|
||||
hasLight: $has_light,
|
||||
maxPerPage: $maxPerPage,
|
||||
dark: [
|
||||
EOF
|
||||
|
||||
touch ./index.html
|
||||
# Generate dark images data
|
||||
for wallpaper in "$subdir"/*; do
|
||||
[ -f "$wallpaper" ] || continue
|
||||
case "$wallpaper" in
|
||||
*.jpg|*.jpeg|*.png|*.JPG|*.JPEG|*.PNG) ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
|
||||
local img_path="${wallpaper#./}"
|
||||
local img_filename="${wallpaper##*/}"
|
||||
local thumbnail_path="thumbnails/$section/$img_filename"
|
||||
echo " { src: '$img_path', thumb: '$thumbnail_path', alt: '$img_filename' }," >> "$data_file"
|
||||
done
|
||||
|
||||
echo "<!DOCTYPE html>
|
||||
# Generate light images data if exists
|
||||
echo " ]," >> "$data_file"
|
||||
if [ "$has_light" = "true" ]; then
|
||||
echo " light: [" >> "$data_file"
|
||||
for wallpaper in "$subdir/light"/*; do
|
||||
[ -f "$wallpaper" ] || continue
|
||||
case "$wallpaper" in
|
||||
*.jpg|*.jpeg|*.png|*.JPG|*.JPEG|*.PNG) ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
|
||||
local img_path="${wallpaper#./}"
|
||||
local img_filename="${wallpaper##*/}"
|
||||
local thumbnail_path="thumbnails/$section/light/$img_filename"
|
||||
echo " { src: '$img_path', thumb: '$thumbnail_path', alt: '$img_filename' }," >> "$data_file"
|
||||
done
|
||||
echo " ]" >> "$data_file"
|
||||
else
|
||||
echo " light: []" >> "$data_file"
|
||||
fi
|
||||
|
||||
echo "};" >> "$data_file"
|
||||
}
|
||||
|
||||
# Clean up old files
|
||||
rm -f *.html *.js
|
||||
|
||||
# Generate thumbnails
|
||||
generate_thumbnails
|
||||
|
||||
# Create main index.html
|
||||
cat > index.html << 'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
|
||||
<link rel='stylesheet' type='text/css' href='style.css'>
|
||||
<title>Gruvbox wallpapers</title>
|
||||
<script src='app.js' defer></script>
|
||||
<script src='https://kit.fontawesome.com/13865d7982.js' crossorigin='anonymous' defer></script>
|
||||
<style>
|
||||
.section-content {
|
||||
margin: 20px 0;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all 0.3s ease-in-out;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
|
||||
.section.selected .section-content {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Theme switcher styles */
|
||||
.section-theme-switcher {
|
||||
text-align: center;
|
||||
margin: 15px 0;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all 0.3s ease-in-out;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
|
||||
.section.selected .section-theme-switcher {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.theme-toggle {
|
||||
display: inline-flex;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.theme-btn {
|
||||
padding: 10px 20px;
|
||||
background-color: var(--bg-color-reverse);
|
||||
color: var(--fg-color-reverse);
|
||||
border: 2px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.3s ease;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
argin: 0 5px 0 5px;
|
||||
}
|
||||
|
||||
.theme-btn:hover {
|
||||
background-color: var(--bg-color-reverse);
|
||||
}
|
||||
|
||||
.theme-btn.active {
|
||||
border: 4px solid var(--fg-color);
|
||||
background-color: var(--bg-color);
|
||||
color: var(--fg-color);
|
||||
}
|
||||
|
||||
.subsection-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.subsection-content.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: var(--fg-color);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class='float-btns'>
|
||||
<a href='https://github.com/AngelJumbo/gruvbox-wallpapers' target='_blank' class='btn float-btn' title='Source code' >
|
||||
<a href='https://github.com/AngelJumbo/gruvbox-wallpapers' target='_blank' class='btn float-btn' title='Source code'>
|
||||
<span>
|
||||
<i class='fa-brands fa-github'></i>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-github-icon lucide-github"><path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"/><path d="M9 18c-4.51 2-5-2-7-2"/></svg>
|
||||
</span>
|
||||
</a>
|
||||
<button onclick='switchTheme()' class='btn float-btn' title='Switch theme'>
|
||||
<button onclick='switchMainTheme()' class='btn float-btn' title='Switch theme'>
|
||||
<span>
|
||||
<i id='light-icon' class='fa-solid fa-sun'></i>
|
||||
<i id='dark-icon' class='fa-solid fa-moon'></i>
|
||||
<svg id="light-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-sun-icon lucide-sun"><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></svg>
|
||||
<svg id="dark-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-moon-icon lucide-moon"><path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"/></svg>
|
||||
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<main>
|
||||
<h1>Gruvbox Wallpapers</h1>" >./index.html
|
||||
<h1>Gruvbox Wallpapers</h1>
|
||||
EOF
|
||||
|
||||
# Generate sections
|
||||
color=1
|
||||
|
||||
maxPerPage=8
|
||||
|
||||
declare -a sections
|
||||
|
||||
generate_thumbnails
|
||||
declare -a sections_with_light
|
||||
|
||||
for subdir in ./wallpapers/*; do
|
||||
section="${subdir##*/}"
|
||||
sections+=("$section")
|
||||
write_section_header $color "$section" ./index.html
|
||||
|
||||
page=1
|
||||
img_count=0
|
||||
subhtml="${section}_page${page}.html"
|
||||
touch ./$subhtml
|
||||
|
||||
echo "<div class='section' id='$section'>" >>./index.html
|
||||
|
||||
echo "<div class='pager'>" >>./index.html
|
||||
countImgs=$(find "$subdir" -type f | wc -l)
|
||||
countImgs=$((countImgs - 1))
|
||||
for i in $(seq 1 $((($countImgs / $maxPerPage) + 1))); do
|
||||
echo "<button class='btn pager-btn' onclick='loadPage(\"$section\", $i)'>$i</button>" >>./index.html
|
||||
done
|
||||
echo "</div>" >>./index.html
|
||||
echo "<div id='$section-content'>" >>./index.html
|
||||
echo "<div class='c'>" >>./$subhtml
|
||||
for wallpaper in ${subdir}/*; do
|
||||
if [ "$img_count" -ge $maxPerPage ]; then
|
||||
echo "</div>" >>./$subhtml
|
||||
page=$((page + 1))
|
||||
subhtml="${section}_page${page}.html"
|
||||
touch ./$subhtml
|
||||
|
||||
echo "<div class='c'>" >>./$subhtml
|
||||
img_count=0
|
||||
fi
|
||||
|
||||
write_img "$wallpaper" "./$subhtml"
|
||||
img_count=$((img_count + 1))
|
||||
done
|
||||
|
||||
echo "</div>" >>./$subhtml
|
||||
|
||||
echo "</div>" >>./index.html
|
||||
echo "</div>" >>./index.html
|
||||
has_light=$(check_has_light_folder "$subdir")
|
||||
|
||||
if [ "$has_light" = "true" ]; then
|
||||
sections_with_light+=("$section")
|
||||
fi
|
||||
|
||||
# Create the data file
|
||||
create_section_data "$section" "$subdir"
|
||||
|
||||
# Add section to main page
|
||||
echo " <h2 class='s$color clickable' onclick='activeSection(\"$section\")'>" >> index.html
|
||||
echo " $(echo "$section" | tr a-z A-Z)" >> index.html
|
||||
echo " </h2>" >> index.html
|
||||
echo " <div class='section' id='$section'>" >> index.html
|
||||
|
||||
# Add theme switcher if section has light variant
|
||||
if [ "$has_light" = "true" ]; then
|
||||
echo " <div class='section-theme-switcher'>" >> index.html
|
||||
echo " <div class='theme-toggle'>" >> index.html
|
||||
echo " <button class='theme-btn active' onclick='switchSectionTheme(\"$section\", \"dark\")' id='$section-dark-btn'>Dark</button>" >> index.html
|
||||
echo " <button class='theme-btn' onclick='switchSectionTheme(\"$section\", \"light\")' id='$section-light-btn'>Light</button>" >> index.html
|
||||
echo " </div>" >> index.html
|
||||
echo " </div>" >> index.html
|
||||
fi
|
||||
|
||||
echo " <div class='section-content' id='$section-content'>" >> index.html
|
||||
echo " <div class='loading'>Loading...</div>" >> index.html
|
||||
echo " </div>" >> index.html
|
||||
echo " </div>" >> index.html
|
||||
|
||||
color=$((color + 1))
|
||||
if [ "$color" -eq 8 ]; then
|
||||
color=1
|
||||
fi
|
||||
done
|
||||
echo "</main>" >>./index.html
|
||||
echo "<script>
|
||||
window.onload = () => {" >>./index.html
|
||||
|
||||
# Add all section data scripts
|
||||
for section in "${sections[@]}"; do
|
||||
echo " loadPage('$section', 1);" >>./index.html
|
||||
echo " <script src='${section}_data.js'></script>" >> index.html
|
||||
done
|
||||
|
||||
echo "
|
||||
activeSection('${sections[0]}');
|
||||
if (window.matchMedia('(prefers-color-scheme: dark)').matches){
|
||||
setTheme('dark');
|
||||
}else{
|
||||
setTheme('light');
|
||||
}
|
||||
}
|
||||
</script>" >>./index.html
|
||||
# Add main JavaScript
|
||||
cat >> index.html << 'EOF'
|
||||
<script>
|
||||
// Global state
|
||||
let activeSectionName = null;
|
||||
let sectionStates = {};
|
||||
|
||||
echo "</body>
|
||||
</html>" >>./index.html
|
||||
// Initialize section state
|
||||
function initSectionState(section) {
|
||||
if (!sectionStates[section]) {
|
||||
sectionStates[section] = {
|
||||
currentTheme: 'dark',
|
||||
currentPages: { dark: 1, light: 1 },
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function activeSection(section) {
|
||||
hideAllSections();
|
||||
const targetSection = document.getElementById(section);
|
||||
|
||||
targetSection.classList.add('selected');
|
||||
activeSectionName = section;
|
||||
|
||||
initSectionState(section);
|
||||
|
||||
// Load content if not already loaded
|
||||
if (!sectionStates[section].loaded) {
|
||||
loadSectionContent(section);
|
||||
}
|
||||
|
||||
// Reset to dark theme
|
||||
if (window.sectionData[section].hasLight) {
|
||||
switchSectionTheme(section, 'dark');
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
targetSection.scrollIntoView({ block: 'start', behavior: 'smooth' });
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function hideAllSections() {
|
||||
document.querySelectorAll('.section').forEach(s => {
|
||||
s.classList.remove('selected');
|
||||
});
|
||||
activeSectionName = null;
|
||||
}
|
||||
|
||||
function loadSectionContent(section) {
|
||||
const contentDiv = document.getElementById(section + '-content');
|
||||
const data = window.sectionData[section];
|
||||
|
||||
if (!data) {
|
||||
contentDiv.innerHTML = '<div class="loading">Error: Section data not found</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
let html = '';
|
||||
|
||||
// Dark content
|
||||
if (data.dark.length > 0) {
|
||||
html += `<div class="subsection-content active" id="${section}-dark">`;
|
||||
|
||||
// Dark pagination
|
||||
const darkPages = Math.ceil(data.dark.length / data.maxPerPage);
|
||||
if (darkPages > 1) {
|
||||
html += '<div class="pager">';
|
||||
for (let i = 1; i <= darkPages; i++) {
|
||||
const selectedClass = i === 1 ? ' selected' : '';
|
||||
html += `<button class="btn pager-btn${selectedClass}" onclick="loadPage('${section}', 'dark', ${i})">${i}</button>`;
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += `<div id="${section}-dark-content">`;
|
||||
html += generateImageGrid(data.dark.slice(0, data.maxPerPage));
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
// Light content
|
||||
if (data.hasLight && data.light.length > 0) {
|
||||
html += `<div class="subsection-content" id="${section}-light">`;
|
||||
|
||||
// Light pagination
|
||||
const lightPages = Math.ceil(data.light.length / data.maxPerPage);
|
||||
if (lightPages > 1) {
|
||||
html += '<div class="pager">';
|
||||
for (let i = 1; i <= lightPages; i++) {
|
||||
const selectedClass = i === 1 ? ' selected' : '';
|
||||
html += `<button class="btn pager-btn${selectedClass}" onclick="loadPage('${section}', 'light', ${i})">${i}</button>`;
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += `<div id="${section}-light-content">`;
|
||||
html += generateImageGrid(data.light.slice(0, data.maxPerPage));
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
contentDiv.innerHTML = html;
|
||||
sectionStates[section].loaded = true;
|
||||
}
|
||||
|
||||
function generateImageGrid(images) {
|
||||
let html = '<div class="c">';
|
||||
images.forEach(img => {
|
||||
html += `<a target="_blank" href="${img.src}">
|
||||
<img loading="lazy" src="${img.thumb}" alt="${img.alt}" width="200">
|
||||
</a>`;
|
||||
});
|
||||
html += '</div>';
|
||||
return html;
|
||||
}
|
||||
|
||||
function switchSectionTheme(section, theme) {
|
||||
const darkBtn = document.getElementById(section + '-dark-btn');
|
||||
const lightBtn = document.getElementById(section + '-light-btn');
|
||||
const darkContent = document.getElementById(section + '-dark');
|
||||
const lightContent = document.getElementById(section + '-light');
|
||||
|
||||
initSectionState(section);
|
||||
sectionStates[section].currentTheme = theme;
|
||||
|
||||
// Update button states
|
||||
if (darkBtn && lightBtn) {
|
||||
darkBtn.classList.toggle('active', theme === 'dark');
|
||||
lightBtn.classList.toggle('active', theme === 'light');
|
||||
}
|
||||
|
||||
// Switch content visibility
|
||||
if (darkContent && lightContent) {
|
||||
darkContent.classList.toggle('active', theme === 'dark');
|
||||
lightContent.classList.toggle('active', theme === 'light');
|
||||
}
|
||||
|
||||
// Load first page of selected theme
|
||||
loadPage(section, theme, 1);
|
||||
}
|
||||
|
||||
function loadPage(section, theme, page) {
|
||||
const data = window.sectionData[section];
|
||||
const images = data[theme];
|
||||
const startIdx = (page - 1) * data.maxPerPage;
|
||||
const endIdx = Math.min(startIdx + data.maxPerPage, images.length);
|
||||
const pageImages = images.slice(startIdx, endIdx);
|
||||
|
||||
const contentDiv = document.getElementById(`${section}-${theme}-content`);
|
||||
if (contentDiv) {
|
||||
contentDiv.innerHTML = generateImageGrid(pageImages);
|
||||
}
|
||||
|
||||
// Update pagination buttons
|
||||
const pagerButtons = document.getElementById(`${section}-${theme}`)?.getElementsByClassName('pager-btn');
|
||||
if (pagerButtons) {
|
||||
for (let i = 0; i < pagerButtons.length; i++) {
|
||||
pagerButtons[i].classList.toggle('selected', i === page - 1);
|
||||
}
|
||||
}
|
||||
|
||||
initSectionState(section);
|
||||
sectionStates[section].currentPages[theme] = page;
|
||||
}
|
||||
|
||||
// Main theme functions
|
||||
const HIDDEN_CLASS = 'hidden';
|
||||
|
||||
function hideThemeSwitcher(currentTheme) {
|
||||
if (currentTheme === 'dark') {
|
||||
document.getElementById('dark-icon')?.classList.add(HIDDEN_CLASS);
|
||||
document.getElementById('light-icon')?.classList.remove(HIDDEN_CLASS);
|
||||
} else {
|
||||
document.getElementById('light-icon')?.classList.add(HIDDEN_CLASS);
|
||||
document.getElementById('dark-icon')?.classList.remove(HIDDEN_CLASS);
|
||||
}
|
||||
}
|
||||
|
||||
function setMainTheme(newTheme) {
|
||||
document.documentElement.style.setProperty('color-scheme', newTheme);
|
||||
hideThemeSwitcher(newTheme);
|
||||
}
|
||||
|
||||
function switchMainTheme() {
|
||||
const current = document.documentElement.style.getPropertyValue('color-scheme');
|
||||
setMainTheme(current === 'dark' ? 'light' : 'dark');
|
||||
}
|
||||
|
||||
// Initialize
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
EOF
|
||||
|
||||
echo " activeSection('${sections[0]}');" >> index.html
|
||||
|
||||
cat >> index.html << 'EOF'
|
||||
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
setMainTheme('dark');
|
||||
} else {
|
||||
setMainTheme('light');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
|
||||
echo "Build complete! Generated $(echo ${#sections[@]}) sections with dynamic content loading."
|
||||
echo "Sections with light variants: ${sections_with_light[*]}"
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1761907660,
|
||||
"narHash": "sha256-kJ8lIZsiPOmbkJypG+B5sReDXSD1KGu2VEPNqhRa/ew=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "2fb006b87f04c4d3bdf08cfdbc7fab9c13d94a15",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
description = "Gruvbox-inspired wallpaper collection";
|
||||
|
||||
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
|
||||
outputs = {
|
||||
self,
|
||||
nixpkgs,
|
||||
}: let
|
||||
systems = ["x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin"];
|
||||
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f (import nixpkgs {inherit system;}));
|
||||
|
||||
mkWallpapersPkg = pkgs: name: path:
|
||||
pkgs.stdenv.mkDerivation {
|
||||
pname = "gruvbox-wallpapers-${name}";
|
||||
version = self.shortRev or "dev";
|
||||
src = ./.;
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
${
|
||||
if name == "default"
|
||||
then "find wallpapers -type f -exec cp {} $out/ \\;"
|
||||
else "cp -r ${path}/* $out/"
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
subdirs = {
|
||||
default = "wallpapers";
|
||||
anime = "wallpapers/anime";
|
||||
brands = "wallpapers/brands";
|
||||
game = "wallpapers/game";
|
||||
minimalistic = "wallpapers/minimalistic";
|
||||
mix = "wallpapers/mix";
|
||||
painting = "wallpapers/painting";
|
||||
photography = "wallpapers/photography";
|
||||
pixelart = "wallpapers/pixelart";
|
||||
renders = "wallpapers/renders";
|
||||
};
|
||||
in {
|
||||
formatter = forAllSystems (pkgs: pkgs.alejandra);
|
||||
|
||||
packages = forAllSystems (
|
||||
pkgs:
|
||||
nixpkgs.lib.mapAttrs (name: path: mkWallpapersPkg pkgs name path) subdirs
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -137,6 +137,7 @@ img:hover {
|
||||
}
|
||||
|
||||
.float-btns {
|
||||
z-index: 10;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
@@ -161,3 +162,181 @@ img:hover {
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Add these styles to your existing style.css */
|
||||
|
||||
.subsection-theme-switch {
|
||||
text-align: center;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.btn.subsection-theme-btn {
|
||||
padding: 8px 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
margin: 0 4px;
|
||||
border-radius: 4px;
|
||||
|
||||
&.selected {
|
||||
background-color: var(--bg-color);
|
||||
color: var(--fg-color);
|
||||
border: 2px solid var(--fg-color);
|
||||
}
|
||||
|
||||
&:not(.selected) {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.subsection-content {
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
/* Ensure subsection content containers are properly spaced */
|
||||
.section .subsection-content + .subsection-content {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Enhanced theme switch styles - Add to your style.css */
|
||||
|
||||
.subsection-theme-switch {
|
||||
text-align: center;
|
||||
margin: 15px 0 20px 0;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all 0.3s ease-in-out;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
|
||||
/* Show theme switch only when section is selected */
|
||||
.section.selected .subsection-theme-switch {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Theme switch container styled like a toggle */
|
||||
.theme-toggle-container {
|
||||
display: inline-flex;
|
||||
background-color: var(--bg-color-3);
|
||||
border-radius: 25px;
|
||||
padding: 4px;
|
||||
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
border: 2px solid var(--fg-color);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.theme-toggle-container::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 4px;
|
||||
width: calc(50% - 4px);
|
||||
height: calc(100% - 8px);
|
||||
background: linear-gradient(135deg, var(--bg-color-reverse), var(--bg-color-3-switch));
|
||||
border-radius: 20px;
|
||||
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.theme-toggle-container.light-active::before {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.btn.subsection-theme-btn {
|
||||
padding: 12px 24px;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--fg-color);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border-radius: 20px;
|
||||
min-width: 80px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
|
||||
&:hover {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
color: var(--fg-color-reverse);
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
&:not(.selected) {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* Add subtle glow effect for selected button */
|
||||
&.selected {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&.selected::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-radius: 20px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Animation for button text */
|
||||
.btn.subsection-theme-btn {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.btn.subsection-theme-btn::before {
|
||||
content: attr(data-text);
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transition: transform 0.3s ease;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.btn.subsection-theme-btn.selected::before {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -50%) scale(1.05);
|
||||
}
|
||||
|
||||
svg {
|
||||
stroke: var(--fg-color-reverse) !important;
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@media screen and (max-width: 640px) {
|
||||
.btn.subsection-theme-btn {
|
||||
padding: 10px 20px;
|
||||
font-size: 12px;
|
||||
min-width: 70px;
|
||||
}
|
||||
|
||||
.theme-toggle-container {
|
||||
padding: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark mode specific adjustments */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.theme-toggle-container {
|
||||
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.theme-toggle-container::before {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 2.5 MiB |
|
Before Width: | Height: | Size: 932 KiB |
|
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.1 MiB |
|
Before Width: | Height: | Size: 11 MiB After Width: | Height: | Size: 11 MiB |
|
Before Width: | Height: | Size: 8.3 MiB After Width: | Height: | Size: 8.3 MiB |
|
Before Width: | Height: | Size: 2.2 MiB After Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 4.4 MiB After Width: | Height: | Size: 4.4 MiB |
|
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 12 MiB After Width: | Height: | Size: 12 MiB |
|
Before Width: | Height: | Size: 3.3 MiB After Width: | Height: | Size: 3.3 MiB |
|
After Width: | Height: | Size: 14 MiB |
|
Before Width: | Height: | Size: 4.0 MiB After Width: | Height: | Size: 4.0 MiB |
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 256 KiB |
|
Before Width: | Height: | Size: 291 KiB After Width: | Height: | Size: 291 KiB |
|
Before Width: | Height: | Size: 435 KiB After Width: | Height: | Size: 435 KiB |
|
After Width: | Height: | Size: 7.9 MiB |
|
After Width: | Height: | Size: 3.1 MiB |
|
After Width: | Height: | Size: 1022 KiB |
|
Before Width: | Height: | Size: 14 MiB After Width: | Height: | Size: 14 MiB |
|
After Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 277 KiB After Width: | Height: | Size: 277 KiB |
|
Before Width: | Height: | Size: 277 KiB After Width: | Height: | Size: 277 KiB |
|
Before Width: | Height: | Size: 365 KiB |
|
After Width: | Height: | Size: 4.8 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 781 KiB After Width: | Height: | Size: 781 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 7.9 MiB |
|
After Width: | Height: | Size: 7.9 MiB |
|
After Width: | Height: | Size: 7.9 MiB |
|
After Width: | Height: | Size: 7.9 MiB |
|
Before Width: | Height: | Size: 167 KiB After Width: | Height: | Size: 167 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 179 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 270 KiB After Width: | Height: | Size: 270 KiB |
|
Before Width: | Height: | Size: 343 KiB After Width: | Height: | Size: 343 KiB |
|
Before Width: | Height: | Size: 287 KiB After Width: | Height: | Size: 287 KiB |
|
Before Width: | Height: | Size: 283 KiB After Width: | Height: | Size: 283 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 286 KiB After Width: | Height: | Size: 286 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 7.9 MiB |
|
After Width: | Height: | Size: 7.9 MiB |
|
After Width: | Height: | Size: 7.9 MiB |
|
After Width: | Height: | Size: 7.9 MiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 169 KiB |
|
After Width: | Height: | Size: 175 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 7.9 MiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 7.9 MiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 4.0 MiB |
|
After Width: | Height: | Size: 3.7 MiB |
|
After Width: | Height: | Size: 4.1 MiB |
|
After Width: | Height: | Size: 3.9 MiB |
|
After Width: | Height: | Size: 3.7 MiB |
|
After Width: | Height: | Size: 734 KiB |
|
After Width: | Height: | Size: 574 KiB |
|
After Width: | Height: | Size: 7.2 MiB |
|
After Width: | Height: | Size: 3.2 MiB |
|
After Width: | Height: | Size: 3.9 MiB |
|
After Width: | Height: | Size: 4.3 MiB |
|
After Width: | Height: | Size: 4.3 MiB |
|
After Width: | Height: | Size: 3.3 MiB |
|
After Width: | Height: | Size: 344 KiB |
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 184 KiB |
|
After Width: | Height: | Size: 7.9 MiB |
|
After Width: | Height: | Size: 7.9 MiB |
|
After Width: | Height: | Size: 7.9 MiB |
|
Before Width: | Height: | Size: 622 KiB After Width: | Height: | Size: 622 KiB |
|
Before Width: | Height: | Size: 7.8 MiB After Width: | Height: | Size: 7.8 MiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |