feat: implement dark mode toggle and enhance chat UI with timestamps

This commit is contained in:
2026-04-29 23:35:40 +02:00
parent 68a895c642
commit e5c5927c54
7 changed files with 276 additions and 214 deletions
+63 -170
View File
@@ -5,154 +5,13 @@
</component>
<component name="ChangeListManager">
<list default="true" id="c88cd8ce-faf7-47a5-802d-e8422c8df996" name="Changes" comment="initial commit">
<change afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/public/styles.css" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/APIService.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.gitignore" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/messenger.iml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/modules.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/vcs.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/.package-lock.json" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/.package-lock.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/SECURITY.md" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/SECURITY.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/_tsc.js" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/_tsc.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/_tsserver.js" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/_tsserver.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/_typingsInstaller.js" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/_typingsInstaller.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/cs/diagnosticMessages.generated.json" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/cs/diagnosticMessages.generated.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/de/diagnosticMessages.generated.json" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/de/diagnosticMessages.generated.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/es/diagnosticMessages.generated.json" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/es/diagnosticMessages.generated.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/fr/diagnosticMessages.generated.json" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/fr/diagnosticMessages.generated.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/it/diagnosticMessages.generated.json" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/it/diagnosticMessages.generated.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/ja/diagnosticMessages.generated.json" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/ja/diagnosticMessages.generated.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/ko/diagnosticMessages.generated.json" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/ko/diagnosticMessages.generated.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.decorators.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.decorators.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.decorators.legacy.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.decorators.legacy.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.dom.asynciterable.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.dom.asynciterable.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.dom.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.dom.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.dom.iterable.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.dom.iterable.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.collection.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.collection.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.core.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.core.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.generator.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.generator.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.iterable.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.iterable.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.promise.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.promise.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.proxy.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.proxy.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.reflect.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.reflect.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.symbol.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.symbol.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2016.array.include.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2016.array.include.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2016.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2016.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2016.full.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2016.full.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2016.intl.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2016.intl.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.date.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.date.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.full.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.full.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.intl.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.intl.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.object.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.object.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.string.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.string.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2018.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2018.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2018.full.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2018.full.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2018.intl.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2018.intl.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2018.promise.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2018.promise.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2018.regexp.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2018.regexp.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2019.array.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2019.array.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2019.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2019.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2019.full.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2019.full.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2019.intl.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2019.intl.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2019.object.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2019.object.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2019.string.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2019.string.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2019.symbol.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2019.symbol.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.bigint.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.bigint.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.date.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.date.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.full.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.full.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.intl.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.intl.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.number.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.number.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.promise.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.promise.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.string.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.string.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2021.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2021.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2021.full.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2021.full.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2021.intl.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2021.intl.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2021.promise.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2021.promise.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2021.string.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2021.string.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2021.weakref.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2021.weakref.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2022.array.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2022.array.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2022.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2022.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2022.error.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2022.error.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2022.full.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2022.full.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2022.intl.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2022.intl.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2022.object.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2022.object.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2022.regexp.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2022.regexp.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2022.string.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2022.string.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2023.array.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2023.array.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2023.collection.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2023.collection.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2023.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2023.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2023.full.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2023.full.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2023.intl.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2023.intl.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.collection.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.collection.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.full.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.full.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.object.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.object.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.promise.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.promise.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.regexp.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.regexp.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.string.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2024.string.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2025.collection.d.ts" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2025.d.ts" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2025.float16.d.ts" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2025.full.d.ts" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2025.intl.d.ts" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2025.iterator.d.ts" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2025.promise.d.ts" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es2025.regexp.d.ts" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es5.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es5.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es6.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.es6.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.array.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.array.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.collection.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.collection.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.date.d.ts" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.decorators.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.decorators.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.disposable.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.disposable.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.error.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.error.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.full.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.full.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.intl.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.intl.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.temporal.d.ts" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.esnext.typedarrays.d.ts" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.scripthost.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.scripthost.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.webworker.asynciterable.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.webworker.asynciterable.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.webworker.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.webworker.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.webworker.importscripts.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.webworker.importscripts.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/lib.webworker.iterable.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/lib.webworker.iterable.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/pl/diagnosticMessages.generated.json" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/pl/diagnosticMessages.generated.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/pt-br/diagnosticMessages.generated.json" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/pt-br/diagnosticMessages.generated.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/ru/diagnosticMessages.generated.json" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/ru/diagnosticMessages.generated.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/tr/diagnosticMessages.generated.json" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/tr/diagnosticMessages.generated.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/tsserverlibrary.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/tsserverlibrary.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/tsserverlibrary.js" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/tsserverlibrary.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/typescript.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/typescript.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/typescript.js" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/typescript.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/watchGuard.js" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/watchGuard.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/zh-cn/diagnosticMessages.generated.json" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/zh-cn/diagnosticMessages.generated.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/lib/zh-tw/diagnosticMessages.generated.json" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/lib/zh-tw/diagnosticMessages.generated.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/node_modules/typescript/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/node_modules/typescript/package.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/package-lock.json" beforeDir="false" afterPath="$PROJECT_DIR$/package-lock.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/APIServices.ts" beforeDir="false" afterPath="$PROJECT_DIR$/public/index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/public/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/public/index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/public/styles.css" beforeDir="false" afterPath="$PROJECT_DIR$/public/styles.css" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/APIService.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/APIService.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/ChatUI.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/ChatUI.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/StateManager.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/StateManager.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/main.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/types.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/types.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/tsconfig.json" beforeDir="false" afterPath="$PROJECT_DIR$/tsconfig.json" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -163,6 +22,7 @@
<persistenceIdMap>
<entry key="_/home/fegger/Code/WEBP/messenger" value="3CiKVJqD0R4NxVpiB3jp5CMZBJD" />
<entry key="_/home/fegger/Code/WEBP/messenger.old" value="3CiC4djikHRSu96Gb5qeHHIlP64" />
<entry key="_/home/fegger/WebstormProjects/messenger" value="3D2sqBAdw2UmoPkhwodtWI8JNja" />
</persistenceIdMap>
</component>
<component name="CopilotUserSelectedChatMode">
@@ -222,7 +82,7 @@
<component name="GithubPullRequestsUISettings">{
&quot;selectedUrlAndAccountId&quot;: {
&quot;url&quot;: &quot;https://github.com/floegger/messenger.git&quot;,
&quot;accountId&quot;: &quot;c3dae145-2cec-468f-9f70-5b09324effc3&quot;
&quot;accountId&quot;: &quot;51fc9917-8632-47ef-b79f-cd5552c43996&quot;
}
}</component>
<component name="McpProjectServerCommands">
@@ -243,30 +103,60 @@
<option name="openDirectoriesWithSingleClick" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;JavaScript Debug.index.html.executor&quot;: &quot;Run&quot;,
&quot;ModuleVcsDetector.initialDetectionPerformed&quot;: &quot;true&quot;,
&quot;Node.js.main.ts.executor&quot;: &quot;Run&quot;,
&quot;RunOnceActivity.MCP Project settings loaded&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252&quot;: &quot;true&quot;,
&quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
&quot;RunOnceActivity.typescript.service.memoryLimit.init&quot;: &quot;true&quot;,
&quot;codeWithMe.voiceChat.enabledByDefault&quot;: &quot;false&quot;,
&quot;git-widget-placeholder&quot;: &quot;dev&quot;,
&quot;javascript.preferred.runtime.type.id&quot;: &quot;node&quot;,
&quot;last_opened_file_path&quot;: &quot;/home/fegger/Code/WEBP&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;http.proxy&quot;,
&quot;ts.external.directory.path&quot;: &quot;/home/fegger/Code/WEBP/messenger/node_modules/typescript/lib&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"JavaScript Debug.index.html.executor": "Run",
"ModuleVcsDetector.initialDetectionPerformed": "true",
"Node.js.main.ts.executor": "Run",
"RunOnceActivity.MCP Project settings loaded": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
"RunOnceActivity.git.unshallow": "true",
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
"codeWithMe.voiceChat.enabledByDefault": "false",
"git-widget-placeholder": "dev",
"javascript.preferred.runtime.type.id": "node",
"last_opened_file_path": "/home/fegger/Code/WEBP",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"npm.build.executor": "Run",
"npm.start.executor": "Run",
"settings.editor.selected.configurable": "http.proxy",
"ts.external.directory.path": "/home/fegger/.local/share/JetBrains/Toolbox/apps/webstorm/plugins/javascript-plugin/jsLanguageServicesImpl/external",
"vue.rearranger.settings.migration": "true"
}
}</component>
}]]></component>
<component name="RunManager" selected="npm.build">
<configuration name="build" type="js.build_tools.npm" temporary="true" nameIsGenerated="true">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="build" />
</scripts>
<node-interpreter value="project" />
<envs />
<method v="2" />
</configuration>
<configuration name="start" type="js.build_tools.npm" temporary="true" nameIsGenerated="true">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="start" />
</scripts>
<node-interpreter value="project" />
<envs />
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="npm.build" />
<item itemvalue="npm.start" />
</list>
</recent_temporary>
</component>
<component name="SharedIndexes">
<attachedChunks>
<set>
@@ -295,6 +185,7 @@
<workItem from="1776869393425" duration="23728000" />
<workItem from="1776920367612" duration="652000" />
<workItem from="1776921034095" duration="1037000" />
<workItem from="1777491687732" duration="1075000" />
</task>
<servers />
</component>
@@ -314,7 +205,9 @@
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="initial commit" />
<option name="LAST_COMMIT_MESSAGE" value="initial commit" />
<MESSAGE value="refactor: simplify HTML structure and improve accessibility for login and registration forms" />
<option name="LAST_COMMIT_MESSAGE" value="refactor: simplify HTML structure and improve accessibility for login and registration forms" />
<option name="MAKE_NEW_CHANGELIST_ACTIVE" value="true" />
</component>
<component name="github-copilot-workspace">
<instructionFileLocations>
+5 -2
View File
@@ -7,6 +7,7 @@
<link rel="stylesheet" href="styles.css"/>
</head>
<body>
<button id="theme-toggle" type="button">Dark</button>
<div id="login-view" class="view">
<div class="auth-container">
@@ -56,12 +57,14 @@
<aside id="user-list">
<h3>Users</h3>
<!-- ChatUI.renderUserList() -->
</aside>
<main class="chat-main">
<div class="chat-header">
<span id="chat-username">Select a user</span>
<button id="reload-btn" type="button">Reload</button>
</div>
<div id="messages">
<!-- ChatUI.renderMessage() -->
</div>
<form id="message-form" class="message-form">
<label class="sr-only" for="message-input">Message</label>
+136 -27
View File
@@ -1,3 +1,49 @@
/* Catppuccin Latte (light) */
:root {
--bg: #e6e9ef; /* Mantle */
--surface: #eff1f5; /* Base */
--sidebar-bg: #e6e9ef; /* Mantle */
--border: #ccd0da; /* Surface0 */
--text: #4c4f69; /* Text */
--text-muted: #8c8fa1; /* Overlay1 */
--input-bg: #eff1f5; /* Base */
--input-border: #bcc0cc; /* Surface1 */
--user-hover: #ccd0da; /* Surface0 */
--reload-bg: #dce0e8; /* Crust */
--reload-border: #bcc0cc; /* Surface1 */
--reload-hover: #ccd0da; /* Surface0 */
--msg-received-bg: #ccd0da; /* Surface0 */
--msg-received-text:#4c4f69; /* Text */
--error-bg: #f2cdcd; /* Flamingo tint */
--error-text: #d20f39; /* Red */
--accent: #1e66f5; /* Blue */
--accent-hover: #04a5e5; /* Sky */
--accent-text: #eff1f5; /* Base */
}
/* Catppuccin Mocha (dark) */
[data-theme="dark"] {
--bg: #181825; /* Mantle */
--surface: #1e1e2e; /* Base */
--sidebar-bg: #181825; /* Mantle */
--border: #313244; /* Surface0 */
--text: #cdd6f4; /* Text */
--text-muted: #6c7086; /* Overlay0 */
--input-bg: #1e1e2e; /* Base */
--input-border: #45475a; /* Surface1 */
--user-hover: #313244; /* Surface0 */
--reload-bg: #313244; /* Surface0 */
--reload-border: #45475a; /* Surface1 */
--reload-hover: #45475a; /* Surface1 */
--msg-received-bg: #313244; /* Surface0 */
--msg-received-text:#cdd6f4; /* Text */
--error-bg: #3b1b27; /* custom deep red */
--error-text: #f38ba8; /* Red */
--accent: #89b4fa; /* Blue */
--accent-hover: #74c7ec; /* Sapphire */
--accent-text: #1e1e2e; /* Base */
}
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
@@ -6,12 +52,14 @@
body {
font-family: 'Segoe UI', Arial, sans-serif;
background: #f0f2f5;
background: var(--bg);
color: var(--text);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: flex-start;
padding: 2rem;
transition: background 0.2s, color 0.2s;
}
.sr-only {
@@ -26,23 +74,43 @@ body {
border: 0;
}
#theme-toggle {
position: fixed;
top: 1rem;
right: 1rem;
background: var(--surface);
color: var(--text);
border: 1px solid var(--border);
border-radius: 20px;
padding: 0.35rem 0.75rem;
font-size: 0.85rem;
cursor: pointer;
transition: background 0.2s, color 0.2s, border-color 0.2s;
z-index: 100;
}
#theme-toggle:hover {
background: var(--user-hover);
}
.auth-container {
width: 100%;
max-width: 440px;
}
.auth-section {
background: white;
background: var(--surface);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 1rem;
box-shadow: 0 1px 4px rgba(0,0,0,0.1);
transition: background 0.2s;
}
.auth-section h2 {
margin-bottom: 1rem;
font-size: 1.2rem;
color: #333;
color: var(--text);
}
form {
@@ -53,22 +121,23 @@ form {
input, select {
padding: 0.6rem 0.8rem;
border: 1px solid #ccc;
border: 1px solid var(--input-border);
border-radius: 6px;
font-size: 0.95rem;
transition: border-color 0.2s;
background: white;
transition: border-color 0.2s, background 0.2s, color 0.2s;
background: var(--input-bg);
color: var(--text);
}
input:focus, select:focus {
outline: none;
border-color: #007bff;
border-color: var(--accent);
}
button[type="submit"] {
padding: 0.6rem;
background: #007bff;
color: white;
background: var(--accent);
color: var(--accent-text);
border: none;
border-radius: 6px;
font-size: 0.95rem;
@@ -77,7 +146,7 @@ button[type="submit"] {
}
button[type="submit"]:hover {
background: #0056b3;
background: var(--accent-hover);
}
.chat-app {
@@ -85,25 +154,27 @@ button[type="submit"]:hover {
width: 100%;
max-width: 900px;
height: 80vh;
background: white;
background: var(--surface);
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 20px rgba(0,0,0,0.12);
transition: background 0.2s;
}
#user-list {
width: 220px;
border-right: 1px solid #e9ecef;
border-right: 1px solid var(--border);
overflow-y: auto;
padding: 1rem;
background: #f8f9fa;
background: var(--sidebar-bg);
transition: background 0.2s, border-color 0.2s;
}
#user-list h3 {
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #888;
color: var(--text-muted);
margin-bottom: 0.8rem;
}
@@ -112,23 +183,52 @@ button[type="submit"]:hover {
border-radius: 6px;
cursor: pointer;
font-size: 0.95rem;
color: #333;
color: var(--text);
transition: background 0.15s;
}
.user-item:hover {
background: #e9ecef;
background: var(--user-hover);
}
.user-item.active {
background: #007bff;
color: white;
background: var(--accent);
color: var(--accent-text);
}
.chat-main {
flex: 1;
display: flex;
flex-direction: column;
min-width: 0;
}
.chat-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.6rem 1rem;
border-bottom: 1px solid var(--border);
background: var(--surface);
font-weight: 600;
font-size: 0.95rem;
color: var(--text);
transition: background 0.2s, border-color 0.2s;
}
.chat-header button {
padding: 0.3rem 0.8rem;
font-size: 0.8rem;
background: var(--reload-bg);
color: var(--text);
border: 1px solid var(--reload-border);
border-radius: 6px;
cursor: pointer;
transition: background 0.15s;
}
.chat-header button:hover {
background: var(--reload-hover);
}
#messages {
@@ -142,31 +242,40 @@ button[type="submit"]:hover {
.message {
max-width: 70%;
width: fit-content;
padding: 8px 12px;
border-radius: 12px;
font-size: 0.95rem;
line-height: 1.4;
word-break: break-word;
display: flex;
flex-direction: column;
gap: 2px;
}
.message-time {
font-size: 0.7rem;
opacity: 0.65;
}
.sent {
background: #007bff;
color: white;
margin-left: auto;
align-self: flex-end;
background: var(--accent);
color: var(--accent-text);
border-bottom-right-radius: 4px;
}
.received {
background: #e9ecef;
color: #333;
margin-right: auto;
align-self: flex-start;
background: var(--msg-received-bg);
color: var(--msg-received-text);
border-bottom-left-radius: 4px;
}
.message-form {
display: flex;
padding: 0.8rem;
border-top: 1px solid #e9ecef;
border-top: 1px solid var(--border);
gap: 0.5rem;
}
@@ -181,8 +290,8 @@ button[type="submit"]:hover {
}
.error-message {
background: #fce4e4;
color: #c0392b;
background: var(--error-bg);
color: var(--error-text);
padding: 0.6rem 1rem;
border-radius: 6px;
margin-top: 0.5rem;
+3 -2
View File
@@ -3,6 +3,7 @@ import {
LoginResponse,
RegisterResponse,
SendMessageResponse,
Message,
} from "./types.js";
export class APIService {
@@ -77,8 +78,8 @@ export class APIService {
async getConversation( token: string, user1Id: string, user2Id:string ): Promise<Message[]> {
const url = new URL( `${APIService.baseUrl}/get_conversation.php` );
url.searchParams.set( "token", token );
url.searchParams.set( "token", user1Id );
url.searchParams.set( "conversation_id", user2Id );
url.searchParams.set( "user1_id", user1Id );
url.searchParams.set( "user2_id", user2Id );
const response = await fetch( url, {method: "GET"} );;
if ( !response.ok ) {
+27 -2
View File
@@ -37,18 +37,31 @@ export class ChatUI {
const bubble = document.createElement( "div" );
bubble.classList.add( "message" );
if ( message.sender_id === currentUserId ) {
if ( String(message.sender_id) === String(currentUserId) ) {
bubble.classList.add( "sent" );
} else {
bubble.classList.add( "received" );
}
bubble.textContent = message.message;
const text = document.createElement( "span" );
text.textContent = message.message;
const time = document.createElement( "span" );
time.classList.add( "message-time" );
time.textContent = formatTimestamp( message.timestamp );
bubble.appendChild( text );
bubble.appendChild( time );
container.appendChild( bubble );
container.scrollTop = container.scrollHeight;
}
setChatHeader ( name: string ): void {
const el = document.getElementById( "chat-username" );
if ( el ) el.textContent = name;
}
renderConversation( messages: Message[], currentUserId: string ): void {
this.clearMessages();
messages.forEach( ( message ) => {
@@ -112,3 +125,15 @@ export class ChatUI {
});
}
}
function formatTimestamp ( timestamp: number | string ): string {
// Try parsing as-is (works for date strings and ms numbers)
let date = new Date( timestamp );
if ( !isNaN( date.getTime() ) ) return date.toLocaleString();
// Fall back: treat as Unix seconds
date = new Date( Number( timestamp ) * 1000 );
if ( !isNaN( date.getTime() ) ) return date.toLocaleString();
return "";
}
+38 -7
View File
@@ -8,9 +8,23 @@ const api = new APIService();
const state = new StateManager();
const ui = new ChatUI();
let pollingInterval: number | null = null;
// initialize app when DOM is ready
document.addEventListener("DOMContentLoaded", async () => {
console.log("[Messenger] App initialised. API →", "http://webp-ilv-backend.cs.technikum-wien.at/messenger");
// Dark mode
const themeToggle = document.getElementById( "theme-toggle" ) as HTMLButtonElement;
const applyTheme = ( dark: boolean ) => {
document.documentElement.dataset.theme = dark ? "dark" : "";
themeToggle.textContent = dark ? "Light" : "Dark";
};
let darkMode = localStorage.getItem( "theme" ) === "dark";
applyTheme( darkMode );
themeToggle.addEventListener( "click", () => {
darkMode = !darkMode;
localStorage.setItem( "theme", darkMode ? "dark" : "light" );
applyTheme( darkMode );
});
// restore from session if available
if (state.isLoggedIn()) {
ui.showView("chat-view");
@@ -82,6 +96,12 @@ document.addEventListener("DOMContentLoaded", async () => {
}
});
const reloadBtn = document.getElementById( "reload-btn" );
reloadBtn?.addEventListener( "click", () => {
const receiverId = state.getSelectedReceiverId();
if ( receiverId ) loadConversation( receiverId );
});
const messageForm = document.getElementById("message-form") as HTMLFormElement;
messageForm?.addEventListener("submit", async (e) => {
e.preventDefault();
@@ -104,7 +124,7 @@ document.addEventListener("DOMContentLoaded", async () => {
sender_id: state.getUserId(),
receiver_id: receiverId,
message: text,
timestamp: Date.now(),
timestamp: Math.floor( Date.now() / 1000 ),
};
ui.renderMessage(message, state.getUserId());
@@ -137,18 +157,29 @@ async function loadUsers(): Promise<boolean> {
}
}
const onUserClick = async ( user: User ) => {
ui.setActiveUser( user.id );
ui.showView( "chat-view" );
async function loadConversation( userId: string ): Promise<void> {
try {
const conversation = await api.getConversation(
state.getToken(),
state.getUserId(),
user.id
userId
);
ui.renderConversation( conversation, state.getUserId() );
} catch (error) {
ui.showError( "Could not load conversation. Please try again." );
}
}
const onUserClick = async ( user: User ) => {
state.setSelectedReceiverId( user.id );
ui.setActiveUser( user.id );
ui.setChatHeader( user.name );
ui.showView( "chat-view" );
if ( pollingInterval !== null ) {
clearInterval( pollingInterval );
}
await loadConversation( user.id );
pollingInterval = window.setInterval( () => loadConversation( user.id ), 15000 );
};
+1 -1
View File
@@ -20,7 +20,7 @@ export interface Message {
sender_id: string;
receiver_id: string;
message: string;
timestamp: number;
timestamp: number | string;
}
export interface SendMessageResponse {