minor
This commit is contained in:
parent
e5243efef4
commit
3bd1a84350
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -1,15 +1,34 @@
|
|||
# Changelog
|
||||
|
||||
## Canary
|
||||
* High-quality portraits
|
||||
* Add the following anywhere in your character's profile to enable high-quality portrait:
|
||||
* `[url=https://some.domain.ext/path/to/image.png]Rising Portrait[/url]`
|
||||
* Replace `https://some.domain.ext/path/to/image.png` with the URL to your portrait.
|
||||
* The URL must point directly to an image resource, such as PNG, GIF, or JPG (think of it as `<img src="YOUR URL" />`).
|
||||
* Yes, animations are supported! (GIF, APNG, AVIF, WebP)
|
||||
* The image must be hosted on one of the following services:
|
||||
* `f-list.net` (profile images and inline images are supported)
|
||||
* [e621.net](https://e621.net)
|
||||
* [imgur.com](https://imgur.com)
|
||||
* [freeimage.host](https://freeimage.host)
|
||||
* [redgifs.com](https://redgifs.com)
|
||||
* High-quality portraits are only visible to other F-Chat Rising users; users on other clients will see your regular portrait.
|
||||
* If your image is not a square, [you're gonna have a bad time](https://www.youtube.com/watch?v=6Ls5j5iz2eA).
|
||||
* [YiffBot 4000](https://www.f-list.net/c/YiffBot%204000) integration
|
||||
* Fix "select/unselect all" behavior in Post Ads (credit: [@FatCatClient](https://github.com/FatCatClient))
|
||||
* Extended emoji support (credit: [@FatCatClient](https://github.com/FatCatClient))
|
||||
|
||||
## 1.25.1
|
||||
* Shift-clicking in eicon selector adds the icon without closing the selector
|
||||
* Minor updates to browser switching
|
||||
|
||||
## 1.25.0
|
||||
* Added option for switching browsers (Credit: [@greyhoof](https://github.com/greyhoof))
|
||||
* Added option for switching browsers (credit: [@greyhoof](https://github.com/greyhoof))
|
||||
* Fixed broken adblocker
|
||||
* Fixed incorrect BBCode rendering of `[collapse=[hr]test[hr]]` (Credit: [@Abeehiltz](https://github.com/Abeehiltz))
|
||||
* Fixed incorrect BBCode rendering of `[collapse=[hr]test[hr]]` (credit: [@Abeehiltz](https://github.com/Abeehiltz))
|
||||
* Fixed TikTok previews
|
||||
* Switched `node-sass` to `sass` for ARM64 compatibility (Credit: [@WhiteHusky](https://github.com/WhiteHusky))
|
||||
* Switched `node-sass` to `sass` for ARM64 compatibility (credit: [@WhiteHusky](https://github.com/WhiteHusky))
|
||||
|
||||
## 1.24.2
|
||||
* Hotfix to address connectivity issues
|
||||
|
|
|
@ -12,3 +12,8 @@ This project contains contributions from:
|
|||
* [Abeehiltz](https://github.com/Abeehiltz)
|
||||
* [greyhoof](https://github.com/greyhoof)
|
||||
* [F-List Team](https://github.com/f-list) (original F-Chat 3.0 client)
|
||||
|
||||
|
||||
## Acknowledgements
|
||||
Some emojis designed by [OpenMoji](https://openmoji.org/) – the open-source emoji and icon project. License: [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/#)
|
||||
|
||||
|
|
11
PRIVACY.md
11
PRIVACY.md
|
@ -26,6 +26,17 @@ When the 'Link Preview' feature is used, F-Chat Rising will connect to the URL b
|
|||
* Twitter previews are proxied through `api.fxtwitter.com`
|
||||
* YouTube previews are proxied through `yewtu.be`
|
||||
|
||||
## High-Quality Portraits
|
||||
When 'High-Quality Portraits' feature is used, F-Chat Rising may connect to the following additional domains:
|
||||
|
||||
* iili.io
|
||||
* e621.net
|
||||
* imgur.com
|
||||
* freeimage.host
|
||||
* redgifs.com
|
||||
|
||||
If you are concerned about your security or privacy, consider disabling the high quality portraits feature in F-Chat Rising settings.
|
||||
|
||||
## Locally Stored Data
|
||||
F-Chat Rising stores data on your computer. This data contains conversation logs, settings, cache, and other
|
||||
information such as custom dictionary words. By default, the data is stored in:
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
@click.middle.prevent.stop="toggleStickyness()"
|
||||
@click.right.passive="dismiss(true)"
|
||||
@click.left.passive="dismiss(true)"
|
||||
><img :src="`${Utils.staticDomain}images/avatar/${character.toLowerCase()}.png`" class="character-avatar icon" :title="character" :alt="character" v-once></a>
|
||||
><img :src="getAvatarUrl()" class="character-avatar icon" :title="character" :alt="character" v-once></a>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -16,6 +16,7 @@ import {Component, Hook, Prop} from '@f-list/vue-ts';
|
|||
import Vue from 'vue';
|
||||
import { EventBus } from '../chat/preview/event-bus';
|
||||
import * as Utils from '../site/utils';
|
||||
import { characterImage } from '../chat/common';
|
||||
|
||||
@Component
|
||||
export default class IconView extends Vue {
|
||||
|
@ -45,6 +46,10 @@ export default class IconView extends Vue {
|
|||
return `flist-character://${this.character}`;
|
||||
}
|
||||
|
||||
getAvatarUrl(): string {
|
||||
return characterImage(this.character);
|
||||
}
|
||||
|
||||
|
||||
dismiss(force: boolean = false): void {
|
||||
// if (!this.preview) {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div style="height:100%; display: flex; position: relative;" id="chatView" @click="userMenuHandle" @contextmenu="userMenuHandle" @touchstart.passive="userMenuHandle"
|
||||
@touchend="userMenuHandle">
|
||||
<sidebar id="sidebar" :label="l('chat.menu')" icon="fa-bars">
|
||||
<img :src="characterImage(ownCharacter.name)" v-if="showAvatars" style="float:left;margin-right:5px;margin-top:5px;width:70px"/>
|
||||
<img :src="characterImage(ownCharacter.name)" v-if="showAvatars" style="float:left;margin-right:5px;margin-top:5px;width:70px; height: 70px;"/>
|
||||
<a target="_blank" :href="ownCharacterLink" class="btn" style="display:block">{{ownCharacter.name}}</a>
|
||||
<a href="#" @click.prevent="logOut()" class="btn"><i class="fas fa-sign-out-alt"></i>{{l('chat.logout')}}</a><br/>
|
||||
<div>
|
||||
|
@ -543,6 +543,7 @@ import { Component, Hook, Watch } from '@f-list/vue-ts';
|
|||
}
|
||||
img {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
margin: -1px 5px -1px -1px;
|
||||
}
|
||||
&:first-child img {
|
||||
|
|
|
@ -95,7 +95,8 @@ export function getStatusClasses(
|
|||
smartFilterIcon = 'user-filter fas fa-filter';
|
||||
}
|
||||
|
||||
const gender = character.gender !== undefined ? character.gender.toLowerCase() : 'none';
|
||||
const baseGender = character.overrides.gender || character.gender;
|
||||
const gender = baseGender !== undefined ? baseGender.toLowerCase() : 'none';
|
||||
|
||||
const isBookmark = (showBookmark) && (core.connection.isOpen) && (core.state.settings.colorBookmarks) &&
|
||||
((character.isFriend) || (character.isBookmarked));
|
||||
|
@ -208,6 +209,11 @@ export default class UserView extends Vue {
|
|||
this.update();
|
||||
}
|
||||
|
||||
@Watch('character.overrides.avatarUrl')
|
||||
onAvatarUrlUpdate(): void {
|
||||
this.update();
|
||||
}
|
||||
|
||||
update(): void {
|
||||
// console.log('user.view.update', this.character.name);
|
||||
|
||||
|
@ -219,7 +225,7 @@ export default class UserView extends Vue {
|
|||
this.matchClass = res.matchClass;
|
||||
this.matchScore = res.matchScore;
|
||||
this.userClass = res.userClass;
|
||||
this.avatarUrl = characterImage(this.character.name);
|
||||
this.avatarUrl = this.character.overrides.avatarUrl || characterImage(this.character.name);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
import {isToday} from 'date-fns';
|
||||
import {Keys} from '../keys';
|
||||
import {Character, Conversation, Settings as ISettings} from './interfaces';
|
||||
import core from './core';
|
||||
|
||||
export function profileLink(this: any | never, character: string): string {
|
||||
return `https://www.f-list.net/c/${character}`;
|
||||
}
|
||||
|
||||
export function characterImage(this: any | never, character: string): string {
|
||||
const c = core.characters.get(character);
|
||||
|
||||
if (c.overrides.avatarUrl) {
|
||||
return c.overrides.avatarUrl;
|
||||
}
|
||||
|
||||
return `https://static.f-list.net/images/avatar/${character.toLowerCase()}.png`;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import { AdCenter } from './ads/ad-center';
|
|||
import { GeneralSettings } from '../electron/common';
|
||||
import { SiteSession } from '../site/site-session';
|
||||
import _ from 'lodash';
|
||||
import { initYiffbot4000Integration } from '../learn/yiffbot';
|
||||
|
||||
function createBBCodeParser(): BBCodeParser {
|
||||
const parser = new BBCodeParser();
|
||||
|
@ -115,6 +116,8 @@ export function init(
|
|||
if(data.settingsStore !== undefined) await data.settingsStore.set('hiddenUsers', newValue);
|
||||
});
|
||||
|
||||
initYiffbot4000Integration();
|
||||
|
||||
connection.onEvent('connecting', async() => {
|
||||
await data.reloadSettings();
|
||||
data.bbCodeParser = createBBCodeParser();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div class="character-preview">
|
||||
<div v-if="match && character" class="row">
|
||||
<div class="col-2">
|
||||
<img :src="avatarUrl(character.character.name)" class="character-avatar">
|
||||
<img :src="getAvatarUrl()" class="character-avatar">
|
||||
</div>
|
||||
|
||||
<div class="col-10">
|
||||
|
@ -140,7 +140,7 @@ export default class CharacterPreview extends Vue {
|
|||
subDomRole?: string;
|
||||
|
||||
formatTime = formatTime;
|
||||
readonly avatarUrl = Utils.avatarURL;
|
||||
// readonly avatarUrl = Utils.avatarURL;
|
||||
|
||||
TagId = TagId;
|
||||
Score = Score;
|
||||
|
@ -150,6 +150,13 @@ export default class CharacterPreview extends Vue {
|
|||
|
||||
conversation?: Conversation.Message[];
|
||||
|
||||
getAvatarUrl(): string {
|
||||
if (this.onlineCharacter && this.onlineCharacter.overrides.avatarUrl) {
|
||||
return this.onlineCharacter.overrides.avatarUrl;
|
||||
}
|
||||
|
||||
return Utils.avatarURL(this.characterName || this.character?.character.name || '');
|
||||
}
|
||||
|
||||
@Hook('mounted')
|
||||
mounted(): void {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<li v-for="(tab,index) in tabs" :key="'tab-' + index" class="nav-item" @click.middle="remove(tab)">
|
||||
<a href="#" @click.prevent="show(tab)" class="nav-link tab"
|
||||
:class="{active: tab === activeTab, hasNew: tab.hasNew && tab !== activeTab}">
|
||||
<img v-if="tab.user" :src="'https://static.f-list.net/images/avatar/' + tab.user.toLowerCase() + '.png'"/>
|
||||
<img v-if="tab.user || tab.avatarUrl" :src="getAvatarImage(tab)"/>
|
||||
<span class="d-sm-inline d-none">{{tab.user || l('window.newTab')}}</span>
|
||||
<a href="#" :aria-label="l('action.close')" style="margin-left:10px;padding:0;color:inherit;text-decoration:none"
|
||||
@click.stop="remove(tab)"><i class="fa fa-times"></i>
|
||||
|
@ -108,6 +108,7 @@
|
|||
view: Electron.BrowserView
|
||||
hasNew: boolean
|
||||
tray: Electron.Tray
|
||||
avatarUrl?: string;
|
||||
}
|
||||
|
||||
// console.log(require('./build/tray.png').default);
|
||||
|
@ -192,6 +193,16 @@
|
|||
menu.unshift({label: tab.user, enabled: false}, {type: 'separator'});
|
||||
tab.tray.setContextMenu(remote.Menu.buildFromTemplate(menu));
|
||||
});
|
||||
electron.ipcRenderer.on('update-avatar-url', (_e: Event, characterName: string, url: string) => {
|
||||
const tab = this.tabs.find((tab) => tab.user === characterName);
|
||||
|
||||
if (!tab) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vue.set(tab, 'avatarUrl', url);
|
||||
// tab.avatarUrl = url;
|
||||
});
|
||||
electron.ipcRenderer.on('disconnect', (_e: Event, id: number) => {
|
||||
const tab = this.tabMap[id];
|
||||
if(tab.hasNew) {
|
||||
|
@ -270,6 +281,14 @@
|
|||
log.debug('init.window.mounted');
|
||||
}
|
||||
|
||||
getAvatarImage(tab: Tab) {
|
||||
if (tab.avatarUrl) {
|
||||
return tab.avatarUrl;
|
||||
}
|
||||
|
||||
return 'https://static.f-list.net/images/avatar/' + (tab.user || '').toLowerCase() + '.png';
|
||||
}
|
||||
|
||||
destroyAllTabs(): void {
|
||||
browserWindow.setBrowserView(null!); //tslint:disable-line:no-null-keyword
|
||||
this.tabs.forEach(destroyTab);
|
||||
|
@ -481,6 +500,7 @@
|
|||
|
||||
img {
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
margin: -5px 3px -5px -5px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@ export function fixLogs(character: string): void {
|
|||
fs.readSync(fd, buffer, 0, 50100, pos);
|
||||
const deserialized = deserializeMessage(buffer, 0, (name) => ({
|
||||
gender: 'None', status: 'online', statusText: '', isFriend: false, isBookmarked: false, isChatOp: false,
|
||||
isIgnored: false, name
|
||||
isIgnored: false, name, overrides: {}
|
||||
}));
|
||||
const time = deserialized.message.time;
|
||||
const day = Math.floor(time.getTime() / dayMs - time.getTimezoneOffset() / 1440);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline'; img-src file: data: https://static.f-list.net http://static.f-list.net; connect-src *">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline'; img-src file: data: https://static.f-list.net http://static.f-list.net https://iili.io https://static1.e621.net https://i.imgur.com https://freeimage.host https://v3.redgifs.com; connect-src *">
|
||||
<title>F-Chat</title>
|
||||
<link href="fa.css" rel="stylesheet">
|
||||
</head>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline'; img-src https://static.f-list.net">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline'; img-src https://static.f-list.net https://iili.io https://static1.e621.net https://i.imgur.com https://freeimage.host https://v3.redgifs.com">
|
||||
<title>F-Chat</title>
|
||||
<link href="fa.css" rel="stylesheet">
|
||||
</head>
|
||||
|
|
|
@ -12,11 +12,18 @@ class Character implements Interfaces.Character {
|
|||
isBookmarked = false;
|
||||
isChatOp = false;
|
||||
isIgnored = false;
|
||||
overrides: CharacterOverrides = {};
|
||||
|
||||
constructor(public name: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export interface CharacterOverrides {
|
||||
avatarUrl?: string;
|
||||
gender?: Interfaces.Gender;
|
||||
status?: Interfaces.Status;
|
||||
}
|
||||
|
||||
class State implements Interfaces.State {
|
||||
characters: {[key: string]: Character | undefined} = {};
|
||||
|
||||
|
@ -56,6 +63,14 @@ class State implements Interfaces.State {
|
|||
character.statusText = decodeHTML(text);
|
||||
}
|
||||
|
||||
setOverride(name: string, type: 'avatarUrl', value: string | undefined): void;
|
||||
setOverride(name: string, type: 'gender', value: Interfaces.Gender | undefined): void;
|
||||
setOverride(name: string, type: 'status', value: Interfaces.Status | undefined): void;
|
||||
setOverride(name: string, type: keyof CharacterOverrides, value: any): void {
|
||||
const char = this.get(name);
|
||||
char.overrides[type] = value;
|
||||
}
|
||||
|
||||
async resolveOwnProfile(): Promise<void> {
|
||||
await methods.fieldsGet();
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Character as CharacterProfile } from '../site/character_page/interfaces';
|
||||
import { CharacterOverrides } from './characters';
|
||||
|
||||
//tslint:disable:no-shadowed-variable
|
||||
export namespace Connection {
|
||||
|
@ -170,7 +171,8 @@ export namespace Character {
|
|||
|
||||
readonly ownProfile: CharacterProfile;
|
||||
|
||||
get(name: string): Character
|
||||
get(name: string): Character;
|
||||
setOverride(name: string, type: keyof CharacterOverrides, value: any): void;
|
||||
}
|
||||
|
||||
export interface Character {
|
||||
|
@ -182,6 +184,7 @@ export namespace Character {
|
|||
readonly isBookmarked: boolean
|
||||
readonly isChatOp: boolean
|
||||
readonly isIgnored: boolean
|
||||
readonly overrides: CharacterOverrides
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import { PermanentIndexedStore } from './store/types';
|
|||
import { CharacterImage, SimpleCharacter } from '../interfaces';
|
||||
import { Scoring } from './matcher-types';
|
||||
import { matchesSmartFilters } from './filter/smart-filter';
|
||||
import * as remote from '@electron/remote';
|
||||
|
||||
|
||||
export interface MetaRecord {
|
||||
|
@ -148,6 +149,54 @@ export class ProfileCache extends AsyncCache<CharacterCacheRecord> {
|
|||
}
|
||||
}
|
||||
|
||||
isSafeImageURL(url: string): boolean {
|
||||
if (url.match(/^https?:\/\/static\.f-list\.net\//i)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (url.match(/^https?:\/\/([a-z0-9\-.]+\.)?imgur\.com\//i)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (url.match(/^https?:\/\/([a-z0-9\-.]+\.)?freeimage\.host\//i)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (url.match(/^https?:\/\/([a-z0-9\-.]+\.)?iili\.io\//i)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (url.match(/^https?:\/\/([a-z0-9\-.]+\.)?redgifs\.com\//i)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (url.match(/^https?:\/\/([a-z0-9\-.]+\.)?e621\.net\//i)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
updateOverrides(c: ComplexCharacter): void {
|
||||
const match = c.character.description.match(/\[url=(.*?)]\s*?Rising\s*?Portrait\s*?\[\/url]/i);
|
||||
|
||||
if (match && match[1]) {
|
||||
const avatarUrl = match[1].trim();
|
||||
|
||||
if (!this.isSafeImageURL(avatarUrl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (c.character.name === core.characters.ownCharacter.name) {
|
||||
const parent = remote.getCurrentWindow().webContents;
|
||||
|
||||
parent.send('update-avatar-url', c.character.name, avatarUrl);
|
||||
}
|
||||
|
||||
core.characters.setOverride(c.character.name, 'avatarUrl', avatarUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async register(c: ComplexCharacter, skipStore: boolean = false): Promise<CharacterCacheRecord> {
|
||||
const k = AsyncCache.nameKey(c.character.name);
|
||||
|
@ -158,6 +207,8 @@ export class ProfileCache extends AsyncCache<CharacterCacheRecord> {
|
|||
console.log(`Storing score 0 for character ${c.character.name}`);
|
||||
}
|
||||
|
||||
this.updateOverrides(c);
|
||||
|
||||
// const totalScoreDimensions = match ? Matcher.countScoresTotal(match) : 0;
|
||||
// const dimensionsAtScoreLevel = match ? (Matcher.countScoresAtLevel(match, score) || 0) : 0;
|
||||
// const dimensionsAboveScoreLevel = match ? (Matcher.countScoresAboveLevel(match, Math.max(score, Scoring.WEAK_MATCH))) : 0;
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import { EventBus } from '../chat/preview/event-bus';
|
||||
import { Message } from '../chat/common';
|
||||
import core from '../chat/core';
|
||||
|
||||
export function initYiffbot4000Integration() {
|
||||
EventBus.$on('private-message', ({ message }: { message: Message }) => {
|
||||
if (message.sender.name === 'YiffBot 4000') {
|
||||
const match = message.text.match(/\[spoiler](.*?FChatRisingBotManifest.*?)\[\/spoiler]/i);
|
||||
|
||||
if (match && match[1]) {
|
||||
try {
|
||||
const manifest = JSON.parse(match[1]);
|
||||
|
||||
if (manifest.type === 'FChatRisingBotManifest' && manifest.version >= 1) {
|
||||
const char = core.characters.get('YiffBot 4000');
|
||||
|
||||
char.overrides.avatarUrl = manifest.avatarUrl;
|
||||
char.overrides.gender = manifest.gender;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('FChatRisingBotManifest.error', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<div class="scores you">
|
||||
<h3>
|
||||
<img :src="avatarUrl(characterMatch.you.you.name)" class="thumbnail"/>
|
||||
<img :src="getAvatarUrl(characterMatch.you.you.name)" class="thumbnail"/>
|
||||
{{characterMatch.you.you.name}}
|
||||
<small v-if="characterMatch.youMultiSpecies" class="species">as {{getSpeciesStr(characterMatch.you)}}</small>
|
||||
</h3>
|
||||
|
@ -20,7 +20,7 @@
|
|||
|
||||
<div class="scores them">
|
||||
<h3>
|
||||
<img :src="avatarUrl(characterMatch.them.you.name)" class="thumbnail" />
|
||||
<img :src="getAvatarUrl(characterMatch.them.you.name)" class="thumbnail" />
|
||||
{{characterMatch.them.you.name}}
|
||||
<small v-if="characterMatch.themMultiSpecies" class="species">as {{getSpeciesStr(characterMatch.them)}}</small>
|
||||
</h3>
|
||||
|
@ -54,8 +54,6 @@
|
|||
// @Prop({required: true})
|
||||
// readonly minimized = false;
|
||||
|
||||
readonly avatarUrl = Utils.avatarURL;
|
||||
|
||||
isMinimized = false;
|
||||
|
||||
|
||||
|
@ -70,6 +68,16 @@
|
|||
// this.isMinimized = this.minimized;
|
||||
// }
|
||||
|
||||
getAvatarUrl(name: string) {
|
||||
const c = core.characters.get(name);
|
||||
|
||||
if (c.overrides.avatarUrl) {
|
||||
return c.overrides.avatarUrl;
|
||||
}
|
||||
|
||||
return Utils.avatarURL(name);
|
||||
}
|
||||
|
||||
getScoreClass(score: Score): CssClassMap {
|
||||
const classes: CssClassMap = {};
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div id="character-page-sidebar" class="card bg-light">
|
||||
<div class="card-body">
|
||||
<img :src="avatarUrl(character.character.name)" class="character-avatar" style="width: 100%; height: auto;">
|
||||
<img :src="getAvatarUrl()" class="character-avatar" style="width: 100%; height: auto;">
|
||||
|
||||
<div v-if="character.character.title" class="character-title">{{ character.character.title }}</div>
|
||||
<character-action-menu :character="character" @rename="showRename()" @delete="showDelete()"
|
||||
|
@ -106,6 +106,7 @@
|
|||
import { MatchReport } from '../../learn/matcher';
|
||||
import MemoDialog from './memo_dialog.vue';
|
||||
import ReportDialog from './report_dialog.vue';
|
||||
import core from '../../chat/core';
|
||||
|
||||
interface ShowableVueDialog extends Vue {
|
||||
show(): void
|
||||
|
@ -152,6 +153,16 @@
|
|||
readonly quickInfoIds: ReadonlyArray<number> = [1, 3, 2, 49, 9, 29, 15, 41, 25]; // Do not sort these.
|
||||
readonly avatarUrl = Utils.avatarURL;
|
||||
|
||||
getAvatarUrl(): string {
|
||||
const onlineCharacter = core.characters.get(this.character.character.name);
|
||||
|
||||
if (onlineCharacter && onlineCharacter.overrides.avatarUrl) {
|
||||
return onlineCharacter.overrides.avatarUrl;
|
||||
}
|
||||
|
||||
return Utils.avatarURL(this.character.character.name);
|
||||
}
|
||||
|
||||
badgeClass(badgeName: string): string {
|
||||
return `character-badge-${badgeName.replace('.', '-')}`;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue