mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-19 19:33:47 +00:00
Introducing Orca Cloud: https://cloud.orcaslicer.com (#13414)
* Add OrcaCloud sync platform and preset bundle sharing system Introduce OrcaCloud, a cloud sync platform for user presets, alongside a preset bundle system that enables sharing printer/filament/process profiles as local exportable bundles or subscribed cloud bundles. OrcaCloud platform: - Auth to Orca Cloud - Encrypted token storage (file-based or system keychain) - User preset sync with - Profile migration from default/bambu folders on first login - Homepage integration with entrance to cloud.orcaslicer.com Preset bundles: - Local bundle import/export with bundle_structure.json metadata - Subscribed cloud bundles with version-based update checking - Thread-safe concurrent bundle access with read-write mutex - Canonical bundle preset naming (_local/<id>/... and _subscribed/<id>/...) - Bundle presets are read-only; grouped under subheaders in combo boxes - PresetBundleDialog with auto-sync toggle, refresh, update notifications - Hyperlinked bundle names to cloud bundle pages Co-authored-by: Sabriel Koh <sabrielkcr@gmail.com> Co-authored-by: Derrick <derrick992110@gmail.com> Co-authored-by: Mykola Nahirnyi <mnahirnyi@amcbridge.com> Co-authored-by: Ian Chua <iancrb00@gmail.com> Co-authored-by: Draginraptor <draginraptor@gmail.com> Co-authored-by: ExPikaPaka <112851715+ExPikaPaka@users.noreply.github.com> Co-authored-by: Ian Bassi <ian.bassi@outlook.com> Co-authored-by: Ocraftyone <Ocraftyone@users.noreply.github.com> Co-authored-by: yw4z <ywsyildiz@gmail.com> Co-authored-by: peterm-m <101202951+peterm-m@users.noreply.github.com> * Fixed an issue on Windows it failed to login Orca Cloud with Google account
This commit is contained in:
75
resources/web/dialog/ExportPresetDialog/index.html
Normal file
75
resources/web/dialog/ExportPresetDialog/index.html
Normal file
@@ -0,0 +1,75 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Cache-Control" content="max-age=0" />
|
||||
<title>Export Presets</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../../include/global.css" /> <!-- ORCA One for all-->
|
||||
<link rel="stylesheet" type="text/css" href="../css/common.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
|
||||
<script type="text/javascript" src="../js/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
<script type="text/javascript" src="../js/common.js"></script>
|
||||
<script src="./index.js"></script>
|
||||
</head>
|
||||
<body onLoad="OnInit()">
|
||||
|
||||
<!-- ORCA column browser -->
|
||||
<div class="cbr-browser-container">
|
||||
<div class="cbr-column">
|
||||
<div class="cbr-column-title-container">
|
||||
<div class="search-icon"></div>
|
||||
<input type="text" class="cbr-search-bar" placeholder=" " tabindex="1"/>
|
||||
<span class="cbr-search-placeholder trans" tid="t15">printer</span>
|
||||
<div class="clear-icon"></div>
|
||||
</div>
|
||||
<div class="cbr-content thin-scroll" id="MachineList">
|
||||
<div class="CValues">
|
||||
<label><input type="checkbox" mode="all" onClick="ChooseAllMachine()" /><span class="trans" tid="t11">all</span></label>
|
||||
</div>
|
||||
<div class="cbr-no-items">No items</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cbr-column">
|
||||
<div class="cbr-column-title-container">
|
||||
<div class="search-icon"></div>
|
||||
<input type="text" class="cbr-search-bar" placeholder=" " tabindex="2"/>
|
||||
<span class="cbr-search-placeholder trans" tid="t16">filament</span>
|
||||
<div class="clear-icon"></div>
|
||||
</div>
|
||||
<div class="cbr-content thin-scroll" id="FilatypeList">
|
||||
<div class="CValues">
|
||||
<label><input type="checkbox" class="trans" tid="t11" onClick="ChooseAllFilament()" /><span class="trans" tid="t11">all</span></label>
|
||||
</div>
|
||||
<div class="cbr-no-items">No items</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cbr-column">
|
||||
<div class="cbr-column-title-container">
|
||||
<div class="search-icon"></div>
|
||||
<input type="text" class="cbr-search-bar" placeholder=" " tabindex="3"/>
|
||||
<span class="cbr-search-placeholder trans" tid="t17">presets</span>
|
||||
<div class="clear-icon"></div>
|
||||
</div>
|
||||
<div class="cbr-content thin-scroll" id="PresetList">
|
||||
<div class="CValues">
|
||||
<label><input type="checkbox" class="trans" tid="t11" onClick="ChooseAllPreset()" /><span class="trans" tid="t11">all</span></label>
|
||||
</div>
|
||||
<div class="cbr-no-items">No items</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="AcceptArea">
|
||||
<div id="export_cloud_btn" class="ButtonStyleConfirm ButtonTypeChoice">Export to OrcaCloud</div>
|
||||
<div id="export_local_btn" class="ButtonStyleRegular ButtonTypeChoice">Export to folder</div>
|
||||
<div id="close_btn" class="ButtonStyleRegular ButtonTypeChoice">Close</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
374
resources/web/dialog/ExportPresetDialog/index.js
Normal file
374
resources/web/dialog/ExportPresetDialog/index.js
Normal file
@@ -0,0 +1,374 @@
|
||||
var g_profile = {
|
||||
machines: [],
|
||||
filaments: [],
|
||||
presets: []
|
||||
};
|
||||
|
||||
var g_search = {
|
||||
machine: "",
|
||||
filament: "",
|
||||
preset: ""
|
||||
};
|
||||
|
||||
function OnInit()
|
||||
{
|
||||
if (typeof TranslatePage === "function")
|
||||
TranslatePage();
|
||||
|
||||
InstallInputSafeKeydown();
|
||||
BindSearchInputs();
|
||||
BindClearIcons();
|
||||
BindBottomButtons();
|
||||
|
||||
// Always load demo data first so the page works without C++ backend.
|
||||
// LoadDemoProfile();
|
||||
RequestProfile();
|
||||
}
|
||||
|
||||
function InstallInputSafeKeydown()
|
||||
{
|
||||
// common.js blocks all key events globally; allow typing in text inputs.
|
||||
document.onkeydown = function (event) {
|
||||
var e = event || window.event || arguments.callee.caller.arguments[0];
|
||||
var target = e && e.target ? e.target : null;
|
||||
var tag = target && target.tagName ? String(target.tagName).toUpperCase() : "";
|
||||
var type = target && target.type ? String(target.type).toLowerCase() : "";
|
||||
|
||||
var editable =
|
||||
!!(target && target.isContentEditable) ||
|
||||
tag === "TEXTAREA" ||
|
||||
(tag === "INPUT" && type !== "checkbox" && type !== "radio" && type !== "button" && type !== "submit");
|
||||
|
||||
if (editable)
|
||||
return true;
|
||||
|
||||
if (e && e.keyCode === 27 && typeof ClosePage === "function")
|
||||
ClosePage();
|
||||
|
||||
if (window.event) {
|
||||
try { e.keyCode = 0; } catch (err) { }
|
||||
e.returnValue = false;
|
||||
}
|
||||
|
||||
if (e && typeof e.preventDefault === "function")
|
||||
e.preventDefault();
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
function RequestProfile()
|
||||
{
|
||||
SendMessage("request_export_preset_profile", {});
|
||||
}
|
||||
|
||||
function HandleStudio(pVal)
|
||||
{
|
||||
var payload = (typeof pVal === "string") ? SafeJsonParse(pVal) : pVal;
|
||||
if (!payload || typeof payload !== "object")
|
||||
return;
|
||||
|
||||
var cmd = String(payload.command || "");
|
||||
if (cmd === "response_export_preset_profile" ) {
|
||||
ApplyProfile(payload.data);
|
||||
}
|
||||
}
|
||||
|
||||
function ApplyProfile(profile)
|
||||
{
|
||||
|
||||
g_profile.machines = BuildNameRows(profile.printers);
|
||||
g_profile.filaments = BuildNameRows(profile.filaments);
|
||||
g_profile.presets = BuildNameRows(profile.process);
|
||||
|
||||
RenderColumn("MachineList", g_profile.machines, "mode", "MachineClick");
|
||||
RenderColumn("FilatypeList", g_profile.filaments, "filatype", "FilaClick");
|
||||
RenderColumn("PresetList", g_profile.presets, "preset", "PresetClick");
|
||||
|
||||
ApplyColumnSearch("MachineList", g_search.machine);
|
||||
ApplyColumnSearch("FilatypeList", g_search.filament);
|
||||
ApplyColumnSearch("PresetList", g_search.preset);
|
||||
}
|
||||
|
||||
function BuildNameRows(names)
|
||||
{
|
||||
var src = Array.isArray(names) ? names : [];
|
||||
var out = [];
|
||||
|
||||
for (var n = 0; n < src.length; n++) {
|
||||
var row = src[n];
|
||||
if (row === undefined || row === null)
|
||||
continue;
|
||||
|
||||
var name = String(row);
|
||||
out.push({ id: name, label: name, checked: false });
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
function RenderColumn(listId, items, attrName, onChangeFn)
|
||||
{
|
||||
var root = $("#" + listId + " .CValues");
|
||||
if (!root.length)
|
||||
return;
|
||||
|
||||
root.find("label:gt(0)").remove();
|
||||
|
||||
var html = "";
|
||||
for (var n = 0; n < items.length; n++) {
|
||||
var one = items[n];
|
||||
html += '<label data-dynamic="1">' +
|
||||
'<input type="checkbox" data-key="' + EscapeAttr(one.id) + '" ' + attrName + '="' + EscapeAttr(one.id) + '"' +
|
||||
(one.checked ? ' checked="checked"' : "") +
|
||||
' onChange="' + onChangeFn + '()" />' +
|
||||
'<span title="' + EscapeAttr(one.label) + '">' + EscapeHtml(one.label) + '</span>' +
|
||||
'</label>';
|
||||
}
|
||||
|
||||
root.append(html);
|
||||
SyncMasterCheckbox(listId);
|
||||
ToggleNoItems(listId, items.length === 0);
|
||||
}
|
||||
|
||||
function ChooseAllMachine()
|
||||
{
|
||||
var checked = !!$("#MachineList .CValues input:first").prop("checked");
|
||||
$("#MachineList .CValues input:gt(0)").prop("checked", checked);
|
||||
SyncListFromDom("MachineList", g_profile.machines);
|
||||
}
|
||||
|
||||
function MachineClick()
|
||||
{
|
||||
SyncMasterCheckbox("MachineList");
|
||||
SyncListFromDom("MachineList", g_profile.machines);
|
||||
}
|
||||
|
||||
function ChooseAllFilament()
|
||||
{
|
||||
var checked = !!$("#FilatypeList .CValues input:first").prop("checked");
|
||||
$("#FilatypeList .CValues input:gt(0)").prop("checked", checked);
|
||||
SyncListFromDom("FilatypeList", g_profile.filaments);
|
||||
}
|
||||
|
||||
function FilaClick()
|
||||
{
|
||||
SyncMasterCheckbox("FilatypeList");
|
||||
SyncListFromDom("FilatypeList", g_profile.filaments);
|
||||
}
|
||||
|
||||
function ChooseAllPreset()
|
||||
{
|
||||
var checked = !!$("#PresetList .CValues input:first").prop("checked");
|
||||
$("#PresetList .CValues input:gt(0)").prop("checked", checked);
|
||||
SyncListFromDom("PresetList", g_profile.presets);
|
||||
}
|
||||
|
||||
function PresetClick()
|
||||
{
|
||||
SyncMasterCheckbox("PresetList");
|
||||
SyncListFromDom("PresetList", g_profile.presets);
|
||||
}
|
||||
|
||||
function SyncMasterCheckbox(listId)
|
||||
{
|
||||
var all = $("#" + listId + " .CValues input:gt(0)");
|
||||
var master = $("#" + listId + " .CValues input:first");
|
||||
|
||||
if (!all.length) {
|
||||
master.prop("checked", false);
|
||||
return;
|
||||
}
|
||||
|
||||
master.prop("checked", all.length === all.filter(":checked").length);
|
||||
}
|
||||
|
||||
function SyncListFromDom(listId, store)
|
||||
{
|
||||
var map = {};
|
||||
for (var n = 0; n < store.length; n++)
|
||||
map[store[n].id] = store[n];
|
||||
|
||||
$("#" + listId + " .CValues input:gt(0)").each(function () {
|
||||
var id = String($(this).attr("data-key") || "");
|
||||
if (map[id])
|
||||
map[id].checked = !!$(this).prop("checked");
|
||||
});
|
||||
}
|
||||
|
||||
function BindSearchInputs()
|
||||
{
|
||||
var inputs = document.querySelectorAll(".cbr-search-bar");
|
||||
|
||||
if (inputs.length > 0) {
|
||||
inputs[0].addEventListener("input", function () {
|
||||
g_search.machine = String(this.value || "").toLowerCase();
|
||||
ApplyColumnSearch("MachineList", g_search.machine);
|
||||
});
|
||||
}
|
||||
|
||||
if (inputs.length > 1) {
|
||||
inputs[1].addEventListener("input", function () {
|
||||
g_search.filament = String(this.value || "").toLowerCase();
|
||||
ApplyColumnSearch("FilatypeList", g_search.filament);
|
||||
});
|
||||
}
|
||||
|
||||
if (inputs.length > 2) {
|
||||
inputs[2].addEventListener("input", function () {
|
||||
g_search.preset = String(this.value || "").toLowerCase();
|
||||
ApplyColumnSearch("PresetList", g_search.preset);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function ApplyColumnSearch(listId, query)
|
||||
{
|
||||
var rows = $("#" + listId + " .CValues label:gt(0)");
|
||||
var visibleCount = 0;
|
||||
|
||||
rows.each(function () {
|
||||
var row = $(this);
|
||||
var text = String(row.text() || "").toLowerCase();
|
||||
var key = String(row.find("input").attr("data-key") || "").toLowerCase();
|
||||
|
||||
if (!query || text.indexOf(query) >= 0 || key.indexOf(query) >= 0) {
|
||||
row.show();
|
||||
visibleCount++;
|
||||
}
|
||||
else {
|
||||
row.hide();
|
||||
}
|
||||
});
|
||||
|
||||
ToggleNoItems(listId, visibleCount === 0);
|
||||
}
|
||||
|
||||
function ToggleNoItems(listId, show)
|
||||
{
|
||||
var node = $("#" + listId + " .cbr-no-items");
|
||||
if (!node.length)
|
||||
return;
|
||||
|
||||
if (show)
|
||||
node.addClass("show");
|
||||
else
|
||||
node.removeClass("show");
|
||||
}
|
||||
|
||||
function BindClearIcons()
|
||||
{
|
||||
var icons = document.querySelectorAll(".clear-icon");
|
||||
|
||||
for (var n = 0; n < icons.length; n++) {
|
||||
icons[n].addEventListener("click", function () {
|
||||
var parent = this.parentElement;
|
||||
if (!parent)
|
||||
return;
|
||||
|
||||
var input = parent.querySelector("input[type='text']");
|
||||
if (!input)
|
||||
return;
|
||||
|
||||
input.value = "";
|
||||
input.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
input.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function BindBottomButtons()
|
||||
{
|
||||
var backBtn = document.getElementById("back_btn");
|
||||
var exportCloud = document.getElementById("export_cloud_btn")
|
||||
var exportLocal = document.getElementById("export_local_btn");
|
||||
var closeBtn = document.getElementById("close_btn");
|
||||
|
||||
backBtn?.addEventListener("click", function () {
|
||||
SendMessage("navigate_back", {});
|
||||
});
|
||||
|
||||
|
||||
exportLocal?.addEventListener("click", function () {
|
||||
SendMessage("export_local", BuildResultPayload());
|
||||
});
|
||||
|
||||
|
||||
closeBtn?.addEventListener("click", () => {
|
||||
const tSend = {
|
||||
sequence_id: Math.round(Date.now() / 1000),
|
||||
command: "close_page"
|
||||
};
|
||||
SendWXMessage(JSON.stringify(tSend));
|
||||
});
|
||||
}
|
||||
|
||||
function BuildResultPayload()
|
||||
{
|
||||
return {
|
||||
machines: g_profile.machines.filter(function (x) { return x.checked; }).map(function (x) { return x.id; }),
|
||||
filaments: g_profile.filaments.filter(function (x) { return x.checked; }).map(function (x) { return x.id; }),
|
||||
presets: g_profile.presets.filter(function (x) { return x.checked; }).map(function (x) { return x.id; })
|
||||
};
|
||||
}
|
||||
|
||||
function LoadDemoProfile()
|
||||
{
|
||||
ApplyProfile({
|
||||
machines: [
|
||||
{ id: "printer_x1c_04", name: "X1 Carbon 0.4 nozzle", selected: 1 },
|
||||
{ id: "printer_p1s_04", name: "P1S 0.4 nozzle", selected: 1 },
|
||||
{ id: "printer_a1_04", name: "A1 0.4 nozzle", selected: 0 },
|
||||
{ id: "printer_prusa_mk4_04", name: "Prusa MK4 0.4 nozzle", selected: 1 }
|
||||
],
|
||||
filaments: [
|
||||
{ id: "filament_generic_pla", name: "Generic PLA", selected: 1 },
|
||||
{ id: "filament_generic_petg", name: "Generic PETG", selected: 1 },
|
||||
{ id: "filament_bambu_abs", name: "Bambu ABS", selected: 0 },
|
||||
{ id: "filament_esun_pla_plus", name: "eSUN PLA+", selected: 1 }
|
||||
],
|
||||
presets: [
|
||||
{ id: "preset_quality_020", name: "Quality 0.20mm", selected: 1 },
|
||||
{ id: "preset_quality_012", name: "Quality 0.12mm", selected: 0 },
|
||||
{ id: "preset_speed_024", name: "Speed 0.24mm", selected: 1 },
|
||||
{ id: "preset_draft_028", name: "Draft 0.28mm", selected: 0 }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
function SendMessage(command, data)
|
||||
{
|
||||
var msg = {};
|
||||
msg.sequence_id = Math.round(new Date() / 1000);
|
||||
msg.command = command;
|
||||
if (data && typeof data === "object")
|
||||
msg.data = data;
|
||||
|
||||
if (typeof SendWXMessage === "function")
|
||||
SendWXMessage(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
function SafeJsonParse(str)
|
||||
{
|
||||
try {
|
||||
return JSON.parse(str);
|
||||
}
|
||||
catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function EscapeHtml(str)
|
||||
{
|
||||
return String(str)
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/\"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
|
||||
function EscapeAttr(str)
|
||||
{
|
||||
return EscapeHtml(str);
|
||||
}
|
||||
191
resources/web/dialog/ExportPresetDialog/styles.css
Normal file
191
resources/web/dialog/ExportPresetDialog/styles.css
Normal file
@@ -0,0 +1,191 @@
|
||||
:root {
|
||||
--cbr-border-color: #d2d2d7;
|
||||
--cbr-header-bg: #f6f7f9;
|
||||
--cbr-panel-bg: #ffffff;
|
||||
--cbr-input-bg: #ffffff;
|
||||
--cbr-input-focus-bg: #f2f8f7;
|
||||
--cbr-label-color: #7b7b84;
|
||||
--cbr-icon-color: #75757f;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--cbr-border-color: #4a4a51;
|
||||
--cbr-header-bg: #2f2f34;
|
||||
--cbr-panel-bg: #2d2d31;
|
||||
--cbr-input-bg: #2d2d31;
|
||||
--cbr-input-focus-bg: #3b3b41;
|
||||
--cbr-label-color: #b9b9bc;
|
||||
--cbr-icon-color: #b9b9bc;
|
||||
}
|
||||
}
|
||||
|
||||
.cbr-browser-container {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
margin: 10px 15px 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
grid-template-rows: minmax(0, 1fr);
|
||||
border: 1px solid var(--cbr-border-color);
|
||||
background: var(--cbr-panel-bg);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.cbr-column {
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cbr-column:not(:last-child) {
|
||||
border-right: 1px solid var(--cbr-border-color);
|
||||
}
|
||||
|
||||
.cbr-column-title-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 36px;
|
||||
padding: 3px 6px;
|
||||
background: var(--cbr-header-bg);
|
||||
border-bottom: 1px solid var(--cbr-border-color);
|
||||
}
|
||||
|
||||
.cbr-search-bar {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
padding: 2px 26px 2px 26px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
background: var(--cbr-input-bg);
|
||||
}
|
||||
|
||||
.cbr-search-bar:hover,
|
||||
.cbr-search-bar:focus {
|
||||
border-color: var(--main-color);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.cbr-search-bar:focus {
|
||||
background: var(--cbr-input-focus-bg);
|
||||
}
|
||||
|
||||
.cbr-search-placeholder {
|
||||
position: absolute;
|
||||
left: 33px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: var(--cbr-label-color);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.cbr-search-bar:not(:placeholder-shown) + .cbr-search-placeholder {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.search-icon,
|
||||
.clear-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--cbr-icon-color);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
left: 11px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.search-icon::before {
|
||||
content: "";
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
box-sizing: border-box;
|
||||
border: 1.8px solid currentColor;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.search-icon::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 5px;
|
||||
height: 1.8px;
|
||||
background: currentColor;
|
||||
transform: rotate(45deg);
|
||||
right: 0;
|
||||
bottom: 2px;
|
||||
}
|
||||
|
||||
.clear-icon {
|
||||
right: 11px;
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.clear-icon::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 1.8px;
|
||||
background: currentColor;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.clear-icon::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 1.8px;
|
||||
background: currentColor;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.cbr-search-bar:not(:placeholder-shown) ~ .clear-icon {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.cbr-content {
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.cbr-column .CValues {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.CValues label {
|
||||
margin: 0 !important;
|
||||
padding: 1px 0;
|
||||
}
|
||||
|
||||
.cbr-content .cbr-no-items {
|
||||
display: none;
|
||||
color: var(--cbr-label-color);
|
||||
font-size: 12px;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.cbr-content .cbr-no-items.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#AcceptArea {
|
||||
border-top: 1px solid var(--cbr-border-color);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user