summaryrefslogtreecommitdiffhomepage
path: root/themes/luci-theme-openwrt-2020/htdocs
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2020-03-23 22:31:50 +0100
committerJo-Philipp Wich <jo@mein.io>2020-03-26 09:54:40 +0100
commit63b5f63a420a4f096dda4e67bf811ba2d1e842df (patch)
tree31ad354f556ce598f5f2a0f0484f2502e722eac4 /themes/luci-theme-openwrt-2020/htdocs
parent0fb2f8f1d1d8748b56522cc81cf68d5aa04b9f50 (diff)
themes: add new theme OpenWrt 2020
Introduce a new theme modelled after the logo guidelines published in https://openwrt.org/_media/docs/guide-graphic-designer/openwrt-logo-usage-guidelines.pdf Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'themes/luci-theme-openwrt-2020/htdocs')
-rw-r--r--themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/GalanoGrotesqueW00-Regular.woff2bin0 -> 29004 bytes
-rw-r--r--themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/cascade.css1816
-rw-r--r--themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/favicon.pngbin0 -> 2184 bytes
-rw-r--r--themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/logo.svg7
-rw-r--r--themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/spinner.svg12
5 files changed, 1835 insertions, 0 deletions
diff --git a/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/GalanoGrotesqueW00-Regular.woff2 b/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/GalanoGrotesqueW00-Regular.woff2
new file mode 100644
index 0000000000..950ac98cc5
--- /dev/null
+++ b/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/GalanoGrotesqueW00-Regular.woff2
Binary files differ
diff --git a/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/cascade.css b/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/cascade.css
new file mode 100644
index 0000000000..eb25f5975b
--- /dev/null
+++ b/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/cascade.css
@@ -0,0 +1,1816 @@
+:root {
+ --main-bright-color: #00A3E1;
+ --main-dark-color: #002B49;
+ --secondary-bright-color: #FFFFFF;
+ --secondary-dark-color: #212322;
+ --danger-color: #CC1111;
+ --warning-color: #CC8800;
+ --regular-font: "GalanoGrotesqueW00-Regular";
+ --base-font-size: 16px;
+}
+
+@font-face {
+ font-family: "GalanoGrotesqueW00-Regular";
+ src: url("GalanoGrotesqueW00-Regular.woff2") format("woff2");
+}
+
+/*
+ * resets and base style
+ */
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+ text-decoration: none;
+ list-style: none;
+ color: inherit;
+ font-family: var(--regular-font), "sans-serif";
+ border: none;
+ font-size: 100%;
+ background: none;
+ outline: none;
+ -webkit-appearance: none;
+ -webkit-text-size-adjust: none;
+}
+
+html {
+ height: 100%;
+ width: 100%;
+ max-width: 1366px;
+ margin: 0 auto;
+ background: #fff linear-gradient(90deg, rgba(0, 0, 0, .8), rgba(0, 0, 0 ,.5), rgba(0, 0, 0, .8));
+}
+
+body {
+ background: var(--secondary-bright-color);
+ color: var(--secondary-dark-color);
+ font-size: var(--base-font-size);
+ cursor: default;
+ display: inline-flex;
+ flex-direction: column;
+ min-height: 100%;
+ min-width: 100%;
+}
+
+/*
+ * scaffholding
+ */
+
+#menubar {
+ background: var(--main-bright-color) url(logo.svg) 10px center/50px 50px no-repeat;
+ padding: 0 1em 0 70px;
+ min-height: 70px;
+ display: flex;
+ align-items: center;
+ color: var(--secondary-bright-color);
+ flex: 0;
+ width: 100%;
+ box-shadow: inset 0 0 1px var(--main-dark-color);
+}
+
+#menubar > * {
+ flex: 1 1 auto;
+}
+
+#menubar .hostname {
+ font-weight: bold;
+ font-size: 2em;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+#menubar .distversion {
+ flex: 3;
+}
+
+#menubar .indicators {
+ flex: 1 1 25%;
+ text-align: right;
+}
+
+#menubar .indicators > * {
+ background: var(--secondary-bright-color);
+ color: var(--main-bright-color);
+ display: inline-block;
+ font-size: .85em;
+ line-height: 1.5em;
+ padding: 0 .5em;
+ margin: .125em;
+ border-radius: 1em;
+ cursor: pointer;
+ white-space: nowrap;
+}
+
+#menubar .indicators > * > #xhr_poll_status_off {
+ background: var(--main-bright-color);
+ color: var(--secondary-bright-color);
+ border-radius: 1em;
+ margin: 0 -.5em;
+ display: block;
+ padding: 0 .5em;
+ border: 2px solid var(--secondary-bright-color);
+ line-height: calc(1.5em - 4px);
+}
+
+#menubar h2,
+.skiplink {
+ display: none;
+}
+
+#maincontainer {
+ flex-direction: row;
+ display: inline-flex;
+ flex: 1 0 auto;
+}
+
+#mainmenu {
+ flex: 1 1 200px;
+ background: var(--main-dark-color);
+ color: var(--main-bright-color);
+ padding: 1em;
+}
+
+#mainmenu > div {
+ position: sticky;
+ top: 1em;
+}
+
+#mainmenu ul {
+ padding: 0;
+ margin: 0 0 .5em .5em;
+ line-height: 1.5em;
+}
+
+#mainmenu ul > li {
+ list-style: none;
+}
+
+#mainmenu li > ul {
+ max-height: 0;
+ overflow: hidden;
+ transition: max-height .1s ease-in-out;
+}
+
+#mainmenu li.selected > a {
+ color: var(--secondary-bright-color);
+}
+
+#mainmenu ul:not(.active) > li.selected > ul,
+#mainmenu li.active > ul {
+ max-height: 3000px;
+ transition: max-height 1s ease-in-out;
+}
+
+#mainmenu .l1 > li > a {
+ font-weight: bold;
+ font-size: 1.05em;
+}
+
+#maincontent {
+ flex: 10;
+ padding: 1em 1em 0 1em;
+}
+
+body > .luci {
+ flex: 0;
+ font-size: .7em;
+ padding: .25em;
+ text-align: right;
+ background: var(--main-bright-color);
+ color: var(--secondary-bright-color);
+ margin: 0;
+}
+
+/*
+ * modal
+ */
+
+body.modal-overlay-active {
+ overflow: hidden;
+}
+
+body.modal-overlay-active #modal_overlay {
+ left: 0;
+ right: 0;
+ opacity: 1;
+}
+
+#modal_overlay {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: -10000px;
+ right: 10000px;
+ background: rgba(0, 0, 0, 0.7);
+ z-index: 10000;
+ overflow-y: scroll;
+ -webkit-overflow-scrolling: touch;
+ transition: opacity .125s ease-in;
+ opacity: 0;
+}
+
+#modal_overlay > .modal {
+ max-width: 80%;
+ margin: 10% auto 25% auto;
+ background: var(--secondary-bright-color);
+ box-shadow: 0 0 3px 1px var(--main-bright-color);
+ padding: .5em;
+ border-radius: .25em;
+}
+
+.modal > h4:first-child {
+ padding: .5rem;
+ margin: -.5rem -.5rem .5rem -.5rem;
+ background: var(--main-bright-color);
+ color: var(--secondary-bright-color);
+ border-radius: .25rem .25rem 0 0;
+}
+
+.modal > *:first-child:last-child {
+ margin: .5em 0 !important;
+}
+
+.modal .cbi-section > legend:first-child { font-size: 120%; }
+
+
+/*
+ * table layout
+ */
+
+.table {
+ display: table;
+ width: 100%;
+ margin: 0 0 1rem 0;
+ position: relative;
+}
+
+.tr {
+ display: table-row;
+}
+
+.tr.cbi-section-table-titles[data-title]::before {
+ font-weight: bold;
+ border-top: none;
+}
+
+.tr[data-title]::before {
+ content: attr(data-title);
+ display: table-cell;
+ border-top: 1px solid var(--main-dark-color);
+ padding: .5em;
+}
+
+.th {
+ font-weight: bold;
+ display: table-cell;
+ padding: .5em;
+ /* word-break: break-word; */
+}
+
+.cbi-section-table-descr .th {
+ opacity: .8;
+ font-size: 90%;
+ font-weight: normal;
+}
+
+.td {
+ display: table-cell;
+ border-top: 1px solid var(--main-dark-color);
+ padding: .5em;
+ vertical-align: middle;
+}
+
+.td input[type="text"],
+.td input[type="password"],
+.td select,
+.td .cbi-dropdown:not(.btn):not(.cbi-button),
+.td .cbi-dynlist {
+ min-width: auto;
+ width: 100%;
+}
+
+.tr.drag-over-above {
+ box-shadow: 0 -6px 6px var(--main-bright-color);
+}
+
+.tr.drag-over-below {
+ box-shadow: 0 6px 6px var(--main-bright-color);
+}
+
+.tr.placeholder {
+ height: 4em;
+ position: relative;
+}
+
+.tr.placeholder > .td {
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ text-align: center;
+ line-height: 3em;
+ font-size: 90%;
+ opacity: .8;
+}
+
+/*
+ * view specific table invariants
+ */
+
+ #cbi-wireless-wifi-device .ifacebadge {
+ flex-direction: column;
+ justify-content: space-around;
+ }
+
+.assoclist .td,
+[data-page="admin-status-overview"] .td {
+ font-size: .9rem;
+ vertical-align: middle;
+}
+
+.assoclist .td:nth-of-type(3) > span {
+ display: block;
+ max-width: 270px;
+ font-size: .8rem;
+}
+
+.assoclist .td:nth-of-type(5) > span {
+ font-size: .8rem;
+}
+
+.assoclist .td > .ifacebadge {
+ flex-wrap: wrap;
+ justify-content: space-around;
+ max-width: 120px;
+ padding: .2em;
+}
+
+.assoclist .td > .ifacebadge::after {
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.assoclist .td > .ifacebadge > img {
+ margin: 0 25px;
+}
+
+.assoclist .td > .ifacebadge[data-ssid][data-ifname] > span {
+ display: none;
+}
+
+.assoclist .td > .ifacebadge[data-ssid][data-ifname]::after {
+ content: attr(data-ssid) " (" attr(data-ifname) ")";
+}
+
+[data-page="admin-status-overview"] .td:nth-of-type(3) {
+ min-width: 100px;
+}
+
+[data-page="admin-network-firewall"] .table > .tr > *:nth-child(1) {
+ flex: 1 1 30%;
+}
+
+[data-page="admin-network-wireless"] .cbi-section-actions > div {
+ display: flex;
+}
+
+[data-page="admin-network-wireless"] .cbi-section-actions > div > * {
+ flex: 1;
+}
+
+[data-page="admin-status-processes"] .table .td:nth-of-type(3),
+[data-tab="leases"] .table .td[data-name="duid"] {
+ word-break: break-word;
+}
+
+/*
+ * uci changelog
+ */
+
+.uci-change-list {
+ font-size: 90%;
+ white-space: pre;
+ overflow: hidden;
+}
+
+.uci-change-list del,
+.uci-change-list ins,
+.uci-change-list var,
+.uci-change-legend-label del,
+.uci-change-legend-label ins,
+.uci-change-legend-label var {
+ text-decoration: none;
+ font-family: monospace;
+ font-style: normal;
+ border: 1px solid #ccc;
+ background: #eee;
+ padding: 2px;
+ display: block;
+ line-height: 15px;
+ margin-bottom: 1px;
+}
+
+.uci-change-list h5 {
+ margin: .5em 0 .25em 0;
+}
+
+.uci-change-list ins,
+.uci-change-legend-label ins {
+ border-color: #0f0;
+ background: #cfc;
+}
+
+.uci-change-list del,
+.uci-change-legend-label del {
+ border-color: #f00;
+ background: #fcc;
+}
+
+.uci-change-list var,
+.uci-change-legend-label var {
+ border-color: #ccc;
+ background: #eee;
+}
+
+.uci-change-list var ins,
+.uci-change-list var del {
+ display: inline-block;
+ border: none;
+ width: 100%;
+ padding: 0;
+}
+
+.uci-change-legend {
+ margin: .5em 0 0 0;
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.uci-change-legend-label {
+ flex: 1 1 10em;
+ white-space: nowrap;
+}
+
+.uci-change-legend-label > ins,
+.uci-change-legend-label > del,
+.uci-change-legend-label > var {
+ float: left;
+ margin-right: 4px;
+ width: 16px;
+ height: 16px;
+ display: block;
+ position: relative;
+}
+
+.uci-change-legend-label var ins,
+.uci-change-legend-label var del {
+ border: none;
+ position: absolute;
+ top: 2px;
+ left: 2px;
+ right: 2px;
+ bottom: 2px;
+}
+
+/*
+ * alignment helpers
+ */
+
+.left {
+ text-align: left !important;
+}
+
+.right {
+ text-align: right !important;
+}
+
+.center {
+ text-align: center !important;
+}
+
+.top {
+ vertical-align: top !important;
+}
+
+.bottom {
+ vertical-align: bottom !important;
+}
+
+.middle {
+ vertical-align: middle !important;
+}
+
+.nowrap {
+ white-space: nowrap !important;
+}
+
+.hidden {
+ display: none !important;
+}
+
+/*
+ * legacy hacks
+ */
+
+[width="33%"] {
+ width: 33%;
+ max-width: 33%;
+}
+
+[width="50%"] {
+ width: 50%;
+ max-width: 50%;
+}
+
+[data-name="_freq"] select {
+ min-width: auto;
+}
+
+.cbi-value-field > div:first-child + br {
+ display: none;
+}
+
+/*
+ * typography
+ */
+
+h1, h2, h3, h4, h5, h6,
+.cbi-section > legend:first-child {
+ font-weight: bold;
+ margin: 0 0 1rem 0;
+}
+
+strong, b {
+ font-weight: bold;
+}
+
+h1 { font-size: 160%; }
+h2 { font-size: 150%; }
+h3 { font-size: 140%; }
+h4 { font-size: 130%; }
+h5 { font-size: 120%; }
+h6 { font-size: 110%; }
+
+.cbi-section > legend:first-child { font-size: 140%; }
+
+p, ul {
+ margin: 0 0 1em 0;
+}
+
+var {
+ color: var(--main-dark-color);
+ font-weight: bold;
+}
+
+code {
+ font-family: monospace;
+ color: var(--main-dark-color);
+}
+
+pre {
+ font-family: monospace;
+ margin: 0 0 1em 0;
+ font-size: .9rem;
+ box-shadow: inset 0 0 2px var(--main-dark-color);
+ padding: .25rem;
+ overflow: auto;
+}
+
+big {
+ font-size: 110%;
+}
+
+small {
+ font-size: 95%;
+}
+
+ul {
+ padding: 0 0 0 1.5em;
+}
+
+ul > li {
+ list-style: disc;
+}
+
+/*
+ * widgets
+ */
+
+.ifacebox, .ifacebadge, .zonebadge {
+ display: inline-flex;
+ line-height: 1.8em;
+ padding: 0 .25em;
+ margin: .25em;
+ box-shadow: 0px 0px 2px var(--main-dark-color);
+ font-size: .9em;
+ border-radius: .5em;
+ overflow: hidden;
+ font-size: .8rem;
+ vertical-align: text-top;
+ background: var(--secondary-bright-color);
+ align-items: center;
+ color: var(--secondary-dark-color);
+ vertical-align: middle;
+}
+
+.zonebadge > .ifacebadge {
+ margin: .125em -.125em .125em .35em;
+}
+
+.zonebadge > .ifacebadge > img
+{
+ margin: .125em 0 .125em .25em;
+}
+
+.ifacebox {
+ display: inline-flex;
+ flex-direction: column;
+ padding: 0;
+ text-align: center;
+ width: 100%;
+ max-width: 100px;
+}
+
+.ifacebox-head {
+ background: var(--main-bright-color);
+ width: 100%;
+}
+
+.ifacebox-body {
+ text-align: center;
+ padding: .3em .25em .25em .25em;
+ white-space: nowrap;
+}
+
+.ifacebadge {
+ display: inline-flex;
+ align-items: center;
+}
+
+.ifacebadge.large {
+ line-height: 1.3em;
+}
+
+.ifacebadge > img {
+ vertical-align: text-bottom;
+ margin: .25em;
+ height: 16px;
+}
+
+.ifacebadge > * {
+ margin-left: .25em;
+}
+
+.network-status-table {
+ display: inline-flex;
+ flex-wrap: wrap;
+ width: 100%;
+ margin: 0 -.2em 1em -.2em;
+}
+
+.network-status-table > .ifacebox {
+ max-width: none;
+ flex: 1 1 45%;
+ margin: .25em;
+ min-width: 250px;
+}
+
+.network-status-table > .ifacebox .ifacebadge {
+ font-size: 100%;
+ max-width: none;
+ flex: 1 1 45%;
+ margin: .2em;
+}
+
+.network-status-table .ifacebox-body > div {
+ display: flex;
+ flex-wrap: wrap;
+ margin: .3em -.1em -.1em -.1em;
+}
+
+.cbi-tooltip-container {
+ cursor: help;
+}
+
+.cbi-tooltip {
+ position: absolute;
+ z-index: 10000;
+ left: -10000px;
+ box-shadow: 0 0 2px rgba(0, 0, 0, .7);
+ border-radius: 3px;
+ background: var(--secondary-bright-color);
+ white-space: pre;
+ padding: 2px 5px;
+ opacity: 0;
+ transition: opacity .25s ease-in;
+ font-size: .8rem;
+}
+
+.cbi-tooltip.error {
+ color: var(--danger-color);
+}
+
+.cbi-tooltip-container:hover .cbi-tooltip:not(:empty) {
+ left: auto;
+ opacity: 1;
+ transition: opacity .25s ease-in;
+}
+
+.zone-forwards {
+ display: flex;
+ align-items: center;
+}
+
+.cbi-progressbar {
+ border-radius: .25em;
+ position: relative;
+ min-width: 20rem;
+ height: 1.5em;
+ box-shadow: 0 0 2px var(--main-dark-color);
+ overflow: hidden;
+ margin: .125rem 0;
+}
+
+.cbi-progressbar > div {
+ background: var(--main-bright-color);
+ height: 100%;
+ transition: width .25s ease-in;
+ width: 0%;
+}
+
+.cbi-progressbar::after {
+ position: absolute;
+ bottom: 0;
+ top: 0;
+ right: 0;
+ left: 0;
+ text-align: center;
+ text-shadow: 0 0 2px var(--secondary-bright-color);
+ content: attr(title);
+ white-space: nowrap;
+ line-height: 1.5em;
+}
+
+.cbi-tabmenu {
+ padding: 0;
+ margin: 0 -.5em 1em -.5em;
+ font-weight: bold;
+ color: var(--main-dark-color);
+}
+
+.cbi-tabmenu > li {
+ display: inline-flex;
+ white-space: nowrap;
+ opacity: 1;
+ height: 1.8em;
+}
+
+.cbi-tabmenu > li > a {
+ flex: 1;
+ margin: .1em .5em;
+}
+
+.cbi-tabmenu > .cbi-tab > a {
+ border-bottom: 2px solid var(--main-dark-color);
+}
+
+[data-tab] {
+ display: none;
+ opacity: 0;
+ transition: opacity .25s ease-in-out;
+}
+
+[data-tab-active="true"] {
+ opacity: 1;
+ height: auto;
+ display: block;
+}
+
+.alert-message:not(.modal) {
+ box-shadow: 0 0 3px var(--secondary-dark-color);
+ padding: .5em;
+ margin: 0 0 1em 0;
+ background: var(--warning-color);
+ color: var(--secondary-bright-color);
+ transition: opacity .4s ease;
+}
+
+.alert-message + .alert-message {
+ margin: -.5em 0 1em 0;
+}
+
+.alert-message.info {
+ background: var(--main-bright-color);
+}
+
+.alert-message.warning {
+ background: var(--warning-color);
+}
+
+.alert-message.danger {
+ background: var(--danger-color);
+}
+
+.alert-message .btn {
+ background: inherit;
+ box-shadow: 0 0 2px var(--secondary-bright-color);
+}
+
+.alert-message .btn:hover {
+ box-shadow: 0 0 4px 1px var(--secondary-bright-color);
+}
+
+@keyframes fade-in {
+ 0% { opacity: 0; }
+ 100% { opacity: 1; }
+}
+
+@keyframes fade-out {
+ 0% { opacity: 1; }
+ 100% { opacity: 0; }
+}
+
+.fade-in {
+ animation: fade-in .4s ease;
+}
+
+.fade-out {
+ animation: fade-out .4s ease;
+ opacity: 0;
+}
+
+/*
+ * forms
+ */
+
+button, .btn {
+ background: var(--main-bright-color);
+ color: var(--secondary-bright-color);
+ line-height: 1.5em;
+ border-radius: .25em;
+ cursor: pointer;
+ box-shadow: 0 0 2px var(--main-dark-color);
+ padding: 0 .5em;
+ display: inline-block;
+}
+
+button:hover, .btn:hover {
+ box-shadow: 0 0 6px var(--main-bright-color);
+}
+
+button + button, .btn + .btn, button + .btn, .btn + button, select + button {
+ margin-left: .25em;
+}
+
+button.important {
+ background: var(--main-dark-color);
+}
+
+button[disabled], button.disabled, .btn[disabled], .btn.disabled {
+ pointer-events: none;
+ opacity: .5;
+}
+
+.cbi-button-apply, .cbi-button-positive {
+ background: var(--main-dark-color);
+}
+
+.cbi-button-negative, .cbi-button-remove {
+ background: var(--danger-color);
+}
+
+.cbi-checkbox input[type="checkbox"] {
+ display: none;
+}
+
+.cbi-checkbox input[type="checkbox"] + label {
+ position: relative;
+ display: inline-block;
+ width: 1.3em;
+ height: 1.3em;
+ vertical-align: text-top;
+}
+
+.cbi-checkbox input[type="checkbox"] + label::before {
+ content: "\0a";
+ height: 1em;
+ width: 1em;
+ box-shadow: 0 0 2px var(--main-dark-color);
+ display: inline-block;
+ border-radius: .25em;
+ margin: .15em 0;
+ position: absolute;
+ left: 0;
+ top: 0;
+ cursor: pointer;
+}
+
+.cbi-checkbox input[type="checkbox"]:checked + label::after {
+ content: "\0a";
+ position: absolute;
+ display: inline-block;
+ background: var(--main-dark-color);
+ top: .35em;
+ left: .2em;
+ width: .6em;
+ height: .6em;
+ border-radius: .15em;
+ cursor: pointer;
+}
+
+input[type="text"],
+input[type="password"],
+select,
+.cbi-dropdown:not(.btn):not(.cbi-button) {
+ border-bottom: 2px solid transparent;
+ box-shadow: inset 0 0 1px var(--main-dark-color);
+ padding: 0 .2rem;
+ line-height: 1.5rem;
+ min-height: calc(1.5rem + 2px);
+ min-width: 20rem;
+ border-radius: .25em;
+}
+
+input[type="text"]:focus,
+input[type="password"]:focus,
+select:focus,
+.cbi-dropdown:not(.btn):not(.cbi-button):focus,
+.cbi-dropdown[open]:not(.btn):not(.cbi-button) {
+ border-color: var(--main-dark-color);
+}
+
+input[type="text"] + .btn, input[type="text"] + button,
+input[type="password"] + .btn, input[type="password"] + button {
+ margin: 0 0 2px -1px;
+ background: var(--main-dark-color);
+ border-radius: 0 .25em .25em 0;
+}
+
+.control-group > select + .btn, .control-group > select + button, {
+ margin-left: .25em;
+}
+
+.control-group > input[type="text"] + .btn, .control-group > input[type="text"] + button,
+.control-group > input[type="password"] + .btn, .control-group > input[type="password"] + button {
+ margin: .125em .125em calc(.125em + 2px) calc(-.125em - .25em) !important;
+}
+
+input[type="checkbox"] {
+ height: 1em;
+ vertical-align: middle;
+ -webkit-appearance: checkbox;
+}
+
+select {
+ padding: .1rem 0;
+ -webkit-appearance: menulist;
+}
+
+textarea {
+ width: 100%;
+ box-shadow: inset 0 0 2px var(--main-dark-color);
+ font-family: monospace;
+ font-size: .9rem;
+ padding: .2rem;
+}
+
+.cbi-input-invalid,
+.cbi-input-invalid:focus {
+ color: var(--danger-color);
+ border-color: var(--danger-color) !important;
+ box-shadow: inset 0 0 2px var(--danger-color);
+}
+
+.control-group {
+ display: inline-flex;
+ margin: 0 -.125rem;
+}
+
+.control-group > *,
+.control-group > .cbi-dropdown > ul > li {
+ justify-content: space-around;
+}
+
+.control-group > * {
+ margin: .125rem !important;
+ min-width: auto;
+}
+
+.control-group > select,
+.control-group > input[type="text"] {
+ flex: 10;
+}
+
+.cbi-value {
+ display: flex;
+ flex-wrap: wrap;
+ margin: 0 0 1em 0;
+}
+
+.cbi-value > label:first-child {
+ flex: 1 1 40%;
+ padding: 0 .5em 0 0;
+}
+
+.cbi-value > .cbi-value-field {
+ flex: 2 2 55%;
+}
+
+.cbi-value > .cbi-section {
+ flex: 1 1 100%;
+}
+
+.cbi-map-descr,
+.cbi-tab-descr,
+.cbi-section-descr,
+.cbi-value-description,
+.cbi-value[data-widget="CBI.DummyValue"] > div:first-child {
+ opacity: .8;
+ font-size: .9rem;
+ padding: .2em 0;
+}
+
+.cbi-map-descr,
+.cbi-tab-descr,
+.cbi-section-descr,
+.cbi-section-table,
+.cbi-section-create {
+ margin: 0 0 1em 0;
+}
+
+.cbi-dynlist {
+ display: inline-block;
+ font-size: 90%;
+ min-height: calc(1.5em + 2px);
+ line-height: 1.5em;
+ min-width: 20rem;
+ flex-wrap: wrap;
+}
+
+.cbi-dynlist > .item {
+ box-shadow: 0 0 2px var(--main-dark-color);
+ margin: .3em 0;
+ padding: .15em .2em;
+ border-radius: .25em;
+ position: relative;
+ overflow: hidden;
+ transition: box-shadow .25s ease-in-out;
+ pointer-events: none;
+ flex: 1 1 100%;
+}
+
+.cbi-dynlist > .item::after {
+ content: "-";
+ top: 0;
+ right: 0;
+ bottom: 0;
+ width: 1.6rem;
+ background: var(--main-bright-color);
+ display: flex;
+ align-items: center;
+ justify-content: space-around;
+ position: absolute;
+ box-shadow: 0 0 2px var(--main-dark-color);
+ text-align: center;
+ color: var(--secondary-bright-color);
+ cursor: pointer;
+ pointer-events: all;
+}
+
+.cbi-dynlist > .item:hover {
+ box-shadow: 0 0 2px var(--main-bright-color);
+}
+
+.cbi-dynlist > .add-item {
+ flex: 1;
+ display: flex;
+}
+
+.cbi-dynlist > .add-item > input {
+ flex: 1;
+ min-width: 18.5rem;
+ border-radius: .25rem 0 0 .25rem;
+}
+
+.cbi-dynlist > .add-item > .btn {
+ flex: 0 0 1.6rem;
+ margin: 0 0 2px -1px;
+ width: 1.6rem;
+ text-align: center;
+}
+
+.cbi-dropdown {
+ display: inline-flex !important;
+ cursor: pointer;
+ height: auto;
+ position: relative;
+ padding: 0 !important;
+}
+
+.cbi-dropdown:not(.btn):not(.cbi-button) {
+ box-shadow: inset 0 0 1px var(--main-dark-color);
+}
+
+.cbi-dropdown > ul {
+ margin: 0 !important;
+ padding: 0;
+ list-style: none;
+ overflow-x: hidden;
+ overflow-y: auto;
+ display: flex;
+ width: 100%;
+}
+
+.cbi-dropdown.btn > ul:not(.dropdown) {
+ padding-left: .5em;
+}
+
+.cbi-dropdown.btn.spinning > ul:not(.dropdown) {
+ padding-left: 0;
+}
+
+.cbi-dropdown.btn > ul.dropdown > li {
+ color: var(--main-dark-color);
+}
+
+.cbi-dropdown > ul.preview {
+ display: none;
+}
+
+.cbi-dropdown > .open,
+.cbi-dropdown > .more {
+ flex-grow: 0;
+ flex-shrink: 0;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ text-align: center;
+ padding: 0 .25em;
+}
+
+.cbi-dropdown.btn > .open,
+.cbi-dropdown.cbi-button > .open {
+ padding: 0 .5em;
+ margin-left: .5em;
+ border-left: 1px solid;
+}
+
+.cbi-dropdown > .more,
+.cbi-dropdown:not(.btn):not(.cbi-button) > ul > li[placeholder] {
+ display: none;
+ justify-content: center;
+ color: rgba(0, 0, 0, .5);
+}
+
+.cbi-dropdown > ul > li {
+ display: none;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ flex-shrink: 1;
+ flex-grow: 1;
+ align-items: center;
+ align-self: center;
+ color: inherit;
+}
+
+.cbi-dropdown > ul.dropdown > li,
+.cbi-dropdown:not(.btn):not(.cbi-button) > ul > li {
+ padding: 0 .25em;
+}
+
+.cbi-dropdown > ul > li .hide-open { display: block; display: initial; }
+.cbi-dropdown > ul > li .hide-close { display: none; }
+
+.cbi-dropdown > ul > li[display]:not([display="0"]) {
+ border-left: 1px solid #ccc;
+}
+
+.cbi-dropdown[empty] > ul {
+ max-width: 1px;
+ max-height: 1.5em;
+}
+
+.cbi-dropdown > ul > li > form {
+ display: none;
+ margin: 0;
+ padding: 0;
+ pointer-events: none;
+}
+
+.cbi-dropdown > ul > li img {
+ align-self: center;
+ margin-right: .25em;
+}
+
+.cbi-dropdown > ul > li input[type="text"] {
+ margin: .25em 0;
+ border: none;
+ background: var(--secondary-bright-color);
+}
+
+.cbi-dropdown[open] {
+ position: relative;
+}
+
+.cbi-dropdown[open] > ul.dropdown {
+ display: block;
+ background: var(--secondary-bright-color);
+ box-shadow: 0 0 1px var(--main-dark-color), 0 0 4px rgba(0, 0, 0, .7);
+ position: absolute;
+ z-index: 1100;
+ max-width: none;
+ min-width: 100%;
+ width: auto;
+ transition: max-height .125s ease-in;
+}
+
+.cbi-dropdown > ul > li[display],
+.cbi-dropdown[open] > ul.preview,
+.cbi-dropdown[open] > ul.dropdown > li,
+.cbi-dropdown[multiple] > ul > li > label,
+.cbi-dropdown[multiple][open] > ul.dropdown > li,
+.cbi-dropdown[multiple][more] > .more,
+.cbi-dropdown[multiple][empty] > .more {
+ flex-grow: 1;
+ display: flex !important;
+}
+
+.cbi-dropdown[empty] > ul > li,
+.cbi-dropdown[optional][open] > ul.dropdown > li[placeholder],
+.cbi-dropdown[multiple][open] > ul.dropdown > li > form {
+ display: block !important;
+}
+
+.cbi-dropdown[open] > ul.dropdown > li .hide-open { display: none; }
+.cbi-dropdown[open] > ul.dropdown > li .hide-close { display: block; display: initial; }
+
+.cbi-dropdown[open] > ul.dropdown > li {
+ border-bottom: 1px solid #ccc;
+}
+
+.cbi-dropdown[open] > ul.dropdown > li[selected] {
+ background: var(--main-dark-color);
+ color: var(--secondary-bright-color);
+}
+
+.cbi-dropdown[open] > ul.dropdown > li.focus {
+ background: var(--main-bright-color);
+}
+
+.cbi-dropdown[open] > ul.dropdown > li:last-child {
+ margin-bottom: 0;
+ border-bottom: none;
+}
+
+.cbi-dropdown[open] > ul.dropdown > li[unselectable] {
+ opacity: 0.7;
+}
+
+.cbi-dropdown[open] > ul.dropdown > li > input.create-item-input:first-child:last-child {
+ width: 100%;
+}
+
+.cbi-dropdown[disabled] {
+ pointer-events: none;
+ opacity: .6;
+}
+
+.cbi-filebrowser {
+ max-width: 100%;
+ width: 1px;
+ box-shadow: 0 0 2px var(--main-dark-color);
+ border-radius: .25rem;
+ display: flex;
+ flex-direction: column;
+ opacity: 0;
+ height: 0;
+ overflow: hidden;
+}
+
+.cbi-filebrowser.open {
+ min-width: 20rem;
+ width: auto;
+ opacity: 1;
+ height: auto;
+ overflow: visible;
+ transition: opacity .25s ease-in;
+}
+
+.cbi-filebrowser > * {
+ max-width: 100%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ padding: 0 0 .25em 0;
+ margin: .25em .25em 0px .25em;
+ white-space: nowrap;
+ border-bottom: 1px solid var(--main-dark-color);
+}
+
+.cbi-filebrowser .cbi-button-positive {
+ margin-right: .25em;
+}
+
+.cbi-filebrowser > div {
+ border-bottom: none;
+}
+
+.cbi-filebrowser > ul > li {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.cbi-filebrowser > ul > li a:hover {
+ font-weight: bold;
+ text-decoration: underline;
+}
+
+.cbi-filebrowser > ul > li > div:first-child {
+ flex: 10;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.cbi-filebrowser > ul > li > div:last-child {
+ flex: 3 3 10em;
+ text-align: right;
+}
+
+.cbi-filebrowser > ul > li > div:last-child > button {
+ padding: .125em .25em;
+ margin: 1px 0 1px .25em;
+}
+
+.cbi-filebrowser .upload {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ margin: 0 -.125em .25em -.125em;
+ padding: 0 0 .125em 0px;
+ border-bottom: 1px solid var(--main-dark-color);
+}
+
+.cbi-filebrowser .upload > * {
+ margin: .125em;
+ flex: 1;
+}
+
+.cbi-filebrowser .upload > div > input {
+ width: 100%;
+}
+
+.cbi-section-actions {
+ text-align: right;
+}
+
+.cbi-page-actions {
+ flex-wrap: wrap;
+ width: 100%;
+ justify-content: flex-end;
+ margin-bottom: 1em;
+ margin-top: 1em;
+ border-top: 1px solid var(--main-dark-color);
+ padding-top: 1em;
+ text-align: right;
+}
+
+div[id$=".ipaddr"] > input,
+.cbi-value-field > div > input[type="password"] {
+ min-width: 18.5rem;
+ border-radius: .25rem 0 0 .25rem;
+}
+
+div[id$=".txpower"] {
+ flex-wrap: wrap;
+ align-items: center;
+}
+
+div[id$=".txpower"] > span {
+ white-space: nowrap;
+ margin-left: .25em;
+}
+
+div[id$=".editlist"] {
+ flex: 1;
+}
+
+[data-errors]::after {
+ content: attr(data-errors);
+ background: var(--danger-color);
+ color: var(--secondary-bright-color);
+ border-radius: .6rem;
+ height: 1.1rem;
+ padding: 0 .25rem;
+ font-size: .9rem;
+ display: inline-block;
+ font-weight: bold;
+ min-width: .6rem;
+ line-height: 1rem;
+ margin: -.1rem 0 0 -.2rem;
+ text-align: center;
+}
+
+@keyframes spin {
+ 100% { transform: rotate(360deg); }
+}
+
+.spinning {
+ position: relative;
+ padding-left: 2.1em !important;
+}
+
+.spinning::before {
+ position: absolute;
+ display: flex;
+ align-items: center;
+ top: 0;
+ bottom: 0;
+ left: .4em;
+ width: 1.3em;
+ animation: spin 1s linear infinite;
+ content: url("/luci-static/openwrt2020/spinner.svg");
+}
+
+button.spinning, .btn.spinning {
+ padding-left: 1.6em !important;
+}
+
+button.spinning::before, .btn.spinning::before {
+ filter: invert(1);
+ left: .2em;
+ width: 1.2em;
+}
+
+#view > div.spinning:first-child {
+ padding: .5em 0;
+}
+
+#view > *:last-child {
+ margin: 0 0 1em 0;
+}
+
+.label {
+ background: var(--main-bright-color);
+ color: var(--secondary-bright-color);
+ font-size: .8rem;
+ padding: 0 .4rem;
+ border-radius: .5rem;
+}
+
+.label.warning {
+ background: var(--danger-color);
+}
+
+ul.deps {
+ margin: 0;
+ padding: 0;
+ font-size: .9rem;
+}
+
+ul.errors {
+ margin: 0 0 1em 0;
+ padding: 0;
+}
+
+@media only screen and (max-width: 800px) {
+ body {
+ padding-top: 70px;
+ }
+
+ #maincontent {
+ padding: .25em;
+ max-width: 100vw;
+ }
+
+ #menubar {
+ background: var(--main-bright-color);
+ padding: 0 .5em;
+ position: fixed;
+ top: 0;
+ z-index: 1000;
+ }
+
+ #menubar > h2 {
+ flex: 0 0 2em;
+ display: block;
+ border: 2px solid var(--secondary-bright-color);
+ color: var(--secondary-bright-color);
+ border-radius: .5em;
+ cursor: pointer;
+ font-size: 100%;
+ margin: 0 1em 0 0;
+ }
+
+ #menubar > h2:hover {
+ border-color: var(--secondary-bright-color);
+ color: var(--secondary-bright-color);
+ }
+
+ #menubar > h2 > * {
+ display: none;
+ }
+
+ #menubar > h2::before {
+ content: "☰";
+ width: 35px;
+ line-height: 35px;
+ text-align: center;
+ display: inline-block;
+ color: inherit;
+ font-weight: bold;
+ }
+
+ #menubar > h2.active::before {
+ content: "×";
+ font-size: 200%;
+ }
+
+ #menubar .hostname {
+ font-size: 1.6em;
+ }
+
+ .distversion {
+ display: none;
+ }
+
+ #mainmenu {
+ overflow-x: hidden;
+ overflow-y: auto;
+ max-width: 0;
+ padding: 1em 0;
+ transition: max-width .25s ease-in-out, padding .25s ease-in-out;
+ position: fixed;
+ z-index: 900;
+ height: 100%;
+ }
+
+ #mainmenu.active {
+ max-width: 200px;
+ padding: 1em 1em calc(1em + 70px) 1em;
+ overflow-x: visible;
+ }
+
+ #mainmenu > div {
+ position: static;
+ }
+
+ #mainmenu ul > li {
+ padding: .25em 0;
+ }
+
+ .hide-xs {
+ display: none !important;
+ }
+
+ .table {
+ display: flex;
+ flex-direction: column;
+ }
+
+ .tr {
+ display: block;
+ border-bottom: 1px solid var(--main-dark-color);
+ margin-bottom: .5em;
+ padding-bottom: .5em;
+ }
+
+ .tr.cbi-section-table-titles[data-title]::before,
+ .tr.cbi-section-table-titles,
+ .tr.cbi-section-table-descr {
+ display: none;
+ }
+
+ .tr[data-title]::before {
+ display: block;
+ font-weight: bold;
+ border-top: none;
+ padding: .4em 0;
+ font-size: 110%;
+ }
+
+ .td {
+ display: block;
+ border-top: none;
+ text-align: left !important;
+ padding: .2em 0;
+ }
+
+ .th, .table-titles {
+ display: none;
+ }
+
+ .td[data-title] {
+ position: relative;
+ padding: .2em 0 .2em 40%;
+ }
+
+ .td[data-title]::before {
+ content: attr(data-title) ": ";
+ white-space: nowrap;
+ font-weight: bold;
+ width: 40%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ padding: .2em 0;
+ text-align: left;
+ display: inline-flex;
+ align-items: center;
+ }
+
+ [data-page="admin-status-overview"] .cbi-section:nth-of-type(1) .td:first-of-type,
+ [data-page="admin-status-overview"] .cbi-section:nth-of-type(2) .td:first-of-type {
+ font-weight: bold;
+ max-width: none;
+ width: 100%;
+ }
+
+ [data-page="admin-status-overview"] .td > span > span { font-size: .9rem; }
+
+ [data-page="admin-status-routes"] .table:nth-of-type(3) .td:nth-of-type(1) { word-break: break-all; }
+
+ [data-page="admin-network-firewall-zones"] .td[data-name="_info"] {
+ padding: .2em 0;
+ line-height: 2.2rem;
+ }
+
+ [data-page="admin-network-firewall-zones"] .td[data-name="_info"]::before {
+ display: none;
+ }
+
+ [data-page="admin-network-firewall-zones"] .td[data-name="_info"] label {
+ font-size: 1rem;
+ }
+
+ #cbi-wireless-wifi-device .tr { display: flex; flex-wrap: wrap; }
+ #cbi-wireless-wifi-device .tr > *:nth-child(1) { flex: 1 1 20%; align-self: center; }
+ #cbi-wireless-wifi-device .tr > *:nth-child(2) { flex: 2 2 75%; }
+ #cbi-wireless-wifi-device .tr > *:nth-child(3) { flex: 3 3 100%; }
+
+ #cbi-network-interface .tr { display: flex; flex-wrap: wrap; }
+ #cbi-network-interface .tr > *:nth-child(1) { flex: 1 1 33%; align-self: center; }
+ #cbi-network-interface .tr > *:nth-child(2) { flex: 2 2 60%; align-self: center; font-size: .9rem; overflow: hidden; }
+ #cbi-network-interface .tr > *:nth-child(3) { flex: 3 3 100%; }
+ #cbi-network-interface .tr > *:nth-child(2) > div { overflow: hidden; text-overflow: ellipsis; }
+
+ .assoclist .tr {
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+ .assoclist .td > .ifacebadge {
+ max-width: 90px;
+ }
+
+ .assoclist .td > .ifacebadge > img {
+ margin: 0 35px;
+ }
+
+ .assoclist .td > .ifacebadge > span {
+ display: none;
+ }
+
+ .assoclist .td > .ifacebadge[data-ifname]::after {
+ content: attr(data-ifname);
+ }
+
+ .assoclist .td > .ifacebadge[data-signal]::after {
+ content: attr(data-signal) " dBm";
+ }
+
+ .assoclist .td:nth-of-type(3) {
+ font-weight: bold;
+ font-size: 1rem;
+ }
+
+ .assoclist .td:nth-of-type(1), .assoclist .td:nth-of-type(4) {
+ flex: 1 1 100px;
+ margin-right: .5em;
+ }
+
+ .assoclist .td:nth-of-type(3), .assoclist .td:nth-of-type(5) {
+ flex: 2 2 calc(100% - 110px);
+ overflow: hidden;
+ text-overflow: ellipsis;
+ align-self: center;
+ }
+
+ .assoclist .td:nth-of-type(6) { flex: 1; text-align: right !important; }
+ .assoclist .td[data-title] { padding: .2em 0; }
+ .assoclist .td[data-title]::before { display: none; }
+
+ .leases6 .td:nth-of-type(3) { word-wrap: break-word; }
+
+ .td.cbi-section-actions > div { display: flex; }
+ .td.cbi-section-actions > div > * { flex: 1; }
+
+ body.modal-overlay-active #modal_overlay > .modal {
+ max-width: 95%;
+ margin: 5% auto;
+ }
+
+ input[type="text"],
+ input[type="password"],
+ select,
+ .cbi-dropdown:not(.btn):not(.cbi-button),
+ .cbi-dynlist {
+ min-height: calc(2.2rem + 2px);
+ line-height: 2.2rem;
+ font-size: 1.2rem;
+ min-width: 10rem;
+ }
+
+ button, .btn {
+ line-height: 1.8rem;
+ font-size: 1.2rem;
+ }
+
+ select {
+ padding: .4em 0;
+ }
+
+ .cbi-value > .cbi-value-field {
+ flex: 1 0 100%;
+ display: flex;
+ flex-direction: column;
+ max-width: 100%;
+ }
+
+ .cbi-value > .cbi-value-field > div[id] {
+ display: flex;
+ flex-direction: row;
+ }
+
+ .cbi-value > .cbi-value-field > div[id] > input,
+ .cbi-value > .cbi-value-field > div[id] > select,
+ .cbi-value > .cbi-value-field > div[id] > .cbi-filebrowser.open {
+ flex: 1;
+ width: 100%;
+ }
+
+ .cbi-dynlist .item::after,
+ .cbi-dynlist .add-item > .btn {
+ line-height: 2em;
+ flex-basis: 2rem;
+ width: 2rem;
+ }
+
+ .ifacebadge.large {
+ font-size: .9rem;
+ }
+
+ .control-group > *,
+ .control-group > .cbi-dropdown > ul > li {
+ flex: 1;
+ white-space: normal;
+ word-wrap: break-word;
+ }
+
+ .cbi-page-actions .cbi-dropdown,
+ .cbi-page-actions .cbi-button-apply:first-child {
+ flex-basis: 100%;
+ }
+
+ .cbi-checkbox {
+ margin: .25rem;
+ }
+
+ .cbi-tabmenu {
+ margin: 0 -.25em 1em -.25em;
+ }
+
+ .cbi-tooltip {
+ font-size: 1rem;
+ box-shadow: 0 0 4px rgba(0, 0, 0, .7);
+ }
+
+ .cbi-value > label:first-child {
+ padding: 0 0 .5em 0;
+ }
+
+ [data-page="admin-system-admin-sshkeys"] .cbi-dynlist > .item {
+ font-size: .9rem;
+ line-height: 1rem;
+ }
+
+ [data-page="admin-system-opkg"] .control-group {
+ flex-wrap: wrap;
+ }
+
+ [data-page="admin-status-iptables"] h2 + div.right {
+ margin: 0 0 1em 0 !important;
+ display: flex;
+ }
+}
+
+@media only screen and (min-width: 800px) and (max-width: 1200px) {
+ .assoclist .tr > *:nth-of-type(2) {
+ display: none;
+ }
+}
diff --git a/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/favicon.png b/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/favicon.png
new file mode 100644
index 0000000000..ee841e823c
--- /dev/null
+++ b/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/favicon.png
Binary files differ
diff --git a/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/logo.svg b/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/logo.svg
new file mode 100644
index 0000000000..878a39d40c
--- /dev/null
+++ b/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/logo.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 81.2 98">
+ <path d="m 40.5,50.8 a 6.6,6.6 0 1 0 0,13.2 6.6,6.6 0 0 0 0,-13.2 m -40.5,-33.9 7,6.8 a 47.5,47.5 0 0 1 67.2,0 l 7,-6.8 a 57.2,57.2 0 0 0 -81.2,0" style="fill:#fff" />
+ <path d="m 12.5,29.2 6.8,7 a 30,30 0 0 1 42.6,0 l 6.8,-7 a 39.7,39.7 0 0 0 -56.3,0" style="fill:#fff" />
+ <path d="m 24.8,41.6 6.8,6.9 a 12.6,12.6 0 0 1 18,0 l 6.8,-6.9 a 22.3,22.3 0 0 0 -31.6,0" style="fill:#fff" />
+ <path d="m 64.9,39.7 a 30.2,30.2 0 1 1 -48.7,0 l -6.9,-7 a 39.9,39.9 0 1 0 62.5,0 z" style="fill:#072342" />
+</svg>
diff --git a/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/spinner.svg b/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/spinner.svg
new file mode 100644
index 0000000000..f3b52eface
--- /dev/null
+++ b/themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/spinner.svg
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="132 132 264 264">
+ <defs>
+ <radialGradient id="g" cx="0%" cy="0%" r="60%">
+ <stop offset=".8" style="stop-opacity:1" />
+ <stop offset="1" style="stop-opacity:.5" />
+ </radialGradient>
+ </defs>
+ <g>
+ <path style="fill:url(#g)" d="M 264 132 A 132 132 0 0 0 132 264 A 132 132 0 0 0 264 396 A 132 132 0 0 0 396 264 A 132 132 0 0 0 264 132 z M 264 170 A 94 94 0 0 1 359 264 A 94 94 0 0 1 264 359 A 94 94 0 0 1 170 264 A 94 94 0 0 1 264 170 z " />
+ </g>
+</svg>