<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Eternal</title>
<style>
body {
font-family: sans-serif;
background: #f5f5f5;
margin: 0;
padding: 0;
}
header {
background: #e60023;
color: white;
padding: 1em;
text-align: center;
font-size: 1.8em;
}
.controls {
padding: 1em;
background: #fff;
text-align: center;
}
.controls input, .controls button {
margin: 0.5em;
padding: 0.5em;
font-size: 1em;
}
.grid {
column-count: 4;
column-gap: 1em;
padding: 1em;
}
.pin {
background: white;
display: inline-block;
margin-bottom: 1em;
width: 100%;
box-sizing: border-box;
border-radius: 10px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
overflow: hidden;
position: relative;
}
.pin img {
width: 100%;
cursor: pointer;
}
.description, .tags {
padding: 0.5em;
}
.favorite {
position: absolute;
top: 8px;
right: 8px;
font-size: 22px;
color: gray;
cursor: pointer;
user-select: none;
}
.favorite.active {
color: gold;
}
.likes {
font-size: 0.9em;
text-align: right;
padding: 0 0.5em 0.5em 0;
color: #888;
}
.tag {
display: inline-block;
background: #eee;
padding: 0.2em 0.5em;
border-radius: 5px;
margin: 0.2em;
cursor: pointer;
}
.tag:hover {
background: #ccc;
}
@media screen and (max-width: 1024px) {
.grid {
column-count: 3;
}
}
@media screen and (max-width: 768px) {
.grid {
column-count: 2;
}
}
@media screen and (max-width: 480px) {
.grid {
column-count: 1;
}
}
#modal {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.7);
display: none;
justify-content: center;
align-items: center;
z-index: 1000;
}
#modal img {
max-width: 90%;
max-height: 80vh;
border-radius: 10px;
}
</style>
</head>
<body>
<header>Pintorrest 完全版</header>
<div class="controls">
<input type="file" id="imageInput" accept="image/*">
<input type="text" id="descInput" placeholder="説明">
<input type="text" id="tagInput" placeholder="タグ(カンマ区切り)">
<button onclick="addPin()">投稿</button>
<br>
<input type="text" id="searchBox" placeholder="検索..." oninput="filterPins()">
</div>
<div class="grid" id="grid"></div>
<div id="modal" onclick="this.style.display='none'">
<img id="modalImg" src="">
</div>
<script>
let pins = JSON.parse(localStorage.getItem("pins") || "[]");
function renderPins() {
const grid = document.getElementById("grid");
grid.innerHTML = '';
pins.forEach((pin, index) => {
const pinElem = document.createElement("div");
pinElem.className = "pin";
pinElem.innerHTML = `
<span class="favorite ${pin.favorited ? 'active' : ''}" onclick="toggleFavorite(${index}, this)">★</span>
<img src="${pin.image}" onclick="showModal('${pin.image}')">
<div class="description">${pin.desc}</div>
<div class="tags">${pin.tags.map(tag => `<span class="tag" onclick="filterByTag('${tag}')">${tag}</span>`).join(' ')}</div>
<div class="likes">♥ ${pin.likes}</div>
`;
grid.appendChild(pinElem);
});
}
function addPin() {
const imageInput = document.getElementById("imageInput");
const desc = document.getElementById("descInput").value.trim();
const tags = document.getElementById("tagInput").value.split(',').map(t => t.trim()).filter(Boolean);
const file = imageInput.files[0];
if (!file || !desc) return alert("画像と説明を入力してください");
const reader = new FileReader();
reader.onload = function(e) {
pins.unshift({
image: e.target.result,
desc: desc,
tags: tags,
likes: 0,
favorited: false
});
savePins();
renderPins();
document.getElementById("descInput").value = '';
document.getElementById("tagInput").value = '';
document.getElementById("imageInput").value = '';
};
reader.readAsDataURL(file);
}
function showModal(src) {
document.getElementById("modalImg").src = src;
document.getElementById("modal").style.display = 'flex';
}
function toggleFavorite(index, elem) {
pins[index].favorited = !pins[index].favorited;
pins[index].likes += pins[index].favorited ? 1 : -1;
savePins();
renderPins();
}
function savePins() {
localStorage.setItem("pins", JSON.stringify(pins));
}
function filterPins() {
const keyword = document.getElementById("searchBox").value.toLowerCase();
document.querySelectorAll(".pin").forEach(pin => {
const text = pin.textContent.toLowerCase();
pin.style.display = text.includes(keyword) ? "inline-block" : "none";
});
}
function filterByTag(tag) {
document.getElementById("searchBox").value = tag;
filterPins();
}
renderPins();
</script>
</body>
</html>