Added database structure for profiles and tattoos. Improved sidebar appearance. Expanded new actors module.

This commit is contained in:
ThePendulum 2020-03-26 03:32:07 +01:00
parent bb3f6fc408
commit d29e296799
12 changed files with 558 additions and 342 deletions

View File

@ -16,7 +16,7 @@
"tabWidth": 4, "tabWidth": 4,
"ignoreUrls": true "ignoreUrls": true
}], }],
"vue/no-v-html" 0: , "vue/no-v-html": 0,
"vue/html-indent": ["error", 4], "vue/html-indent": ["error", 4],
"vue/multiline-html-element-content-newline": 0, "vue/multiline-html-element-content-newline": 0,
"vue/singleline-html-element-content-newline": 0, "vue/singleline-html-element-content-newline": 0,

View File

@ -2,7 +2,7 @@
<header class="header"> <header class="header">
<div class="header-nav"> <div class="header-nav">
<Icon <Icon
icon="grid2" icon="menu"
class="sidebar-toggle" class="sidebar-toggle"
@click.native.stop="toggleSidebar" @click.native.stop="toggleSidebar"
/> />
@ -203,8 +203,8 @@ export default {
.sidebar-toggle { .sidebar-toggle {
display: none; display: none;
fill: var(--shadow-modest); fill: var(--shadow-modest);
padding: 0 1.5rem 0 1rem; padding: 0 1rem;
width: 1.25rem; width: 1.5rem;
height: 100%; height: 100%;
&:hover { &:hover {

View File

@ -5,7 +5,7 @@
> >
<div class="sidebar-header"> <div class="sidebar-header">
<Icon <Icon
icon="cross" icon="cross2"
class="sidebar-close" class="sidebar-close"
@click.native="toggleSidebar(false)" @click.native="toggleSidebar(false)"
/> />
@ -31,6 +31,21 @@
<nav class="nav"> <nav class="nav">
<ul class="nolist"> <ul class="nolist">
<li class="nav-item">
<router-link
v-slot="{ href, isActive, navigate }"
to="/home"
@click.native="toggleSidebar(false)"
>
<a
class="nav-link"
:href="href"
:class="{ active: isActive }"
@click="navigate"
>Home</a>
</router-link>
</li>
<li class="nav-item"> <li class="nav-item">
<router-link <router-link
v-slot="{ href, isActive, navigate }" v-slot="{ href, isActive, navigate }"
@ -96,7 +111,7 @@ export default {
logoPrimary, logoPrimary,
logoLight, logoLight,
}; };
} },
}; };
</script> </script>
@ -122,9 +137,9 @@ export default {
} }
.sidebar-close { .sidebar-close {
width: 1.25rem; width: 1.5rem;
height: 100%; height: 100%;
padding: 0 1.5rem 0 1rem; padding: 0 1rem;
fill: var(--lighten); fill: var(--lighten);
&:hover { &:hover {

View File

@ -106,10 +106,6 @@ export default {
color: var(--primary); color: var(--primary);
} }
} }
.dark .sidebar {
border-right: solid 1px var(--shadow-weak);
}
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -201,6 +197,10 @@ export default {
padding: 1rem; padding: 1rem;
} }
.dark .sidebar {
border-right: solid 1px var(--shadow-hint);
}
@media(max-width: $breakpoint3) { @media(max-width: $breakpoint3) {
.tag { .tag {
flex-direction: column; flex-direction: column;

View File

@ -90,8 +90,6 @@ async function mounted() {
[category]: tagSlugs.map(tagSlug => tagsBySlug[tagSlug]), [category]: tagSlugs.map(tagSlug => tagsBySlug[tagSlug]),
}), {}); }), {});
console.log(this.categories);
this.pageTitle = 'Tags'; this.pageTitle = 'Tags';
} }

View File

@ -1,5 +1,5 @@
<!-- Generated by IcoMoon.io --> <!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<title>menu</title> <title>menu</title>
<path d="M2 6h28v6h-28zM2 14h28v6h-28zM2 22h28v6h-28z"></path> <path d="M13 7c1.105 0 2 0.895 2 2s-0.895 2-2 2c-1.105 0-2-0.895-2-2s0.895-2 2-2zM8 7c1.105 0 2 0.895 2 2s-0.895 2-2 2c-1.105 0-2-0.895-2-2s0.895-2 2-2zM3 7c1.105 0 2 0.895 2 2s-0.895 2-2 2c-1.105 0-2-0.895-2-2s0.895-2 2-2z"></path>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 221 B

After

Width:  |  Height:  |  Size: 391 B

5
assets/img/menu3.svg Normal file
View File

@ -0,0 +1,5 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<title>menu3</title>
<path d="M1 3h14v3h-14zM1 7h14v3h-14zM1 11h14v3h-14z"></path>
</svg>

After

Width:  |  Height:  |  Size: 221 B

View File

@ -250,6 +250,28 @@ exports.up = knex => Promise.resolve()
.unique() .unique()
.notNullable(); .notNullable();
table.string('slug', 32)
.unique();
table.integer('alias_for', 12)
.references('id')
.inTable('actors');
table.integer('network_id', 12)
.references('id')
.inTable('networks');
table.datetime('created_at')
.defaultTo(knex.fn.now());
}))
.then(() => knex.schema.createTable('actors_profiles', (table) => {
table.increments('id', 12);
table.integer('actor_id')
.references('id')
.inTable('actors')
.notNullable();
table.date('birthdate'); table.date('birthdate');
table.string('gender', 18); table.string('gender', 18);
table.text('description'); table.text('description');
@ -283,19 +305,142 @@ exports.up = knex => Promise.resolve()
table.string('piercings'); table.string('piercings');
table.string('tattoos'); table.string('tattoos');
table.integer('alias_for', 12)
.references('id')
.inTable('actors');
table.string('slug', 32)
.unique();
table.datetime('created_at') table.datetime('created_at')
.defaultTo(knex.fn.now()); .defaultTo(knex.fn.now());
table.datetime('scraped_at'); table.datetime('scraped_at');
table.boolean('scrape_success'); table.boolean('scrape_success');
})) }))
.then(() => knex.schema.createTable('body', (table) => {
table.string('slug', 20)
.primary();
table.string('name');
}))
.then(() => knex('body').insert([
// head
{ slug: 'head', name: 'head' },
{ slug: 'face', name: 'face' },
{ slug: 'scalp', name: 'scalp' },
{ slug: 'forehead', name: 'forehead' },
{ slug: 'cheek', name: 'cheek' },
{ slug: 'chin', name: 'chin' },
{ slug: 'neck', name: 'neck' },
{ slug: 'throat', name: 'throat' },
// eyes
{ slug: 'eyelid', name: 'eyelid' },
{ slug: 'eyeball', name: 'eyeball' },
{ slug: 'eyebrow', name: 'eyebrow' },
// mouth
{ slug: 'tongue', name: 'tongue' },
{ slug: 'lip', name: 'lip' },
{ slug: 'upper-lip', name: 'upper lip' },
{ slug: 'lower-lip', name: 'lower lip' },
{ slug: 'inner-lip', name: 'inner lip' },
{ slug: 'above-lip', name: 'above lip' },
{ slug: 'below-lip', name: 'below lip' },
// nose
{ slug: 'nose', name: 'nose' },
{ slug: 'third-eye', name: 'third eye' },
{ slug: 'bridge', name: 'bridge' },
{ slug: 'nostril', name: 'nostril' },
{ slug: 'septum', name: 'septum' },
{ slug: 'septril', name: 'septril' },
// ear
{ slug: 'ear', name: 'ear' },
{ slug: 'earlobe', name: 'earlobe' },
{ slug: 'helix', name: 'helix' },
{ slug: 'tragus', name: 'tragus' },
{ slug: 'conch', name: 'conch' },
{ slug: 'rook', name: 'rook' },
{ slug: 'behind-ear', name: 'behind ear' },
// arms
{ slug: 'arm', name: 'arm' },
{ slug: 'upper-arm', name: 'upper arm' },
{ slug: 'lower-arm', name: 'lower arm' },
{ slug: 'elbow', name: 'elbow' },
{ slug: 'inner-elbow', name: 'inner elbow' },
{ slug: 'outer-elbow', name: 'outer elbow' },
// hands
{ slug: 'hand', name: 'hand' },
{ slug: 'fingers', name: 'fingers' },
{ slug: 'knuckles', name: 'knucles' },
{ slug: 'thumb', name: 'thumb' },
{ slug: 'index-finger', name: 'index finger' },
{ slug: 'middle-finger', name: 'middle finger' },
{ slug: 'ring-finger', name: 'ring finger' },
{ slug: 'pinky', name: 'pinky' },
{ slug: 'back-of-hand', name: 'back of hand' },
{ slug: 'inner-wrist', name: 'inner wrist' },
{ slug: 'outer-wrist', name: 'outer wrist' },
// torso
{ slug: 'shoulder', name: 'shoulder' },
{ slug: 'collarbone', name: 'collarbone' },
{ slug: 'chest', name: 'chest' },
{ slug: 'rib-cage', name: 'rib cage' },
{ slug: 'underboob', name: 'underboob' },
{ slug: 'boob', name: 'boob' },
{ slug: 'nipple', name: 'nipple' },
{ slug: 'abdomen', name: 'abdomen' },
{ slug: 'lower-abdomen', name: 'lower abdomen' },
// back
{ slug: 'back', name: 'back' },
{ slug: 'upper-back', name: 'upper back' },
{ slug: 'middle-back', name: 'lower back' },
{ slug: 'lower-back', name: 'lower back' },
{ slug: 'spine', name: 'spine' },
// bottom
{ slug: 'butt', name: 'butt' },
{ slug: 'hip', name: 'hip' },
// genitals
{ slug: 'pubic-mound', name: 'pubic mound' },
{ slug: 'anus', name: 'anus' },
{ slug: 'vagina', name: 'vagina' },
{ slug: 'outer-labia', name: 'outer labia' },
{ slug: 'inner-labia', name: 'inner labia' },
{ slug: 'clitoris', name: 'clitoris' },
{ slug: 'penis', name: 'penis' },
{ slug: 'glans', name: 'glans' },
{ slug: 'foreskin', name: 'foreskin' },
{ slug: 'shaft', name: 'shaft' },
{ slug: 'scrotum', name: 'scrotum' },
// legs
{ slug: 'leg', name: 'leg' },
{ slug: 'groin', name: 'groin' },
{ slug: 'upper-leg', name: 'upper leg' },
{ slug: 'lower-leg', name: 'lower leg' },
{ slug: 'knee', name: 'knee' },
{ slug: 'inner-knee', name: 'inner knee' },
// feet
{ slug: 'inner-ankle', name: 'inner ankle' },
{ slug: 'outer-ankle', name: 'outer ankle' },
{ slug: 'foot', name: 'foot' },
{ slug: 'toes', name: 'toes' },
{ slug: 'big-toe', name: 'big toe' },
{ slug: 'index-toe', name: 'index toe' },
{ slug: 'middle-toe', name: 'middle toe' },
{ slug: 'fourth-toe', name: 'fourth toe' },
{ slug: 'little-toe', name: 'little toe' },
]))
.then(() => knex.schema.createTable('actors_tattoos', (table) => {
table.increments('id');
table.integer('actor_id', 12)
.notNullable()
.references('id')
.inTable('actors');
table.string('body_slug', 20)
.references('slug')
.inTable('body');
table.enum('side', ['left', 'right', 'center', 'both']);
table.string('description');
table.datetime('created_at')
.defaultTo(knex.fn.now());
}))
.then(() => knex.schema.createTable('actors_avatars', (table) => { .then(() => knex.schema.createTable('actors_avatars', (table) => {
table.integer('actor_id', 12) table.integer('actor_id', 12)
.notNullable() .notNullable()
@ -581,8 +726,8 @@ exports.up = knex => Promise.resolve()
COMMENT ON VIEW movie_actors IS E'@foreignKey (movie_id) references releases (id)\n@foreignKey (actor_id) references actors (id)'; COMMENT ON VIEW movie_actors IS E'@foreignKey (movie_id) references releases (id)\n@foreignKey (actor_id) references actors (id)';
COMMENT ON VIEW movie_tags IS E'@foreignKey (movie_id) references releases (id)\n@foreignKey (tag_id) references tags (id)'; COMMENT ON VIEW movie_tags IS E'@foreignKey (movie_id) references releases (id)\n@foreignKey (tag_id) references tags (id)';
COMMENT ON COLUMN actors.height IS E'@omit read,update,create,delete,all,many'; COMMENT ON COLUMN actors_profiles.height IS E'@omit read,update,create,delete,all,many';
COMMENT ON COLUMN actors.weight IS E'@omit read,update,create,delete,all,many'; COMMENT ON COLUMN actors_profiles.weight IS E'@omit read,update,create,delete,all,many';
`)); `));
exports.down = knex => knex.raw(` exports.down = knex => knex.raw(`
@ -599,10 +744,16 @@ exports.down = knex => knex.raw(`
DROP TABLE IF EXISTS releases_teasers CASCADE; DROP TABLE IF EXISTS releases_teasers CASCADE;
DROP TABLE IF EXISTS releases_tags CASCADE; DROP TABLE IF EXISTS releases_tags CASCADE;
DROP TABLE IF EXISTS releases_search CASCADE; DROP TABLE IF EXISTS releases_search CASCADE;
DROP TABLE IF EXISTS batches CASCADE; DROP TABLE IF EXISTS batches CASCADE;
DROP TABLE IF EXISTS actors_avatars CASCADE; DROP TABLE IF EXISTS actors_avatars CASCADE;
DROP TABLE IF EXISTS actors_photos CASCADE; DROP TABLE IF EXISTS actors_photos CASCADE;
DROP TABLE IF EXISTS actors_social CASCADE; DROP TABLE IF EXISTS actors_social CASCADE;
DROP TABLE IF EXISTS actors_profiles CASCADE;
DROP TABLE IF EXISTS actors_tattoos CASCADE;
DROP TABLE IF EXISTS body CASCADE;
DROP TABLE IF EXISTS sites_tags CASCADE; DROP TABLE IF EXISTS sites_tags CASCADE;
DROP TABLE IF EXISTS sites_social CASCADE; DROP TABLE IF EXISTS sites_social CASCADE;
DROP TABLE IF EXISTS networks_social CASCADE; DROP TABLE IF EXISTS networks_social CASCADE;

View File

@ -1,28 +1,75 @@
'use strict'; 'use strict';
const knex = require('./knex');
const slugify = require('./utils/slugify'); const slugify = require('./utils/slugify');
const capitalize = require('./utils/capitalize');
function toBaseActors(actorsOrNames) { function toBaseActors(actorsOrNames, release) {
return actorsOrNames.map((actorOrName) => { return actorsOrNames.map((actorOrName) => {
if (actorOrName.name) { if (actorOrName.name) {
return { return {
...actorOrName, ...actorOrName,
name: capitalize(actorOrName.name),
slug: slugify(actorOrName.name), slug: slugify(actorOrName.name),
networkId: release.site.network.id,
}; };
} }
return { return {
name: actorOrName, name: capitalize(actorOrName),
slug: slugify(actorOrName.name), slug: slugify(actorOrName),
networkId: release.site.network.id,
}; };
}); });
} }
async function associateActors(releases) { function curateActorEntry(baseActor) {
const rawActors = releases.map(release => release.actors).flat().filter(Boolean); const actorEntry = {
const baseActors = toBaseActors(rawActors); name: baseActor.name,
slug: baseActor.slug,
};
console.log(baseActors); if (baseActor.name.split(/\s+/).length === 1) {
// attach network ID for single names, to reduce mismatches
actorEntry.network_id = baseActor.networkId;
}
return actorEntry;
}
function curateActorEntries(baseActors) {
return baseActors.map(baseActor => curateActorEntry(baseActor));
}
async function getActors(baseActors) {
const existingActors = await knex('actors')
.whereIn('slug', baseActors.map(baseActor => baseActor.slug))
.orWhereIn('name', baseActors.map(baseActor => baseActor.slug));
if (existingActors.length === 0) {
// TODO: TESTING ONLY
await knex('actors').insert(curateActorEntries(baseActors.slice(0, 3)));
}
console.log(existingActors);
}
async function associateActors(releases) {
const baseActorsByReleaseId = releases.reduce((acc, release) => {
if (release.actors) {
acc[release.id] = toBaseActors(release.actors, release);
}
return acc;
}, {});
const baseActors = Object.values(baseActorsByReleaseId).flat();
const baseActorsBySlug = baseActors.reduce((acc, baseActor) => ({ ...acc, [baseActor.slug]: baseActor }), {});
const uniqueBaseActors = Object.values(baseActorsBySlug);
const actors = await getActors(uniqueBaseActors);
console.log(actors);
} }
module.exports = { module.exports = {

View File

@ -6,7 +6,7 @@ function capitalize(string, trim = true) {
} }
const capitalized = string const capitalized = string
.split(/\s/) .split(/\s+/)
.map(component => `${component.charAt(0).toUpperCase()}${component.slice(1)}`) .map(component => `${component.charAt(0).toUpperCase()}${component.slice(1)}`)
.join(' '); .join(' ');

View File

@ -11,14 +11,14 @@ const schemaExtender = makeExtendSchemaPlugin(_build => ({
IMPERIAL IMPERIAL
} }
extend type Actor { extend type ActorProfile {
age: Int @requires(columns: ["birthdate"]) age: Int @requires(columns: ["birthdate"])
height(units:Units): String @requires(columns: ["height"]) height(units:Units): String @requires(columns: ["height"])
weight(units:Units): String @requires(columns: ["weight"]) weight(units:Units): String @requires(columns: ["weight"])
} }
`, `,
resolvers: { resolvers: {
Actor: { ActorProfile: {
age(parent, _args, _context, _info) { age(parent, _args, _context, _info) {
if (!parent.birthdate) return null; if (!parent.birthdate) return null;