Skip to content

Commit 4d8bfeb

Browse files
committed
Updated README.md a bit.
1 parent 2a1318a commit 4d8bfeb

File tree

4 files changed

+243
-2
lines changed

4 files changed

+243
-2
lines changed

zephyrcore/zephyr.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* and data binding capabilities.
44
*/
55
export default class ZephyrJS extends HTMLElement {
6-
static baseUrl = 'https://cdn.jsdelivr.net/gh/RPDevJesco/ZephyrJS@0.08';
6+
static baseUrl = 'https://cdn.jsdelivr.net/gh/RPDevJesco/ZephyrJS@0.09';
77

88
static setBaseUrl(url) {
99
ZephyrJS.baseUrl = url.endsWith('/') ? url : url + '/';

zephyrtemplates/Blog.js

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import ZephyrJS, { defineCustomElement } from "../zephyrcore/zephyr.js";
2+
3+
export default class Blog extends ZephyrJS {
4+
static get observedAttributes() {
5+
return ['user'];
6+
}
7+
8+
static get isCoreTemplate() {
9+
return true;
10+
}
11+
12+
constructor() {
13+
super();
14+
this.state = {
15+
posts: [],
16+
user: 'Anonymous',
17+
newPostContent: ''
18+
};
19+
}
20+
21+
connectedCallback() {
22+
super.connectedCallback();
23+
this.loadPosts();
24+
}
25+
26+
attributeChangedCallback(name, oldValue, newValue) {
27+
if (name === 'user') {
28+
this.setState({ user: newValue });
29+
}
30+
}
31+
32+
async loadPosts() {
33+
// In a real application, this would fetch posts from a server
34+
const dummyPosts = [
35+
{ id: 1, author: 'John Doe', content: 'This is a short post, like a tweet!', likes: 5, comments: [], timestamp: new Date().toISOString() },
36+
{ id: 2, author: 'Jane Smith', content: 'This is a longer post that would be more like a blog entry. It contains more detailed information and might span multiple paragraphs.', likes: 10, comments: [], timestamp: new Date().toISOString() }
37+
];
38+
await this.setState({ posts: dummyPosts });
39+
}
40+
41+
createPost(content) {
42+
const newPost = {
43+
id: this.state.posts.length + 1,
44+
author: this.state.user,
45+
content,
46+
likes: 0,
47+
comments: [],
48+
timestamp: new Date().toISOString()
49+
};
50+
this.setState({
51+
posts: [newPost, ...this.state.posts],
52+
newPostContent: ''
53+
});
54+
}
55+
56+
likePost(postId) {
57+
const updatedPosts = this.state.posts.map(post =>
58+
post.id === postId ? { ...post, likes: post.likes + 1 } : post
59+
);
60+
this.setState({ posts: updatedPosts });
61+
}
62+
63+
addComment(postId, comment) {
64+
const updatedPosts = this.state.posts.map(post =>
65+
post.id === postId ? { ...post, comments: [...post.comments, { author: this.state.user, content: comment }] } : post
66+
);
67+
this.setState({ posts: updatedPosts });
68+
}
69+
70+
evolvePost(postId, newContent) {
71+
const updatedPosts = this.state.posts.map(post =>
72+
post.id === postId ? { ...post, content: newContent, evolutions: [...(post.evolutions || []), { content: post.content, timestamp: new Date().toISOString() }] } : post
73+
);
74+
this.setState({ posts: updatedPosts });
75+
}
76+
77+
render() {
78+
return `
79+
<div class="blog-container">
80+
<div class="new-post">
81+
<textarea bind="{{newPostContent}}" placeholder="What's on your mind?"></textarea>
82+
<button on="click:{{createPost}}">Post</button>
83+
</div>
84+
<div class="posts">
85+
${this.state.posts.map(post => this.renderPost(post)).join('')}
86+
</div>
87+
</div>
88+
`;
89+
}
90+
91+
renderPost(post) {
92+
const isLongPost = post.content.length > 280;
93+
return `
94+
<div class="post ${isLongPost ? 'long-post' : 'short-post'}">
95+
<div class="post-header">
96+
<span class="author">${post.author}</span>
97+
<span class="timestamp">${new Date(post.timestamp).toLocaleString()}</span>
98+
</div>
99+
<div class="post-content">
100+
${isLongPost ? `<h2>${post.content.split(' ').slice(0, 5).join(' ')}...</h2>` : ''}
101+
<p>${isLongPost ? post.content.slice(0, 280) + '... <span class="read-more" on="click:{{expandPost}}">Read more</span>' : post.content}</p>
102+
</div>
103+
<div class="post-actions">
104+
<button on="click:{{likePost}}" data-post-id="${post.id}">👍 ${post.likes}</button>
105+
<button on="click:{{showComments}}" data-post-id="${post.id}">💬 ${post.comments.length}</button>
106+
<button on="click:{{evolvePost}}" data-post-id="${post.id}">🔄 Evolve</button>
107+
</div>
108+
<div class="comments" style="display: none;">
109+
${post.comments.map(comment => `
110+
<div class="comment">
111+
<span class="comment-author">${comment.author}:</span>
112+
<span class="comment-content">${comment.content}</span>
113+
</div>
114+
`).join('')}
115+
<div class="new-comment">
116+
<input type="text" placeholder="Add a comment...">
117+
<button on="click:{{addComment}}" data-post-id="${post.id}">Comment</button>
118+
</div>
119+
</div>
120+
</div>
121+
`;
122+
}
123+
124+
expandPost(event) {
125+
const postContent = event.target.closest('.post-content');
126+
const fullContent = this.state.posts.find(post => post.id === parseInt(event.target.closest('.post').dataset.postId)).content;
127+
postContent.innerHTML = `<p>${fullContent}</p>`;
128+
}
129+
130+
showComments(event) {
131+
const commentsSection = event.target.closest('.post').querySelector('.comments');
132+
commentsSection.style.display = commentsSection.style.display === 'none' ? 'block' : 'none';
133+
}
134+
135+
createPost() {
136+
if (this.state.newPostContent.trim()) {
137+
this.createPost(this.state.newPostContent);
138+
}
139+
}
140+
141+
likePost(event) {
142+
const postId = parseInt(event.target.dataset.postId);
143+
this.likePost(postId);
144+
}
145+
146+
addComment(event) {
147+
const postId = parseInt(event.target.dataset.postId);
148+
const commentInput = event.target.previousElementSibling;
149+
if (commentInput.value.trim()) {
150+
this.addComment(postId, commentInput.value);
151+
commentInput.value = '';
152+
}
153+
}
154+
155+
evolvePost(event) {
156+
const postId = parseInt(event.target.dataset.postId);
157+
const post = this.state.posts.find(p => p.id === postId);
158+
const newContent = prompt('Evolve this post:', post.content);
159+
if (newContent && newContent !== post.content) {
160+
this.evolvePost(postId, newContent);
161+
}
162+
}
163+
}
164+
165+
customElements.define('zephyr-blog', Blog);

zephyrtemplates/ZephyrCore.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,5 @@ import TooltipComponent from "../zephyrtemplates/TooltipComponent.js";
5555
import MarkdownShowcase from "../zephyrtemplates/MarkdownShowcase.js";
5656
import TimelineView from "../zephyrtemplates/TimelineView.js";
5757
import TimelineItem from "../zephyrtemplates/TimelineItem.js";
58-
import Modal from "../zephyrtemplates/Modal.js";
58+
import Modal from "../zephyrtemplates/Modal.js";
59+
import Blog from "../zephyrtemplates/Blog.js";
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<template id="blog">
2+
<style>
3+
.blog-container {
4+
font-family: Arial, sans-serif;
5+
max-width: 800px;
6+
margin: 0 auto;
7+
padding: 20px;
8+
}
9+
.new-post {
10+
margin-bottom: 20px;
11+
}
12+
.new-post textarea {
13+
width: 100%;
14+
height: 100px;
15+
margin-bottom: 10px;
16+
}
17+
.post {
18+
background-color: #f0f2f5;
19+
border-radius: 8px;
20+
padding: 15px;
21+
margin-bottom: 20px;
22+
}
23+
.post-header {
24+
display: flex;
25+
justify-content: space-between;
26+
margin-bottom: 10px;
27+
}
28+
.author {
29+
font-weight: bold;
30+
}
31+
.timestamp {
32+
color: #65676B;
33+
}
34+
.post-content h2 {
35+
margin-top: 0;
36+
}
37+
.post-actions {
38+
margin-top: 10px;
39+
}
40+
.post-actions button {
41+
margin-right: 10px;
42+
}
43+
.comments {
44+
margin-top: 10px;
45+
padding-top: 10px;
46+
border-top: 1px solid #ccc;
47+
}
48+
.comment {
49+
margin-bottom: 5px;
50+
}
51+
.comment-author {
52+
font-weight: bold;
53+
}
54+
.new-comment {
55+
margin-top: 10px;
56+
}
57+
.new-comment input {
58+
width: calc(100% - 80px);
59+
}
60+
.read-more {
61+
color: #1877F2;
62+
cursor: pointer;
63+
}
64+
</style>
65+
66+
<div class="blog-container">
67+
<div class="new-post">
68+
<textarea bind="{{newPostContent}}" placeholder="What's on your mind?"></textarea>
69+
<button on="click:{{createPost}}">Post</button>
70+
</div>
71+
<div class="posts">
72+
<!-- Posts will be dynamically inserted here -->
73+
</div>
74+
</div>
75+
</template>

0 commit comments

Comments
 (0)