diff --git a/README.cn.md b/README.cn.md index 156ee66..9936cc9 100644 --- a/README.cn.md +++ b/README.cn.md @@ -118,6 +118,18 @@ Stable Diffusion Webui 扩展Civitai助手,用于更轻松的管理和使用Ci ![](img/get_one_model_info.jpg) +## 代理 +**如果你是刚更新新版本,你需要重启SD webui再来使用** + +代理输入框在插件页面最下方。 + +**每次填入或清除代理后,都要保存,并用SDwebui设置页面的Reload UI按钮刷新UI** + +然后所有发到civitai的请求就会用代理。 + +依据使用的代理软件不同,有时候,甚至sock5代理, 也要填入http开头的形式"http://xxxxx"才能生效。 + + ## 其他设置 **保存设置按钮, 会保存扫描模型区域,以及其他设置 这两个区域的选项** diff --git a/README.md b/README.md index 1b70bf0..333abcd 100644 --- a/README.md +++ b/README.md @@ -21,10 +21,10 @@ Civitai: [Civitai Url](https://civitai.com/models/16768/civitai-helper-sd-webui- * Checking all your local model's new version from Civitai * Download a new version directly into SD model folder (with info+preview) * Modified Built-in "Extra Network" cards, to add the following buttons on each card: - - 🖼: Modified "replace preview" text into this icon + - 🖼️: Modified "replace preview" text into this icon - 🌐: Open this model's Civitai url in a new tab - 💡: Add this model's trigger words to prompt - - 🏷: Use this model's preview image's prompt + - 🏷️: Use this model's preview image's prompt * Above buttons support thumbnail mode of Extra Network * Option to always show additional buttons, to work with touchscreen. @@ -41,9 +41,13 @@ Done. # How to Use ## Update Your SD Webui -This extension need to get extra network's cards id. **Which is added to SD webui since 2023-02-06.** +* v1.6.x works with SD webui version from 2023-03-25 or later, which uses gradio version 3.23.0 +* v1.5.x works with SD webui version from 2023-02-06 - 2023-03-24. + +**Check your SD webui Page's bottom, "gradio" version number** +* If it is v3.23.0 or later, install v1.6.x. +* If it is v3.16.x, install v1.5.7 from [Civitai](https://civitai.com/models/16768/civitai-helper-sd-webui-civitai-extension) -So, if you are using a version earlier than this, you need to update your SD Webui! ## Scanning Models Go to extension tab "Civitai Helper". There is a button called "Scan model". @@ -128,6 +132,20 @@ After clicking button, extension will download that civitai model's info and pre ![](img/get_one_model_info.jpg) +## Proxy +**If you are updating to new version, you need to re-lanuch SD webui before using it.** + +Proxy textbox is at the bottom of extension tab. + +**Each time you fill or clear a proxy value, you need to save setting, and Re-load UI with setting tab's reload button.** + +Then all requests to civitai will use the proxy. + +Sometime, even sock5 proxy, need to be used as "http://xxxxx", depence on which proxy tool you are using. + + + + ## Other Setting **The Save Setting button, will save both "Scan Model"'s setting and other setting.** @@ -136,6 +154,8 @@ After clicking button, extension will download that civitai model's info and pre ![](img/other_setting.jpg) + + ## Preview Image Extra network uses both `model_file.png` and `model_file.preview.png` as preview image. But `model_file.png` has higher priority, because it is created by yourself. @@ -206,6 +226,12 @@ Since v1.5.5, we've already optimized the SHA256 function to the top. So the onl # Change Log +## v1.6.0 +* Fix some UI issues to work with gradio 3.23.0 +* Support Proxy when connecting to civitai. Check document for detail. +* check realpath when opening file, to fix error when using junction +* Fix multiple addtional buttons issue after switching tabs. + ## v1.5.7 * Fix Localization issue for 4 addtional buttons on cards diff --git a/icon/.keep b/icon/.keep new file mode 100644 index 0000000..e69de29 diff --git a/javascript/civitai_helper.js b/javascript/civitai_helper.js index 0b513e2..b5eb664 100644 --- a/javascript/civitai_helper.js +++ b/javascript/civitai_helper.js @@ -1,5 +1,18 @@ "use strict"; + +function ch_convert_file_path_to_url(path){ + let prefix = "file="; + let path_to_url = path.replaceAll('\\', '/'); + return prefix+path_to_url; +} + +function ch_img_node_str(path){ + return ``; +} + + + // send msg to python side by filling a hidden text box // then will click a button to trigger an action // msg is an object, not a string, will be stringify in this function @@ -73,6 +86,17 @@ const get_new_ch_py_msg = (max_count=3) => new Promise((resolve, reject) => { }) +function getActiveTabType() { + const currentTab = get_uiCurrentTabContent(); + switch (currentTab.id) { + case "tab_txt2img": + return "txt2img"; + case "tab_img2img": + return "img2img"; + } + return null; +} + function getActivePrompt() { @@ -300,12 +324,32 @@ onUiLoaded(() => { let model_type_list = ["textual_inversion", "hypernetworks", "checkpoints", "lora"]; let cardid_suffix = "cards"; + //get init py msg + // let init_py_msg_str = get_ch_py_msg(); + // let extension_path = ""; + // if (!init_py_msg_str) { + // console.log("Can not get init_py_msg"); + // } else { + // init_py_msg = JSON.parse(init_py_msg_str); + // if (init_py_msg) { + // extension_path = init_py_msg.extension_path; + // console.log("get extension path: " + extension_path); + // } + // } + + // //icon image node as string + // function icon(icon_name){ + // let icon_path = extension_path+"/icon/"+icon_name; + // return ch_img_node_str(icon_path); + // } + + // update extra network tab pages' cards // * replace "replace preview" text button into an icon // * add 3 button to each card: // - open model url 🌐 // - add trigger words 💡 - // - use preview image's prompt 🏷 + // - use preview image's prompt 🏷️ // notice: javascript can not get response from python side // so, these buttons just sent request to python // then, python side gonna open url and update prompt text box, without telling js side. @@ -320,7 +364,7 @@ onUiLoaded(() => { let btn_thumb_backgroundImage = "none"; let btn_thumb_background = "rgba(0, 0, 0, 0.8)"; - let ch_btn_txts = ['🌐', '💡', '🏷']; + let ch_btn_txts = ['🌐', '💡', '🏷️']; let replace_preview_text = getTranslation("replace preview"); if (!replace_preview_text) { replace_preview_text = "replace preview"; @@ -354,7 +398,50 @@ onUiLoaded(() => { let cards = null; let need_to_add_buttons = false; let is_thumb_mode = false; + + //get current tab + let active_tab_type = getActiveTabType(); + if (!active_tab_type){active_tab_type = "txt2img";} + for (const tab_prefix of tab_prefix_list) { + if (tab_prefix != active_tab_type) {continue;} + + + //find out current selected model type tab + let active_extra_tab_type = ""; + let extra_tabs = gradioApp().getElementById(tab_prefix+"_extra_tabs"); + if (!extra_tabs) {console.log("can not find extra_tabs: " + tab_prefix+"_extra_tabs");} + //get tab buttons + let extra_tab_btns = extra_tabs.firstChild.querySelectorAll("button"); + console.log("find buttons: " + extra_tab_btns.length); + + for (let extra_tab_btn of extra_tab_btns) { + console.log(extra_tab_btn.innerHTML); + if (extra_tab_btn.className.indexOf("selected") >= 0) { + console.log("found active tab: " + extra_tab_btn.innerHTML); + + switch (extra_tab_btn.innerHTML.trim()) { + case "Textual Inversion": + active_extra_tab_type = "ti"; + break; + case "Hypernetworks": + active_extra_tab_type = "hyper"; + break; + case "Checkpoints": + active_extra_tab_type = "ckp"; + break; + case "Lora": + active_extra_tab_type = "lora"; + break; + } + + break; + + + } + } + + for (const js_model_type of model_type_list) { //get model_type for python side switch (js_model_type) { @@ -377,6 +464,15 @@ onUiLoaded(() => { continue; } + + //only handle current sub-tab + if (model_type != active_extra_tab_type) { + continue; + } + + console.log("handle active extra tab"); + + extra_network_id = tab_prefix+"_"+js_model_type+"_"+cardid_suffix; // console.log("searching extra_network_node: " + extra_network_id); extra_network_node = gradioApp().getElementById(extra_network_id); @@ -470,7 +566,7 @@ onUiLoaded(() => { if (replace_preview_btn) { if (replace_preview_btn.innerHTML == replace_preview_text) { need_to_add_buttons = true; - replace_preview_btn.innerHTML = "🖼"; + replace_preview_btn.innerHTML = "🖼️"; if (!is_thumb_mode) { replace_preview_btn.style.fontSize = btn_fontSize; replace_preview_btn.style.margin = btn_margin; @@ -544,7 +640,7 @@ onUiLoaded(() => { let use_preview_prompt_node = document.createElement("a"); use_preview_prompt_node.href = "#"; - use_preview_prompt_node.innerHTML = "🏷"; + use_preview_prompt_node.innerHTML = "🏷️"; if (!is_thumb_mode) { use_preview_prompt_node.style.fontSize = btn_fontSize; use_preview_prompt_node.style.margin = btn_margin; @@ -582,27 +678,31 @@ onUiLoaded(() => { let tab_id = "" let extra_tab = null; let extra_toolbar = null; + let extra_network_refresh_btn = null; //add refresh button to extra network's toolbar for (let prefix of tab_prefix_list) { tab_id = prefix + "_extra_tabs"; extra_tab = gradioApp().getElementById(tab_id); //get toolbar - extra_toolbar = extra_tab.querySelector("div.flex.border-b-2.flex-wrap"); + //get Refresh button + extra_network_refresh_btn = gradioApp().getElementById(prefix+"_extra_refresh"); - if (!extra_toolbar){ - console.log("can not get extra network toolbar for " + tab_id); + + if (!extra_network_refresh_btn){ + console.log("can not get extra network refresh button for " + tab_id); continue; } // add refresh button to toolbar let ch_refresh = document.createElement("button"); - ch_refresh.innerHTML = "Refresh Civitai Helper"; - ch_refresh.title = "Refresh Civitai Helper's model card buttons"; - ch_refresh.className = "gr-button gr-button-lg gr-button-secondary"; + ch_refresh.innerHTML = "🔁"; + ch_refresh.title = "Refresh Civitai Helper's additional buttons"; + ch_refresh.className = "lg secondary gradio-button"; + ch_refresh.style.fontSize = "200%"; ch_refresh.onclick = update_card_for_civitai; - extra_toolbar.appendChild(ch_refresh); + extra_network_refresh_btn.parentNode.appendChild(ch_refresh); } diff --git a/scripts/ch_lib/__pycache__/civitai.cpython-310.pyc b/scripts/ch_lib/__pycache__/civitai.cpython-310.pyc index 5678474..9659de9 100644 Binary files a/scripts/ch_lib/__pycache__/civitai.cpython-310.pyc and b/scripts/ch_lib/__pycache__/civitai.cpython-310.pyc differ diff --git a/scripts/ch_lib/__pycache__/downloader.cpython-310.pyc b/scripts/ch_lib/__pycache__/downloader.cpython-310.pyc index e90dcf6..6110af6 100644 Binary files a/scripts/ch_lib/__pycache__/downloader.cpython-310.pyc and b/scripts/ch_lib/__pycache__/downloader.cpython-310.pyc differ diff --git a/scripts/ch_lib/__pycache__/model.cpython-310.pyc b/scripts/ch_lib/__pycache__/model.cpython-310.pyc index f8f9ff4..91d6747 100644 Binary files a/scripts/ch_lib/__pycache__/model.cpython-310.pyc and b/scripts/ch_lib/__pycache__/model.cpython-310.pyc differ diff --git a/scripts/ch_lib/__pycache__/setting.cpython-310.pyc b/scripts/ch_lib/__pycache__/setting.cpython-310.pyc index 78c675c..2571e36 100644 Binary files a/scripts/ch_lib/__pycache__/setting.cpython-310.pyc and b/scripts/ch_lib/__pycache__/setting.cpython-310.pyc differ diff --git a/scripts/ch_lib/__pycache__/util.cpython-310.pyc b/scripts/ch_lib/__pycache__/util.cpython-310.pyc index 4bb6cf2..b1a1954 100644 Binary files a/scripts/ch_lib/__pycache__/util.cpython-310.pyc and b/scripts/ch_lib/__pycache__/util.cpython-310.pyc differ diff --git a/scripts/ch_lib/civitai.py b/scripts/ch_lib/civitai.py index 77f64bc..9fad166 100644 --- a/scripts/ch_lib/civitai.py +++ b/scripts/ch_lib/civitai.py @@ -43,7 +43,7 @@ def get_model_info_by_hash(hash:str): util.printD("hash is empty") return - r = requests.get(url_dict["hash"]+hash, headers=util.def_headers) + r = requests.get(url_dict["hash"]+hash, headers=util.def_headers, proxies=util.proxies) if not r.ok: if r.status_code == 404: # this is not a civitai model @@ -80,7 +80,7 @@ def get_model_info_by_id(id:str) -> dict: util.printD("id is empty") return - r = requests.get(url_dict["modelId"]+str(id), headers=util.def_headers) + r = requests.get(url_dict["modelId"]+str(id), headers=util.def_headers, proxies=util.proxies) if not r.ok: if r.status_code == 404: # this is not a civitai model @@ -116,7 +116,7 @@ def get_version_info_by_version_id(id:str) -> dict: util.printD("id is empty") return - r = requests.get(url_dict["modelVersionId"]+str(id), headers=util.def_headers) + r = requests.get(url_dict["modelVersionId"]+str(id), headers=util.def_headers, proxies=util.proxies) if not r.ok: if r.status_code == 404: # this is not a civitai model diff --git a/scripts/ch_lib/downloader.py b/scripts/ch_lib/downloader.py index fa24a5d..8febb7f 100644 --- a/scripts/ch_lib/downloader.py +++ b/scripts/ch_lib/downloader.py @@ -31,7 +31,7 @@ def dl(url, folder, filename, filepath): file_path = os.path.join(folder, filename) # first request for header - rh = requests.get(url, stream=True, verify=False, headers=util.def_headers) + rh = requests.get(url, stream=True, verify=False, headers=util.def_headers, proxies=util.proxies) # get file size total_size = 0 total_size = int(rh.headers['Content-Length']) @@ -79,7 +79,7 @@ def dl(url, folder, filename, filepath): headers['User-Agent'] = util.def_headers['User-Agent'] # download with header - r = requests.get(url, stream=True, verify=False, headers=headers) + r = requests.get(url, stream=True, verify=False, headers=headers, proxies=util.proxies) # write to file with open(dl_file_path, "ab") as f: diff --git a/scripts/ch_lib/model.py b/scripts/ch_lib/model.py index 2052006..729012d 100644 --- a/scripts/ch_lib/model.py +++ b/scripts/ch_lib/model.py @@ -49,14 +49,14 @@ def get_custom_model_folder(): # write model info to file def write_model_info(path, model_info): util.printD("Write model info to file: " + path) - with open(path, 'w') as f: + with open(os.path.realpath(path), 'w') as f: f.write(json.dumps(model_info, indent=4)) def load_model_info(path): # util.printD("Load model info from file: " + path) model_info = None - with open(path, 'r') as f: + with open(os.path.realpath(path), 'r') as f: try: model_info = json.load(f) except Exception as e: diff --git a/scripts/ch_lib/setting.py b/scripts/ch_lib/setting.py index b70bad1..aabff85 100644 --- a/scripts/ch_lib/setting.py +++ b/scripts/ch_lib/setting.py @@ -18,6 +18,7 @@ data = { "open_url_with_js": True, "always_display": False, "show_btn_on_thumb": True, + "proxy": "", }, "tool":{ } @@ -79,11 +80,14 @@ def load(): if "show_btn_on_thumb" not in data["general"].keys(): data["general"]["show_btn_on_thumb"] = True + if "proxy" not in data["general"].keys(): + data["general"]["proxy"] = "" + return # save setting from parameter -def save_from_input(max_size_preview, skip_nsfw_preview, open_url_with_js, always_display, show_btn_on_thumb): +def save_from_input(max_size_preview, skip_nsfw_preview, open_url_with_js, always_display, show_btn_on_thumb, proxy): global data data = { "model":{ @@ -94,6 +98,7 @@ def save_from_input(max_size_preview, skip_nsfw_preview, open_url_with_js, alway "open_url_with_js": open_url_with_js, "always_display": always_display, "show_btn_on_thumb": show_btn_on_thumb, + "proxy": proxy, }, "tool":{ } diff --git a/scripts/ch_lib/util.py b/scripts/ch_lib/util.py index c1a233e..28cc4f4 100644 --- a/scripts/ch_lib/util.py +++ b/scripts/ch_lib/util.py @@ -5,11 +5,15 @@ import hashlib import requests import shutil -version = "1.5.7" + +version = "1.6.0" def_headers = {'User-Agent': 'Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148'} +proxies = None + + # print for debugging def printD(msg): print(f"Civitai Helper: {msg}") @@ -29,7 +33,7 @@ def gen_file_sha256(filname): blocksize=1 << 20 h = hashlib.sha256() length = 0 - with open(filname, 'rb') as f: + with open(os.path.realpath(filname), 'rb') as f: for block in read_chunks(f, size=blocksize): length += len(block) h.update(block) @@ -39,33 +43,20 @@ def gen_file_sha256(filname): printD("length: " + str(length)) return hash_value -# def gen_file_sha256(filname): -# printD("Calculate SHA256") -# # force to use Memory Optimized SHA256 -# # In case people don't understand this and uncheck it then stuck their system -# printD("Using Memory Optimized SHA256") -# hash_sha256 = hashlib.sha256() -# with open(filname, "rb") as f: -# for chunk in iter(lambda: f.read(4096), b""): -# hash_sha256.update(chunk) - -# hash_value = hash_sha256.hexdigest() -# printD("sha256: " + hash_value) -# return hash_value # get preview image def download_file(url, path): printD("Downloading file from: " + url) # get file - r = requests.get(url, stream=True, headers=def_headers) + r = requests.get(url, stream=True, headers=def_headers, proxies=proxies) if not r.ok: printD("Get error code: " + str(r.status_code)) printD(r.text) return # write to file - with open(path, 'wb') as f: + with open(os.path.realpath(path), 'wb') as f: r.raw.decode_content = True shutil.copyfileobj(r.raw, f) @@ -93,3 +84,22 @@ def get_subfolders(folder:str) -> list: return subfolders + +# get relative path +def get_relative_path(item_path:str, parent_path:str) -> str: + # printD("item_path:"+item_path) + # printD("parent_path:"+parent_path) + # item path must start with parent_path + if not item_path: + return "" + if not parent_path: + return "" + if not item_path.startswith(parent_path): + return item_path + + relative = item_path[len(parent_path):] + if relative[:1] == "/" or relative[:1] == "\\": + relative = relative[1:] + + # printD("relative:"+relative) + return relative \ No newline at end of file diff --git a/scripts/civitai_helper.py b/scripts/civitai_helper.py index 8419d1c..3c2f6fd 100644 --- a/scripts/civitai_helper.py +++ b/scripts/civitai_helper.py @@ -26,13 +26,35 @@ from scripts.ch_lib import util # init + +# root path +root_path = os.getcwd() + +# extension path +extension_path = scripts.basedir() + model.get_custom_model_folder() setting.load() +# set proxy +if setting.data["general"]["proxy"]: + util.printD("Set Proxy: "+setting.data["general"]["proxy"]) + util.proxies = { + "http": setting.data["general"]["proxy"], + "https": setting.data["general"]["proxy"], + } + + def on_ui_tabs(): # init + # init_py_msg = { + # # relative extension path + # "extension_path": util.get_relative_path(extension_path, root_path), + # } + # init_py_msg_str = json.dumps(init_py_msg) + # get prompt textarea # check modules/ui.py, search for txt2img_paste_fields @@ -62,8 +84,8 @@ def on_ui_tabs(): return [model_info, model_name, model_type, dl_subfolder_drop.update(choices=subfolders), dl_version_drop.update(choices=version_strs)] # ====UI==== - # with gr.Blocks(analytics_enabled=False) as civitai_helper: - with gr.Blocks(css="button {background-color: #228be6}") as civitai_helper: + with gr.Blocks(analytics_enabled=False) as civitai_helper: + # with gr.Blocks(css=".block.padded {padding: 10px !important}") as civitai_helper: # init max_size_preview = setting.data["model"]["max_size_preview"] @@ -71,6 +93,7 @@ def on_ui_tabs(): open_url_with_js = setting.data["general"]["open_url_with_js"] always_display = setting.data["general"]["always_display"] show_btn_on_thumb = setting.data["general"]["show_btn_on_thumb"] + proxy = setting.data["general"]["proxy"] model_types = list(model.folders.keys()) no_info_model_names = civitai.get_model_names_by_input("ckp", False) @@ -80,8 +103,7 @@ def on_ui_tabs(): - # with gr.Tab("Model"): - with gr.Box(): + with gr.Box(elem_classes="ch_box"): with gr.Column(): gr.Markdown("### Scan Models for Civitai") with gr.Row(): @@ -95,20 +117,20 @@ def on_ui_tabs(): scan_model_log_md = gr.Markdown(value="Scanning takes time, just wait. Check console log for detail", elem_id="ch_scan_model_log_md") - with gr.Box(): + with gr.Box(elem_classes="ch_box"): with gr.Column(): gr.Markdown("### Get Model Info from Civitai by URL") gr.Markdown("Use this when scanning can not find a local model on civitai") with gr.Row(): model_type_drop = gr.Dropdown(choices=model_types, label="Model Type", value="ckp", multiselect=False) - empty_info_only_ckb = gr.Checkbox(label="Only Show Models have no Info", value=False, elem_id="cn_empty_info_only_ckb") + empty_info_only_ckb = gr.Checkbox(label="Only Show Models have no Info", value=False, elem_id="cn_empty_info_only_ckb", elem_classes="ch_vpadding") model_name_drop = gr.Dropdown(choices=no_info_model_names, label="Model", value="ckp", multiselect=False) model_url_or_id_txtbox = gr.Textbox(label="Civitai URL", lines=1, value="") get_civitai_model_info_by_id_btn = gr.Button(value="Get Model Info from Civitai", variant="primary") get_model_by_id_log_md = gr.Markdown("") - with gr.Box(): + with gr.Box(elem_classes="ch_box"): with gr.Column(): gr.Markdown("### Download Model") with gr.Row(): @@ -125,7 +147,7 @@ def on_ui_tabs(): dl_civitai_model_by_id_btn = gr.Button(value="3. Download Model", variant="primary") dl_log_md = gr.Markdown(value="Check Console log for Downloading Status") - with gr.Box(): + with gr.Box(elem_classes="ch_box"): with gr.Column(): gr.Markdown("### Check models' new version") with gr.Row(): @@ -134,7 +156,7 @@ def on_ui_tabs(): check_models_new_version_log_md = gr.HTML("It takes time, just wait. Check console log for detail") - with gr.Box(): + with gr.Box(elem_classes="ch_box"): with gr.Column(): gr.Markdown("### Other Setting") with gr.Row(): @@ -142,6 +164,8 @@ def on_ui_tabs(): always_display_ckb = gr.Checkbox(label="Always Display Buttons", value=always_display, elem_id="ch_always_display_ckb") show_btn_on_thumb_ckb = gr.Checkbox(label="Show Button On Thumb Mode", value=show_btn_on_thumb, elem_id="ch_show_btn_on_thumb_ckb") + proxy_txtbox = gr.Textbox(label="Proxy", interactive=True, lines=1, value=proxy, info="format: http://127.0.0.1:port") + save_setting_btn = gr.Button(value="Save Setting") general_log_md = gr.Markdown(value="") @@ -176,7 +200,7 @@ def on_ui_tabs(): check_models_new_version_btn.click(model_action_civitai.check_models_new_version_to_md, inputs=model_types_ckbg, outputs=check_models_new_version_log_md) # Other Setting - save_setting_btn.click(setting.save_from_input, inputs=[max_size_preview_ckb, skip_nsfw_preview_ckb, open_url_with_js_ckb, always_display_ckb, show_btn_on_thumb_ckb], outputs=general_log_md) + save_setting_btn.click(setting.save_from_input, inputs=[max_size_preview_ckb, skip_nsfw_preview_ckb, open_url_with_js_ckb, always_display_ckb, show_btn_on_thumb_ckb, proxy_txtbox], outputs=general_log_md) # js action js_open_url_btn.click(js_action_civitai.open_model_url, inputs=[js_msg_txtbox, open_url_with_js_ckb], outputs=py_msg_txtbox) @@ -190,3 +214,4 @@ def on_ui_tabs(): script_callbacks.on_ui_tabs(on_ui_tabs) + diff --git a/style.css b/style.css index 91a62ea..387156e 100644 --- a/style.css +++ b/style.css @@ -7,3 +7,12 @@ blockquote ol { list-style:decimal; margin:4px 40px; } + +.block.padded.ch_box { + padding: 10px !important; +} + +.block.padded.ch_vpadding { + padding: 10px 0 !important; +} +