3.0 Beta 5

This commit is contained in:
2026-04-13 15:14:24 +02:00
parent c56b0aab8a
commit 931ac91526
16 changed files with 151 additions and 32 deletions

View File

@@ -42,12 +42,12 @@
{ {
"type": "initial", "type": "initial",
"maximumWarning": "500kB", "maximumWarning": "500kB",
"maximumError": "1MB" "maximumError": "100MB"
}, },
{ {
"type": "anyComponentStyle", "type": "anyComponentStyle",
"maximumWarning": "4kB", "maximumWarning": "4kB",
"maximumError": "8kB" "maximumError": "100MB"
} }
], ],
"outputHashing": "all", "outputHashing": "all",

View File

@@ -1,5 +1,5 @@
{ {
"version": "3.0 Beta 4 (April 11, 2026)", "version": "3.0 Beta 5 (April 13, 2026)",
"ok": "Ok", "ok": "Ok",
"back": "Back", "back": "Back",
"aChatProgram": "A messaging platform that you can trust.", "aChatProgram": "A messaging platform that you can trust.",
@@ -104,11 +104,15 @@
"changeLogDialog": { "changeLogDialog": {
"label": "Chatenium has been updated", "label": "Chatenium has been updated",
"changeLog": { "changeLog": {
"1": "Added support for text channels inside networks", "1": "Started implementing Chatenium Pictures",
"2": "Bug fixes in message box" "2": "Made small changes to the UI",
"3": "Minor bug fixes in message box"
} }
}, },
"chatnav": { "chatnav": {
"pictureList": {
"myPictures": "My pictures"
},
"dmList": { "dmList": {
"newChat": "Start new chat", "newChat": "Start new chat",
"messageBox": { "messageBox": {
@@ -121,6 +125,11 @@
"newNetwork": "Start new network" "newNetwork": "Start new network"
} }
}, },
"pictures": {
"albumList": {
"noAlbum": "This user has no albums published"
}
},
"elements": { "elements": {
"messageBox": { "messageBox": {
"editMessageLabel": "Editing message: ", "editMessageLabel": "Editing message: ",

View File

@@ -61,8 +61,6 @@ export class Dm implements OnInit {
} }
} }
this.store.messageBox.editingMessage.set(null)
this.store.messageBox.message.set("")
return return
} }

View File

@@ -104,6 +104,7 @@ export class MessageBox {
this.viewModel().message.set("") this.viewModel().message.set("")
this.viewModel().files.set([]) this.viewModel().files.set([])
this.viewModel().dialogOpen.set(false) this.viewModel().dialogOpen.set(false)
this.viewModel().editingMessage.set(null)
} }
handleEnterKeydown(e: any) { handleEnterKeydown(e: any) {

View File

@@ -0,0 +1,3 @@
img {
display: block;
}

View File

@@ -4,7 +4,7 @@
@for (network of serviceManager.networks(); track network.networkId) { @for (network of serviceManager.networks(); track network.networkId) {
<button [class.enlarge]="breakpoint() == 'mobile'" tuiButton <button [class.enlarge]="breakpoint() == 'mobile'" tuiButton
[appearance]="router.url == '/chat/network/' + network.networkId ? 'primary' : 'flat'" [appearance]="router.url.startsWith('/chat/network/' + network.networkId) ? 'primary' : 'flat'"
[routerLink]="'/chat/network/' + network.networkId"> [routerLink]="'/chat/network/' + network.networkId">
<oimg [src]="network.picture" height="35px" width="35px" [radius]="10"></oimg> <oimg [src]="network.picture" height="35px" width="35px" [radius]="10"></oimg>
<div class="info"> <div class="info">

View File

@@ -120,8 +120,6 @@ export class Text {
} }
}) })
} }
this.store.messageBox.message.set("")
} }
async deleteMessage(messageId: string) { async deleteMessage(messageId: string) {

View File

@@ -20,7 +20,7 @@
<div tuiGroup orientation="vertical" style="width: 100%"> <div tuiGroup orientation="vertical" style="width: 100%">
@for (channel of category.channels; track channel) { @for (channel of category.channels; track channel) {
<button tuiButton class="channel" appearance="secondary" [disabled]="channel.type != 'message'" [routerLink]="'/chat/network/'+store.networkData().networkId+'/'+category.categoryId+'/'+channel.channelId"> <button tuiButton class="channel" [appearance]="router.url.endsWith(channel.channelId) ? 'primary' : 'secondary'" [disabled]="channel.type != 'message'" [routerLink]="'/chat/network/'+store.networkData().networkId+'/'+category.categoryId+'/'+channel.channelId">
@switch (channel.type) { @switch (channel.type) {
@case ("message") { @case ("message") {
<tui-icon icon="@tui.hash"></tui-icon> <tui-icon icon="@tui.hash"></tui-icon>

View File

@@ -14,7 +14,7 @@
grid-template-columns: 1fr 300px; grid-template-columns: 1fr 300px;
#router { #router {
background: var(--tui-background-neutral-1-pressed); background: var(--tui-background-neutral-1);
} }
main { main {

View File

@@ -1,5 +1,5 @@
import {Component, inject, OnInit, signal} from '@angular/core'; import {Component, inject, OnInit, signal} from '@angular/core';
import {ActivatedRoute, RouterLink, RouterOutlet} from '@angular/router'; import {ActivatedRoute, Router, RouterLink, RouterOutlet} from '@angular/router';
import {Chat} from '@chatenium/chatenium-sdk/domain/chatService.schema'; import {Chat} from '@chatenium/chatenium-sdk/domain/chatService.schema';
import {Message} from '@chatenium/chatenium-sdk/domain/dmService.schema'; import {Message} from '@chatenium/chatenium-sdk/domain/dmService.schema';
import {MessageBoxViewModel} from '../elements/message-box/message-box-viewmodel'; import {MessageBoxViewModel} from '../elements/message-box/message-box-viewmodel';
@@ -31,6 +31,7 @@ export class Network implements OnInit {
route = inject(ActivatedRoute) route = inject(ActivatedRoute)
indexedDb = inject(IndexedDB) indexedDb = inject(IndexedDB)
breakpoint = inject(TUI_BREAKPOINT) breakpoint = inject(TUI_BREAKPOINT)
router = inject(Router)
routerOutletActive = signal(false) routerOutletActive = signal(false)

View File

@@ -1,5 +1,5 @@
<button disabled tuiButton appearance="secondary" iconStart="@tui.mail-plus"> <button (click)="router.navigate(['/chat/picture/'+serviceManager.currentSession()!.userData.userid])" tuiButton [appearance]="router.url == '/chat/picture/' + serviceManager.currentSession()!.userData.userid ? 'primary' : 'secondary'" iconStart="@tui.user">
{{"chat.chatnav.dmList.newChat"|translate}} {{"chat.chatnav.pictureList.myPictures"|translate}}
</button> </button>
@for (chat of serviceManager.chats(); track chat.chatid) { @for (chat of serviceManager.chats(); track chat.chatid) {

View File

@@ -1,10 +1,14 @@
<ng-template [(tuiDialog)]="viewerOpen">
<oimg [src]="viewedPicture!.path" height="100%" width="100%" [radius]="0"></oimg>
</ng-template>
<main> <main>
@defer (when store) { @defer (when store) {
<navbar backButtonDest="/chat"> <navbar backButtonDest="/chat">
<div class="data"> <div class="data">
<oimg [src]="store.uploaderData().pfp" height="50px" width="50px" [radius]="15"></oimg> <oimg [src]="store.uploaderData().pfp" height="50px" width="50px" [radius]="15"></oimg>
<div class="uploader-data"> <div class="uploader-data">
@if (store.uploaderData().displayName == "") { @if (!store.uploaderData().displayName) {
<span class="main-name">{{'@'+store.uploaderData().username}}</span> <span class="main-name">{{'@'+store.uploaderData().username}}</span>
} @else { } @else {
<span class="main-name">{{store.uploaderData().displayName}}</span> <span class="main-name">{{store.uploaderData().displayName}}</span>
@@ -18,8 +22,27 @@
</navbar> </navbar>
<main> <main>
@if (openedAlbum) {
<div style="display: flex; align-items: center; gap: 10px">
<button tuiButton appearance="flat" iconStart="@tui.chevron-left" (click)="exitAlbum()"></button>
<h1 style="padding: 0; margin: 0">{{openedAlbum.name}}</h1>
</div>
<div id="pictureList">
@for (picture of openedAlbum.images; track picture) {
<oimg (click)="viewPicture(picture)" [src]="picture.path" height="200px" width="200px" [radius]="25" objectFit="none"></oimg>
}
</div>
} @else {
@if (store.albums().length == 0) {
<tui-block-status style="height: 300px">
<tui-icon icon="@tui.frown" tuiSlot="top" style="font-size: 150px"></tui-icon>
<h4>{{"chat.pictures.albumList.noAlbum"|translate}}</h4>
</tui-block-status>
} @else {
<div id="albumList">
@for (album of store.albums(); track album) { @for (album of store.albums(); track album) {
<div class="album"> <div class="album" (click)="enterAlbum(album.albumId)">
<masonry [maxColSize]="3" style="height: 300px; pointer-events: none;"> <masonry [maxColSize]="3" style="height: 300px; pointer-events: none;">
@for (file of album.images; track file) { @for (file of album.images; track file) {
<img [src]="file.path+'_thumbnail.png'" style="filter: blur(5px)"/> <img [src]="file.path+'_thumbnail.png'" style="filter: blur(5px)"/>
@@ -30,6 +53,9 @@
</div> </div>
</div> </div>
} }
</div>
}
}
</main> </main>
} }
</main> </main>

View File

@@ -31,7 +31,7 @@ main {
} }
} }
main { #albumList {
display: flex; display: flex;
gap: 10px; gap: 10px;
flex-wrap: wrap; flex-wrap: wrap;
@@ -45,6 +45,7 @@ main {
border-radius: 30px; border-radius: 30px;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
cursor: pointer;
.album-name { .album-name {
position: absolute; position: absolute;
@@ -66,4 +67,19 @@ main {
} }
} }
} }
#pictureList {
display: flex;
flex-wrap: wrap;
gap: 10px;
align-content: flex-start;
overflow-y: scroll;
oimg {
background: var(--tui-background-base-alt);
height: 200px;
border-radius: 25px;
cursor: pointer;
}
}
} }

View File

@@ -1,12 +1,17 @@
import {Component, inject, signal} from '@angular/core'; import {Component, inject, signal} from '@angular/core';
import {DmStorage, PictureStorage, ServiceManager} from '../../../service-manager'; import {DmStorage, PictureStorage, ServiceManager} from '../../../service-manager';
import {ActivatedRoute} from '@angular/router'; import {ActivatedRoute, Router} from '@angular/router';
import {IndexedDB} from '../../../storage/indexed-db'; import {IndexedDB} from '../../../storage/indexed-db';
import {TUI_BREAKPOINT, TuiButton, TuiIcon} from '@taiga-ui/core'; import {TUI_BREAKPOINT, TuiButton, TuiDialog, TuiIcon} from '@taiga-ui/core';
import {PictureService} from '@chatenium/chatenium-sdk/services/pictureService'; import {PictureService} from '@chatenium/chatenium-sdk/services/pictureService';
import {Navbar} from '../../elements/navbar/navbar'; import {Navbar} from '../../elements/navbar/navbar';
import {Oimg} from '../../elements/oimg/oimg'; import {Oimg} from '../../elements/oimg/oimg';
import {Masonry} from '../../elements/masonry/masonry'; import {Masonry} from '../../elements/masonry/masonry';
import {Album, Image} from '@chatenium/chatenium-sdk/domain/pictureService.schema';
import {pictureHandlers} from '@chatenium/chatenium-sdk/mocks/handlers/picture.http';
import {TuiBlockStatusComponent} from '@taiga-ui/layout';
import {TranslatePipe} from '@ngx-translate/core';
import {TuiBadgedContentDirective} from '@taiga-ui/kit';
@Component({ @Component({
selector: 'app-see', selector: 'app-see',
@@ -15,7 +20,11 @@ import {Masonry} from '../../elements/masonry/masonry';
Oimg, Oimg,
TuiButton, TuiButton,
TuiIcon, TuiIcon,
Masonry Masonry,
TuiDialog,
TuiBlockStatusComponent,
TranslatePipe,
TuiBadgedContentDirective
], ],
templateUrl: './see.html', templateUrl: './see.html',
styleUrl: './see.scss', styleUrl: './see.scss',
@@ -25,13 +34,50 @@ export class See {
route = inject(ActivatedRoute) route = inject(ActivatedRoute)
indexedDb = inject(IndexedDB) indexedDb = inject(IndexedDB)
breakpoint = inject(TUI_BREAKPOINT) breakpoint = inject(TUI_BREAKPOINT)
router = inject(Router)
uploaderId = "" uploaderId = ""
openedAlbum: Album | null = null
viewedPicture: Image | null = null
get viewerOpen() {
return this.viewedPicture != null
}
set viewerOpen(_: any) {
this.viewedPicture = null
this.router.navigate([], {
queryParams: { pictureId: null },
queryParamsHandling: "merge"
})
}
get store(): PictureStorage { get store(): PictureStorage {
return this.serviceManager.pictureServices()[this.uploaderId] return this.serviceManager.pictureServices()[this.uploaderId]
} }
enterAlbum(albumId: string) {
this.router.navigate([], {
queryParams: { albumId: albumId },
queryParamsHandling: "merge"
})
}
exitAlbum() {
this.openedAlbum = null
this.router.navigate([], {
queryParams: { albumId: null },
queryParamsHandling: "merge"
})
}
viewPicture(picture: Image) {
this.viewedPicture = picture
this.router.navigate([], {
queryParams: { pictureId: picture.imageId },
queryParamsHandling: "merge"
})
}
ngOnInit() { ngOnInit() {
this.route.params.subscribe(async params => { this.route.params.subscribe(async params => {
const uploaderId = params['uploaderId']; const uploaderId = params['uploaderId'];
@@ -60,7 +106,28 @@ export class See {
service: newService, service: newService,
} as PictureStorage } as PictureStorage
})); }));
// Show album
this.route.queryParams.subscribe(params => {
const albumId = params['albumId'];
if (albumId) {
const album = uploaderInfo.pictures.find(a => a.albumId === albumId)
if (album) {
this.openedAlbum = album
const pictureId = params['pictureId'];
if (pictureId) {
const picture = album.images.find(img => img.imageId === pictureId)
if (picture) {
this.viewedPicture = picture
}
}
}
}
})
} }
}); });
} }
protected readonly pictureHandlers = pictureHandlers;
} }

View File

@@ -1,5 +1,5 @@
export const environment = { export const environment = {
version: "3.0-beta4", version: "3.0-beta5",
api_url: "http://localhost:3000", api_url: "http://localhost:3000",
cdn_url: "http://localhost:4000", cdn_url: "http://localhost:4000",
ws_url: "ws://localhost:3000", ws_url: "ws://localhost:3000",

View File

@@ -1,5 +1,5 @@
export const environment = { export const environment = {
version: "3.0-beta4", version: "3.0-beta5",
api_url: "https://api.chatenium.hu", api_url: "https://api.chatenium.hu",
cdn_url: "https://cdn.chatenium.hu", cdn_url: "https://cdn.chatenium.hu",
ws_url: "wss://api.chatenium.hu", ws_url: "wss://api.chatenium.hu",