This commit is contained in:
retoor 2025-05-19 01:07:11 +02:00
parent 527b010b24
commit db5431d77d
5 changed files with 101 additions and 53 deletions

View File

@ -55,6 +55,7 @@ from snek.view.upload import UploadView
from snek.view.user import UserView from snek.view.user import UserView
from snek.view.web import WebView from snek.view.web import WebView
from snek.view.channel import ChannelAttachmentView from snek.view.channel import ChannelAttachmentView
from snek.view.settings.containers import ContainersIndexView, ContainersCreateView, ContainersUpdateView, ContainersDeleteView
from snek.webdav import WebdavApplication from snek.webdav import WebdavApplication
from snek.sgit import GitApplication from snek.sgit import GitApplication
SESSION_KEY = b"c79a0c5fda4b424189c427d28c9f7c34" SESSION_KEY = b"c79a0c5fda4b424189c427d28c9f7c34"
@ -208,6 +209,10 @@ class Application(BaseApplication):
self.router.add_view("/settings/repositories/create.html", RepositoriesCreateView) self.router.add_view("/settings/repositories/create.html", RepositoriesCreateView)
self.router.add_view("/settings/repositories/repository/{name}/update.html", RepositoriesUpdateView) self.router.add_view("/settings/repositories/repository/{name}/update.html", RepositoriesUpdateView)
self.router.add_view("/settings/repositories/repository/{name}/delete.html", RepositoriesDeleteView) self.router.add_view("/settings/repositories/repository/{name}/delete.html", RepositoriesDeleteView)
self.router.add_view("/settings/containers/index.html", ContainersIndexView)
self.router.add_view("/settings/containers/create.html", ContainersCreateView)
self.router.add_view("/settings/containers/container/{uid}/update.html", ContainersUpdateView)
self.router.add_view("/settings/containers/container/{uid}/delete.html", ContainersDeleteView)
self.webdav = WebdavApplication(self) self.webdav = WebdavApplication(self)
self.git = GitApplication(self) self.git = GitApplication(self)
self.add_subapp("/webdav", self.webdav) self.add_subapp("/webdav", self.webdav)

View File

@ -53,7 +53,8 @@ class ChatInputComponent extends HTMLElement {
this.textarea.focus(); this.textarea.focus();
} }
connectedCallback() { async connectedCallback() {
this.user = await app.rpc.getUser(null);
this.liveType = this.getAttribute("live-type") === "true"; this.liveType = this.getAttribute("live-type") === "true";
this.liveTypeInterval = parseInt(this.getAttribute("live-type-interval")) || 3; this.liveTypeInterval = parseInt(this.getAttribute("live-type-interval")) || 3;
this.channelUid = this.getAttribute("channel"); this.channelUid = this.getAttribute("channel");
@ -193,7 +194,7 @@ class ChatInputComponent extends HTMLElement {
if (this.trackSecondsBetweenEvents(this.lastUpdateEvent, new Date()) > 1) { if (this.trackSecondsBetweenEvents(this.lastUpdateEvent, new Date()) > 1) {
this.lastUpdateEvent = new Date(); this.lastUpdateEvent = new Date();
if (typeof app !== "undefined" && app.rpc && typeof app.rpc.set_typing === "function") { if (typeof app !== "undefined" && app.rpc && typeof app.rpc.set_typing === "function") {
app.rpc.set_typing(this.channelUid); app.rpc.set_typing(this.channelUid,this.user.color);
} }
} }
} }

View File

@ -1,28 +1,42 @@
/* each star */
.star {
position: absolute;
width: 2px;
height: 2px;
background: #fff;
border-radius: 50%;
opacity: 0;
/* flicker animation */
animation: twinkle ease-in-out infinite;
}
@keyframes twinkle { .star {
0%, 100% { opacity: 0; } position: absolute;
50% { opacity: 1; } width: 2px;
} height: 2px;
background: var(--star-color, #fff);
border-radius: 50%;
opacity: 0;
transition: background 0.5s ease;
animation: twinkle ease-in-out infinite;
}
/* optional page content */ @keyframes twinkle {
.content { 0%, 100% { opacity: 0; }
position: relative; 50% { opacity: 1; }
z-index: 1; }
color: #eee;
font-family: sans-serif;
text-align: center;
top: 40%;
transform: translateY(-40%);
}
@keyframes star-glow-frames {
0% {
box-shadow: 0 0 5px --star-color;
}
50% {
box-shadow: 0 0 20px --star-color, 0 0 30px --star-color;
}
100% {
box-shadow: 0 0 5px --star-color;
}
}
.star-glow {
animation: star-glow-frames 1s;
}
.content {
position: relative;
z-index: 1;
color: var(--star-content-color, #eee);
font-family: sans-serif;
text-align: center;
top: 40%;
transform: translateY(-40%);
}

View File

@ -1,31 +1,56 @@
<script> <script type="module">
import { app } from "/app.js";
// number of stars you want
const STAR_COUNT = 200;
const body = document.body;
for (let i = 0; i < STAR_COUNT; i++) { const STAR_COUNT = 200;
const star = document.createElement('div'); const body = document.body;
star.classList.add('star');
// random position within the viewport function createStar() {
star.style.left = Math.random() * 100 + '%'; const star = document.createElement('div');
star.style.top = Math.random() * 100 + '%'; star.classList.add('star');
star.style.left = `${Math.random() * 100}%`;
star.style.top = `${Math.random() * 100}%`;
const size = Math.random() * 2 + 1;
star.style.width = `${size}px`;
star.style.height = `${size}px`;
const duration = Math.random() * 3 + 2;
const delay = Math.random() * 5;
star.style.animationDuration = `${duration}s`;
star.style.animationDelay = `${delay}s`;
body.appendChild(star);
}
// random size (optional) Array.from({ length: STAR_COUNT }, createStar);
const size = Math.random() * 2 + 1; // between 1px and 3px
star.style.width = size + 'px';
star.style.height = size + 'px';
// random animation timing for natural flicker function lightenColor(hex, percent) {
const duration = Math.random() * 3 + 2; // 2s5s const num = parseInt(hex.replace("#", ""), 16);
const delay = Math.random() * 5; // 0s5s let r = (num >> 16) + Math.round(255 * percent / 100);
star.style.animationDuration = duration + 's'; let g = ((num >> 8) & 0x00FF) + Math.round(255 * percent / 100);
star.style.animationDelay = delay + 's'; let b = (num & 0x0000FF) + Math.round(255 * percent / 100);
r = Math.min(255, r);
g = Math.min(255, g);
b = Math.min(255, b);
return `#${(1 << 24 | r << 16 | g << 8 | b).toString(16).slice(1)}`;
}
body.appendChild(star); const originalColor = document.documentElement.style.getPropertyValue("--star-color").trim();
}
</script> function glowCSSVariable(varName, glowColor, duration = 500) {
const root = document.documentElement;
//igetComputedStyle(root).getPropertyValue(varName).trim();
glowColor = lightenColor(glowColor, 20);
root.style.setProperty(varName, glowColor);
setTimeout(() => {
root.style.setProperty(varName, originalColor);
}, duration);
}
function updateStarColorDelayed(color) {
glowCSSVariable('--star-color', color, 2500);
}
app.ws.addEventListener("set_typing", (data) => {
updateStarColorDelayed(data.data.color);
});
</script>

View File

@ -36,9 +36,11 @@ class RPCView(BaseView):
async def db_update(self, table_name, record): async def db_update(self, table_name, record):
self._require_login() self._require_login()
return await self.services.db.update(self.user_uid, table_name, record) return await self.services.db.update(self.user_uid, table_name, record)
async def set_typing(self,channel_uid): async def set_typing(self,channel_uid,color=None):
self._require_login() self._require_login()
user = await self.services.user.get(self.user_uid) user = await self.services.user.get(self.user_uid)
if not color:
color = user["color"]
return await self.services.socket.broadcast(channel_uid, { return await self.services.socket.broadcast(channel_uid, {
"channel_uid": "293ecf12-08c9-494b-b423-48ba1a2d12c2", "channel_uid": "293ecf12-08c9-494b-b423-48ba1a2d12c2",
"event": "set_typing", "event": "set_typing",
@ -47,7 +49,8 @@ class RPCView(BaseView):
"user_uid": user['uid'], "user_uid": user['uid'],
"username": user["username"], "username": user["username"],
"nick": user["nick"], "nick": user["nick"],
"channel_uid": channel_uid "channel_uid": channel_uid,
"color": color
} }
}) })