split files up

This commit is contained in:
2024-12-02 09:54:55 +11:00
parent 225561e088
commit f14f49c2cd
3 changed files with 255 additions and 269 deletions

View File

@@ -1,182 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<style>
body {
margin: 0;
min-height: 100vh;
background: #242424;
font-family: monospace;
background-image: url("data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h20v20H0V0zm2 2v16h16V2H2z' fill='%23000000' fill-opacity='0.05'/%3E%3C/svg%3E");
}
a {
text-decoration: none;
color: inherit;
}
.bg-pattern {
position: fixed;
inset: 0;
opacity: 0.05;
z-index: 0;
background-image: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%239C92AC' fill-opacity='0.4'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
}
.container {
max-width: 600px;
margin: 0 auto;
padding: 2rem;
position: relative;
z-index: 1;
padding-top: 100px;
}
header {
text-align: center;
margin-bottom: 100px;
color:#f0f0f0;
font-size: 20px;
}
h1 {
font-size: 2.5rem;
transform: rotate(-1deg);
text-shadow: 2px 2px 0 #ffffff52, 3px 3px 0 #000;
margin-bottom: 0.5rem;
}
.social-links {
margin-top: 1rem;
font-size: 1rem;
}
.social-links a {
margin: 0 10px;
color: #f0f0f0;
text-decoration: none;
font-weight: bold;
}
.social-links a:hover {
color: #2563eb;
}
.post {
background: white;
padding: 1.5rem;
margin-bottom: 2rem;
border: 2px solid #000;
position: relative;
box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.1), 6px 6px 0 rgba(0, 0, 0, 0.05);
}
.post-header {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
}
.avatar {
width: 48px;
height: 48px;
background: #f0f0f0;
border: 2px solid black;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
transform: rotate(-2deg);
box-shadow: 2px 2px 0 #000;
}
.post-content {
text-shadow: 1px 1px 0 #fff;
}
.image-placeholder {
margin-top: 1rem;
border: 4px solid black;
background: #f0f0f0;
text-align: center;
transform: rotate(1deg);
box-shadow: 4px 4px 0 #000;
}
.post-actions {
margin-top: 1rem;
display: flex;
gap: 1rem;
}
.action-btn {
border: none;
background: none;
cursor: pointer;
display: flex;
align-items: center;
gap: 0.5rem;
font-family: inherit;
}
.action-btn.like {
color: #db2777;
transform: rotate(-1deg);
}
.action-btn.repost {
color: #2563eb;
transform: rotate(1deg);
}
.corner {
position: absolute;
width: 12px;
height: 12px;
border: 2px solid black;
}
.corner-tl {
top: -2px;
left: -2px;
border-right: 0;
border-bottom: 0;
}
.corner-tr {
top: -2px;
right: -2px;
border-left: 0;
border-bottom: 0;
}
.corner-bl {
bottom: -2px;
left: -2px;
border-right: 0;
border-top: 0;
}
.corner-br {
bottom: -2px;
right: -2px;
border-left: 0;
border-top: 0;
}
.avatar-img {
width: 250px;
height: 250px;
margin: 20px auto;
display: block;
}
</style>
<link rel="stylesheet" href="style.css">
<script src="main.js" defer></script>
</head>
<body>
<div class="bg-pattern"></div>
<div class="container">
<img src="/avatar.png" alt="Avatar" class="avatar-img">
<img src="avatar.png" alt="Avatar" class="avatar-img">
<header>
<h1>Litruv</h1>
<div>Dev/Tech Artist @<a href="https://mates.dev/">MatesMedia</a>
@@ -191,96 +22,5 @@
</header>
<div id="posts"></div>
</div>
<script>
function formatDate(dateString) {
return new Date(dateString).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
function getRandomRotation() {
return Math.random() * 6 - 3;
}
function createPost(post) {
const article = document.createElement('div');
article.className = 'post';
article.style.transform = `rotate(${getRandomRotation()}deg)`;
const postLink = document.createElement('a');
postLink.href = post.url;
postLink.target = "_blank";
postLink.style.textDecoration = "none";
const imageHTML = post.embed.length > 0
? post.embed.map(img => `
<a href="${img.url}" target="_blank">
<img class="image-placeholder" src="${img.url}" alt="${img.alt || 'Image'}" style="width: 100%;" />
</a>
`).join('')
: '';
article.innerHTML = `
<div class="post-header">
<div class="avatar">
<img src="${post.avatar}" alt="${post.author}" style="width: 100%; height: 100%; object-fit: cover;" />
</div>
<div>
<div style="font-weight: bold;">${post.author} (@${post.handle})</div>
<div style="font-size: 0.875rem; color: #666;">
${formatDate(post.createdAt)}
</div>
</div>
</div>
<div class="post-content">${post.text}</div>
${imageHTML}
<div class="post-actions">
<button class="action-btn like">♥ ${post.likes}</button>
<button class="action-btn repost">⟲ ${post.reposts}</button>
</div>
`;
postLink.appendChild(article);
return postLink;
}
function filterOriginalPosts(feed) {
return feed.filter((item) => {
const isRepost = item?.reason?.$type === 'app.bsky.feed.defs#reasonRepost';
const isReply = item?.post?.record?.reply;
return !isRepost && !isReply;
});
}
async function fetchPosts() {
try {
const response = await fetch("https://public.api.bsky.app/xrpc/app.bsky.feed.getAuthorFeed?actor=lit.mates.dev&limit=20&filter=posts_no_replies");
if (!response.ok) {
throw new Error('Failed to fetch posts');
}
const data = await response.json();
const filteredFeed = filterOriginalPosts(data.feed);
const posts = filteredFeed.map(item => ({
author: item.post.author.displayName,
handle: item.post.author.handle,
avatar: item.post.author.avatar,
createdAt: item.post.record.createdAt,
text: item.post.record.text,
likes: item.post.likeCount || 0,
reposts: item.post.repostCount || 0,
url: `https://bsky.app/profile/${item.post.author.handle}/post/${item.post.cid}`,
embed: item.post.embed?.images?.map(img => ({
url: img.fullsize,
alt: img.alt || ''
})) || []
}));
const postsContainer = document.getElementById('posts');
postsContainer.innerHTML = '';
posts.forEach(post => {
postsContainer.appendChild(createPost(post));
});
} catch (error) {
console.error('Error fetching posts:', error);
}
}
fetchPosts();
</script>
</body>
</html>

89
main.js Normal file
View File

@@ -0,0 +1,89 @@
function formatDate(dateString) {
return new Date(dateString).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
function getRandomRotation() {
return Math.random() * 3 - 1.5
}
function createPost(post) {
const article = document.createElement('div');
article.className = 'post';
article.style.transform = `rotate(${getRandomRotation()}deg)`;
const postLink = document.createElement('a');
postLink.href = post.url;
postLink.target = "_blank";
postLink.style.textDecoration = "none";
const imageHTML = post.embed.length > 0
? post.embed.map(img => `
<a href="${img.url}" target="_blank">
<img class="image-placeholder" src="${img.url}" alt="${img.alt || 'Image'}" style="width: 100%;" />
</a>
`).join('')
: '';
article.innerHTML = `
<div class="post-header">
<div class="avatar">
<img src="${post.avatar}" alt="${post.author}" style="width: 100%; height: 100%; object-fit: cover;" />
</div>
<div>
<div style="font-weight: bold;">${post.author} (@${post.handle})</div>
<div style="font-size: 0.875rem; color: #666;">
${formatDate(post.createdAt)}
</div>
</div>
</div>
<div class="post-content">${post.text}</div>
${imageHTML}
<div class="post-actions">
<button class="action-btn like">♥ ${post.likes}</button>
<button class="action-btn repost">⟲ ${post.reposts}</button>
</div>
`;
postLink.appendChild(article);
return postLink;
}
function filterOriginalPosts(feed) {
return feed.filter((item) => {
const isRepost = item?.reason?.$type === 'app.bsky.feed.defs#reasonRepost';
const isReply = item?.post?.record?.reply;
return !isRepost && !isReply;
});
}
async function fetchPosts() {
try {
const response = await fetch("https://public.api.bsky.app/xrpc/app.bsky.feed.getAuthorFeed?actor=lit.mates.dev&limit=20&filter=posts_no_replies");
if (!response.ok) {
throw new Error('Failed to fetch posts');
}
const data = await response.json();
const filteredFeed = filterOriginalPosts(data.feed);
const posts = filteredFeed.map(item => ({
author: item.post.author.displayName,
handle: item.post.author.handle,
avatar: item.post.author.avatar,
createdAt: item.post.record.createdAt,
text: item.post.record.text,
likes: item.post.likeCount || 0,
reposts: item.post.repostCount || 0,
url: `https://bsky.app/profile/${item.post.author.handle}/post/${item.post.cid}`,
embed: item.post.embed?.images?.map(img => ({
url: img.fullsize,
alt: img.alt || ''
})) || []
}));
const postsContainer = document.getElementById('posts');
postsContainer.innerHTML = '';
posts.forEach(post => {
postsContainer.appendChild(createPost(post));
});
} catch (error) {
console.error('Error fetching posts:', error);
}
}
fetchPosts();

157
style.css Normal file
View File

@@ -0,0 +1,157 @@
body {
margin: 0;
min-height: 100vh;
background: #242424;
font-family: monospace;
background-image: url("data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h20v20H0V0zm2 2v16h16V2H2z' fill='%23000000' fill-opacity='0.05'/%3E%3C/svg%3E");
}
a {
text-decoration: none;
color: inherit;
}
.bg-pattern {
position: fixed;
inset: 0;
opacity: 0.05;
z-index: 0;
background-image: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%239C92AC' fill-opacity='0.4'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
}
.container {
max-width: 600px;
margin: 0 auto;
padding: 2rem;
position: relative;
z-index: 1;
padding-top: 100px;
}
header {
text-align: center;
margin-bottom: 100px;
color: #f0f0f0;
font-size: 20px;
}
h1 {
font-size: 2.5rem;
transform: rotate(-1deg);
text-shadow: 2px 2px 0 #ffffff52, 3px 3px 0 #000;
margin-bottom: 0.5rem;
}
.social-links {
margin-top: 1rem;
font-size: 1rem;
}
.social-links a {
margin: 0 10px;
color: #f0f0f0;
text-decoration: none;
font-weight: bold;
}
.social-links a:hover {
color: #2563eb;
}
.post {
background: white;
padding: 1.5rem;
margin-bottom: 2rem;
border: 2px solid #000;
position: relative;
box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.1), 6px 6px 0 rgba(0, 0, 0, 0.05);
}
.post-header {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
}
.avatar {
width: 48px;
height: 48px;
background: #f0f0f0;
border: 2px solid black;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
transform: rotate(-2deg);
box-shadow: 2px 2px 0 #000;
}
.post-content {
text-shadow: 1px 1px 0 #fff;
}
.image-placeholder {
margin-top: 1rem;
border: 4px solid black;
background: #f0f0f0;
text-align: center;
transform: rotate(1deg);
box-shadow: 4px 4px 0 #000;
}
.post-actions {
margin-top: 1rem;
display: flex;
gap: 1rem;
}
.action-btn {
border: none;
background: none;
cursor: pointer;
display: flex;
align-items: center;
gap: 0.5rem;
font-family: inherit;
}
.action-btn.like {
color: #db2777;
transform: rotate(-1deg);
}
.action-btn.repost {
color: #2563eb;
transform: rotate(1deg);
}
.avatar-img {
width: 250px;
height: 250px;
margin: 20px auto;
display: block;
}
@keyframes wiggle {
0% {
transform: rotate(2deg);
}
50% {
transform: rotate(-2deg);
}
100% {
transform: rotate(2deg);
}
}
.post {
transform: rotate(0deg);
transition: transform 0.3s ease-in-out;
}
.post:hover {
animation: wiggle 2s ease-in-out infinite;
transform: rotate(2deg);
}