New theming system

plugins-v3
Agate 2020-05-15 14:12:36 +02:00
rodzic c505f6ff9b
commit cd422832dd
196 zmienionych plików z 3355 dodań i 3482 usunięć

Wyświetl plik

@ -108,7 +108,7 @@ flake8:
variables:
GIT_STRATEGY: fetch
before_script:
- pip install flake8
- pip install 'flake8<3.7'
script:
- flake8 -v api
cache:

Wyświetl plik

@ -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
^^^^^^^^^^^^^

Wyświetl plik

@ -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;
}

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 8.2 KiB

Wyświetl plik

@ -1 +0,0 @@
/* Project specific Javascript goes here. */

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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",

Wyświetl plik

@ -30,7 +30,7 @@
#orange-square {
width: 56px;
height: 56px;
background-color: #f2711c
background-color: #f2711c;
}
#fake-content {
height: 100vh;

Wyświetl plik

@ -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)

Wyświetl plik

@ -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

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -36,7 +36,3 @@ export default {
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Wyświetl plik

@ -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>

Wyświetl plik

@ -1,9 +1,9 @@
<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">
<div class="ui six wide column current-track">
<div class="ui six wide column current-track">
<div class="ui basic segment" id="player">
<template v-if="currentTrack">
<img class="ui image" v-if="currentTrack.album && currentTrack.album.cover && currentTrack.album.cover.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.album.cover.square_crop)">
@ -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>

Wyświetl plik

@ -142,6 +142,3 @@ export default {
},
}
</script>
<style scoped>
</style>

Wyświetl plik

@ -157,7 +157,3 @@ export default {
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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">

Wyświetl plik

@ -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) {

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -37,7 +37,3 @@ export default {
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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">&infin;</span>
<span class="ui circular tiny vibrant label">&infin;</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>

Wyświetl plik

@ -98,7 +98,3 @@ export default {
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Wyświetl plik

@ -236,7 +236,3 @@ export default {
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -23,7 +23,3 @@ export default {
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -37,7 +37,3 @@ export default {
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Wyświetl plik

@ -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"
}
}

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -20,10 +20,3 @@ export default {
}
}
</script>
<style lang="scss">
.ui.circular.avatar {
width: 28px;
height: 28px;
font-size: 1em !important;
}
</style>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -36,7 +36,3 @@ export default {
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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"

Wyświetl plik

@ -58,7 +58,3 @@ export default {
},
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
</style>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -95,7 +95,3 @@ export default {
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -38,7 +38,3 @@ export default {
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Wyświetl plik

@ -98,7 +98,3 @@ export default {
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -82,11 +82,3 @@ export default {
}
}
</script>
<style scoped>
.ui.form .field > .selection.dropdown {
min-width: 200px;
}
</style>

Wyświetl plik

@ -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>
&nbsp;

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -200,7 +200,7 @@ export default {
// confirmationMessage: confirmationMessage,
// isDangerous: true,
// allowAll: false,
// confirmColor: 'red',
// confirmColor: 'danger',
// },
]
}

Wyświetl plik

@ -194,7 +194,7 @@ export default {
confirmationMessage: confirmationMessage,
isDangerous: true,
allowAll: false,
confirmColor: 'red',
confirmColor: 'danger',
},
]
}

Wyświetl plik

@ -201,7 +201,7 @@ export default {
confirmationMessage: confirmationMessage,
isDangerous: true,
allowAll: false,
confirmColor: 'red',
confirmColor: 'danger',
},
]
}

Wyświetl plik

@ -211,7 +211,7 @@ export default {
confirmationMessage: confirmationMessage,
isDangerous: true,
allowAll: false,
confirmColor: 'red',
confirmColor: 'danger',
},
]
}

Wyświetl plik

@ -185,7 +185,7 @@ export default {
confirmationMessage: confirmationMessage,
isDangerous: true,
allowAll: false,
confirmColor: 'red',
confirmColor: 'danger',
},
]
}

Wyświetl plik

@ -196,7 +196,7 @@ export default {
confirmationMessage: confirmationMessage,
isDangerous: true,
allowAll: false,
confirmColor: 'red',
confirmColor: 'danger',
},
]
}

Wyświetl plik

@ -261,7 +261,7 @@ export default {
confirmationMessage: confirmationMessage,
isDangerous: true,
allowAll: false,
confirmColor: 'red',
confirmColor: 'danger',
},
]
}

Wyświetl plik

@ -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>

Wyświetl plik

@ -67,6 +67,3 @@ export default {
}
}
</script>
<style scoped>
</style>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>&nbsp;
<i class="success check icon"></i>&nbsp;
<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>&nbsp;
<i class="warning redo icon"></i>&nbsp;
<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: () => {

Wyświetl plik

@ -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>&nbsp;
<i class="success check icon"></i>&nbsp;
<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>&nbsp;
<i class="dangerx icon"></i>&nbsp;
<translate translate-context="Content/*/Button.Label">Refuse</translate>
</button>
</div>

Wyświetl plik

@ -82,6 +82,3 @@ export default {
}
}
</script>
<style scoped>
</style>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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