mirror of
https://github.com/KevinMidboe/seasoned.git
synced 2026-05-09 07:35:37 +00:00
Compare commits
1 Commits
feat/submi
...
feat/apple
| Author | SHA1 | Date | |
|---|---|---|---|
| 8110b9da69 |
350
docs/api/assets/anchor.js
Normal file
350
docs/api/assets/anchor.js
Normal file
@@ -0,0 +1,350 @@
|
|||||||
|
/*!
|
||||||
|
* AnchorJS - v4.0.0 - 2017-06-02
|
||||||
|
* https://github.com/bryanbraun/anchorjs
|
||||||
|
* Copyright (c) 2017 Bryan Braun; Licensed MIT
|
||||||
|
*/
|
||||||
|
/* eslint-env amd, node */
|
||||||
|
|
||||||
|
// https://github.com/umdjs/umd/blob/master/templates/returnExports.js
|
||||||
|
(function(root, factory) {
|
||||||
|
'use strict';
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as an anonymous module.
|
||||||
|
define([], factory);
|
||||||
|
} else if (typeof module === 'object' && module.exports) {
|
||||||
|
// Node. Does not work with strict CommonJS, but
|
||||||
|
// only CommonJS-like environments that support module.exports,
|
||||||
|
// like Node.
|
||||||
|
module.exports = factory();
|
||||||
|
} else {
|
||||||
|
// Browser globals (root is window)
|
||||||
|
root.AnchorJS = factory();
|
||||||
|
root.anchors = new root.AnchorJS();
|
||||||
|
}
|
||||||
|
})(this, function() {
|
||||||
|
'use strict';
|
||||||
|
function AnchorJS(options) {
|
||||||
|
this.options = options || {};
|
||||||
|
this.elements = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns options to the internal options object, and provides defaults.
|
||||||
|
* @param {Object} opts - Options object
|
||||||
|
*/
|
||||||
|
function _applyRemainingDefaultOptions(opts) {
|
||||||
|
opts.icon = opts.hasOwnProperty('icon') ? opts.icon : '\ue9cb'; // Accepts characters (and also URLs?), like '#', '¶', '❡', or '§'.
|
||||||
|
opts.visible = opts.hasOwnProperty('visible') ? opts.visible : 'hover'; // Also accepts 'always' & 'touch'
|
||||||
|
opts.placement = opts.hasOwnProperty('placement')
|
||||||
|
? opts.placement
|
||||||
|
: 'right'; // Also accepts 'left'
|
||||||
|
opts.class = opts.hasOwnProperty('class') ? opts.class : ''; // Accepts any class name.
|
||||||
|
// Using Math.floor here will ensure the value is Number-cast and an integer.
|
||||||
|
opts.truncate = opts.hasOwnProperty('truncate')
|
||||||
|
? Math.floor(opts.truncate)
|
||||||
|
: 64; // Accepts any value that can be typecast to a number.
|
||||||
|
}
|
||||||
|
|
||||||
|
_applyRemainingDefaultOptions(this.options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks to see if this device supports touch. Uses criteria pulled from Modernizr:
|
||||||
|
* https://github.com/Modernizr/Modernizr/blob/da22eb27631fc4957f67607fe6042e85c0a84656/feature-detects/touchevents.js#L40
|
||||||
|
* @returns {Boolean} - true if the current device supports touch.
|
||||||
|
*/
|
||||||
|
this.isTouchDevice = function() {
|
||||||
|
return !!(
|
||||||
|
'ontouchstart' in window ||
|
||||||
|
(window.DocumentTouch && document instanceof DocumentTouch)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add anchor links to page elements.
|
||||||
|
* @param {String|Array|Nodelist} selector - A CSS selector for targeting the elements you wish to add anchor links
|
||||||
|
* to. Also accepts an array or nodeList containing the relavant elements.
|
||||||
|
* @returns {this} - The AnchorJS object
|
||||||
|
*/
|
||||||
|
this.add = function(selector) {
|
||||||
|
var elements,
|
||||||
|
elsWithIds,
|
||||||
|
idList,
|
||||||
|
elementID,
|
||||||
|
i,
|
||||||
|
index,
|
||||||
|
count,
|
||||||
|
tidyText,
|
||||||
|
newTidyText,
|
||||||
|
readableID,
|
||||||
|
anchor,
|
||||||
|
visibleOptionToUse,
|
||||||
|
indexesToDrop = [];
|
||||||
|
|
||||||
|
// We reapply options here because somebody may have overwritten the default options object when setting options.
|
||||||
|
// For example, this overwrites all options but visible:
|
||||||
|
//
|
||||||
|
// anchors.options = { visible: 'always'; }
|
||||||
|
_applyRemainingDefaultOptions(this.options);
|
||||||
|
|
||||||
|
visibleOptionToUse = this.options.visible;
|
||||||
|
if (visibleOptionToUse === 'touch') {
|
||||||
|
visibleOptionToUse = this.isTouchDevice() ? 'always' : 'hover';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provide a sensible default selector, if none is given.
|
||||||
|
if (!selector) {
|
||||||
|
selector = 'h2, h3, h4, h5, h6';
|
||||||
|
}
|
||||||
|
|
||||||
|
elements = _getElements(selector);
|
||||||
|
|
||||||
|
if (elements.length === 0) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
_addBaselineStyles();
|
||||||
|
|
||||||
|
// We produce a list of existing IDs so we don't generate a duplicate.
|
||||||
|
elsWithIds = document.querySelectorAll('[id]');
|
||||||
|
idList = [].map.call(elsWithIds, function assign(el) {
|
||||||
|
return el.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (i = 0; i < elements.length; i++) {
|
||||||
|
if (this.hasAnchorJSLink(elements[i])) {
|
||||||
|
indexesToDrop.push(i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elements[i].hasAttribute('id')) {
|
||||||
|
elementID = elements[i].getAttribute('id');
|
||||||
|
} else if (elements[i].hasAttribute('data-anchor-id')) {
|
||||||
|
elementID = elements[i].getAttribute('data-anchor-id');
|
||||||
|
} else {
|
||||||
|
tidyText = this.urlify(elements[i].textContent);
|
||||||
|
|
||||||
|
// Compare our generated ID to existing IDs (and increment it if needed)
|
||||||
|
// before we add it to the page.
|
||||||
|
newTidyText = tidyText;
|
||||||
|
count = 0;
|
||||||
|
do {
|
||||||
|
if (index !== undefined) {
|
||||||
|
newTidyText = tidyText + '-' + count;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = idList.indexOf(newTidyText);
|
||||||
|
count += 1;
|
||||||
|
} while (index !== -1);
|
||||||
|
index = undefined;
|
||||||
|
idList.push(newTidyText);
|
||||||
|
|
||||||
|
elements[i].setAttribute('id', newTidyText);
|
||||||
|
elementID = newTidyText;
|
||||||
|
}
|
||||||
|
|
||||||
|
readableID = elementID.replace(/-/g, ' ');
|
||||||
|
|
||||||
|
// The following code builds the following DOM structure in a more effiecient (albeit opaque) way.
|
||||||
|
// '<a class="anchorjs-link ' + this.options.class + '" href="#' + elementID + '" aria-label="Anchor link for: ' + readableID + '" data-anchorjs-icon="' + this.options.icon + '"></a>';
|
||||||
|
anchor = document.createElement('a');
|
||||||
|
anchor.className = 'anchorjs-link ' + this.options.class;
|
||||||
|
anchor.href = '#' + elementID;
|
||||||
|
anchor.setAttribute('aria-label', 'Anchor link for: ' + readableID);
|
||||||
|
anchor.setAttribute('data-anchorjs-icon', this.options.icon);
|
||||||
|
|
||||||
|
if (visibleOptionToUse === 'always') {
|
||||||
|
anchor.style.opacity = '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.options.icon === '\ue9cb') {
|
||||||
|
anchor.style.font = '1em/1 anchorjs-icons';
|
||||||
|
|
||||||
|
// We set lineHeight = 1 here because the `anchorjs-icons` font family could otherwise affect the
|
||||||
|
// height of the heading. This isn't the case for icons with `placement: left`, so we restore
|
||||||
|
// line-height: inherit in that case, ensuring they remain positioned correctly. For more info,
|
||||||
|
// see https://github.com/bryanbraun/anchorjs/issues/39.
|
||||||
|
if (this.options.placement === 'left') {
|
||||||
|
anchor.style.lineHeight = 'inherit';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.options.placement === 'left') {
|
||||||
|
anchor.style.position = 'absolute';
|
||||||
|
anchor.style.marginLeft = '-1em';
|
||||||
|
anchor.style.paddingRight = '0.5em';
|
||||||
|
elements[i].insertBefore(anchor, elements[i].firstChild);
|
||||||
|
} else {
|
||||||
|
// if the option provided is `right` (or anything else).
|
||||||
|
anchor.style.paddingLeft = '0.375em';
|
||||||
|
elements[i].appendChild(anchor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < indexesToDrop.length; i++) {
|
||||||
|
elements.splice(indexesToDrop[i] - i, 1);
|
||||||
|
}
|
||||||
|
this.elements = this.elements.concat(elements);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all anchorjs-links from elements targed by the selector.
|
||||||
|
* @param {String|Array|Nodelist} selector - A CSS selector string targeting elements with anchor links,
|
||||||
|
* OR a nodeList / array containing the DOM elements.
|
||||||
|
* @returns {this} - The AnchorJS object
|
||||||
|
*/
|
||||||
|
this.remove = function(selector) {
|
||||||
|
var index,
|
||||||
|
domAnchor,
|
||||||
|
elements = _getElements(selector);
|
||||||
|
|
||||||
|
for (var i = 0; i < elements.length; i++) {
|
||||||
|
domAnchor = elements[i].querySelector('.anchorjs-link');
|
||||||
|
if (domAnchor) {
|
||||||
|
// Drop the element from our main list, if it's in there.
|
||||||
|
index = this.elements.indexOf(elements[i]);
|
||||||
|
if (index !== -1) {
|
||||||
|
this.elements.splice(index, 1);
|
||||||
|
}
|
||||||
|
// Remove the anchor from the DOM.
|
||||||
|
elements[i].removeChild(domAnchor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all anchorjs links. Mostly used for tests.
|
||||||
|
*/
|
||||||
|
this.removeAll = function() {
|
||||||
|
this.remove(this.elements);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Urlify - Refine text so it makes a good ID.
|
||||||
|
*
|
||||||
|
* To do this, we remove apostrophes, replace nonsafe characters with hyphens,
|
||||||
|
* remove extra hyphens, truncate, trim hyphens, and make lowercase.
|
||||||
|
*
|
||||||
|
* @param {String} text - Any text. Usually pulled from the webpage element we are linking to.
|
||||||
|
* @returns {String} - hyphen-delimited text for use in IDs and URLs.
|
||||||
|
*/
|
||||||
|
this.urlify = function(text) {
|
||||||
|
// Regex for finding the nonsafe URL characters (many need escaping): & +$,:;=?@"#{}|^~[`%!'<>]./()*\
|
||||||
|
var nonsafeChars = /[& +$,:;=?@"#{}|^~[`%!'<>\]\.\/\(\)\*\\]/g,
|
||||||
|
urlText;
|
||||||
|
|
||||||
|
// The reason we include this _applyRemainingDefaultOptions is so urlify can be called independently,
|
||||||
|
// even after setting options. This can be useful for tests or other applications.
|
||||||
|
if (!this.options.truncate) {
|
||||||
|
_applyRemainingDefaultOptions(this.options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: we trim hyphens after truncating because truncating can cause dangling hyphens.
|
||||||
|
// Example string: // " ⚡⚡ Don't forget: URL fragments should be i18n-friendly, hyphenated, short, and clean."
|
||||||
|
urlText = text
|
||||||
|
.trim() // "⚡⚡ Don't forget: URL fragments should be i18n-friendly, hyphenated, short, and clean."
|
||||||
|
.replace(/\'/gi, '') // "⚡⚡ Dont forget: URL fragments should be i18n-friendly, hyphenated, short, and clean."
|
||||||
|
.replace(nonsafeChars, '-') // "⚡⚡-Dont-forget--URL-fragments-should-be-i18n-friendly--hyphenated--short--and-clean-"
|
||||||
|
.replace(/-{2,}/g, '-') // "⚡⚡-Dont-forget-URL-fragments-should-be-i18n-friendly-hyphenated-short-and-clean-"
|
||||||
|
.substring(0, this.options.truncate) // "⚡⚡-Dont-forget-URL-fragments-should-be-i18n-friendly-hyphenated-"
|
||||||
|
.replace(/^-+|-+$/gm, '') // "⚡⚡-Dont-forget-URL-fragments-should-be-i18n-friendly-hyphenated"
|
||||||
|
.toLowerCase(); // "⚡⚡-dont-forget-url-fragments-should-be-i18n-friendly-hyphenated"
|
||||||
|
|
||||||
|
return urlText;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if this element already has an AnchorJS link on it.
|
||||||
|
* Uses this technique: http://stackoverflow.com/a/5898748/1154642
|
||||||
|
* @param {HTMLElemnt} el - a DOM node
|
||||||
|
* @returns {Boolean} true/false
|
||||||
|
*/
|
||||||
|
this.hasAnchorJSLink = function(el) {
|
||||||
|
var hasLeftAnchor =
|
||||||
|
el.firstChild &&
|
||||||
|
(' ' + el.firstChild.className + ' ').indexOf(' anchorjs-link ') > -1,
|
||||||
|
hasRightAnchor =
|
||||||
|
el.lastChild &&
|
||||||
|
(' ' + el.lastChild.className + ' ').indexOf(' anchorjs-link ') > -1;
|
||||||
|
|
||||||
|
return hasLeftAnchor || hasRightAnchor || false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns a selector, nodeList, or array of elements into an array of elements (so we can use array methods).
|
||||||
|
* It also throws errors on any other inputs. Used to handle inputs to .add and .remove.
|
||||||
|
* @param {String|Array|Nodelist} input - A CSS selector string targeting elements with anchor links,
|
||||||
|
* OR a nodeList / array containing the DOM elements.
|
||||||
|
* @returns {Array} - An array containing the elements we want.
|
||||||
|
*/
|
||||||
|
function _getElements(input) {
|
||||||
|
var elements;
|
||||||
|
if (typeof input === 'string' || input instanceof String) {
|
||||||
|
// See https://davidwalsh.name/nodelist-array for the technique transforming nodeList -> Array.
|
||||||
|
elements = [].slice.call(document.querySelectorAll(input));
|
||||||
|
// I checked the 'input instanceof NodeList' test in IE9 and modern browsers and it worked for me.
|
||||||
|
} else if (Array.isArray(input) || input instanceof NodeList) {
|
||||||
|
elements = [].slice.call(input);
|
||||||
|
} else {
|
||||||
|
throw new Error('The selector provided to AnchorJS was invalid.');
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _addBaselineStyles
|
||||||
|
* Adds baseline styles to the page, used by all AnchorJS links irregardless of configuration.
|
||||||
|
*/
|
||||||
|
function _addBaselineStyles() {
|
||||||
|
// We don't want to add global baseline styles if they've been added before.
|
||||||
|
if (document.head.querySelector('style.anchorjs') !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var style = document.createElement('style'),
|
||||||
|
linkRule =
|
||||||
|
' .anchorjs-link {' +
|
||||||
|
' opacity: 0;' +
|
||||||
|
' text-decoration: none;' +
|
||||||
|
' -webkit-font-smoothing: antialiased;' +
|
||||||
|
' -moz-osx-font-smoothing: grayscale;' +
|
||||||
|
' }',
|
||||||
|
hoverRule =
|
||||||
|
' *:hover > .anchorjs-link,' +
|
||||||
|
' .anchorjs-link:focus {' +
|
||||||
|
' opacity: 1;' +
|
||||||
|
' }',
|
||||||
|
anchorjsLinkFontFace =
|
||||||
|
' @font-face {' +
|
||||||
|
' font-family: "anchorjs-icons";' + // Icon from icomoon; 10px wide & 10px tall; 2 empty below & 4 above
|
||||||
|
' src: url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype");' +
|
||||||
|
' }',
|
||||||
|
pseudoElContent =
|
||||||
|
' [data-anchorjs-icon]::after {' +
|
||||||
|
' content: attr(data-anchorjs-icon);' +
|
||||||
|
' }',
|
||||||
|
firstStyleEl;
|
||||||
|
|
||||||
|
style.className = 'anchorjs';
|
||||||
|
style.appendChild(document.createTextNode('')); // Necessary for Webkit.
|
||||||
|
|
||||||
|
// We place it in the head with the other style tags, if possible, so as to
|
||||||
|
// not look out of place. We insert before the others so these styles can be
|
||||||
|
// overridden if necessary.
|
||||||
|
firstStyleEl = document.head.querySelector('[rel="stylesheet"], style');
|
||||||
|
if (firstStyleEl === undefined) {
|
||||||
|
document.head.appendChild(style);
|
||||||
|
} else {
|
||||||
|
document.head.insertBefore(style, firstStyleEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
style.sheet.insertRule(linkRule, style.sheet.cssRules.length);
|
||||||
|
style.sheet.insertRule(hoverRule, style.sheet.cssRules.length);
|
||||||
|
style.sheet.insertRule(pseudoElContent, style.sheet.cssRules.length);
|
||||||
|
style.sheet.insertRule(anchorjsLinkFontFace, style.sheet.cssRules.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return AnchorJS;
|
||||||
|
});
|
||||||
12
docs/api/assets/bass-addons.css
Normal file
12
docs/api/assets/bass-addons.css
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.input {
|
||||||
|
font-family: inherit;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 2rem;
|
||||||
|
padding: .5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
font-size: .875rem;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
544
docs/api/assets/bass.css
Normal file
544
docs/api/assets/bass.css
Normal file
@@ -0,0 +1,544 @@
|
|||||||
|
/*! Basscss | http://basscss.com | MIT License */
|
||||||
|
|
||||||
|
.h1{ font-size: 2rem }
|
||||||
|
.h2{ font-size: 1.5rem }
|
||||||
|
.h3{ font-size: 1.25rem }
|
||||||
|
.h4{ font-size: 1rem }
|
||||||
|
.h5{ font-size: .875rem }
|
||||||
|
.h6{ font-size: .75rem }
|
||||||
|
|
||||||
|
.font-family-inherit{ font-family:inherit }
|
||||||
|
.font-size-inherit{ font-size:inherit }
|
||||||
|
.text-decoration-none{ text-decoration:none }
|
||||||
|
|
||||||
|
.bold{ font-weight: bold; font-weight: bold }
|
||||||
|
.regular{ font-weight:normal }
|
||||||
|
.italic{ font-style:italic }
|
||||||
|
.caps{ text-transform:uppercase; letter-spacing: .2em; }
|
||||||
|
|
||||||
|
.left-align{ text-align:left }
|
||||||
|
.center{ text-align:center }
|
||||||
|
.right-align{ text-align:right }
|
||||||
|
.justify{ text-align:justify }
|
||||||
|
|
||||||
|
.nowrap{ white-space:nowrap }
|
||||||
|
.break-word{ word-wrap:break-word }
|
||||||
|
|
||||||
|
.line-height-1{ line-height: 1 }
|
||||||
|
.line-height-2{ line-height: 1.125 }
|
||||||
|
.line-height-3{ line-height: 1.25 }
|
||||||
|
.line-height-4{ line-height: 1.5 }
|
||||||
|
|
||||||
|
.list-style-none{ list-style:none }
|
||||||
|
.underline{ text-decoration:underline }
|
||||||
|
|
||||||
|
.truncate{
|
||||||
|
max-width:100%;
|
||||||
|
overflow:hidden;
|
||||||
|
text-overflow:ellipsis;
|
||||||
|
white-space:nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-reset{
|
||||||
|
list-style:none;
|
||||||
|
padding-left:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline{ display:inline }
|
||||||
|
.block{ display:block }
|
||||||
|
.inline-block{ display:inline-block }
|
||||||
|
.table{ display:table }
|
||||||
|
.table-cell{ display:table-cell }
|
||||||
|
|
||||||
|
.overflow-hidden{ overflow:hidden }
|
||||||
|
.overflow-scroll{ overflow:scroll }
|
||||||
|
.overflow-auto{ overflow:auto }
|
||||||
|
|
||||||
|
.clearfix:before,
|
||||||
|
.clearfix:after{
|
||||||
|
content:" ";
|
||||||
|
display:table
|
||||||
|
}
|
||||||
|
.clearfix:after{ clear:both }
|
||||||
|
|
||||||
|
.left{ float:left }
|
||||||
|
.right{ float:right }
|
||||||
|
|
||||||
|
.fit{ max-width:100% }
|
||||||
|
|
||||||
|
.max-width-1{ max-width: 24rem }
|
||||||
|
.max-width-2{ max-width: 32rem }
|
||||||
|
.max-width-3{ max-width: 48rem }
|
||||||
|
.max-width-4{ max-width: 64rem }
|
||||||
|
|
||||||
|
.border-box{ box-sizing:border-box }
|
||||||
|
|
||||||
|
.align-baseline{ vertical-align:baseline }
|
||||||
|
.align-top{ vertical-align:top }
|
||||||
|
.align-middle{ vertical-align:middle }
|
||||||
|
.align-bottom{ vertical-align:bottom }
|
||||||
|
|
||||||
|
.m0{ margin:0 }
|
||||||
|
.mt0{ margin-top:0 }
|
||||||
|
.mr0{ margin-right:0 }
|
||||||
|
.mb0{ margin-bottom:0 }
|
||||||
|
.ml0{ margin-left:0 }
|
||||||
|
.mx0{ margin-left:0; margin-right:0 }
|
||||||
|
.my0{ margin-top:0; margin-bottom:0 }
|
||||||
|
|
||||||
|
.m1{ margin: .5rem }
|
||||||
|
.mt1{ margin-top: .5rem }
|
||||||
|
.mr1{ margin-right: .5rem }
|
||||||
|
.mb1{ margin-bottom: .5rem }
|
||||||
|
.ml1{ margin-left: .5rem }
|
||||||
|
.mx1{ margin-left: .5rem; margin-right: .5rem }
|
||||||
|
.my1{ margin-top: .5rem; margin-bottom: .5rem }
|
||||||
|
|
||||||
|
.m2{ margin: 1rem }
|
||||||
|
.mt2{ margin-top: 1rem }
|
||||||
|
.mr2{ margin-right: 1rem }
|
||||||
|
.mb2{ margin-bottom: 1rem }
|
||||||
|
.ml2{ margin-left: 1rem }
|
||||||
|
.mx2{ margin-left: 1rem; margin-right: 1rem }
|
||||||
|
.my2{ margin-top: 1rem; margin-bottom: 1rem }
|
||||||
|
|
||||||
|
.m3{ margin: 2rem }
|
||||||
|
.mt3{ margin-top: 2rem }
|
||||||
|
.mr3{ margin-right: 2rem }
|
||||||
|
.mb3{ margin-bottom: 2rem }
|
||||||
|
.ml3{ margin-left: 2rem }
|
||||||
|
.mx3{ margin-left: 2rem; margin-right: 2rem }
|
||||||
|
.my3{ margin-top: 2rem; margin-bottom: 2rem }
|
||||||
|
|
||||||
|
.m4{ margin: 4rem }
|
||||||
|
.mt4{ margin-top: 4rem }
|
||||||
|
.mr4{ margin-right: 4rem }
|
||||||
|
.mb4{ margin-bottom: 4rem }
|
||||||
|
.ml4{ margin-left: 4rem }
|
||||||
|
.mx4{ margin-left: 4rem; margin-right: 4rem }
|
||||||
|
.my4{ margin-top: 4rem; margin-bottom: 4rem }
|
||||||
|
|
||||||
|
.mxn1{ margin-left: -.5rem; margin-right: -.5rem; }
|
||||||
|
.mxn2{ margin-left: -1rem; margin-right: -1rem; }
|
||||||
|
.mxn3{ margin-left: -2rem; margin-right: -2rem; }
|
||||||
|
.mxn4{ margin-left: -4rem; margin-right: -4rem; }
|
||||||
|
|
||||||
|
.ml-auto{ margin-left:auto }
|
||||||
|
.mr-auto{ margin-right:auto }
|
||||||
|
.mx-auto{ margin-left:auto; margin-right:auto; }
|
||||||
|
|
||||||
|
.p0{ padding:0 }
|
||||||
|
.pt0{ padding-top:0 }
|
||||||
|
.pr0{ padding-right:0 }
|
||||||
|
.pb0{ padding-bottom:0 }
|
||||||
|
.pl0{ padding-left:0 }
|
||||||
|
.px0{ padding-left:0; padding-right:0 }
|
||||||
|
.py0{ padding-top:0; padding-bottom:0 }
|
||||||
|
|
||||||
|
.p1{ padding: .5rem }
|
||||||
|
.pt1{ padding-top: .5rem }
|
||||||
|
.pr1{ padding-right: .5rem }
|
||||||
|
.pb1{ padding-bottom: .5rem }
|
||||||
|
.pl1{ padding-left: .5rem }
|
||||||
|
.py1{ padding-top: .5rem; padding-bottom: .5rem }
|
||||||
|
.px1{ padding-left: .5rem; padding-right: .5rem }
|
||||||
|
|
||||||
|
.p2{ padding: 1rem }
|
||||||
|
.pt2{ padding-top: 1rem }
|
||||||
|
.pr2{ padding-right: 1rem }
|
||||||
|
.pb2{ padding-bottom: 1rem }
|
||||||
|
.pl2{ padding-left: 1rem }
|
||||||
|
.py2{ padding-top: 1rem; padding-bottom: 1rem }
|
||||||
|
.px2{ padding-left: 1rem; padding-right: 1rem }
|
||||||
|
|
||||||
|
.p3{ padding: 2rem }
|
||||||
|
.pt3{ padding-top: 2rem }
|
||||||
|
.pr3{ padding-right: 2rem }
|
||||||
|
.pb3{ padding-bottom: 2rem }
|
||||||
|
.pl3{ padding-left: 2rem }
|
||||||
|
.py3{ padding-top: 2rem; padding-bottom: 2rem }
|
||||||
|
.px3{ padding-left: 2rem; padding-right: 2rem }
|
||||||
|
|
||||||
|
.p4{ padding: 4rem }
|
||||||
|
.pt4{ padding-top: 4rem }
|
||||||
|
.pr4{ padding-right: 4rem }
|
||||||
|
.pb4{ padding-bottom: 4rem }
|
||||||
|
.pl4{ padding-left: 4rem }
|
||||||
|
.py4{ padding-top: 4rem; padding-bottom: 4rem }
|
||||||
|
.px4{ padding-left: 4rem; padding-right: 4rem }
|
||||||
|
|
||||||
|
.col{
|
||||||
|
float:left;
|
||||||
|
box-sizing:border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-right{
|
||||||
|
float:right;
|
||||||
|
box-sizing:border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-1{
|
||||||
|
width:8.33333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-2{
|
||||||
|
width:16.66667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-3{
|
||||||
|
width:25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-4{
|
||||||
|
width:33.33333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-5{
|
||||||
|
width:41.66667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-6{
|
||||||
|
width:50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-7{
|
||||||
|
width:58.33333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-8{
|
||||||
|
width:66.66667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-9{
|
||||||
|
width:75%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-10{
|
||||||
|
width:83.33333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-11{
|
||||||
|
width:91.66667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-12{
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
@media (min-width: 40em){
|
||||||
|
|
||||||
|
.sm-col{
|
||||||
|
float:left;
|
||||||
|
box-sizing:border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm-col-right{
|
||||||
|
float:right;
|
||||||
|
box-sizing:border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm-col-1{
|
||||||
|
width:8.33333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm-col-2{
|
||||||
|
width:16.66667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm-col-3{
|
||||||
|
width:25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm-col-4{
|
||||||
|
width:33.33333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm-col-5{
|
||||||
|
width:41.66667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm-col-6{
|
||||||
|
width:50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm-col-7{
|
||||||
|
width:58.33333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm-col-8{
|
||||||
|
width:66.66667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm-col-9{
|
||||||
|
width:75%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm-col-10{
|
||||||
|
width:83.33333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm-col-11{
|
||||||
|
width:91.66667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm-col-12{
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@media (min-width: 52em){
|
||||||
|
|
||||||
|
.md-col{
|
||||||
|
float:left;
|
||||||
|
box-sizing:border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-col-right{
|
||||||
|
float:right;
|
||||||
|
box-sizing:border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-col-1{
|
||||||
|
width:8.33333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-col-2{
|
||||||
|
width:16.66667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-col-3{
|
||||||
|
width:25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-col-4{
|
||||||
|
width:33.33333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-col-5{
|
||||||
|
width:41.66667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-col-6{
|
||||||
|
width:50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-col-7{
|
||||||
|
width:58.33333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-col-8{
|
||||||
|
width:66.66667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-col-9{
|
||||||
|
width:75%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-col-10{
|
||||||
|
width:83.33333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-col-11{
|
||||||
|
width:91.66667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-col-12{
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@media (min-width: 64em){
|
||||||
|
|
||||||
|
.lg-col{
|
||||||
|
float:left;
|
||||||
|
box-sizing:border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg-col-right{
|
||||||
|
float:right;
|
||||||
|
box-sizing:border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg-col-1{
|
||||||
|
width:8.33333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg-col-2{
|
||||||
|
width:16.66667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg-col-3{
|
||||||
|
width:25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg-col-4{
|
||||||
|
width:33.33333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg-col-5{
|
||||||
|
width:41.66667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg-col-6{
|
||||||
|
width:50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg-col-7{
|
||||||
|
width:58.33333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg-col-8{
|
||||||
|
width:66.66667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg-col-9{
|
||||||
|
width:75%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg-col-10{
|
||||||
|
width:83.33333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg-col-11{
|
||||||
|
width:91.66667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg-col-12{
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex }
|
||||||
|
|
||||||
|
@media (min-width: 40em){
|
||||||
|
.sm-flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 52em){
|
||||||
|
.md-flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 64em){
|
||||||
|
.lg-flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex }
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-column{ -webkit-box-orient:vertical; -webkit-box-direction:normal; -webkit-flex-direction:column; -ms-flex-direction:column; flex-direction:column }
|
||||||
|
.flex-wrap{ -webkit-flex-wrap:wrap; -ms-flex-wrap:wrap; flex-wrap:wrap }
|
||||||
|
|
||||||
|
.items-start{ -webkit-box-align:start; -webkit-align-items:flex-start; -ms-flex-align:start; -ms-grid-row-align:flex-start; align-items:flex-start }
|
||||||
|
.items-end{ -webkit-box-align:end; -webkit-align-items:flex-end; -ms-flex-align:end; -ms-grid-row-align:flex-end; align-items:flex-end }
|
||||||
|
.items-center{ -webkit-box-align:center; -webkit-align-items:center; -ms-flex-align:center; -ms-grid-row-align:center; align-items:center }
|
||||||
|
.items-baseline{ -webkit-box-align:baseline; -webkit-align-items:baseline; -ms-flex-align:baseline; -ms-grid-row-align:baseline; align-items:baseline }
|
||||||
|
.items-stretch{ -webkit-box-align:stretch; -webkit-align-items:stretch; -ms-flex-align:stretch; -ms-grid-row-align:stretch; align-items:stretch }
|
||||||
|
|
||||||
|
.self-start{ -webkit-align-self:flex-start; -ms-flex-item-align:start; align-self:flex-start }
|
||||||
|
.self-end{ -webkit-align-self:flex-end; -ms-flex-item-align:end; align-self:flex-end }
|
||||||
|
.self-center{ -webkit-align-self:center; -ms-flex-item-align:center; align-self:center }
|
||||||
|
.self-baseline{ -webkit-align-self:baseline; -ms-flex-item-align:baseline; align-self:baseline }
|
||||||
|
.self-stretch{ -webkit-align-self:stretch; -ms-flex-item-align:stretch; align-self:stretch }
|
||||||
|
|
||||||
|
.justify-start{ -webkit-box-pack:start; -webkit-justify-content:flex-start; -ms-flex-pack:start; justify-content:flex-start }
|
||||||
|
.justify-end{ -webkit-box-pack:end; -webkit-justify-content:flex-end; -ms-flex-pack:end; justify-content:flex-end }
|
||||||
|
.justify-center{ -webkit-box-pack:center; -webkit-justify-content:center; -ms-flex-pack:center; justify-content:center }
|
||||||
|
.justify-between{ -webkit-box-pack:justify; -webkit-justify-content:space-between; -ms-flex-pack:justify; justify-content:space-between }
|
||||||
|
.justify-around{ -webkit-justify-content:space-around; -ms-flex-pack:distribute; justify-content:space-around }
|
||||||
|
|
||||||
|
.content-start{ -webkit-align-content:flex-start; -ms-flex-line-pack:start; align-content:flex-start }
|
||||||
|
.content-end{ -webkit-align-content:flex-end; -ms-flex-line-pack:end; align-content:flex-end }
|
||||||
|
.content-center{ -webkit-align-content:center; -ms-flex-line-pack:center; align-content:center }
|
||||||
|
.content-between{ -webkit-align-content:space-between; -ms-flex-line-pack:justify; align-content:space-between }
|
||||||
|
.content-around{ -webkit-align-content:space-around; -ms-flex-line-pack:distribute; align-content:space-around }
|
||||||
|
.content-stretch{ -webkit-align-content:stretch; -ms-flex-line-pack:stretch; align-content:stretch }
|
||||||
|
.flex-auto{
|
||||||
|
-webkit-box-flex:1;
|
||||||
|
-webkit-flex:1 1 auto;
|
||||||
|
-ms-flex:1 1 auto;
|
||||||
|
flex:1 1 auto;
|
||||||
|
min-width:0;
|
||||||
|
min-height:0;
|
||||||
|
}
|
||||||
|
.flex-none{ -webkit-box-flex:0; -webkit-flex:none; -ms-flex:none; flex:none }
|
||||||
|
.fs0{ flex-shrink: 0 }
|
||||||
|
|
||||||
|
.order-0{ -webkit-box-ordinal-group:1; -webkit-order:0; -ms-flex-order:0; order:0 }
|
||||||
|
.order-1{ -webkit-box-ordinal-group:2; -webkit-order:1; -ms-flex-order:1; order:1 }
|
||||||
|
.order-2{ -webkit-box-ordinal-group:3; -webkit-order:2; -ms-flex-order:2; order:2 }
|
||||||
|
.order-3{ -webkit-box-ordinal-group:4; -webkit-order:3; -ms-flex-order:3; order:3 }
|
||||||
|
.order-last{ -webkit-box-ordinal-group:100000; -webkit-order:99999; -ms-flex-order:99999; order:99999 }
|
||||||
|
|
||||||
|
.relative{ position:relative }
|
||||||
|
.absolute{ position:absolute }
|
||||||
|
.fixed{ position:fixed }
|
||||||
|
|
||||||
|
.top-0{ top:0 }
|
||||||
|
.right-0{ right:0 }
|
||||||
|
.bottom-0{ bottom:0 }
|
||||||
|
.left-0{ left:0 }
|
||||||
|
|
||||||
|
.z1{ z-index: 1 }
|
||||||
|
.z2{ z-index: 2 }
|
||||||
|
.z3{ z-index: 3 }
|
||||||
|
.z4{ z-index: 4 }
|
||||||
|
|
||||||
|
.border{
|
||||||
|
border-style:solid;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-top{
|
||||||
|
border-top-style:solid;
|
||||||
|
border-top-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-right{
|
||||||
|
border-right-style:solid;
|
||||||
|
border-right-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-bottom{
|
||||||
|
border-bottom-style:solid;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-left{
|
||||||
|
border-left-style:solid;
|
||||||
|
border-left-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-none{ border:0 }
|
||||||
|
|
||||||
|
.rounded{ border-radius: 3px }
|
||||||
|
.circle{ border-radius:50% }
|
||||||
|
|
||||||
|
.rounded-top{ border-radius: 3px 3px 0 0 }
|
||||||
|
.rounded-right{ border-radius: 0 3px 3px 0 }
|
||||||
|
.rounded-bottom{ border-radius: 0 0 3px 3px }
|
||||||
|
.rounded-left{ border-radius: 3px 0 0 3px }
|
||||||
|
|
||||||
|
.not-rounded{ border-radius:0 }
|
||||||
|
|
||||||
|
.hide{
|
||||||
|
position:absolute !important;
|
||||||
|
height:1px;
|
||||||
|
width:1px;
|
||||||
|
overflow:hidden;
|
||||||
|
clip:rect(1px, 1px, 1px, 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 40em){
|
||||||
|
.xs-hide{ display:none !important }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 40em) and (max-width: 52em){
|
||||||
|
.sm-hide{ display:none !important }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 52em) and (max-width: 64em){
|
||||||
|
.md-hide{ display:none !important }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 64em){
|
||||||
|
.lg-hide{ display:none !important }
|
||||||
|
}
|
||||||
|
|
||||||
|
.display-none{ display:none !important }
|
||||||
|
|
||||||
BIN
docs/api/assets/fonts/EOT/SourceCodePro-Bold.eot
Executable file
BIN
docs/api/assets/fonts/EOT/SourceCodePro-Bold.eot
Executable file
Binary file not shown.
BIN
docs/api/assets/fonts/EOT/SourceCodePro-Regular.eot
Executable file
BIN
docs/api/assets/fonts/EOT/SourceCodePro-Regular.eot
Executable file
Binary file not shown.
93
docs/api/assets/fonts/LICENSE.txt
Executable file
93
docs/api/assets/fonts/LICENSE.txt
Executable file
@@ -0,0 +1,93 @@
|
|||||||
|
Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
|
||||||
|
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
BIN
docs/api/assets/fonts/OTF/SourceCodePro-Bold.otf
Executable file
BIN
docs/api/assets/fonts/OTF/SourceCodePro-Bold.otf
Executable file
Binary file not shown.
BIN
docs/api/assets/fonts/OTF/SourceCodePro-Regular.otf
Executable file
BIN
docs/api/assets/fonts/OTF/SourceCodePro-Regular.otf
Executable file
Binary file not shown.
BIN
docs/api/assets/fonts/TTF/SourceCodePro-Bold.ttf
Executable file
BIN
docs/api/assets/fonts/TTF/SourceCodePro-Bold.ttf
Executable file
Binary file not shown.
BIN
docs/api/assets/fonts/TTF/SourceCodePro-Regular.ttf
Executable file
BIN
docs/api/assets/fonts/TTF/SourceCodePro-Regular.ttf
Executable file
Binary file not shown.
BIN
docs/api/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff
Executable file
BIN
docs/api/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff
Executable file
Binary file not shown.
BIN
docs/api/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff
Executable file
BIN
docs/api/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff
Executable file
Binary file not shown.
BIN
docs/api/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff
Executable file
BIN
docs/api/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff
Executable file
Binary file not shown.
BIN
docs/api/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff
Executable file
BIN
docs/api/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff
Executable file
Binary file not shown.
BIN
docs/api/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2
Executable file
BIN
docs/api/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2
Executable file
Binary file not shown.
BIN
docs/api/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2
Executable file
BIN
docs/api/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2
Executable file
Binary file not shown.
BIN
docs/api/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2
Executable file
BIN
docs/api/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2
Executable file
Binary file not shown.
BIN
docs/api/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2
Executable file
BIN
docs/api/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2
Executable file
Binary file not shown.
23
docs/api/assets/fonts/source-code-pro.css
Executable file
23
docs/api/assets/fonts/source-code-pro.css
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
@font-face{
|
||||||
|
font-family: 'Source Code Pro';
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
font-stretch: normal;
|
||||||
|
src: url('EOT/SourceCodePro-Regular.eot') format('embedded-opentype'),
|
||||||
|
url('WOFF2/TTF/SourceCodePro-Regular.ttf.woff2') format('woff2'),
|
||||||
|
url('WOFF/OTF/SourceCodePro-Regular.otf.woff') format('woff'),
|
||||||
|
url('OTF/SourceCodePro-Regular.otf') format('opentype'),
|
||||||
|
url('TTF/SourceCodePro-Regular.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face{
|
||||||
|
font-family: 'Source Code Pro';
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: normal;
|
||||||
|
font-stretch: normal;
|
||||||
|
src: url('EOT/SourceCodePro-Bold.eot') format('embedded-opentype'),
|
||||||
|
url('WOFF2/TTF/SourceCodePro-Bold.ttf.woff2') format('woff2'),
|
||||||
|
url('WOFF/OTF/SourceCodePro-Bold.otf.woff') format('woff'),
|
||||||
|
url('OTF/SourceCodePro-Bold.otf') format('opentype'),
|
||||||
|
url('TTF/SourceCodePro-Bold.ttf') format('truetype');
|
||||||
|
}
|
||||||
123
docs/api/assets/github.css
Normal file
123
docs/api/assets/github.css
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding: 0.5em;
|
||||||
|
color: #333;
|
||||||
|
background: #f8f8f8;
|
||||||
|
-webkit-text-size-adjust: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment,
|
||||||
|
.diff .hljs-header,
|
||||||
|
.hljs-javadoc {
|
||||||
|
color: #998;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-keyword,
|
||||||
|
.css .rule .hljs-keyword,
|
||||||
|
.hljs-winutils,
|
||||||
|
.nginx .hljs-title,
|
||||||
|
.hljs-subst,
|
||||||
|
.hljs-request,
|
||||||
|
.hljs-status {
|
||||||
|
color: #1184CE;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-number,
|
||||||
|
.hljs-hexcolor,
|
||||||
|
.ruby .hljs-constant {
|
||||||
|
color: #ed225d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-tag .hljs-value,
|
||||||
|
.hljs-phpdoc,
|
||||||
|
.hljs-dartdoc,
|
||||||
|
.tex .hljs-formula {
|
||||||
|
color: #ed225d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-title,
|
||||||
|
.hljs-id,
|
||||||
|
.scss .hljs-preprocessor {
|
||||||
|
color: #900;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-list .hljs-keyword,
|
||||||
|
.hljs-subst {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-class .hljs-title,
|
||||||
|
.hljs-type,
|
||||||
|
.vhdl .hljs-literal,
|
||||||
|
.tex .hljs-command {
|
||||||
|
color: #458;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-tag,
|
||||||
|
.hljs-tag .hljs-title,
|
||||||
|
.hljs-rules .hljs-property,
|
||||||
|
.django .hljs-tag .hljs-keyword {
|
||||||
|
color: #000080;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-attribute,
|
||||||
|
.hljs-variable,
|
||||||
|
.lisp .hljs-body {
|
||||||
|
color: #008080;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-regexp {
|
||||||
|
color: #009926;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-symbol,
|
||||||
|
.ruby .hljs-symbol .hljs-string,
|
||||||
|
.lisp .hljs-keyword,
|
||||||
|
.clojure .hljs-keyword,
|
||||||
|
.scheme .hljs-keyword,
|
||||||
|
.tex .hljs-special,
|
||||||
|
.hljs-prompt {
|
||||||
|
color: #990073;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-built_in {
|
||||||
|
color: #0086b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-preprocessor,
|
||||||
|
.hljs-pragma,
|
||||||
|
.hljs-pi,
|
||||||
|
.hljs-doctype,
|
||||||
|
.hljs-shebang,
|
||||||
|
.hljs-cdata {
|
||||||
|
color: #999;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-deletion {
|
||||||
|
background: #fdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-addition {
|
||||||
|
background: #dfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diff .hljs-change {
|
||||||
|
background: #0086b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-chunk {
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
168
docs/api/assets/site.js
Normal file
168
docs/api/assets/site.js
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
/* global anchors */
|
||||||
|
|
||||||
|
// add anchor links to headers
|
||||||
|
anchors.options.placement = 'left';
|
||||||
|
anchors.add('h3');
|
||||||
|
|
||||||
|
// Filter UI
|
||||||
|
var tocElements = document.getElementById('toc').getElementsByTagName('li');
|
||||||
|
|
||||||
|
document.getElementById('filter-input').addEventListener('keyup', function(e) {
|
||||||
|
var i, element, children;
|
||||||
|
|
||||||
|
// enter key
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
// go to the first displayed item in the toc
|
||||||
|
for (i = 0; i < tocElements.length; i++) {
|
||||||
|
element = tocElements[i];
|
||||||
|
if (!element.classList.contains('display-none')) {
|
||||||
|
location.replace(element.firstChild.href);
|
||||||
|
return e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var match = function() {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
var value = this.value.toLowerCase();
|
||||||
|
|
||||||
|
if (!value.match(/^\s*$/)) {
|
||||||
|
match = function(element) {
|
||||||
|
var html = element.firstChild.innerHTML;
|
||||||
|
return html && html.toLowerCase().indexOf(value) !== -1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < tocElements.length; i++) {
|
||||||
|
element = tocElements[i];
|
||||||
|
children = Array.from(element.getElementsByTagName('li'));
|
||||||
|
if (match(element) || children.some(match)) {
|
||||||
|
element.classList.remove('display-none');
|
||||||
|
} else {
|
||||||
|
element.classList.add('display-none');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var items = document.getElementsByClassName('toggle-sibling');
|
||||||
|
for (var j = 0; j < items.length; j++) {
|
||||||
|
items[j].addEventListener('click', toggleSibling);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSibling() {
|
||||||
|
var stepSibling = this.parentNode.getElementsByClassName('toggle-target')[0];
|
||||||
|
var icon = this.getElementsByClassName('icon')[0];
|
||||||
|
var klass = 'display-none';
|
||||||
|
if (stepSibling.classList.contains(klass)) {
|
||||||
|
stepSibling.classList.remove(klass);
|
||||||
|
icon.innerHTML = '▾';
|
||||||
|
} else {
|
||||||
|
stepSibling.classList.add(klass);
|
||||||
|
icon.innerHTML = '▸';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showHashTarget(targetId) {
|
||||||
|
if (targetId) {
|
||||||
|
var hashTarget = document.getElementById(targetId);
|
||||||
|
// new target is hidden
|
||||||
|
if (
|
||||||
|
hashTarget &&
|
||||||
|
hashTarget.offsetHeight === 0 &&
|
||||||
|
hashTarget.parentNode.parentNode.classList.contains('display-none')
|
||||||
|
) {
|
||||||
|
hashTarget.parentNode.parentNode.classList.remove('display-none');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scrollIntoView(targetId) {
|
||||||
|
// Only scroll to element if we don't have a stored scroll position.
|
||||||
|
if (targetId && !history.state) {
|
||||||
|
var hashTarget = document.getElementById(targetId);
|
||||||
|
if (hashTarget) {
|
||||||
|
hashTarget.scrollIntoView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotoCurrentTarget() {
|
||||||
|
showHashTarget(location.hash.substring(1));
|
||||||
|
scrollIntoView(location.hash.substring(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('hashchange', gotoCurrentTarget);
|
||||||
|
gotoCurrentTarget();
|
||||||
|
|
||||||
|
var toclinks = document.getElementsByClassName('pre-open');
|
||||||
|
for (var k = 0; k < toclinks.length; k++) {
|
||||||
|
toclinks[k].addEventListener('mousedown', preOpen, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function preOpen() {
|
||||||
|
showHashTarget(this.hash.substring(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
var split_left = document.querySelector('#split-left');
|
||||||
|
var split_right = document.querySelector('#split-right');
|
||||||
|
var split_parent = split_left.parentNode;
|
||||||
|
var cw_with_sb = split_left.clientWidth;
|
||||||
|
split_left.style.overflow = 'hidden';
|
||||||
|
var cw_without_sb = split_left.clientWidth;
|
||||||
|
split_left.style.overflow = '';
|
||||||
|
|
||||||
|
Split(['#split-left', '#split-right'], {
|
||||||
|
elementStyle: function(dimension, size, gutterSize) {
|
||||||
|
return {
|
||||||
|
'flex-basis': 'calc(' + size + '% - ' + gutterSize + 'px)'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
gutterStyle: function(dimension, gutterSize) {
|
||||||
|
return {
|
||||||
|
'flex-basis': gutterSize + 'px'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
gutterSize: 20,
|
||||||
|
sizes: [33, 67]
|
||||||
|
});
|
||||||
|
|
||||||
|
// Chrome doesn't remember scroll position properly so do it ourselves.
|
||||||
|
// Also works on Firefox and Edge.
|
||||||
|
|
||||||
|
function updateState() {
|
||||||
|
history.replaceState(
|
||||||
|
{
|
||||||
|
left_top: split_left.scrollTop,
|
||||||
|
right_top: split_right.scrollTop
|
||||||
|
},
|
||||||
|
document.title
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadState(ev) {
|
||||||
|
if (ev) {
|
||||||
|
// Edge doesn't replace change history.state on popstate.
|
||||||
|
history.replaceState(ev.state, document.title);
|
||||||
|
}
|
||||||
|
if (history.state) {
|
||||||
|
split_left.scrollTop = history.state.left_top;
|
||||||
|
split_right.scrollTop = history.state.right_top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('load', function() {
|
||||||
|
// Restore after Firefox scrolls to hash.
|
||||||
|
setTimeout(function() {
|
||||||
|
loadState();
|
||||||
|
// Update with initial scroll position.
|
||||||
|
updateState();
|
||||||
|
// Update scroll positions only after we've loaded because Firefox
|
||||||
|
// emits an initial scroll event with 0.
|
||||||
|
split_left.addEventListener('scroll', updateState);
|
||||||
|
split_right.addEventListener('scroll', updateState);
|
||||||
|
}, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('popstate', loadState);
|
||||||
15
docs/api/assets/split.css
Normal file
15
docs/api/assets/split.css
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
.gutter {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gutter.gutter-vertical {
|
||||||
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII=');
|
||||||
|
cursor: ns-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gutter.gutter-horizontal {
|
||||||
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==');
|
||||||
|
cursor: ew-resize;
|
||||||
|
}
|
||||||
586
docs/api/assets/split.js
Normal file
586
docs/api/assets/split.js
Normal file
@@ -0,0 +1,586 @@
|
|||||||
|
/*! Split.js - v1.3.5 */
|
||||||
|
// https://github.com/nathancahill/Split.js
|
||||||
|
// Copyright (c) 2017 Nathan Cahill; Licensed MIT
|
||||||
|
|
||||||
|
(function(global, factory) {
|
||||||
|
typeof exports === 'object' && typeof module !== 'undefined'
|
||||||
|
? (module.exports = factory())
|
||||||
|
: typeof define === 'function' && define.amd
|
||||||
|
? define(factory)
|
||||||
|
: (global.Split = factory());
|
||||||
|
})(this, function() {
|
||||||
|
'use strict';
|
||||||
|
// The programming goals of Split.js are to deliver readable, understandable and
|
||||||
|
// maintainable code, while at the same time manually optimizing for tiny minified file size,
|
||||||
|
// browser compatibility without additional requirements, graceful fallback (IE8 is supported)
|
||||||
|
// and very few assumptions about the user's page layout.
|
||||||
|
var global = window;
|
||||||
|
var document = global.document;
|
||||||
|
|
||||||
|
// Save a couple long function names that are used frequently.
|
||||||
|
// This optimization saves around 400 bytes.
|
||||||
|
var addEventListener = 'addEventListener';
|
||||||
|
var removeEventListener = 'removeEventListener';
|
||||||
|
var getBoundingClientRect = 'getBoundingClientRect';
|
||||||
|
var NOOP = function() {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Figure out if we're in IE8 or not. IE8 will still render correctly,
|
||||||
|
// but will be static instead of draggable.
|
||||||
|
var isIE8 = global.attachEvent && !global[addEventListener];
|
||||||
|
|
||||||
|
// This library only needs two helper functions:
|
||||||
|
//
|
||||||
|
// The first determines which prefixes of CSS calc we need.
|
||||||
|
// We only need to do this once on startup, when this anonymous function is called.
|
||||||
|
//
|
||||||
|
// Tests -webkit, -moz and -o prefixes. Modified from StackOverflow:
|
||||||
|
// http://stackoverflow.com/questions/16625140/js-feature-detection-to-detect-the-usage-of-webkit-calc-over-calc/16625167#16625167
|
||||||
|
var calc =
|
||||||
|
['', '-webkit-', '-moz-', '-o-']
|
||||||
|
.filter(function(prefix) {
|
||||||
|
var el = document.createElement('div');
|
||||||
|
el.style.cssText = 'width:' + prefix + 'calc(9px)';
|
||||||
|
|
||||||
|
return !!el.style.length;
|
||||||
|
})
|
||||||
|
.shift() + 'calc';
|
||||||
|
|
||||||
|
// The second helper function allows elements and string selectors to be used
|
||||||
|
// interchangeably. In either case an element is returned. This allows us to
|
||||||
|
// do `Split([elem1, elem2])` as well as `Split(['#id1', '#id2'])`.
|
||||||
|
var elementOrSelector = function(el) {
|
||||||
|
if (typeof el === 'string' || el instanceof String) {
|
||||||
|
return document.querySelector(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
return el;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The main function to initialize a split. Split.js thinks about each pair
|
||||||
|
// of elements as an independant pair. Dragging the gutter between two elements
|
||||||
|
// only changes the dimensions of elements in that pair. This is key to understanding
|
||||||
|
// how the following functions operate, since each function is bound to a pair.
|
||||||
|
//
|
||||||
|
// A pair object is shaped like this:
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// a: DOM element,
|
||||||
|
// b: DOM element,
|
||||||
|
// aMin: Number,
|
||||||
|
// bMin: Number,
|
||||||
|
// dragging: Boolean,
|
||||||
|
// parent: DOM element,
|
||||||
|
// isFirst: Boolean,
|
||||||
|
// isLast: Boolean,
|
||||||
|
// direction: 'horizontal' | 'vertical'
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// The basic sequence:
|
||||||
|
//
|
||||||
|
// 1. Set defaults to something sane. `options` doesn't have to be passed at all.
|
||||||
|
// 2. Initialize a bunch of strings based on the direction we're splitting.
|
||||||
|
// A lot of the behavior in the rest of the library is paramatized down to
|
||||||
|
// rely on CSS strings and classes.
|
||||||
|
// 3. Define the dragging helper functions, and a few helpers to go with them.
|
||||||
|
// 4. Loop through the elements while pairing them off. Every pair gets an
|
||||||
|
// `pair` object, a gutter, and special isFirst/isLast properties.
|
||||||
|
// 5. Actually size the pair elements, insert gutters and attach event listeners.
|
||||||
|
var Split = function(ids, options) {
|
||||||
|
if (options === void 0) options = {};
|
||||||
|
|
||||||
|
var dimension;
|
||||||
|
var clientDimension;
|
||||||
|
var clientAxis;
|
||||||
|
var position;
|
||||||
|
var paddingA;
|
||||||
|
var paddingB;
|
||||||
|
var elements;
|
||||||
|
|
||||||
|
// All DOM elements in the split should have a common parent. We can grab
|
||||||
|
// the first elements parent and hope users read the docs because the
|
||||||
|
// behavior will be whacky otherwise.
|
||||||
|
var parent = elementOrSelector(ids[0]).parentNode;
|
||||||
|
var parentFlexDirection = global.getComputedStyle(parent).flexDirection;
|
||||||
|
|
||||||
|
// Set default options.sizes to equal percentages of the parent element.
|
||||||
|
var sizes =
|
||||||
|
options.sizes ||
|
||||||
|
ids.map(function() {
|
||||||
|
return 100 / ids.length;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Standardize minSize to an array if it isn't already. This allows minSize
|
||||||
|
// to be passed as a number.
|
||||||
|
var minSize = options.minSize !== undefined ? options.minSize : 100;
|
||||||
|
var minSizes = Array.isArray(minSize)
|
||||||
|
? minSize
|
||||||
|
: ids.map(function() {
|
||||||
|
return minSize;
|
||||||
|
});
|
||||||
|
var gutterSize = options.gutterSize !== undefined ? options.gutterSize : 10;
|
||||||
|
var snapOffset = options.snapOffset !== undefined ? options.snapOffset : 30;
|
||||||
|
var direction = options.direction || 'horizontal';
|
||||||
|
var cursor =
|
||||||
|
options.cursor ||
|
||||||
|
(direction === 'horizontal' ? 'ew-resize' : 'ns-resize');
|
||||||
|
var gutter =
|
||||||
|
options.gutter ||
|
||||||
|
function(i, gutterDirection) {
|
||||||
|
var gut = document.createElement('div');
|
||||||
|
gut.className = 'gutter gutter-' + gutterDirection;
|
||||||
|
return gut;
|
||||||
|
};
|
||||||
|
var elementStyle =
|
||||||
|
options.elementStyle ||
|
||||||
|
function(dim, size, gutSize) {
|
||||||
|
var style = {};
|
||||||
|
|
||||||
|
if (typeof size !== 'string' && !(size instanceof String)) {
|
||||||
|
if (!isIE8) {
|
||||||
|
style[dim] = calc + '(' + size + '% - ' + gutSize + 'px)';
|
||||||
|
} else {
|
||||||
|
style[dim] = size + '%';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
style[dim] = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return style;
|
||||||
|
};
|
||||||
|
var gutterStyle =
|
||||||
|
options.gutterStyle ||
|
||||||
|
function(dim, gutSize) {
|
||||||
|
return (obj = {}), (obj[dim] = gutSize + 'px'), obj;
|
||||||
|
var obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. Initialize a bunch of strings based on the direction we're splitting.
|
||||||
|
// A lot of the behavior in the rest of the library is paramatized down to
|
||||||
|
// rely on CSS strings and classes.
|
||||||
|
if (direction === 'horizontal') {
|
||||||
|
dimension = 'width';
|
||||||
|
clientDimension = 'clientWidth';
|
||||||
|
clientAxis = 'clientX';
|
||||||
|
position = 'left';
|
||||||
|
paddingA = 'paddingLeft';
|
||||||
|
paddingB = 'paddingRight';
|
||||||
|
} else if (direction === 'vertical') {
|
||||||
|
dimension = 'height';
|
||||||
|
clientDimension = 'clientHeight';
|
||||||
|
clientAxis = 'clientY';
|
||||||
|
position = 'top';
|
||||||
|
paddingA = 'paddingTop';
|
||||||
|
paddingB = 'paddingBottom';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Define the dragging helper functions, and a few helpers to go with them.
|
||||||
|
// Each helper is bound to a pair object that contains it's metadata. This
|
||||||
|
// also makes it easy to store references to listeners that that will be
|
||||||
|
// added and removed.
|
||||||
|
//
|
||||||
|
// Even though there are no other functions contained in them, aliasing
|
||||||
|
// this to self saves 50 bytes or so since it's used so frequently.
|
||||||
|
//
|
||||||
|
// The pair object saves metadata like dragging state, position and
|
||||||
|
// event listener references.
|
||||||
|
|
||||||
|
function setElementSize(el, size, gutSize) {
|
||||||
|
// Split.js allows setting sizes via numbers (ideally), or if you must,
|
||||||
|
// by string, like '300px'. This is less than ideal, because it breaks
|
||||||
|
// the fluid layout that `calc(% - px)` provides. You're on your own if you do that,
|
||||||
|
// make sure you calculate the gutter size by hand.
|
||||||
|
var style = elementStyle(dimension, size, gutSize);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
Object.keys(style).forEach(function(prop) {
|
||||||
|
return (el.style[prop] = style[prop]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setGutterSize(gutterElement, gutSize) {
|
||||||
|
var style = gutterStyle(dimension, gutSize);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
Object.keys(style).forEach(function(prop) {
|
||||||
|
return (gutterElement.style[prop] = style[prop]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually adjust the size of elements `a` and `b` to `offset` while dragging.
|
||||||
|
// calc is used to allow calc(percentage + gutterpx) on the whole split instance,
|
||||||
|
// which allows the viewport to be resized without additional logic.
|
||||||
|
// Element a's size is the same as offset. b's size is total size - a size.
|
||||||
|
// Both sizes are calculated from the initial parent percentage,
|
||||||
|
// then the gutter size is subtracted.
|
||||||
|
function adjust(offset) {
|
||||||
|
var a = elements[this.a];
|
||||||
|
var b = elements[this.b];
|
||||||
|
var percentage = a.size + b.size;
|
||||||
|
|
||||||
|
a.size = (offset / this.size) * percentage;
|
||||||
|
b.size = percentage - (offset / this.size) * percentage;
|
||||||
|
|
||||||
|
setElementSize(a.element, a.size, this.aGutterSize);
|
||||||
|
setElementSize(b.element, b.size, this.bGutterSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// drag, where all the magic happens. The logic is really quite simple:
|
||||||
|
//
|
||||||
|
// 1. Ignore if the pair is not dragging.
|
||||||
|
// 2. Get the offset of the event.
|
||||||
|
// 3. Snap offset to min if within snappable range (within min + snapOffset).
|
||||||
|
// 4. Actually adjust each element in the pair to offset.
|
||||||
|
//
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// | | <- a.minSize || b.minSize -> | |
|
||||||
|
// | | | <- this.snapOffset || this.snapOffset -> | | |
|
||||||
|
// | | | || | | |
|
||||||
|
// | | | || | | |
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// | <- this.start this.size -> |
|
||||||
|
function drag(e) {
|
||||||
|
var offset;
|
||||||
|
|
||||||
|
if (!this.dragging) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the offset of the event from the first side of the
|
||||||
|
// pair `this.start`. Supports touch events, but not multitouch, so only the first
|
||||||
|
// finger `touches[0]` is counted.
|
||||||
|
if ('touches' in e) {
|
||||||
|
offset = e.touches[0][clientAxis] - this.start;
|
||||||
|
} else {
|
||||||
|
offset = e[clientAxis] - this.start;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If within snapOffset of min or max, set offset to min or max.
|
||||||
|
// snapOffset buffers a.minSize and b.minSize, so logic is opposite for both.
|
||||||
|
// Include the appropriate gutter sizes to prevent overflows.
|
||||||
|
if (offset <= elements[this.a].minSize + snapOffset + this.aGutterSize) {
|
||||||
|
offset = elements[this.a].minSize + this.aGutterSize;
|
||||||
|
} else if (
|
||||||
|
offset >=
|
||||||
|
this.size - (elements[this.b].minSize + snapOffset + this.bGutterSize)
|
||||||
|
) {
|
||||||
|
offset = this.size - (elements[this.b].minSize + this.bGutterSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually adjust the size.
|
||||||
|
adjust.call(this, offset);
|
||||||
|
|
||||||
|
// Call the drag callback continously. Don't do anything too intensive
|
||||||
|
// in this callback.
|
||||||
|
if (options.onDrag) {
|
||||||
|
options.onDrag();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache some important sizes when drag starts, so we don't have to do that
|
||||||
|
// continously:
|
||||||
|
//
|
||||||
|
// `size`: The total size of the pair. First + second + first gutter + second gutter.
|
||||||
|
// `start`: The leading side of the first element.
|
||||||
|
//
|
||||||
|
// ------------------------------------------------
|
||||||
|
// | aGutterSize -> ||| |
|
||||||
|
// | ||| |
|
||||||
|
// | ||| |
|
||||||
|
// | ||| <- bGutterSize |
|
||||||
|
// ------------------------------------------------
|
||||||
|
// | <- start size -> |
|
||||||
|
function calculateSizes() {
|
||||||
|
// Figure out the parent size minus padding.
|
||||||
|
var a = elements[this.a].element;
|
||||||
|
var b = elements[this.b].element;
|
||||||
|
|
||||||
|
this.size =
|
||||||
|
a[getBoundingClientRect]()[dimension] +
|
||||||
|
b[getBoundingClientRect]()[dimension] +
|
||||||
|
this.aGutterSize +
|
||||||
|
this.bGutterSize;
|
||||||
|
this.start = a[getBoundingClientRect]()[position];
|
||||||
|
}
|
||||||
|
|
||||||
|
// stopDragging is very similar to startDragging in reverse.
|
||||||
|
function stopDragging() {
|
||||||
|
var self = this;
|
||||||
|
var a = elements[self.a].element;
|
||||||
|
var b = elements[self.b].element;
|
||||||
|
|
||||||
|
if (self.dragging && options.onDragEnd) {
|
||||||
|
options.onDragEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.dragging = false;
|
||||||
|
|
||||||
|
// Remove the stored event listeners. This is why we store them.
|
||||||
|
global[removeEventListener]('mouseup', self.stop);
|
||||||
|
global[removeEventListener]('touchend', self.stop);
|
||||||
|
global[removeEventListener]('touchcancel', self.stop);
|
||||||
|
|
||||||
|
self.parent[removeEventListener]('mousemove', self.move);
|
||||||
|
self.parent[removeEventListener]('touchmove', self.move);
|
||||||
|
|
||||||
|
// Delete them once they are removed. I think this makes a difference
|
||||||
|
// in memory usage with a lot of splits on one page. But I don't know for sure.
|
||||||
|
delete self.stop;
|
||||||
|
delete self.move;
|
||||||
|
|
||||||
|
a[removeEventListener]('selectstart', NOOP);
|
||||||
|
a[removeEventListener]('dragstart', NOOP);
|
||||||
|
b[removeEventListener]('selectstart', NOOP);
|
||||||
|
b[removeEventListener]('dragstart', NOOP);
|
||||||
|
|
||||||
|
a.style.userSelect = '';
|
||||||
|
a.style.webkitUserSelect = '';
|
||||||
|
a.style.MozUserSelect = '';
|
||||||
|
a.style.pointerEvents = '';
|
||||||
|
|
||||||
|
b.style.userSelect = '';
|
||||||
|
b.style.webkitUserSelect = '';
|
||||||
|
b.style.MozUserSelect = '';
|
||||||
|
b.style.pointerEvents = '';
|
||||||
|
|
||||||
|
self.gutter.style.cursor = '';
|
||||||
|
self.parent.style.cursor = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// startDragging calls `calculateSizes` to store the inital size in the pair object.
|
||||||
|
// It also adds event listeners for mouse/touch events,
|
||||||
|
// and prevents selection while dragging so avoid the selecting text.
|
||||||
|
function startDragging(e) {
|
||||||
|
// Alias frequently used variables to save space. 200 bytes.
|
||||||
|
var self = this;
|
||||||
|
var a = elements[self.a].element;
|
||||||
|
var b = elements[self.b].element;
|
||||||
|
|
||||||
|
// Call the onDragStart callback.
|
||||||
|
if (!self.dragging && options.onDragStart) {
|
||||||
|
options.onDragStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't actually drag the element. We emulate that in the drag function.
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Set the dragging property of the pair object.
|
||||||
|
self.dragging = true;
|
||||||
|
|
||||||
|
// Create two event listeners bound to the same pair object and store
|
||||||
|
// them in the pair object.
|
||||||
|
self.move = drag.bind(self);
|
||||||
|
self.stop = stopDragging.bind(self);
|
||||||
|
|
||||||
|
// All the binding. `window` gets the stop events in case we drag out of the elements.
|
||||||
|
global[addEventListener]('mouseup', self.stop);
|
||||||
|
global[addEventListener]('touchend', self.stop);
|
||||||
|
global[addEventListener]('touchcancel', self.stop);
|
||||||
|
|
||||||
|
self.parent[addEventListener]('mousemove', self.move);
|
||||||
|
self.parent[addEventListener]('touchmove', self.move);
|
||||||
|
|
||||||
|
// Disable selection. Disable!
|
||||||
|
a[addEventListener]('selectstart', NOOP);
|
||||||
|
a[addEventListener]('dragstart', NOOP);
|
||||||
|
b[addEventListener]('selectstart', NOOP);
|
||||||
|
b[addEventListener]('dragstart', NOOP);
|
||||||
|
|
||||||
|
a.style.userSelect = 'none';
|
||||||
|
a.style.webkitUserSelect = 'none';
|
||||||
|
a.style.MozUserSelect = 'none';
|
||||||
|
a.style.pointerEvents = 'none';
|
||||||
|
|
||||||
|
b.style.userSelect = 'none';
|
||||||
|
b.style.webkitUserSelect = 'none';
|
||||||
|
b.style.MozUserSelect = 'none';
|
||||||
|
b.style.pointerEvents = 'none';
|
||||||
|
|
||||||
|
// Set the cursor, both on the gutter and the parent element.
|
||||||
|
// Doing only a, b and gutter causes flickering.
|
||||||
|
self.gutter.style.cursor = cursor;
|
||||||
|
self.parent.style.cursor = cursor;
|
||||||
|
|
||||||
|
// Cache the initial sizes of the pair.
|
||||||
|
calculateSizes.call(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Create pair and element objects. Each pair has an index reference to
|
||||||
|
// elements `a` and `b` of the pair (first and second elements).
|
||||||
|
// Loop through the elements while pairing them off. Every pair gets a
|
||||||
|
// `pair` object, a gutter, and isFirst/isLast properties.
|
||||||
|
//
|
||||||
|
// Basic logic:
|
||||||
|
//
|
||||||
|
// - Starting with the second element `i > 0`, create `pair` objects with
|
||||||
|
// `a = i - 1` and `b = i`
|
||||||
|
// - Set gutter sizes based on the _pair_ being first/last. The first and last
|
||||||
|
// pair have gutterSize / 2, since they only have one half gutter, and not two.
|
||||||
|
// - Create gutter elements and add event listeners.
|
||||||
|
// - Set the size of the elements, minus the gutter sizes.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
// | i=0 | i=1 | i=2 | i=3 |
|
||||||
|
// | | isFirst | | isLast |
|
||||||
|
// | pair 0 pair 1 pair 2 |
|
||||||
|
// | | | | |
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
var pairs = [];
|
||||||
|
elements = ids.map(function(id, i) {
|
||||||
|
// Create the element object.
|
||||||
|
var element = {
|
||||||
|
element: elementOrSelector(id),
|
||||||
|
size: sizes[i],
|
||||||
|
minSize: minSizes[i]
|
||||||
|
};
|
||||||
|
|
||||||
|
var pair;
|
||||||
|
|
||||||
|
if (i > 0) {
|
||||||
|
// Create the pair object with it's metadata.
|
||||||
|
pair = {
|
||||||
|
a: i - 1,
|
||||||
|
b: i,
|
||||||
|
dragging: false,
|
||||||
|
isFirst: i === 1,
|
||||||
|
isLast: i === ids.length - 1,
|
||||||
|
direction: direction,
|
||||||
|
parent: parent
|
||||||
|
};
|
||||||
|
|
||||||
|
// For first and last pairs, first and last gutter width is half.
|
||||||
|
pair.aGutterSize = gutterSize;
|
||||||
|
pair.bGutterSize = gutterSize;
|
||||||
|
|
||||||
|
if (pair.isFirst) {
|
||||||
|
pair.aGutterSize = gutterSize / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pair.isLast) {
|
||||||
|
pair.bGutterSize = gutterSize / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the parent has a reverse flex-direction, switch the pair elements.
|
||||||
|
if (
|
||||||
|
parentFlexDirection === 'row-reverse' ||
|
||||||
|
parentFlexDirection === 'column-reverse'
|
||||||
|
) {
|
||||||
|
var temp = pair.a;
|
||||||
|
pair.a = pair.b;
|
||||||
|
pair.b = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the size of the current element. IE8 is supported by
|
||||||
|
// staticly assigning sizes without draggable gutters. Assigns a string
|
||||||
|
// to `size`.
|
||||||
|
//
|
||||||
|
// IE9 and above
|
||||||
|
if (!isIE8) {
|
||||||
|
// Create gutter elements for each pair.
|
||||||
|
if (i > 0) {
|
||||||
|
var gutterElement = gutter(i, direction);
|
||||||
|
setGutterSize(gutterElement, gutterSize);
|
||||||
|
|
||||||
|
gutterElement[addEventListener](
|
||||||
|
'mousedown',
|
||||||
|
startDragging.bind(pair)
|
||||||
|
);
|
||||||
|
gutterElement[addEventListener](
|
||||||
|
'touchstart',
|
||||||
|
startDragging.bind(pair)
|
||||||
|
);
|
||||||
|
|
||||||
|
parent.insertBefore(gutterElement, element.element);
|
||||||
|
|
||||||
|
pair.gutter = gutterElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the element size to our determined size.
|
||||||
|
// Half-size gutters for first and last elements.
|
||||||
|
if (i === 0 || i === ids.length - 1) {
|
||||||
|
setElementSize(element.element, element.size, gutterSize / 2);
|
||||||
|
} else {
|
||||||
|
setElementSize(element.element, element.size, gutterSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
var computedSize = element.element[getBoundingClientRect]()[dimension];
|
||||||
|
|
||||||
|
if (computedSize < element.minSize) {
|
||||||
|
element.minSize = computedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// After the first iteration, and we have a pair object, append it to the
|
||||||
|
// list of pairs.
|
||||||
|
if (i > 0) {
|
||||||
|
pairs.push(pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
|
});
|
||||||
|
|
||||||
|
function setSizes(newSizes) {
|
||||||
|
newSizes.forEach(function(newSize, i) {
|
||||||
|
if (i > 0) {
|
||||||
|
var pair = pairs[i - 1];
|
||||||
|
var a = elements[pair.a];
|
||||||
|
var b = elements[pair.b];
|
||||||
|
|
||||||
|
a.size = newSizes[i - 1];
|
||||||
|
b.size = newSize;
|
||||||
|
|
||||||
|
setElementSize(a.element, a.size, pair.aGutterSize);
|
||||||
|
setElementSize(b.element, b.size, pair.bGutterSize);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroy() {
|
||||||
|
pairs.forEach(function(pair) {
|
||||||
|
pair.parent.removeChild(pair.gutter);
|
||||||
|
elements[pair.a].element.style[dimension] = '';
|
||||||
|
elements[pair.b].element.style[dimension] = '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isIE8) {
|
||||||
|
return {
|
||||||
|
setSizes: setSizes,
|
||||||
|
destroy: destroy
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setSizes: setSizes,
|
||||||
|
getSizes: function getSizes() {
|
||||||
|
return elements.map(function(element) {
|
||||||
|
return element.size;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
collapse: function collapse(i) {
|
||||||
|
if (i === pairs.length) {
|
||||||
|
var pair = pairs[i - 1];
|
||||||
|
|
||||||
|
calculateSizes.call(pair);
|
||||||
|
|
||||||
|
if (!isIE8) {
|
||||||
|
adjust.call(pair, pair.size - pair.bGutterSize);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var pair$1 = pairs[i];
|
||||||
|
|
||||||
|
calculateSizes.call(pair$1);
|
||||||
|
|
||||||
|
if (!isIE8) {
|
||||||
|
adjust.call(pair$1, pair$1.aGutterSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
destroy: destroy
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return Split;
|
||||||
|
});
|
||||||
140
docs/api/assets/style.css
Normal file
140
docs/api/assets/style.css
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
.documentation {
|
||||||
|
font-family: Helvetica, sans-serif;
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.5;
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.black {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-white {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
margin: 20px 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation h3 {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-bottom {
|
||||||
|
border-color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #1184CE;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation a[href]:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.py1-ul li {
|
||||||
|
padding: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.max-height-100 {
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.height-viewport-100 {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
section:target h3 {
|
||||||
|
font-weight:700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentation td,
|
||||||
|
.documentation th {
|
||||||
|
padding: .25rem .25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1:hover .anchorjs-link,
|
||||||
|
h2:hover .anchorjs-link,
|
||||||
|
h3:hover .anchorjs-link,
|
||||||
|
h4:hover .anchorjs-link {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fix-3 {
|
||||||
|
width: 25%;
|
||||||
|
max-width: 244px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fix-3 {
|
||||||
|
width: 25%;
|
||||||
|
max-width: 244px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 52em) {
|
||||||
|
.fix-margin-3 {
|
||||||
|
margin-left: 25%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pre, pre, code, .code {
|
||||||
|
font-family: Source Code Pro,Menlo,Consolas,Liberation Mono,monospace;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fill-light {
|
||||||
|
background: #F9F9F9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.width2 {
|
||||||
|
width: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
font-family: inherit;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 2rem;
|
||||||
|
padding: .5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
font-size: .875rem;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose table th,
|
||||||
|
.prose table td {
|
||||||
|
text-align: left;
|
||||||
|
padding:8px;
|
||||||
|
border:1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose table th:nth-child(1) { border-right: none; }
|
||||||
|
.prose table th:nth-child(2) { border-left: none; }
|
||||||
|
|
||||||
|
.prose table {
|
||||||
|
border:1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose-big {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quiet {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.minishadow {
|
||||||
|
box-shadow: 2px 2px 10px #f3f3f3;
|
||||||
|
}
|
||||||
770
docs/api/index.html
Normal file
770
docs/api/index.html
Normal file
@@ -0,0 +1,770 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset='utf-8' />
|
||||||
|
<title>seasoned-request 1.0.0 | Documentation</title>
|
||||||
|
<meta name='description' content='seasoned request app'>
|
||||||
|
<meta name='viewport' content='width=device-width,initial-scale=1'>
|
||||||
|
<link href='assets/bass.css' rel='stylesheet' />
|
||||||
|
<link href='assets/style.css' rel='stylesheet' />
|
||||||
|
<link href='assets/github.css' rel='stylesheet' />
|
||||||
|
<link href='assets/split.css' rel='stylesheet' />
|
||||||
|
</head>
|
||||||
|
<body class='documentation m0'>
|
||||||
|
<div class='flex'>
|
||||||
|
<div id='split-left' class='overflow-auto fs0 height-viewport-100'>
|
||||||
|
<div class='py1 px2'>
|
||||||
|
<h3 class='mb0 no-anchor'>seasoned-request</h3>
|
||||||
|
<div class='mb1'><code>1.0.0</code></div>
|
||||||
|
<input
|
||||||
|
placeholder='Filter'
|
||||||
|
id='filter-input'
|
||||||
|
class='col12 block input'
|
||||||
|
type='text' />
|
||||||
|
<div id='toc'>
|
||||||
|
<ul class='list-reset h5 py1-ul'>
|
||||||
|
|
||||||
|
|
||||||
|
<li><a
|
||||||
|
href='#getmovie'
|
||||||
|
class="">
|
||||||
|
getMovie
|
||||||
|
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
<li><a
|
||||||
|
href='#getshow'
|
||||||
|
class="">
|
||||||
|
getShow
|
||||||
|
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
<li><a
|
||||||
|
href='#gettmdblistbypath'
|
||||||
|
class="">
|
||||||
|
getTmdbListByPath
|
||||||
|
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
<li><a
|
||||||
|
href='#searchtmdb'
|
||||||
|
class="">
|
||||||
|
searchTmdb
|
||||||
|
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
<li><a
|
||||||
|
href='#searchtorrents'
|
||||||
|
class="">
|
||||||
|
searchTorrents
|
||||||
|
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
<li><a
|
||||||
|
href='#addmagnet'
|
||||||
|
class="">
|
||||||
|
addMagnet
|
||||||
|
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
<li><a
|
||||||
|
href='#request'
|
||||||
|
class="">
|
||||||
|
request
|
||||||
|
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
<li><a
|
||||||
|
href='#elasticsearchmoviesandshows'
|
||||||
|
class="">
|
||||||
|
elasticSearchMoviesAndShows
|
||||||
|
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class='mt1 h6 quiet'>
|
||||||
|
<a href='https://documentation.js.org/reading-documentation.html'>Need help reading this?</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id='split-right' class='relative overflow-auto height-viewport-100'>
|
||||||
|
|
||||||
|
|
||||||
|
<section class='p2 mb2 clearfix bg-white minishadow'>
|
||||||
|
|
||||||
|
|
||||||
|
<div class='clearfix'>
|
||||||
|
|
||||||
|
<h3 class='fl m0' id='getmovie'>
|
||||||
|
getMovie
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<p>Fetches tmdb movie by id. Can optionally include cast credits in result object.</p>
|
||||||
|
|
||||||
|
<div class='pre p1 fill-light mt0'>getMovie</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='py1 quiet mt1 prose-big'>Parameters</div>
|
||||||
|
<div class='prose'>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>id</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number">number</a>)</code>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>credits</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean">boolean</a>
|
||||||
|
= <code>false</code>)</code>
|
||||||
|
Include credits
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='py1 quiet mt1 prose-big'>Returns</div>
|
||||||
|
<code><a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object">object</a></code>:
|
||||||
|
Tmdb response
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<section class='p2 mb2 clearfix bg-white minishadow'>
|
||||||
|
|
||||||
|
|
||||||
|
<div class='clearfix'>
|
||||||
|
|
||||||
|
<h3 class='fl m0' id='getshow'>
|
||||||
|
getShow
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<p>Fetches tmdb show by id. Can optionally include cast credits in result object.</p>
|
||||||
|
|
||||||
|
<div class='pre p1 fill-light mt0'>getShow</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='py1 quiet mt1 prose-big'>Parameters</div>
|
||||||
|
<div class='prose'>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>id</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number">number</a>)</code>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>credits</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean">boolean</a>
|
||||||
|
= <code>false</code>)</code>
|
||||||
|
Include credits
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='py1 quiet mt1 prose-big'>Returns</div>
|
||||||
|
<code><a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object">object</a></code>:
|
||||||
|
Tmdb response
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<section class='p2 mb2 clearfix bg-white minishadow'>
|
||||||
|
|
||||||
|
|
||||||
|
<div class='clearfix'>
|
||||||
|
|
||||||
|
<h3 class='fl m0' id='gettmdblistbypath'>
|
||||||
|
getTmdbListByPath
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<p>Fetches tmdb list by path.</p>
|
||||||
|
|
||||||
|
<div class='pre p1 fill-light mt0'>getTmdbListByPath</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='py1 quiet mt1 prose-big'>Parameters</div>
|
||||||
|
<div class='prose'>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>listPath</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String">string</a>)</code>
|
||||||
|
Path of list
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>page</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number">number</a>
|
||||||
|
= <code>1</code>)</code>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='py1 quiet mt1 prose-big'>Returns</div>
|
||||||
|
<code><a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object">object</a></code>:
|
||||||
|
Tmdb list response
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<section class='p2 mb2 clearfix bg-white minishadow'>
|
||||||
|
|
||||||
|
|
||||||
|
<div class='clearfix'>
|
||||||
|
|
||||||
|
<h3 class='fl m0' id='searchtmdb'>
|
||||||
|
searchTmdb
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<p>Fetches tmdb movies and shows by query.</p>
|
||||||
|
|
||||||
|
<div class='pre p1 fill-light mt0'>searchTmdb</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='py1 quiet mt1 prose-big'>Parameters</div>
|
||||||
|
<div class='prose'>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>query</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String">string</a>)</code>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>page</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number">number</a>
|
||||||
|
= <code>1</code>)</code>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='py1 quiet mt1 prose-big'>Returns</div>
|
||||||
|
<code><a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object">object</a></code>:
|
||||||
|
Tmdb response
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<section class='p2 mb2 clearfix bg-white minishadow'>
|
||||||
|
|
||||||
|
|
||||||
|
<div class='clearfix'>
|
||||||
|
|
||||||
|
<h3 class='fl m0' id='searchtorrents'>
|
||||||
|
searchTorrents
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<p>Search for torrents by query</p>
|
||||||
|
|
||||||
|
<div class='pre p1 fill-light mt0'>searchTorrents</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='py1 quiet mt1 prose-big'>Parameters</div>
|
||||||
|
<div class='prose'>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>query</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String">string</a>)</code>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>authorization_token</span> <code class='quiet'>(any)</code>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>credits</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean">boolean</a>)</code>
|
||||||
|
Include credits
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='py1 quiet mt1 prose-big'>Returns</div>
|
||||||
|
<code><a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object">object</a></code>:
|
||||||
|
Torrent response
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<section class='p2 mb2 clearfix bg-white minishadow'>
|
||||||
|
|
||||||
|
|
||||||
|
<div class='clearfix'>
|
||||||
|
|
||||||
|
<h3 class='fl m0' id='addmagnet'>
|
||||||
|
addMagnet
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<p>Add magnet to download queue.</p>
|
||||||
|
|
||||||
|
<div class='pre p1 fill-light mt0'>addMagnet</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='py1 quiet mt1 prose-big'>Parameters</div>
|
||||||
|
<div class='prose'>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>magnet</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String">string</a>)</code>
|
||||||
|
Magnet link
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>name</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean">boolean</a>)</code>
|
||||||
|
Name of torrent
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>tmdb_id</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean">boolean</a>)</code>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='py1 quiet mt1 prose-big'>Returns</div>
|
||||||
|
<code><a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object">object</a></code>:
|
||||||
|
Success/Failure response
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<section class='p2 mb2 clearfix bg-white minishadow'>
|
||||||
|
|
||||||
|
|
||||||
|
<div class='clearfix'>
|
||||||
|
|
||||||
|
<h3 class='fl m0' id='request'>
|
||||||
|
request
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<p>Request a movie or show from id. If authorization token is included the user will be linked
|
||||||
|
to the requested item.</p>
|
||||||
|
|
||||||
|
<div class='pre p1 fill-light mt0'>request</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='py1 quiet mt1 prose-big'>Parameters</div>
|
||||||
|
<div class='prose'>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>id</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number">number</a>)</code>
|
||||||
|
Movie or show id
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>type</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String">string</a>)</code>
|
||||||
|
Movie or show type
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>authorization_token</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String">string</a>?
|
||||||
|
= <code>undefined</code>)</code>
|
||||||
|
To identify the requesting user
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='py1 quiet mt1 prose-big'>Returns</div>
|
||||||
|
<code><a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object">object</a></code>:
|
||||||
|
Success/Failure response
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<section class='p2 mb2 clearfix bg-white minishadow'>
|
||||||
|
|
||||||
|
|
||||||
|
<div class='clearfix'>
|
||||||
|
|
||||||
|
<h3 class='fl m0' id='elasticsearchmoviesandshows'>
|
||||||
|
elasticSearchMoviesAndShows
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<p>Search elastic indexes movies and shows by query. Doc includes Tmdb daily export of Movies and
|
||||||
|
Tv Shows. See tmdb docs for more info: <a href="https://developers.themoviedb.org/3/getting-started/daily-file-exports">https://developers.themoviedb.org/3/getting-started/daily-file-exports</a></p>
|
||||||
|
|
||||||
|
<div class='pre p1 fill-light mt0'>elasticSearchMoviesAndShows</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='py1 quiet mt1 prose-big'>Parameters</div>
|
||||||
|
<div class='prose'>
|
||||||
|
|
||||||
|
<div class='space-bottom0'>
|
||||||
|
<div>
|
||||||
|
<span class='code bold'>query</span> <code class='quiet'>(<a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String">string</a>)</code>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='py1 quiet mt1 prose-big'>Returns</div>
|
||||||
|
<code><a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object">object</a></code>:
|
||||||
|
List of movies and shows matching query
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src='assets/anchor.js'></script>
|
||||||
|
<script src='assets/split.js'></script>
|
||||||
|
<script src='assets/site.js'></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
10
index.html
10
index.html
File diff suppressed because one or more lines are too long
@@ -11,7 +11,7 @@
|
|||||||
"docs": "documentation build src/api.js -f html -o docs/api && documentation build src/api.js -f md -o docs/api.md"
|
"docs": "documentation build src/api.js -f html -o docs/api && documentation build src/api.js -f md -o docs/api.md"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.18.1",
|
"axios": "^0.15.3",
|
||||||
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||||
"connect-history-api-fallback": "^1.3.0",
|
"connect-history-api-fallback": "^1.3.0",
|
||||||
"express": "^4.16.1",
|
"express": "^4.16.1",
|
||||||
@@ -34,9 +34,7 @@
|
|||||||
"file-loader": "^0.9.0",
|
"file-loader": "^0.9.0",
|
||||||
"node-sass": "^4.5.0",
|
"node-sass": "^4.5.0",
|
||||||
"sass-loader": "^5.0.1",
|
"sass-loader": "^5.0.1",
|
||||||
"schema-utils": "^2.4.1",
|
|
||||||
"vue-loader": "^10.0.0",
|
"vue-loader": "^10.0.0",
|
||||||
"vue-svg-inline-loader": "^1.3.1",
|
|
||||||
"vue-template-compiler": "2.6.10",
|
"vue-template-compiler": "2.6.10",
|
||||||
"webpack": "^2.2.0",
|
"webpack": "^2.2.0",
|
||||||
"webpack-dev-server": "^2.2.0"
|
"webpack-dev-server": "^2.2.0"
|
||||||
|
|||||||
100
src/App.vue
100
src/App.vue
@@ -5,8 +5,6 @@
|
|||||||
<navigation></navigation>
|
<navigation></navigation>
|
||||||
|
|
||||||
<!-- Header with search field -->
|
<!-- Header with search field -->
|
||||||
|
|
||||||
<!-- TODO move this to the navigation component -->
|
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<search-input v-model="query"></search-input>
|
<search-input v-model="query"></search-input>
|
||||||
</header>
|
</header>
|
||||||
@@ -14,29 +12,24 @@
|
|||||||
<!-- Movie popup that will show above existing rendered content -->
|
<!-- Movie popup that will show above existing rendered content -->
|
||||||
<movie-popup v-if="moviePopupIsVisible" :id="popupID" :type="popupType"></movie-popup>
|
<movie-popup v-if="moviePopupIsVisible" :id="popupID" :type="popupType"></movie-popup>
|
||||||
|
|
||||||
|
|
||||||
<darkmode-toggle />
|
|
||||||
|
|
||||||
<!-- Display the component assigned to the given route (default: home) -->
|
<!-- Display the component assigned to the given route (default: home) -->
|
||||||
<router-view class="content" :key="$route.fullPath"></router-view>
|
<router-view class="content"></router-view>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Navigation from '@/components/Navigation'
|
import Navigation from '@/components/Navigation.vue'
|
||||||
import MoviePopup from '@/components/MoviePopup'
|
import MoviePopup from '@/components/MoviePopup.vue'
|
||||||
import SearchInput from '@/components/SearchInput'
|
import SearchInput from '@/components/SearchInput.vue'
|
||||||
import DarkmodeToggle from '@/components/ui/darkmodeToggle'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'app',
|
name: 'app',
|
||||||
components: {
|
components: {
|
||||||
Navigation,
|
Navigation,
|
||||||
MoviePopup,
|
MoviePopup,
|
||||||
SearchInput,
|
SearchInput
|
||||||
DarkmodeToggle
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -74,7 +67,7 @@ export default {
|
|||||||
.content {
|
.content {
|
||||||
@include tablet-min{
|
@include tablet-min{
|
||||||
width: calc(100% - 95px);
|
width: calc(100% - 95px);
|
||||||
margin-top: $header-size;
|
padding-top: $header-size;
|
||||||
margin-left: 95px;
|
margin-left: 95px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
@@ -82,34 +75,29 @@ export default {
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
// @import "./src/scss/main";
|
@import "./src/scss/main";
|
||||||
@import "./src/scss/variables";
|
@import "./src/scss/variables";
|
||||||
@import "./src/scss/media-queries";
|
@import "./src/scss/media-queries";
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
}
|
||||||
|
|
||||||
*{
|
*{
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
html {
|
html, body{
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
body{
|
body{
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
font-family: 'Roboto', sans-serif;
|
font-family: 'Roboto', sans-serif;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
background: $background-color;
|
background: $c-light;
|
||||||
color: $text-color;
|
color: $c-dark;
|
||||||
transition: background-color .5s ease, color .5s ease;
|
|
||||||
&.hidden{
|
&.hidden{
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
h1,h2,h3 {
|
|
||||||
transition: color .5s ease;
|
|
||||||
}
|
|
||||||
a:any-link {
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
input, textarea, button{
|
input, textarea, button{
|
||||||
font-family: 'Roboto', sans-serif;
|
font-family: 'Roboto', sans-serif;
|
||||||
}
|
}
|
||||||
@@ -123,15 +111,12 @@ img{
|
|||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-scroll {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapper{
|
.wrapper{
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.header{
|
.header{
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
background: $c-white;
|
||||||
z-index: 15;
|
z-index: 15;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -143,6 +128,61 @@ img{
|
|||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
&__search{
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
z-index: 5;
|
||||||
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 55px;
|
||||||
|
@include tablet-min{
|
||||||
|
position: relative;
|
||||||
|
height: 75px;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
&-input{
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 15px 20px 15px 45px;
|
||||||
|
outline: none;
|
||||||
|
border: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
color: $c-dark;
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 16px;
|
||||||
|
@include tablet-min{
|
||||||
|
padding: 15px 30px 15px 60px;
|
||||||
|
}
|
||||||
|
@include tablet-landscape-min{
|
||||||
|
padding: 15px 30px 15px 80px;
|
||||||
|
}
|
||||||
|
@include desktop-min{
|
||||||
|
padding: 15px 30px 15px 90px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-arrow {
|
||||||
|
height: 19px;
|
||||||
|
width: 30px;
|
||||||
|
display: flex;
|
||||||
|
align-self: center;
|
||||||
|
margin-right: 30px;
|
||||||
|
|
||||||
|
-moz-transition: all 0.5s ease;
|
||||||
|
-webkit-transition: all 0.5s ease;
|
||||||
|
transition: all 0.5s ease;
|
||||||
|
|
||||||
|
&.down {
|
||||||
|
-ms-transform: rotate(180deg);
|
||||||
|
-moz-transform: rotate(180deg);
|
||||||
|
-webkit-transform: rotate(180deg);
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-input:focus + &-icon{
|
||||||
|
fill: $c-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// router view transition
|
// router view transition
|
||||||
|
|||||||
109
src/api.js
109
src/api.js
@@ -1,5 +1,5 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import storage from '@/storage'
|
import storage from '@/storage.js'
|
||||||
import config from '@/config.json'
|
import config from '@/config.json'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
|
||||||
@@ -25,8 +25,7 @@ const getMovie = (id, credits=false) => {
|
|||||||
url.searchParams.append('credits', true)
|
url.searchParams.append('credits', true)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fetch(url.href)
|
return axios.get(url.href)
|
||||||
.then(resp => resp.json())
|
|
||||||
.catch(error => { console.error(`api error getting movie: ${id}`); throw error })
|
.catch(error => { console.error(`api error getting movie: ${id}`); throw error })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,51 +42,24 @@ const getShow = (id, credits=false) => {
|
|||||||
url.searchParams.append('credits', true)
|
url.searchParams.append('credits', true)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fetch(url.href)
|
return axios.get(url.href)
|
||||||
.then(resp => resp.json())
|
|
||||||
.catch(error => { console.error(`api error getting show: ${id}`); throw error })
|
.catch(error => { console.error(`api error getting show: ${id}`); throw error })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches tmdb list by name.
|
* Fetches tmdb list by path.
|
||||||
* @param {string} name List the fetch
|
* @param {string} listPath Path of list
|
||||||
* @param {number} [page=1]
|
* @param {number} [page=1]
|
||||||
* @returns {object} Tmdb list response
|
* @returns {object} Tmdb list response
|
||||||
*/
|
*/
|
||||||
const getTmdbMovieListByName = (name, page=1) => {
|
const getTmdbListByPath = (listPath, page=1) => {
|
||||||
const url = new URL('v2/movie/' + name, SEASONED_URL)
|
const url = new URL(listPath, SEASONED_URL)
|
||||||
url.searchParams.append('page', page)
|
url.searchParams.append('page', page)
|
||||||
|
// TODO - remove. this is temporary fix for user-requests endpoint (also import)
|
||||||
const headers = { authorization: storage.token }
|
const headers = { authorization: storage.token }
|
||||||
|
|
||||||
return fetch(url.href, { headers: headers })
|
return axios.get(url.href, { headers: headers })
|
||||||
.then(resp => resp.json())
|
.catch(error => { console.error(`api error getting list: ${listPath}, page: ${page}`); throw error })
|
||||||
// .catch(error => { console.error(`api error getting list: ${name}, page: ${page}`); throw error })
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches requested items.
|
|
||||||
* @param {number} [page=1]
|
|
||||||
* @returns {object} Request response
|
|
||||||
*/
|
|
||||||
const getRequests = (page=1) => {
|
|
||||||
const url = new URL('v2/request', SEASONED_URL)
|
|
||||||
url.searchParams.append('page', page)
|
|
||||||
const headers = { authorization: storage.token }
|
|
||||||
|
|
||||||
return fetch(url.href, { headers: headers })
|
|
||||||
.then(resp => resp.json())
|
|
||||||
// .catch(error => { console.error(`api error getting list: ${name}, page: ${page}`); throw error })
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const getUserRequests = (page=1) => {
|
|
||||||
const url = new URL('v1/user/requests', SEASONED_URL)
|
|
||||||
url.searchParams.append('page', page)
|
|
||||||
|
|
||||||
const headers = { authorization: localStorage.getItem('token') }
|
|
||||||
|
|
||||||
return fetch(url.href, { headers })
|
|
||||||
.then(resp => resp.json())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,8 +73,7 @@ const searchTmdb = (query, page=1) => {
|
|||||||
url.searchParams.append('query', query)
|
url.searchParams.append('query', query)
|
||||||
url.searchParams.append('page', page)
|
url.searchParams.append('page', page)
|
||||||
|
|
||||||
return fetch(url.href)
|
return axios.get(url.href)
|
||||||
.then(resp => resp.json())
|
|
||||||
.catch(error => { console.error(`api error searching: ${query}, page: ${page}`); throw error })
|
.catch(error => { console.error(`api error searching: ${query}, page: ${page}`); throw error })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,13 +86,12 @@ const searchTmdb = (query, page=1) => {
|
|||||||
* @returns {object} Torrent response
|
* @returns {object} Torrent response
|
||||||
*/
|
*/
|
||||||
const searchTorrents = (query, authorization_token) => {
|
const searchTorrents = (query, authorization_token) => {
|
||||||
const url = new URL('/api/v1/pirate/search', SEASONED_URL)
|
const url = new URL('v1/pirate/search', SEASONED_URL)
|
||||||
url.searchParams.append('query', query)
|
url.searchParams.append('query', query)
|
||||||
|
|
||||||
const headers = { authorization: storage.token }
|
const headers = { authorization: storage.token }
|
||||||
|
|
||||||
return fetch(url.href, { headers: headers })
|
return axios.get(url.href, { headers: headers })
|
||||||
.then(resp => resp.json())
|
|
||||||
.catch(error => { console.error(`api error searching torrents: ${query}`); throw error })
|
.catch(error => { console.error(`api error searching torrents: ${query}`); throw error })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,23 +105,15 @@ const searchTorrents = (query, authorization_token) => {
|
|||||||
const addMagnet = (magnet, name, tmdb_id) => {
|
const addMagnet = (magnet, name, tmdb_id) => {
|
||||||
const url = new URL('v1/pirate/add', SEASONED_URL)
|
const url = new URL('v1/pirate/add', SEASONED_URL)
|
||||||
|
|
||||||
const body = JSON.stringify({
|
const body = {
|
||||||
magnet: magnet,
|
magnet: magnet,
|
||||||
name: name,
|
name: name,
|
||||||
tmdb_id: tmdb_id
|
tmdb_id: tmdb_id
|
||||||
})
|
|
||||||
const headers = {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
authorization: storage.token
|
|
||||||
}
|
}
|
||||||
|
const headers = { authorization: storage.token }
|
||||||
|
|
||||||
return fetch(url.href, {
|
return axios.post(url.href, body, { headers: headers })
|
||||||
method: 'POST',
|
.catch(error => { console.error(`api error adding magnet: ${name}`); throw error })
|
||||||
headers,
|
|
||||||
body
|
|
||||||
})
|
|
||||||
.then(resp => resp.json())
|
|
||||||
.catch(error => { console.error(`api error adding magnet: ${name} ${error}`); throw error })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - Plex/Request - - -
|
// - - - Plex/Request - - -
|
||||||
@@ -213,7 +175,9 @@ const getRequestStatus = (id, type, authorization_token=undefined) => {
|
|||||||
// - - - Authenticate with plex - - -
|
// - - - Authenticate with plex - - -
|
||||||
|
|
||||||
const plexAuthenticate = (username, password) => {
|
const plexAuthenticate = (username, password) => {
|
||||||
const url = new URL('https://plex.tv/api/v2/users/signin')
|
const url = new URL('https://plex.tv/users/sign_in.json')
|
||||||
|
url.searchParams.append('user[login]', username)
|
||||||
|
url.searchParams.append('user[password]', password)
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@@ -224,17 +188,7 @@ const plexAuthenticate = (username, password) => {
|
|||||||
'X-Plex-Client-Identifier': '123'
|
'X-Plex-Client-Identifier': '123'
|
||||||
}
|
}
|
||||||
|
|
||||||
let formData = new FormData()
|
return axios.post(url.href, { headers: headers })
|
||||||
formData.set('login', username)
|
|
||||||
formData.set('password', password)
|
|
||||||
formData.set('rememberMe', false)
|
|
||||||
|
|
||||||
return axios({
|
|
||||||
method: 'POST',
|
|
||||||
url: url.href,
|
|
||||||
headers: headers,
|
|
||||||
data: formData
|
|
||||||
})
|
|
||||||
.catch(error => { console.error(`api error authentication plex: ${username}`); throw error })
|
.catch(error => { console.error(`api error authentication plex: ${username}`); throw error })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,10 +196,9 @@ const plexAuthenticate = (username, password) => {
|
|||||||
// - - - Random emoji - - -
|
// - - - Random emoji - - -
|
||||||
|
|
||||||
const getEmoji = () => {
|
const getEmoji = () => {
|
||||||
const url = new URL('v1/emoji', SEASONED_URL)
|
const url = path.join(SEASONED_URL, 'v1/emoji')
|
||||||
|
|
||||||
return fetch(url.href)
|
return axios.get(url)
|
||||||
.then(resp => resp.json())
|
|
||||||
.catch(error => { console.log('api error getting emoji'); throw error })
|
.catch(error => { console.log('api error getting emoji'); throw error })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,18 +252,4 @@ const elasticSearchMoviesAndShows = (query) => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
export {
|
export { getMovie, getShow, getTmdbListByPath, searchTmdb, searchTorrents, addMagnet, request, getRequestStatus, plexAuthenticate, getEmoji, elasticSearchMoviesAndShows }
|
||||||
getMovie,
|
|
||||||
getShow,
|
|
||||||
getTmdbMovieListByName,
|
|
||||||
searchTmdb,
|
|
||||||
getUserRequests,
|
|
||||||
getRequests,
|
|
||||||
searchTorrents,
|
|
||||||
addMagnet,
|
|
||||||
request,
|
|
||||||
getRequestStatus,
|
|
||||||
plexAuthenticate,
|
|
||||||
getEmoji,
|
|
||||||
elasticSearchMoviesAndShows
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,39 +1,72 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="not-found">
|
<section class="not-found">
|
||||||
<h1 class="not-found__title">Page Not Found</h1>
|
<div class="not-found__content">
|
||||||
|
<h2 class="not-found__title">Page Not Found</h2>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<script>
|
||||||
@import "./src/scss/variables";
|
import storage from '../storage.js'
|
||||||
@import "./src/scss/media-queries";
|
export default {
|
||||||
|
created(){
|
||||||
.not-found {
|
document.title = 'Page Not Found' + storage.pageTitlePostfix;
|
||||||
display: flex;
|
|
||||||
height: calc(100vh - var(--header-size));
|
|
||||||
width: 100%;
|
|
||||||
background: url('~assets/pulp-fiction.jpg') no-repeat 50% 50%;
|
|
||||||
background-size: cover;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
height: calc(100vh - var(--header-size));
|
|
||||||
width: 100%;
|
|
||||||
background: $background-40;
|
|
||||||
}
|
|
||||||
&__title {
|
|
||||||
padding-top: 40vh;
|
|
||||||
font-size: 2rem;
|
|
||||||
font-weight: 500;
|
|
||||||
color: $text-color;
|
|
||||||
position: relative;
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
@include tablet-min {
|
|
||||||
font-size: 2.3rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "./src/scss/variables";
|
||||||
|
@import "./src/scss/media-queries";
|
||||||
|
.not-found{
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100vh - 100px);
|
||||||
|
background: url('~assets/pulp-fiction.jpg') no-repeat 50% 50%;
|
||||||
|
background-size: cover;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
@include tablet-min{
|
||||||
|
height: calc(100vh - 75px);
|
||||||
|
}
|
||||||
|
&:before{
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba($c-light, 0.7);
|
||||||
|
}
|
||||||
|
&-shortList{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
&__content{
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 20px;
|
||||||
|
text-align: center;
|
||||||
|
@include tablet-min{
|
||||||
|
padding: 20px 0 0 0;
|
||||||
|
}
|
||||||
|
&-shortList {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__title{
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $c-dark;
|
||||||
|
position: relative;
|
||||||
|
margin: 0;
|
||||||
|
@include tablet-min{
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__button{
|
||||||
|
position: relative;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -2,84 +2,27 @@
|
|||||||
<section>
|
<section>
|
||||||
<LandingBanner />
|
<LandingBanner />
|
||||||
|
|
||||||
<div v-for="list in lists">
|
<movies-list v-for="item in homepageLists" :propList="item" :shortList="true"></movies-list>
|
||||||
<list-header :title="list.title" :link="'/list/' + list.route" />
|
|
||||||
|
|
||||||
<results-list :results="list.data" :shortList="true" />
|
|
||||||
<loader v-if="!list.data.length" />
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import LandingBanner from '@/components/LandingBanner'
|
import storage from '../storage.js'
|
||||||
import ListHeader from '@/components/ListHeader'
|
import LandingBanner from '@/components/LandingBanner.vue'
|
||||||
import ResultsList from '@/components/ResultsList'
|
import MoviesList from './MoviesList.vue'
|
||||||
import Loader from '@/components/ui/Loader'
|
|
||||||
|
|
||||||
import { getTmdbMovieListByName, getRequests } from '@/api'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'home',
|
name: 'home',
|
||||||
components: { LandingBanner, ResultsList, ListHeader, Loader },
|
components: { LandingBanner, MoviesList },
|
||||||
data(){
|
data(){
|
||||||
return {
|
return {
|
||||||
imageFile: 'dist/pulp-fiction.jpg',
|
homepageLists: storage.homepageLists,
|
||||||
requests: [],
|
imageFile: 'dist/pulp-fiction.jpg'
|
||||||
nowplaying: [],
|
|
||||||
upcoming: [],
|
|
||||||
popular: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
lists() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
title: 'Requests',
|
|
||||||
route: 'request',
|
|
||||||
data: this.requests
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Now playing',
|
|
||||||
route: 'now_playing',
|
|
||||||
data: this.nowplaying
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Upcoming',
|
|
||||||
route: 'upcoming',
|
|
||||||
data: this.upcoming
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Popular',
|
|
||||||
route: 'popular',
|
|
||||||
data: this.popular
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
fetchRequests() {
|
|
||||||
getRequests()
|
|
||||||
.then(results => this.requests = results.results)
|
|
||||||
},
|
|
||||||
fetchNowPlaying() {
|
|
||||||
getTmdbMovieListByName('now_playing')
|
|
||||||
.then(results => this.nowplaying = results.results)
|
|
||||||
},
|
|
||||||
fetchUpcoming() {
|
|
||||||
getTmdbMovieListByName('upcoming')
|
|
||||||
.then(results => this.upcoming = results.results)
|
|
||||||
},
|
|
||||||
fetchPopular() {
|
|
||||||
getTmdbMovieListByName('popular')
|
|
||||||
.then(results => this.popular = results.results)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created(){
|
created(){
|
||||||
this.fetchRequests()
|
document.title = 'TMDb';
|
||||||
this.fetchNowPlaying()
|
storage.backTitle = document.title;
|
||||||
this.fetchUpcoming()
|
|
||||||
this.fetchPopular()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -26,6 +26,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -42,11 +43,10 @@ header {
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: 50% 50%;
|
background-position: 50% 50%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
background-color: $c-dark;
|
||||||
@include tablet-min {
|
@include tablet-min {
|
||||||
height: 284px;
|
height: 284px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -54,14 +54,12 @@ header {
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: $background-70;
|
background: rgba($c-light, 0.7);
|
||||||
transition: background-color .5s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: color .5s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
@@ -69,9 +67,8 @@ header {
|
|||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.5px;
|
||||||
color: $text-color;
|
color: $c-dark;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
@include tablet-min{
|
@include tablet-min{
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
}
|
}
|
||||||
@@ -81,12 +78,35 @@ header {
|
|||||||
display: block;
|
display: block;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
color: $text-color-70;
|
color: $c-dark;
|
||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
|
|
||||||
@include tablet-min{
|
@include tablet-min{
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
text-decoration: none;
|
||||||
|
color: $c-dark;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 300;
|
||||||
|
opacity: 0.7;
|
||||||
|
transition: opacity 0.5s ease;
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
&-icon {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 2px;
|
||||||
|
width: 16px;
|
||||||
|
height: 15px;
|
||||||
|
fill: $c-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
530
src/components/LargeMovie.vue
Normal file
530
src/components/LargeMovie.vue
Normal file
@@ -0,0 +1,530 @@
|
|||||||
|
<template>
|
||||||
|
<div class="wrapper">
|
||||||
|
<div class="backdrop" :style="backdropStyle"></div>
|
||||||
|
|
||||||
|
<div class="title-container">
|
||||||
|
<h1> {{ title }} </h1>
|
||||||
|
<h2> ({{ movie.year }}) </h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="opacity-overlay-bottom"></div>
|
||||||
|
|
||||||
|
<div class="info-container">
|
||||||
|
<div class="button">
|
||||||
|
<svg class="action-icon">
|
||||||
|
<use :xlink:href="'#iconSent'"></use>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<span>Request movie</span>
|
||||||
|
</div>
|
||||||
|
<div class="button--grey">
|
||||||
|
<svg class="action-icon">
|
||||||
|
<use :xlink:href="'#icon_info'"></use>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<span>See more info</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "./src/scss/variables";
|
||||||
|
|
||||||
|
$blue: rgb(0,122,255);
|
||||||
|
$blue-hover: rgb(10,132,255);
|
||||||
|
$grey: rgb(44,44,46);
|
||||||
|
$grey-hover: rgb(58,58,60);
|
||||||
|
|
||||||
|
.action-icon {
|
||||||
|
transform: translateY(-0.2px);
|
||||||
|
width: 19px;
|
||||||
|
height: 19px;
|
||||||
|
margin-right: 8px;
|
||||||
|
// fill: rgba($c-dark, 0.5);
|
||||||
|
fill: white;
|
||||||
|
transition: fill 0.5s ease, transform 0.5s ease;
|
||||||
|
&.waiting {
|
||||||
|
transform: scale(0.8, 0.8);
|
||||||
|
}
|
||||||
|
&.pending {
|
||||||
|
fill: #f8bd2d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin button {
|
||||||
|
width: 300px;
|
||||||
|
min-height: 50px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: $blue;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
transition: transform 0.5s ease, box-shadow 0.3s ease;
|
||||||
|
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $blue-hover;
|
||||||
|
transform: scale(1.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:last-of-type) {
|
||||||
|
margin-bottom: 0.7rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-container {
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
padding-left: 3rem;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 5rem;
|
||||||
|
display: inline;
|
||||||
|
color: $c-green;
|
||||||
|
-webkit-text-stroke: 1.1px $c-green-dark;
|
||||||
|
// border: 1px solid $c-green;
|
||||||
|
// text-shadow: -1px 0 $c-green-dark, 0 1px $c-green-dark, 1px 0 $c-green-dark, 0 -1px $c-green-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 2.7rem;
|
||||||
|
display: inline;
|
||||||
|
color: $c-green;
|
||||||
|
-webkit-text-stroke: 1.1px $c-green-dark;
|
||||||
|
// border: 1px solid $c-green;
|
||||||
|
// text-shadow: -1px 0 $c-green-dark, 0 1px $c-green-dark, 1px 0 $c-green-dark, 0 -1px $c-green-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-container {
|
||||||
|
width: calc(100% - 80px);
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
// background-color: red;
|
||||||
|
margin: 40px;
|
||||||
|
|
||||||
|
.button {
|
||||||
|
@include button;
|
||||||
|
|
||||||
|
&--grey {
|
||||||
|
@include button;
|
||||||
|
background-color: $grey;
|
||||||
|
|
||||||
|
&:hover{
|
||||||
|
background-color: $grey-hover;
|
||||||
|
}
|
||||||
|
|
||||||
|
span { color: white; }
|
||||||
|
}
|
||||||
|
|
||||||
|
span { color: white; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
$width: 88vw;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
left: calc(50% - #{$width} / 2);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: $width;
|
||||||
|
height: 82vh;
|
||||||
|
// -webkit-mask-size: auto 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.backdrop {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
// -webkit-mask-image: linear-gradient(to top, transparent 5%, black);
|
||||||
|
border-radius: 0 0 8px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opacity-overlay-bottom {
|
||||||
|
// background-color: #0c0a09;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
height: 55%;
|
||||||
|
width: 100%;
|
||||||
|
align-self: flex-end;
|
||||||
|
-webkit-mask: linear-gradient(to bottom, transparent 0%, black 100%);
|
||||||
|
mask: linear-gradient(to top, transparent 25%, black 75%);
|
||||||
|
-webkit-mask: linear-gradient(transparent, black);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
|
border-radius: 0 0 8px 8px;
|
||||||
|
|
||||||
|
// background: linear-gradient(180deg, rgba(0,0,0,0.29315476190476186) 0%, rgba(0,0,0,1) 100%, rgba(9,9,121,1) 100%, rgba(0,0,0,1) 100%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import storage from '@/storage.js'
|
||||||
|
import img from '@/directives/v-image.js'
|
||||||
|
import TorrentList from './TorrentList.vue'
|
||||||
|
import Person from './Person.vue'
|
||||||
|
import SidebarAction from './movie/SidebarAction.vue'
|
||||||
|
|
||||||
|
import LoadingPlaceholder from './ui/LoadingPlaceholder.vue'
|
||||||
|
|
||||||
|
import { getMovie, getShow, request, getRequestStatus } from '@/api.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: ['id', 'type'],
|
||||||
|
components: { TorrentList, Person, LoadingPlaceholder, SidebarAction },
|
||||||
|
directives: { img: img }, // TODO decide to remove or use
|
||||||
|
computed: {
|
||||||
|
backdropStyle() {
|
||||||
|
let value = ''
|
||||||
|
if (this.movie && this.backdrop) {
|
||||||
|
value = 'url(' + this.ASSET_URL + this.ASSET_SIZES[2] + this.backdrop + ')'
|
||||||
|
// value = 'url(https://kevinmidboe.com/assets/arrival.jpg)'
|
||||||
|
console.log('value', value)
|
||||||
|
}
|
||||||
|
console.log('bool', this.backdrop)
|
||||||
|
return { 'background-image': value, 'background-size': 'cover', 'background-repeat': 'no-repeat'}
|
||||||
|
return { 'background-image': movie && backdrop !== null ? 'url(' + this.ASSET_URL + ASSET_SIZES[1] + backdrop + ')' : '' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data(){
|
||||||
|
return{
|
||||||
|
ASSET_URL: 'https://image.tmdb.org/t/p/',
|
||||||
|
ASSET_SIZES: ['w500', 'w780', 'original'],
|
||||||
|
movie: undefined,
|
||||||
|
title: undefined,
|
||||||
|
poster: undefined,
|
||||||
|
backdrop: undefined,
|
||||||
|
matched: false,
|
||||||
|
userLoggedIn: storage.sessionId ? true : false,
|
||||||
|
requested: false,
|
||||||
|
admin: localStorage.getItem('admin'),
|
||||||
|
showTorrents: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
parseResponse(resp) {
|
||||||
|
const l = {fe: 0}
|
||||||
|
|
||||||
|
console.log('resp', resp)
|
||||||
|
let movie = resp.data;
|
||||||
|
this.movie = { ...movie }
|
||||||
|
this.title = movie.title
|
||||||
|
this.poster = movie.poster
|
||||||
|
this.backdrop = movie.backdrop
|
||||||
|
this.matched = movie.existsInPlex
|
||||||
|
this.checkIfRequested(movie)
|
||||||
|
.then(status => this.requested = status)
|
||||||
|
|
||||||
|
document.title = movie.title + storage.pageTitlePostfix
|
||||||
|
},
|
||||||
|
async checkIfRequested(movie) {
|
||||||
|
return await getRequestStatus(movie.id, movie.type)
|
||||||
|
},
|
||||||
|
nestedDataToString(data) {
|
||||||
|
let nestedArray = []
|
||||||
|
data.forEach(item => nestedArray.push(item));
|
||||||
|
return nestedArray.join(', ');
|
||||||
|
},
|
||||||
|
sendRequest(){
|
||||||
|
request(this.id, this.type, storage.token)
|
||||||
|
.then(resp => {
|
||||||
|
if (resp.success) {
|
||||||
|
this.requested = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
openTmdb(){
|
||||||
|
const tmdbType = this.type === 'show' ? 'tv' : this.type
|
||||||
|
window.location.href = 'https://www.themoviedb.org/' + tmdbType + '/' + this.id
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
id: function(val){
|
||||||
|
if (this.type === 'movie') {
|
||||||
|
this.fetchMovie(val);
|
||||||
|
} else {
|
||||||
|
this.fetchShow(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
document.title = this.prevDocumentTitle
|
||||||
|
},
|
||||||
|
created(){
|
||||||
|
console.log('👋')
|
||||||
|
this.prevDocumentTitle = document.title
|
||||||
|
|
||||||
|
if (this.type === 'movie') {
|
||||||
|
getMovie(this.id)
|
||||||
|
.then(this.parseResponse)
|
||||||
|
.catch(error => {
|
||||||
|
this.$router.push({ name: '404' });
|
||||||
|
})
|
||||||
|
} else if (this.type === 'show') {
|
||||||
|
getShow(this.id)
|
||||||
|
.then(this.parseResponse)
|
||||||
|
.catch(error => {
|
||||||
|
this.$router.push({ name: '404' });
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.error('No type found, unable to fetch item')
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('admin: ', this.admin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "./src/scss/loading-placeholder";
|
||||||
|
@import "./src/scss/variables";
|
||||||
|
@import "./src/scss/media-queries";
|
||||||
|
|
||||||
|
.movie {
|
||||||
|
&__wrap {
|
||||||
|
display: flex;
|
||||||
|
&--header {
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
&--main {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-direction: column;
|
||||||
|
@include tablet-min{
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__header {
|
||||||
|
height: 250px;
|
||||||
|
position: relative;
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 50% 50%;
|
||||||
|
background-color: $c-dark;
|
||||||
|
@include tablet-min {
|
||||||
|
height: 350px;
|
||||||
|
}
|
||||||
|
&:before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba($c-dark, 0.85);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__poster {
|
||||||
|
display: none;
|
||||||
|
@include tablet-min {
|
||||||
|
background: $c-white;
|
||||||
|
height: 0;
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
width: calc(45% - 40px);
|
||||||
|
top: 40px;
|
||||||
|
left: 40px;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__img {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.97) translateZ(0);
|
||||||
|
transition: opacity 0.5s ease, transform 0.5s ease;
|
||||||
|
|
||||||
|
&.is-loaded {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
position: relative;
|
||||||
|
padding: 20px;
|
||||||
|
color: $c-green;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
@include tablet-min {
|
||||||
|
width: 55%;
|
||||||
|
text-align: left;
|
||||||
|
margin-left: 45%;
|
||||||
|
padding: 30px 30px 30px 40px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.4;
|
||||||
|
font-size: 24px;
|
||||||
|
@include tablet-min {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
display: block;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 300;
|
||||||
|
color: rgba($c-white, 0.7);
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__main {
|
||||||
|
background: $c-light;
|
||||||
|
min-height: calc(100vh - 250px);
|
||||||
|
@include tablet-min {
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
&__actions {
|
||||||
|
text-align: center;
|
||||||
|
// min-height: 394px;
|
||||||
|
width: 100%;
|
||||||
|
order: 2;
|
||||||
|
padding: 20px;
|
||||||
|
border-top: 1px solid rgba($c-dark, 0.05);
|
||||||
|
@include tablet-min {
|
||||||
|
order: 1;
|
||||||
|
width: 45%;
|
||||||
|
padding: 185px 0 40px 40px;
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
&-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
text-decoration: none;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: rgba($c-dark, 0.5);
|
||||||
|
transition: color 0.5s ease;
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 5px 0;
|
||||||
|
border-bottom: 1px solid rgba($c-dark, 0.05);
|
||||||
|
&:hover {
|
||||||
|
color: rgba($c-dark, 0.75);
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
color: $c-dark;
|
||||||
|
}
|
||||||
|
&.pending {
|
||||||
|
color: #f8bd2d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
margin: 0 10px 0 0;
|
||||||
|
fill: rgba($c-dark, 0.5);
|
||||||
|
transition: fill 0.5s ease, transform 0.5s ease;
|
||||||
|
&.waiting {
|
||||||
|
transform: scale(0.8, 0.8);
|
||||||
|
}
|
||||||
|
&.pending {
|
||||||
|
fill: #f8bd2d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-link:hover &-icon {
|
||||||
|
fill: rgba($c-dark, 0.75);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
&-link.active &-icon {
|
||||||
|
fill: $c-green;
|
||||||
|
}
|
||||||
|
&-text {
|
||||||
|
display: block;
|
||||||
|
padding-top: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin:4.4px;
|
||||||
|
margin-left: -3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__info {
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
order: 1;
|
||||||
|
@include tablet-min {
|
||||||
|
order: 2;
|
||||||
|
padding: 40px;
|
||||||
|
width: 55%;
|
||||||
|
margin-left: 45%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__actions + &__info {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
&__description {
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.8;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
@include tablet-min {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__details {
|
||||||
|
&-block {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
&-block:not(:last-child) {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
margin-right: 20px;
|
||||||
|
@include tablet-min {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
margin-right: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-title {
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 400;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $c-green;
|
||||||
|
@include tablet-min {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-text {
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__admin {
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
order: 2;
|
||||||
|
@include tablet-min {
|
||||||
|
order: 3;
|
||||||
|
padding: 40px;
|
||||||
|
padding-top: 0px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
&-title {
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 400;
|
||||||
|
text-transform: uppercase;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $c-green;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
@include tablet-min {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
<template>
|
|
||||||
<header :class="{ 'sticky': sticky }">
|
|
||||||
<h2>{{ title }}</h2>
|
|
||||||
|
|
||||||
<span v-if="info" class="result-count">{{ info }}</span>
|
|
||||||
<router-link v-else-if="link" :to="link" class='view-more'>
|
|
||||||
View All
|
|
||||||
</router-link>
|
|
||||||
</header>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
sticky: {
|
|
||||||
type: Boolean,
|
|
||||||
required: false,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
info: {
|
|
||||||
type: String,
|
|
||||||
required: false
|
|
||||||
},
|
|
||||||
link: {
|
|
||||||
type: String,
|
|
||||||
required: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import './src/scss/variables';
|
|
||||||
@import './src/scss/media-queries';
|
|
||||||
|
|
||||||
header {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 1.8rem 12px;
|
|
||||||
|
|
||||||
&.sticky {
|
|
||||||
background-color: $background-color;
|
|
||||||
|
|
||||||
position: sticky;
|
|
||||||
position: -webkit-sticky;
|
|
||||||
top: $header-size;
|
|
||||||
z-index: 4;
|
|
||||||
|
|
||||||
padding-bottom: 1rem;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 300;
|
|
||||||
text-transform: capitalize;
|
|
||||||
line-height: 18px;
|
|
||||||
margin: 0;
|
|
||||||
color: $text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.view-more {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 300;
|
|
||||||
letter-spacing: .5px;
|
|
||||||
color: $text-color-70;
|
|
||||||
text-decoration: none;
|
|
||||||
transition: color .5s ease;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:after{
|
|
||||||
content: " →";
|
|
||||||
}
|
|
||||||
&:hover{
|
|
||||||
color: $text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.result-count {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 300;
|
|
||||||
letter-spacing: .5px;
|
|
||||||
color: $text-color;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include tablet-min {
|
|
||||||
padding-left: 1.25rem;;
|
|
||||||
}
|
|
||||||
@include desktop-lg-min {
|
|
||||||
padding-left: 1.75rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
|
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<list-header :title="listTitle" :info="resultCount" :sticky="true" />
|
|
||||||
|
|
||||||
<results-list :results="results" v-if="results" />
|
|
||||||
|
|
||||||
<loader v-if="!results.length" />
|
|
||||||
|
|
||||||
<div v-if="page < totalPages" class="fullwidth-button">
|
|
||||||
<seasoned-button @click="loadMore">load more</seasoned-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import ListHeader from '@/components/ListHeader'
|
|
||||||
import ResultsList from '@/components/ResultsList'
|
|
||||||
import SeasonedButton from '@/components/ui/SeasonedButton'
|
|
||||||
import Loader from '@/components/ui/Loader'
|
|
||||||
import { getTmdbMovieListByName, getRequests } from '@/api'
|
|
||||||
import store from '@/store'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: { ListHeader, ResultsList, SeasonedButton, Loader },
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
legalTmdbLists: [ 'now_playing', 'upcoming', 'popular' ],
|
|
||||||
results: [],
|
|
||||||
page: 1,
|
|
||||||
totalPages: 0,
|
|
||||||
totalResults: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
listTitle() {
|
|
||||||
if (this.results.length === 0)
|
|
||||||
return ''
|
|
||||||
|
|
||||||
const routeListName = this.$route.params.name
|
|
||||||
console.log('routelistname', routeListName)
|
|
||||||
return routeListName.includes('_') ? routeListName.split('_').join(' ') : routeListName
|
|
||||||
},
|
|
||||||
resultCount() {
|
|
||||||
if (this.results.length === 0)
|
|
||||||
return ''
|
|
||||||
|
|
||||||
const loadedResults = this.results.length
|
|
||||||
const totalResults = this.totalResults < 10000 ? this.totalResults : '∞'
|
|
||||||
return `${loadedResults} of ${totalResults} results`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
loadMore() {
|
|
||||||
console.log(this.$route)
|
|
||||||
this.page++
|
|
||||||
|
|
||||||
window.history.replaceState({}, 'search', `/#/${this.$route.fullPath}?page=${this.page}`)
|
|
||||||
this.init()
|
|
||||||
},
|
|
||||||
init() {
|
|
||||||
const routeListName = this.$route.params.name
|
|
||||||
|
|
||||||
if (routeListName === 'request') {
|
|
||||||
getRequests(this.page)
|
|
||||||
.then(results => {
|
|
||||||
this.results = this.results.concat(...results.results)
|
|
||||||
this.page = results.page
|
|
||||||
this.totalPages = results.total_pages
|
|
||||||
this.totalResults = results.total_results
|
|
||||||
})
|
|
||||||
} else if (this.legalTmdbLists.includes(routeListName)) {
|
|
||||||
getTmdbMovieListByName(routeListName, this.page)
|
|
||||||
.then(results => {
|
|
||||||
this.results = this.results.concat(...results.results)
|
|
||||||
this.page = results.page
|
|
||||||
this.totalPages = results.total_pages
|
|
||||||
this.totalResults = results.total_results
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// TODO handle if list is not found
|
|
||||||
console.log('404 this is not a tmdb list')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
if (this.results.length === 0)
|
|
||||||
this.init()
|
|
||||||
|
|
||||||
store.dispatch('documentTitle/updateTitle', `${this.$router.history.current.name} ${this.$route.params.name}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.fullwidth-button {
|
|
||||||
width: 100%;
|
|
||||||
margin: 1rem 0;
|
|
||||||
padding-bottom: 2rem;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
<section class="movie">
|
<section class="movie">
|
||||||
|
|
||||||
<!-- HEADER w/ POSTER -->
|
<!-- HEADER w/ POSTER -->
|
||||||
<header class="movie__header" :style="{ 'background-image': movie && backdrop !== null ? 'url(' + ASSET_URL + ASSET_SIZES[1] + backdrop + ')' : '' }" :class="compact ? 'compact' : ''" @click="compact=!compact">
|
<header class="movie__header" :style="{ 'background-image': movie && backdrop !== null ? 'url(' + ASSET_URL + ASSET_SIZES[1] + backdrop + ')' : '' }">
|
||||||
<div class="movie__wrap movie__wrap--header">
|
<div class="movie__wrap movie__wrap--header">
|
||||||
<figure class="movie__poster">
|
<figure class="movie__poster">
|
||||||
<img v-if="movie && poster === null"
|
<img v-if="movie && poster === null"
|
||||||
@@ -20,8 +20,7 @@
|
|||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
<div class="movie__title">
|
<div class="movie__title">
|
||||||
<h1 v-if="movie">{{ movie.title }}</h1>
|
<h1>{{ title }}</h1>
|
||||||
<loading-placeholder v-else :count="1" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -32,31 +31,23 @@
|
|||||||
|
|
||||||
<!-- SIDEBAR ACTIONS -->
|
<!-- SIDEBAR ACTIONS -->
|
||||||
<div class="movie__actions" v-if="movie">
|
<div class="movie__actions" v-if="movie">
|
||||||
<sidebar-list-element :iconRef="'#iconNot_exsits'" :active="requested"
|
|
||||||
:iconRefActive="'#iconExists'" :textActive="'Already in plex 🎉'" :class="requested ? 'rotate-180' : null">
|
|
||||||
Not yet in plex
|
|
||||||
</sidebar-list-element>
|
|
||||||
|
|
||||||
<sidebar-list-element @click="sendRequest" :iconRef="'#iconSent'"
|
<sidebar-action
|
||||||
:active="requested" :textActive="'Requested to be downloaded'">
|
:text="'Not yet in plex'" :iconRef="'#iconNot_exsits'"
|
||||||
Request to be downloaded?
|
:textActive="'Already in plex 🎉'" :iconRefActive="'#iconExists'"
|
||||||
</sidebar-list-element>
|
:active="matched"></sidebar-action>
|
||||||
|
<sidebar-action
|
||||||
<sidebar-list-element v-if="admin" @click="showTorrents=!showTorrents"
|
@click="sendRequest"
|
||||||
:iconRef="'#icon_torrents'" :active="showTorrents"
|
:text="'Request to be downloaded?'" :iconRef="'#iconSent'"
|
||||||
:supplementaryText="numberOfTorrentResults">
|
:textActive="'Requested to be downloaded'"
|
||||||
Search for torrents
|
:active="requested"></sidebar-action>
|
||||||
</sidebar-list-element>
|
<sidebar-action
|
||||||
|
v-if="admin" @click="showTorrents=!showTorrents"
|
||||||
<sidebar-list-element @click="showIssueForm = !showIssueForm"
|
:text="'Search for torrents'" :iconRef="'#icon_torrents'"
|
||||||
:iconRef="null"
|
:active="showTorrents"></sidebar-action>
|
||||||
:active="showIssueForm">
|
<sidebar-action
|
||||||
⚠️ Report an issue!
|
@click="openTmdb()"
|
||||||
</sidebar-list-element>
|
:iconRef="'#icon_info'" :text="'See more info'"></sidebar-action>
|
||||||
|
|
||||||
<sidebar-list-element @click="openTmdb" :iconRef="'#icon_info'">
|
|
||||||
See more info
|
|
||||||
</sidebar-list-element>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Loading placeholder -->
|
<!-- Loading placeholder -->
|
||||||
@@ -69,16 +60,14 @@
|
|||||||
|
|
||||||
<!-- MOVIE INFO -->
|
<!-- MOVIE INFO -->
|
||||||
<div class="movie__info">
|
<div class="movie__info">
|
||||||
|
<div class="movie__description" v-if="movie"> {{ movie.overview }}</div>
|
||||||
|
|
||||||
<!-- Loading placeholder -->
|
<!-- Loading placeholder -->
|
||||||
<div v-if="!movie" class="movie__description">
|
<div v-else class="movie__description">
|
||||||
<loading-placeholder :count="12" />
|
<loading-placeholder :count="12" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="movie__details" v-if="movie && !showIssueForm">
|
<div class="movie__details" v-if="movie">
|
||||||
<div class="movie__description">
|
|
||||||
{{ movie.overview }}
|
|
||||||
</div>
|
|
||||||
<div v-if="movie.year" class="movie__details-block">
|
<div v-if="movie.year" class="movie__details-block">
|
||||||
<h2 class="movie__details-title">Release Date</h2>
|
<h2 class="movie__details-title">Release Date</h2>
|
||||||
<div class="movie__details-text">{{ movie.year }}</div>
|
<div class="movie__details-text">{{ movie.year }}</div>
|
||||||
@@ -100,17 +89,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div v-if="showIssueForm" class="issueForm">
|
|
||||||
<h2 class="movie__details-title">Report an issue</h2>
|
|
||||||
<RadioButtons class="issueOptions"
|
|
||||||
:options="issueOptions"
|
|
||||||
:value.sync="selectedIssue" />
|
|
||||||
<TextArea title="Additional information" :rows="3"
|
|
||||||
placeholder="Placeholder text" />
|
|
||||||
<SeasonedButton @click="reportIssue">Report issue</SeasonedButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- TODO: change this classname, this is general -->
|
<!-- TODO: change this classname, this is general -->
|
||||||
@@ -133,30 +111,19 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import storage from '@/storage'
|
import storage from '@/storage.js'
|
||||||
import img from '@/directives/v-image'
|
import img from '@/directives/v-image.js'
|
||||||
import TorrentList from './TorrentList'
|
import TorrentList from './TorrentList.vue'
|
||||||
import Person from './Person'
|
import Person from './Person.vue'
|
||||||
import SidebarListElement from './ui/sidebarListElem'
|
import SidebarAction from './movie/SidebarAction.vue'
|
||||||
import store from '@/store'
|
|
||||||
import LoadingPlaceholder from './ui/LoadingPlaceholder'
|
|
||||||
import RadioButtons from './ui/RadioButtons'
|
|
||||||
import TextArea from './ui/TextArea'
|
|
||||||
import SeasonedButton from './ui/SeasonedButton'
|
|
||||||
|
|
||||||
import { getMovie, getShow, request, getRequestStatus } from '@/api'
|
import LoadingPlaceholder from './ui/LoadingPlaceholder.vue'
|
||||||
|
|
||||||
|
import { getMovie, getShow, request, getRequestStatus } from '@/api.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['id', 'type'],
|
props: ['id', 'type'],
|
||||||
components: {
|
components: { TorrentList, Person, LoadingPlaceholder, SidebarAction },
|
||||||
TorrentList,
|
|
||||||
Person,
|
|
||||||
LoadingPlaceholder,
|
|
||||||
SidebarListElement,
|
|
||||||
RadioButtons,
|
|
||||||
TextArea,
|
|
||||||
SeasonedButton
|
|
||||||
},
|
|
||||||
directives: { img: img }, // TODO decide to remove or use
|
directives: { img: img }, // TODO decide to remove or use
|
||||||
data(){
|
data(){
|
||||||
return{
|
return{
|
||||||
@@ -170,14 +137,12 @@ export default {
|
|||||||
userLoggedIn: storage.sessionId ? true : false,
|
userLoggedIn: storage.sessionId ? true : false,
|
||||||
requested: false,
|
requested: false,
|
||||||
admin: localStorage.getItem('admin'),
|
admin: localStorage.getItem('admin'),
|
||||||
showTorrents: false,
|
showTorrents: false
|
||||||
compact: false,
|
|
||||||
showIssueForm: false,
|
|
||||||
selectedIssue: null
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
parseResponse(movie) {
|
parseResponse(resp) {
|
||||||
|
let movie = resp.data;
|
||||||
this.movie = { ...movie }
|
this.movie = { ...movie }
|
||||||
this.title = movie.title
|
this.title = movie.title
|
||||||
this.poster = movie.poster
|
this.poster = movie.poster
|
||||||
@@ -186,7 +151,7 @@ export default {
|
|||||||
this.checkIfRequested(movie)
|
this.checkIfRequested(movie)
|
||||||
.then(status => this.requested = status)
|
.then(status => this.requested = status)
|
||||||
|
|
||||||
store.dispatch('documentTitle/updateTitle', movie.title)
|
document.title = movie.title + storage.pageTitlePostfix
|
||||||
},
|
},
|
||||||
async checkIfRequested(movie) {
|
async checkIfRequested(movie) {
|
||||||
return await getRequestStatus(movie.id, movie.type)
|
return await getRequestStatus(movie.id, movie.type)
|
||||||
@@ -208,15 +173,6 @@ export default {
|
|||||||
const tmdbType = this.type === 'show' ? 'tv' : this.type
|
const tmdbType = this.type === 'show' ? 'tv' : this.type
|
||||||
window.location.href = 'https://www.themoviedb.org/' + tmdbType + '/' + this.id
|
window.location.href = 'https://www.themoviedb.org/' + tmdbType + '/' + this.id
|
||||||
},
|
},
|
||||||
reportIssue() {
|
|
||||||
if (this.showIssueForm) {
|
|
||||||
this.$notifications.success({
|
|
||||||
title: 'Issue successfully submitted',
|
|
||||||
description: 'Reported issue: Missing subtitles',
|
|
||||||
timeout: 300000
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
id: function(val){
|
id: function(val){
|
||||||
@@ -227,46 +183,11 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
numberOfTorrentResults: () => {
|
|
||||||
let numTorrents = store.getters['torrentModule/resultCount']
|
|
||||||
return numTorrents !== null ? numTorrents + ' results' : null
|
|
||||||
},
|
|
||||||
issueOptions: function() {
|
|
||||||
return [{
|
|
||||||
value: 'playback',
|
|
||||||
text: 'Unable to play'
|
|
||||||
}, {
|
|
||||||
value: 'missing-episode',
|
|
||||||
text: 'Missing Episode',
|
|
||||||
subElements: this.seasonOptions
|
|
||||||
}, {
|
|
||||||
value: 'missing-subtitle',
|
|
||||||
text: 'Missing subtitles'
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
seasonOptions: function() {
|
|
||||||
if (this.movie.type !== 'show') {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
const options = []
|
|
||||||
const length = this.movie.seasons;
|
|
||||||
|
|
||||||
for (var i = 0; i < length; i++) {
|
|
||||||
options.push({
|
|
||||||
value: i+1,
|
|
||||||
text: `Season ${i+1}`
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
store.dispatch('documentTitle/updateTitle', this.prevDocumentTitle)
|
document.title = this.prevDocumentTitle
|
||||||
},
|
},
|
||||||
created(){
|
created(){
|
||||||
this.prevDocumentTitle = store.getters['documentTitle/title']
|
this.prevDocumentTitle = document.title
|
||||||
|
|
||||||
if (this.type === 'movie') {
|
if (this.type === 'movie') {
|
||||||
getMovie(this.id)
|
getMovie(this.id)
|
||||||
@@ -293,9 +214,6 @@ export default {
|
|||||||
@import "./src/scss/media-queries";
|
@import "./src/scss/media-queries";
|
||||||
|
|
||||||
.movie {
|
.movie {
|
||||||
background-color: $background-color;
|
|
||||||
color: $text-color;
|
|
||||||
|
|
||||||
&__wrap {
|
&__wrap {
|
||||||
display: flex;
|
display: flex;
|
||||||
&--header {
|
&--header {
|
||||||
@@ -312,16 +230,12 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&__header {
|
&__header {
|
||||||
$duration: 0.2s;
|
|
||||||
height: 250px;
|
height: 250px;
|
||||||
transform: scaleY(1);
|
|
||||||
transition: height $duration ease;
|
|
||||||
transform-origin: top;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: 50% 50%;
|
background-position: 50% 50%;
|
||||||
background-color: $background-color;
|
background-color: $c-dark;
|
||||||
@include tablet-min {
|
@include tablet-min {
|
||||||
height: 350px;
|
height: 350px;
|
||||||
}
|
}
|
||||||
@@ -334,17 +248,14 @@ export default {
|
|||||||
z-index: 0;
|
z-index: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: $background-dark-85;
|
background: rgba($c-dark, 0.85);
|
||||||
}
|
|
||||||
&.compact {
|
|
||||||
height: 100px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__poster {
|
&__poster {
|
||||||
display: none;
|
display: none;
|
||||||
@include tablet-min {
|
@include tablet-min {
|
||||||
background: $background-color;
|
background: $c-white;
|
||||||
height: 0;
|
height: 0;
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -371,7 +282,7 @@ export default {
|
|||||||
&__title {
|
&__title {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
color: $green;
|
color: $c-green;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@include tablet-min {
|
@include tablet-min {
|
||||||
@@ -388,8 +299,16 @@ export default {
|
|||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
span {
|
||||||
|
display: block;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 300;
|
||||||
|
color: rgba($c-white, 0.7);
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&__main {
|
&__main {
|
||||||
|
background: $c-light;
|
||||||
min-height: calc(100vh - 250px);
|
min-height: calc(100vh - 250px);
|
||||||
@include tablet-min {
|
@include tablet-min {
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
@@ -399,16 +318,64 @@ export default {
|
|||||||
}
|
}
|
||||||
&__actions {
|
&__actions {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
// min-height: 394px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
order: 2;
|
order: 2;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border-top: 1px solid $text-color-5;
|
border-top: 1px solid rgba($c-dark, 0.05);
|
||||||
@include tablet-min {
|
@include tablet-min {
|
||||||
order: 1;
|
order: 1;
|
||||||
width: 45%;
|
width: 45%;
|
||||||
padding: 185px 0 40px 40px;
|
padding: 185px 0 40px 40px;
|
||||||
border-top: 0;
|
border-top: 0;
|
||||||
}
|
}
|
||||||
|
&-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
text-decoration: none;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: rgba($c-dark, 0.5);
|
||||||
|
transition: color 0.5s ease;
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 5px 0;
|
||||||
|
border-bottom: 1px solid rgba($c-dark, 0.05);
|
||||||
|
&:hover {
|
||||||
|
color: rgba($c-dark, 0.75);
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
color: $c-dark;
|
||||||
|
}
|
||||||
|
&.pending {
|
||||||
|
color: #f8bd2d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
margin: 0 10px 0 0;
|
||||||
|
fill: rgba($c-dark, 0.5);
|
||||||
|
transition: fill 0.5s ease, transform 0.5s ease;
|
||||||
|
&.waiting {
|
||||||
|
transform: scale(0.8, 0.8);
|
||||||
|
}
|
||||||
|
&.pending {
|
||||||
|
fill: #f8bd2d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-link:hover &-icon {
|
||||||
|
fill: rgba($c-dark, 0.75);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
&-link.active &-icon {
|
||||||
|
fill: $c-green;
|
||||||
|
}
|
||||||
|
&-text {
|
||||||
|
display: block;
|
||||||
|
padding-top: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin:4.4px;
|
||||||
|
margin-left: -3px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&__info {
|
&__info {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -421,7 +388,7 @@ export default {
|
|||||||
margin-left: 45%;
|
margin-left: 45%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&__info {
|
&__actions + &__info {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
&__description {
|
&__description {
|
||||||
@@ -429,19 +396,15 @@ export default {
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height: 1.8;
|
line-height: 1.8;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
flex: 0 0 100%;
|
|
||||||
|
|
||||||
@include tablet-min {
|
@include tablet-min {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&__details {
|
&__details {
|
||||||
display: flex;
|
&-block {
|
||||||
width: 100%;
|
float: left;
|
||||||
flex-direction: row;
|
}
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
&-block:not(:last-child) {
|
&-block:not(:last-child) {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
@@ -455,7 +418,7 @@ export default {
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: $green;
|
color: $c-green;
|
||||||
@include tablet-min {
|
@include tablet-min {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
@@ -482,7 +445,7 @@ export default {
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: $green;
|
color: $c-green;
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
@include tablet-min {
|
@include tablet-min {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@@ -490,24 +453,4 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.issueForm {
|
|
||||||
// padding: 40px;
|
|
||||||
|
|
||||||
.issueOptions {
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.seasonOptions {
|
|
||||||
margin-top: 2rem;
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
> :not(h2) {
|
|
||||||
margin-left: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container info">
|
<div class="container info">
|
||||||
<movie :id="$route.params.id" :type="'page'"></movie>
|
<!-- <movie :id="$route.params.id" :type="'page'"></movie> -->
|
||||||
|
<LargeMovie :id"$route.params.id"></LargeMovie>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Movie from './Movie';
|
import Movie from './Movie.vue';
|
||||||
|
import LargeMovie from './LargeMovie.vue';
|
||||||
export default {
|
export default {
|
||||||
components: { Movie }
|
components: { Movie, LargeMovie }
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="movie-popup" @click="$popup.close()">
|
<div class="movie-popup" @click="$popup.close()">
|
||||||
<div class="movie-popup__box" @click.stop>
|
<div class="movie-popup__box" @click.stop>
|
||||||
<movie :id="id" :type="type"></movie>
|
<!-- <movie :id="id" :type="type"></movie> -->
|
||||||
|
|
||||||
|
<large-movie :id="id" :type="type"></large-movie>
|
||||||
<button class="movie-popup__close" @click="$popup.close()"></button>
|
<button class="movie-popup__close" @click="$popup.close()"></button>
|
||||||
</div>
|
</div>
|
||||||
<i class="loader"></i>
|
<i class="loader"></i>
|
||||||
@@ -9,36 +11,20 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Movie from './Movie';
|
import Movie from './Movie.vue';
|
||||||
|
import LargeMovie from './LargeMovie.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: ['id', 'type'],
|
||||||
id: {
|
components: { Movie, LargeMovie },
|
||||||
type: Number,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: { Movie },
|
|
||||||
methods: {
|
|
||||||
checkEventForEscapeKey(event) {
|
|
||||||
if (event.keyCode == 27) {
|
|
||||||
this.$popup.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created(){
|
created(){
|
||||||
window.addEventListener('keyup', this.checkEventForEscapeKey)
|
let that = this
|
||||||
document.getElementsByTagName("body")[0].classList += " no-scroll";
|
window.addEventListener('keyup', function(e){
|
||||||
},
|
if (e.keyCode == 27) {
|
||||||
beforeDestroy() {
|
that.$popup.close()
|
||||||
window.removeEventListener('keyup', this.checkEventForEscapeKey)
|
}
|
||||||
document.getElementsByTagName("body")[0].classList.remove("no-scroll");
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -53,21 +39,9 @@ export default {
|
|||||||
z-index: 20;
|
z-index: 20;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
background: rgba($dark, 0.93);
|
background: rgba($c-dark, 0.93);
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
&__box{
|
|
||||||
width: 100%;
|
|
||||||
max-width: 768px;
|
|
||||||
position: relative;
|
|
||||||
z-index: 5;
|
|
||||||
background: $background-color-secondary;
|
|
||||||
padding-bottom: 50px;
|
|
||||||
@include tablet-min{
|
|
||||||
padding-bottom: 0;
|
|
||||||
margin: 40px auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__close{
|
&__close{
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -88,7 +62,7 @@ export default {
|
|||||||
left: 10px;
|
left: 10px;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 2px;
|
height: 2px;
|
||||||
background: $white;
|
background: $c-white;
|
||||||
}
|
}
|
||||||
&:before{
|
&:before{
|
||||||
transform: rotate(45deg);
|
transform: rotate(45deg);
|
||||||
@@ -97,7 +71,7 @@ export default {
|
|||||||
transform: rotate(-45deg);
|
transform: rotate(-45deg);
|
||||||
}
|
}
|
||||||
&:hover{
|
&:hover{
|
||||||
background: $green;
|
background: $c-green;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
328
src/components/MoviesList.vue
Normal file
328
src/components/MoviesList.vue
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class='movies-list' v-if="!error">
|
||||||
|
<header class='list-header'>
|
||||||
|
<h2 class='header__title'>{{ listTitle }}</h2>
|
||||||
|
|
||||||
|
<router-link class='header__view-more'
|
||||||
|
:to="'/list/' + list.route"
|
||||||
|
v-if='shortList'>
|
||||||
|
View All</router-link>
|
||||||
|
|
||||||
|
<div v-else style="line-height: 0;">
|
||||||
|
<span class='header__result-count' v-if="totalResults">{{ resultCount }} results</span>
|
||||||
|
<loading-placeholder v-else :count="1" lineClass='short nomargin'></loading-placeholder>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- <ul class="filter">
|
||||||
|
<li class="filter-item" v-for="(item, index) in results" @click="applyFilter(item, index)" :class="{'active': item === selectedRelaseType}">{{ item.title }}</li>
|
||||||
|
</ul> -->
|
||||||
|
|
||||||
|
<ul class='results'>
|
||||||
|
<movies-list-item v-for='movie in results' :movie="movie" :shortList="shortList"></movies-list-item>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<loader v-if="loader" />
|
||||||
|
|
||||||
|
<div class='end-section' v-if="!shortList">
|
||||||
|
<seasoned-button v-if="currentPage < totalPages" @click="loadMore">load more</seasoned-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else style="display: flex; height: 50vh; width: 100%; justify-content: center; align-items: center;">
|
||||||
|
|
||||||
|
<h1 v-if="error">{{ error }}</h1>
|
||||||
|
<h1 v-else>Unable to load list: {{ listTitle }}</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import storage from '@/storage.js'
|
||||||
|
import MoviesListItem from '@/components/MoviesListItem.vue'
|
||||||
|
import SeasonedButton from '@/components/ui/SeasonedButton.vue'
|
||||||
|
import LoadingPlaceholder from '@/components/ui/LoadingPlaceholder.vue'
|
||||||
|
import Loader from '@/components/ui/Loader.vue'
|
||||||
|
import { searchTmdb, getTmdbListByPath } from '@/api.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
shortList: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
propList: Object
|
||||||
|
},
|
||||||
|
components: { MoviesListItem, SeasonedButton, LoadingPlaceholder, Loader },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
listTitle: 'No listname found',
|
||||||
|
results: [],
|
||||||
|
currentPage: 1,
|
||||||
|
totalResults: 0,
|
||||||
|
totalPages: -1,
|
||||||
|
fetchingResults: false,
|
||||||
|
error: undefined,
|
||||||
|
loader: false,
|
||||||
|
|
||||||
|
filters: {
|
||||||
|
status: {
|
||||||
|
elms: ['all', 'requested', 'downloading', 'downloaded'],
|
||||||
|
selected: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
resultCount() {
|
||||||
|
return this.totalResults.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeMount() {
|
||||||
|
if (this.propList) {
|
||||||
|
this.list = this.propList
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setPageFromUrlQuery()
|
||||||
|
this.parseURI()
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.results.length === 0 && this.error === undefined) {
|
||||||
|
this.loader = true
|
||||||
|
}
|
||||||
|
}, 200)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setPageFromUrlQuery() {
|
||||||
|
if (this.$route.query.page)
|
||||||
|
this.currentPage = this.$route.query.page
|
||||||
|
console.log('url page param found', this.currentPage)
|
||||||
|
},
|
||||||
|
getListByName(name) {
|
||||||
|
return storage.homepageLists.filter(list => list.route === name)[0]
|
||||||
|
},
|
||||||
|
parseURI() {
|
||||||
|
const currentRouteName = this.$route.name
|
||||||
|
|
||||||
|
// route name is list - we are in a list view
|
||||||
|
if (currentRouteName === 'list') {
|
||||||
|
const nameParam = this.$route.params.name
|
||||||
|
if (this.getListByName(nameParam)) {
|
||||||
|
this.list = this.getListByName(nameParam)
|
||||||
|
this.listTitle = this.list.title
|
||||||
|
this.fetchListitems()
|
||||||
|
} else {
|
||||||
|
this.error = `Unable to load list: `
|
||||||
|
}
|
||||||
|
} // route name is search - we are searcing
|
||||||
|
else if (currentRouteName === 'search') {
|
||||||
|
if (this.$route.query.query) {
|
||||||
|
this.query = decodeURIComponent(this.$route.query.query)
|
||||||
|
this.listTitle = 'Search results: ' + this.query
|
||||||
|
this.fetchSearchItems()
|
||||||
|
} else {
|
||||||
|
this.error = 'Search query is not defined, please try again'
|
||||||
|
}
|
||||||
|
|
||||||
|
} // no matched route found - using prop to fetch list items
|
||||||
|
else {
|
||||||
|
this.listTitle = this.list.title
|
||||||
|
this.fetchListitems()
|
||||||
|
}
|
||||||
|
|
||||||
|
document.title = this.listTitle
|
||||||
|
},
|
||||||
|
// TODO these should receive a path not get it from list instance
|
||||||
|
fetchListitems() {
|
||||||
|
getTmdbListByPath(this.list.path, this.currentPage)
|
||||||
|
.then(this.parseResponse)
|
||||||
|
.catch(error => {
|
||||||
|
console.error(error)
|
||||||
|
this.error = 'Network error'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
fetchSearchItems() {
|
||||||
|
searchTmdb(this.query, this.currentPage)
|
||||||
|
.then(this.parseResponse)
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO what parts are modular and what parts do we want the component to deal with
|
||||||
|
// if we pass in some object and then as we initialize we set to local variables.
|
||||||
|
// This way we call the http-api from outside and pass the response in to the component[0]
|
||||||
|
// Could also parse the response we are requesting then return a clean object we can
|
||||||
|
// pass down[1].
|
||||||
|
|
||||||
|
// [0] if this is done we should also take the page, total pages, total results and
|
||||||
|
// the list of results. Maybe also the title of the list or use local title as fallback?
|
||||||
|
// [1] an issue with this that duplicate code will be needed for doing the same with
|
||||||
|
// url params and paths.
|
||||||
|
// (What if we eliminated folder based routes and implemented the routes in hashes
|
||||||
|
// with single page applications today the navigation is simple enought that it
|
||||||
|
// would maybe not be needed to have a path-route but a hash-local.storage
|
||||||
|
// implementation; would allow sharing and remembering paths is just silly for most
|
||||||
|
// Single-Page-Applications that are tightly scoped applications)
|
||||||
|
parseResponse(response) {
|
||||||
|
const data = response.data
|
||||||
|
if (data.page > data.total_pages) {
|
||||||
|
console.error('You have reached the end')
|
||||||
|
this.error = 'You have reached the end'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.results.length) {
|
||||||
|
this.results.push(...data.results)
|
||||||
|
} else {
|
||||||
|
this.results = this.shortList ? data.results.slice(0,12) : data.results
|
||||||
|
}
|
||||||
|
this.page = data.page
|
||||||
|
this.totalPages = data.total_pages
|
||||||
|
this.totalResults = data.total_results || data.results.length
|
||||||
|
|
||||||
|
this.loader = false
|
||||||
|
|
||||||
|
console.info(`Response from list: ${this.listTitle}`, { results: this.results, page: this.page, totalPages: this.totalPages, totalResults: this.totalResults })
|
||||||
|
},
|
||||||
|
loadMore(){
|
||||||
|
this.currentPage++;
|
||||||
|
|
||||||
|
console.log('path and name:', this.$route.path, this.$route.name)
|
||||||
|
let url = ''
|
||||||
|
|
||||||
|
if (this.$route.path.includes('list'))
|
||||||
|
url = `/#${this.$route.path}?page=${this.currentPage}`
|
||||||
|
else if (this.$route.path.includes('search'))
|
||||||
|
url = `/#/search?query=${this.query}&page=${this.currentPage}`
|
||||||
|
|
||||||
|
console.log('new url', url)
|
||||||
|
window.history.replaceState({}, 'foo', url)
|
||||||
|
|
||||||
|
this.parseURI()
|
||||||
|
},
|
||||||
|
// sort() {
|
||||||
|
// console.log(this.showFilters)
|
||||||
|
// },
|
||||||
|
// toggleFilter(item, index){
|
||||||
|
// this.showFilter = this.showFilter ? false : true;
|
||||||
|
// // this.results = this.results.filter(result => result.status != 'downloaded')
|
||||||
|
// },
|
||||||
|
// applyFilter(item, index) {
|
||||||
|
// this.filter = item;
|
||||||
|
// this.filters.status.selected = index;
|
||||||
|
// console.log('applied query filter: ', item, index)
|
||||||
|
// this.fetchCategory()
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route: function () {
|
||||||
|
console.log('updated route')
|
||||||
|
this.results = false
|
||||||
|
this.currentPage = 1
|
||||||
|
this.setPageFromUrlQuery()
|
||||||
|
this.parseURI()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "./src/scss/variables";
|
||||||
|
@import "./src/scss/media-queries";
|
||||||
|
@import "./src/scss/elements";
|
||||||
|
|
||||||
|
.movies-list {
|
||||||
|
list-style: none;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 15px;
|
||||||
|
|
||||||
|
.results {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-header {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 20px 10px;
|
||||||
|
|
||||||
|
@include tablet-min{
|
||||||
|
padding: 23px 15px;
|
||||||
|
}
|
||||||
|
@include tablet-landscape-min{
|
||||||
|
padding: 16px 25px;
|
||||||
|
}
|
||||||
|
@include desktop-min{
|
||||||
|
padding: 8px 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header__title {
|
||||||
|
line-height: 18px;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #081c24;
|
||||||
|
font-weight: 300;
|
||||||
|
// flex-basis: 50%;
|
||||||
|
text-transform: capitalize;
|
||||||
|
|
||||||
|
@include tablet-min{
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header__result-count {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 300;
|
||||||
|
letter-spacing: .5px;
|
||||||
|
color: rgba(8,28,36,.5);
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header__view-more {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 300;
|
||||||
|
letter-spacing: .5px;
|
||||||
|
color: rgba($c-dark, 0.5);
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color .5s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:after{
|
||||||
|
content: " →";
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
color: $c-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.end-section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
margin: 1rem 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@import "./src/scss/media-queries";
|
||||||
|
.form__group-input {
|
||||||
|
padding: 10px 5px 10px 15px;
|
||||||
|
margin-left: 0;
|
||||||
|
height: 38px;
|
||||||
|
width: 150px;
|
||||||
|
font-size: 15px;
|
||||||
|
@include desktop-min {
|
||||||
|
width: 200px;
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
<li class="movies-item" :class="{'shortList': shortList}">
|
<li class="movies-item" :class="{'shortList': shortList}">
|
||||||
<a class="movies-item__link" :class="{'no-image': noImage}" @click.prevent="openMoviePopup(movie.id, movie.type)">
|
<a class="movies-item__link" :class="{'no-image': noImage}" @click.prevent="openMoviePopup(movie.id, movie.type)">
|
||||||
|
|
||||||
<!-- TODO change to picture element -->
|
|
||||||
<figure class="movies-item__poster">
|
<figure class="movies-item__poster">
|
||||||
<img v-if="!noImage" class="movies-item__img" src="~assets/placeholder.png" v-img="poster()" alt="">
|
<img v-if="!noImage" class="movies-item__img" src="~assets/placeholder.png" v-img="poster()" alt="">
|
||||||
<img v-if="noImage" class="movies-item__img is-loaded" src="~assets/no-image.png" alt="">
|
<img v-if="noImage" class="movies-item__img is-loaded" src="~assets/no-image.png" alt="">
|
||||||
@@ -16,7 +15,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import img from '../directives/v-image'
|
import img from '../directives/v-image.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['movie', 'shortList'],
|
props: ['movie', 'shortList'],
|
||||||
@@ -24,7 +23,7 @@ export default {
|
|||||||
img: img
|
img: img
|
||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
return {
|
return{
|
||||||
noImage: false
|
noImage: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -37,7 +36,7 @@ export default {
|
|||||||
this.noImage = true
|
this.noImage = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
openMoviePopup(id, type) {
|
openMoviePopup(id, type){
|
||||||
this.$popup.open(id, type)
|
this.$popup.open(id, type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,33 +46,53 @@ export default {
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "./src/scss/variables";
|
@import "./src/scss/variables";
|
||||||
@import "./src/scss/media-queries";
|
@import "./src/scss/media-queries";
|
||||||
|
|
||||||
.movies-item {
|
.movies-item {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
background-color: $background-color;
|
|
||||||
transition: background-color 0.5s ease;
|
|
||||||
|
|
||||||
@include tablet-min{
|
@include tablet-min{
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
}
|
}
|
||||||
@include tablet-landscape-min{
|
@include tablet-landscape-min{
|
||||||
padding: 15px;
|
padding: 20px;
|
||||||
width: 25%;
|
width: 25%;
|
||||||
}
|
}
|
||||||
@include desktop-min{
|
@include desktop-min{
|
||||||
padding: 15px;
|
padding: 30px;
|
||||||
width: 20%;
|
width: 20%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include desktop-lg-min{
|
@include desktop-lg-min{
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
width: 12.5%;
|
width: 16.5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.shortList {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
&:nth-child(-n+6) { // show first 6
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include tablet-landscape-min{
|
||||||
|
&:nth-child(-n+8) { // show first 8
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include desktop-min{
|
||||||
|
&:nth-child(-n+10) { // show first 10
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include desktop-lg-min{
|
||||||
|
display: block; // show all
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__link{
|
&__link{
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: $text-color-70;
|
color: rgba($c-dark, 0.5);
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
&__content{
|
&__content{
|
||||||
@@ -82,6 +101,7 @@ export default {
|
|||||||
&__poster{
|
&__poster{
|
||||||
transition: transform 0.5s ease, box-shadow 0.3s ease;
|
transition: transform 0.5s ease, box-shadow 0.3s ease;
|
||||||
transform: translateZ(0);
|
transform: translateZ(0);
|
||||||
|
background: $c-white;
|
||||||
}
|
}
|
||||||
&__img{
|
&__img{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -95,14 +115,13 @@ export default {
|
|||||||
}
|
}
|
||||||
&__link:not(.no-image):hover &__poster{
|
&__link:not(.no-image):hover &__poster{
|
||||||
transform: scale(1.03);
|
transform: scale(1.03);
|
||||||
box-shadow: 0 0 10px rgba($dark, 0.1);
|
box-shadow: 0 0 10px rgba($c-dark, 0.1);
|
||||||
}
|
}
|
||||||
&__title{
|
&__title{
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.5px;
|
||||||
transition: color 0.5s ease;
|
transition: color 0.5s ease;
|
||||||
cursor: pointer;
|
|
||||||
@include mobile-ls-min{
|
@include mobile-ls-min{
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
@@ -111,7 +130,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&__link:hover &__title{
|
&__link:hover &__title{
|
||||||
color: $text-color;
|
color: $c-dark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -6,15 +6,16 @@
|
|||||||
<use xlink:href="#svgLogo"></use>
|
<use xlink:href="#svgLogo"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<div class="nav__hamburger" @click="toggleNav">
|
<div class="nav__hamburger" @click="toggleNav">
|
||||||
<div v-for="_ in 3" class="bar"></div>
|
<div class="bar"></div>
|
||||||
|
<div class="bar"></div>
|
||||||
|
<div class="bar"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="nav__list">
|
<ul class="nav__list">
|
||||||
<li class="nav__item" v-for="item in listTypes">
|
<li class="nav__item" v-for="item in listTypes">
|
||||||
<router-link class="nav__link" :to="'/list/' + item.route">
|
<router-link class="nav__link" :to="'/list/' + item.route">
|
||||||
<div class="nav__link-wrap">
|
<div class="nav__link-wrap">
|
||||||
|
<!-- <img :src="item.icon" class="nav__link-icon"> -->
|
||||||
<svg class="nav__link-icon">
|
<svg class="nav__link-icon">
|
||||||
<use :xlink:href="'#icon_' + item.route"></use>
|
<use :xlink:href="'#icon_' + item.route"></use>
|
||||||
</svg>
|
</svg>
|
||||||
@@ -22,9 +23,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="nav__item nav__item--profile">
|
<li class="nav__item nav__item--profile">
|
||||||
<router-link class="nav__link nav__link--profile" :to="{name: 'signin'}" v-if="!userLoggedIn">
|
<router-link class="nav__link nav__link--profile" :to="{name: 'signin'}" v-if="!userLoggedIn">
|
||||||
<div class="nav__link-wrap">
|
<div class="nav__link-wrap">
|
||||||
<svg class="nav__link-icon">
|
<svg class="nav__link-icon">
|
||||||
<use xlink:href="#iconLogin"></use>
|
<use xlink:href="#iconLogin"></use>
|
||||||
@@ -32,8 +32,7 @@
|
|||||||
<span class="nav__link-title">Sign in</span>
|
<span class="nav__link-title">Sign in</span>
|
||||||
</div>
|
</div>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
<router-link class="nav__link nav__link--profile" :to="{name: 'profile'}" v-if="userLoggedIn">
|
||||||
<router-link class="nav__link nav__link--profile" :to="{name: 'profile'}" v-if="userLoggedIn">
|
|
||||||
<div class="nav__link-wrap">
|
<div class="nav__link-wrap">
|
||||||
<svg class="nav__link-icon">
|
<svg class="nav__link-icon">
|
||||||
<use xlink:href="#iconLogin"></use>
|
<use xlink:href="#iconLogin"></use>
|
||||||
@@ -44,13 +43,12 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import storage from '@/storage'
|
import storage from '@/storage.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data(){
|
data(){
|
||||||
@@ -69,7 +67,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
created(){
|
created(){
|
||||||
// TODO move this to state manager
|
|
||||||
eventHub.$on('setUserStatus', this.setUserStatus);
|
eventHub.$on('setUserStatus', this.setUserStatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,59 +75,53 @@ export default {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "./src/scss/variables";
|
@import "./src/scss/variables";
|
||||||
@import "./src/scss/media-queries";
|
@import "./src/scss/media-queries";
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spacer {
|
.spacer {
|
||||||
@include mobile-only {
|
@include mobile-only {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: $header-size;
|
height: $header-size-mobile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav {
|
.nav {
|
||||||
transition: background .5s ease;
|
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
|
background: $c-white;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
display: block;
|
display: block;
|
||||||
color: $text-color;
|
|
||||||
background-color: $background-color-secondary;
|
|
||||||
|
|
||||||
@include tablet-min{
|
@include tablet-min{
|
||||||
width: 95px;
|
width: 95px;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
&__logo {
|
&__logo{
|
||||||
width: 55px;
|
width: 55px;
|
||||||
height: $header-size;
|
height: $header-size-mobile;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
background: $background-nav-logo;
|
background: $c-dark;
|
||||||
@include tablet-min{
|
@include tablet-min{
|
||||||
width: 95px;
|
width: 95px;
|
||||||
|
height: $header-size;
|
||||||
}
|
}
|
||||||
&-image{
|
&-image{
|
||||||
width: 35px;
|
width: 35px;
|
||||||
height: 31px;
|
height: 31px;
|
||||||
fill: $green;
|
fill: $c-green;
|
||||||
transition: transform 0.5s ease;
|
transition: transform 0.5s ease;
|
||||||
@include tablet-min{
|
@include tablet-min{
|
||||||
width: 45px;
|
width: 45px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:hover &-image {
|
&:hover &-image{
|
||||||
transform: scale(1.04);
|
transform: scale(1.04);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&__hamburger {
|
&__hamburger{
|
||||||
display: block;
|
display: block;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 55px;
|
width: 55px;
|
||||||
@@ -138,22 +129,23 @@ export default {
|
|||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
background: $c-white;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
border-left: 1px solid $background-color;
|
border-left: 1px solid $c-light;
|
||||||
@include tablet-min{
|
@include tablet-min{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.bar {
|
.bar{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 23px;
|
width: 23px;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
background-color: $text-color-70;
|
background: rgba($c-dark, 0.5);
|
||||||
transition: all 300ms ease;
|
transition: all 300ms ease;
|
||||||
&:nth-child(1) {
|
&:nth-child(1){
|
||||||
left: 16px;
|
left: 16px;
|
||||||
top: 17px;
|
top: 17px;
|
||||||
}
|
}
|
||||||
&:nth-child(2) {
|
&:nth-child(2){
|
||||||
left: 16px;
|
left: 16px;
|
||||||
top: 25px;
|
top: 25px;
|
||||||
&:after {
|
&:after {
|
||||||
@@ -163,15 +155,16 @@ export default {
|
|||||||
top: 0px;
|
top: 0px;
|
||||||
width: 23px;
|
width: 23px;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
|
background: transparent;
|
||||||
transition: all 300ms ease;
|
transition: all 300ms ease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:nth-child(3) {
|
&:nth-child(3){
|
||||||
right: 15px;
|
right: 15px;
|
||||||
top: 33px;
|
top: 33px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&--active {
|
&--active{
|
||||||
.bar{
|
.bar{
|
||||||
&:nth-child(1),
|
&:nth-child(1),
|
||||||
&:nth-child(3){
|
&:nth-child(3){
|
||||||
@@ -182,13 +175,12 @@ export default {
|
|||||||
}
|
}
|
||||||
&:nth-child(2):after {
|
&:nth-child(2):after {
|
||||||
transform: rotate(-90deg);
|
transform: rotate(-90deg);
|
||||||
// background: rgba($c-dark, 0.5);
|
background: rgba($c-dark, 0.5);
|
||||||
background-color: $text-color-70;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&__list {
|
&__list{
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -197,22 +189,23 @@ export default {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 50px;
|
top: 50px;
|
||||||
border-top: 1px solid $background-color;
|
background: rgba($c-white, 0.98);
|
||||||
@include mobile-only {
|
border-top: 1px solid $c-light;
|
||||||
display: flex;
|
@include mobile-only{
|
||||||
flex-wrap: wrap;
|
|
||||||
font-size: 0;
|
font-size: 0;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
background-color: $background-95;
|
height: calc(100vh - 50px);
|
||||||
|
transition: all 0.5s ease;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
&--active{
|
&--active{
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@include tablet-min {
|
@include tablet-min{
|
||||||
display: flex;
|
display: flex;
|
||||||
|
background: transparent;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -220,44 +213,31 @@ export default {
|
|||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&__item {
|
&__item{
|
||||||
transition: background .5s ease, color .5s ease, border .5s ease;
|
@include mobile-only{
|
||||||
background-color: $background-color-secondary;
|
display: inline-block;
|
||||||
color: $text-color-70;
|
|
||||||
|
|
||||||
@include mobile-only {
|
|
||||||
flex: 0 0 50%;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-bottom: 1px solid $background-color;
|
width: 50%;
|
||||||
|
border-bottom: 1px solid $c-light;
|
||||||
&:nth-child(odd){
|
&:nth-child(odd){
|
||||||
border-right: 1px solid $background-color;
|
border-right: 1px solid $c-light;
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
// flex: 0 0 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@include tablet-min {
|
@include tablet-min{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-bottom: 1px solid $text-color-5;
|
border-bottom: 1px solid $c-light;
|
||||||
|
&--profile{
|
||||||
&--profile {
|
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: $header-size;
|
width: $header-size;
|
||||||
height: $header-size;
|
height: $header-size;
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
border-left: 1px solid $background-color;
|
border-left: 1px solid $c-light;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:hover, .is-active {
|
|
||||||
color: $text-color;
|
|
||||||
background-color: $background-color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
&__link {
|
&__link{
|
||||||
background-color: inherit; // a elements have a transparent background
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@@ -268,6 +248,8 @@ export default {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.5px;
|
||||||
|
color: rgba($c-dark, 0.7);
|
||||||
|
transition: color 0.5s ease, background 0.5s ease;
|
||||||
position: relative;
|
position: relative;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
&-wrap {
|
&-wrap {
|
||||||
@@ -276,38 +258,49 @@ export default {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include mobile-only {
|
@include mobile-only{
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
padding: 20px 0;
|
padding: 20px 0;
|
||||||
}
|
}
|
||||||
@include tablet-min {
|
@include tablet-min{
|
||||||
width: 95px;
|
width: 95px;
|
||||||
height: 95px;
|
height: 95px;
|
||||||
font-size: 9px;
|
font-size: 9px;
|
||||||
&--profile {
|
&--profile{
|
||||||
width: 75px;
|
width: 75px;
|
||||||
height: 75px;
|
height: 75px;
|
||||||
background-color: $background-color-secondary;
|
background: $c-white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&-icon {
|
&-icon{
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
fill: $text-color-70;
|
fill: rgba($c-dark, 0.7);
|
||||||
@include tablet-min {
|
transition: fill 0.5s ease;
|
||||||
|
@include tablet-min{
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
&-title {
|
&-title{
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
&:hover &-icon, &.is-active &-icon {
|
&:hover{
|
||||||
fill: $text-color;
|
color: $c-dark;
|
||||||
|
}
|
||||||
|
&:hover &-icon{
|
||||||
|
fill: $c-dark;
|
||||||
|
}
|
||||||
|
&.is-active{
|
||||||
|
color: $c-dark;
|
||||||
|
background: $c-light;
|
||||||
|
}
|
||||||
|
&.is-active &-icon{
|
||||||
|
fill: $c-dark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,18 +3,17 @@
|
|||||||
<div class="profile__content" v-if="userLoggedIn">
|
<div class="profile__content" v-if="userLoggedIn">
|
||||||
<header class="profile__header">
|
<header class="profile__header">
|
||||||
<h2 class="profile__title">{{ emoji }} Welcome {{ userName }}</h2>
|
<h2 class="profile__title">{{ emoji }} Welcome {{ userName }}</h2>
|
||||||
|
|
||||||
<div class="button--group">
|
<div class="button--group">
|
||||||
<seasoned-button @click="showSettings = !showSettings">{{ showSettings ? 'hide settings' : 'show settings' }}</seasoned-button>
|
<seasoned-button @click="showSettings = !showSettings">{{ showSettings ? 'hide settings' : 'show settings' }}</seasoned-button>
|
||||||
|
|
||||||
<seasoned-button @click="logOut">Log out</seasoned-button>
|
<seasoned-button @click="logOut">Log out</seasoned-button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<settings v-if="showSettings"></settings>
|
<settings v-if="showSettings"></settings>
|
||||||
|
|
||||||
<list-header title="User requests" :info="resultCount"/>
|
<movies-list :propList="user_requestsList"></movies-list>
|
||||||
<results-list v-if="results" :results="results" />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section class="not-found" v-if="!userLoggedIn">
|
<section class="not-found" v-if="!userLoggedIn">
|
||||||
@@ -29,35 +28,23 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import storage from '@/storage'
|
import storage from '@/storage.js'
|
||||||
import store from '@/store'
|
import MoviesList from '@/components/MoviesList.vue'
|
||||||
import ListHeader from '@/components/ListHeader'
|
import Settings from '@/components/Settings.vue'
|
||||||
import ResultsList from '@/components/ResultsList'
|
import SeasonedButton from '@/components/ui/SeasonedButton.vue'
|
||||||
import Settings from '@/components/Settings'
|
|
||||||
import SeasonedButton from '@/components/ui/SeasonedButton'
|
|
||||||
|
|
||||||
import { getEmoji, getUserRequests } from '@/api'
|
import { getEmoji } from '@/api.js'
|
||||||
|
// import CreatedLists from './CreatedLists.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { ListHeader, ResultsList, Settings, SeasonedButton },
|
components: { MoviesList, Settings, SeasonedButton },
|
||||||
data(){
|
data(){
|
||||||
return{
|
return{
|
||||||
userLoggedIn: '',
|
userLoggedIn: '',
|
||||||
userName: '',
|
userName: '',
|
||||||
emoji: '',
|
emoji: '',
|
||||||
results: undefined,
|
showSettings: false,
|
||||||
totalResults: undefined,
|
user_requestsList: storage.user_requestsList
|
||||||
showSettings: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
resultCount() {
|
|
||||||
if (this.results === undefined)
|
|
||||||
return
|
|
||||||
|
|
||||||
const loadedResults = this.results.length
|
|
||||||
const totalResults = this.totalResults < 10000 ? this.totalResults : '∞'
|
|
||||||
return `${loadedResults} of ${totalResults} results`
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -87,24 +74,16 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
created(){
|
created(){
|
||||||
|
document.title = 'Profile' + storage.pageTitlePostfix;
|
||||||
|
storage.backTitle = document.title;
|
||||||
if(!localStorage.getItem('token')){
|
if(!localStorage.getItem('token')){
|
||||||
this.userLoggedIn = false;
|
this.userLoggedIn = false;
|
||||||
} else {
|
} else {
|
||||||
this.userLoggedIn = true;
|
this.userLoggedIn = true;
|
||||||
this.getUserInfo();
|
this.getUserInfo();
|
||||||
|
|
||||||
getUserRequests()
|
|
||||||
.then(results => {
|
|
||||||
this.results = results.results
|
|
||||||
this.totalResults = results.total_results
|
|
||||||
})
|
|
||||||
|
|
||||||
getEmoji()
|
getEmoji()
|
||||||
.then(resp => {
|
.then(resp => this.emoji = resp.data.emoji )
|
||||||
const { emoji } = resp
|
|
||||||
this.emoji = emoji
|
|
||||||
store.dispatch('documentTitle/updateEmoji', emoji)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,10 +93,6 @@ export default {
|
|||||||
@import "./src/scss/variables";
|
@import "./src/scss/variables";
|
||||||
@import "./src/scss/media-queries";
|
@import "./src/scss/media-queries";
|
||||||
|
|
||||||
.button--group {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DUPLICATE CODE
|
// DUPLICATE CODE
|
||||||
.profile{
|
.profile{
|
||||||
&__header{
|
&__header{
|
||||||
@@ -125,17 +100,7 @@ export default {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border-bottom: 1px solid $text-color-5;
|
border-bottom: 1px solid rgba($c-dark, 0.05);
|
||||||
|
|
||||||
@include mobile-only {
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
|
|
||||||
.button--group {
|
|
||||||
padding-top: 2rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include tablet-min{
|
@include tablet-min{
|
||||||
padding: 29px 30px;
|
padding: 29px 30px;
|
||||||
}
|
}
|
||||||
@@ -150,7 +115,7 @@ export default {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
color: $text-color;
|
color: $c-dark;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
@include tablet-min{
|
@include tablet-min{
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
|
|||||||
@@ -1,52 +1,80 @@
|
|||||||
<template>
|
<template>
|
||||||
<section>
|
<section class="profile">
|
||||||
<h1>Register new user</h1>
|
<div class="profile__content">
|
||||||
|
<h2 class='settings__header'>Register new user</h2>
|
||||||
|
|
||||||
<seasoned-input placeholder="username" icon="Email" type="username" :value.sync="username" />
|
<form class="form">
|
||||||
|
<seasoned-input text="username" icon="Email"
|
||||||
|
@inputValue="setValue('username', $event)"></seasoned-input>
|
||||||
|
<seasoned-input text="password" icon="Keyhole" type="password"
|
||||||
|
@inputValue="setValue('password', $event)"></seasoned-input>
|
||||||
|
<seasoned-input text="repeat password" icon="Keyhole" type="password"
|
||||||
|
@inputValue="setValue('passwordRepeat', $event)"></seasoned-input>
|
||||||
|
|
||||||
<seasoned-input placeholder="password" icon="Keyhole" type="password"
|
<transition name="message-fade">
|
||||||
:value.sync="password" @enter="requestNewUser"/>
|
<div class="message" :class="messageClass" v-if="showMessage">
|
||||||
|
<span class="message-text">{{ messageText }}</span>
|
||||||
|
<span class="message-dismiss" v-on:click="dismissMessage">X</span>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
|
||||||
<seasoned-input placeholder="repeat password" icon="Keyhole" type="password"
|
<div class="form__group">
|
||||||
:value.sync="passwordRepeat" @enter="requestNewUser"/>
|
<seasoned-button @click="requestNewUser">Register</seasoned-button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="form__group">
|
||||||
|
<router-link class="form__group-link" :to="{name: 'signin'}" exact title="Sign in here">
|
||||||
|
<span class="form__group-signin">Sign in here</span>
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
|
||||||
<seasoned-button @click="requestNewUser">Register</seasoned-button>
|
</div>
|
||||||
|
<section class="not-found" v-if="userLoggedIn === false">
|
||||||
<router-link class="link" to="/signin">Have a user? Sign in here</router-link>
|
<div class="not-found__content">
|
||||||
<seasoned-messages :messages.sync="messages"></seasoned-messages>
|
<h2 class="not-found__title">Authentication Request Failed</h2>
|
||||||
|
<button class="not-found__button button">Log In</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import SeasonedButton from '@/components/ui/SeasonedButton'
|
import storage from '@/storage.js'
|
||||||
import SeasonedInput from '@/components/ui/SeasonedInput'
|
import SeasonedButton from '@/components/ui/SeasonedButton.vue'
|
||||||
import SeasonedMessages from '@/components/ui/SeasonedMessages'
|
import SeasonedInput from '@/components/ui/SeasonedInput.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { SeasonedButton, SeasonedInput, SeasonedMessages },
|
components: { SeasonedButton, SeasonedInput },
|
||||||
data() {
|
data(){
|
||||||
return {
|
return{
|
||||||
messages: [],
|
userLoggedIn: '',
|
||||||
username: null,
|
username: undefined,
|
||||||
password: null,
|
password: undefined,
|
||||||
passwordRepeat: null
|
passwordRepeat: undefined,
|
||||||
|
showMessage: false,
|
||||||
|
messageClass: 'message-success',
|
||||||
|
messageText: 'hello world'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
requestNewUser(){
|
requestNewUser(){
|
||||||
let { username, password, passwordRepeat } = this
|
let username = this.username
|
||||||
|
let password = this.password
|
||||||
let verifyCredentials = this.checkCredentials(username, password, passwordRepeat);
|
let password_re = this.passwordRepeat
|
||||||
|
|
||||||
|
let verifyCredentials = this.checkCredentials(username, password, password_re);
|
||||||
|
|
||||||
if (verifyCredentials.verified) {
|
if (verifyCredentials.verified) {
|
||||||
axios.post(`https://api.kevinmidboe.com/api/v1/user`, {
|
axios.post(`https://api.kevinmidboe.com/api/v1/user`, {
|
||||||
username: username,
|
username: username,
|
||||||
password: password
|
password: password
|
||||||
})
|
})
|
||||||
.then(resp => {
|
.then(function(resp) {
|
||||||
let data = resp.data;
|
let data = resp.data;
|
||||||
if (data.success){
|
if (data.success){
|
||||||
|
this.msg(data.message, 'success');
|
||||||
localStorage.setItem('token', data.token);
|
localStorage.setItem('token', data.token);
|
||||||
localStorage.setItem('username', username);
|
localStorage.setItem('username', username);
|
||||||
localStorage.setItem('admin', data.admin)
|
localStorage.setItem('admin', data.admin)
|
||||||
@@ -54,34 +82,28 @@ export default {
|
|||||||
eventHub.$emit('setUserStatus');
|
eventHub.$emit('setUserStatus');
|
||||||
this.$router.push({ name: 'profile' })
|
this.$router.push({ name: 'profile' })
|
||||||
}
|
}
|
||||||
})
|
}.bind(this))
|
||||||
.catch(error => {
|
.catch(function(error){
|
||||||
this.messages.push({ type: 'error', title: 'Unexpected error', message: error.response.data.error })
|
this.msg(error.response.data.error, 'warning')
|
||||||
});
|
}.bind(this));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.messages.push({ type: 'warning', title: 'Parse error', message: verifyCredentials.reason })
|
this.msg(verifyCredentials.reason, 'warning');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
checkCredentials(username, password, passwordRepeat) {
|
checkCredentials(username, password, password_re) {
|
||||||
if (!username || username.length === 0) {
|
if (password !== password_re) {
|
||||||
return {
|
|
||||||
verified: false,
|
|
||||||
reason: 'Fill inn username'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!password || !passwordRepeat) {
|
|
||||||
return {
|
|
||||||
verified: false,
|
|
||||||
reason: "Fill inn both password fields"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (password !== passwordRepeat) {
|
|
||||||
return {
|
return {
|
||||||
verified: false,
|
verified: false,
|
||||||
reason: 'Passwords do not match'
|
reason: 'Passwords do not match'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (username === undefined) {
|
||||||
|
return {
|
||||||
|
verified: false,
|
||||||
|
reason: 'Please insert username'
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return {
|
return {
|
||||||
verified: true,
|
verified: true,
|
||||||
@@ -89,38 +111,92 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
msg(text, status){
|
||||||
|
if (status === 'warning')
|
||||||
|
this.messageClass = 'message-warning';
|
||||||
|
else if (status === 'success')
|
||||||
|
this.messageClass = 'message-success';
|
||||||
|
else
|
||||||
|
this.messageClass = 'message-info';
|
||||||
|
this.messageText = text;
|
||||||
|
this.showMessage = true;
|
||||||
|
// setTimeout(() => this.showMessage = false, 3500);
|
||||||
|
},
|
||||||
|
dismissMessage(){
|
||||||
|
this.showMessage = false;
|
||||||
|
},
|
||||||
|
setValue(l, t) {
|
||||||
|
this[l] = t
|
||||||
|
},
|
||||||
logOut(){
|
logOut(){
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
eventHub.$emit('setUserStatus');
|
eventHub.$emit('setUserStatus');
|
||||||
this.$router.push({ name: 'home' });
|
this.$router.push({ name: 'home' });
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
created(){
|
||||||
|
document.title = 'Profile' + storage.pageTitlePostfix;
|
||||||
|
storage.backTitle = document.title;
|
||||||
|
},
|
||||||
|
mounted(){
|
||||||
|
// this.$refs.email.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "./src/scss/variables";
|
@import "./src/scss/variables";
|
||||||
|
@import "./src/scss/media-queries";
|
||||||
|
@import "./src/scss/message";
|
||||||
|
|
||||||
section {
|
// DUPLICATE CODE
|
||||||
padding: 1.3rem;
|
.settings {
|
||||||
|
padding: 35px;
|
||||||
|
|
||||||
@include tablet-min {
|
&__header {
|
||||||
padding: 4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
color: $text-color;
|
color: $c-dark;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.profile__content {
|
||||||
|
padding: 35px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
.link {
|
|
||||||
display: block;
|
.center {
|
||||||
width: max-content;
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
// TODO, fix this. if single child it adds weird margin
|
||||||
|
> div:last-child {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__group{
|
||||||
|
justify-content: unset;
|
||||||
|
&__input-icon {
|
||||||
|
margin-top: 8px;
|
||||||
|
height: 22px;
|
||||||
|
width: 22px;
|
||||||
|
}
|
||||||
|
&-input {
|
||||||
|
padding: 10px 5px 10px 45px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 17px;
|
||||||
|
width: 75%;
|
||||||
|
// @include desktop-min {
|
||||||
|
// width: 400px;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
<template>
|
|
||||||
<ul class="results" :class="{'shortList': shortList}">
|
|
||||||
<movies-list-item v-for='movie in results' :movie="movie" />
|
|
||||||
</ul>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import MoviesListItem from '@/components/MoviesListItem'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: { MoviesListItem },
|
|
||||||
props: {
|
|
||||||
results: {
|
|
||||||
type: Array,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
shortList: {
|
|
||||||
type: Boolean,
|
|
||||||
required: false,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import './src/scss/media-queries';
|
|
||||||
|
|
||||||
.results {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
&.shortList > li {
|
|
||||||
display: none;
|
|
||||||
|
|
||||||
&:nth-child(-n+4) {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include tablet-min {
|
|
||||||
.results.shortList > li:nth-child(-n+6) {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@include tablet-landscape-min {
|
|
||||||
.results.shortList > li:nth-child(-n+8) {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@include desktop-min {
|
|
||||||
.results.shortList > li:nth-child(-n+10) {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@include desktop-lg-min {
|
|
||||||
.results.shortList > li:nth-child(-n+16) {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<list-header :title="title" :info="resultCount" :sticky="true" />
|
|
||||||
|
|
||||||
<results-list :results="results" />
|
|
||||||
|
|
||||||
<div v-if="page < totalPages" class="fullwidth-button">
|
|
||||||
<seasoned-button @click="loadMore">load more</seasoned-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<loader v-if="!results.length" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { searchTmdb } from '@/api'
|
|
||||||
import ListHeader from '@/components/ListHeader'
|
|
||||||
import ResultsList from '@/components/ResultsList'
|
|
||||||
import SeasonedButton from '@/components/ui/SeasonedButton'
|
|
||||||
import Loader from '@/components/ui/Loader'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: { ListHeader, ResultsList, SeasonedButton, Loader },
|
|
||||||
props: {
|
|
||||||
propQuery: {
|
|
||||||
type: String,
|
|
||||||
required: false
|
|
||||||
},
|
|
||||||
propPage: {
|
|
||||||
type: Number,
|
|
||||||
required: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
loading: true,
|
|
||||||
query: String,
|
|
||||||
title: String,
|
|
||||||
page: Number,
|
|
||||||
totalPages: 0,
|
|
||||||
results: [],
|
|
||||||
totalResults: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
resultCount() {
|
|
||||||
const loadedResults = this.results.length
|
|
||||||
const totalResults = this.totalResults < 10000 ? this.totalResults : '∞'
|
|
||||||
return `${loadedResults} of ${totalResults} results`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
search(query=this.query, page=this.page) {
|
|
||||||
searchTmdb(query, page)
|
|
||||||
.then(this.parseResponse)
|
|
||||||
},
|
|
||||||
parseResponse(data) {
|
|
||||||
if (this.results.length > 0) {
|
|
||||||
this.results.push(...data.results)
|
|
||||||
} else {
|
|
||||||
this.results = data.results
|
|
||||||
}
|
|
||||||
|
|
||||||
this.totalPages = data.total_pages
|
|
||||||
this.totalResults = data.total_results || data.results.length
|
|
||||||
|
|
||||||
this.loading = false
|
|
||||||
},
|
|
||||||
loadMore() {
|
|
||||||
this.page++
|
|
||||||
|
|
||||||
window.history.replaceState({}, 'search', `/#/search?query=${this.query}&page=${this.page}`)
|
|
||||||
this.search()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
const { query, page } = this.$route.query
|
|
||||||
|
|
||||||
if (!query) {
|
|
||||||
// abort
|
|
||||||
console.error('abort, no query')
|
|
||||||
}
|
|
||||||
this.query = decodeURIComponent(query)
|
|
||||||
this.page = page ? page : 1
|
|
||||||
this.title = `Search results: ${this.query}`
|
|
||||||
|
|
||||||
this.search()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.fullwidth-button {
|
|
||||||
width: 100%;
|
|
||||||
margin: 1rem 0;
|
|
||||||
padding-bottom: 2rem;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<input
|
<input
|
||||||
ref="input"
|
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Search for a movie or show"
|
placeholder="Search for a movie or show"
|
||||||
autocorrect="off"
|
autocorrect="off"
|
||||||
@@ -16,7 +15,7 @@
|
|||||||
@keydown.up="navigateUp"
|
@keydown.up="navigateUp"
|
||||||
@keydown.down="navigateDown" />
|
@keydown.down="navigateDown" />
|
||||||
|
|
||||||
<svg class="search--icon" fill="currentColor"><use xlink:href="#iconSearch"></use></svg>
|
<svg class="search--icon"><use xlink:href="#iconSearch"></use></svg>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
@@ -44,9 +43,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import SeasonedButton from '@/components/ui/SeasonedButton'
|
import SeasonedButton from '@/components/ui/SeasonedButton.vue'
|
||||||
|
|
||||||
import { elasticSearchMoviesAndShows } from '@/api'
|
import { elasticSearchMoviesAndShows } from '@/api.js'
|
||||||
import config from '@/config.json'
|
import config from '@/config.json'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -94,13 +93,6 @@ export default {
|
|||||||
navigateUp() {
|
navigateUp() {
|
||||||
this.focus = true
|
this.focus = true
|
||||||
this.selectedResult--
|
this.selectedResult--
|
||||||
const input = this.$refs.input;
|
|
||||||
const textLength = input.value.length
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
input.focus()
|
|
||||||
input.setSelectionRange(textLength, textLength + 1)
|
|
||||||
}, 1)
|
|
||||||
},
|
},
|
||||||
handleInput(e){
|
handleInput(e){
|
||||||
this.selectedResult = 0
|
this.selectedResult = 0
|
||||||
@@ -112,21 +104,21 @@ export default {
|
|||||||
|
|
||||||
elasticSearchMoviesAndShows(this.query)
|
elasticSearchMoviesAndShows(this.query)
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
const data = resp.hits.hits
|
const data = resp.data.hits.hits
|
||||||
|
|
||||||
this.elasticSearchResults = data.map(item => {
|
this.elasticSearchResults = data.map(item => {
|
||||||
const index = item._index.slice(0, -1)
|
const index = item._index.slice(0, -1)
|
||||||
if (index === 'movie' || item._source.original_title) {
|
if (index === 'movie') {
|
||||||
return {
|
return {
|
||||||
name: item._source.original_title,
|
name: item._source.original_title,
|
||||||
id: item._source.id,
|
id: item._source.id,
|
||||||
type: 'movie'
|
type: index
|
||||||
}
|
}
|
||||||
} else if (index === 'show' || item._source.original_name) {
|
} else if (index === 'show') {
|
||||||
return {
|
return {
|
||||||
name: item._source.original_name,
|
name: item._source.original_name,
|
||||||
id: item._source.id,
|
id: item._source.id,
|
||||||
type: 'show'
|
type: index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -187,7 +179,7 @@ export default {
|
|||||||
z-index: 5;
|
z-index: 5;
|
||||||
min-height: $header-size;
|
min-height: $header-size;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
background-color: $background-color-secondary;
|
background-color: white;
|
||||||
|
|
||||||
@include mobile-only {
|
@include mobile-only {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -217,51 +209,49 @@ export default {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-bottom: 2px solid transparent;
|
border-bottom: 2px solid transparent;
|
||||||
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
color: $text-color-50;
|
|
||||||
|
|
||||||
&.active, &:hover, &:active {
|
&.active, &:hover, &:active {
|
||||||
color: $text-color;
|
color: $c-dark;
|
||||||
border-bottom: 2px solid $text-color;
|
border-bottom: 2px solid black;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.search {
|
.search {
|
||||||
height: $header-size;
|
height: $header-size-mobile;
|
||||||
display: flex;
|
display: flex;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
border: 0;
|
|
||||||
background-color: $background-color-secondary;
|
|
||||||
|
|
||||||
// TODO check if this is for mobile
|
// TODO check if this is for mobile
|
||||||
width: calc(100% - 110px);
|
width: calc(100% - 110px);
|
||||||
|
// width: 100%;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 55px;
|
right: 55px;
|
||||||
|
|
||||||
@include tablet-min{
|
@include tablet-min{
|
||||||
position: relative;
|
position: relative;
|
||||||
|
height: $header-size;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
|
// height: 75px;
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 13px 20px 13px 45px;
|
padding: 13px 20px 13px 45px;
|
||||||
outline: none;
|
outline: none;
|
||||||
margin: 0;
|
|
||||||
border: 0;
|
border: 0;
|
||||||
background-color: $background-color-secondary;
|
background-color: transparent;
|
||||||
|
color: $c-dark;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-size: 19px;
|
font-size: 19px;
|
||||||
color: $text-color;
|
|
||||||
transition: background-color .5s ease, color .5s ease;
|
|
||||||
|
|
||||||
@include tablet-min {
|
@include tablet-min {
|
||||||
padding: 13px 30px 13px 60px;
|
padding: 13px 30px 13px 60px;
|
||||||
@@ -271,7 +261,7 @@ export default {
|
|||||||
&--icon{
|
&--icon{
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
fill: $text-color-50;
|
fill: rgba($c-dark, 0.5);
|
||||||
transition: fill 0.5s ease;
|
transition: fill 0.5s ease;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@@ -6,24 +6,22 @@
|
|||||||
<span class="settings__info">Sign in to your plex account to get information about recently added movies and to see your watch history</span>
|
<span class="settings__info">Sign in to your plex account to get information about recently added movies and to see your watch history</span>
|
||||||
|
|
||||||
<form class="form">
|
<form class="form">
|
||||||
<seasoned-input placeholder="plex username" icon="Email" :value.sync="plexUsername"/>
|
<seasoned-input text="plex username" icon="Email"
|
||||||
<seasoned-input placeholder="plex password" icon="Keyhole" type="password"
|
@inputValue="setValue('plexUsername', $event)"/>
|
||||||
:value.sync="plexPassword" @submit="authenticatePlex" />
|
<seasoned-input text="plex password" icon="Keyhole" type="password"
|
||||||
|
@inputValue="setValue('plexPassword', $event)"/>
|
||||||
|
|
||||||
<seasoned-button @click="authenticatePlex">link plex account</seasoned-button>
|
<seasoned-button @click="authenticatePlex">link plex account</seasoned-button>
|
||||||
|
|
||||||
<seasoned-messages :messages.sync="messages" />
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<hr class='setting__divider'>
|
<hr class='setting__divider'>
|
||||||
|
|
||||||
<h3 class='settings__header'>Change password</h3>
|
<h3 class='settings__header'>Change password</h3>
|
||||||
<form class="form">
|
<form class="form">
|
||||||
<seasoned-input placeholder="new password" icon="Keyhole" type="password"
|
<seasoned-input text="new password" icon="Keyhole" type="password"
|
||||||
:value.sync="newPassword" />
|
@inputValue="setValue('newPass', $event)"/>
|
||||||
|
<seasoned-input text="repeat new password" icon="Keyhole" type="password"
|
||||||
<seasoned-input placeholder="repeat new password" icon="Keyhole" type="password"
|
@inputValue="setValue('newPassConfirm', $event)"/>
|
||||||
:value.sync="newPasswordRepeat" />
|
|
||||||
|
|
||||||
<seasoned-button @click="changePassword">change password</seasoned-button>
|
<seasoned-button @click="changePassword">change password</seasoned-button>
|
||||||
</form>
|
</form>
|
||||||
@@ -44,27 +42,26 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import storage from '@/storage'
|
import storage from '@/storage.js'
|
||||||
import SeasonedInput from '@/components/ui/SeasonedInput'
|
import SeasonedInput from '@/components/ui/SeasonedInput.vue'
|
||||||
import SeasonedButton from '@/components/ui/SeasonedButton'
|
import SeasonedButton from '@/components/ui/SeasonedButton.vue'
|
||||||
import SeasonedMessages from '@/components/ui/SeasonedMessages'
|
|
||||||
|
|
||||||
import { plexAuthenticate } from '@/api'
|
import { plexAuthenticate } from '@/api.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { SeasonedInput, SeasonedButton, SeasonedMessages },
|
components: { SeasonedInput, SeasonedButton },
|
||||||
data(){
|
data(){
|
||||||
return{
|
return{
|
||||||
userLoggedIn: '',
|
userLoggedIn: '',
|
||||||
messages: [],
|
plexUsername: undefined,
|
||||||
plexUsername: null,
|
plexPassword: undefined,
|
||||||
plexPassword: null,
|
newPass: undefined,
|
||||||
newPassword: null,
|
newPassConfirm: undefined
|
||||||
newPasswordRepeat: null
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setValue(l, t) {
|
setValue(l, t) {
|
||||||
|
console.log('l, t', l, t)
|
||||||
this[l] = t
|
this[l] = t
|
||||||
},
|
},
|
||||||
changePassword() {
|
changePassword() {
|
||||||
@@ -75,20 +72,18 @@ export default {
|
|||||||
let password = this.plexPassword
|
let password = this.plexPassword
|
||||||
|
|
||||||
plexAuthenticate(username, password)
|
plexAuthenticate(username, password)
|
||||||
.then(resp => {
|
.then((resp) => {
|
||||||
const data = resp.data
|
let data = resp.data;
|
||||||
this.messages.push({ type: 'success', title: 'Authenticated with plex', message: 'Successfully linked plex account with seasoned request' })
|
console.log('response from plex:', data.user)
|
||||||
|
|
||||||
console.log('response from plex:', data.username)
|
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
console.error(error);
|
console.log('error: ', error)
|
||||||
|
|
||||||
this.messages.push({ type: 'error', title: 'Something went wrong', message: error.message })
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created(){
|
created(){
|
||||||
|
document.title = 'Settings' + storage.pageTitlePostfix;
|
||||||
|
storage.backTitle = document.title;
|
||||||
if (localStorage.getItem('token')){
|
if (localStorage.getItem('token')){
|
||||||
this.userLoggedIn = true
|
this.userLoggedIn = true
|
||||||
}
|
}
|
||||||
@@ -99,7 +94,6 @@ export default {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "./src/scss/variables";
|
@import "./src/scss/variables";
|
||||||
@import "./src/scss/media-queries";
|
@import "./src/scss/media-queries";
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
@@ -129,16 +123,12 @@ a {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.settings {
|
.settings {
|
||||||
padding: 3rem;
|
padding: 35px;
|
||||||
|
|
||||||
@include mobile-only {
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__header {
|
&__header {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
color: $text-color;
|
color: $c-dark;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
|||||||
@@ -1,34 +1,52 @@
|
|||||||
<template>
|
<template>
|
||||||
<section>
|
<section class="profile">
|
||||||
<h1>Sign in</h1>
|
<div class="profile__content">
|
||||||
|
<h2 class='settings__header'>Sign in</h2>
|
||||||
|
|
||||||
<seasoned-input placeholder="username" icon="Email" type="username" :value.sync="username" />
|
<form class="form">
|
||||||
<seasoned-input placeholder="password" icon="Keyhole" type="password" :value.sync="password" @enter="signin"/>
|
<div class="form__buffer"></div>
|
||||||
|
|
||||||
<seasoned-button @click="signin">sign in</seasoned-button>
|
<seasoned-input text="username" icon="Email" type="username"
|
||||||
|
@inputValue="setValue('username', $event)" />
|
||||||
|
<seasoned-input text="username" icon="Keyhole" type="password"
|
||||||
|
@inputValue="setValue('password', $event)" />
|
||||||
|
|
||||||
<router-link class="link" to="/register">Don't have a user? Register here</router-link>
|
<seasoned-button @click="signin">sign in</seasoned-button>
|
||||||
<seasoned-messages :messages.sync="messages"></seasoned-messages>
|
|
||||||
|
<transition name="message-fade">
|
||||||
|
<div class="message" :class="messageClass" v-if="showMessage">
|
||||||
|
<span class="message-text">{{ messageText }}</span>
|
||||||
|
<span class="message-dismiss" @click="showMessage=false">X</span>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="form__group">
|
||||||
|
<router-link class="form__group-link" :to="{name: 'register'}" exact title="Sign in here">
|
||||||
|
<span class="form__group-signin">Don't have a user? Register here</span>
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import storage from '../storage'
|
import storage from '../storage.js'
|
||||||
import SeasonedInput from '@/components/ui/SeasonedInput'
|
import SeasonedInput from '@/components/ui/SeasonedInput.vue'
|
||||||
import SeasonedButton from '@/components/ui/SeasonedButton'
|
import SeasonedButton from '@/components/ui/SeasonedButton.vue'
|
||||||
import SeasonedMessages from '@/components/ui/SeasonedMessages'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { SeasonedInput, SeasonedButton, SeasonedMessages },
|
components: { SeasonedInput, SeasonedButton },
|
||||||
data(){
|
data(){
|
||||||
return{
|
return{
|
||||||
messages: [],
|
userLoggedIn: '',
|
||||||
username: null,
|
showMessage: false,
|
||||||
password: null
|
messageClass: 'message-success',
|
||||||
|
messageText: 'hello world',
|
||||||
|
username: undefined,
|
||||||
|
password: undefined
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -43,57 +61,98 @@ export default {
|
|||||||
username: username,
|
username: username,
|
||||||
password: password
|
password: password
|
||||||
})
|
})
|
||||||
.then(resp => {
|
.then(function (resp){
|
||||||
let data = resp.data;
|
let data = resp.data;
|
||||||
if (data.success){
|
if (data.success){
|
||||||
localStorage.setItem('token', data.token);
|
localStorage.setItem('token', data.token);
|
||||||
localStorage.setItem('username', username);
|
localStorage.setItem('username', username);
|
||||||
localStorage.setItem('admin', data.admin);
|
localStorage.setItem('admin', data.admin);
|
||||||
|
this.userLoggedIn = true;
|
||||||
|
|
||||||
eventHub.$emit('setUserStatus');
|
eventHub.$emit('setUserStatus');
|
||||||
this.$router.push({ name: 'profile' })
|
this.$router.push({ name: 'profile' })
|
||||||
}
|
}
|
||||||
})
|
}.bind(this))
|
||||||
.catch(error => {
|
.catch(function (error){
|
||||||
if (error.message.endsWith('401')) {
|
if (error.message.endsWith('401'))
|
||||||
this.messages.push({ type: 'warning', title: 'Access denied', message: 'Incorrect username or password' })
|
this.msg('Incorrect username or password ', 'warning')
|
||||||
}
|
else
|
||||||
else {
|
this.msg(error.message, 'warning')
|
||||||
this.messages.push({ type: 'error', title: 'Unexpected error', message: error.message })
|
}.bind(this));
|
||||||
}
|
},
|
||||||
});
|
msg(text, status){
|
||||||
}
|
if (status === 'warning')
|
||||||
|
this.messageClass = 'message-warning';
|
||||||
|
else if (status === 'success')
|
||||||
|
this.messageClass = 'message-success';
|
||||||
|
else
|
||||||
|
this.messageClass = 'message-info';
|
||||||
|
this.messageText = text;
|
||||||
|
this.showMessage = true;
|
||||||
|
// setTimeout(() => this.showMessage = false, 3500);
|
||||||
|
},
|
||||||
|
toggleView(){
|
||||||
|
this.register = false;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created(){
|
created(){
|
||||||
document.title = 'Sign in' + storage.pageTitlePostfix;
|
document.title = 'Sign in' + storage.pageTitlePostfix;
|
||||||
storage.backTitle = document.title;
|
storage.backTitle = document.title;
|
||||||
|
if (this.userLoggedIn == true) {
|
||||||
|
this.$router.push({ name: 'profile' })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted(){
|
||||||
|
// this.$refs.email.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "./src/scss/variables";
|
@import "./src/scss/variables";
|
||||||
|
@import "./src/scss/message";
|
||||||
|
|
||||||
section {
|
// DUPLICATE CODE
|
||||||
padding: 1.3rem;
|
.settings {
|
||||||
|
padding: 35px;
|
||||||
|
|
||||||
@include tablet-min {
|
&__header {
|
||||||
padding: 4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
color: $text-color;
|
color: $c-dark;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.profile__content {
|
||||||
|
padding: 35px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
.link {
|
.form {
|
||||||
display: block;
|
> div:last-child {
|
||||||
width: max-content;
|
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__group{
|
||||||
|
justify-content: unset;
|
||||||
|
&__input-icon {
|
||||||
|
margin-top: 8px;
|
||||||
|
height: 22px;
|
||||||
|
width: 22px;
|
||||||
|
}
|
||||||
|
&-input {
|
||||||
|
padding: 10px 5px 10px 45px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 17px;
|
||||||
|
width: 75%;
|
||||||
|
// @include desktop-min {
|
||||||
|
// width: 400px;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,105 +1,53 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="show" class="container">
|
<div v-if="show">
|
||||||
<h2 class="torrentHeader-text">Searching for: {{ editedSearchQuery || query }}</h2>
|
<h2 class="title">torrents: {{ query }}</h2>
|
||||||
<!-- <div class="torrentHeader">
|
|
||||||
<span class="torrentHeader-text">Searching for: </span>
|
|
||||||
|
|
||||||
|
|
||||||
<span id="search" :contenteditable="editSearchQuery ? true : false" class="torrentHeader-text editable">{{ editedSearchQuery || query }}</span>
|
|
||||||
|
|
||||||
|
|
||||||
<svg v-if="!editSearchQuery" class="torrentHeader-editIcon" @click="toggleEditSearchQuery">
|
|
||||||
<use xlink:href="#icon_radar"></use>
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
<svg v-else class="torrentHeader-editIcon" @click="toggleEditSearchQuery">
|
|
||||||
<use xlink:href="#icon_check"></use>
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<div v-if="listLoaded">
|
<div v-if="listLoaded">
|
||||||
<div v-if="torrents.length > 0">
|
<ul class="filter">
|
||||||
<ul class="filter">
|
<li class="filter-item" v-for="(item, index) in release_types" @click="applyFilter(item, index)" :class="{'active': item === selectedRelaseType}">{{ item }}</li>
|
||||||
<li class="filter-item" v-for="(item, index) in release_types" @click="applyFilter(item, index)" :class="{'active': item === selectedRelaseType}">{{ item }}</li>
|
</ul>
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr class="table__header noselect">
|
<tr class="table__header noselect">
|
||||||
<th @click="sortTable('name')" :class="selectedSortableClass('name')">
|
<th @click="sortTable('name')">
|
||||||
<span>Name</span>
|
<span>Name</span>
|
||||||
<span v-if="prevCol === 'name' && direction">↑</span>
|
<span v-if="prevCol === 'name' && direction">↑</span>
|
||||||
<span v-if="prevCol === 'name' && !direction">↓</span>
|
<span v-if="prevCol === 'name' && !direction">↓</span>
|
||||||
</th>
|
</th>
|
||||||
<th @click="sortTable('seed')" :class="selectedSortableClass('seed')">
|
<th @click="sortTable('seed')">
|
||||||
<span>Seed</span>
|
<span>Seed</span>
|
||||||
<span v-if="prevCol === 'seed' && direction">↑</span>
|
<span v-if="prevCol === 'seed' && direction">↑</span>
|
||||||
<span v-if="prevCol === 'seed' && !direction">↓</span>
|
<span v-if="prevCol === 'seed' && !direction">↓</span>
|
||||||
</th>
|
</th>
|
||||||
<th @click="sortTable('size')" :class="selectedSortableClass('size')">
|
<th @click="sortTable('size')">
|
||||||
<span>Size</span>
|
<span>Size</span>
|
||||||
<span v-if="prevCol === 'size' && direction">↑</span>
|
<span v-if="prevCol === 'size' && direction">↑</span>
|
||||||
<span v-if="prevCol === 'size' && !direction">↓</span>
|
<span v-if="prevCol === 'size' && !direction">↓</span>
|
||||||
<th>
|
<th>
|
||||||
<span>Magnet</span>
|
<span>Magnet</span>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="torrent in torrents" class="table__content">
|
<tr v-for="torrent in torrents" class="table__content">
|
||||||
<td @click="expand($event, torrent.name)">{{ torrent.name }}</td>
|
<td @click="expand($event, torrent.name)">{{ torrent.name }}</td>
|
||||||
<td @click="expand($event, torrent.name)">{{ torrent.seed }}</td>
|
<td @click="expand($event, torrent.name)">{{ torrent.seed }}</td>
|
||||||
<td @click="expand($event, torrent.name)">{{ torrent.size }}</td>
|
<td @click="expand($event, torrent.name)">{{ torrent.size }}</td>
|
||||||
<td @click="sendTorrent(torrent.magnet, torrent.name, $event)" class="download">
|
<td @click="sendTorrent(torrent.magnet, torrent.name, $event)" class="download">
|
||||||
<svg class="download__icon"><use xlink:href="#iconUnmatched"></use></svg>
|
<svg class="download__icon"><use xlink:href="#iconUnmatched"></use></svg>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div style="
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 1rem;
|
|
||||||
">
|
|
||||||
<seasonedButton @click="resetTorrentsAndToggleEditSearchQuery">Edit search query</seasonedButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else style="display: flex;
|
|
||||||
padding-bottom: 2rem;
|
|
||||||
justify-content: center;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
align-items: center;">
|
|
||||||
<h2>No results found</h2>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<div class="editQuery" v-if="editSearchQuery">
|
|
||||||
|
|
||||||
<seasonedInput placeholder="Torrent query" icon="_torrents" :value.sync="editedSearchQuery" @enter="fetchTorrents(editedSearchQuery)" />
|
|
||||||
|
|
||||||
<div style="height: 45px; width: 5px;"></div>
|
|
||||||
|
|
||||||
<seasonedButton @click="fetchTorrents(editedSearchQuery)">Search</seasonedButton>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<seasonedButton @click="toggleEditSearchQuery" :active="editSearchQuery ? true : false">Edit search query</seasonedButton>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<i v-else class="torrentloader"></i>
|
||||||
<div v-else class="torrentloader"><i></i></div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import storage from '@/storage'
|
import storage from '@/storage.js'
|
||||||
import store from '@/store'
|
import { sortableSize } from '@/utils.js'
|
||||||
import { sortableSize } from '@/utils'
|
import { searchTorrents, addMagnet } from '@/api.js'
|
||||||
import { searchTorrents, addMagnet } from '@/api'
|
|
||||||
|
|
||||||
import SeasonedButton from '@/components/ui/SeasonedButton'
|
|
||||||
import SeasonedInput from '@/components/ui/SeasonedInput'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { SeasonedButton, SeasonedInput },
|
|
||||||
props: {
|
props: {
|
||||||
query: {
|
query: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -116,34 +64,21 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
listLoaded: false,
|
listLoaded: false,
|
||||||
torrents: [],
|
torrents: undefined,
|
||||||
torrentResponse: undefined,
|
torrentResponse: undefined,
|
||||||
currentPage: 0,
|
currentPage: 0,
|
||||||
prevCol: '',
|
prevCol: '',
|
||||||
direction: false,
|
direction: false,
|
||||||
release_types: ['all'],
|
release_types: ['all'],
|
||||||
selectedRelaseType: 'all',
|
selectedRelaseType: 'all'
|
||||||
editSearchQuery: false,
|
|
||||||
editedSearchQuery: ''
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeMount() {
|
beforeMount() {
|
||||||
if (localStorage.getItem('admin')) {
|
if (localStorage.getItem('admin')) {
|
||||||
this.fetchTorrents()
|
this.fetchTorrents()
|
||||||
}
|
}
|
||||||
store.dispatch('torrentModule/reset')
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
selectedSortableClass(headerName) {
|
|
||||||
return headerName === this.prevCol ? 'active' : ''
|
|
||||||
},
|
|
||||||
resetTorrentsAndToggleEditSearchQuery() {
|
|
||||||
this.torrents = []
|
|
||||||
this.toggleEditSearchQuery()
|
|
||||||
},
|
|
||||||
toggleEditSearchQuery() {
|
|
||||||
this.editSearchQuery = !this.editSearchQuery;
|
|
||||||
},
|
|
||||||
expand(event, name) {
|
expand(event, name) {
|
||||||
const existingExpandedElement = document.getElementsByClassName('expanded')[0]
|
const existingExpandedElement = document.getElementsByClassName('expanded')[0]
|
||||||
|
|
||||||
@@ -249,41 +184,35 @@ export default {
|
|||||||
this.torrents = torrents.filter(torrent => torrent.release_type.includes(item))
|
this.torrents = torrents.filter(torrent => torrent.release_type.includes(item))
|
||||||
this.sortTable(this.prevCol, true)
|
this.sortTable(this.prevCol, true)
|
||||||
},
|
},
|
||||||
updateResultCountInStore() {
|
fetchTorrents(){
|
||||||
store.dispatch('torrentModule/setResults', this.torrents)
|
searchTorrents(this.query, 'all', this.currentPage, storage.token)
|
||||||
store.dispatch('torrentModule/setResultCount', this.torrentResponse.length)
|
.then(resp => {
|
||||||
},
|
let data = resp.data;
|
||||||
fetchTorrents(query=undefined){
|
console.log('data results', data.results);
|
||||||
this.listLoaded = false;
|
this.torrentResponse = data.results;
|
||||||
this.editSearchQuery = false;
|
this.torrents = data.results;
|
||||||
|
|
||||||
searchTorrents(query || this.query, 'all', this.currentPage, storage.token)
|
|
||||||
.then(data => {
|
|
||||||
this.torrentResponse = [...data.results];
|
|
||||||
this.torrents = data.results;
|
|
||||||
this.listLoaded = true;
|
|
||||||
})
|
|
||||||
.then(this.updateResultCountInStore)
|
|
||||||
.then(this.findRelaseTypes)
|
|
||||||
.catch(e => {
|
|
||||||
const error = e.toString()
|
|
||||||
this.errorMessage = error.indexOf('401') != -1 ? 'Permission denied' : 'Nothing found';
|
|
||||||
this.listLoaded = true;
|
this.listLoaded = true;
|
||||||
});
|
})
|
||||||
|
.then(this.findRelaseTypes)
|
||||||
|
.catch(e => {
|
||||||
|
const error = e.toString()
|
||||||
|
this.errorMessage = error.indexOf('401') != -1 ? 'Permission denied' : 'Nothing found';
|
||||||
|
this.listLoaded = true;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss">
|
||||||
@import "./src/scss/variables";
|
@import "./src/scss/variables";
|
||||||
.expanded {
|
.expanded {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin: 0 1rem;
|
margin: 0 1rem;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
border-left: 1px solid $text-color;
|
border-left: 1px solid rgba($c-dark, 0.5);
|
||||||
border-right: 1px solid $text-color;
|
border-right: 1px solid rgba($c-dark, 0.5);
|
||||||
border-bottom: 1px solid $text-color;
|
border-bottom: 1px solid rgba($c-dark, 0.5);
|
||||||
|
|
||||||
td {
|
td {
|
||||||
// border-left: 1px solid $c-dark;
|
// border-left: 1px solid $c-dark;
|
||||||
@@ -298,44 +227,16 @@ export default {
|
|||||||
@import "./src/scss/media-queries";
|
@import "./src/scss/media-queries";
|
||||||
@import "./src/scss/elements";
|
@import "./src/scss/elements";
|
||||||
|
|
||||||
.container {
|
.title {
|
||||||
background-color: $background-color;
|
margin: 0;
|
||||||
}
|
font-weight: 400;
|
||||||
|
text-transform: uppercase;
|
||||||
.torrentHeader {
|
text-align: center;
|
||||||
display: flex;
|
font-size: 14px;
|
||||||
align-items: center;
|
color: $c-green;
|
||||||
justify-content: center;
|
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
|
@include tablet-min{
|
||||||
|
font-size: 16px;
|
||||||
&-text {
|
|
||||||
font-weight: 400;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-size: 14px;
|
|
||||||
color: $green;
|
|
||||||
text-align: center;
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
@include tablet-min {
|
|
||||||
font-size: 16px
|
|
||||||
}
|
|
||||||
|
|
||||||
&.editable {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-editIcon {
|
|
||||||
margin-left: 10px;
|
|
||||||
margin-top: -3px;
|
|
||||||
width: 22px;
|
|
||||||
height: 22px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
fill: $green;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,9 +250,9 @@ table {
|
|||||||
display: flex;
|
display: flex;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0 1rem;
|
margin: 0 1rem;
|
||||||
border-left: 1px solid $text-color;
|
border-left: 1px solid rgba($c-dark, 0.8);
|
||||||
border-right: 1px solid $text-color;
|
border-right: 1px solid rgba($c-dark, 0.8);
|
||||||
border-bottom: 1px solid $text-color;
|
border-bottom: 1px solid rgba($c-dark, 0.8);
|
||||||
|
|
||||||
th, td {
|
th, td {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -363,7 +264,6 @@ table {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
min-width: 75px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
th:first-child, td:first-child {
|
th:first-child, td:first-child {
|
||||||
@@ -397,7 +297,7 @@ table {
|
|||||||
|
|
||||||
.table__content {
|
.table__content {
|
||||||
td:not(:last-child) {
|
td:not(:last-child) {
|
||||||
border-right: 1px solid $text-color;
|
border-right: 1px solid rgba($c-dark, 0.8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,12 +309,12 @@ table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.table__header {
|
.table__header {
|
||||||
color: $text-color;
|
background-color: white;
|
||||||
|
color: $c-dark;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: $background-color-secondary;
|
|
||||||
|
|
||||||
border-top: 1px solid $text-color;
|
border-top: 1px solid rgba($c-dark, 0.8);
|
||||||
border-top-left-radius: 3px;
|
border-top-left-radius: 3px;
|
||||||
border-top-right-radius: 3px;
|
border-top-right-radius: 3px;
|
||||||
|
|
||||||
@@ -440,66 +340,47 @@ table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
th:not(:last-child) {
|
th:not(:last-child) {
|
||||||
border-right: 1px solid $text-color;
|
border-right: 1px solid rgba($c-dark, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.editQuery {
|
|
||||||
display: flex;
|
|
||||||
width: 70%;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
@include mobile-only {
|
|
||||||
width: 90%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.download {
|
.download {
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
fill: $text-color-70;
|
fill: rgba($c-dark, 0.6);
|
||||||
height: 1.2rem;
|
height: 1.2rem;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
fill: $text-color;
|
fill: $c-dark;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active &__icon {
|
&.active &__icon {
|
||||||
fill: $green;
|
fill: $c-green;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.torrentloader {
|
.torrentloader{
|
||||||
width: 100%;
|
animation: load 1s linear infinite;
|
||||||
padding: 2rem 0;
|
border: 2px solid $c-dark;
|
||||||
|
border-radius: 50%;
|
||||||
i {
|
display: block;
|
||||||
animation: load 1s linear infinite;
|
height: 30px;
|
||||||
border: 2px solid $text-color;
|
left: 50%;
|
||||||
|
margin: 2rem auto;
|
||||||
|
width: 30px;
|
||||||
|
&:after {
|
||||||
|
border: 5px solid $c-green;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
display: block;
|
content: '';
|
||||||
height: 30px;
|
left: 10px;
|
||||||
left: 50%;
|
position: absolute;
|
||||||
margin: 0 auto;
|
top: 16px;
|
||||||
width: 30px;
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
border: 5px solid $green;
|
|
||||||
border-radius: 50%;
|
|
||||||
content: '';
|
|
||||||
left: 10px;
|
|
||||||
position: absolute;
|
|
||||||
top: 16px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@keyframes load {
|
@keyframes load {
|
||||||
100% { transform: rotate(360deg); }
|
100% { transform: rotate(360deg); }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
95
src/components/movie/SidebarAction.vue
Normal file
95
src/components/movie/SidebarAction.vue
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
<template>
|
||||||
|
<div class="action">
|
||||||
|
<a class="action-link" :class="{'active': active}" @click="$emit('click')">
|
||||||
|
<svg class="action-icon">
|
||||||
|
<use v-if="active && iconRefActive" :xlink:href="iconRefActive"></use>
|
||||||
|
<use v-else :xlink:href="iconRef"></use>
|
||||||
|
</svg>
|
||||||
|
<span class="action-text">{{ active && textActive ? textActive : text }}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
iconRef: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
iconRefActive: {
|
||||||
|
type: String,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
active: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
textActive: {
|
||||||
|
type: String,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "./src/scss/loading-placeholder";
|
||||||
|
@import "./src/scss/variables";
|
||||||
|
@import "./src/scss/media-queries";
|
||||||
|
|
||||||
|
.action {
|
||||||
|
&-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
text-decoration: none;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: rgba($c-dark, 0.5);
|
||||||
|
transition: color 0.5s ease;
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 5px 0;
|
||||||
|
border-bottom: 1px solid rgba($c-dark, 0.05);
|
||||||
|
&:hover {
|
||||||
|
color: rgba($c-dark, 0.75);
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
color: $c-dark;
|
||||||
|
}
|
||||||
|
&.pending {
|
||||||
|
color: #f8bd2d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
margin: 0 10px 0 0;
|
||||||
|
fill: rgba($c-dark, 0.5);
|
||||||
|
transition: fill 0.5s ease, transform 0.5s ease;
|
||||||
|
&.waiting {
|
||||||
|
transform: scale(0.8, 0.8);
|
||||||
|
}
|
||||||
|
&.pending {
|
||||||
|
fill: #f8bd2d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-link:hover &-icon {
|
||||||
|
fill: rgba($c-dark, 0.75);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
&-link.active &-icon {
|
||||||
|
fill: $c-green;
|
||||||
|
}
|
||||||
|
&-text {
|
||||||
|
display: block;
|
||||||
|
padding-top: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin:4.4px;
|
||||||
|
margin-left: -3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -17,26 +17,29 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&--icon{
|
&--icon{
|
||||||
border: 2px solid $text-color-70;
|
border: 2px solid rgba($c-dark, 0.9);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
display: block;
|
display: block;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
// left: 50%;
|
||||||
|
// margin: -1.5em;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
|
|
||||||
&-spinner {
|
&-spinner {
|
||||||
display: block;
|
// border: 2px solid transparent;
|
||||||
|
display: block;
|
||||||
animation: load 1s linear infinite;
|
animation: load 1s linear infinite;
|
||||||
height: 35px;
|
height: 35px;
|
||||||
width: 35px;
|
width: 35px;
|
||||||
&:after {
|
&:after {
|
||||||
border: 7px solid $green-90;
|
border: 7px solid rgba($c-green, 0.9);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
content: '';
|
content: '';
|
||||||
left: 8px;
|
left: 8px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 22px;
|
top: 22px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@keyframes load {
|
@keyframes load {
|
||||||
|
|||||||
@@ -1,133 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<label v-for="option in options" class="radio" @click="selected = option.value">
|
|
||||||
<input type="radio" v-model="selected" :value="option.value" />
|
|
||||||
<label>{{ option.text }}</label>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="sub-radios" v-if="option.subElements && selected === option.value">
|
|
||||||
<label class="radio" v-for="elem in option.subElements">
|
|
||||||
<input type="radio" v-model="selectedSubItem" :value="option.value + '-' + elem.value" />
|
|
||||||
<label>{{ elem.text }}</label>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
options: {
|
|
||||||
type: Array,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
required: false,
|
|
||||||
default: undefined
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
selected: this.value || this.options[0].value,
|
|
||||||
selectedSubItem: null
|
|
||||||
};
|
|
||||||
},
|
|
||||||
beforeMount() {
|
|
||||||
this.handleChange()
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
selected() {
|
|
||||||
this.handleChange();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleChange() {
|
|
||||||
if (this.value !== undefined) {
|
|
||||||
this.$emit("update:value", this.selected);
|
|
||||||
} else {
|
|
||||||
this.$emit("changed", this.selected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import "./src/scss/variables.scss";
|
|
||||||
|
|
||||||
$radioSize: 16px;
|
|
||||||
$ui-border-width: 2px;
|
|
||||||
|
|
||||||
.sub-radios {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex: 0 0 100%;
|
|
||||||
margin-left: 1rem;
|
|
||||||
|
|
||||||
&:first-of-type {
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin-bottom: 14px;
|
|
||||||
width: max-content;
|
|
||||||
|
|
||||||
input[type="radio"] {
|
|
||||||
display: block;
|
|
||||||
opacity: 0;
|
|
||||||
|
|
||||||
+ label {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
cursor: pointer;
|
|
||||||
padding-left: 1.25rem;
|
|
||||||
font-weight: 300;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: "";
|
|
||||||
display: inline-block;
|
|
||||||
position: absolute;
|
|
||||||
left: -($radioSize / 4) * 4;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: $ui-border-width solid $text-color-70;
|
|
||||||
width: $radioSize;
|
|
||||||
height: $radioSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
display: inline-block;
|
|
||||||
left: -($radioSize / 4) * 3;
|
|
||||||
top: $radioSize / 4;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: ($radioSize / 4) * 3;
|
|
||||||
height: ($radioSize / 4) * 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:checked,
|
|
||||||
&:hover {
|
|
||||||
+ label::after {
|
|
||||||
background-color: $green;
|
|
||||||
}
|
|
||||||
+ label::before {
|
|
||||||
border-color: $text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
+ label::before {
|
|
||||||
outline: $ui-border-width solid Highlight;
|
|
||||||
outline-style: auto;
|
|
||||||
outline-color: -webkit-focus-ring-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -13,6 +13,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
emit() {
|
emit() {
|
||||||
|
console.log('emitted')
|
||||||
this.$emit('click')
|
this.$emit('click')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,30 +26,36 @@ export default {
|
|||||||
|
|
||||||
.button{
|
.button{
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border: 1px solid $text-color;
|
border: 1px solid $c-dark;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
background: $c-dark;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
line-height: 2;
|
line-height: 2;
|
||||||
height: 45px;
|
letter-spacing: 0.5px;
|
||||||
letter-spacing: 1.2px;
|
|
||||||
padding: 5px 20px 4px 20px;
|
padding: 5px 20px 4px 20px;
|
||||||
margin: 0;
|
|
||||||
margin-right: 0.3rem;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: $text-color;
|
color: $c-dark;
|
||||||
background: $background-color-secondary;
|
background: transparent;
|
||||||
outline: none;
|
outline: none;
|
||||||
transition: background 0.5s ease, color 0.5s ease, border-color .5s ease;
|
transition: background 0.5s ease, color 0.5s ease;
|
||||||
|
|
||||||
@include tablet-min{
|
@include tablet-min{
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 6px 20px 5px 20px;
|
padding: 6px 20px 5px 20px;
|
||||||
}
|
}
|
||||||
|
&:active, &:hover{
|
||||||
body:not(.touch) &:hover, &:focus, &:active, &.active {
|
background: $c-dark;
|
||||||
background: $text-color;
|
color: $c-white;
|
||||||
color: $background-color;
|
}
|
||||||
|
body:not(.touch) &:hover, &:focus{
|
||||||
|
background: $c-dark;
|
||||||
|
color: $c-white;
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
@extend .button;
|
||||||
|
background: $c-dark;
|
||||||
|
color: $c-white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -1,37 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="group" :class="{ completed: value }">
|
<div class="group" :class="{ completed: value.length > 0 }">
|
||||||
<svg class="group__input-icon"><use v-bind="{'xlink:href':'#icon' + icon}"></use></svg>
|
<svg class="group__input-icon"><use v-bind="{'xlink:href':'#icon' + icon}"></use></svg>
|
||||||
<input class="group__input" :type="tempType || type" @input="handleInput" v-model="inputValue"
|
<input class="group__input" :type="tempType || type" ref="plex_username"
|
||||||
:placeholder="placeholder" @keyup.enter="submit" />
|
v-model="value" :placeholder="text" @input="handleInput" />
|
||||||
|
|
||||||
<i v-if="value && type === 'password'" @click="toggleShowPassword" class="group__input-show noselect">show</i>
|
<i v-if="value.length > 0 && type === 'password'" @click="toggleShowPassword" class="group__input-show noselect">show</i>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
placeholder: { type: String },
|
text: { type: String },
|
||||||
icon: { type: String },
|
icon: { type: String },
|
||||||
type: { type: String, default: 'text' },
|
type: { type: String }
|
||||||
value: { type: String, default: undefined }
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return { value: '', tempType: undefined }
|
||||||
inputValue: this.value || undefined,
|
|
||||||
tempType: undefined
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
submit(event) {
|
handleInput(value) {
|
||||||
this.$emit('enter')
|
console.log('this.value', this.value)
|
||||||
},
|
this.$emit('inputValue', this.value)
|
||||||
handleInput(event) {
|
|
||||||
if (this.value !== undefined) {
|
|
||||||
this.$emit('update:value', this.inputValue)
|
|
||||||
} else {
|
|
||||||
this.$emit('change', this.inputValue, event)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
toggleShowPassword() {
|
toggleShowPassword() {
|
||||||
if (this.tempType === 'text') {
|
if (this.tempType === 'text') {
|
||||||
@@ -50,45 +40,42 @@ export default {
|
|||||||
.group{
|
.group{
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
&:hover, &:focus {
|
&:hover, &:focus {
|
||||||
.group__input {
|
.group__input {
|
||||||
border-color: $text-color;
|
border-color: $c-dark;
|
||||||
|
|
||||||
&-icon {
|
&-icon {
|
||||||
fill: $text-color;
|
fill: $c-dark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.completed {
|
&.completed {
|
||||||
.group__input {
|
.group__input {
|
||||||
border-color: $text-color;
|
border-color: $c-dark;
|
||||||
|
|
||||||
&-icon {
|
&-icon {
|
||||||
fill: $text-color;
|
fill: $c-dark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__input {
|
&__input {
|
||||||
width: 100%;
|
width: 75%;
|
||||||
max-width: 35rem;
|
max-width: 35rem;
|
||||||
padding: 10px 10px 10px 45px;
|
padding: 10px 10px 10px 45px;
|
||||||
|
// padding: 15px 10px 15px 45px;
|
||||||
outline: none;
|
outline: none;
|
||||||
background-color: $background-color-secondary;
|
background-color: $c-white;
|
||||||
color: $text-color;
|
color: $c-dark;
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
border: 1px solid $text-color-50;
|
border: 1px solid rgba($c-dark, 0.5);
|
||||||
margin: 0;
|
margin-left: -2.2rem;
|
||||||
margin-left: -2.2rem !important;
|
// margin-bottom: 1rem;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
transition: color .5s ease, background-color .5s ease, border .5s ease;
|
transition: border-color .5s ease;
|
||||||
|
|
||||||
border-radius: 0;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
|
|
||||||
&-show {
|
&-show {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -98,14 +85,14 @@ export default {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: $text-color-50;
|
color: rgba($c-dark, 0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__input-icon {
|
&__input-icon {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
fill: $text-color-50;
|
fill: rgba($c-dark, 0.5);
|
||||||
transition: fill 0.5s ease;
|
transition: fill 0.5s ease;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
|||||||
@@ -1,169 +0,0 @@
|
|||||||
<template>
|
|
||||||
<transition-group name="fade">
|
|
||||||
<div class="message" v-for="(message, index) in reversedMessages" :class="message.type || 'warning'" :key="index">
|
|
||||||
<span class="pinstripe"></span>
|
|
||||||
<div>
|
|
||||||
<h2>{{ message.title || defaultTitles[message.type] }}</h2>
|
|
||||||
<span>{{ message.message }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button class="dismiss" @click="clicked(message)">X</button>
|
|
||||||
</div>
|
|
||||||
</transition-group>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
messages: {
|
|
||||||
required: true,
|
|
||||||
type: Array
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
defaultTitles: {
|
|
||||||
error: 'Unexpected error',
|
|
||||||
warning: 'Something went wrong',
|
|
||||||
undefined: 'Something went wrong'
|
|
||||||
},
|
|
||||||
localMessages: [...this.messages]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
reversedMessages() {
|
|
||||||
return [...this.messages].reverse()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
clicked(e) {
|
|
||||||
const removedMessage = [...this.messages].filter(mes => mes !== e)
|
|
||||||
this.$emit('update:messages', removedMessage)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// watch: {
|
|
||||||
// messages(propState, oldState) {
|
|
||||||
// const newMessage = propState.filter(msg => !this.localMessages.includes(msg))
|
|
||||||
// console.log('newMessage', newMessage)
|
|
||||||
// this.localMessages = this.localMessages.concat(newMessage)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import "./src/scss/variables";
|
|
||||||
@import "./src/scss/media-queries";
|
|
||||||
|
|
||||||
.fade-enter-active {
|
|
||||||
transition: opacity .4s;
|
|
||||||
}
|
|
||||||
.fade-leave-active {
|
|
||||||
transition: opacity .1s;
|
|
||||||
}
|
|
||||||
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 35rem;
|
|
||||||
height: 75px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
margin-top: 1rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
color: $text-color-70;
|
|
||||||
|
|
||||||
> div {
|
|
||||||
margin: 6px 24px;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-weight: 300;
|
|
||||||
letter-spacing: 0.25px;
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.3rem;
|
|
||||||
color: $text-color;
|
|
||||||
transition: color .5s ease;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
font-weight: 300;
|
|
||||||
color: $text-color-70;
|
|
||||||
transition: color .5s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include mobile-only {
|
|
||||||
> div {
|
|
||||||
margin: 6px 6px;
|
|
||||||
line-height: 1.3rem;
|
|
||||||
}
|
|
||||||
h2 {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.pinstripe {
|
|
||||||
height: 100%;
|
|
||||||
width: 0.5rem;
|
|
||||||
// background-color: $color-error-highlight;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dismiss {
|
|
||||||
position: relative;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
-moz-appearance: none;
|
|
||||||
background-color: transparent;
|
|
||||||
border: unset;
|
|
||||||
font-size: 18px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
top: 0;
|
|
||||||
float: right;
|
|
||||||
height: 1.5rem;
|
|
||||||
width: 1.5rem;
|
|
||||||
padding: 0;
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
color: $text-color-70;
|
|
||||||
transition: color .5s ease;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: $text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.success {
|
|
||||||
background-color: $color-success;
|
|
||||||
|
|
||||||
.pinstripe {
|
|
||||||
background-color: $color-success-highlight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.error {
|
|
||||||
background-color: $color-error;
|
|
||||||
|
|
||||||
.pinstripe {
|
|
||||||
background-color: $color-error-highlight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.warning {
|
|
||||||
background-color: $color-warning;
|
|
||||||
|
|
||||||
.pinstripe {
|
|
||||||
background-color: $color-warning-highlight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="wrapper">
|
|
||||||
<h3 v-if="title" class="title">{{ title }}</h3>
|
|
||||||
<textarea :placeholder="placeholder" @input="handleInput" v-model="value" :rows="rows" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
placeholder: {
|
|
||||||
type: String,
|
|
||||||
required: false
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
required: false
|
|
||||||
},
|
|
||||||
rows: {
|
|
||||||
type: Number,
|
|
||||||
required: false,
|
|
||||||
default: 10
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
default: undefined
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleInput(event) {
|
|
||||||
if (this.value !== undefined) {
|
|
||||||
this.$emit('update:value', this.value)
|
|
||||||
} else {
|
|
||||||
this.$emit('input', this.value, event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import "./src/scss/variables.scss";
|
|
||||||
|
|
||||||
.wrapper {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
margin: 0;
|
|
||||||
font-weight: 400;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-size: 14px;
|
|
||||||
color: $green;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
@include tablet-min {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
width: 100%;
|
|
||||||
font-size: 14px;
|
|
||||||
padding: 0.5rem;
|
|
||||||
border: 2px solid $text-color-50;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
border-color: $text-color;
|
|
||||||
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
-webkit-box-shadow: none;
|
|
||||||
-moz-box-shadow: none;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
<template>
|
|
||||||
|
|
||||||
<div class="darkToggle">
|
|
||||||
<span @click="toggleDarkmode()">{{ darkmodeToggleIcon }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
darkmode: window.getComputedStyle(document.body).colorScheme.includes('dark')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
toggleDarkmode() {
|
|
||||||
this.darkmode = !this.darkmode;
|
|
||||||
document.body.className = this.darkmode ? 'dark' : 'light'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
darkmodeToggleIcon() {
|
|
||||||
return this.darkmode ? '🌝' : '🌚'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.darkToggle {
|
|
||||||
height: 25px;
|
|
||||||
width: 25px;
|
|
||||||
cursor: pointer;
|
|
||||||
// background-color: red;
|
|
||||||
position: fixed;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
margin-right: 2px;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: 1;
|
|
||||||
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<a @click="$emit('click')"><li>
|
|
||||||
<figure :class="activeClassIfActive" v-if="iconRefNameIfActive">
|
|
||||||
<svg class="icon">
|
|
||||||
<use :xlink:href="iconRefNameIfActive"/>
|
|
||||||
</svg>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
<span :class="activeClassIfActive">{{ contentTextToDisplay }}</span>
|
|
||||||
|
|
||||||
<span v-if="supplementaryText" class="supplementary-text">
|
|
||||||
{{ supplementaryText }}
|
|
||||||
</span>
|
|
||||||
</li></a>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// TODO if a image is hovered and we can't set the hover color we want to
|
|
||||||
// go into it and change the fill
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
iconRef: {
|
|
||||||
type: String,
|
|
||||||
required: false
|
|
||||||
},
|
|
||||||
iconRefActive: {
|
|
||||||
type: String,
|
|
||||||
required: false
|
|
||||||
},
|
|
||||||
active: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
textActive: {
|
|
||||||
type: String,
|
|
||||||
required: false
|
|
||||||
},
|
|
||||||
supplementaryText: {
|
|
||||||
type: String,
|
|
||||||
required: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
iconRefNameIfActive() {
|
|
||||||
const { iconRefActive, iconRef, active } = this
|
|
||||||
|
|
||||||
if ((iconRefActive && iconRef) && active) {
|
|
||||||
return iconRefActive
|
|
||||||
}
|
|
||||||
return iconRef
|
|
||||||
},
|
|
||||||
contentTextToDisplay() {
|
|
||||||
const { textActive, active, $slots } = this
|
|
||||||
|
|
||||||
if (textActive && active)
|
|
||||||
return textActive
|
|
||||||
|
|
||||||
if ($slots.default && $slots.default.length > 0)
|
|
||||||
return $slots.default[0].text
|
|
||||||
|
|
||||||
return ''
|
|
||||||
},
|
|
||||||
activeClassIfActive() {
|
|
||||||
return this.active ? 'active' : ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import "./src/scss/variables";
|
|
||||||
@import "./src/scss/media-queries";
|
|
||||||
|
|
||||||
li {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
text-decoration: none;
|
|
||||||
text-transform: uppercase;
|
|
||||||
color: $text-color-50;
|
|
||||||
transition: color 0.5s ease;
|
|
||||||
font-size: 11px;
|
|
||||||
padding: 10px 0;
|
|
||||||
border-bottom: 1px solid $text-color-5;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: $text-color-70;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.active {
|
|
||||||
color: $text-color;
|
|
||||||
}
|
|
||||||
.pending {
|
|
||||||
color: #f8bd2d;
|
|
||||||
}
|
|
||||||
|
|
||||||
.supplementary-text {
|
|
||||||
flex-grow: 1;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
figure, figure > .icon {
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
margin: 0 7px 0 0;
|
|
||||||
fill: $text-color-50;
|
|
||||||
transition: fill 0.5s ease, transform 0.5s ease;
|
|
||||||
&.waiting {
|
|
||||||
transform: scale(0.8, 0.8);
|
|
||||||
}
|
|
||||||
&.pending {
|
|
||||||
fill: #f8bd2d;
|
|
||||||
}
|
|
||||||
&:hover &-icon {
|
|
||||||
fill: $text-color-70;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
&.active > svg {
|
|
||||||
fill: $green;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -2,7 +2,6 @@ import Vue from 'vue'
|
|||||||
import VueRouter from 'vue-router'
|
import VueRouter from 'vue-router'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import router from './routes'
|
import router from './routes'
|
||||||
import store from './store'
|
|
||||||
|
|
||||||
import Toast from './plugins/Toast'
|
import Toast from './plugins/Toast'
|
||||||
import DataTablee from 'vue-data-tablee'
|
import DataTablee from 'vue-data-tablee'
|
||||||
@@ -17,12 +16,9 @@ Vue.use(Toast)
|
|||||||
Vue.use(DataTablee)
|
Vue.use(DataTablee)
|
||||||
Vue.use(VModal, { dialog: true })
|
Vue.use(VModal, { dialog: true })
|
||||||
|
|
||||||
store.dispatch('darkmodeModule/findAndSetDarkmodeSupported')
|
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#app',
|
el: '#app',
|
||||||
router,
|
router,
|
||||||
store,
|
|
||||||
components: { App },
|
components: { App },
|
||||||
template: '<App />'
|
template: '<App />'
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
export default {
|
|
||||||
namespaced: true,
|
|
||||||
state: {
|
|
||||||
darkmodeSupported: undefined,
|
|
||||||
userChoice: undefined
|
|
||||||
},
|
|
||||||
getters: {
|
|
||||||
darkmodeSupported: (state) => {
|
|
||||||
return state.darkmodeSupported
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mutations: {
|
|
||||||
SET_DARKMODE_SUPPORT: (state, browserSupported) => {
|
|
||||||
state.darkmodeSupported = browserSupported
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
findAndSetDarkmodeSupported({ commit }) {
|
|
||||||
const browserSupported = window.matchMedia('(prefers-color-scheme)').media !== 'not all'
|
|
||||||
commit('SET_DARKMODE_SUPPORT', browserSupported)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
const capitalize = (string) => {
|
|
||||||
return string.includes(' ') ?
|
|
||||||
string.split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1).replace('_', ' ')).join(' ')
|
|
||||||
: string.charAt(0).toUpperCase() + string.slice(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
const setDocumentTitle = (state) => {
|
|
||||||
document.title = `${state.emoji} ${state.titlePrefix} | ${capitalize(state.title)}`
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
namespaced: true,
|
|
||||||
state: {
|
|
||||||
emoji: '🍕',
|
|
||||||
titlePrefix: 'request',
|
|
||||||
title: undefined
|
|
||||||
},
|
|
||||||
getters: {
|
|
||||||
title: (state) => {
|
|
||||||
return state.title
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mutations: {
|
|
||||||
SET_EMOJI: (state, emoji) => {
|
|
||||||
state.emoji = emoji
|
|
||||||
setDocumentTitle(state)
|
|
||||||
},
|
|
||||||
SET_TITLE: (state, title) => {
|
|
||||||
state.title = title
|
|
||||||
setDocumentTitle(state)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
updateEmoji({ commit }, emoji) {
|
|
||||||
commit('SET_EMOJI', emoji)
|
|
||||||
},
|
|
||||||
updateTitle({ commit }, title) {
|
|
||||||
commit('SET_TITLE', title)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
|
|
||||||
export default {
|
|
||||||
namespaced: true,
|
|
||||||
state: {
|
|
||||||
results: [],
|
|
||||||
resultCount: null
|
|
||||||
},
|
|
||||||
getters: {
|
|
||||||
results: (state) => {
|
|
||||||
return state.results
|
|
||||||
},
|
|
||||||
resultCount: (state) => {
|
|
||||||
return state.resultCount
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mutations: {
|
|
||||||
SET_RESULTS: (state, results) => {
|
|
||||||
state.results = results;
|
|
||||||
},
|
|
||||||
SET_RESULT_COUNT: (state, count) => {
|
|
||||||
state.resultCount = count;
|
|
||||||
},
|
|
||||||
RESET: (state) => {
|
|
||||||
state.results = []
|
|
||||||
state.resultCount = null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
setResults({ commit }, results) {
|
|
||||||
commit('SET_RESULTS', results)
|
|
||||||
},
|
|
||||||
setResultCount({ commit }, count) {
|
|
||||||
commit('SET_RESULT_COUNT', count)
|
|
||||||
},
|
|
||||||
reset({ commit }) {
|
|
||||||
commit('RESET')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import VueRouter from 'vue-router';
|
import VueRouter from 'vue-router';
|
||||||
import store from '@/store'
|
|
||||||
|
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
@@ -19,35 +18,37 @@ let routes = [
|
|||||||
{
|
{
|
||||||
name: 'list',
|
name: 'list',
|
||||||
path: '/list/:name',
|
path: '/list/:name',
|
||||||
component: (resolve) => require(['./components/ListPage.vue'], resolve)
|
component: (resolve) => require(['./components/MoviesList.vue'], resolve)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'request',
|
name: 'request',
|
||||||
path: '/request/all',
|
path: '/request/all',
|
||||||
components: {
|
components: {
|
||||||
'request-router-view': require('./components/ListPage.vue')
|
'request-router-view': require('./components/MoviesList.vue')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'search',
|
name: 'search',
|
||||||
path: '/search',
|
path: '/search',
|
||||||
component: (resolve) => require(['./components/Search.vue'], resolve)
|
component: (resolve) => require(['./components/MoviesList.vue'], resolve)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'register',
|
name: 'register',
|
||||||
path: '/register',
|
path: '/register',
|
||||||
component: (resolve) => require(['./components/Register.vue'], resolve)
|
component: (resolve) => require(['./components/Register.vue'], resolve)
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'settings',
|
|
||||||
path: '/settings',
|
|
||||||
component: (resolve) => require(['./components/Settings.vue'], resolve)
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'signin',
|
name: 'signin',
|
||||||
path: '/signin',
|
path: '/signin',
|
||||||
component: (resolve) => require(['./components/Signin.vue'], resolve)
|
component: (resolve) => require(['./components/Signin.vue'], resolve)
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'settings',
|
||||||
|
path: '/profile/settings',
|
||||||
|
components: {
|
||||||
|
'search-router-view': require('./components/Settings.vue')
|
||||||
|
}
|
||||||
|
},
|
||||||
// {
|
// {
|
||||||
// name: 'user-requests',
|
// name: 'user-requests',
|
||||||
// path: '/profile/requests',
|
// path: '/profile/requests',
|
||||||
@@ -78,8 +79,6 @@ const router = new VueRouter({
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
store.dispatch('documentTitle/updateTitle', to.name)
|
|
||||||
|
|
||||||
// Toggle mobile nav
|
// Toggle mobile nav
|
||||||
if(document.querySelector('.nav__hamburger--active')){
|
if(document.querySelector('.nav__hamburger--active')){
|
||||||
document.querySelector('.nav__hamburger').classList.remove('nav__hamburger--active');
|
document.querySelector('.nav__hamburger').classList.remove('nav__hamburger--active');
|
||||||
|
|||||||
@@ -2,18 +2,21 @@
|
|||||||
@import "./src/scss/media-queries";
|
@import "./src/scss/media-queries";
|
||||||
|
|
||||||
.filter {
|
.filter {
|
||||||
|
// margin: 10px 10px 20px;
|
||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
|
// overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
transition: color .2s ease;
|
transition: color .2s ease;
|
||||||
|
// justify-content: space-evenly;
|
||||||
|
|
||||||
&-item {
|
&-item {
|
||||||
padding: 6px 15px;
|
padding: 6px 15px;
|
||||||
background-color: $background-color-secondary;
|
background-color: $c-white;
|
||||||
transition: color 0.2s ease;
|
transition: color 0.2s ease;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 200;
|
font-weight: 200;
|
||||||
@@ -21,17 +24,16 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
white-space:nowrap;
|
white-space:nowrap;
|
||||||
|
// overflow: hidden;
|
||||||
&:nth-child(n+2) {
|
&:nth-child(n+2) {
|
||||||
border-left: solid 1px;
|
border-left: solid 1px;
|
||||||
}
|
}
|
||||||
&.active, &:hover {
|
&.active, &:hover {
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
background-color: $teal;
|
background-color: #091c24;
|
||||||
color: $green;
|
color: $c-green;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include tablet-min {
|
@include tablet-min {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|||||||
43
src/scss/message.scss
Normal file
43
src/scss/message.scss
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// TODO move all this to a plugin or something
|
||||||
|
|
||||||
|
.message-enter-active {
|
||||||
|
transition: all .3s ease;
|
||||||
|
}
|
||||||
|
.message-fade-leave-active {
|
||||||
|
transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
|
||||||
|
}
|
||||||
|
.message-fade-enter, .message-fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.message{
|
||||||
|
width: 75%;
|
||||||
|
max-width: 35rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding: 12px 15px 12px 15px;
|
||||||
|
position: relative;
|
||||||
|
&-text{
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
&-dismiss{
|
||||||
|
position: absolute;
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 100;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
margin-top: 2px;
|
||||||
|
margin-right: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-warning{
|
||||||
|
background-color: #f2dede;
|
||||||
|
border: 1px solid #b75b91;
|
||||||
|
color: #b75b91;
|
||||||
|
}
|
||||||
|
.message-success{
|
||||||
|
background-color: #dff0d9;
|
||||||
|
border: 1px solid #3e7549;
|
||||||
|
color: #3e7549;
|
||||||
|
}
|
||||||
@@ -1,123 +1,12 @@
|
|||||||
// Colors
|
// Colors
|
||||||
// @import "./media-queries";
|
$c-green: #01d277;
|
||||||
@import "./src/scss/media-queries";
|
$c-dark: #081c24;
|
||||||
|
$c-white: #ffffff;
|
||||||
|
$c-light: #f8f8f8;
|
||||||
|
$c-green-light: #dff0d9;
|
||||||
|
$c-green-dark: #3e7549;
|
||||||
|
$c-red-light: #f2dede;
|
||||||
|
$c-red-dark: #b75b91;
|
||||||
|
|
||||||
:root {
|
$header-size: 75px;
|
||||||
color-scheme: light;
|
$header-size-mobile: 50px;
|
||||||
--text-color: #081c24;
|
|
||||||
--text-color-70: rgba(8, 28, 36, 0.7);
|
|
||||||
--text-color-50: rgba(8, 28, 36, 0.5);
|
|
||||||
--text-color-5: rgba(8, 28, 36, 0.05);
|
|
||||||
--text-color-secondary: orange;
|
|
||||||
--background-color: #f8f8f8;
|
|
||||||
--background-color-secondary: #ffffff;
|
|
||||||
--background-95: rgba(255, 255, 255, 0.95);
|
|
||||||
--background-70: rgba(255, 255, 255, 0.7);
|
|
||||||
--background-40: rgba(255, 255, 255, 0.4);
|
|
||||||
--background-nav-logo: #081c24;
|
|
||||||
|
|
||||||
--color-green: #01d277;
|
|
||||||
--color-green-90: rgba(1, 210, 119, .9);
|
|
||||||
--color-teal: #091c24;
|
|
||||||
--color-black: #081c24;
|
|
||||||
--white: #fff;
|
|
||||||
--white-70: rgba(255,255,255,0.7);
|
|
||||||
|
|
||||||
--color-warning: rgba(241, 188, 53, 0.7);
|
|
||||||
--color-warning-highlight: #f1bc35;
|
|
||||||
--color-success: rgba(0, 100, 66, 0.8);
|
|
||||||
--color-success-text: #fff;
|
|
||||||
--color-success-highlight: rgb(0, 100, 66);
|
|
||||||
--color-error: rgba(220, 48, 35, 0.8);
|
|
||||||
--color-error-highlight: #DC3023;
|
|
||||||
|
|
||||||
--header-size: 75px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
:root {
|
|
||||||
color-scheme: light dark;
|
|
||||||
--text-color: #fff;
|
|
||||||
--text-color-70: rgba(255, 255, 255, 0.7);
|
|
||||||
--text-color-50: rgba(255, 255, 255, 0.5);
|
|
||||||
--text-color-5: rgba(255, 255, 255, 0.05);
|
|
||||||
--text-color-secondary: orange;
|
|
||||||
--background-color: #1e1f22;
|
|
||||||
--background-color-secondary: #111111;
|
|
||||||
--background-95: rgba(30, 31, 34, 0.95);
|
|
||||||
--background-70: rgba(30, 31, 34, 0.8);
|
|
||||||
--background-40: rgba(30, 31, 34, 0.4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include mobile-only {
|
|
||||||
:root {
|
|
||||||
--header-size: 50px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$header-size: var(--header-size);
|
|
||||||
|
|
||||||
$dark: rgb(30, 31, 34);
|
|
||||||
$green: var(--color-green);
|
|
||||||
$green-90: var(--color-green-90);
|
|
||||||
$teal: #091c24;
|
|
||||||
$black: #081c24;
|
|
||||||
$black-80: rgba(0,0,0,0.8);
|
|
||||||
$white: #fff;
|
|
||||||
$white-80: rgba(255,255,255,0.8);
|
|
||||||
|
|
||||||
$text-color: var(--text-color) !default;
|
|
||||||
$text-color-70: var(--text-color-70) !default;
|
|
||||||
$text-color-50: var(--text-color-50) !default;
|
|
||||||
$text-color-5: var(--text-color-5) !default;
|
|
||||||
$text-color-secondary: var(--text-color-secondary) !default;
|
|
||||||
$background-color: var(--background-color) !default;
|
|
||||||
$background-color-secondary: var(--background-color-secondary) !default;
|
|
||||||
$background-95: var(--background-95) !default;
|
|
||||||
$background-70: var(--background-70) !default;
|
|
||||||
$background-40: var(--background-40) !default;
|
|
||||||
$background-dark-85: rgba($dark, 0.85) !default;
|
|
||||||
$background-nav-logo: var(--background-nav-logo) !default;
|
|
||||||
$color-warning: var(--color-warning) !default;
|
|
||||||
$color-warning-highlight: var(--color-warning-highlight) !default;
|
|
||||||
$color-success: var(--color-success) !default;
|
|
||||||
$color-success-highlight: var(--color-success-highlight) !default;
|
|
||||||
$color-error: var(--color-error) !default;
|
|
||||||
$color-error-highlight: var(--color-error-highlight) !default;
|
|
||||||
|
|
||||||
.halloween {
|
|
||||||
--text-color: #6a318c;
|
|
||||||
--text-color-secondary: #fb5a33;
|
|
||||||
--background-color: #80c350;
|
|
||||||
--background-color-secondary: #ff9234;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark {
|
|
||||||
--text-color: #fff;
|
|
||||||
--text-color-70: rgba(255, 255, 255, 0.7);
|
|
||||||
--text-color-50: rgba(255, 255, 255, 0.5);
|
|
||||||
--text-color-5: rgba(255, 255, 255, 0.05);
|
|
||||||
--text-color-secondary: orange;
|
|
||||||
--background-color: #1e1f22;
|
|
||||||
--background-color-secondary: #111111;
|
|
||||||
--background-95: rgba(30, 31, 34, 0.95);
|
|
||||||
--background-70: rgba(30, 31, 34, 0.7);
|
|
||||||
--color-teal: #091c24;
|
|
||||||
}
|
|
||||||
|
|
||||||
.light {
|
|
||||||
--text-color: #081c24;
|
|
||||||
--text-color-70: rgba(8, 28, 36, 0.7);
|
|
||||||
--text-color-50: rgba(8, 28, 36, 0.5);
|
|
||||||
--text-color-5: rgba(8, 28, 36, 0.05);
|
|
||||||
--text-color-inverted: #fff;
|
|
||||||
--text-color-secondary: orange;
|
|
||||||
--background-color: #f8f8f8;
|
|
||||||
--background-color-secondary: #ffffff;
|
|
||||||
--background-95: rgba(255, 255, 255, 0.95);
|
|
||||||
--background-70: rgba(255, 255, 255, 0.7);
|
|
||||||
--background-nav-logo: #081c24;
|
|
||||||
--color-green: #01d277;
|
|
||||||
--color-teal: #091c24;
|
|
||||||
}
|
|
||||||
18
src/store.js
18
src/store.js
@@ -1,18 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
import Vuex from 'vuex'
|
|
||||||
|
|
||||||
import torrentModule from './modules/torrentModule'
|
|
||||||
import darkmodeModule from './modules/darkmodeModule'
|
|
||||||
import documentTitle from './modules/documentTitle'
|
|
||||||
|
|
||||||
Vue.use(Vuex)
|
|
||||||
|
|
||||||
const store = new Vuex.Store({
|
|
||||||
modules: {
|
|
||||||
torrentModule,
|
|
||||||
darkmodeModule,
|
|
||||||
documentTitle
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export default store
|
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
const sortableSize = (string) => {
|
function sortableSize(string) {
|
||||||
const UNITS = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
const UNITS = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||||
const [numStr, unit] = string.split(' ');
|
const [numStr, unit] = string.split(' ');
|
||||||
|
if (UNITS.indexOf(unit) === -1)
|
||||||
if (UNITS.indexOf(unit) === -1)
|
|
||||||
return string
|
return string
|
||||||
|
const exponent = UNITS.indexOf(unit) * 3
|
||||||
const exponent = UNITS.indexOf(unit) * 3
|
|
||||||
return numStr * (Math.pow(10, exponent))
|
return numStr * (Math.pow(10, exponent))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,20 +12,13 @@ module.exports = {
|
|||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.vue$/,
|
test: /\.vue$/,
|
||||||
use: [
|
loader: 'vue-loader',
|
||||||
{
|
options: {
|
||||||
loader: 'vue-loader',
|
loaders: {
|
||||||
options: {
|
'scss': 'vue-style-loader!css-loader!sass-loader',
|
||||||
loaders: {
|
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
|
||||||
'scss': 'vue-style-loader!css-loader!sass-loader',
|
|
||||||
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'vue-svg-inline-loader'
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
@@ -46,7 +39,6 @@ module.exports = {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.js', '.vue', '.json', 'scss'],
|
|
||||||
alias: {
|
alias: {
|
||||||
'vue$': 'vue/dist/vue.common.js',
|
'vue$': 'vue/dist/vue.common.js',
|
||||||
'@': path.resolve(__dirname, './src'),
|
'@': path.resolve(__dirname, './src'),
|
||||||
|
|||||||
Reference in New Issue
Block a user