diff --git a/src/snek/app.py b/src/snek/app.py index 24af03b..227c23a 100644 --- a/src/snek/app.py +++ b/src/snek/app.py @@ -55,6 +55,7 @@ from snek.view.upload import UploadView from snek.view.user import UserView from snek.view.web import WebView from snek.view.channel import ChannelAttachmentView +from snek.view.settings.containers import ContainersIndexView, ContainersCreateView, ContainersUpdateView, ContainersDeleteView from snek.webdav import WebdavApplication from snek.sgit import GitApplication 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/repository/{name}/update.html", RepositoriesUpdateView) 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.git = GitApplication(self) self.add_subapp("/webdav", self.webdav) diff --git a/src/snek/static/chat-input.js b/src/snek/static/chat-input.js index 2d0914e..cec3d57 100644 --- a/src/snek/static/chat-input.js +++ b/src/snek/static/chat-input.js @@ -53,7 +53,8 @@ class ChatInputComponent extends HTMLElement { this.textarea.focus(); } - connectedCallback() { + async connectedCallback() { + this.user = await app.rpc.getUser(null); this.liveType = this.getAttribute("live-type") === "true"; this.liveTypeInterval = parseInt(this.getAttribute("live-type-interval")) || 3; this.channelUid = this.getAttribute("channel"); @@ -193,7 +194,7 @@ class ChatInputComponent extends HTMLElement { if (this.trackSecondsBetweenEvents(this.lastUpdateEvent, new Date()) > 1) { this.lastUpdateEvent = new Date(); 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); } } } diff --git a/src/snek/static/sandbox.css b/src/snek/static/sandbox.css index 1419fe4..c2ffffb 100644 --- a/src/snek/static/sandbox.css +++ b/src/snek/static/sandbox.css @@ -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 { - 0%, 100% { opacity: 0; } - 50% { opacity: 1; } - } +.star { + position: absolute; + 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 */ - .content { - position: relative; - z-index: 1; - color: #eee; - font-family: sans-serif; - text-align: center; - top: 40%; - transform: translateY(-40%); - } +@keyframes twinkle { + 0%, 100% { opacity: 0; } + 50% { opacity: 1; } +} +@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%); +} diff --git a/src/snek/templates/sandbox.html b/src/snek/templates/sandbox.html index 6fd9b3f..0322b00 100644 --- a/src/snek/templates/sandbox.html +++ b/src/snek/templates/sandbox.html @@ -1,31 +1,56 @@ - +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); +}); + diff --git a/src/snek/view/rpc.py b/src/snek/view/rpc.py index de94633..fd48124 100644 --- a/src/snek/view/rpc.py +++ b/src/snek/view/rpc.py @@ -36,9 +36,11 @@ class RPCView(BaseView): async def db_update(self, table_name, record): self._require_login() 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() user = await self.services.user.get(self.user_uid) + if not color: + color = user["color"] return await self.services.socket.broadcast(channel_uid, { "channel_uid": "293ecf12-08c9-494b-b423-48ba1a2d12c2", "event": "set_typing", @@ -47,7 +49,8 @@ class RPCView(BaseView): "user_uid": user['uid'], "username": user["username"], "nick": user["nick"], - "channel_uid": channel_uid + "channel_uid": channel_uid, + "color": color } })