Charater rating badge on private chats
This commit is contained in:
parent
dc87871ad0
commit
6183acc30a
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<modal :buttons="false" ref="dialog" @open="onOpen" @close="onClose" style="width:98%" dialogClass="ads-dialog">
|
||||
<template slot="title">
|
||||
Channel Ads for {{character.name}}
|
||||
Channel Ads for <user :character="character">{{character.name}}</user>
|
||||
</template>
|
||||
|
||||
<div class="row ad-viewer" ref="pageBody">
|
||||
|
@ -25,9 +25,10 @@ import { Character } from '../fchat/interfaces';
|
|||
import { AdCachedPosting } from '../learn/ad-cache';
|
||||
import core from './core';
|
||||
import {formatTime} from './common';
|
||||
import UserView from './UserView.vue';
|
||||
|
||||
@Component({
|
||||
components: {modal: Modal}
|
||||
components: {modal: Modal, user: UserView}
|
||||
})
|
||||
export default class AdView extends CustomDialog {
|
||||
@Prop({required: true})
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
import core from './core';
|
||||
import {Character, Connection} from './interfaces';
|
||||
import l from './localize';
|
||||
import UserView from './user_view';
|
||||
import UserView from './UserView.vue';
|
||||
|
||||
type Options = {
|
||||
kinks: Kink[],
|
||||
|
|
|
@ -25,7 +25,11 @@
|
|||
{{conversations.consoleTab.name}}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
{{l('chat.pms')}}
|
||||
<div @click.prevent="showAddPmPartner()" class="pm-add"><a href="#"><span class="fas fa-plus"></span></a></div>
|
||||
|
||||
<div class="list-group conversation-nav" ref="privateConversations">
|
||||
<a v-for="conversation in conversations.privateConversations" href="#" @click.prevent="conversation.show()"
|
||||
:class="getClasses(conversation)" :data-character="conversation.character.name" data-touch="false"
|
||||
|
@ -91,6 +95,7 @@
|
|||
<user-menu ref="userMenu" :reportDialog="$refs['reportDialog']"></user-menu>
|
||||
<recent-conversations ref="recentDialog"></recent-conversations>
|
||||
<image-preview ref="imagePreview"></image-preview>
|
||||
<add-pm-partner ref="addPmPartnerDialog"></add-pm-partner>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -107,12 +112,13 @@
|
|||
import core from './core';
|
||||
import {Character, Connection, Conversation} from './interfaces';
|
||||
import l from './localize';
|
||||
import PmPartnerAdder from './PmPartnerAdder.vue';
|
||||
import RecentConversations from './RecentConversations.vue';
|
||||
import ReportDialog from './ReportDialog.vue';
|
||||
import SettingsView from './SettingsView.vue';
|
||||
import Sidebar from './Sidebar.vue';
|
||||
import StatusSwitcher from './StatusSwitcher.vue';
|
||||
import {getStatusIcon} from './user_view';
|
||||
import {getStatusIcon} from './UserView.vue';
|
||||
import UserList from './UserList.vue';
|
||||
import UserMenu from './UserMenu.vue';
|
||||
import ImagePreview from './ImagePreview.vue';
|
||||
|
@ -128,7 +134,8 @@
|
|||
'user-list': UserList, channels: ChannelList, 'status-switcher': StatusSwitcher, 'character-search': CharacterSearch,
|
||||
settings: SettingsView, conversation: ConversationView, 'report-dialog': ReportDialog, sidebar: Sidebar,
|
||||
'user-menu': UserMenu, 'recent-conversations': RecentConversations,
|
||||
'image-preview': ImagePreview
|
||||
'image-preview': ImagePreview,
|
||||
'add-pm-partner': PmPartnerAdder
|
||||
}
|
||||
})
|
||||
export default class ChatView extends Vue {
|
||||
|
@ -294,6 +301,10 @@
|
|||
(<StatusSwitcher>this.$refs['statusDialog']).show();
|
||||
}
|
||||
|
||||
showAddPmPartner(): void {
|
||||
(<PmPartnerAdder>this.$refs['addPmPartnerDialog']).show();
|
||||
}
|
||||
|
||||
userMenuHandle(e: MouseEvent | TouchEvent): void {
|
||||
(<UserMenu>this.$refs['userMenu']).handleEvent(e);
|
||||
}
|
||||
|
@ -329,6 +340,12 @@
|
|||
user-select: text;
|
||||
}
|
||||
|
||||
.pm-add {
|
||||
font-size: 90%;
|
||||
float: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.list-group.conversation-nav {
|
||||
margin-bottom: 10px;
|
||||
.list-group-item {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<img :src="characterImage" style="height:60px;width:60px;margin-right:10px" v-if="settings.showAvatars"/>
|
||||
<div style="flex:1;position:relative;display:flex;flex-direction:column">
|
||||
<div>
|
||||
<user :character="conversation.character"></user>
|
||||
<user :character="conversation.character" :match="true"></user>
|
||||
<a href="#" @click.prevent="showLogs()" class="btn">
|
||||
<span class="fa fa-file-alt"></span> <span class="btn-text">{{l('logs.title')}}</span>
|
||||
</a>
|
||||
|
@ -17,6 +17,10 @@
|
|||
<a href="#" @click.prevent="showAds()" class="btn">
|
||||
<span class="fa fa-ad"></span><span class="btn-text">Ads</span>
|
||||
</a>
|
||||
|
||||
<a href="#" @click.prevent="showChannels()" class="btn">
|
||||
<span class="fa fa-tv"></span><span class="btn-text">Channels</span>
|
||||
</a>
|
||||
</div>
|
||||
<div style="overflow:auto;max-height:50px">
|
||||
{{l('status.' + conversation.character.status)}}
|
||||
|
@ -140,7 +144,8 @@
|
|||
<settings ref="settingsDialog" :conversation="conversation"></settings>
|
||||
<logs ref="logsDialog" :conversation="conversation"></logs>
|
||||
<manage-channel ref="manageDialog" v-if="isChannel(conversation)" :channel="conversation.channel"></manage-channel>
|
||||
<ad-view ref="adViewer" v-if="isPrivate(conversation)" :character="conversation.character"></ad-view>
|
||||
<ad-view ref="adViewer" v-if="isPrivate(conversation) && conversation.character" :character="conversation.character"></ad-view>
|
||||
<channel-list ref="channelList" v-if="isPrivate(conversation)" :character="conversation.character"></channel-list>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -163,13 +168,14 @@
|
|||
import MessageView from './message_view';
|
||||
import ReportDialog from './ReportDialog.vue';
|
||||
import {isCommand} from './slash_commands';
|
||||
import UserView from './user_view';
|
||||
import UserView from './UserView.vue';
|
||||
import UserChannelList from './UserChannelList.vue';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
user: UserView, 'bbcode-editor': Editor, 'manage-channel': ManageChannel, settings: ConversationSettings,
|
||||
logs: Logs, 'message-view': MessageView, bbcode: BBCodeView, 'command-help': CommandHelp,
|
||||
'ad-view': AdView
|
||||
'ad-view': AdView, 'channel-list': UserChannelList
|
||||
}
|
||||
})
|
||||
export default class ConversationView extends Vue {
|
||||
|
@ -411,6 +417,10 @@
|
|||
(<AdView>this.$refs['adViewer']).show();
|
||||
}
|
||||
|
||||
showChannels(): void {
|
||||
(<UserChannelList>this.$refs['channelList']).show();
|
||||
}
|
||||
|
||||
|
||||
isAutopostingAds(): boolean {
|
||||
return this.conversation.adManager.isActive();
|
||||
|
@ -635,6 +645,43 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.user-view {
|
||||
.match-found {
|
||||
margin-left: 3px;
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
border-radius: 3px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
font-size: 75%;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
text-transform: uppercase;
|
||||
|
||||
&.match {
|
||||
background-color: rgb(0, 142, 0);
|
||||
border: solid 1px rgb(0, 113, 0);
|
||||
}
|
||||
|
||||
&.weak-match {
|
||||
background-color: rgb(0, 80, 0);
|
||||
border: 1px solid rgb(0, 64, 0);
|
||||
}
|
||||
|
||||
&.weak-mismatch {
|
||||
background-color: rgb(152, 134, 0);
|
||||
border: 1px solid rgb(142, 126, 0);
|
||||
}
|
||||
|
||||
&.mismatch {
|
||||
background-color: rgb(171, 0, 0);
|
||||
border: 1px solid rgb(128, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.message {
|
||||
&.message-event {
|
||||
font-size: 85%;
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<template>
|
||||
<modal action="Open Conversation" ref="dialog" @submit="submit" style="width:98%" dialogClass="ads-dialog" buttonText="Open">
|
||||
<div>
|
||||
<input type="text" id="name" v-model="name" placeholder="Name" />
|
||||
<div class="error" v-if="error">{{error}}</div>
|
||||
</div>
|
||||
|
||||
</modal>
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="ts">
|
||||
import { Component } from '@f-list/vue-ts';
|
||||
import CustomDialog from '../components/custom_dialog';
|
||||
import Modal from '../components/Modal.vue';
|
||||
import core from './core';
|
||||
|
||||
@Component({
|
||||
components: {modal: Modal}
|
||||
})
|
||||
export default class PmPartnerAdder extends CustomDialog {
|
||||
name = '';
|
||||
error: string | null = null;
|
||||
|
||||
submit(): void {
|
||||
const c = core.characters.get(this.name);
|
||||
|
||||
if (c) {
|
||||
const conversation = core.conversations.getPrivate(c);
|
||||
|
||||
conversation.show();
|
||||
|
||||
this.name = '';
|
||||
this.error = '';
|
||||
} else {
|
||||
this.error = `Unknown character '${this.name}'`;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -24,7 +24,7 @@
|
|||
import core from './core';
|
||||
import {Character, Conversation} from './interfaces';
|
||||
import l from './localize';
|
||||
import UserView from './user_view';
|
||||
import UserView from './UserView.vue';
|
||||
|
||||
@Component({
|
||||
components: {'user-view': UserView, 'channel-view': ChannelView, modal: Modal, tabs: Tabs}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
import core from './core';
|
||||
import {Character, userStatuses} from './interfaces';
|
||||
import l from './localize';
|
||||
import {getStatusIcon} from './user_view';
|
||||
import {getStatusIcon} from './UserView.vue';
|
||||
|
||||
@Component({
|
||||
components: {modal: Modal, editor: Editor, dropdown: Dropdown}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
<template>
|
||||
<modal :buttons="false" ref="dialog" style="width:98%" dialogClass="">
|
||||
<template slot="title">
|
||||
Channels for <user :character="character">{{character.name}}</user>
|
||||
</template>
|
||||
|
||||
<div class="user-channel-list" ref="pageBody">
|
||||
<template v-for="channel in channels">
|
||||
<h3><a href="#" @click.prevent="jumpToChannel(channel)">#{{channel.name}}</a></h3>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
</modal>
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import * as _ from 'lodash';
|
||||
import { Component, Hook, Prop, Watch } from '@f-list/vue-ts';
|
||||
import CustomDialog from '../components/custom_dialog';
|
||||
import Modal from '../components/Modal.vue';
|
||||
import { Character } from '../fchat/interfaces';
|
||||
import core from './core';
|
||||
import { Conversation } from './interfaces';
|
||||
import UserView from './UserView.vue';
|
||||
import ChannelConversation = Conversation.ChannelConversation;
|
||||
|
||||
@Component({
|
||||
components: {modal: Modal, user: UserView}
|
||||
})
|
||||
export default class UserChannelList extends CustomDialog {
|
||||
@Prop({required: true})
|
||||
readonly character!: Character;
|
||||
|
||||
channels: ChannelConversation[] = [];
|
||||
|
||||
@Watch('character')
|
||||
onNameUpdate(): void {
|
||||
this.update();
|
||||
}
|
||||
|
||||
|
||||
@Hook('mounted')
|
||||
onMounted(): void {
|
||||
this.update();
|
||||
}
|
||||
|
||||
update(): void {
|
||||
if (!this.character) {
|
||||
this.channels = [];
|
||||
return;
|
||||
}
|
||||
|
||||
this.channels = _.sortBy(
|
||||
_.filter(
|
||||
core.conversations.channelConversations,
|
||||
(cc: ChannelConversation) => !!cc.channel.members[this.character.name]
|
||||
),
|
||||
'name'
|
||||
);
|
||||
}
|
||||
|
||||
jumpToChannel(channel: ChannelConversation): void {
|
||||
channel.show();
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
.user-channel-list h3 {
|
||||
font-size: 120%;
|
||||
}
|
||||
</style>
|
|
@ -36,7 +36,7 @@
|
|||
import {Channel, Character, Conversation} from './interfaces';
|
||||
import l from './localize';
|
||||
import Sidebar from './Sidebar.vue';
|
||||
import UserView from './user_view';
|
||||
import UserView from './UserView.vue';
|
||||
|
||||
@Component({
|
||||
components: {user: UserView, sidebar: Sidebar, tabs: Tabs}
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
<span class="far fa-fw fa-sticky-note"></span>{{l('user.memo')}}</a>
|
||||
<a tabindex="-1" href="#" @click.prevent="setBookmarked()" class="list-group-item list-group-item-action">
|
||||
<span class="far fa-fw fa-bookmark"></span>{{l('user.' + (character.isBookmarked ? 'unbookmark' : 'bookmark'))}}</a>
|
||||
<a tabindex="-1" href="#" @click.prevent="showAdLogs()" class="list-group-item list-group-item-action" :class="{ disabled: !hasAdLogs()}">
|
||||
<span class="far fa-fw fa-ad"></span>Show ad log
|
||||
</a>
|
||||
<a tabindex="-1" href="#" @click.prevent="setHidden()" class="list-group-item list-group-item-action" v-show="!isChatOp">
|
||||
<span class="fa fa-fw fa-eye-slash"></span>{{l('user.' + (isHidden ? 'unhide' : 'hide'))}}</a>
|
||||
<a tabindex="-1" href="#" @click.prevent="report()" class="list-group-item list-group-item-action" style="border-top-width:1px">
|
||||
|
@ -36,6 +39,7 @@
|
|||
<div style="float:right;text-align:right;">{{getByteLength(memo)}} / 1000</div>
|
||||
<textarea class="form-control" v-model="memo" :disabled="memoLoading" maxlength="1000"></textarea>
|
||||
</modal>
|
||||
<ad-view ref="adViewDialog" :character="character" v-if="character"></ad-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -43,6 +47,7 @@
|
|||
import {Component, Prop} from '@f-list/vue-ts';
|
||||
import Vue from 'vue';
|
||||
import Modal from '../components/Modal.vue';
|
||||
import AdView from './AdView.vue';
|
||||
import {BBCodeView} from './bbcode';
|
||||
import {characterImage, errorToString, getByteLength, profileLink} from './common';
|
||||
import core from './core';
|
||||
|
@ -51,7 +56,7 @@
|
|||
import ReportDialog from './ReportDialog.vue';
|
||||
|
||||
@Component({
|
||||
components: {bbcode: BBCodeView, modal: Modal}
|
||||
components: {bbcode: BBCodeView, modal: Modal, 'ad-view': AdView}
|
||||
})
|
||||
export default class UserMenu extends Vue {
|
||||
@Prop({required: true})
|
||||
|
@ -120,6 +125,30 @@
|
|||
.catch((e: object) => alert(errorToString(e)));
|
||||
}
|
||||
|
||||
|
||||
showAdLogs(): void {
|
||||
if (!this.hasAdLogs()) {
|
||||
return;
|
||||
}
|
||||
|
||||
(<AdView>this.$refs['adViewDialog']).show();
|
||||
}
|
||||
|
||||
|
||||
hasAdLogs(): boolean {
|
||||
if (!this.character) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const cache = core.cache.adCache.get(this.character.name);
|
||||
|
||||
if (!cache) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (cache.count() > 0);
|
||||
}
|
||||
|
||||
get isChannelMod(): boolean {
|
||||
if(this.channel === undefined) return false;
|
||||
if(core.characters.ownCharacter.isChatOp) return true;
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
<!-- Linebreaks inside this template will break BBCode views -->
|
||||
<template><span :class="userClass" v-bind:bbcodeTag.prop="'user'" v-bind:character.prop="character" v-bind:channel.prop="channel"><span v-if="!!statusClass" :class="statusClass"></span><span v-if="!!rankIcon" :class="rankIcon"></span>{{character.name}}<span v-if="!!matchClass" :class="matchClass">{{getMatchScoreTitle(matchScore)}}</span></span></template>
|
||||
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Hook, Prop } from '@f-list/vue-ts';
|
||||
import Vue from 'vue';
|
||||
import {Channel, Character} from '../fchat';
|
||||
import { Score, Scoring } from '../learn/matcher';
|
||||
import core from './core';
|
||||
import { EventBus } from './event-bus';
|
||||
|
||||
|
||||
export function getStatusIcon(status: Character.Status): string {
|
||||
switch(status) {
|
||||
case 'online':
|
||||
return 'far fa-user';
|
||||
case 'looking':
|
||||
return 'fa fa-eye';
|
||||
case 'dnd':
|
||||
return 'fa fa-minus-circle';
|
||||
case 'offline':
|
||||
return 'fa fa-ban';
|
||||
case 'away':
|
||||
return 'far fa-circle';
|
||||
case 'busy':
|
||||
return 'fa fa-cog';
|
||||
case 'idle':
|
||||
return 'far fa-clock';
|
||||
case 'crown':
|
||||
return 'fa fa-birthday-cake';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
|
||||
}
|
||||
})
|
||||
export default class UserView extends Vue {
|
||||
@Prop({required: true})
|
||||
readonly character!: Character;
|
||||
|
||||
@Prop()
|
||||
readonly channel?: Channel;
|
||||
|
||||
@Prop()
|
||||
readonly showStatus?: boolean = true;
|
||||
|
||||
@Prop()
|
||||
readonly bookmark?: boolean = false;
|
||||
|
||||
@Prop()
|
||||
readonly match?: boolean = false;
|
||||
|
||||
userClass = '';
|
||||
|
||||
rankIcon: string | null = null;
|
||||
statusClass: string | null = null;
|
||||
matchClass: string | null = null;
|
||||
matchScore: number | null = null;
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
scoreWatcher: ((event: any) => void) | null = null;
|
||||
|
||||
@Hook('mounted')
|
||||
onMounted(): void {
|
||||
this.update();
|
||||
|
||||
if ((this.match) && (!this.matchClass)) {
|
||||
if (this.scoreWatcher) {
|
||||
EventBus.$off('character-score', this.scoreWatcher);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-unsafe-any no-any
|
||||
this.scoreWatcher = (event: any): void => {
|
||||
// tslint:disable-next-line no-unsafe-any no-any
|
||||
if ((event.character) && (event.character.name === this.character.name)) {
|
||||
this.update();
|
||||
|
||||
if (this.scoreWatcher) {
|
||||
EventBus.$off('character-score', this.scoreWatcher);
|
||||
|
||||
delete this.scoreWatcher;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EventBus.$on(
|
||||
'character-score',
|
||||
this.scoreWatcher
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Hook('beforeDestroy')
|
||||
onBeforeDestroy(): void {
|
||||
if (this.scoreWatcher)
|
||||
EventBus.$off('character-score', this.scoreWatcher);
|
||||
}
|
||||
|
||||
|
||||
@Hook('beforeUpdate')
|
||||
onBeforeUpdate(): void {
|
||||
this.update();
|
||||
}
|
||||
|
||||
|
||||
update(): void {
|
||||
this.rankIcon = null;
|
||||
this.statusClass = null;
|
||||
this.matchClass = null;
|
||||
|
||||
if (this.match) console.log('Update');
|
||||
|
||||
if(this.character.isChatOp) {
|
||||
this.rankIcon = 'far fa-gem';
|
||||
} else if(this.channel !== undefined) {
|
||||
this.rankIcon = (this.channel.owner === this.character.name)
|
||||
? 'fa fa-key'
|
||||
: this.channel.opList.indexOf(this.character.name) !== -1
|
||||
? (this.channel.id.substr(0, 4) === 'adh-' ? 'fa fa-shield-alt' : 'fa fa-star')
|
||||
: null;
|
||||
}
|
||||
|
||||
if ((this.showStatus) || (this.character.status === 'crown'))
|
||||
this.statusClass = `fa-fw ${getStatusIcon(this.character.status)}`;
|
||||
|
||||
if (this.match) console.log('Update prematch');
|
||||
|
||||
if (this.match) {
|
||||
const cache = core.cache.profileCache.getSync(this.character.name);
|
||||
|
||||
if (cache) {
|
||||
this.matchClass = `match-found ${Score.getClasses(cache.matchScore)}`;
|
||||
this.matchScore = cache.matchScore;
|
||||
} else {
|
||||
core.cache.addProfile(this.character.name);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.match) console.log('Update post match');
|
||||
|
||||
const gender = this.character.gender !== undefined ? this.character.gender.toLowerCase() : 'none';
|
||||
|
||||
const isBookmark = (this.bookmark) && (core.connection.isOpen) && (core.state.settings.colorBookmarks) &&
|
||||
((this.character.isFriend) || (this.character.isBookmarked));
|
||||
|
||||
|
||||
this.userClass = `user-view gender-${gender}${isBookmark ? ' user-bookmark' : ''}`;
|
||||
|
||||
if (this.match) console.log('Update done');
|
||||
}
|
||||
|
||||
|
||||
getMatchScoreTitle(score: number | null): string {
|
||||
switch (score) {
|
||||
case Scoring.MATCH:
|
||||
return 'Great';
|
||||
|
||||
case Scoring.WEAK_MATCH:
|
||||
return 'Good';
|
||||
|
||||
case Scoring.WEAK_MISMATCH:
|
||||
return 'Maybe';
|
||||
|
||||
case Scoring.MISMATCH:
|
||||
return 'No';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
//tslint:disable-next-line:variable-name
|
||||
/* const UserView = Vue.extend({
|
||||
functional: true,
|
||||
render(this: void | Vue, createElement: CreateElement, context?: RenderContext): VNode {
|
||||
const props = <{character: Character, channel?: Channel, showStatus?: true, bookmark?: false, match?: false}>(
|
||||
context !== undefined ? context.props : (<Vue>this).$options.propsData);
|
||||
|
||||
const character = props.character;
|
||||
|
||||
let matchClasses: string | undefined;
|
||||
|
||||
if (props.match) {
|
||||
const cache = core.cache.profileCache.getSync(character.name);
|
||||
|
||||
if (cache) {
|
||||
matchClasses = Score.getClasses(cache.matchScore);
|
||||
}
|
||||
}
|
||||
|
||||
let rankIcon;
|
||||
if(character.isChatOp) rankIcon = 'far fa-gem';
|
||||
else if(props.channel !== undefined)
|
||||
rankIcon = props.channel.owner === character.name ? 'fa fa-key' : props.channel.opList.indexOf(character.name) !== -1 ?
|
||||
(props.channel.id.substr(0, 4) === 'adh-' ? 'fa fa-shield-alt' : 'fa fa-star') : '';
|
||||
else rankIcon = '';
|
||||
const children: (VNode | string)[] = [character.name];
|
||||
if(rankIcon !== '') children.unshift(createElement('span', {staticClass: rankIcon}));
|
||||
if(props.showStatus !== undefined || character.status === 'crown')
|
||||
children.unshift(createElement('span', {staticClass: `fa-fw ${getStatusIcon(character.status)}`}));
|
||||
const gender = character.gender !== undefined ? character.gender.toLowerCase() : 'none';
|
||||
const isBookmark = props.bookmark !== false && core.connection.isOpen && core.state.settings.colorBookmarks &&
|
||||
(character.isFriend || character.isBookmarked);
|
||||
return createElement('span', {
|
||||
attrs: {class: `user-view gender-${gender}${isBookmark ? ' user-bookmark' : ''} ${matchClasses}`},
|
||||
domProps: {character, channel: props.channel, bbcodeTag: 'user'}
|
||||
}, children);
|
||||
}
|
||||
});
|
||||
|
||||
export default UserView;
|
||||
*/
|
||||
|
||||
</script>
|
||||
|
|
@ -8,7 +8,7 @@ import {characterImage} from './common';
|
|||
import core from './core';
|
||||
import {Character} from './interfaces';
|
||||
import {default as UrlView} from '../bbcode/UrlTagView.vue';
|
||||
import UserView from './user_view';
|
||||
import UserView from './UserView.vue';
|
||||
|
||||
export const BBCodeView: Component = {
|
||||
functional: true,
|
||||
|
|
|
@ -9,6 +9,7 @@ import ChannelConversation = Conversation.ChannelConversation;
|
|||
* 'imagepreview-show': {url: string}
|
||||
* 'imagepreview-toggle-stickyness': {url: string}
|
||||
* 'character-data': {character: Character}
|
||||
* 'character-score': {character: Character, score: number}
|
||||
* 'private-message': {message: Message}
|
||||
* 'channel-ad': {message: Message, channel: Conversation, profile: ComplexCharacter | undefined}
|
||||
* 'channel-message': {message: Message, channel: Conversation}
|
||||
|
|
|
@ -6,7 +6,7 @@ import {BBCodeView} from './bbcode';
|
|||
import {formatTime} from './common';
|
||||
import core from './core';
|
||||
import {Conversation} from './interfaces';
|
||||
import UserView from './user_view';
|
||||
import UserView from './UserView.vue';
|
||||
|
||||
const userPostfix: {[key: number]: string | undefined} = {
|
||||
[Conversation.Message.Type.Message]: ': ',
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
// TODO convert this to single-file once Vue supports it for functional components.
|
||||
//template:
|
||||
//<span class="gender" :class="genderClass" @click="click" @contextmenu.prevent="showMenu" style="cursor:pointer;" ref="main"><span
|
||||
//class="fa" :class="statusIcon"></span> <span class="fa" :class="rankIcon"></span>{{character.name}}</span>
|
||||
|
||||
import Vue, {CreateElement, RenderContext, VNode} from 'vue';
|
||||
import {Channel, Character} from '../fchat';
|
||||
import core from './core';
|
||||
|
||||
export function getStatusIcon(status: Character.Status): string {
|
||||
switch(status) {
|
||||
case 'online':
|
||||
return 'far fa-user';
|
||||
case 'looking':
|
||||
return 'fa fa-eye';
|
||||
case 'dnd':
|
||||
return 'fa fa-minus-circle';
|
||||
case 'offline':
|
||||
return 'fa fa-ban';
|
||||
case 'away':
|
||||
return 'far fa-circle';
|
||||
case 'busy':
|
||||
return 'fa fa-cog';
|
||||
case 'idle':
|
||||
return 'far fa-clock';
|
||||
case 'crown':
|
||||
return 'fa fa-birthday-cake';
|
||||
}
|
||||
}
|
||||
|
||||
//tslint:disable-next-line:variable-name
|
||||
const UserView = Vue.extend({
|
||||
functional: true,
|
||||
render(this: void | Vue, createElement: CreateElement, context?: RenderContext): VNode {
|
||||
const props = <{character: Character, channel?: Channel, showStatus?: true, bookmark?: false}>(
|
||||
context !== undefined ? context.props : (<Vue>this).$options.propsData);
|
||||
const character = props.character;
|
||||
let rankIcon;
|
||||
if(character.isChatOp) rankIcon = 'far fa-gem';
|
||||
else if(props.channel !== undefined)
|
||||
rankIcon = props.channel.owner === character.name ? 'fa fa-key' : props.channel.opList.indexOf(character.name) !== -1 ?
|
||||
(props.channel.id.substr(0, 4) === 'adh-' ? 'fa fa-shield-alt' : 'fa fa-star') : '';
|
||||
else rankIcon = '';
|
||||
const children: (VNode | string)[] = [character.name];
|
||||
if(rankIcon !== '') children.unshift(createElement('span', {staticClass: rankIcon}));
|
||||
if(props.showStatus !== undefined || character.status === 'crown')
|
||||
children.unshift(createElement('span', {staticClass: `fa-fw ${getStatusIcon(character.status)}`}));
|
||||
const gender = character.gender !== undefined ? character.gender.toLowerCase() : 'none';
|
||||
const isBookmark = props.bookmark !== false && core.connection.isOpen && core.state.settings.colorBookmarks &&
|
||||
(character.isFriend || character.isBookmarked);
|
||||
return createElement('span', {
|
||||
attrs: {class: `user-view gender-${gender}${isBookmark ? ' user-bookmark' : ''}`},
|
||||
domProps: {character, channel: props.channel, bbcodeTag: 'user'}
|
||||
}, children);
|
||||
}
|
||||
});
|
||||
|
||||
export default UserView;
|
|
@ -3,7 +3,7 @@ import core from '../chat/core';
|
|||
import { ChannelAdEvent, ChannelMessageEvent, CharacterDataEvent, EventBus } from '../chat/event-bus';
|
||||
import { Conversation } from '../chat/interfaces';
|
||||
import { methods } from '../site/character_page/data_store';
|
||||
import { Character } from '../site/character_page/interfaces';
|
||||
import { Character as ComplexCharacter } from '../site/character_page/interfaces';
|
||||
import { Gender } from './matcher';
|
||||
import { AdCache } from './ad-cache';
|
||||
import { ChannelConversationCache } from './channel-conversation-cache';
|
||||
|
@ -74,7 +74,15 @@ export class CacheManager {
|
|||
}
|
||||
|
||||
|
||||
updateAdScoringForProfile(c: Character, score: number): void {
|
||||
updateAdScoringForProfile(c: ComplexCharacter, score: number): void {
|
||||
EventBus.$emit(
|
||||
'character-score',
|
||||
{
|
||||
character: c,
|
||||
score
|
||||
}
|
||||
);
|
||||
|
||||
_.each(
|
||||
core.conversations.channelConversations,
|
||||
(ch: ChannelConversation) => {
|
||||
|
@ -92,7 +100,7 @@ export class CacheManager {
|
|||
}
|
||||
|
||||
|
||||
async addProfile(character: string | Character): Promise<void> {
|
||||
async addProfile(character: string | ComplexCharacter): Promise<void> {
|
||||
if (typeof character === 'string') {
|
||||
// console.log('Learn discover', character);
|
||||
|
||||
|
@ -237,7 +245,7 @@ export class CacheManager {
|
|||
}
|
||||
|
||||
|
||||
setProfile(c: Character): void {
|
||||
setProfile(c: ComplexCharacter): void {
|
||||
this.characterProfiler = new CharacterProfiler(c, this.adCache);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,17 @@ export class ProfileCache extends AsyncCache<CharacterCacheRecord> {
|
|||
}
|
||||
|
||||
|
||||
getSync(name: string): CharacterCacheRecord | null {
|
||||
const key = AsyncCache.nameKey(name);
|
||||
|
||||
if (key in this.cache) {
|
||||
return this.cache[key];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
async get(name: string, skipStore: boolean = false): Promise<CharacterCacheRecord | null> {
|
||||
const key = AsyncCache.nameKey(name);
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ This repository contains a modified version of the mainline F-Chat 3.0 client.
|
|||
## Key Differences
|
||||
|
||||
* Ads view
|
||||
* Highlight ads from characters most interesting to you / hide ads from characters clearly incompatible
|
||||
* View recent ads from a character on any channel to which you subscribe
|
||||
* Highlight ads from characters most interesting to you
|
||||
* View a character's recent ads
|
||||
* Ad auto-posting
|
||||
* Manage channel's ad settings via "Tab Settings"
|
||||
* Automatically re-post ads every 11-18 minutes (randomized) for up to 180 minutes
|
||||
|
@ -35,6 +35,11 @@ This repository contains a modified version of the mainline F-Chat 3.0 client.
|
|||
* Improvements to log browsing
|
||||
* Fix broken BBCode, such as `[big]` in character profiles
|
||||
* Which channels my chart partner is on?
|
||||
* Reposition ad settings and toggle
|
||||
* Cache image list, guestbook pages
|
||||
* Bug: Invalid Ticket
|
||||
* Bug: Posting on the same second
|
||||
* Bug: Images tab count is off
|
||||
|
||||
|
||||
# F-List Exported
|
||||
|
|
Loading…
Reference in New Issue