Ad UI cleanup

This commit is contained in:
Mr. Stallion 2020-03-22 13:39:45 -05:00
parent a95d483eb6
commit 2466e8f3be
7 changed files with 207 additions and 98 deletions

View File

@ -0,0 +1,96 @@
<template>
<modal :action="`Ad settings for ${conversation.name}`" @submit="submit" ref="dialog" @open="load()" dialogClass="w-100"
:buttonText="l('conversationSettings.save')">
<div class="form-group ad-list" v-for="(ad, index) in ads">
<label :for="'ad' + conversation.key + '-' + index" class="control-label">Ad #{{(index + 1)}}
<a v-if="(index > 0)" @click="moveAdUp(index)" title="Move Up"><i class="fa fa-arrow-up"></i></a>
<a v-if="(index < ads.length - 1)" @click="moveAdDown(index)" title="Move Down"><i class="fa fa-arrow-down"></i></a>
<a @click="removeAd(index)" title="Remove Ad"><i class="fa fa-minus-circle"></i></a>
</label>
<textarea :id="'ad' + conversation.key + '-' + index" class="form-control" v-model="ads[index]"></textarea>
</div>
<button class="btn btn-outline-secondary" @click="addAd()">Add Another</button>
</modal>
</template>
<script lang="ts">
import {Component, Prop} from '@f-list/vue-ts';
import CustomDialog from '../components/custom_dialog';
import Modal from '../components/Modal.vue';
import {Conversation} from './interfaces';
import l from './localize';
@Component({
components: {modal: Modal}
})
export default class ConversationAdSettings extends CustomDialog {
@Prop({required: true})
readonly conversation!: Conversation;
l = l;
setting = Conversation.Setting;
ads!: string[];
load(): void {
const settings = this.conversation.settings;
this.ads = settings.adSettings.ads.slice(0);
if (this.ads.length === 0) {
this.ads.push('');
}
}
submit(): void {
this.conversation.settings = {
notify: this.conversation.settings.notify,
highlight: this.conversation.settings.highlight,
highlightWords: this.conversation.settings.highlightWords,
joinMessages: this.conversation.settings.joinMessages,
defaultHighlights: this.conversation.settings.defaultHighlights,
adSettings: {
ads: this.ads.map((ad: string) => ad.trim()).filter((ad: string) => (ad.length > 0))
}
};
}
addAd(): void {
this.ads.push('');
}
removeAd(index: number): void {
if (confirm('Are you sure you wish to remove this ad?')) {
this.ads.splice(index, 1);
}
}
moveAdUp(index: number): void {
const ad = this.ads.splice(index, 1);
this.ads.splice(index - 1, 0, ad[0]);
}
moveAdDown(index: number): void {
const ad = this.ads.splice(index, 1);
this.ads.splice(index + 1, 0, ad[0]);
}
}
</script>
<style lang="scss">
.form-group.ad-list label a {
padding-right: 0.3rem;
opacity:0.3
}
.form-group.ad-list label a:hover {
opacity:0.6
}
</style>

View File

@ -35,19 +35,6 @@
<option :value="setting.False">{{l('conversationSettings.false')}}</option> <option :value="setting.False">{{l('conversationSettings.false')}}</option>
</select> </select>
</div> </div>
<h5>Auto-Posting Channel Ads</h5>
<div class="form-group ad-list" v-for="(ad, index) in ads">
<label :for="'ad' + conversation.key + '-' + index" class="control-label">Ad #{{(index + 1)}}
<a v-if="(index > 0)" @click="moveAdUp(index)" title="Move Up"><i class="fa fa-arrow-up"></i></a>
<a v-if="(index < ads.length - 1)" @click="moveAdDown(index)" title="Move Down"><i class="fa fa-arrow-down"></i></a>
<a @click="removeAd(index)" title="Remove Ad"><i class="fa fa-minus-circle"></i></a>
</label>
<textarea :id="'ad' + conversation.key + '-' + index" class="form-control" v-model="ads[index]"></textarea>
</div>
<button class="btn btn-outline-secondary" @click="addAd()">Add Another</button>
</modal> </modal>
</template> </template>
@ -71,7 +58,6 @@
highlightWords!: string; highlightWords!: string;
joinMessages!: Conversation.Setting; joinMessages!: Conversation.Setting;
defaultHighlights!: boolean; defaultHighlights!: boolean;
ads!: string[];
load(): void { load(): void {
const settings = this.conversation.settings; const settings = this.conversation.settings;
@ -80,11 +66,6 @@
this.highlightWords = settings.highlightWords.join(','); this.highlightWords = settings.highlightWords.join(',');
this.joinMessages = settings.joinMessages; this.joinMessages = settings.joinMessages;
this.defaultHighlights = settings.defaultHighlights; this.defaultHighlights = settings.defaultHighlights;
this.ads = settings.adSettings.ads.slice(0);
if (this.ads.length === 0) {
this.ads.push('');
}
} }
submit(): void { submit(): void {
@ -94,49 +75,9 @@
highlightWords: this.highlightWords.split(',').map((x) => x.trim()).filter((x) => (x.length > 0)), highlightWords: this.highlightWords.split(',').map((x) => x.trim()).filter((x) => (x.length > 0)),
joinMessages: this.joinMessages, joinMessages: this.joinMessages,
defaultHighlights: this.defaultHighlights, defaultHighlights: this.defaultHighlights,
adSettings: { adSettings: this.conversation.settings.adSettings
ads: this.ads.map((ad: string) => ad.trim()).filter((ad: string) => (ad.length > 0))
}
}; };
} }
addAd(): void {
this.ads.push('');
}
removeAd(index: number): void {
if (confirm('Are you sure you wish to remove this ad?')) {
this.ads.splice(index, 1);
}
}
moveAdUp(index: number): void {
const ad = this.ads.splice(index, 1);
this.ads.splice(index - 1, 0, ad[0]);
}
moveAdDown(index: number): void {
const ad = this.ads.splice(index, 1);
this.ads.splice(index + 1, 0, ad[0]);
}
} }
</script> </script>
<style lang="scss">
.form-group.ad-list label a {
padding-right: 0.3rem;
opacity:0.3
}
.form-group.ad-list label a:hover {
opacity:0.6
}
</style>

View File

@ -50,16 +50,31 @@
<a href="#" @click.prevent="reportDialog.report()" class="btn"> <a href="#" @click.prevent="reportDialog.report()" class="btn">
<span class="fa fa-exclamation-triangle"></span><span class="btn-text">{{l('chat.report')}}</span></a> <span class="fa fa-exclamation-triangle"></span><span class="btn-text">{{l('chat.report')}}</span></a>
</div> </div>
<ul class="nav nav-pills mode-switcher">
<li v-for="mode in modes" class="nav-item"> <!-- <ul class="nav nav-pills mode-switcher">-->
<a :class="isChannel(conversation) ? {active: conversation.mode == mode, disabled: conversation.channel.mode != 'both'} : undefined" <!-- <li v-for="mode in modes" class="nav-item">-->
class="nav-link" href="#" @click.prevent="setMode(mode)">{{l('channel.mode.' + mode)}}</a> <!-- <a :class="isChannel(conversation) ? {active: conversation.mode == mode, disabled: conversation.channel.mode != 'both'} : undefined"-->
</li> <!-- class="nav-link" href="#" @click.prevent="setMode(mode)">{{l('channel.mode.' + mode)}}</a>-->
<li> <!-- </li>-->
<a @click.prevent="toggleNonMatchingAds()" :class="{active: showNonMatchingAds}" v-show="(conversation.mode == 'both' || conversation.mode == 'ads')" <!-- <li>-->
class="nav-link" href="#">Non-Matching</a> <!-- <a @click.prevent="toggleNonMatchingAds()" :class="{active: showNonMatchingAds}" v-show="(conversation.mode == 'both' || conversation.mode == 'ads')"-->
</li> <!-- class="nav-link" href="#">Non-Matching</a>-->
</ul> <!-- </li>-->
<!-- </ul>-->
<div class="btn-toolbar">
<dropdown :keep-open="false" title="View" :icon-class="{fas: true, 'fa-comments': conversation.mode === 'chat', 'fa-ad': conversation.mode === 'ads', 'fa-asterisk': conversation.mode === 'both'}" wrap-class="btn-group views" link-class="btn btn-secondary dropdown-toggle" v-show="(conversation.channel.mode == 'both')">
<button v-for="mode in modes" class="dropdown-item" :class="{ selected: conversation.mode == mode }" type="button" @click="setMode(mode)">{{l('channel.mode.' + mode)}}</button>
</dropdown>
<dropdown :keep-open="false" title="Ads" :icon-class="{fas: true, 'fa-pause': !conversation.adManager.isActive(), 'fa-play': conversation.adManager.isActive()}" wrap-class="btn-group ads" link-class="btn btn-secondary dropdown-toggle" v-show="(conversation.channel.mode == 'both' || conversation.channel.mode == 'ads')">
<button class="dropdown-item" type="button" @click="toggleAutoPostAds()">{{conversation.adManager.isActive() ? 'Stop' : 'Start'}} Posting Ads</button>
<button class="dropdown-item" type="button" @click="showAdSettings()">Edit Channel Ads</button>
<div class="dropdown-divider"></div>
<button class="dropdown-item" :class="{ selected: showNonMatchingAds }" type="button" @click="toggleNonMatchingAds()">Show Incompatible Ads</button>
</dropdown>
</div>
</div> </div>
<div style="z-index:5;position:absolute;left:0;right:0;max-height:60%;overflow:auto" <div style="z-index:5;position:absolute;left:0;right:0;max-height:60%;overflow:auto"
:style="{display: descriptionExpanded ? 'block' : 'none'}" class="bg-solid-text border-bottom"> :style="{display: descriptionExpanded ? 'block' : 'none'}" class="bg-solid-text border-bottom">
@ -91,7 +106,7 @@
</div> </div>
<a class="btn btn-sm btn-outline-primary renew-autoposts" @click="renewAutoPosting()" v-if="!adsRequireSetup">{{l('admgr.renew')}}</a> <a class="btn btn-sm btn-outline-primary renew-autoposts" @click="renewAutoPosting()" v-if="!adsRequireSetup">{{l('admgr.renew')}}</a>
<a class="btn btn-sm btn-outline-primary renew-autoposts" @click="showSettings()" v-if="adsRequireSetup">{{l('admgr.setup')}}</a> <a class="btn btn-sm btn-outline-primary renew-autoposts" @click="showAdSettings()" v-if="adsRequireSetup">{{l('admgr.setup')}}</a>
</div> </div>
<div class="border-top messages" :class="getMessageWrapperClasses()" ref="messages" <div class="border-top messages" :class="getMessageWrapperClasses()" ref="messages"
@scroll="onMessagesScroll" style="flex:1;overflow:auto;margin-top:2px"> @scroll="onMessagesScroll" style="flex:1;overflow:auto;margin-top:2px">
@ -130,23 +145,24 @@
</div> </div>
<ul class="nav nav-pills send-ads-switcher" v-if="isChannel(conversation)" <ul class="nav nav-pills send-ads-switcher" v-if="isChannel(conversation)"
style="position:relative;z-index:10;margin-right:5px"> style="position:relative;z-index:10;margin-right:5px">
<li class="nav-item"> <li class="nav-item" v-show="((conversation.channel.mode === 'both') || (conversation.channel.mode === 'chat'))">
<a href="#" :class="{active: !conversation.isSendingAds, disabled: (conversation.channel.mode != 'both') || (conversation.adManager.isActive())}" <a href="#" :class="{active: !conversation.isSendingAds, disabled: (conversation.channel.mode != 'both') || (conversation.adManager.isActive())}"
class="nav-link" @click.prevent="setSendingAds(false)">{{l('channel.mode.chat')}}</a> class="nav-link" @click.prevent="setSendingAds(false)">{{l('channel.mode.chat')}}</a>
</li> </li>
<li class="nav-item"> <li class="nav-item" v-show="((conversation.channel.mode === 'both') || (conversation.channel.mode === 'ads'))">
<a href="#" :class="{active: conversation.isSendingAds, disabled: (conversation.channel.mode != 'both') || (conversation.adManager.isActive())}" <a href="#" :class="{active: conversation.isSendingAds, disabled: (conversation.channel.mode != 'both') || (conversation.adManager.isActive())}"
class="nav-link" @click.prevent="setSendingAds(true)">{{adsMode}}</a> class="nav-link" @click.prevent="setSendingAds(true)">{{adsMode}}</a>
</li> </li>
<li class="nav-item"> <!-- <li class="nav-item">-->
<a href="#" :class="{active: conversation.adManager.isActive()}" class="nav-link toggle-autopost" @click="toggleAutoPostAds()">{{l('admgr.toggleAutoPost')}}</a> <!-- <a href="#" :class="{active: conversation.adManager.isActive()}" class="nav-link toggle-autopost" @click="toggleAutoPostAds()">{{l('admgr.toggleAutoPost')}}</a>-->
</li> <!-- </li>-->
</ul> </ul>
<div class="btn btn-sm btn-primary" v-show="!settings.enterSend" @click="sendButton">{{l('chat.send')}}</div> <div class="btn btn-sm btn-primary" v-show="!settings.enterSend" @click="sendButton">{{l('chat.send')}}</div>
</div> </div>
</bbcode-editor> </bbcode-editor>
<command-help ref="helpDialog"></command-help> <command-help ref="helpDialog"></command-help>
<settings ref="settingsDialog" :conversation="conversation"></settings> <settings ref="settingsDialog" :conversation="conversation"></settings>
<adSettings ref="adSettingsDialog" :conversation="conversation"></adSettings>
<logs ref="logsDialog" :conversation="conversation"></logs> <logs ref="logsDialog" :conversation="conversation"></logs>
<manage-channel ref="manageDialog" v-if="isChannel(conversation)" :channel="conversation.channel"></manage-channel> <manage-channel ref="manageDialog" v-if="isChannel(conversation)" :channel="conversation.channel"></manage-channel>
<ad-view ref="adViewer" v-if="isPrivate(conversation) && conversation.character" :character="conversation.character"></ad-view> <ad-view ref="adViewer" v-if="isPrivate(conversation) && conversation.character" :character="conversation.character"></ad-view>
@ -166,6 +182,7 @@
import CommandHelp from './CommandHelp.vue'; import CommandHelp from './CommandHelp.vue';
import { characterImage, getByteLength, getKey } from './common'; import { characterImage, getByteLength, getKey } from './common';
import ConversationSettings from './ConversationSettings.vue'; import ConversationSettings from './ConversationSettings.vue';
import ConversationAdSettings from './ConversationAdSettings.vue';
import core from './core'; import core from './core';
import {Channel, channelModes, Character, Conversation, Settings} from './interfaces'; import {Channel, channelModes, Character, Conversation, Settings} from './interfaces';
import l from './localize'; import l from './localize';
@ -177,13 +194,14 @@
import UserView from './UserView.vue'; import UserView from './UserView.vue';
import UserChannelList from './UserChannelList.vue'; import UserChannelList from './UserChannelList.vue';
import * as _ from 'lodash'; import * as _ from 'lodash';
import Dropdown from '../components/Dropdown.vue';
@Component({ @Component({
components: { components: {
user: UserView, 'bbcode-editor': Editor, 'manage-channel': ManageChannel, settings: ConversationSettings, user: UserView, 'bbcode-editor': Editor, 'manage-channel': ManageChannel, settings: ConversationSettings,
logs: Logs, 'message-view': MessageView, bbcode: BBCodeView(core.bbCodeParser), 'command-help': CommandHelp, logs: Logs, 'message-view': MessageView, bbcode: BBCodeView(core.bbCodeParser), 'command-help': CommandHelp,
'ad-view': AdView, 'channel-list': UserChannelList 'ad-view': AdView, 'channel-list': UserChannelList, dropdown: Dropdown, adSettings: ConversationAdSettings
} }
}) })
export default class ConversationView extends Vue { export default class ConversationView extends Vue {
@ -447,6 +465,10 @@
(<ConversationSettings>this.$refs['settingsDialog']).show(); (<ConversationSettings>this.$refs['settingsDialog']).show();
} }
showAdSettings(): void {
(<ConversationAdSettings>this.$refs['adSettingsDialog']).show();
}
showManage(): void { showManage(): void {
(<ManageChannel>this.$refs['manageDialog']).show(); (<ManageChannel>this.$refs['manageDialog']).show();
} }
@ -573,6 +595,47 @@
} }
} }
.btn-toolbar {
.btn-group {
margin-right: 0.3rem;
&:last-child {
margin-right: 0;
}
a.btn {
padding-left: 0.5rem;
padding-right: 0.5rem;
i {
margin-right: 0.4rem;
font-size: 90%;
}
}
button::before {
display: inline-block;
width: 1.3rem;
height: 1rem;
content: '';
margin-left: -1.3rem;
margin-right: 0.1rem;
padding-left: 0.3rem;
font-weight: bold;
}
button.selected::before {
content: '✓';
}
&.views {
button.selected::before {
content: '•';
}
}
}
}
.send-ads-switcher a { .send-ads-switcher a {
padding: 3px 10px; padding: 3px 10px;
} }
@ -584,13 +647,14 @@
.auto-ads { .auto-ads {
background-color: rgba(255, 128, 32, 0.8); background-color: rgb(220, 113, 31);
padding-left: 10px; padding-left: 10px;
padding-right: 10px; padding-right: 10px;
padding-top: 5px; padding-top: 5px;
padding-bottom: 5px; padding-bottom: 5px;
margin: 0; margin: 0;
position: relative; position: relative;
margin-top: 5px;
.renew-autoposts { .renew-autoposts {
display: block; display: block;

View File

@ -21,14 +21,13 @@
<script lang="ts"> <script lang="ts">
import { Component, Hook, Prop } from '@f-list/vue-ts'; import { Component, Hook, Prop } from '@f-list/vue-ts';
import Modal from '../components/Modal.vue'; import Modal from '../components/Modal.vue';
import Dropdown from '../components/Dropdown.vue';
import CustomDialog from '../components/custom_dialog'; import CustomDialog from '../components/custom_dialog';
import core from './core'; import core from './core';
import { BBCodeView } from '../bbcode/view'; import { BBCodeView } from '../bbcode/view';
import * as _ from 'lodash'; import * as _ from 'lodash';
@Component({ @Component({
components: {modal: Modal, dropdown: Dropdown, bbcode: BBCodeView(core.bbCodeParser)} components: {modal: Modal, bbcode: BBCodeView(core.bbCodeParser)}
}) })
export default class StatusPicker extends CustomDialog { export default class StatusPicker extends CustomDialog {
@Prop({required: true}) @Prop({required: true})

View File

@ -20,11 +20,11 @@ const strings: {[key: string]: string | undefined} = {
'admgr.postingBegins': 'Posting beings in {0}m {1}s', 'admgr.postingBegins': 'Posting beings in {0}m {1}s',
'admgr.nextPostDue': 'Next ad in {0}m {1}s', 'admgr.nextPostDue': 'Next ad in {0}m {1}s',
'admgr.expiresIn': ', auto-posting expires in {0}m {1}s', 'admgr.expiresIn': ', auto-posting expires in {0}m {1}s',
'admgr.noAds': 'No ads have been set up -- auto-posting will be cancelled. Click "Tab Settings" to set up your ads.', 'admgr.noAds': 'No ads have been set up -- auto-posting will be cancelled. Click "Ads > Edit Channel Ads" to set up your ads.',
'admgr.activeHeader': 'Auto-Posting Ads', 'admgr.activeHeader': 'Auto-Posting Ads',
'admgr.comingNext': 'Coming Next', 'admgr.comingNext': 'Coming Next',
'admgr.renew': 'Renew', 'admgr.renew': 'Renew',
'admgr.setup': 'Setup Ads', 'admgr.setup': 'Set-Up Ads',
'admgr.toggleAutoPost': 'Auto-Post Ads', 'admgr.toggleAutoPost': 'Auto-Post Ads',
'consoleWarning.head': 'THIS IS THE DANGER ZONE.', 'consoleWarning.head': 'THIS IS THE DANGER ZONE.',
'consoleWarning.body': `ANYTHING YOU WRITE OR PASTE IN HERE COULD BE USED TO STEAL YOUR PASSWORDS OR TAKE OVER YOUR ENTIRE COMPUTER. This is where happiness goes to die. If you aren't a developer or a special kind of daredevil, please get out of here!`, 'consoleWarning.body': `ANYTHING YOU WRITE OR PASTE IN HERE COULD BE USED TO STEAL YOUR PASSWORDS OR TAKE OVER YOUR ENTIRE COMPUTER. This is where happiness goes to die. If you aren't a developer or a special kind of daredevil, please get out of here!`,
@ -439,4 +439,4 @@ export default function l(key: string, ...args: (string | number)[]): string {
while(i-- > 0) while(i-- > 0)
str = str.replace(new RegExp(`\\{${i}\\}`, 'igm'), args[i].toString()); str = str.replace(new RegExp(`\\{${i}\\}`, 'igm'), args[i].toString());
return str; return str;
} }

View File

@ -1,7 +1,8 @@
<template> <template>
<div class="dropdown" @focusout="blur"> <div :class="wrapClass" @focusout="blur">
<a :class="linkClass" aria-haspopup="true" :aria-expanded="isOpen" @click.prevent="isOpen = !isOpen" href="#" <a :class="linkClass" aria-haspopup="true" :aria-expanded="isOpen" @click.prevent="isOpen = !isOpen" href="#"
style="width:100%;text-align:left;align-items:center" role="button" tabindex="-1" ref="button"> style="width:100%;text-align:left;align-items:center" role="button" tabindex="-1" ref="button">
<i :class="iconClass" v-if="!!iconClass"></i>
<slot name="title">{{title}}</slot> <slot name="title">{{title}}</slot>
</a> </a>
<div class="dropdown-menu" ref="menu" @mousedown.prevent.stop @click.prevent.stop="menuClick()"> <div class="dropdown-menu" ref="menu" @mousedown.prevent.stop @click.prevent.stop="menuClick()">
@ -19,6 +20,10 @@
isOpen = false; isOpen = false;
@Prop({default: 'btn btn-secondary dropdown-toggle'}) @Prop({default: 'btn btn-secondary dropdown-toggle'})
readonly linkClass!: string; readonly linkClass!: string;
@Prop({default: 'dropdown'})
readonly wrapClass!: string;
@Prop
readonly iconClass?: string;
@Prop @Prop
readonly keepOpen?: boolean; readonly keepOpen?: boolean;
@Prop @Prop
@ -52,4 +57,4 @@
if(!this.keepOpen) this.isOpen = false; if(!this.keepOpen) this.isOpen = false;
} }
} }
</script> </script>

View File

@ -31,7 +31,7 @@ This repository contains a heavily customized version of the mainline F-Chat 3.0
* Custom kink explanations can be expanded inline * Custom kink explanations can be expanded inline
* Custom kinks are highlighted * Custom kinks are highlighted
* Gender, anthro/human preference, age, sexual preference, and sub/dom preference are highlighted if compatible or incompatible * Gender, anthro/human preference, age, sexual preference, and sub/dom preference are highlighted if compatible or incompatible
* Guestbook, friend, and group counts are visible on tabs * Guestbook, friend, and group counts are visible on tab titles
* Character images are expanded inline * Character images are expanded inline
* Cleaner presentation for the side bar details (age, etc.), sorted in most relevant order * Cleaner presentation for the side bar details (age, etc.), sorted in most relevant order
* Less informative side bar details (views, contact) are separated and shown in a less prominent way * Less informative side bar details (views, contact) are separated and shown in a less prominent way
@ -55,17 +55,26 @@ This repository contains a heavily customized version of the mainline F-Chat 3.0
## How to Set Up Ads ## How to Set Up Ads
1. Open a conversation channel of your preference, such as `#LFRP` 1. Open a conversation channel of your preference, such as `#Sex Driven LFRP`
1. Click `Tab Settings` 1. Locate `Ads` dropdown at the top right corner of the channel view
1. Enter one or more `Channel Auto-Posting Ads` 1. Click `Ads > Edit Channel Ads`
1. Enter one or more ads
1. Click `Save settings` 1. Click `Save settings`
1. Click `Auto-Post Ads` 1. Click `Ads > Start Posting Ads`
1. To stop, click `Ads > Stop Posting Ads`
## FAQ ## FAQ
1. The more information you have in your profile (**non-custom** kinks in particular), the better the matching quality will be. 1. The more information you have in your profile (**non-custom** kinks in particular), the better the matching quality will be. The algorithm considers the following data points:
1. Non-binary gender preference matching relies on kinks. For example, if your non-binary character has a preference for females, make sure 'females' are listed as a favorite kink. * Age
* Gender
* Sexual preference
* Dominance preference
* Human/anthro preference
* Non-custom kinks
* Species
1. Maching for non-binary genders relies on kinks. For example, if your non-binary character has a preference for females, make sure 'females' are listed as a favorite kink.
1. 'Underage' kink is considered to apply to characters aged 16 or above; 'ageplay' kink is considered to apply to characters aged 16 or below. 1. 'Underage' kink is considered to apply to characters aged 16 or above; 'ageplay' kink is considered to apply to characters aged 16 or below.
1. 'Older characters' and 'younger characters' kink preferences are interpreted as age difference of 5+ years. 1. 'Older characters' and 'younger characters' kink preferences are interpreted as age difference of 5+ years.
1. Comparison results will get faster over time, as more and more character data is cached. 1. Comparison results will get faster over time, as more and more character data is cached.
@ -75,15 +84,10 @@ This repository contains a heavily customized version of the mainline F-Chat 3.0
* Collect data on ads / responses to determine which ads work best * Collect data on ads / responses to determine which ads work best
* Preview mode should allow detaching from the main window * Preview mode should allow detaching from the main window
* Split chat view / separate window for specific chats?
* Improve log browsing * Improve log browsing
* Reposition ad settings and toggle
* Save character's status messages
* Conversation bot API * Conversation bot API
* 'Filter unmatching ads' is not channel specific -- it's either on everywhere or nowhere * 'Filter unmatching ads' is not channel specific -- it's either on everywhere or nowhere
* AD UI Cleanup / hide to popovers? * Bug? Usually submissive vs usually submissive shows up as 'maybe'
* image loading animation
* Usually submissive vs usually submissive shows up as 'maybe'?
# F-List Exported # F-List Exported