forked from DebaucheryLibrarian/traxxx
Merged filters into new settings dialog, added experimental summary field.
This commit is contained in:
83
assets/components/settings/filters.vue
Normal file
83
assets/components/settings/filters.vue
Normal file
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<div class="dialog-section">
|
||||
<h3 class="form-heading">Show me</h3>
|
||||
|
||||
<ul class="tags nolist">
|
||||
<li
|
||||
v-for="tag in tags"
|
||||
:key="tag"
|
||||
class="tags-item"
|
||||
>
|
||||
<Checkbox
|
||||
:checked="!tagFilter.includes(tag)"
|
||||
:label="tag"
|
||||
class="tag"
|
||||
@change="(state) => filterTag(tag, state)"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p class="disclaimer">You may still incidentally see filtered out content</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Checkbox from '../form/checkbox.vue';
|
||||
|
||||
function tagFilter() {
|
||||
return this.$store.state.ui.tagFilter;
|
||||
}
|
||||
|
||||
function filterTag(tag, isChecked) {
|
||||
if (isChecked) {
|
||||
this.$store.dispatch('setTagFilter', this.tagFilter.filter((filteredTag) => filteredTag !== tag));
|
||||
} else {
|
||||
this.$store.dispatch('setTagFilter', this.tagFilter.concat(tag));
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Checkbox,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tags: ['anal', 'gay', 'transsexual', 'bisexual', 'pissing', 'anal prolapse'],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
tagFilter,
|
||||
},
|
||||
methods: {
|
||||
filterTag,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dialog-body {
|
||||
width: 40rem;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.filters {
|
||||
width: 20rem;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.tags-item {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tag {
|
||||
padding: .5rem 0;
|
||||
}
|
||||
|
||||
.disclaimer {
|
||||
margin: 1rem 0 0 0;
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
font-size: .9rem;
|
||||
color: var(--shadow);
|
||||
}
|
||||
</style>
|
||||
81
assets/components/settings/settings.vue
Normal file
81
assets/components/settings/settings.vue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<Dialog
|
||||
title="Settings"
|
||||
@close="$emit('close')"
|
||||
>
|
||||
<nav class="tabs">
|
||||
<button
|
||||
class="tab"
|
||||
:class="{ selected: section === 'filters' }"
|
||||
@click="section = 'filters'"
|
||||
>Filters</button>
|
||||
|
||||
<button
|
||||
class="tab"
|
||||
:class="{ selected: section === 'summary' }"
|
||||
@click="section = 'summary'"
|
||||
>Summary</button>
|
||||
</nav>
|
||||
|
||||
<div class="dialog-body">
|
||||
<component :is="sections[section]" />
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { shallowRef } from 'vue';
|
||||
|
||||
import Filters from './filters.vue';
|
||||
import Summary from './summary.vue';
|
||||
|
||||
export default {
|
||||
emits: ['close'],
|
||||
data() {
|
||||
return {
|
||||
sections: {
|
||||
filters: shallowRef(Filters),
|
||||
summary: shallowRef(Summary),
|
||||
},
|
||||
section: 'filters',
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dialog-body {
|
||||
width: 40rem;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.tab {
|
||||
flex-grow: 1;
|
||||
padding: .75rem 1rem;
|
||||
background: var(--shadow-touch);
|
||||
border: none;
|
||||
border-bottom: solid 1px var(--shadow-hint);
|
||||
color: var(--shadow);
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
|
||||
&:not(:first-child) {
|
||||
border-left: solid 1px var(--shadow-hint);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background: none;
|
||||
color: var(--primary);
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--shadow-strong);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
327
assets/components/settings/summary.vue
Normal file
327
assets/components/settings/summary.vue
Normal file
@@ -0,0 +1,327 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="dialog-section">
|
||||
<h3 class="form-heading">Summary format</h3>
|
||||
|
||||
<ul class="summary nolist">
|
||||
<li
|
||||
v-for="(group, groupIndex) in summaryFormat"
|
||||
:key="groupIndex"
|
||||
class="summary-group"
|
||||
>
|
||||
<div class="summary-options">
|
||||
<label class="summary-option">Delimiter
|
||||
<input
|
||||
class="input summary-delimiter"
|
||||
:value="group.delimiter"
|
||||
@change="setSummaryGroupValue(groupIndex, 'delimiter', $event.target.value)"
|
||||
>
|
||||
</label>
|
||||
|
||||
<label class="summary-option">Brackets
|
||||
<select
|
||||
class="select summary-delimiter"
|
||||
:value="group.bracket"
|
||||
@change="setSummaryGroupValue(groupIndex, 'bracket', $event.target.value)"
|
||||
>
|
||||
<option
|
||||
v-for="bracket in brackets"
|
||||
:key="bracket"
|
||||
>{{ bracket }}</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<ul class="summary-segments nolist">
|
||||
<li
|
||||
v-for="(segment, segmentIndex) in group.segments"
|
||||
:key="segmentIndex"
|
||||
class="summary-segment"
|
||||
>
|
||||
<select
|
||||
class="select summary-prop"
|
||||
:value="segment.prop"
|
||||
@change="setSummarySegmentValue(groupIndex, segmentIndex, 'prop', $event.target.value)"
|
||||
>
|
||||
<option>channel</option>
|
||||
<option>network</option>
|
||||
<option>title</option>
|
||||
<option>movie</option>
|
||||
<option>tags</option>
|
||||
<option>actors</option>
|
||||
<option>date</option>
|
||||
</select>
|
||||
|
||||
<input
|
||||
v-if="delimitedProps.includes(segment.prop)"
|
||||
class="input summary-delimiter"
|
||||
:value="segment.delimiter"
|
||||
@change="setSummarySegmentValue(groupIndex, segmentIndex, 'delimiter', $event.target.value)"
|
||||
>
|
||||
|
||||
<select
|
||||
v-if="segment.prop === 'date'"
|
||||
class="select summary-format"
|
||||
:value="segment.format"
|
||||
@change="setSummarySegmentValue(groupIndex, segmentIndex, 'format', $event.target.value)"
|
||||
>
|
||||
<option>YYYY-MM-DD</option>
|
||||
<option>DD-MM-YYYY</option>
|
||||
<option>MM/DD/YYYY</option>
|
||||
</select>
|
||||
|
||||
<Icon
|
||||
icon="bin"
|
||||
class="active"
|
||||
@click="removeSummarySegment(groupIndex, segmentIndex)"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<li class="summary-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="button button-secondary"
|
||||
@click="addSummarySegment(groupIndex)"
|
||||
>Add segment</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="button button-secondary"
|
||||
@click="removeSummaryGroup(groupIndex)"
|
||||
>Remove group</button>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="summary summary-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="button button-secondary"
|
||||
@click="addSummaryGroup"
|
||||
>Add group</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="button button-secondary"
|
||||
@click="resetSummaryFormat"
|
||||
>Reset to default</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="dialog-section">
|
||||
<h3 class="form-heading">Preview</h3>
|
||||
|
||||
<input
|
||||
class="input summary-preview"
|
||||
:value="summary"
|
||||
:title="summary"
|
||||
disabled
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import formatSummary from '../../js/utils/format-summary';
|
||||
|
||||
function summary() {
|
||||
return formatSummary(this.scene, this.summaryFormat);
|
||||
}
|
||||
|
||||
function summaryFormat() {
|
||||
return this.$store.state.ui.summaryFormat;
|
||||
}
|
||||
|
||||
function setSummaryGroupValue(targetGroupIndex, target, value) {
|
||||
const newFormat = this.summaryFormat.map((group, groupIndex) => {
|
||||
if (groupIndex === targetGroupIndex) {
|
||||
return {
|
||||
...group,
|
||||
[target]: value,
|
||||
};
|
||||
}
|
||||
|
||||
return group;
|
||||
});
|
||||
|
||||
this.$store.dispatch('setSummaryFormat', newFormat);
|
||||
}
|
||||
|
||||
function setSummarySegmentValue(targetGroupIndex, targetSegmentIndex, target, value) {
|
||||
const newFormat = this.summaryFormat.map((group, groupIndex) => {
|
||||
if (groupIndex === targetGroupIndex) {
|
||||
return {
|
||||
...group,
|
||||
segments: group.segments.map((segment, segmentIndex) => {
|
||||
if (segmentIndex === targetSegmentIndex) {
|
||||
return {
|
||||
...segment,
|
||||
[target]: value,
|
||||
};
|
||||
}
|
||||
|
||||
return segment;
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
return group;
|
||||
});
|
||||
|
||||
this.$store.dispatch('setSummaryFormat', newFormat);
|
||||
}
|
||||
|
||||
function addSummarySegment(targetGroupIndex) {
|
||||
const newFormat = this.summaryFormat.map((group, groupIndex) => {
|
||||
if (groupIndex === targetGroupIndex) {
|
||||
return {
|
||||
...group,
|
||||
segments: group.segments.concat({
|
||||
prop: 'title',
|
||||
delimiter: ',', // default delimiter for when prop is changed to iterabte like actors or tags
|
||||
format: 'YYYY-MM-DD', // default format for when prop is changed to date
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
return group;
|
||||
});
|
||||
|
||||
this.$store.dispatch('setSummaryFormat', newFormat);
|
||||
}
|
||||
|
||||
function addSummaryGroup() {
|
||||
const newFormat = this.summaryFormat.concat({
|
||||
delimiter: ' - ',
|
||||
segments: [{ prop: 'title' }],
|
||||
});
|
||||
|
||||
this.$store.dispatch('setSummaryFormat', newFormat);
|
||||
}
|
||||
|
||||
function removeSummaryGroup(groupIndex) {
|
||||
const newFormat = this.summaryFormat.filter((group, index) => index !== groupIndex);
|
||||
|
||||
this.$store.dispatch('setSummaryFormat', newFormat);
|
||||
}
|
||||
|
||||
function removeSummarySegment(targetGroupIndex, targetSegmentIndex) {
|
||||
const newFormat = this.summaryFormat.map((group, groupIndex) => ({
|
||||
...group,
|
||||
segments: groupIndex === targetGroupIndex
|
||||
? group.segments.filter((segment, index) => index !== targetSegmentIndex)
|
||||
: group.segments,
|
||||
}));
|
||||
|
||||
this.$store.dispatch('setSummaryFormat', newFormat);
|
||||
}
|
||||
|
||||
function resetSummaryFormat() {
|
||||
this.$store.dispatch('setSummaryFormat', this.$store.state.ui.defaultSummaryFormat);
|
||||
}
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
delimiters: [null, '-', '_', ',', '.'],
|
||||
brackets: [null, '()', '[]', '{}', '<>'],
|
||||
delimitedProps: ['actors', 'tags'],
|
||||
scene: {
|
||||
channel: 'Channel',
|
||||
network: 'Network',
|
||||
title: 'Title',
|
||||
movie: 'Movie',
|
||||
scene: 1,
|
||||
actors: ['Jane Doe', 'John Doe'],
|
||||
date: new Date(),
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
summary,
|
||||
summaryFormat,
|
||||
},
|
||||
methods: {
|
||||
addSummaryGroup,
|
||||
setSummaryGroupValue,
|
||||
addSummarySegment,
|
||||
setSummarySegmentValue,
|
||||
removeSummaryGroup,
|
||||
removeSummarySegment,
|
||||
resetSummaryFormat,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.summary {
|
||||
.icon {
|
||||
padding: .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.summary-group,
|
||||
.summary-segment {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.summary-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: .5rem;
|
||||
|
||||
.button {
|
||||
margin-top: .5rem;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
padding-bottom: .5rem;
|
||||
border-bottom: solid 1px var(--shadow-hint);
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.summary-segments {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.summary-segment {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: .25rem;
|
||||
}
|
||||
|
||||
.summary-delimiter {
|
||||
width: 5rem;
|
||||
}
|
||||
|
||||
.summary-format {
|
||||
width: 9rem;
|
||||
}
|
||||
|
||||
.summary-prop {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.summary-options {
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
.summary-option:not(:last-child) {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.summary-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.summary-preview {
|
||||
width: 100%;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user