New theming system
This commit is contained in:
parent
c505f6ff9b
commit
cd422832dd
|
@ -108,7 +108,7 @@ flake8:
|
|||
variables:
|
||||
GIT_STRATEGY: fetch
|
||||
before_script:
|
||||
- pip install flake8
|
||||
- pip install 'flake8<3.7'
|
||||
script:
|
||||
- flake8 -v api
|
||||
cache:
|
||||
|
|
|
@ -704,6 +704,21 @@ Views: you can find some readable views tests in file: ``api/tests/users/test_vi
|
|||
Contributing to the front-end
|
||||
-----------------------------
|
||||
|
||||
Styles and themes
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
Our UI framework is Fomantic UI (https://fomantic-ui.com/), and Funkwhale's custom styles are written in SCSS. All the styles are configured in ``front/src/styles/_main.scss``,
|
||||
including imporing of Fomantic UI styles and components.
|
||||
|
||||
We're applying several changes on top of the Fomantic CSS files, before they are imported:
|
||||
|
||||
1. Many hardcoded color values are replaced by CSS vars: e.g ``color: orange`` is replaced by ``color: var(--vibrant-color)``. This makes theming way easier.
|
||||
2. Unused components variations and icons are stripped from the source files, in order to reduce the final size of our CSS files
|
||||
|
||||
This changes are applied automatically when running ``yarn install``, through a ``postinstall`` hook. Internally, ``front/scripts/fix-fomantic-css.py`` is called
|
||||
and handle both kind of modifications. Please refer to this script if you need to use new icons to the project, or restore some components variations that
|
||||
were stripped in order to use them.
|
||||
|
||||
Running tests
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
/* These styles are generated from project.scss. */
|
||||
|
||||
.alert-debug {
|
||||
color: black;
|
||||
background-color: white;
|
||||
border-color: #d6e9c6;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
color: #b94a48;
|
||||
background-color: #f2dede;
|
||||
border-color: #eed3d7;
|
||||
}
|
||||
|
||||
/* This is a fix for the bootstrap4 alpha release */
|
||||
@media (max-width: 47.9em) {
|
||||
.navbar-nav .nav-item {
|
||||
float: none;
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.navbar-nav .nav-item + .nav-item {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.nav.navbar-nav.pull-right {
|
||||
float: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Display django-debug-toolbar.
|
||||
See https://github.com/django-debug-toolbar/django-debug-toolbar/issues/742
|
||||
and https://github.com/pydanny/cookiecutter-django/issues/317
|
||||
*/
|
||||
[hidden][style="display: block;"] {
|
||||
display: block !important;
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 8.2 KiB |
|
@ -1 +0,0 @@
|
|||
/* Project specific Javascript goes here. */
|
|
@ -1,51 +0,0 @@
|
|||
// project specific CSS goes here
|
||||
|
||||
// Alert colors
|
||||
|
||||
$white: #fff;
|
||||
$mint-green: #d6e9c6;
|
||||
$black: #000;
|
||||
$pink: #f2dede;
|
||||
$dark-pink: #eed3d7;
|
||||
$red: #b94a48;
|
||||
|
||||
// bootstrap alert CSS, translated to the django-standard levels of
|
||||
// debug, info, success, warning, error
|
||||
|
||||
.alert-debug {
|
||||
background-color: $white;
|
||||
border-color: $mint-green;
|
||||
color: $black;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background-color: $pink;
|
||||
border-color: $dark-pink;
|
||||
color: $red;
|
||||
}
|
||||
|
||||
// This is a fix for the bootstrap4 alpha release
|
||||
|
||||
@media (max-width: 47.9em) {
|
||||
.navbar-nav .nav-item {
|
||||
display: inline-block;
|
||||
float: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.navbar-nav .nav-item + .nav-item {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.nav.navbar-nav.pull-right {
|
||||
float: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
// Display django-debug-toolbar.
|
||||
// See https://github.com/django-debug-toolbar/django-debug-toolbar/issues/742
|
||||
// and https://github.com/pydanny/cookiecutter-django/issues/317
|
||||
|
||||
[hidden][style="display: block;"] {
|
||||
display: block !important;
|
||||
}
|
|
@ -10,7 +10,9 @@
|
|||
"test:unit": "vue-cli-service test:unit",
|
||||
"lint": "vue-cli-service lint",
|
||||
"i18n-compile": "scripts/i18n-compile.sh",
|
||||
"i18n-extract": "scripts/i18n-extract.sh"
|
||||
"i18n-extract": "scripts/i18n-extract.sh",
|
||||
"fix-fomantic-css": "scripts/fix-fomantic-css.sh",
|
||||
"postinstall": "yarn run fix-fomantic-css"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.18.0",
|
||||
|
@ -25,6 +27,7 @@
|
|||
"qs": "^6.7.0",
|
||||
"register-service-worker": "^1.6.2",
|
||||
"sanitize-html": "^1.20.1",
|
||||
"sass": "^1.26.5",
|
||||
"showdown": "^1.8.6",
|
||||
"text-clipper": "^1.3.0",
|
||||
"vue": "^2.6.10",
|
||||
|
@ -54,7 +57,6 @@
|
|||
"glob-all": "^3.1.0",
|
||||
"mocha": "^5.2.0",
|
||||
"moxios": "^0.4.0",
|
||||
"node-sass": "^4.9.3",
|
||||
"preload-webpack-plugin": "^3.0.0-beta.4",
|
||||
"purgecss-webpack-plugin": "^1.6.0",
|
||||
"sass-loader": "^8.0.2",
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#orange-square {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
background-color: #f2711c
|
||||
background-color: #f2711c;
|
||||
}
|
||||
#fake-content {
|
||||
height: 100vh;
|
||||
|
|
|
@ -0,0 +1,897 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
This scripts handles all the heavy-lifting of parsing CSS files from ``fomantic-ui-css`` and:
|
||||
|
||||
1. Replace hardcoded values by their CSS vars counterparts, for easier theming
|
||||
2. Strip unused styles and icons to reduce the final size of CSS
|
||||
|
||||
Updated files are not modified in place, but instead copied to another directory (``fomantic-ui-css/tweaked``), in order
|
||||
to allow easy comparison detection of changes.
|
||||
|
||||
If you change this file, you'll need to run ``yarn run fix-fomantic-css`` manually for the changes
|
||||
to be picked up. If the ``NOSTRIP`` environment variable is set, the second step will be skipped.
|
||||
"""
|
||||
import argparse
|
||||
import os
|
||||
|
||||
STRIP_UNUSED = "NOSTRIP" not in os.environ
|
||||
|
||||
# Perform a blind replacement of some strings in all fomantic CSS files
|
||||
GLOBAL_REPLACES = [
|
||||
# some selectors are repeated in the stylesheet, for some reason
|
||||
(".ui.ui.ui.ui", ".ui"),
|
||||
(".ui.ui.ui", ".ui"),
|
||||
(".ui.ui", ".ui"),
|
||||
(".icon.icon.icon.icon", ".icon"),
|
||||
(".icon.icon.icon", ".icon"),
|
||||
(".icon.icon", ".icon"),
|
||||
# actually useful stuff
|
||||
("'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif", "var(--font-family)"),
|
||||
(".orange", ".vibrant"),
|
||||
("#F2711C", "var(--vibrant-color)"),
|
||||
("#FF851B", "var(--vibrant-color)"),
|
||||
("#f26202", "var(--vibrant-hover-color)"),
|
||||
("#e76b00", "var(--vibrant-hover-color)"),
|
||||
("#cf590c", "var(--vibrant-active-color)"),
|
||||
("#f56100", "var(--vibrant-active-color)"),
|
||||
("#e76b00", "var(--vibrant-active-color)"),
|
||||
("#e55b00", "var(--vibrant-focus-color)"),
|
||||
("#f17000", "var(--vibrant-focus-color)"),
|
||||
(".green", ".success"),
|
||||
("#21BA45", "var(--success-color)"),
|
||||
("#2ECC40", "var(--success-color)"),
|
||||
("#16ab39", "var(--success-hover-color)"),
|
||||
("#1ea92e", "var(--success-hover-color)"),
|
||||
("#198f35", "var(--success-active-color)"),
|
||||
("#25a233", "var(--success-active-color)"),
|
||||
("#0ea432", "var(--success-focus-color)"),
|
||||
("#19b82b", "var(--success-focus-color)"),
|
||||
(".blue", ".primary"),
|
||||
("#2185D0", "var(--primary-color)"),
|
||||
("#54C8FF", "var(--primary-color)"),
|
||||
("#54C8FF", "var(--primary-color)"),
|
||||
("#1678c2", "var(--primary-hover-color)"),
|
||||
("#21b8ff", "var(--primary-hover-color)"),
|
||||
("#1a69a4", "var(--primary-active-color)"),
|
||||
("#0d71bb", "var(--primary-focus-color)"),
|
||||
("#2bbbff", "var(--primary-focus-color)"),
|
||||
(".yellow", ".warning"),
|
||||
("#FBBD08", "var(--warning-color)"),
|
||||
("#FFE21F", "var(--warning-color)"),
|
||||
("#eaae00", "var(--warning-hover-color)"),
|
||||
("#ebcd00", "var(--warning-hover-color)"),
|
||||
("#cd9903", "var(--warning-active-color)"),
|
||||
("#ebcd00", "var(--warning-active-color)"),
|
||||
("#daa300", "var(--warning-focus-color)"),
|
||||
("#f5d500", "var(--warning-focus-color)"),
|
||||
(".red.", ".danger."),
|
||||
("#DB2828", "var(--danger-color)"),
|
||||
("#FF695E", "var(--danger-color)"),
|
||||
("#d01919", "var(--danger-hover-color)"),
|
||||
("#ff392b", "var(--danger-hover-color)"),
|
||||
("#b21e1e", "var(--danger-active-color)"),
|
||||
("#ca1010", "var(--danger-focus-color)"),
|
||||
("#ff4335", "var(--danger-focus-color)"),
|
||||
]
|
||||
|
||||
def discard_unused_icons(rule):
|
||||
"""
|
||||
Add an icon to this list if you want to use it in the app.
|
||||
"""
|
||||
used_icons = [
|
||||
".angle",
|
||||
".arrow",
|
||||
".at",
|
||||
".ban",
|
||||
".bell",
|
||||
".book",
|
||||
".bookmark",
|
||||
".check",
|
||||
".clock",
|
||||
".close",
|
||||
".cloud",
|
||||
".code",
|
||||
".comment",
|
||||
".copy",
|
||||
".copyright",
|
||||
".danger",
|
||||
".database",
|
||||
".delete",
|
||||
".disc",
|
||||
".down angle",
|
||||
".download",
|
||||
".dropdown",
|
||||
".edit",
|
||||
".ellipsis",
|
||||
".eraser",
|
||||
".external",
|
||||
".eye",
|
||||
".feed",
|
||||
".file",
|
||||
".forward",
|
||||
".globe",
|
||||
".hashtag",
|
||||
".headphones",
|
||||
".heart",
|
||||
".home",
|
||||
".hourglass",
|
||||
".info",
|
||||
".layer",
|
||||
".lines",
|
||||
".link",
|
||||
".list",
|
||||
".loading",
|
||||
".lock",
|
||||
".minus",
|
||||
".mobile",
|
||||
".music",
|
||||
".paper",
|
||||
".pause",
|
||||
".pencil",
|
||||
".play",
|
||||
".plus",
|
||||
".podcast",
|
||||
".question",
|
||||
".question ",
|
||||
".random",
|
||||
".redo",
|
||||
".refresh",
|
||||
".repeat",
|
||||
".rss",
|
||||
".search",
|
||||
".server",
|
||||
".share",
|
||||
".shield",
|
||||
".sidebar",
|
||||
".sign",
|
||||
".spinner",
|
||||
".step",
|
||||
".stream",
|
||||
".track",
|
||||
".trash",
|
||||
".undo",
|
||||
".upload",
|
||||
".user",
|
||||
".users",
|
||||
".volume",
|
||||
".wikipedia",
|
||||
".wrench",
|
||||
".x",
|
||||
]
|
||||
if ":before" not in rule["lines"][0]:
|
||||
return False
|
||||
|
||||
return not match(rule, used_icons)
|
||||
|
||||
|
||||
"""
|
||||
Below is the main configuration object that is used for fine-grained replacement of properties
|
||||
in component files. It also handles removal of unused selectors.
|
||||
|
||||
Example config for a component:
|
||||
|
||||
REPLACEMENTS = {
|
||||
# applies to fomantic-ui-css/components/component-name.css
|
||||
"component-name": {
|
||||
# Discard any CSS rule matching one of the selectors listed below
|
||||
# matching is done using a simple string search, so ``.pink`` will remove
|
||||
# rules applied to ``.pink``, ``.pink.button`` and `.pinkdark`
|
||||
"skip": [
|
||||
".unused.variation",
|
||||
".pink",
|
||||
],
|
||||
# replace some CSS properties values in specific selectors
|
||||
(".inverted", ".dark"): [
|
||||
("background", "var(--inverted-background)"),
|
||||
("color", "var(--inverted-color)"),
|
||||
],
|
||||
(".active"): [
|
||||
("font-size", "var(--active-font-size)"),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
Given the previous config, the following style sheet:
|
||||
|
||||
.. code-block:: css
|
||||
|
||||
.unsed.variation {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
.primary {
|
||||
color: white;
|
||||
}
|
||||
.primary.pink {
|
||||
color: pink;
|
||||
}
|
||||
.inverted.primary {
|
||||
background: black;
|
||||
color: white;
|
||||
border-top: 1px solid red;
|
||||
}
|
||||
.inverted.primary.active {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
Would be converted to:
|
||||
|
||||
.. code-block:: css
|
||||
|
||||
.primary {
|
||||
color: white;
|
||||
}
|
||||
.inverted.primary {
|
||||
background: var(--inverted-background);
|
||||
color: var(--inverted-color);
|
||||
border-top: 1px solid red;
|
||||
}
|
||||
.inverted.primary.active {
|
||||
font-size: var(--active-font-size);
|
||||
}
|
||||
|
||||
"""
|
||||
REPLACEMENTS = {
|
||||
"site": {
|
||||
("a",): [
|
||||
("color", "var(--link-color)"),
|
||||
("text-decoration", "var(--link-text-decoration)"),
|
||||
],
|
||||
("a:hover",): [
|
||||
("color", "var(--link-hover-color)"),
|
||||
("text-decoration", "var(--link-hover-text-decoration)"),
|
||||
],
|
||||
("body",): [
|
||||
("background", "var(--site-background)"),
|
||||
("color", "var(--text-color)"),
|
||||
],
|
||||
("::-webkit-selection", "::-moz-selection", "::selection",): [
|
||||
("color", "var(--text-selection-color)"),
|
||||
("background-color", "var(--text-selection-background)"),
|
||||
],
|
||||
(
|
||||
"textarea::-webkit-selection",
|
||||
"input::-webkit-selection",
|
||||
"textarea::-moz-selection",
|
||||
"input::-moz-selection",
|
||||
"textarea::selection",
|
||||
"input::selection",
|
||||
): [
|
||||
("color", "var(--input-selection-color)"),
|
||||
("background-color", "var(--input-selection-background)"),
|
||||
],
|
||||
},
|
||||
"button": {
|
||||
"skip": [
|
||||
".vertical",
|
||||
".animated",
|
||||
".active",
|
||||
".olive",
|
||||
".brown",
|
||||
".teal",
|
||||
".violet",
|
||||
".purple",
|
||||
".brown",
|
||||
".grey",
|
||||
".black",
|
||||
".positive",
|
||||
".negative",
|
||||
".secondary",
|
||||
".tertiary",
|
||||
".facebook",
|
||||
".twitter",
|
||||
".google.plus",
|
||||
".vk",
|
||||
".linkedin",
|
||||
".instagram",
|
||||
".youtube",
|
||||
".whatsapp",
|
||||
".telegram",
|
||||
],
|
||||
(".ui.orange.button", ".ui.orange.button:hover"): [
|
||||
("background-color", "var(--button-orange-background)")
|
||||
],
|
||||
(".ui.basic.button",): [
|
||||
("background", "var(--button-basic-background)"),
|
||||
("color", "var(--button-basic-color)"),
|
||||
("box-shadow", "var(--button-basic-box-shadow)"),
|
||||
],
|
||||
(".ui.basic.button:hover",): [
|
||||
("background", "var(--button-basic-hover-background)"),
|
||||
("color", "var(--button-basic-hover-color)"),
|
||||
("box-shadow", "var(--button-basic-hover-box-shadow)"),
|
||||
],
|
||||
},
|
||||
"card": {
|
||||
"skip": [
|
||||
".inverted",
|
||||
".olive",
|
||||
".brown",
|
||||
".teal",
|
||||
".violet",
|
||||
".purple",
|
||||
".brown",
|
||||
".grey",
|
||||
".pink",
|
||||
".black",
|
||||
".vibrant",
|
||||
".success",
|
||||
".warning",
|
||||
".danger",
|
||||
".primary",
|
||||
".secondary",
|
||||
".horizontal",
|
||||
".raised",
|
||||
]
|
||||
},
|
||||
"checkbox": {
|
||||
(
|
||||
".ui.toggle.checkbox label",
|
||||
".ui.toggle.checkbox input:checked ~ label",
|
||||
'.ui.checkbox input[type="checkbox"]',
|
||||
".ui.checkbox input:focus ~ label",
|
||||
".ui.toggle.checkbox input:focus:checked ~ label",
|
||||
".ui.checkbox input:active ~ label",
|
||||
): [("color", "var(--form-label-color)"),],
|
||||
(".ui.toggle.checkbox label:before",): [
|
||||
("background", "var(--input-background)"),
|
||||
],
|
||||
},
|
||||
"divider": {
|
||||
(".ui.divider:not(.vertical):not(.horizontal)",): [
|
||||
("border-top", "var(--divider)"),
|
||||
("border-bottom", "var(--divider)"),
|
||||
],
|
||||
(".ui.divider",): [("color", "var(--text-color)"),],
|
||||
},
|
||||
"dimmer": {
|
||||
(".ui.inverted.dimmer",): [
|
||||
("background-color", "var(--dimmer-background)"),
|
||||
("color", "var(--dropdown-color)"),
|
||||
],
|
||||
},
|
||||
"dropdown": {
|
||||
"skip": [".error", ".info", ".success", ".warning",],
|
||||
(
|
||||
".ui.selection.dropdown",
|
||||
".ui.selection.visible.dropdown > .text:not(.default)",
|
||||
".ui.dropdown .menu",
|
||||
): [
|
||||
("background", "var(--dropdown-background)"),
|
||||
("color", "var(--dropdown-color)"),
|
||||
],
|
||||
(".ui.dropdown .menu > .item",): [("color", "var(--dropdown-item-color)"),],
|
||||
(".ui.dropdown .menu > .item:hover",): [
|
||||
("color", "var(--dropdown-item-hover-color)"),
|
||||
("background", "var(--dropdown-item-hover-background)"),
|
||||
],
|
||||
(".ui.dropdown .menu .selected.item",): [
|
||||
("color", "var(--dropdown-item-selected-color)"),
|
||||
("background", "var(--dropdown-item-selected-background)"),
|
||||
],
|
||||
(".ui.dropdown .menu > .header:not(.ui)",): [
|
||||
("color", "var(--dropdown-header-color)"),
|
||||
],
|
||||
(".ui.dropdown .menu > .divider",): [("border-top", "var(--divider)"),],
|
||||
},
|
||||
"form": {
|
||||
"skip": [".inverted", ".success", ".warning", ".error", ".info",],
|
||||
('.ui.form input[type="text"]', ".ui.form select", ".ui.input textarea"): [
|
||||
("background", "var(--input-background)"),
|
||||
("color", "var(--input-color)"),
|
||||
],
|
||||
(
|
||||
'.ui.form input[type="text"]:focus',
|
||||
".ui.form select:focus",
|
||||
".ui.form textarea:focus",
|
||||
): [
|
||||
("background", "var(--input-focus-background)"),
|
||||
("color", "var(--input-focus-color)"),
|
||||
],
|
||||
(
|
||||
".ui.form ::-webkit-input-placeholder",
|
||||
".ui.form :-ms-input-placeholder",
|
||||
".ui.form ::-moz-placeholder",
|
||||
): [("color", "var(--input-placeholder-color)"),],
|
||||
(
|
||||
".ui.form :focus::-webkit-input-placeholder",
|
||||
".ui.form :focus:-ms-input-placeholder",
|
||||
".ui.form :focus::-moz-placeholder",
|
||||
): [("color", "var(--input-focus-placeholder-color)"),],
|
||||
(".ui.form .field > label", ".ui.form .inline.fields .field > label",): [
|
||||
("color", "var(--form-label-color)"),
|
||||
],
|
||||
},
|
||||
"grid": {
|
||||
"skip": [
|
||||
"wide tablet",
|
||||
"screen",
|
||||
"mobile only",
|
||||
"tablet only",
|
||||
"computer only",
|
||||
"computer reversed",
|
||||
"tablet reversed",
|
||||
"wide computer",
|
||||
"wide mobile",
|
||||
"wide tablet",
|
||||
"vertically",
|
||||
".celled",
|
||||
".doubling",
|
||||
".olive",
|
||||
".brown",
|
||||
".teal",
|
||||
".violet",
|
||||
".purple",
|
||||
".brown",
|
||||
".grey",
|
||||
".black",
|
||||
".positive",
|
||||
".negative",
|
||||
".secondary",
|
||||
".tertiary",
|
||||
".danger",
|
||||
".vibrant",
|
||||
".warning",
|
||||
".primary",
|
||||
".success",
|
||||
".justified",
|
||||
".centered",
|
||||
]
|
||||
},
|
||||
"icon": {"skip": discard_unused_icons},
|
||||
"input": {
|
||||
(".ui.input > input",): [
|
||||
("background", "var(--input-background)"),
|
||||
("color", "var(--input-color)"),
|
||||
],
|
||||
(".ui.input > input:focus",): [
|
||||
("background", "var(--input-focus-background)"),
|
||||
("color", "var(--input-focus-color)"),
|
||||
],
|
||||
(
|
||||
".ui.input > input::-webkit-input-placeholder",
|
||||
".ui.input > input::-moz-placeholder",
|
||||
".ui.input > input:-ms-input-placeholder",
|
||||
): [("color", "var(--input-placeholder-color)"),],
|
||||
(
|
||||
".ui.input > input:focus::-webkit-input-placeholder",
|
||||
".ui.input > input:focus::-moz-placeholder",
|
||||
".ui.input > input:focus:-ms-input-placeholder",
|
||||
): [("color", "var(--input-focus-placeholder-color)"),],
|
||||
},
|
||||
"item": {
|
||||
(".ui.divided.items > .item",): [("border-top", "var(--divider)"),],
|
||||
(".ui.items > .item > .content",): [("color", "var(--text-color)"),],
|
||||
(".ui.items > .item .extra",): [
|
||||
("color", "var(--really-discrete-text-color)"),
|
||||
],
|
||||
},
|
||||
"header": {
|
||||
"skip": [
|
||||
".inverted",
|
||||
".block",
|
||||
".olive",
|
||||
".brown",
|
||||
".teal",
|
||||
".violet",
|
||||
".purple",
|
||||
".brown",
|
||||
".grey",
|
||||
".black",
|
||||
".pink",
|
||||
],
|
||||
(".ui.header",): [("color", "var(--header-color)"),],
|
||||
(".ui.header .sub.header",): [("color", "var(--header-color)"),],
|
||||
},
|
||||
"label": {
|
||||
"skip": [
|
||||
".olive",
|
||||
".brown",
|
||||
".teal",
|
||||
".violet",
|
||||
".purple",
|
||||
".brown",
|
||||
".grey",
|
||||
".black",
|
||||
".positive",
|
||||
".negative",
|
||||
".secondary",
|
||||
".tertiary",
|
||||
".facebook",
|
||||
".twitter",
|
||||
".google.plus",
|
||||
".vk",
|
||||
".linkedin",
|
||||
".instagram",
|
||||
".youtube",
|
||||
".whatsapp",
|
||||
".telegram",
|
||||
".corner",
|
||||
"ribbon",
|
||||
"pointing",
|
||||
"attached",
|
||||
],
|
||||
},
|
||||
"list": {
|
||||
"skip": [
|
||||
".mini",
|
||||
".tiny",
|
||||
".small",
|
||||
".large",
|
||||
".big",
|
||||
".huge",
|
||||
".massive",
|
||||
".celled",
|
||||
".horizontal",
|
||||
".bulleted",
|
||||
".ordered",
|
||||
".suffixed",
|
||||
".inverted",
|
||||
".fitted",
|
||||
"aligned",
|
||||
],
|
||||
(".ui.list .list > .item a.header", ".ui.list .list > a.item"): [
|
||||
("color", "var(--link-color)"),
|
||||
("text-decoration", "var(--link-text-decoration)"),
|
||||
],
|
||||
("a:hover", ".ui.list .list > a.item:hover"): [
|
||||
("color", "var(--link-hover-color)"),
|
||||
("text-decoration", "var(--link-hover-text-decoration)"),
|
||||
],
|
||||
},
|
||||
"loader": {
|
||||
"skip": [
|
||||
".olive",
|
||||
".brown",
|
||||
".teal",
|
||||
".violet",
|
||||
".purple",
|
||||
".brown",
|
||||
".grey",
|
||||
".black",
|
||||
".pink",
|
||||
".primary",
|
||||
".vibrant",
|
||||
".warning",
|
||||
".success",
|
||||
".danger",
|
||||
".elastic",
|
||||
],
|
||||
(".ui.inverted.dimmer > .ui.loader",): [("color", "var(--dimmer-color)"),],
|
||||
},
|
||||
"message": {
|
||||
"skip": [
|
||||
".olive",
|
||||
".brown",
|
||||
".teal",
|
||||
".violet",
|
||||
".purple",
|
||||
".brown",
|
||||
".grey",
|
||||
".black",
|
||||
".pink",
|
||||
".vibrant",
|
||||
".primary",
|
||||
".secondary",
|
||||
".floating",
|
||||
],
|
||||
},
|
||||
"menu": {
|
||||
"skip": [
|
||||
".inverted.pointing",
|
||||
".olive",
|
||||
".brown",
|
||||
".teal",
|
||||
".violet",
|
||||
".purple",
|
||||
".brown",
|
||||
".grey",
|
||||
".black",
|
||||
".vertical.tabular",
|
||||
".primary.menu",
|
||||
".pink.menu",
|
||||
".vibrant.menu",
|
||||
".warning.menu",
|
||||
".success.menu",
|
||||
".danger.menu",
|
||||
".fitted",
|
||||
"fixed",
|
||||
],
|
||||
(".ui.menu .item",): [("color", "var(--menu-item-color)"),],
|
||||
(".ui.vertical.inverted.menu .menu .item", ".ui.inverted.menu .item"): [
|
||||
("color", "var(--inverted-menu-item-color)"),
|
||||
],
|
||||
(".inverted-ui.menu .active.item",): [
|
||||
("color", "var(--menu-inverted-active-item-color)"),
|
||||
],
|
||||
(".ui.secondary.pointing.menu .active.item",): [
|
||||
("color", "var(--secondary-menu-active-item-color)"),
|
||||
],
|
||||
(
|
||||
".ui.secondary.pointing.menu a.item:hover",
|
||||
".ui.secondary.pointing.menu .active.item:hover",
|
||||
): [("color", "var(--secondary-menu-hover-item-color)"),],
|
||||
(".ui.menu .ui.dropdown .menu > .item",): [
|
||||
("color", "var(--dropdown-item-color) !important"),
|
||||
],
|
||||
(".ui.menu .ui.dropdown .menu > .item:hover",): [
|
||||
("color", "var(--dropdown-item-hover-color) !important"),
|
||||
("background", "var(--dropdown-item-hover-background) !important"),
|
||||
],
|
||||
(".ui.menu .dropdown.item .menu",): [
|
||||
("color", "var(--dropdown--color)"),
|
||||
("background", "var(--dropdown-background)"),
|
||||
],
|
||||
(".ui.menu .ui.dropdown .menu > .active.item",): [
|
||||
("color", "var(--dropdown-item-selected-color)"),
|
||||
("background", "var(--dropdown-item-selected-background) !important"),
|
||||
],
|
||||
},
|
||||
"modal": {
|
||||
(".ui.modal", ".ui.modal > .actions", ".ui.modal > .content"): [
|
||||
("background", "var(--modal-background)"),
|
||||
("border-bottom", "var(--divider)"),
|
||||
("border-top", "var(--divider)"),
|
||||
],
|
||||
(".ui.modal > .close.inside",): [("color", "var(--text-color)"),],
|
||||
(".ui.modal > .header",): [
|
||||
("color", "var(--header-color)"),
|
||||
("background", "var(--modal-background)"),
|
||||
("border-bottom", "var(--divider)"),
|
||||
("border-top", "var(--divider)"),
|
||||
],
|
||||
},
|
||||
"search": {
|
||||
(
|
||||
".ui.search > .results",
|
||||
".ui.search > .results .result",
|
||||
".ui.category.search > .results .category .results",
|
||||
".ui.category.search > .results .category",
|
||||
".ui.category.search > .results .category > .name",
|
||||
".ui.search > .results > .message .header",
|
||||
".ui.search > .results > .message .description",
|
||||
): [
|
||||
("background", "var(--dropdown-background)"),
|
||||
("color", "var(--dropdown-item-color)"),
|
||||
],
|
||||
(
|
||||
".ui.search > .results .result .title",
|
||||
".ui.search > .results .result .description",
|
||||
): [("color", "var(--dropdown-item-color)"),],
|
||||
(".ui.search > .results .result:hover",): [
|
||||
("color", "var(--dropdown-item-hover-color)"),
|
||||
("background", "var(--dropdown-item-hover-background)"),
|
||||
],
|
||||
},
|
||||
"segment": {
|
||||
"skip": [
|
||||
".stacked",
|
||||
".horizontal.segment",
|
||||
".inverted.segment",
|
||||
".circular",
|
||||
".piled",
|
||||
],
|
||||
},
|
||||
"sidebar": {
|
||||
(".ui.left.visible.sidebar",): [("box-shadow", "var(--sidebar-box-shadow)"),]
|
||||
},
|
||||
"statistic": {
|
||||
(".ui.statistic > .value", ".ui.statistic > .label"): [
|
||||
("color", "var(--text-color)"),
|
||||
],
|
||||
},
|
||||
"progress": {
|
||||
(".ui.progress.success > .label",): [("color", "var(--text-color)"),],
|
||||
},
|
||||
"table": {
|
||||
"skip": [
|
||||
".marked",
|
||||
".active",
|
||||
".olive",
|
||||
".brown",
|
||||
".teal",
|
||||
".violet",
|
||||
".purple",
|
||||
".brown",
|
||||
".grey",
|
||||
".black",
|
||||
".padded",
|
||||
".column.table",
|
||||
".inverted",
|
||||
".definition",
|
||||
".error",
|
||||
".negative",
|
||||
".structured",
|
||||
"tablet stackable",
|
||||
],
|
||||
(".ui.table", ".ui.table > thead > tr > th",): [
|
||||
("color", "var(--text-color)"),
|
||||
("background", "var(--table-background)"),
|
||||
],
|
||||
(".ui.table > tr > td", ".ui.table > tbody + tbody tr:first-child > td"): [
|
||||
("border-top", "var(--table-border)"),
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def match(rule, skip):
|
||||
if hasattr(skip, "__call__"):
|
||||
return skip(rule)
|
||||
for s in skip:
|
||||
for rs in rule["selectors"]:
|
||||
if s in rs:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def rules_from_media_query(rule):
|
||||
internal = rule["lines"][1:-1]
|
||||
return parse_rules("\n".join(internal))
|
||||
|
||||
|
||||
def wraps(rule, internal_rules):
|
||||
return {
|
||||
"lines": [rule["lines"][0]]
|
||||
+ [line for r in internal_rules for line in r["lines"]]
|
||||
+ ["}"]
|
||||
}
|
||||
|
||||
|
||||
def set_vars(component_name, rules):
|
||||
"""
|
||||
Given rules parsed via ``parse_rules``, replace properties values when needed
|
||||
using ``REPLACEMENTS`` and ``GLOBAL_REPLACES``.
|
||||
|
||||
Also remove unused styles if STRIP_UNUSED is set to True.
|
||||
"""
|
||||
final_rules = []
|
||||
try:
|
||||
conf = REPLACEMENTS[component_name]
|
||||
except KeyError:
|
||||
return rules
|
||||
selectors = list(conf.keys()) + list()
|
||||
skip = None
|
||||
if STRIP_UNUSED:
|
||||
skip = conf.get("skip", [])
|
||||
try:
|
||||
skip = set(skip)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
for rule in rules:
|
||||
if rule["lines"][0].startswith("@media"):
|
||||
# manual handling of media queries, becaues our parser is really
|
||||
# simplistic
|
||||
internal_rules = rules_from_media_query(rule)
|
||||
internal_rules = set_vars(component_name, internal_rules)
|
||||
rule = wraps(rule, internal_rules)
|
||||
if len(rule["lines"]) > 2:
|
||||
final_rules.append(rule)
|
||||
continue
|
||||
|
||||
if skip and match(rule, skip):
|
||||
# discard rule entirely
|
||||
continue
|
||||
|
||||
matching = []
|
||||
for s in selectors:
|
||||
if set(s) & set(rule["selectors"]):
|
||||
matching.append(s)
|
||||
if not matching:
|
||||
# no replacements to apply, keep rule as is
|
||||
final_rules.append(rule)
|
||||
continue
|
||||
new_rule = {"lines": []}
|
||||
|
||||
for m in matching:
|
||||
# the block match one of our replacement rules, so we loop on each line
|
||||
# and replace values if needed.
|
||||
replacements = conf[m]
|
||||
for line in rule["lines"]:
|
||||
for property, new_value in replacements:
|
||||
if line.strip().startswith("{}:".format(property)):
|
||||
new_property = "{}: {};".format(property, new_value)
|
||||
indentation = " " * (len(line) - len(line.lstrip(" ")))
|
||||
line = indentation + new_property
|
||||
break
|
||||
new_rule["lines"].append(line)
|
||||
final_rules.append(new_rule)
|
||||
return final_rules
|
||||
|
||||
|
||||
def parse_rules(text):
|
||||
"""
|
||||
Really basic CSS parsers that stores selectors and corresponding properties. Only works
|
||||
because the source files have coma-separated selectors (one per line), and one
|
||||
property/value per line.
|
||||
|
||||
Returns a list of dictionaries, each dictionarry containing the selectors and
|
||||
lines of of each block.
|
||||
"""
|
||||
rules = []
|
||||
current_rule = None
|
||||
opened_brackets = 0
|
||||
current_selector = []
|
||||
for line in text.splitlines():
|
||||
if not current_rule and line.endswith(","):
|
||||
current_selector.append(line.rstrip(",").strip())
|
||||
elif line.endswith(" {"):
|
||||
# for media queries
|
||||
opened_brackets += 1
|
||||
if not current_rule:
|
||||
current_selector.append(line.rstrip("{").strip())
|
||||
current_rule = {
|
||||
"lines": [",\n".join(current_selector) + " {"],
|
||||
"selectors": current_selector,
|
||||
}
|
||||
else:
|
||||
current_rule["lines"].append(line)
|
||||
elif current_rule:
|
||||
current_rule["lines"].append(line)
|
||||
if line.strip() == "}":
|
||||
opened_brackets -= 1
|
||||
if not opened_brackets:
|
||||
# move on to next rule
|
||||
rules.append(current_rule)
|
||||
current_rule = None
|
||||
current_selector = []
|
||||
|
||||
return rules
|
||||
|
||||
|
||||
def serialize_rules(rules):
|
||||
"""
|
||||
Convert rules back to valid CSS.
|
||||
"""
|
||||
lines = []
|
||||
for rule in rules:
|
||||
for line in rule["lines"]:
|
||||
lines.append(line)
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def iter_components(dir):
|
||||
for dname, dirs, files in os.walk(dir):
|
||||
for fname in files:
|
||||
if fname.endswith(".min.css"):
|
||||
continue
|
||||
if fname.endswith(".js"):
|
||||
continue
|
||||
if "semantic" in fname:
|
||||
continue
|
||||
if fname.endswith(".css"):
|
||||
yield os.path.join(dname, fname)
|
||||
|
||||
|
||||
def replace_vars(source, dest):
|
||||
components = list(sorted(iter_components(os.path.join(source, "components"))))
|
||||
for c in components:
|
||||
with open(c, "r") as f:
|
||||
text = f.read()
|
||||
|
||||
for s, r in GLOBAL_REPLACES:
|
||||
text = text.replace(s, r)
|
||||
text = text.replace(s.lower(), r)
|
||||
text = text.replace(s.upper(), r)
|
||||
rules = parse_rules(text)
|
||||
name = c.split("/")[-1].split(".")[0]
|
||||
updated_rules = set_vars(name, rules)
|
||||
text = serialize_rules(updated_rules)
|
||||
with open(os.path.join(dest, "{}.css".format(name)), "w") as f:
|
||||
f.write(text)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Replace hardcoded values by CSS vars and strip unused rules")
|
||||
parser.add_argument(
|
||||
"source", help="Source path of the fomantic-ui-less distribution to fix"
|
||||
)
|
||||
parser.add_argument(
|
||||
"dest", help="Destination directory where fixed files should be written"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
replace_vars(source=args.source, dest=args.dest)
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash -eux
|
||||
|
||||
find node_modules/fomantic-ui-css/components -name "*.min.css" -delete
|
||||
mkdir -p node_modules/fomantic-ui-css/tweaked
|
||||
echo 'Removing google font…'
|
||||
sed -i '/@import url(/d' node_modules/fomantic-ui-css/components/site.css
|
||||
echo "Replacing hardcoded values by CSS vars…"
|
||||
scripts/fix-fomantic-css.py node_modules/fomantic-ui-css node_modules/fomantic-ui-css/tweaked
|
|
@ -444,194 +444,4 @@ export default {
|
|||
<style lang="scss">
|
||||
@import "style/_main";
|
||||
|
||||
.ui.bottom-player {
|
||||
z-index: 999999;
|
||||
width: 100%;
|
||||
width: 100vw;
|
||||
.ui.top.attached.progress {
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
.dimmed {
|
||||
.ui.bottom-player {
|
||||
@include media("<desktop") {
|
||||
z-index: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#app.queue-focused {
|
||||
.queue-not-focused {
|
||||
@include media("<desktop") {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.when-queue-focused {
|
||||
.group {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 1.1em;
|
||||
> * {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
}
|
||||
@include media("<desktop") {
|
||||
width: 100%;
|
||||
justify-content: space-between !important;
|
||||
}
|
||||
}
|
||||
#app:not(.queue-focused) {
|
||||
.when-queue-focused {
|
||||
@include media("<desktop") {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ui.bottom-player > .segment.fixed-controls {
|
||||
width: 100%;
|
||||
width: 100vw;
|
||||
border-radius: 0;
|
||||
padding: 0em;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
z-index: 1001;
|
||||
height: $bottom-player-height;
|
||||
.controls-row {
|
||||
height: $bottom-player-height;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
@include media(">desktop") {
|
||||
padding: 0 1em;
|
||||
justify-content: space-around;
|
||||
}
|
||||
}
|
||||
cursor: pointer;
|
||||
.indicating.progress {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ui.progress .bar {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.ui.progress .buffer.bar {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
@keyframes MOVE-BG {
|
||||
from {
|
||||
transform: translateX(0px);
|
||||
}
|
||||
to {
|
||||
transform: translateX(46px);
|
||||
}
|
||||
}
|
||||
.discrete.link {
|
||||
color: inherit;
|
||||
}
|
||||
.indicating.progress .bar {
|
||||
left: -46px;
|
||||
width: 200% !important;
|
||||
color: grey;
|
||||
background: repeating-linear-gradient(
|
||||
-55deg,
|
||||
grey 1px,
|
||||
grey 10px,
|
||||
transparent 10px,
|
||||
transparent 20px
|
||||
) !important;
|
||||
|
||||
animation-name: MOVE-BG;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
.ui.progress:not([data-percent]):not(.indeterminate)
|
||||
.bar.position:not(.buffer) {
|
||||
background: #ff851b;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.track-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
flex-grow: 1;
|
||||
.image {
|
||||
padding: 0.5em;
|
||||
width: auto;
|
||||
margin-right: 0.5em;
|
||||
> img {
|
||||
max-height: 3.7em;
|
||||
max-width: 4.7em;
|
||||
}
|
||||
}
|
||||
}
|
||||
.controls {
|
||||
min-width: 8em;
|
||||
font-size: 1.1em;
|
||||
@include media(">desktop") {
|
||||
&:not(.fluid) {
|
||||
width: 20%;
|
||||
}
|
||||
&.queue-controls {
|
||||
width: 32.5%;
|
||||
}
|
||||
&.progress-controls {
|
||||
width: 10%;
|
||||
}
|
||||
&.player-controls {
|
||||
width: 15%;
|
||||
}
|
||||
}
|
||||
&.small, .small {
|
||||
@include media(">desktop") {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
.icon {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
.icon.large {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
&:not(.track-controls) {
|
||||
@include media(">desktop") {
|
||||
line-height: 1em;
|
||||
}
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
&.align-right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
&.align-left {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
> * {
|
||||
padding: 0.5em;
|
||||
}
|
||||
}
|
||||
&.player-controls {
|
||||
.icon {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.queue-enter-active, .queue-leave-active {
|
||||
transition: all 0.2s ease-in-out;
|
||||
.current-track, .queue-column {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
.queue-enter, .queue-leave-to {
|
||||
transform: translateY(100vh);
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<main class="main pusher">
|
||||
<main class="main pusher page-about">
|
||||
<section :class="['ui', 'head', {'with-background': banner}, 'vertical', 'center', 'aligned', 'stripe', 'segment']" :style="headerStyle">
|
||||
<div class="segment-content">
|
||||
<h1 class="ui center aligned large header">
|
||||
|
@ -173,22 +173,22 @@
|
|||
<translate translate-context="Content/Home/Header">Statistics</translate>
|
||||
</h3>
|
||||
<p>
|
||||
<i class="user grey icon"></i><translate translate-context="Content/Home/Stat" :translate-params="{count: stats.users.toLocaleString($store.state.ui.momentLocale) }" :translate-n="stats.users" translate-plural="%{ count } active users">%{ count } active user</translate>
|
||||
<i class="user really discrete icon"></i><translate translate-context="Content/Home/Stat" :translate-params="{count: stats.users.toLocaleString($store.state.ui.momentLocale) }" :translate-n="stats.users" translate-plural="%{ count } active users">%{ count } active user</translate>
|
||||
</p>
|
||||
<p>
|
||||
<i class="music grey icon"></i><translate translate-context="Content/Home/Stat" :translate-params="{count: parseInt(stats.hours).toLocaleString($store.state.ui.momentLocale)}" :translate-n="parseInt(stats.hours)" translate-plural="%{ count } hours of music">%{ count } hour of music</translate>
|
||||
<i class="music really discrete icon"></i><translate translate-context="Content/Home/Stat" :translate-params="{count: parseInt(stats.hours).toLocaleString($store.state.ui.momentLocale)}" :translate-n="parseInt(stats.hours)" translate-plural="%{ count } hours of music">%{ count } hour of music</translate>
|
||||
</p>
|
||||
<p v-if="stats.artists">
|
||||
<i class="users grey icon"></i><translate translate-context="Content/Home/Stat" :translate-params="{count: stats.artists.toLocaleString($store.state.ui.momentLocale) }" :translate-n="stats.artists" translate-plural="%{ count } artists">%{ count } artists</translate>
|
||||
<i class="users really discrete icon"></i><translate translate-context="Content/Home/Stat" :translate-params="{count: stats.artists.toLocaleString($store.state.ui.momentLocale) }" :translate-n="stats.artists" translate-plural="%{ count } artists">%{ count } artists</translate>
|
||||
</p>
|
||||
<p v-if="stats.albums">
|
||||
<i class="headphones grey icon"></i><translate translate-context="Content/Home/Stat" :translate-params="{count: stats.albums.toLocaleString($store.state.ui.momentLocale) }" :translate-n="stats.albums" translate-plural="%{ count } albums">%{ count } albums</translate>
|
||||
<i class="headphones really discrete icon"></i><translate translate-context="Content/Home/Stat" :translate-params="{count: stats.albums.toLocaleString($store.state.ui.momentLocale) }" :translate-n="stats.albums" translate-plural="%{ count } albums">%{ count } albums</translate>
|
||||
</p>
|
||||
<p v-if="stats.tracks">
|
||||
<i class="file grey icon"></i><translate translate-context="Content/Home/Stat" :translate-params="{count: stats.tracks.toLocaleString($store.state.ui.momentLocale) }" :translate-n="stats.tracks" translate-plural="%{ count } tracks">%{ count } tracks</translate>
|
||||
<i class="file really discrete icon"></i><translate translate-context="Content/Home/Stat" :translate-params="{count: stats.tracks.toLocaleString($store.state.ui.momentLocale) }" :translate-n="stats.tracks" translate-plural="%{ count } tracks">%{ count } tracks</translate>
|
||||
</p>
|
||||
<p v-if="stats.listenings">
|
||||
<i class="play grey icon"></i><translate translate-context="Content/Home/Stat" :translate-params="{count: stats.listenings.toLocaleString($store.state.ui.momentLocale) }" :translate-n="stats.listenings" translate-plural="%{ count } listenings">%{ count } listenings</translate>
|
||||
<i class="play really discrete icon"></i><translate translate-context="Content/Home/Stat" :translate-params="{count: stats.listenings.toLocaleString($store.state.ui.momentLocale) }" :translate-n="stats.listenings" translate-plural="%{ count } listenings">%{ count } listenings</translate>
|
||||
</p>
|
||||
</template>
|
||||
</div>
|
||||
|
@ -285,38 +285,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="scss">
|
||||
|
||||
.ui.list .list.icon {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h1.header, h1 .sub.header {
|
||||
text-shadow: 0 2px 0 rgba(0,0,0,.8);
|
||||
color: #fff !important;
|
||||
}
|
||||
h1.ui.header {
|
||||
font-size: 3em;
|
||||
}
|
||||
h1.ui.header .sub.header {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.main.pusher {
|
||||
margin-top: 0;
|
||||
min-height: 10em;
|
||||
}
|
||||
section.segment.head {
|
||||
padding: 8em 3em;
|
||||
background: linear-gradient(90deg, rgba(40,88,125,1) 0%, rgba(64,130,180,1) 100%);
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
#pod {
|
||||
font-size: 110%;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -9,16 +9,16 @@
|
|||
<h4 v-else class="ui header ellipsis">
|
||||
<span v-translate="{instanceUrl: instanceHostname}" translate-context="Footer/About/Title">About %{instanceUrl}</span>
|
||||
</h4>
|
||||
<div class="ui link list">
|
||||
<router-link class="item" to="/about">
|
||||
<div class="ui list">
|
||||
<router-link class="link item" to="/about">
|
||||
<translate translate-context="Footer/About/List item.Link">About page</translate>
|
||||
</router-link>
|
||||
<a v-if="version" class="item" href="https://docs.funkwhale.audio/changelog.html" target="_blank">
|
||||
<a v-if="version" class="link item" href="https://docs.funkwhale.audio/changelog.html" target="_blank">
|
||||
<translate translate-context="Footer/*/List item" :translate-params="{version: version}" >Version %{version}</translate>
|
||||
</a>
|
||||
<div role="button" class="item" @click="$emit('show:set-instance-modal')" >
|
||||
<a role="button" class="link item" @click.prevent="$emit('show:set-instance-modal')" >
|
||||
<translate translate-context="Footer/*/List item.Link">Use another instance</translate>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="ui form">
|
||||
<div class="ui field">
|
||||
|
@ -31,10 +31,10 @@
|
|||
</section>
|
||||
<section class="four wide column">
|
||||
<h4 v-translate class="ui header" translate-context="Footer/*/Title">Using Funkwhale</h4>
|
||||
<div class="ui link list">
|
||||
<a href="https://docs.funkwhale.audio" class="item" target="_blank"><translate translate-context="Footer/*/List item.Link/Short, Noun">Documentation</translate></a>
|
||||
<a href="https://funkwhale.audio/apps" class="item" target="_blank"><translate translate-context="Footer/*/List item.Link">Mobile and desktop apps</translate></a>
|
||||
<div role="button" class="item" @click="$emit('show:shortcuts-modal')"><translate translate-context="*/*/*/Noun">Keyboard shortcuts</translate></div>
|
||||
<div class="ui list">
|
||||
<a href="https://docs.funkwhale.audio" class="link item" target="_blank"><translate translate-context="Footer/*/List item.Link/Short, Noun">Documentation</translate></a>
|
||||
<a href="https://funkwhale.audio/apps" class="link item" target="_blank"><translate translate-context="Footer/*/List item.Link">Mobile and desktop apps</translate></a>
|
||||
<a role="button" class="link item" @click.prevent="$emit('show:shortcuts-modal')"><translate translate-context="*/*/*/Noun">Keyboard shortcuts</translate></a>
|
||||
</div>
|
||||
<div class="ui form">
|
||||
<div class="ui field">
|
||||
|
@ -47,18 +47,18 @@
|
|||
</section>
|
||||
<section class="four wide column">
|
||||
<h4 v-translate translate-context="Footer/*/Link" class="ui header">Getting help</h4>
|
||||
<div class="ui link list">
|
||||
<a href="https://governance.funkwhale.audio/g/kQgxNq15/funkwhale" class="item" target="_blank"><translate translate-context="Footer/*/Listitem.Link">Support forum</translate></a>
|
||||
<a href="https://riot.im/app/#/room/#funkwhale-troubleshooting:matrix.org" class="item" target="_blank"><translate translate-context="Footer/*/List item.Link">Chat room</translate></a>
|
||||
<a href="https://dev.funkwhale.audio/funkwhale/funkwhale/issues" class="item" target="_blank"><translate translate-context="Footer/*/List item.Link">Issue tracker</translate></a>
|
||||
<div class="ui list">
|
||||
<a href="https://governance.funkwhale.audio/g/kQgxNq15/funkwhale" class="link item" target="_blank"><translate translate-context="Footer/*/Listitem.Link">Support forum</translate></a>
|
||||
<a href="https://riot.im/app/#/room/#funkwhale-troubleshooting:matrix.org" class="link item" target="_blank"><translate translate-context="Footer/*/List item.Link">Chat room</translate></a>
|
||||
<a href="https://dev.funkwhale.audio/funkwhale/funkwhale/issues" class="link item" target="_blank"><translate translate-context="Footer/*/List item.Link">Issue tracker</translate></a>
|
||||
</div>
|
||||
</section>
|
||||
<section class="four wide column">
|
||||
<h4 v-translate class="ui header" translate-context="Footer/*/Title/Short">About Funkwhale</h4>
|
||||
<div class="ui link list">
|
||||
<a href="https://funkwhale.audio" class="item" target="_blank"><translate translate-context="Footer/*/List item.Link">Official website</translate></a>
|
||||
<a href="https://contribute.funkwhale.audio" class="item" target="_blank"><translate translate-context="Footer/*/List item.Link">Contribute</translate></a>
|
||||
<a href="https://dev.funkwhale.audio/funkwhale/funkwhale" class="item" target="_blank"><translate translate-context="Footer/*/List item.Link">Source code</translate></a>
|
||||
<div class="ui list">
|
||||
<a href="https://funkwhale.audio" class="link item" target="_blank"><translate translate-context="Footer/*/List item.Link">Official website</translate></a>
|
||||
<a href="https://contribute.funkwhale.audio" class="link item" target="_blank"><translate translate-context="Footer/*/List item.Link">Contribute</translate></a>
|
||||
<a href="https://dev.funkwhale.audio/funkwhale/funkwhale" class="link item" target="_blank"><translate translate-context="Footer/*/List item.Link">Source code</translate></a>
|
||||
</div>
|
||||
<div class="ui hidden divider"></div>
|
||||
<p>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<main class="main pusher" v-title="labels.title">
|
||||
<main class="main pusher page-home" v-title="labels.title">
|
||||
<section :class="['ui', 'head', {'with-background': banner}, 'vertical', 'center', 'aligned', 'stripe', 'segment']" :style="headerStyle">
|
||||
<div class="segment-content">
|
||||
<h1 class="ui center aligned large header">
|
||||
|
@ -32,7 +32,7 @@
|
|||
<div v-if="truncatedDescription" class="ui hidden divider"></div>
|
||||
<div class="ui relaxed list">
|
||||
<div class="item" v-if="truncatedDescription">
|
||||
<i class="arrow right grey icon"></i>
|
||||
<i class="arrow right icon"></i>
|
||||
<div class="content">
|
||||
<router-link class="ui link" :to="{name: 'about'}">
|
||||
<translate translate-context="Content/Home/Link">Learn more</translate>
|
||||
|
@ -40,7 +40,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="item" v-if="rules">
|
||||
<i class="book open grey icon"></i>
|
||||
<i class="book open icon"></i>
|
||||
<div class="content">
|
||||
<router-link class="ui link" v-if="rules" :to="{name: 'about', hash: '#rules'}">
|
||||
<translate translate-context="Content/Home/Link">Server rules</translate>
|
||||
|
@ -56,10 +56,10 @@
|
|||
<translate translate-context="Content/Home/Header">Statistics</translate>
|
||||
</h3>
|
||||
<p>
|
||||
<i class="user grey icon"></i><translate translate-context="Content/Home/Stat" :translate-params="{count: stats.users.toLocaleString($store.state.ui.momentLocale) }" :translate-n="stats.users" translate-plural="%{ count } active users">%{ count } active user</translate>
|
||||
<i class="user icon"></i><translate translate-context="Content/Home/Stat" :translate-params="{count: stats.users.toLocaleString($store.state.ui.momentLocale) }" :translate-n="stats.users" translate-plural="%{ count } active users">%{ count } active user</translate>
|
||||
</p>
|
||||
<p>
|
||||
<i class="music grey icon"></i><translate translate-context="Content/Home/Stat" :translate-params="{count: parseInt(stats.hours).toLocaleString($store.state.ui.momentLocale)}" :translate-n="parseInt(stats.hours)" translate-plural="%{ count } hours of music">%{ count } hour of music</translate>
|
||||
<i class="music icon"></i><translate translate-context="Content/Home/Stat" :translate-params="{count: parseInt(stats.hours).toLocaleString($store.state.ui.momentLocale)}" :translate-n="parseInt(stats.hours)" translate-plural="%{ count } hours of music">%{ count } hour of music</translate>
|
||||
</p>
|
||||
|
||||
</template>
|
||||
|
@ -67,7 +67,7 @@
|
|||
<h3 class="sub header">
|
||||
<translate translate-context="Content/Home/Header/Name">Contact</translate>
|
||||
</h3>
|
||||
<i class="at grey icon"></i>
|
||||
<i class="at icon"></i>
|
||||
<a :href="`mailto:${contactEmail}`">{{ contactEmail }}</a>
|
||||
</template>
|
||||
|
||||
|
@ -98,7 +98,7 @@
|
|||
<h3 class="header">
|
||||
<translate translate-context="Head/Login/Title">Log In</translate>
|
||||
</h3>
|
||||
<login-form button-classes="basic green" :show-signup="false"></login-form>
|
||||
<login-form button-classes="basic success" :show-signup="false"></login-form>
|
||||
<div class="ui hidden clearing divider"></div>
|
||||
</div>
|
||||
<div class="four wide column">
|
||||
|
@ -112,7 +112,7 @@
|
|||
<p v-if="defaultUploadQuota">
|
||||
<translate translate-context="Content/Home/Paragraph" :translate-params="{quota: humanSize(defaultUploadQuota * 1000 * 1000)}">Users on this pod also get %{ quota } of free storage to upload their own content!</translate>
|
||||
</p>
|
||||
<signup-form button-classes="basic green" :show-login="false"></signup-form>
|
||||
<signup-form button-classes="basic success" :show-login="false"></signup-form>
|
||||
</template>
|
||||
<div v-else>
|
||||
<p translate-context="Content/Home/Paragraph">Registrations are closed on this pod. You can signup on another pod using the link below.</p>
|
||||
|
@ -288,39 +288,3 @@ export default {
|
|||
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="scss">
|
||||
@import "../style/vendor/media";
|
||||
|
||||
.ui.list .list.icon {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h1.header, h1 .sub.header {
|
||||
text-shadow: 1px 1px 2px rgba(0,0,0,.8);
|
||||
color: #fff !important;
|
||||
}
|
||||
h1.ui.header {
|
||||
@include media(">tablet") {
|
||||
font-size: 3em;
|
||||
}
|
||||
}
|
||||
h1.ui.header .sub.header {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.main.pusher {
|
||||
margin-top: 0;
|
||||
min-height: 10em;
|
||||
}
|
||||
section.segment.head {
|
||||
padding: 8em 3em;
|
||||
background: linear-gradient(90deg, rgba(40,88,125,1) 0%, rgba(64,130,180,1) 100%);
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
#pod {
|
||||
font-size: 110%;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -36,7 +36,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div v-if='maxPage > 1' class="ui pagination menu" role="navigation" :aria-label="labels.pagination">
|
||||
<div v-if='maxPage > 1' class="ui pagination menu component-pagination" role="navigation" :aria-label="labels.pagination">
|
||||
<a href
|
||||
:disabled="current - 1 < 1"
|
||||
@click.prevent.stop="selectPage(current - 1)"
|
||||
|
@ -95,10 +95,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
.ui.pagination.menu .item {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<section class="main with-background" :aria-label="labels.queue">
|
||||
<section class="main with-background component-queue" :aria-label="labels.queue">
|
||||
<div :class="['ui vertical stripe queue segment', playerFocused ? 'player-focused' : '']">
|
||||
<div class="ui fluid container">
|
||||
<div class="ui stackable grid" id="queue-grid">
|
||||
|
@ -55,7 +55,7 @@
|
|||
<div class="progress-area" v-if="currentTrack && !errored">
|
||||
<div
|
||||
ref="progress"
|
||||
:class="['ui', 'small', 'orange', {'indicating': isLoadingAudio}, 'progress']"
|
||||
:class="['ui', 'small', 'vibrant', {'indicating': isLoadingAudio}, 'progress']"
|
||||
@click="touchProgress">
|
||||
<div class="buffer bar" :data-percent="bufferProgress" :style="{ 'width': bufferProgress + '%' }"></div>
|
||||
<div class="position bar" :data-percent="progress" :style="{ 'width': progress + '%' }"></div>
|
||||
|
@ -64,7 +64,7 @@
|
|||
<div class="progress-area" v-else>
|
||||
<div
|
||||
ref="progress"
|
||||
:class="['ui', 'small', 'orange', 'progress']">
|
||||
:class="['ui', 'small', 'vibrant', 'progress']">
|
||||
<div class="buffer bar"></div>
|
||||
<div class="position bar"></div>
|
||||
</div>
|
||||
|
@ -124,7 +124,7 @@
|
|||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui sixteen wide mobile ten wide computer column queue-column">
|
||||
<div class="ui ten wide column queue-column">
|
||||
<div class="ui basic clearing fixed-header segment">
|
||||
<h2 class="ui header">
|
||||
<div class="content">
|
||||
|
@ -155,7 +155,7 @@
|
|||
:key="index"
|
||||
:class="['queue-item', {'active': index === queue.currentIndex}]">
|
||||
<td class="handle">
|
||||
<i class="grip lines grey icon"></i>
|
||||
<i class="grip lines icon"></i>
|
||||
</td>
|
||||
<td class="image-cell" @click="$store.dispatch('queue/currentIndex', index)">
|
||||
<img class="ui mini image" v-if="track.album && track.album.cover && track.album.cover.original" :src="$store.getters['instance/absoluteUrl'](track.album.cover.square_crop)">
|
||||
|
@ -374,204 +374,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import "../style/vendor/media";
|
||||
|
||||
.main {
|
||||
position: absolute;
|
||||
min-height: 100vh;
|
||||
width: 100vw;
|
||||
z-index: 1000;
|
||||
padding-bottom: 3em;
|
||||
}
|
||||
.main > .button {
|
||||
position: fixed;
|
||||
top: 1em;
|
||||
right: 1em;
|
||||
z-index: 9999999;
|
||||
@include media("<desktop") {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.queue.segment:not(.player-focused) {
|
||||
#player {
|
||||
@include media("<desktop") {
|
||||
height: 0;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.queue.segment #player {
|
||||
padding: 0em;
|
||||
> * {
|
||||
padding: 0.5em;
|
||||
}
|
||||
}
|
||||
.player-focused .grid > .ui.queue-column {
|
||||
@include media("<desktop") {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.queue-column {
|
||||
overflow-y: auto;
|
||||
}
|
||||
.queue-column .table {
|
||||
margin-top: 4em !important;
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
.ui.table > tbody > tr > td.controls {
|
||||
text-align: right;
|
||||
}
|
||||
.ui.table > tbody > tr > td {
|
||||
border: none;
|
||||
}
|
||||
td:first-child {
|
||||
padding-left: 1em !important;
|
||||
}
|
||||
td:last-child {
|
||||
padding-right: 1em !important;
|
||||
}
|
||||
.image-cell {
|
||||
width: 4em;
|
||||
}
|
||||
.queue.segment {
|
||||
@include media("<desktop") {
|
||||
padding: 0;
|
||||
}
|
||||
> .container {
|
||||
margin: 0 !important;
|
||||
}
|
||||
}
|
||||
.handle {
|
||||
@include media("<desktop") {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.duration-cell {
|
||||
@include media("<tablet") {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.fixed-header {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 9;
|
||||
@include media("<desktop") {
|
||||
padding: 1em;
|
||||
}
|
||||
@include media(">desktop") {
|
||||
right: 1em;
|
||||
left: 38%;
|
||||
}
|
||||
.header .content {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.current-track #player {
|
||||
font-size: 1.8em;
|
||||
padding: 1em;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
position: fixed;
|
||||
height: 100vh;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
width: 32%;
|
||||
@include media("<desktop") {
|
||||
padding: 0.5em;
|
||||
font-size: 1.5em;
|
||||
width: 100%;
|
||||
width: 100vw;
|
||||
left: 0;
|
||||
right: 0;
|
||||
> .image {
|
||||
max-height: 50vh;
|
||||
}
|
||||
}
|
||||
> *:not(.image) {
|
||||
width: 100%;
|
||||
}
|
||||
h1 {
|
||||
margin: 0;
|
||||
min-height: auto;
|
||||
}
|
||||
}
|
||||
.progress-area {
|
||||
overflow: hidden;
|
||||
}
|
||||
.progress-wrapper, .warning.message {
|
||||
max-width: 25em;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.ui.progress .buffer.bar {
|
||||
position: absolute;
|
||||
background-color: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
.ui.progress:not([data-percent]):not(.indeterminate)
|
||||
.bar.position:not(.buffer) {
|
||||
background: #ff851b;
|
||||
}
|
||||
|
||||
.indicating.progress .bar {
|
||||
left: -46px;
|
||||
width: 200% !important;
|
||||
color: grey;
|
||||
background: repeating-linear-gradient(
|
||||
-55deg,
|
||||
grey 1px,
|
||||
grey 10px,
|
||||
transparent 10px,
|
||||
transparent 20px
|
||||
) !important;
|
||||
|
||||
animation-name: MOVE-BG;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
.ui.progress {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
.timer {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
.progress {
|
||||
cursor: pointer;
|
||||
.bar {
|
||||
min-width: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.player-controls {
|
||||
.control:not(:first-child) {
|
||||
margin-left: 1em;
|
||||
}
|
||||
.icon {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
}
|
||||
|
||||
.handle {
|
||||
cursor: grab;
|
||||
}
|
||||
.sortable-chosen {
|
||||
cursor: grabbing;
|
||||
}
|
||||
.queue-item.sortable-ghost {
|
||||
td {
|
||||
border-top: 3px dashed rgba(0, 0, 0, 0.15) !important;
|
||||
border-bottom: 3px dashed rgba(0, 0, 0, 0.15) !important;
|
||||
&:first-child {
|
||||
border-left: 3px dashed rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
&:last-child {
|
||||
border-right: 3px dashed rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -142,6 +142,3 @@ export default {
|
|||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -157,7 +157,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<template>
|
||||
<aside :class="['ui', 'vertical', 'left', 'visible', 'wide', {'collapsed': isCollapsed}, 'sidebar',]">
|
||||
<aside :class="['ui', 'vertical', 'left', 'visible', 'wide', {'collapsed': isCollapsed}, 'sidebar', 'component-sidebar']">
|
||||
<header class="ui basic segment header-wrapper">
|
||||
<router-link :title="'Funkwhale'" :to="{name: logoUrl}">
|
||||
<i class="logo bordered inverted orange big icon">
|
||||
<i class="logo bordered inverted vibrant big icon">
|
||||
<logo class="logo"></logo>
|
||||
</i>
|
||||
</router-link>
|
||||
|
@ -88,7 +88,7 @@
|
|||
|
||||
<span
|
||||
@click="isCollapsed = !isCollapsed"
|
||||
:class="['ui', 'basic', 'big', {'orange': !isCollapsed}, 'inverted icon', 'collapse', 'button']">
|
||||
:class="['ui', 'basic', 'big', {'vibrant': !isCollapsed}, 'inverted icon', 'collapse', 'button']">
|
||||
<i class="sidebar icon"></i></span>
|
||||
</div>
|
||||
</nav>
|
||||
|
@ -343,239 +343,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="scss">
|
||||
@import "../style/vendor/media";
|
||||
|
||||
$sidebar-color: #2D2F33;
|
||||
|
||||
.sidebar {
|
||||
background: $sidebar-color;
|
||||
z-index: 1;
|
||||
@include media(">desktop") {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding-bottom: 4em;
|
||||
}
|
||||
> nav {
|
||||
flex-grow: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
@include media(">desktop") {
|
||||
.menu .item.collapse-button-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
.collapse.button {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
@include media("<=desktop") {
|
||||
position: static !important;
|
||||
width: 100% !important;
|
||||
&.collapsed {
|
||||
.player-wrapper,
|
||||
.search,
|
||||
.signup.segment,
|
||||
nav.secondary {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
margin: 0;
|
||||
background-color: $sidebar-color;
|
||||
}
|
||||
.menu.vertical {
|
||||
background: $sidebar-color;
|
||||
}
|
||||
}
|
||||
|
||||
.ui.vertical.menu {
|
||||
.item .item {
|
||||
font-size: 1em;
|
||||
> i.icon {
|
||||
float: none;
|
||||
margin: 0 0.5em 0 0;
|
||||
}
|
||||
&:not(.active) {
|
||||
// color: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
}
|
||||
.item.active {
|
||||
border-right: 5px solid #F2711C;
|
||||
border-radius: 0 !important;
|
||||
background-color: rgba(255, 255, 255, 0.15) !important;
|
||||
}
|
||||
.item.collapsed {
|
||||
&:not(:focus) > .menu {
|
||||
display: none;
|
||||
}
|
||||
.header {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
.collaspable.item .header {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.ui.secondary.menu {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
.tabs {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
justify-content: space-between;
|
||||
@include media("<=desktop") {
|
||||
max-height: 500px;
|
||||
}
|
||||
}
|
||||
.ui.tab.active {
|
||||
display: flex;
|
||||
}
|
||||
.tab[data-tab="queue"] {
|
||||
flex-direction: column;
|
||||
tr {
|
||||
cursor: pointer;
|
||||
}
|
||||
td:nth-child(2) {
|
||||
width: 55px;
|
||||
}
|
||||
}
|
||||
.item .header .angle.icon {
|
||||
float: right;
|
||||
margin: 0;
|
||||
}
|
||||
.tab[data-tab="library"] {
|
||||
flex-direction: column;
|
||||
flex: 1 1 auto;
|
||||
> .menu {
|
||||
flex: 1;
|
||||
flex-grow: 1;
|
||||
}
|
||||
> .player-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.sidebar .segment {
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.ui.menu .item.inline.admin-dropdown.dropdown > .menu {
|
||||
left: 0;
|
||||
right: auto;
|
||||
}
|
||||
.ui.segment.header-wrapper {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 4em;
|
||||
nav {
|
||||
> .item, > .menu > .item > .item {
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nav.top.title-menu {
|
||||
flex-grow: 1;
|
||||
.item {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.collapsed .search-wrapper {
|
||||
@include media("<desktop") {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
.ui.search {
|
||||
display: flex;
|
||||
}
|
||||
.ui.message.black {
|
||||
background: $sidebar-color;
|
||||
}
|
||||
|
||||
.ui.mini.image {
|
||||
width: 100%;
|
||||
}
|
||||
nav.top {
|
||||
align-items: self-end;
|
||||
padding: 0.5em 0;
|
||||
> .item, > .right.menu > .item {
|
||||
// color: rgba(255, 255, 255, 0.9) !important;
|
||||
font-size: 1.2em;
|
||||
&:hover, > .dropdown > .icon {
|
||||
// color: rgba(255, 255, 255, 0.9) !important;
|
||||
}
|
||||
> .label, > .dropdown > .label {
|
||||
font-size: 0.5em;
|
||||
right: 1.7em;
|
||||
bottom: -0.5em;
|
||||
z-index: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ui.user-dropdown > .text > .label {
|
||||
margin-right: 0;
|
||||
}
|
||||
.logo-wrapper {
|
||||
display: inline-block;
|
||||
margin: 0 auto;
|
||||
@include media("<desktop") {
|
||||
margin: 0;
|
||||
}
|
||||
img {
|
||||
height: 1em;
|
||||
display: inline-block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
@include media(">tablet") {
|
||||
img {
|
||||
height: 1.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
aside.ui.sidebar {
|
||||
overflow-y: visible !important;
|
||||
.ui.search .input {
|
||||
flex: 1;
|
||||
.prompt {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
.ui.search .results {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.ui.search .name {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
.ui.tiny.avatar.image {
|
||||
position: relative;
|
||||
top: -0.5em;
|
||||
width: 3em;
|
||||
}
|
||||
|
||||
:not(.active) button.title {
|
||||
outline-color: white;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<form :id="group.id" class="ui form" @submit.prevent="save">
|
||||
<form :id="group.id" class="ui form component-settings-group" @submit.prevent="save">
|
||||
<div class="ui divider" />
|
||||
<h3 class="ui header">{{ group.label }}</h3>
|
||||
<div v-if="errors.length > 0" class="ui negative message">
|
||||
|
@ -78,7 +78,7 @@
|
|||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
:class="['ui', {'loading': isLoading}, 'right', 'floated', 'green', 'button']">
|
||||
:class="['ui', {'loading': isLoading}, 'right', 'floated', 'success', 'button']">
|
||||
<translate translate-context="Content/*/Button.Label/Verb">Save</translate>
|
||||
</button>
|
||||
</form>
|
||||
|
@ -176,10 +176,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
.ui.checkbox p {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div class="album-entries">
|
||||
<div :class="[{active: currentTrack && isPlaying && track.id === currentTrack.id}, 'album-entry']" v-for="track in tracks" :key="track.id">
|
||||
<div class="actions">
|
||||
<play-button class="basic circular icon" :button-classes="['circular inverted orange icon button']" :discrete="true" :icon-only="true" :track="track"></play-button>
|
||||
<play-button class="basic circular icon" :button-classes="['circular inverted vibrant icon button']" :discrete="true" :icon-only="true" :track="track"></play-button>
|
||||
</div>
|
||||
<div class="position">{{ prettyPosition(track.position) }}</div>
|
||||
<div class="content ellipsis">
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div
|
||||
@click="$router.push({name: 'channels.detail', params: {id: urlId}})"
|
||||
:class="['ui', 'head-image', {'circular': object.artist.content_category != 'podcast'}, {'padded': object.artist.content_category === 'podcast'}, 'image', {'default-cover': !object.artist.cover}]" v-lazy:background-image="imageUrl">
|
||||
<play-button :icon-only="true" :is-playable="true" :button-classes="['ui', 'circular', 'large', 'orange', 'icon', 'button']" :artist="object.artist"></play-button>
|
||||
<play-button :icon-only="true" :is-playable="true" :button-classes="['ui', 'circular', 'large', 'vibrant', 'icon', 'button']" :artist="object.artist"></play-button>
|
||||
</div>
|
||||
<div class="content">
|
||||
<strong>
|
||||
|
@ -37,7 +37,7 @@
|
|||
class="right floated basic icon"
|
||||
:dropdown-only="true"
|
||||
:is-playable="true"
|
||||
:dropdown-icon-classes="['ellipsis', 'horizontal', 'large', 'grey']" :artist="object.artist" :channel="object" :account="object.attributed_to"></play-button>
|
||||
:dropdown-icon-classes="['ellipsis', 'horizontal', 'large really discrete']" :artist="object.artist" :channel="object" :account="object.attributed_to"></play-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -58,14 +58,9 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
imageUrl () {
|
||||
let url = '../../assets/audio/default-cover.png'
|
||||
|
||||
if (this.object.artist.cover) {
|
||||
url = this.$store.getters['instance/absoluteUrl'](this.object.artist.cover.medium_square_crop)
|
||||
} else {
|
||||
return null
|
||||
return this.$store.getters['instance/absoluteUrl'](this.object.artist.cover.medium_square_crop)
|
||||
}
|
||||
return url
|
||||
},
|
||||
urlId () {
|
||||
if (this.object.actor && this.object.actor.is_local) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div :class="[{active: currentTrack && isPlaying && entry.id === currentTrack.id}, 'channel-entry-card']">
|
||||
<div class="controls">
|
||||
<play-button class="basic circular icon" :discrete="true" :icon-only="true" :is-playable="true" :button-classes="['ui', 'circular', 'inverted orange', 'icon', 'button']" :track="entry"></play-button>
|
||||
<play-button class="basic circular icon" :discrete="true" :icon-only="true" :is-playable="true" :button-classes="['ui', 'circular', 'inverted vibrant', 'icon', 'button']" :track="entry"></play-button>
|
||||
</div>
|
||||
<img
|
||||
@click="$router.push({name: 'library.tracks.detail', params: {id: entry.id}})"
|
||||
|
@ -62,16 +62,6 @@ export default {
|
|||
isPlaying () {
|
||||
return this.$store.state.player.playing
|
||||
},
|
||||
imageUrl () {
|
||||
let url = '../../assets/audio/default-cover.png'
|
||||
let cover = this.cover
|
||||
if (cover && cover.original) {
|
||||
url = this.$store.getters['instance/absoluteUrl'](cover.medium_square_crop)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
return url
|
||||
},
|
||||
cover () {
|
||||
if (this.entry.cover) {
|
||||
return this.entry.cover
|
||||
|
@ -88,7 +78,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="controls">
|
||||
<play-button :icon-only="true" :is-playable="true" :button-classes="['ui', 'circular', 'orange', 'icon', 'button']" :album="serie"></play-button>
|
||||
<play-button :icon-only="true" :is-playable="true" :button-classes="['ui', 'circular', 'vibrant', 'icon', 'button']" :album="serie"></play-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -36,16 +36,6 @@ export default {
|
|||
PlayButton,
|
||||
},
|
||||
computed: {
|
||||
imageUrl () {
|
||||
let url = '../../assets/audio/default-cover.png'
|
||||
let cover = this.cover
|
||||
if (cover && cover.original) {
|
||||
url = this.$store.getters['instance/absoluteUrl'](cover.medium_square_crop)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
return url
|
||||
},
|
||||
cover () {
|
||||
if (this.serie.cover) {
|
||||
return this.serie.cover
|
||||
|
@ -60,10 +50,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
.default-cover {
|
||||
background-image: url("../../assets/audio/default-cover.png") !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -115,12 +115,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
p.message {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: -2em;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -37,7 +37,3 @@ export default {
|
|||
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<span :title="title" :class="['ui', {'tiny': discrete}, {'icon': !discrete}, {'buttons': !dropdownOnly && !iconOnly}, 'play-button']">
|
||||
<span :title="title" :class="['ui', {'tiny': discrete}, {'icon': !discrete}, {'buttons': !dropdownOnly && !iconOnly}, 'play-button component-play-button']">
|
||||
<button
|
||||
v-if="!dropdownOnly"
|
||||
:title="labels.playNow"
|
||||
|
@ -12,6 +12,7 @@
|
|||
<div
|
||||
v-if="!discrete && !iconOnly"
|
||||
@click.prevent="clicked = true"
|
||||
role="button"
|
||||
:class="['ui', {disabled: !playable && !filterableArtist}, 'floating', 'dropdown', {'icon': !dropdownOnly}, {'button': !dropdownOnly}]">
|
||||
<i :class="dropdownIconClasses.concat(['icon'])" :title="title" ></i>
|
||||
<div class="menu" v-if="clicked">
|
||||
|
@ -288,14 +289,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
i {
|
||||
cursor: pointer;
|
||||
}
|
||||
button.item {
|
||||
background-color: white;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<template>
|
||||
<section v-if="currentTrack" class="player-wrapper ui bottom-player">
|
||||
<section v-if="currentTrack" class="player-wrapper ui bottom-player component-player">
|
||||
<div class="ui inverted segment fixed-controls" @click.prevent.stop="toggleMobilePlayer">
|
||||
<div
|
||||
:class="['ui', 'top attached', 'small', 'orange', 'inverted', {'indicating': isLoadingAudio}, 'progress']">
|
||||
:class="['ui', 'top attached', 'small', 'inverted', {'indicating': isLoadingAudio}, 'progress']">
|
||||
<div class="buffer bar" :data-percent="bufferProgress" :style="{ 'width': bufferProgress + '%' }"></div>
|
||||
<div class="position bar" :data-percent="progress" :style="{ 'width': progress + '%' }"></div>
|
||||
</div>
|
||||
|
@ -128,7 +128,7 @@
|
|||
:disabled="!currentTrack">
|
||||
<i
|
||||
class="repeat icon">
|
||||
<span class="ui circular tiny orange label">1</span>
|
||||
<span class="ui circular tiny vibrant label">1</span>
|
||||
</i>
|
||||
</span>
|
||||
<span
|
||||
|
@ -141,7 +141,7 @@
|
|||
@click.prevent.stop="$store.commit('player/looping', 0)">
|
||||
<i
|
||||
class="repeat icon">
|
||||
<span class="ui circular tiny orange label">∞</span>
|
||||
<span class="ui circular tiny vibrant label">∞</span>
|
||||
</i>
|
||||
</span>
|
||||
<span
|
||||
|
@ -436,7 +436,6 @@ export default {
|
|||
param = "token"
|
||||
value = this.$store.state.auth.scopedTokens.listen
|
||||
}
|
||||
console.log('HELLO', param, value, this.$store.state.auth.scopedTokens)
|
||||
sources.forEach(e => {
|
||||
e.url = url.updateQueryString(e.url, param, value)
|
||||
})
|
||||
|
@ -777,77 +776,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="scss">
|
||||
@import "../../style/vendor/media";
|
||||
.controls {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.controls .icon.big {
|
||||
cursor: pointer;
|
||||
font-size: 2em !important;
|
||||
}
|
||||
|
||||
.controls .icon {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.timer {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.looping {
|
||||
i {
|
||||
position: relative;
|
||||
}
|
||||
.ui.circular.label {
|
||||
font-family: sans-serif;
|
||||
position: absolute;
|
||||
font-size: 0.5em !important;
|
||||
bottom: -0.7rem;
|
||||
right: -0.7rem;
|
||||
padding: 2px 0 !important;
|
||||
width: 15px !important;
|
||||
height: 15px !important;
|
||||
min-width: 15px !important;
|
||||
min-height: 15px !important;
|
||||
@include media(">desktop") {
|
||||
font-size: 0.6em !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.shuffling.loader.inline {
|
||||
margin: 0;
|
||||
}
|
||||
.control.circular.button {
|
||||
padding: 0;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
}
|
||||
.fake-dropdown {
|
||||
border: 1px solid gray;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
min-width: 10em;
|
||||
> * {
|
||||
padding: 0.5em;
|
||||
|
||||
}
|
||||
.position.control {
|
||||
padding-right: 1em;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.angle.icon {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -98,7 +98,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -236,7 +236,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<span :class="['volume-control', {'expanded': expanded}]" @click.prevent.stop="" @mouseover="handleOver" @mouseleave="handleLeave">
|
||||
<span :class="['component-volume-control', {'expanded': expanded}]" @click.prevent.stop="" @mouseover="handleOver" @mouseleave="handleLeave">
|
||||
<span
|
||||
role="button"
|
||||
v-if="sliderVolume === 0"
|
||||
|
@ -82,37 +82,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.volume-control {
|
||||
display: flex;
|
||||
line-height: inherit;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
input {
|
||||
max-width: 5.5em;
|
||||
height: 4px;
|
||||
}
|
||||
&.expandable {
|
||||
.popup {
|
||||
background-color: #1B1C1D;
|
||||
position: absolute;
|
||||
left: -4em;
|
||||
top: -7em;
|
||||
transform: rotate(-90deg);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 2.5em;
|
||||
padding: 0 0.5em;
|
||||
box-shadow: 1px 1px 3px rgba(125, 125, 125, 0.5);
|
||||
}
|
||||
input {
|
||||
max-width: 8.5em;
|
||||
}
|
||||
&:not(:hover):not(.expanded) .popup {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<div class="card app-card">
|
||||
<div class="card app-card component-album-card">
|
||||
<div
|
||||
@click="$router.push({name: 'library.albums.detail', params: {id: album.id}})"
|
||||
:class="['ui', 'head-image', 'image', {'default-cover': !album.cover.original}]" v-lazy:background-image="imageUrl">
|
||||
<play-button :icon-only="true" :is-playable="album.is_playable" :button-classes="['ui', 'circular', 'large', 'orange', 'icon', 'button']" :album="album"></play-button>
|
||||
<play-button :icon-only="true" :is-playable="album.is_playable" :button-classes="['ui', 'circular', 'large', 'vibrant', 'icon', 'button']" :album="album"></play-button>
|
||||
</div>
|
||||
<div class="content">
|
||||
<strong>
|
||||
|
@ -21,7 +21,7 @@
|
|||
</div>
|
||||
<div class="extra content">
|
||||
<translate translate-context="*/*/*" :translate-params="{count: album.tracks.length}" :translate-n="album.tracks.length" translate-plural="%{ count } tracks">%{ count } track</translate>
|
||||
<play-button class="right floated basic icon" :dropdown-only="true" :is-playable="album.is_playable" :dropdown-icon-classes="['ellipsis', 'horizontal', 'large', 'grey']" :album="album"></play-button>
|
||||
<play-button class="right floated basic icon" :dropdown-only="true" :is-playable="album.is_playable" :dropdown-icon-classes="['ellipsis', 'horizontal', 'large really discrete']" :album="album"></play-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -38,28 +38,10 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
imageUrl () {
|
||||
let url = '../../../assets/audio/default-cover.png'
|
||||
|
||||
if (this.album.cover.original) {
|
||||
url = this.$store.getters['instance/absoluteUrl'](this.album.cover.medium_square_crop)
|
||||
} else {
|
||||
return null
|
||||
return this.$store.getters['instance/absoluteUrl'](this.album.cover.medium_square_crop)
|
||||
}
|
||||
return url
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="scss">
|
||||
|
||||
.default-cover {
|
||||
background-image: url("../../../assets/audio/default-cover.png") !important;
|
||||
}
|
||||
|
||||
.card.app-card > .head-image > .icon {
|
||||
margin: 0.5em;
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -91,18 +91,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
|
||||
|
||||
.wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
.ui.cards {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.ui.cards .ui.button {
|
||||
margin-right: 0px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div
|
||||
@click="$router.push({name: 'library.artists.detail', params: {id: artist.id}})"
|
||||
:class="['ui', 'head-image', 'circular', 'image', {'default-cover': !cover.original}]" v-lazy:background-image="imageUrl">
|
||||
<play-button :icon-only="true" :is-playable="artist.is_playable" :button-classes="['ui', 'circular', 'large', 'orange', 'icon', 'button']" :artist="artist"></play-button>
|
||||
<play-button :icon-only="true" :is-playable="artist.is_playable" :button-classes="['ui', 'circular', 'large', 'vibrant', 'icon', 'button']" :artist="artist"></play-button>
|
||||
</div>
|
||||
<div class="content">
|
||||
<strong>
|
||||
|
@ -16,7 +16,7 @@
|
|||
</div>
|
||||
<div class="extra content">
|
||||
<translate translate-context="*/*/*" :translate-params="{count: artist.tracks_count}" :translate-n="artist.tracks_count" translate-plural="%{ count } tracks">%{ count } track</translate>
|
||||
<play-button class="right floated basic icon" :dropdown-only="true" :is-playable="artist.is_playable" :dropdown-icon-classes="['ellipsis', 'horizontal', 'large', 'grey']" :artist="artist"></play-button>
|
||||
<play-button class="right floated basic icon" :dropdown-only="true" :is-playable="artist.is_playable" :dropdown-icon-classes="['ellipsis', 'horizontal', 'large really discrete']" :artist="artist"></play-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -39,14 +39,10 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
imageUrl () {
|
||||
let url = '../../../assets/audio/default-cover.png'
|
||||
let cover = this.cover
|
||||
if (cover.original) {
|
||||
url = this.$store.getters['instance/absoluteUrl'](cover.medium_square_crop)
|
||||
} else {
|
||||
return null
|
||||
return this.$store.getters['instance/absoluteUrl'](cover.medium_square_crop)
|
||||
}
|
||||
return url
|
||||
},
|
||||
cover () {
|
||||
if (this.artist.cover && this.artist.cover.original) {
|
||||
|
@ -61,10 +57,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
.default-cover {
|
||||
background-image: url("../../../assets/audio/default-cover.png") !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -90,27 +90,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import "../../../style/vendor/media";
|
||||
|
||||
.wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
.ui.cards {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.ui.three.cards .card {
|
||||
width: 100%;
|
||||
}
|
||||
@include media(">tablet") {
|
||||
.ui.three.cards .card {
|
||||
width: 25em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.ui.cards .ui.button {
|
||||
margin-right: 0px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<tr>
|
||||
<td>
|
||||
<play-button :class="['basic', {orange: currentTrack && isPlaying && track.id === currentTrack.id}, 'icon']" :discrete="true" :is-playable="playable" :track="track"></play-button>
|
||||
<play-button :class="['basic', {vibrant: currentTrack && isPlaying && track.id === currentTrack.id}, 'icon']" :discrete="true" :is-playable="playable" :track="track"></play-button>
|
||||
</td>
|
||||
<td>
|
||||
<img class="ui mini image" v-if="track.album && track.album.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](track.album.cover.small_square_crop)">
|
||||
|
@ -12,17 +12,17 @@
|
|||
<template v-if="displayPosition && track.position">
|
||||
{{ track.position }}.
|
||||
</template>
|
||||
{{ track.title }}
|
||||
{{ track.title|truncate(40) }}
|
||||
</router-link>
|
||||
</td>
|
||||
<td colspan="4">
|
||||
<router-link class="artist discrete link" :to="{name: 'library.artists.detail', params: {id: track.artist.id }}">
|
||||
{{ track.artist.name }}
|
||||
{{ track.artist.name|truncate(40) }}
|
||||
</router-link>
|
||||
</td>
|
||||
<td colspan="4">
|
||||
<router-link v-if="track.album" class="album discrete link" :title="track.album.title" :to="{name: 'library.albums.detail', params: {id: track.album.id }}">
|
||||
{{ track.album.title }}
|
||||
{{ track.album.title|truncate(40) }}
|
||||
</router-link>
|
||||
</td>
|
||||
<td colspan="4" v-if="track.uploads && track.uploads.length > 0">
|
||||
|
@ -32,17 +32,17 @@
|
|||
<translate translate-context="*/*/*">N/A</translate>
|
||||
</td>
|
||||
<td colspan="2" v-if="displayActions" class="align right">
|
||||
<track-favorite-icon class="favorite-icon" :track="track"></track-favorite-icon>
|
||||
<play-button
|
||||
class="play-button basic icon"
|
||||
:dropdown-only="true"
|
||||
:is-playable="track.is_playable"
|
||||
:dropdown-icon-classes="['ellipsis', 'vertical', 'large', 'grey']"
|
||||
:dropdown-icon-classes="['ellipsis', 'vertical', 'large really discrete']"
|
||||
:track="track"
|
||||
></play-button>
|
||||
<track-playlist-icon
|
||||
v-if="$store.state.auth.authenticated"
|
||||
:track="track"></track-playlist-icon>
|
||||
<track-favorite-icon class="favorite-icon" :track="track"></track-favorite-icon>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
@ -83,13 +83,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style lang="scss" scoped>
|
||||
tr:not(:hover) {
|
||||
.favorite-icon:not(.favorited),
|
||||
.playlist-icon {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="table-wrapper">
|
||||
<div class="table-wrapper component-track-table">
|
||||
<inline-search-bar v-model="query" v-if="search" @search="additionalTracks = []; loadMore()"></inline-search-bar>
|
||||
<slot v-if="!isLoading && allTracks.length === 0" name="empty-state">
|
||||
<empty-state @refresh="fetchData" :refresh="true"></empty-state>
|
||||
|
@ -90,16 +90,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
tr:not(:hover) .favorite-icon:not(.favorited) {
|
||||
display: none;
|
||||
}
|
||||
pre {
|
||||
overflow-x: scroll;
|
||||
}
|
||||
.table-wrapper {
|
||||
overflow: visible;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="component-track-widget">
|
||||
<h3 class="ui header">
|
||||
<slot name="title"></slot>
|
||||
<span v-if="showCount" class="ui tiny circular label">{{ count }}</span>
|
||||
|
@ -9,7 +9,7 @@
|
|||
<div class="ui tiny image">
|
||||
<img v-if="object.track.album && object.track.album.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](object.track.album.cover.medium_square_crop)">
|
||||
<img v-else src="../../../assets/audio/default-cover.png">
|
||||
<play-button class="play-overlay" :icon-only="true" :button-classes="['ui', 'circular', 'tiny', 'orange', 'icon', 'button']" :track="object.track"></play-button>
|
||||
<play-button class="play-overlay" :icon-only="true" :button-classes="['ui', 'circular', 'tiny', 'vibrant', 'icon', 'button']" :track="object.track"></play-button>
|
||||
</div>
|
||||
<div class="middle aligned content">
|
||||
<div class="ui unstackable grid">
|
||||
|
@ -38,7 +38,7 @@
|
|||
class="basic icon"
|
||||
:account="object.actor"
|
||||
:dropdown-only="true"
|
||||
:dropdown-icon-classes="['ellipsis', 'vertical', 'large', 'grey']"
|
||||
:dropdown-icon-classes="['ellipsis', 'vertical', 'large really discrete']"
|
||||
:track="object.track"></play-button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -151,37 +151,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "../../../style/vendor/media";
|
||||
|
||||
.play-overlay {
|
||||
position: absolute;
|
||||
top: 4em;
|
||||
left: 4em;
|
||||
@include media(">tablet") {
|
||||
top: 2.5em;
|
||||
left: 2.5em;
|
||||
}
|
||||
}
|
||||
.refresh.icon {
|
||||
float: right;
|
||||
}
|
||||
.ui.divided.items > .item:last-child {
|
||||
padding-bottom: 1em !important;
|
||||
}
|
||||
|
||||
@include media(">tablet") {
|
||||
.divided.items > .track-item.inline {
|
||||
width: 25em;
|
||||
float: left;
|
||||
border-top: none;
|
||||
&,
|
||||
&:first-child {
|
||||
margin-top: 0.5em !important;
|
||||
margin-right: 0.5em !important;
|
||||
padding: 1em 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
|
||||
<form class="ui form" @submit.prevent="submit()">
|
||||
<form class="ui form component-form" @submit.prevent="submit()">
|
||||
<div v-if="errors.length > 0" class="ui negative message">
|
||||
<div class="header"><translate translate-context="Content/*/Error message.Title">We cannot save your changes</translate></div>
|
||||
<ul class="list">
|
||||
|
@ -62,7 +62,7 @@
|
|||
</div>
|
||||
|
||||
</div>
|
||||
<button :class="['ui', {'loading': isLoading}, 'green', 'button']" type="submit">
|
||||
<button :class="['ui', {'loading': isLoading}, 'success', 'button']" type="submit">
|
||||
<translate v-if="updating" key="2" translate-context="Content/Applications/Button.Label/Verb">Update application</translate>
|
||||
<translate v-else key="2" translate-context="Content/Applications/Button.Label/Verb">Create application</translate>
|
||||
</button>
|
||||
|
@ -173,13 +173,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
.parent.checkbox {
|
||||
margin: 1em 0;
|
||||
}
|
||||
.child.checkbox {
|
||||
margin-left: 1em;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -16,15 +16,15 @@
|
|||
<form v-else-if="application && !code" :class="['ui', {loading: isLoading}, 'form']" @submit.prevent="submit">
|
||||
<h3><translate translate-context="Content/Auth/Title" :translate-params="{app: application.name}">%{ app } wants to access your Funkwhale account</translate></h3>
|
||||
|
||||
<h4 v-for="topic in topicScopes" class="ui header">
|
||||
<span v-if="topic.write && !topic.read" :class="['ui', 'basic', 'right floated', 'tiny', 'label']">
|
||||
<h4 v-for="topic in topicScopes" class="ui header vertical-align">
|
||||
<span v-if="topic.write && !topic.read" :class="['ui', 'basic', 'right floated', 'tiny', 'vertically-spaced component-label label']">
|
||||
<i class="pencil icon"></i>
|
||||
<translate translate-context="Content/Auth/Label/Noun">Write-only</translate>
|
||||
</span>
|
||||
<span v-else-if="!topic.write && topic.read" :class="['ui', 'basic', 'right floated', 'tiny', 'label']">
|
||||
<span v-else-if="!topic.write && topic.read" :class="['ui', 'basic', 'right floated', 'tiny', 'vertically-spaced component-label label']">
|
||||
<translate translate-context="Content/Auth/Label/Noun">Read-only</translate>
|
||||
</span>
|
||||
<span v-else-if="topic.write && topic.read" :class="['ui', 'basic', 'right floated', 'tiny', 'label']">
|
||||
<span v-else-if="topic.write && topic.read" :class="['ui', 'basic', 'right floated', 'tiny', 'vertically-spaced component-label label']">
|
||||
<i class="pencil icon"></i>
|
||||
<translate translate-context="Content/Auth/Label/Noun">Full access</translate>
|
||||
</span>
|
||||
|
@ -43,7 +43,7 @@
|
|||
</ul>
|
||||
|
||||
</div>
|
||||
<button class="ui green labeled icon button" type="submit">
|
||||
<button class="ui success labeled icon button" type="submit">
|
||||
<i class="lock open icon"></i>
|
||||
<translate translate-context="Content/Signup/Button.Label/Verb" :translate-params="{app: application.name}">Authorize %{ app }</translate>
|
||||
</button>
|
||||
|
@ -189,13 +189,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
.ui.header .content {
|
||||
text-align: left;
|
||||
}
|
||||
.ui.header > .ui.label {
|
||||
margin-top: 0.3em;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -55,7 +55,7 @@ import PasswordInput from "@/components/forms/PasswordInput"
|
|||
export default {
|
||||
props: {
|
||||
next: { type: String, default: "/library" },
|
||||
buttonClasses: { type: String, default: "green" },
|
||||
buttonClasses: { type: String, default: "success" },
|
||||
showSignup: { type: Boolean, default: true},
|
||||
},
|
||||
components: {
|
||||
|
@ -117,7 +117,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -23,7 +23,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -81,7 +81,7 @@
|
|||
<password-input required v-model="new_password" />
|
||||
</div>
|
||||
<dangerous-button
|
||||
:class="['ui', {'loading': isLoading}, 'yellow', 'button']"
|
||||
:class="['ui', {'loading': isLoading}, 'warning', 'button']"
|
||||
:action="submitPassword">
|
||||
<translate translate-context="Content/Settings/Button.Label">Change password</translate>
|
||||
<p slot="modal-header"><translate translate-context="Popup/Settings/Title">Change your password?</translate></p>
|
||||
|
@ -178,7 +178,7 @@
|
|||
</td>
|
||||
<td>
|
||||
<dangerous-button
|
||||
class="ui tiny basic red button"
|
||||
class="ui tiny basic danger button"
|
||||
@confirm="revokeApp(app.client_id)">
|
||||
<translate translate-context="*/*/*/Verb">Revoke</translate>
|
||||
<p slot="modal-header" v-translate="{application: app.name}" translate-context="Popup/Settings/Title">Revoke access for application "%{ application }"?</p>
|
||||
|
@ -207,7 +207,7 @@
|
|||
</div>
|
||||
</h2>
|
||||
<p><translate translate-context="Content/Settings/Paragraph">This is the list of applications that you have created.</translate></p>
|
||||
<router-link class="ui basic green button" :to="{name: 'settings.applications.new'}">
|
||||
<router-link class="ui basic success button" :to="{name: 'settings.applications.new'}">
|
||||
<translate translate-context="Content/Settings/Button.Label">Create a new application</translate>
|
||||
</router-link>
|
||||
<table v-if="ownedApps.length > 0" class="ui compact very basic unstackable table">
|
||||
|
@ -233,11 +233,11 @@
|
|||
<human-date :date="app.created" />
|
||||
</td>
|
||||
<td>
|
||||
<router-link class="ui basic tiny green button" :to="{name: 'settings.applications.edit', params: {id: app.client_id}}">
|
||||
<router-link class="ui basic tiny success button" :to="{name: 'settings.applications.edit', params: {id: app.client_id}}">
|
||||
<translate translate-context="Content/*/Button.Label/Verb">Edit</translate>
|
||||
</router-link>
|
||||
<dangerous-button
|
||||
class="ui tiny basic red button"
|
||||
class="ui tiny basic danger button"
|
||||
@confirm="deleteApp(app.client_id)">
|
||||
<translate translate-context="*/*/*/Verb">Delete</translate>
|
||||
<p slot="modal-header" v-translate="{application: app.name}" translate-context="Popup/Settings/Title">Delete application "%{ application }"?</p>
|
||||
|
@ -283,7 +283,7 @@
|
|||
<password-input required v-model="password" />
|
||||
</div>
|
||||
<dangerous-button
|
||||
:class="['ui', {'loading': isDeletingAccount}, {disabled: !password}, 'red', 'button']"
|
||||
:class="['ui', {'loading': isDeletingAccount}, {disabled: !password}, 'danger', 'button']"
|
||||
:action="deleteAccount">
|
||||
<translate translate-context="*/*/Button.Label">Delete my account…</translate>
|
||||
<p slot="modal-header"><translate translate-context="Popup/Settings/Title">Do you want to delete your account?</translate></p>
|
||||
|
@ -534,7 +534,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
</p>
|
||||
</div>
|
||||
<h2><translate translate-context="Content/Login/Title/Verb">Log in to your Funkwhale account</translate></h2>
|
||||
<login-form button-classes="basic green" :show-signup="false"></login-form>
|
||||
<login-form button-classes="basic success" :show-signup="false"></login-form>
|
||||
</div>
|
||||
<form
|
||||
v-else
|
||||
|
@ -93,7 +93,7 @@ export default {
|
|||
props: {
|
||||
defaultInvitation: { type: String, required: false, default: null },
|
||||
next: { type: String, default: "/" },
|
||||
buttonClasses: { type: String, default: "green" },
|
||||
buttonClasses: { type: String, default: "success" },
|
||||
customization: { type: Object, default: null},
|
||||
fetchDescriptionHtml: { type: Boolean, default: false},
|
||||
fetchDescriptionHtml: { type: Boolean, default: false},
|
||||
|
@ -176,7 +176,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
</div>
|
||||
<dangerous-button
|
||||
v-if="token"
|
||||
:class="['ui', {'loading': isLoading}, 'grey', 'button']"
|
||||
:class="['ui', {'loading': isLoading}, 'button']"
|
||||
:action="requestNewToken">
|
||||
<translate translate-context="*/Settings/Button.Label/Verb">Request a new password</translate>
|
||||
<p slot="modal-header"><translate translate-context="Popup/Settings/Title">Request a new Subsonic API password?</translate></p>
|
||||
|
@ -42,12 +42,12 @@
|
|||
</dangerous-button>
|
||||
<button
|
||||
v-else
|
||||
color="grey"
|
||||
color=""
|
||||
:class="['ui', {'loading': isLoading}, 'button']"
|
||||
@click="requestNewToken"><translate translate-context="Content/Settings/Button.Label/Verb">Request a password</translate></button>
|
||||
<dangerous-button
|
||||
v-if="token"
|
||||
:class="['ui', {'loading': isLoading}, 'yellow', 'button']"
|
||||
:class="['ui', {'loading': isLoading}, 'warning', 'button']"
|
||||
:action="disable">
|
||||
<translate translate-context="Content/Settings/Button.Label/Verb">Disable Subsonic access</translate>
|
||||
<p slot="modal-header"><translate translate-context="Popup/Settings/Title">Disable Subsonic API access?</translate></p>
|
||||
|
@ -135,7 +135,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -37,7 +37,3 @@ export default {
|
|||
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<form @submit.stop.prevent :class="['ui', {loading: isLoadingStep1}, 'form']">
|
||||
<form @submit.stop.prevent :class="['ui', {loading: isLoadingStep1}, 'form component-file-upload']">
|
||||
<div v-if="errors.length > 0" class="ui negative message">
|
||||
<div class="header"><translate translate-context="Content/*/Error message.Title">Error while publishing</translate></div>
|
||||
<ul class="list">
|
||||
|
@ -60,7 +60,7 @@
|
|||
<div
|
||||
v-if="file.error"
|
||||
@click.stop.prevent="selectedUploadId = file.response.uuid"
|
||||
class="ui basic red icon label"
|
||||
class="ui basic danger icon label"
|
||||
:title="file.error">
|
||||
<i class="warning sign icon"></i>
|
||||
</div>
|
||||
|
@ -402,9 +402,9 @@ export default {
|
|||
} else {
|
||||
d.icon = "user"
|
||||
if (c.artist.content_category === 'podcast') {
|
||||
d.iconClass = "bordered grey icon"
|
||||
d.iconClass = "bordered icon"
|
||||
} else {
|
||||
d.iconClass = "circular grey icon"
|
||||
d.iconClass = "circular icon"
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<span class="feedback" v-if="isLoading || isDone">
|
||||
<span v-if="isLoading" :class="['ui', 'active', size, 'inline', 'loader']"></span>
|
||||
<i v-if="isDone" :class="['green', size, 'check', 'icon']"></i>
|
||||
<i v-if="isDone" :class="['success', size, 'check', 'icon']"></i>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="table-wrapper">
|
||||
<div class="table-wrapper component-action-table">
|
||||
<table class="ui compact very basic unstackable table">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -30,7 +30,7 @@
|
|||
<div class="field">
|
||||
<dangerous-button
|
||||
v-if="selectAll || currentAction.isDangerous" :class="['ui', {disabled: checked.length === 0}, {'loading': actionLoading}, 'button']"
|
||||
:confirm-color="currentAction.confirmColor || 'green'"
|
||||
:confirm-color="currentAction.confirmColor || 'success'"
|
||||
@confirm="launchAction">
|
||||
<translate translate-context="Content/*/Button.Label/Short, Verb">Go</translate>
|
||||
<p slot="modal-header">
|
||||
|
@ -300,11 +300,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.count.field {
|
||||
font-weight: normal;
|
||||
}
|
||||
.ui.form .inline.fields {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -20,10 +20,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.ui.circular.avatar {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
font-size: 1em !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
</template>
|
||||
</div>
|
||||
<div class="ui bottom attached segment">
|
||||
<span :class="['right', 'floated', {'ui red text': remainingChars < 0}]" v-if="charLimit">
|
||||
<span :class="['right', 'floated', {'ui danger text': remainingChars < 0}]" v-if="charLimit">
|
||||
{{ remainingChars }}
|
||||
</span>
|
||||
<p>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="ui fluid action input">
|
||||
<div class="ui fluid action input component-copy-input">
|
||||
<p class="message" v-if="copied">
|
||||
<translate translate-context="Content/*/Paragraph">Text copied to clipboard!</translate>
|
||||
</p>
|
||||
|
@ -39,14 +39,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.message {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: -3em;
|
||||
padding: 0.3em;
|
||||
box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.3);
|
||||
background-color: white;
|
||||
z-index: 999;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -34,7 +34,7 @@ export default {
|
|||
props: {
|
||||
action: {type: Function, required: false},
|
||||
disabled: {type: Boolean, default: false},
|
||||
confirmColor: {type: String, default: "red", required: false}
|
||||
confirmColor: {type: String, default: "danger", required: false}
|
||||
},
|
||||
components: {
|
||||
Modal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="ui small placeholder segment">
|
||||
<div class="ui small placeholder segment component-placeholder component-empty-state">
|
||||
<div class="ui header">
|
||||
<div class="content">
|
||||
<slot name="title">
|
||||
|
@ -28,13 +28,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ui.small.placeholder.segment {
|
||||
min-height: auto;
|
||||
}
|
||||
.ui.header .content {
|
||||
text-align: center;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<span>
|
||||
<span class="component-user-link">
|
||||
<template v-if="avatar">
|
||||
<img
|
||||
class="ui tiny circular avatar"
|
||||
|
@ -32,9 +32,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.tiny.circular.avatar {
|
||||
width: 1.7em;
|
||||
height: 1.7em;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
translate-context="Content/Home/Placeholder"
|
||||
>No tracks have been added to your favorites yet</translate>
|
||||
</div>
|
||||
<router-link :to="'/library'" class="ui green labeled icon button">
|
||||
<router-link :to="'/library'" class="ui success labeled icon button">
|
||||
<i class="headphones icon"></i>
|
||||
<translate translate-context="Content/*/Verb">Browse the library</translate>
|
||||
</router-link>
|
||||
|
@ -178,7 +178,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -36,7 +36,3 @@ export default {
|
|||
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
<div role="button" class="ui basic cancel button">
|
||||
<translate translate-context="*/*/Button.Label/Verb">Close</translate>
|
||||
</div>
|
||||
<div role="button" @click="showModal = false; $emit('refresh')" class="ui confirm green button" v-if="fetch && fetch.status === 'finished'">
|
||||
<div role="button" @click="showModal = false; $emit('refresh')" class="ui confirm success button" v-if="fetch && fetch.status === 'finished'">
|
||||
<translate translate-context="*/*/Button.Label/Verb">Close and reload page</translate>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
<translate v-else translate-context="*/*/*" :translate-params="{count: totalTracks}" :translate-n="totalTracks" translate-plural="%{ count } tracks">%{ count } track</translate>
|
||||
</template>
|
||||
<div class="ui small hidden divider"></div>
|
||||
<play-button class="orange" :tracks="object.tracks"></play-button>
|
||||
<play-button class="vibrant" :tracks="object.tracks"></play-button>
|
||||
<div class="ui hidden horizontal divider"></div>
|
||||
<album-dropdown
|
||||
:object="object"
|
||||
|
@ -75,7 +75,7 @@
|
|||
</template>
|
||||
<human-duration v-if="totalDuration > 0" :duration="totalDuration"></human-duration>
|
||||
<div class="ui small hidden divider"></div>
|
||||
<play-button class="orange" :tracks="object.tracks"></play-button>
|
||||
<play-button class="vibrant" :tracks="object.tracks"></play-button>
|
||||
<div class="ui horizontal hidden divider"></div>
|
||||
<album-dropdown
|
||||
:object="object"
|
||||
|
|
|
@ -58,7 +58,3 @@ export default {
|
|||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
item-selector=".column"
|
||||
percent-position="true"
|
||||
stagger="0"
|
||||
class="ui stackable three column doubling grid">
|
||||
class="">
|
||||
<div
|
||||
v-if="result.results.length > 0"
|
||||
class="ui app-cards cards">
|
||||
|
@ -67,7 +67,7 @@
|
|||
<router-link
|
||||
v-if="$store.state.auth.authenticated"
|
||||
:to="{name: 'content.index'}"
|
||||
class="ui green button labeled icon">
|
||||
class="ui success button labeled icon">
|
||||
<i class="upload icon"></i>
|
||||
<translate translate-context="Content/*/Verb">
|
||||
Add some music
|
||||
|
@ -223,7 +223,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
</div>
|
||||
<div class="ui buttons">
|
||||
<play-button :is-playable="isPlayable" class="orange" :artist="object">
|
||||
<play-button :is-playable="isPlayable" class="vibrant" :artist="object">
|
||||
<translate translate-context="Content/Artist/Button.Label/Verb">Play all albums</translate>
|
||||
</play-button>
|
||||
</div>
|
||||
|
|
|
@ -95,7 +95,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
<router-link
|
||||
v-if="$store.state.auth.authenticated"
|
||||
:to="{name: 'content.index'}"
|
||||
class="ui green button labeled icon">
|
||||
class="ui success button labeled icon">
|
||||
<i class="upload icon"></i>
|
||||
<translate translate-context="Content/*/Verb">
|
||||
Add some music
|
||||
|
@ -214,24 +214,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="scss">
|
||||
@import "../../style/vendor/media";
|
||||
|
||||
.wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
.ui.cards {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.ui.three.cards .card {
|
||||
width: 100%;
|
||||
}
|
||||
@include media(">tablet") {
|
||||
.ui.three.cards .card {
|
||||
width: 25em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -18,19 +18,19 @@
|
|||
|
||||
<span class="right floated">
|
||||
<span v-if="obj.is_approved && obj.is_applied">
|
||||
<i class="green check icon"></i>
|
||||
<i class="success check icon"></i>
|
||||
<translate translate-context="Content/Library/Card/Short">Approved and applied</translate>
|
||||
</span>
|
||||
<span v-else-if="obj.is_approved">
|
||||
<i class="green check icon"></i>
|
||||
<i class="success check icon"></i>
|
||||
<translate translate-context="Content/*/*/Short">Approved</translate>
|
||||
</span>
|
||||
<span v-else-if="obj.is_approved === null">
|
||||
<i class="yellow hourglass icon"></i>
|
||||
<i class="warning hourglass icon"></i>
|
||||
<translate translate-context="Content/Admin/*/Noun">Pending review</translate>
|
||||
</span>
|
||||
<span v-else-if="obj.is_approved === false">
|
||||
<i class="red x icon"></i>
|
||||
<i class="dangerx icon"></i>
|
||||
<translate translate-context="Content/Library/*/Short">Rejected</translate>
|
||||
</span>
|
||||
</span>
|
||||
|
@ -95,18 +95,18 @@
|
|||
<button
|
||||
v-if="canApprove && obj.is_approved !== true"
|
||||
@click="approve(true)"
|
||||
:class="['ui', {loading: isLoading}, 'green', 'basic', 'button']">
|
||||
:class="['ui', {loading: isLoading}, 'success', 'basic', 'button']">
|
||||
<translate translate-context="Content/*/Button.Label/Verb">Approve</translate>
|
||||
</button>
|
||||
<button
|
||||
v-if="canApprove && obj.is_approved === null"
|
||||
@click="approve(false)"
|
||||
:class="['ui', {loading: isLoading}, 'yellow', 'basic', 'button']">
|
||||
:class="['ui', {loading: isLoading}, 'warning', 'basic', 'button']">
|
||||
<translate translate-context="Content/Library/Button.Label">Reject</translate>
|
||||
</button>
|
||||
<dangerous-button
|
||||
v-if="canDelete"
|
||||
:class="['ui', {loading: isLoading}, 'basic red button']"
|
||||
:class="['ui', {loading: isLoading}, 'basic danger button']"
|
||||
:action="remove">
|
||||
<translate translate-context="*/*/*/Verb">Delete</translate>
|
||||
<p slot="modal-header"><translate translate-context="Popup/Library/Title">Delete this suggestion?</translate></p>
|
||||
|
|
|
@ -123,7 +123,7 @@
|
|||
>
|
||||
<translate translate-context="*/*/Button.Label/Verb">Cancel</translate>
|
||||
</router-link>
|
||||
<button :class="['ui', {'loading': isLoading}, 'right', 'floated', 'green', 'button']" type="submit" :disabled="isLoading || !mutationPayload">
|
||||
<button :class="['ui', {'loading': isLoading}, 'right', 'floated', 'success', 'button']" type="submit" :disabled="isLoading || !mutationPayload">
|
||||
<translate v-if="canEdit" key="1" translate-context="Content/Library/Button.Label/Verb">Submit and apply edit</translate>
|
||||
<translate v-else key="2" translate-context="Content/Library/Button.Label/Verb">Submit suggestion</translate>
|
||||
</button>
|
||||
|
@ -256,8 +256,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.reset.button {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="component-file-upload">
|
||||
<div class="ui top attached tabular menu">
|
||||
<a :class="['item', {active: currentTab === 'summary'}]" @click="currentTab = 'summary'"><translate translate-context="Content/Library/Tab.Title/Short">Summary</translate></a>
|
||||
<a :class="['item', {active: currentTab === 'uploads'}]" @click="currentTab = 'uploads'">
|
||||
|
@ -7,10 +7,10 @@
|
|||
<div v-if="files.length === 0" class="ui label">
|
||||
0
|
||||
</div>
|
||||
<div v-else-if="files.length > uploadedFilesCount + erroredFilesCount" class="ui yellow label">
|
||||
<div v-else-if="files.length > uploadedFilesCount + erroredFilesCount" class="ui warning label">
|
||||
{{ uploadedFilesCount + erroredFilesCount }}/{{ files.length }}
|
||||
</div>
|
||||
<div v-else :class="['ui', {'green': erroredFilesCount === 0}, {'red': erroredFilesCount > 0}, 'label']">
|
||||
<div v-else :class="['ui', {'success': erroredFilesCount === 0}, {'danger': erroredFilesCount > 0}, 'label']">
|
||||
{{ uploadedFilesCount + erroredFilesCount }}/{{ files.length }}
|
||||
</div>
|
||||
</a>
|
||||
|
@ -19,10 +19,10 @@
|
|||
<div v-if="processableFiles === 0" class="ui label">
|
||||
0
|
||||
</div>
|
||||
<div v-else-if="processableFiles > processedFilesCount" class="ui yellow label">
|
||||
<div v-else-if="processableFiles > processedFilesCount" class="ui warning label">
|
||||
{{ processedFilesCount }}/{{ processableFiles }}
|
||||
</div>
|
||||
<div v-else :class="['ui', {'green': uploads.errored === 0}, {'red': uploads.errored > 0}, 'label']">
|
||||
<div v-else :class="['ui', {'success': uploads.errored === 0}, {'danger': uploads.errored > 0}, 'label']">
|
||||
{{ processedFilesCount }}/{{ processableFiles }}
|
||||
</div>
|
||||
</a>
|
||||
|
@ -54,12 +54,12 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="ui green button"><translate translate-context="Content/Library/Button.Label">Proceed</translate></button>
|
||||
<button type="submit" class="ui success button"><translate translate-context="Content/Library/Button.Label">Proceed</translate></button>
|
||||
</form>
|
||||
</div>
|
||||
<div :class="['ui', 'bottom', 'attached', 'segment', {hidden: currentTab != 'uploads'}]">
|
||||
<div :class="['ui', {loading: isLoadingQuota}, 'container']">
|
||||
<div :class="['ui', {red: remainingSpace === 0}, {yellow: remainingSpace > 0 && remainingSpace <= 50}, 'small', 'statistic']">
|
||||
<div :class="['ui', {red: remainingSpace === 0}, {warning: remainingSpace > 0 && remainingSpace <= 50}, 'small', 'statistic']">
|
||||
<div class="label">
|
||||
<translate translate-context="Content/Library/Paragraph">Remaining storage space</translate>
|
||||
</div>
|
||||
|
@ -113,14 +113,14 @@
|
|||
<td>{{ file.size | humanSize }}</td>
|
||||
<td>
|
||||
<span v-if="file.error" class="ui tooltip" :data-tooltip="labels.tooltips[file.error]">
|
||||
<span class="ui red icon label">
|
||||
<span class="ui danger icon label">
|
||||
<i class="question circle outline icon" /> {{ file.error }}
|
||||
</span>
|
||||
</span>
|
||||
<span v-else-if="file.success" class="ui green label">
|
||||
<span v-else-if="file.success" class="ui success label">
|
||||
<translate translate-context="Content/Library/Table" key="1">Uploaded</translate>
|
||||
</span>
|
||||
<span v-else-if="file.active" class="ui yellow label">
|
||||
<span v-else-if="file.active" class="ui warning label">
|
||||
<translate translate-context="Content/Library/Table" key="2">Uploading…</translate>
|
||||
({{ parseInt(file.progress) }}%)
|
||||
</span>
|
||||
|
@ -137,7 +137,7 @@
|
|||
</button>
|
||||
</template>
|
||||
<template v-else-if="!file.success">
|
||||
<button class="ui tiny basic red icon right floated button" @click.prevent="$refs.upload.remove(file)"><i class="delete icon"></i></button>
|
||||
<button class="ui tiny basic danger icon right floated button" @click.prevent="$refs.upload.remove(file)"><i class="delete icon"></i></button>
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -396,16 +396,3 @@ export default {
|
|||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
.file-uploads.ui.button {
|
||||
display: block;
|
||||
padding: 2em 1em;
|
||||
width: 100%;
|
||||
box-shadow: none;
|
||||
border-style: dashed !important;
|
||||
border: 3px solid rgba(50, 50, 50, 0.5);
|
||||
font-size: 1.5em;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -38,7 +38,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -98,7 +98,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="main library pusher">
|
||||
<div class="main pusher page-library">
|
||||
<router-view :key="$router.currentRoute.name"></router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -21,35 +21,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style lang="scss">
|
||||
@import "../../style/vendor/media";
|
||||
|
||||
.library {
|
||||
.ui.segment.head {
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
padding: 0;
|
||||
.segment-content {
|
||||
margin: 0 auto;
|
||||
padding: 2em;
|
||||
@include media(">tablet") {
|
||||
padding: 4em;
|
||||
}
|
||||
}
|
||||
&.with-background {
|
||||
.header {
|
||||
&,
|
||||
.sub {
|
||||
text-shadow: 0 1px 0 rgba(0, 0, 0, 0.8);
|
||||
color: white !important;
|
||||
}
|
||||
}
|
||||
.segment-content {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<h3 class="ui header">
|
||||
<translate translate-context="Content/Radio/Title">User radios</translate>
|
||||
</h3>
|
||||
<router-link class="ui green basic button" to="/library/radios/build" exact>
|
||||
<router-link class="ui success basic button" to="/library/radios/build" exact>
|
||||
<translate translate-context="Content/Radio/Button.Label/Verb">Create your own radio</translate>
|
||||
</router-link>
|
||||
<div class="ui hidden divider"></div>
|
||||
|
@ -71,7 +71,7 @@
|
|||
<router-link
|
||||
v-if="$store.state.auth.authenticated"
|
||||
:to="{name: 'library.radios.build'}"
|
||||
class="ui green button labeled icon">
|
||||
class="ui success button labeled icon">
|
||||
<i class="rss icon"></i>
|
||||
<translate translate-context="Content/*/Verb">
|
||||
Create a radio
|
||||
|
@ -215,7 +215,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<main v-title="labels.title">
|
||||
<section class="ui vertical stripe segment">
|
||||
<h2 class="ui header">
|
||||
<span class="ui circular huge hashtag label">
|
||||
<span class="ui circular huge hashtag label component-label">
|
||||
{{ labels.title }}
|
||||
</span>
|
||||
</h2>
|
||||
|
@ -83,11 +83,3 @@ export default {
|
|||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
.ui.circular.label {
|
||||
padding-left: 1em !important;
|
||||
padding-right: 1em !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -82,11 +82,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.ui.form .field > .selection.dropdown {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</h1>
|
||||
</div>
|
||||
<div class="eight wide right aligned column button-group">
|
||||
<play-button class="orange" :track="track">
|
||||
<play-button class="vibrant" :track="track">
|
||||
<translate translate-context="*/Queue/Button.Label/Short, Verb">Play</translate>
|
||||
</play-button>
|
||||
|
||||
|
|
|
@ -232,11 +232,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="scss">
|
||||
.table.center.aligned {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<label for="public"><translate translate-context="Content/Radio/Checkbox.Label/Verb">Display publicly</translate></label>
|
||||
</div>
|
||||
<div class="ui hidden divider"></div>
|
||||
<button :disabled="!canSave" @click="save" :class="['ui', 'green', {loading: isLoading}, 'button']">
|
||||
<button :disabled="!canSave" @click="save" :class="['ui', 'success', {loading: isLoading}, 'button']">
|
||||
<translate translate-context="Content/*/Button.Label/Verb">Save</translate>
|
||||
</button>
|
||||
<radio-button v-if="id" type="custom" :custom-radio-id="id"></radio-button>
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
<span
|
||||
@click="showCandidadesModal = !showCandidadesModal"
|
||||
v-if="checkResult"
|
||||
:class="['ui', {'green': checkResult.candidates.count > 10}, 'label']">
|
||||
:class="['ui', {'success': checkResult.candidates.count > 10}, 'label']">
|
||||
{{ checkResult.candidates.count }} tracks matching filter
|
||||
</span>
|
||||
<modal v-if="checkResult" :show.sync="showCandidadesModal">
|
||||
|
@ -49,14 +49,14 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<div class="ui basic black deny button">
|
||||
<div class="ui basic deny button">
|
||||
<translate translate-context="*/*/Button.Label/Verb">Cancel</translate>
|
||||
</div>
|
||||
</div>
|
||||
</modal>
|
||||
</td>
|
||||
<td>
|
||||
<button @click="$emit('delete', index)" class="ui basic red button"><translate translate-context="Content/Radio/Button.Label/Verb">Remove</translate></button>
|
||||
<button @click="$emit('delete', index)" class="ui basic danger button"><translate translate-context="Content/Radio/Button.Label/Verb">Remove</translate></button>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
|
|
@ -200,7 +200,7 @@ export default {
|
|||
// confirmationMessage: confirmationMessage,
|
||||
// isDangerous: true,
|
||||
// allowAll: false,
|
||||
// confirmColor: 'red',
|
||||
// confirmColor: 'danger',
|
||||
// },
|
||||
]
|
||||
}
|
||||
|
|
|
@ -194,7 +194,7 @@ export default {
|
|||
confirmationMessage: confirmationMessage,
|
||||
isDangerous: true,
|
||||
allowAll: false,
|
||||
confirmColor: 'red',
|
||||
confirmColor: 'danger',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
|
|
@ -201,7 +201,7 @@ export default {
|
|||
confirmationMessage: confirmationMessage,
|
||||
isDangerous: true,
|
||||
allowAll: false,
|
||||
confirmColor: 'red',
|
||||
confirmColor: 'danger',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
|
|
@ -211,7 +211,7 @@ export default {
|
|||
confirmationMessage: confirmationMessage,
|
||||
isDangerous: true,
|
||||
allowAll: false,
|
||||
confirmColor: 'red',
|
||||
confirmColor: 'danger',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
|
|
@ -185,7 +185,7 @@ export default {
|
|||
confirmationMessage: confirmationMessage,
|
||||
isDangerous: true,
|
||||
allowAll: false,
|
||||
confirmColor: 'red',
|
||||
confirmColor: 'danger',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
|
|
@ -196,7 +196,7 @@ export default {
|
|||
confirmationMessage: confirmationMessage,
|
||||
isDangerous: true,
|
||||
allowAll: false,
|
||||
confirmColor: 'red',
|
||||
confirmColor: 'danger',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
|
|
@ -261,7 +261,7 @@ export default {
|
|||
confirmationMessage: confirmationMessage,
|
||||
isDangerous: true,
|
||||
allowAll: false,
|
||||
confirmColor: 'red',
|
||||
confirmColor: 'danger',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
<td>
|
||||
<router-link :to="{name: 'manage.moderation.domains.detail', params: {id: scope.obj.name }}">
|
||||
{{ scope.obj.name }}
|
||||
<i v-if="allowListEnabled && scope.obj.allowed" class="green check icon" :title="labels.allowListTitle"></i>
|
||||
<i v-if="allowListEnabled && scope.obj.allowed" class="success check icon" :title="labels.allowListTitle"></i>
|
||||
</router-link>
|
||||
</td>
|
||||
<td>
|
||||
|
|
|
@ -67,6 +67,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -54,11 +54,11 @@
|
|||
<button @click.prevent="$emit('cancel')" class="ui basic left floated button">
|
||||
<translate translate-context="*/*/Button.Label/Verb">Cancel</translate>
|
||||
</button>
|
||||
<button :class="['ui', 'right', 'floated', 'green', {'disabled loading': isLoading}, 'button']" :disabled="isLoading">
|
||||
<button :class="['ui', 'right', 'floated', 'success', {'disabled loading': isLoading}, 'button']" :disabled="isLoading">
|
||||
<translate translate-context="Content/Moderation/Card.Button.Label/Verb" v-if="object" key="1">Update</translate>
|
||||
<translate translate-context="Content/Moderation/Card.Button.Label/Verb" v-else key="2">Create</translate>
|
||||
</button>
|
||||
<dangerous-button v-if="object" class="ui right floated basic red button" @confirm="remove">
|
||||
<dangerous-button v-if="object" class="ui right floated basic danger button" @confirm="remove">
|
||||
<translate translate-context="*/*/*/Verb">Delete</translate>
|
||||
<p slot="modal-header">
|
||||
<translate translate-context="Popup/Moderation/Title">Delete this moderation rule?</translate>
|
||||
|
@ -200,15 +200,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ui.placeholder.segment .field,
|
||||
.ui.placeholder.segment textarea,
|
||||
.ui.placeholder.segment > .ui.input,
|
||||
.ui.placeholder.segment .button {
|
||||
max-width: 100%;
|
||||
}
|
||||
.segment .right.floated.button {
|
||||
margin-left: 1em;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
</div>
|
||||
<div class="meta">
|
||||
<dangerous-button
|
||||
:class="['ui', {loading: isLoading}, 'basic borderless mini grey button']"
|
||||
:class="['ui', {loading: isLoading}, 'basic borderless mini button']"
|
||||
@confirm="remove(note)">
|
||||
<i class="trash icon"></i>
|
||||
<translate translate-context="*/*/*/Verb">Delete</translate>
|
||||
|
|
|
@ -59,12 +59,12 @@
|
|||
</td>
|
||||
<td v-if="obj.is_handled">
|
||||
<span v-if="obj.is_handled">
|
||||
<i class="green check icon"></i>
|
||||
<i class="success check icon"></i>
|
||||
<translate translate-context="Content/*/*/Short">Resolved</translate>
|
||||
</span>
|
||||
</td>
|
||||
<td v-else>
|
||||
<i class="red x icon"></i>
|
||||
<i class="dangerx icon"></i>
|
||||
<translate translate-context="Content/*/*/Short">Unresolved</translate>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -215,14 +215,14 @@
|
|||
v-if="obj.is_handled === false"
|
||||
@click="resolve(true)"
|
||||
:class="['ui', {loading: isLoading}, 'button']">
|
||||
<i class="green check icon"></i>
|
||||
<i class="success check icon"></i>
|
||||
<translate translate-context="Content/*/Button.Label/Verb">Resolve</translate>
|
||||
</button>
|
||||
<button
|
||||
v-if="obj.is_handled === true"
|
||||
@click="resolve(false)"
|
||||
:class="['ui', {loading: isLoading}, 'button']">
|
||||
<i class="yellow redo icon"></i>
|
||||
<i class="warning redo icon"></i>
|
||||
<translate translate-context="Content/*/Button.Label">Unresolve</translate>
|
||||
</button>
|
||||
<template v-for="action in actions">
|
||||
|
@ -357,7 +357,7 @@ export default {
|
|||
modalContent: this.$pgettext('Content/Moderation/Popup,Paragraph', 'This will delete the object associated with this report and mark the report as resolved. The deletion is irreversible.'),
|
||||
modalConfirmLabel: this.$pgettext('*/*/*/Verb', 'Delete'),
|
||||
icon: 'x',
|
||||
iconColor: 'red',
|
||||
iconColor: 'danger',
|
||||
show: (obj) => { return !!obj.target },
|
||||
dangerous: true,
|
||||
handler: () => {
|
||||
|
|
|
@ -41,15 +41,15 @@
|
|||
</td>
|
||||
<td>
|
||||
<template v-if="obj.status === 'pending'">
|
||||
<i class="yellow hourglass icon"></i>
|
||||
<i class="warning hourglass icon"></i>
|
||||
<translate translate-context="Content/Library/*/Short">Pending</translate>
|
||||
</template>
|
||||
<template v-else-if="obj.status === 'refused'">
|
||||
<i class="red x icon"></i>
|
||||
<i class="dangerx icon"></i>
|
||||
<translate translate-context="Content/*/*/Short">Refused</translate>
|
||||
</template>
|
||||
<template v-else-if="obj.status === 'approved'">
|
||||
<i class="green check icon"></i>
|
||||
<i class="success check icon"></i>
|
||||
<translate translate-context="Content/*/*/Short">Approved</translate>
|
||||
</template>
|
||||
</td>
|
||||
|
@ -118,14 +118,14 @@
|
|||
v-if="obj.status === 'pending' || obj.status === 'refused'"
|
||||
@click="approve(true)"
|
||||
:class="['ui', {loading: isLoading}, 'button']">
|
||||
<i class="green check icon"></i>
|
||||
<i class="success check icon"></i>
|
||||
<translate translate-context="Content/*/Button.Label/Verb">Approve</translate>
|
||||
</button>
|
||||
<button
|
||||
v-if="obj.status === 'pending'"
|
||||
@click="approve(false)"
|
||||
:class="['ui', {loading: isLoading}, 'button']">
|
||||
<i class="red x icon"></i>
|
||||
<i class="dangerx icon"></i>
|
||||
<translate translate-context="Content/*/Button.Label">Refuse</translate>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -82,6 +82,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -47,8 +47,8 @@
|
|||
<router-link :to="{name: 'manage.users.users.detail', params: {id: scope.obj.id }}">{{ scope.obj.owner.username }}</router-link>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="scope.obj.users.length > 0" class="ui green basic label"><translate translate-context="Content/Admin/Table">Used</translate></span>
|
||||
<span v-else-if="moment().isAfter(scope.obj.expiration_date)" class="ui red basic label"><translate translate-context="Content/Admin/Table">Expired</translate></span>
|
||||
<span v-if="scope.obj.users.length > 0" class="ui success basic label"><translate translate-context="Content/Admin/Table">Used</translate></span>
|
||||
<span v-else-if="moment().isAfter(scope.obj.expiration_date)" class="ui danger basic label"><translate translate-context="Content/Admin/Table">Expired</translate></span>
|
||||
<span v-else class="ui basic label"><translate translate-context="Content/Admin/Table">Not used</translate></span>
|
||||
</td>
|
||||
<td>
|
||||
|
|
|
@ -52,8 +52,8 @@
|
|||
<span>{{ scope.obj.email }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="scope.obj.is_active" class="ui basic green label"><translate translate-context="Content/Admin/Table">Active</translate></span>
|
||||
<span v-else class="ui basic grey label"><translate translate-context="Content/Admin/Table">Inactive</translate></span>
|
||||
<span v-if="scope.obj.is_active" class="ui basic success label"><translate translate-context="Content/Admin/Table">Active</translate></span>
|
||||
<span v-else class="ui basic label"><translate translate-context="Content/Admin/Table">Inactive</translate></span>
|
||||
</td>
|
||||
<td>
|
||||
<human-date :date="scope.obj.date_joined"></human-date>
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
</div>
|
||||
<div class="actions">
|
||||
<div class="ui basic cancel button"><translate translate-context="*/*/Button.Label/Verb">Cancel</translate></div>
|
||||
<div :class="['ui', 'green', {loading: isLoading}, 'button']" @click="hide"><translate translate-context="Popup/*/Button.Label">Hide content</translate></div>
|
||||
<div :class="['ui', 'success', {loading: isLoading}, 'button']" @click="hide"><translate translate-context="Popup/*/Button.Label">Hide content</translate></div>
|
||||
</div>
|
||||
</modal>
|
||||
</template>
|
||||
|
@ -102,7 +102,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
<div class="ui basic cancel button"><translate translate-context="*/*/Button.Label/Verb">Cancel</translate></div>
|
||||
<button
|
||||
v-if="canSubmit"
|
||||
:class="['ui', 'green', {loading: isLoading}, 'button']"
|
||||
:class="['ui', 'success', {loading: isLoading}, 'button']"
|
||||
type="submit" form="report-form">
|
||||
<translate translate-context="Popup/*/Button.Label">Submit report</translate>
|
||||
</button>
|
||||
|
@ -204,7 +204,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
</td>
|
||||
<td><human-date :date="item.activity.creation_date" /></td>
|
||||
<td class="read collapsing">
|
||||
<span @click="markRead(false)" v-if="item.is_read" :title="labels.markUnread">
|
||||
<span @click="markRead(false)" role="button" v-if="item.is_read" :title="labels.markUnread">
|
||||
<i class="redo icon" />
|
||||
</span>
|
||||
<span @click="markRead(true)" v-else :title="labels.markRead">
|
||||
<span @click="markRead(true)" role="button" v-else :title="labels.markRead">
|
||||
<i class="check icon" />
|
||||
</span>
|
||||
</td>
|
||||
|
@ -68,13 +68,13 @@ export default {
|
|||
if (a.related_object.approved === null) {
|
||||
message = this.labels.libraryPendingFollowMessage
|
||||
acceptFollow = {
|
||||
buttonClass: 'green',
|
||||
buttonClass: 'success',
|
||||
icon: 'check',
|
||||
label: this.$pgettext('Content/*/Button.Label/Verb', 'Approve'),
|
||||
handler: () => { self.approveLibraryFollow(a.related_object) }
|
||||
},
|
||||
rejectFollow = {
|
||||
buttonClass: 'red',
|
||||
buttonClass: 'danger',
|
||||
icon: 'x',
|
||||
label: this.$pgettext('Content/*/Button.Label/Verb', 'Reject'),
|
||||
handler: () => { self.rejectLibraryFollow(a.related_object) }
|
||||
|
@ -146,8 +146,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.read > span {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
@click="$router.push({name: 'library.playlists.detail', params: {id: playlist.id }})"
|
||||
:class="['ui', 'head-image', 'squares']">
|
||||
<img v-lazy="url" v-for="(url, idx) in images" :key="idx" />
|
||||
<play-button :icon-only="true" :is-playable="playlist.is_playable" :button-classes="['ui', 'circular', 'large', 'orange', 'icon', 'button']" :playlist="playlist"></play-button>
|
||||
<play-button :icon-only="true" :is-playable="playlist.is_playable" :button-classes="['ui', 'circular', 'large', 'vibrant', 'icon', 'button']" :playlist="playlist"></play-button>
|
||||
</div>
|
||||
<div class="content">
|
||||
<strong>
|
||||
|
@ -18,7 +18,7 @@
|
|||
</div>
|
||||
<div class="extra content">
|
||||
<translate translate-context="*/*/*" :translate-params="{count: playlist.tracks_count}" :translate-n="playlist.tracks_count" translate-plural="%{ count } tracks">%{ count } track</translate>
|
||||
<play-button class="right floated basic icon" :dropdown-only="true" :is-playable="playlist.is_playable" :dropdown-icon-classes="['ellipsis', 'horizontal', 'large', 'grey']" :playlist="playlist"></play-button>
|
||||
<play-button class="right floated basic icon" :dropdown-only="true" :is-playable="playlist.is_playable" :dropdown-icon-classes="['ellipsis', 'horizontal', 'large really discrete']" :playlist="playlist"></play-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -21,7 +21,3 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue