diff --git a/AvocadoEdition_Light/README.md b/AvocadoEdition_Light/README.md deleted file mode 100644 index c823d04..0000000 --- a/AvocadoEdition_Light/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# AvocadoEdition -아보카도 에디션 코어 파일 - ------------------------------ - -해당 경로에 있는 파일들을 설치할 Root 디렉토리에 업로드해주세요. -자세한 설치 방법은 https://github.com/tateck-develop/AvocadoEdition/wiki 이곳을 참고해 주시길 바랍니다. - ------------------------------ - -2022.04.24 : enter.php 파일 44번 라인 css 연결 경로 수정 \ No newline at end of file diff --git a/AvocadoEdition_Light/_common.php b/AvocadoEdition_Light/_common.php index 1357c56..2f770cf 100644 --- a/AvocadoEdition_Light/_common.php +++ b/AvocadoEdition_Light/_common.php @@ -1,2 +1,2 @@ img { + width: 300px; + height: 225px; +} + +#theme_list li .tmli_if:hover>img { + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; + filter: alpha(opacity=50); + -moz-opacity: 0.5; + -khtml-opacity: 0.5; + opacity: 0.5; +} + +#theme_list li .tmli_tit { + position: relative; + border-top: 1px solid #d1dee2; + background: #e5ecef; +} + +#theme_list li .tmli_tit p { + height: 40px; + line-height: 40px; + padding: 0 10px 0; + font-weight: bold; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + +#theme_list li .tmli_tit button.tmli_dt { + position: absolute; + top: 8px; + right: 10px; + padding: 5px; + background: #111; + color: #fff; + display: none; + border: none +} + +#theme_list li .tmli_if:hover button.tmli_dt { + display: block +} + +#theme_list li .theme_sl { + float: left; + border: none; + margin-top: 5px; + padding: 0 5px; + height: 26px; + background: #999; + color: #fff +} + +#theme_list li .theme_sl:hover { + background: #ff3061 +} + +#theme_list li .theme_deactive { + margin-left: 4px +} + +#theme_list li .theme_sl_use { + background: #ff3061; + line-height: 26px +} + +#theme_list li .theme_pr { + float: right; + margin-top: 5px; + padding: 0 5px; + height: 26px; + line-height: 24px; + border: 1px solid #ccc; + background: #fafafa; +} + +#theme_list li .theme_preview { + float: right; + margin-top: 5px; + padding: 0 5px; + height: 26px; + border: 1px solid #ccc; + background: #fafafa; + margin-right: 3px +} + +#theme_detail { + position: fixed; + top: 50%; + height: 540px; + width: 900px; + margin-top: -271px; + background: #fff; + background: #f3f3f3; + border: 1px solid #000; + -webkit-box-shadow: 1px 2px 5px rgba(150, 150, 150, 100.5); + -moz-box-shadow: 1px 2px 5px rgba(150, 150, 150, 0.5); + box-shadow: 1px 2px 5px rgba(150, 150, 150, 0.5); + z-index: 1000 +} + +#theme_detail:after { + display: block; + visibility: hidden; + clear: both; + content: "" +} + +#theme_detail h2 { + font-size: 1.25em; + background: #fff; + padding: 0 15px; + line-height: 40px; + border-bottom: 1px solid #d8d8d8; + margin: 0 +} + +.theme_dt_img { + float: left; + padding: 20px +} + +.theme_dt_img img { + border: 1px solid #aaa; +} + +.theme_dt_if { + float: left; + width: 235px; + padding: 20px 0 +} + +.theme_dt_if table { + width: 100%; + border-collapse: collapse; + margin: 15px 0 0; + font-size: 0.92em +} + +.theme_dt_if table th { + padding: 5px; + background: #fff; + border-bottom: 1px solid #f3f3f3; + vertical-align: top; + color: #3f51b5 +} + +.theme_dt_if table td { + padding: 5px; + background: #fff; + border-bottom: 1px solid #f3f3f3; + line-height: 1.56em +} + +.theme_dt_if table td a { + text-decoration: underline +} + +.theme_dt_if p { + line-height: 1.5em +} + +.if_p_bg { + display: inline-block; + width: 20px; + height: 1px; + background: #000; + margin: 30px 0 10px +} + +#theme_detail .theme_dt_btn { + position: absolute; + top: 0px; + right: 0px; + background: #fff; +} + +#theme_detail .theme_dt_btn .close_btn { + border: 0; + border-left: 1px solid #d8d8d8; + background: url('../img/close.png') 50% 50% no-repeat; + width: 40px; + height: 40px; + overflow: hidden; + text-indent: -99999px +} + +#theme_detail .theme_dt_btn .close_btn:hover { + background-color: #eceffc +} + +#theme_detail .theme_dt_btn .btn_03 { + line-height: 28px; + display: inline-block; + vertical-align: top; + margin-top: 6px; + padding: 0 6px; + border-radius: 5px +} diff --git a/AvocadoEdition_Light/adm/css/admin.layout.css b/AvocadoEdition_Light/adm/css/admin.layout.css index dee126c..25761e5 100644 --- a/AvocadoEdition_Light/adm/css/admin.layout.css +++ b/AvocadoEdition_Light/adm/css/admin.layout.css @@ -5,7 +5,9 @@ body { height: 100%; } -#wrap {} +#wrap { + display: block; +} #header { display: block; @@ -16,7 +18,6 @@ body { width: 200px; min-height: 100%; background: #1d1d1f; - vertical-align: top; z-index: 999; } diff --git a/AvocadoEdition_Light/adm/css/amberstone.cp.css b/AvocadoEdition_Light/adm/css/amberstone.cp.css new file mode 100644 index 0000000..f517c0f --- /dev/null +++ b/AvocadoEdition_Light/adm/css/amberstone.cp.css @@ -0,0 +1,216 @@ +.amber-color-picker { + border: 1px solid #E8E7E0; + background: #FFFFFF; + border-radius: 2px; + line-height: 24px; + min-height: 24px; + min-width: 200px; + display: inline-block; + position: relative; +} + +.amber-color-picker>input { + border: 0; + width: 100%; + height: 100%; + position: absolute; + left: 0; + top: 0; + box-sizing: border-box; + padding: 0 8px 0 24px; + background: transparent; +} + +.amber-color-picker>.neo-preview { + pointer-events: none; + position: absolute; + left: 4px; + top: 4px; + height: 16px; + width: 16px; + border: 1px solid #0004; + box-sizing: border-box; + background: #FFF; + border-radius: 2px; + background-image: + linear-gradient(45deg, #ccc 25%, transparent 25%), + linear-gradient(-45deg, #ccc 25%, transparent 25%), + linear-gradient(45deg, transparent 75%, #ccc 75%), + linear-gradient(-45deg, transparent 75%, #ccc 75%); + background-size: 14px 14px; + background-position: 0 0, 0 7px, 7px -7px, -7px 0; +} + +.amber-color-picker>.neo-preview::before { + content: ""; + position: absolute; + left: 0; + right: 0; + bottom: 0; + top: 0; + background: var(--background); +} + +.amber-color-picker>.amber-palette { + z-index: 10000; + background: #FFF; + position: absolute; + left: -1px; + top: 26px; + padding: 8px; + border-radius: 4px; + border: 1px solid #E8E7E0; + box-shadow: 0 1px 1px #0004; + display: flex; + flex-direction: column; + gap: 2px; +} + +.amber-color-picker>.amber-palette>.amber-inner { + width: 100%; + height: 100%; + flex-grow: 1; + display: flex; + gap: 2px; +} + +.amber-color-picker>.amber-palette::before { + content:"Amber Color Picker :: Author: Arcturus"; + font-size: 8px; + color: #CCC; + right: 8px; + bottom: 0px; + line-height: 8px; + position: absolute; +} + +.amber-color-picker>.amber-palette>.amber-inner>.amber-palette-area { + position: relative; + width: 200px; + height: 200px; + border: 1px solid #E8E7E0; + cursor: crosshair; +} + +.amber-color-picker>.amber-palette>.amber-inner>.amber-palette-area::before { + content: ""; + position:absolute; + left: 0; + right: 0; + bottom: 0; + top: 0; + background: linear-gradient(to bottom, transparent, #000); + pointer-events: none; +} + +.amber-color-picker>.amber-palette>.amber-inner>.amber-palette-area>div { + position: absolute; + pointer-events: none; + height: 11px; + width: 11px; + border-radius: 50%; + border:2px solid #fff; + box-sizing: border-box; + box-shadow: 0 0 2px #000; + margin-left: -7px; + margin-top: -7px +} + +.amber-color-picker>.amber-palette>.amber-inner>.amber-hue-area { + border: 1px solid #E8E7E0; + width: 16px; + height: 200px; + position: relative; + background: linear-gradient(to bottom, red 0%, magenta 16.67%, blue 33.34%, cyan 50%, lime 66.67%, yellow 83.33%, red 100%); + cursor:ns-resize; +} + +.amber-color-picker>.amber-palette>.amber-inner>.amber-hue-area>div { + position: absolute; + pointer-events: none; + margin-left: -1px; + margin-top: -3px; + width: 100%; + height:2px; + border:2px solid #FFF; + border-width: 2px 1px 2px 1px; + box-shadow: 0 0 2px #000; +} + +.amber-color-picker>.amber-palette>.amber-inner>.amber-alpha-area { + border: 1px solid #E8E7E0; + width: 16px; + height: 200px; + position: relative; + cursor:ns-resize; + background-image: + linear-gradient(45deg, #ccc 25%, transparent 25%), + linear-gradient(-45deg, #ccc 25%, transparent 25%), + linear-gradient(45deg, transparent 75%, #ccc 75%), + linear-gradient(-45deg, transparent 75%, #ccc 75%); + background-size: 16px 16px; + background-position: 0 0, 0 8px, 8px -8px, -8px 0; +} + +.amber-color-picker>.amber-palette>.amber-inner>.amber-alpha-area::before { + content: ""; + position: absolute; + pointer-events: none; + left: 0; + top: 0; + right: 0; + bottom: 0; + background: var(--background); +} + +.amber-color-picker>.amber-palette>.amber-inner>.amber-alpha-area>div { + position: absolute; + pointer-events: none; + margin-left: -1px; + margin-top: -3px; + width: 100%; + height:2px; + border:2px solid #FFF; + border-width: 2px 1px 2px 1px; + box-shadow: 0 0 2px #000; +} + +.amber-color-picker>.amber-palette>.amber-inner>.amber-recent-color { + display: grid; + position: relative; + border: 1px solid #E8E7E0; + grid-template-columns: repeat(5, 1fr); + grid-template-rows: repeat(9, 1fr); + width: calc(21px * 5 - 1); + gap: 1px; + align-items: start; + padding: 1px; +} + +.amber-color-picker>.amber-palette>.amber-inner>.amber-recent-color>div { + border: 1px solid #E8E7E0; + box-sizing: border-box; + width: 20px; + height: 20px; + border-radius: 3px; + overflow: hidden; + position: relative; + background-image: + linear-gradient(45deg, #ccc 25%, transparent 25%), + linear-gradient(-45deg, #ccc 25%, transparent 25%), + linear-gradient(45deg, transparent 75%, #ccc 75%), + linear-gradient(-45deg, transparent 75%, #ccc 75%); + background-size: 16px 16px; + background-position: 0 0, 0 8px, 8px -8px, -8px 0; +} + +.amber-color-picker>.amber-palette>.amber-inner>.amber-recent-color>div::before { + content: ""; + position: absolute; + pointer-events: none; + left: 0; + top: 0; + right: 0; + bottom: 0; + background: var(--background); +} diff --git a/AvocadoEdition_Light/adm/css/guide.css b/AvocadoEdition_Light/adm/css/guide.css index b0056f9..d7b8dac 100644 --- a/AvocadoEdition_Light/adm/css/guide.css +++ b/AvocadoEdition_Light/adm/css/guide.css @@ -88,7 +88,7 @@ h1 { top: 50%; white-space: nowrap; transform: translateY(-50%); - -webkit=transform: translateY(-50%); + -webkit-transform: translateY(-50%); } .admin-preview-box .ui-btn { diff --git a/AvocadoEdition_Light/adm/css/theme.css b/AvocadoEdition_Light/adm/css/theme.css index a4a9ebc..2f86862 100644 --- a/AvocadoEdition_Light/adm/css/theme.css +++ b/AvocadoEdition_Light/adm/css/theme.css @@ -31,7 +31,7 @@ body { height: 50px; line-height: 50px; padding: 0 3px; - *display: inline; + display: inline; zoom: 1; } diff --git a/AvocadoEdition_Light/adm/js/amberstone.cp.js b/AvocadoEdition_Light/adm/js/amberstone.cp.js new file mode 100644 index 0000000..b2e2d45 --- /dev/null +++ b/AvocadoEdition_Light/adm/js/amberstone.cp.js @@ -0,0 +1,633 @@ + +class ColorPicker { + constructor(wrapper) { + this.pointerDrag = false; + this.hueDrag = false; + this.opacityDrag = false; + + this.currentSaturation = 0; + this.currentValue = 0; + this.currentHue = 0; + this.currentAlpha = 1; + this.currentX; + this.currentY; + this.initialX; + this.initialY; + this.xOffset = 0; + this.yOffset = 0; + // this.element = wrapper; + this.wrapper = createElement("div", { + classList: ["amber-color-picker"] + }); + this.preview = createElement("div", { + classList: ["neo-preview"] + }); + this.input = createElement("input", { + + }); + this.dialog = createElement("div", { + classList: ["amber-palette"], + css: { + display: "none" + } + }); + this.inner = createElement("div", { + classList: ["amber-inner"] + }); + this.palette_area = createElement("div", { + classList: ["amber-palette-area"] + }); + this.palette_pointer = createElement("div", { + + }); + this.hue_area = createElement("div", { + classList: ["amber-hue-area"] + }); + this.hue_pointer = createElement("div", { + + }); + this.alpha_area = createElement("div", { + classList: ["amber-alpha-area"] + }); + this.alpha_pointer = createElement("div", { + + }); + this.desc = createElement("div", { + innerHTML: "rgb(0,0,0), rgba(0,0,0,0) 등 css 에서 지원하는 색상 형식 입력 가능", + css: { + "color":"#A0A0A0", + "font-size":"9px", + "line-height":"16px", + "padding": "4px" + } + }); + this.recentcolor = createElement("div", { + classList: ["amber-recent-color"] + }); + this.palette_area.appendChild(this.palette_pointer); + this.hue_area.appendChild(this.hue_pointer); + this.alpha_area.appendChild(this.alpha_pointer); + this.inner.appendChild(this.palette_area); + this.inner.appendChild(this.hue_area); + this.inner.appendChild(this.alpha_area); + this.inner.appendChild(this.recentcolor); + this.dialog.appendChild(this.inner); + this.dialog.appendChild(this.desc); + this.wrapper.appendChild(this.input); + this.wrapper.appendChild(this.preview); + this.wrapper.appendChild(this.dialog); + for (let j = 0; j < wrapper.attributes.length; j++) { + const attr = wrapper.attributes[j]; + if (attr.name == "class") continue; + this.input.setAttribute(attr.name, attr.value); + } + wrapper.parentNode.replaceChild(this.wrapper, wrapper); + this.input.addEventListener("change", (evt) => { + this.procEvent(evt, true); + }); + this.input.addEventListener("keyup", (evt) => { + this.procEvent(evt); + }); + this.input.addEventListener("focus", (evt) => { + this.openDialog(); + }); + this.palette_area.addEventListener("mousedown", (evt) => { + this.pointerDrag = true; + this.movePointer(evt); + }); + this.hue_area.addEventListener("mousedown", (evt) => { + this.hueDrag = true; + this.moveHue(evt); + }); + this.alpha_area.addEventListener("mousedown", (evt) => { + this.opacityDrag = true; + this.moveAlpha(evt); + }); + window.addEventListener("mouseup", (evt) => { + this.pointerDrag = false; + this.hueDrag = false; + this.opacityDrag = false; + }); + window.addEventListener("mousemove", (evt) => { + this.movePointer(evt); + this.moveHue(evt); + this.moveAlpha(evt); + }); + this.init(); + } + + init() { + this.checkFocusLeave(() => { + this.dialog.style.setProperty('display', 'none'); + this.addPaletteColor(this.input.value); + }); + this.regex = /[ㅁㅠㅊㅇㄷㄹ]/g; + this.replacementMap = { + 'ㅁ': 'a', + 'ㅠ': 'b', + 'ㅊ': 'c', + 'ㅇ': 'd', + 'ㄷ': 'e', + 'ㄹ': 'f' + }; + this.setColor(1); + this.getSavedPalette(); + } + + getSavedPalette() { + const d = localStorage.getItem('amber-palette'); + if (d) { + try { + this.saved_palette = JSON.parse(d); + this.prepareSavedPalette(); + } catch(ex) { + console.error(ex); + } + } else { + this.saved_palette = []; + localStorage.setItem('amber-palette', JSON.stringify([])); + } + } + + addPaletteColor(color) { + const index = this.saved_palette.indexOf(color.toLowerCase()); + if (index > -1) { + this.saved_palette.splice(index, 1); + } + this.saved_palette.unshift(color.toLowerCase()); + if (this.saved_palette.length > 45) { + this.saved_palette.pop(); + } + localStorage.setItem('amber-palette', JSON.stringify(this.saved_palette)); + } + + prepareSavedPalette() { + this.recentcolor.innerHTML = ""; + for(const e of this.saved_palette) { + const col = createElement("div", { + css: { + "--background": e + }, + attributes: { + title: e + } + }); + col.addEventListener("click", (evt) => { + this.input.value = e; + this.setColor(1); + }); + this.recentcolor.appendChild(col); + } + } + + openDialog() { + this.dialog.style.setProperty('display', 'flex'); + this.getSavedPalette(); + } + + movePointer(evt) { + if (this.pointerDrag) { + evt.preventDefault(); + let rect = this.palette_area.getBoundingClientRect(); + let cstyle = getComputedStyle(this.palette_area); + let newX = evt.clientX - rect.left; + let newY = evt.clientY - rect.top; + newX = Math.max(0, Math.min(parseInt(cstyle.width), newX)); + newY = Math.max(0, Math.min(parseInt(cstyle.height), newY)); + + this.currentSaturation = newX / parseInt(cstyle.width); + this.currentValue = 1 - (newY / parseInt(cstyle.height)); + + const newRgb = this.hsvToRgba(this.currentHue, this.currentSaturation, this.currentValue); + + this.input.value = this.rgbToHex(newRgb.r, newRgb.g, newRgb.b) + (Math.max(0, Math.min(255, Math.floor(this.currentAlpha * 255)))).toString(16).padStart(2, '0'); + this.setColor(); + this.currentX = newX; + this.currentY = newY; + this.setTranslate(this.currentX, this.currentY, this.palette_pointer); + } + } + + moveHue(evt) { + if (this.hueDrag) { + evt.preventDefault(); + let rect = this.hue_area.getBoundingClientRect(); + let cstyle = getComputedStyle(this.hue_area); + let newY = evt.clientY - rect.top; + const my = parseInt(cstyle.height); + newY = Math.max(0, Math.min(my, newY)); + + this.currentHue = (1 - (newY / my)) * 360; + + const newRgb = this.hsvToRgba(this.currentHue, this.currentSaturation, this.currentValue); + + this.input.value = this.rgbToHex(newRgb.r, newRgb.g, newRgb.b) + (Math.max(0, Math.min(255, Math.floor(this.currentAlpha * 255)))).toString(16).padStart(2, '0'); + + this.setColor(); + this.setTranslateY(newY, this.hue_pointer); + } + } + + moveAlpha(evt) { + if (this.opacityDrag) { + evt.preventDefault(); + let rect = this.alpha_area.getBoundingClientRect(); + let cstyle = getComputedStyle(this.alpha_area); + let newY = evt.clientY - rect.top; + const my = parseInt(cstyle.height); + newY = Math.max(0, Math.min(my, newY)); + + this.currentAlpha = 1 - Math.min(1, Math.max(0, newY / my)); + + const newRgb = this.hsvToRgba(this.currentHue, this.currentSaturation, this.currentValue); + + this.input.value = this.rgbToHex(newRgb.r, newRgb.g, newRgb.b) + (Math.max(0, Math.min(255, Math.floor(this.currentAlpha * 255)))).toString(16).padStart(2, '0'); + + this.setColor(); + this.setTranslateY(newY, this.alpha_pointer); + } + } + + setTranslate(xPos, yPos, el) { + el.style.transform = `translate3d(${xPos}px, ${yPos}px, 0)`; + } + + setTranslateY(yPos, el) { + el.style.transform = `translateY(${yPos}px)`; + } + + checkFocusLeave(callback) { + const self = this; + function isFocusInside(elem) { + return self.wrapper.contains(elem == undefined ? document.activeElement : elem); + } + + let wasFocusInside = isFocusInside(); + + document.addEventListener('focusin', checkFocus); + document.addEventListener('mousedown', checkFocus); + document.addEventListener('touchstart', checkFocus); + + function checkFocus(event) { + setTimeout(() => { + const isFocusInsideNow = isFocusInside(event.target); + if (wasFocusInside && !isFocusInsideNow) { + callback(); + } + + wasFocusInside = isFocusInsideNow; + }, 0); + } + + return function cleanup() { + document.removeEventListener('focusin', checkFocus); + document.removeEventListener('mousedown', checkFocus); + document.removeEventListener('touchstart', checkFocus); + }; + } + + setColor(c) { + const val = this.procInput(this.input.value); + if (val) { + if (c) { + const tar = this.rgbToHsv(val.r, val.g, val.b); + this.currentHue = tar.h; + this.currentSaturation = tar.s; + this.currentValue = tar.v; + this.currentAlpha = val.a; + } + + const t1 = this.hsvToRgba(this.currentHue, 0, 1, 1); + const t2 = this.hsvToRgba(this.currentHue, 1, 1, 1); + + let cstyle = getComputedStyle(this.palette_area); + + if (c) { + const hsv = this.rgbToHsv(val.r, val.g, val.b); + const mx = parseInt(cstyle.width); + const my = parseInt(cstyle.height); + const x = Math.min(mx, Math.max(0, (mx * hsv.s))); + const y = Math.min(my, Math.max(0, my - (my * hsv.v))); + this.setTranslate(x, y, this.palette_pointer); + this.setTranslateY(my - ((hsv.h / 360) * my), this.hue_pointer); + this.setTranslateY(my - (this.currentAlpha * my), this.alpha_pointer); + } + + this.palette_area.style.background = `linear-gradient(to right, rgb(${t1.r},${t1.g},${t1.b}), rgb(${t2.r},${t2.g},${t2.b}))`; + this.preview.style.setProperty('--background', `rgba(${val.r},${val.g},${val.b},${val.a.toFixed(2)})`); + this.alpha_area.style.setProperty('--background', `linear-gradient(to bottom, rgba(${val.r},${val.g},${val.b},1), rgba(${val.r},${val.g},${val.b},0))`); + } + } + + procEvent(evt, validate = false) { + const cursorPosition = this.input.selectionStart; + const val = this.procInput(this.input.value); + if (val) { + this.setColor(1); + } + if (validate) { + if (val) { + this.wrapper.style.setProperty('background', '#FFFFFF'); + this.wrapper.style.setProperty('border-color', '#F2F2F0'); + if (val.type == "hex") { + if (this.input.value[0] != '#') { + this.input.value = `#${this.input.value}`; + } + } + this.addPaletteColor(this.input.value); + } else { + this.wrapper.style.setProperty('background', '#FFDDDD'); + this.wrapper.style.setProperty('border-color', '#EEA0A0'); + } + } + } + + procInput(input) { + input = input.replace(/\s/g, ''); + + // RGB and RGBA + let match = input.match(/^rgba?\((\d+),(\d+),(\d+)(?:,([\d.]+))?\)$/); + if (match) { + return { + r: parseInt(match[1]), + g: parseInt(match[2]), + b: parseInt(match[3]), + a: match[4] ? parseFloat(match[4]) : 1, + type: "rgb/rgba" + }; + } + + // HSV and HSVA + match = input.match(/^hsva?\((\d+),(\d+)%,(\d+)%(?:,([\d.]+))?\)$/); + if (match) { + let h = parseInt(match[1]) / 360; + let s = parseInt(match[2]) / 100; + let v = parseInt(match[3]) / 100; + let a = match[4] ? parseFloat(match[4]) : 1; + return hsvToRgb(h, s, v, a); + } + + // HSL and HSLA + match = input.match(/^hsla?\((\d+),(\d+)%,(\d+)%(?:,([\d.]+))?\)$/); + if (match) { + let h = parseInt(match[1]) / 360; + let s = parseInt(match[2]) / 100; + let l = parseInt(match[3]) / 100; + let a = match[4] ? parseFloat(match[4]) : 1; + return hslToRgb(h, s, l, a); + } + + // HWB + match = input.match(/^hwb\((\d+),(\d+)%,(\d+)%(?:,([\d.]+))?\)$/); + if (match) { + let h = parseInt(match[1]) / 360; + let w = parseInt(match[2]) / 100; + let b = parseInt(match[3]) / 100; + let a = match[4] ? parseFloat(match[4]) : 1; + return hwbToRgb(h, w, b, a); + } + + // LAB + match = input.match(/^lab\((\d+)%,([-\d.]+),([-\d.]+)(?:,([\d.]+))?\)$/); + if (match) { + let l = parseInt(match[1]); + let a = parseFloat(match[2]); + let b = parseFloat(match[3]); + let alpha = match[4] ? parseFloat(match[4]) : 1; + return labToRgb(l, a, b, alpha); + } + + // LCH + match = input.match(/^lch\((\d+)%,([-\d.]+),([-\d.]+)(?:,([\d.]+))?\)$/); + if (match) { + let l = parseInt(match[1]); + let c = parseFloat(match[2]); + let h = parseFloat(match[3]); + let alpha = match[4] ? parseFloat(match[4]) : 1; + return lchToRgb(l, c, h, alpha); + } + + // If no match found, return null + return this.procHexRgba(input); + } + + procHexRgba(input) { + input = input.replace(/^#/, ''); + if (input.length != 4 && input.length != 8 && input.length != 3 && input.length != 6) { + return null; + } + + if (input.length == 3) { + let val = `${input[0]}${input[0]}${input[1]}${input[1]}${input[2]}${input[2]}`; + let rgb = this.hexToRgb(val); + + return { r: rgb.r, g: rgb.g, b: rgb.b, a: 1, type: "hex" }; + } else if (input.length == 4) { + let val = `${input[0]}${input[0]}${input[1]}${input[1]}${input[2]}${input[2]}`; + let rgb = this.hexToRgb(`${input[0]}${input[0]}${input[1]}${input[1]}${input[2]}${input[2]}`); + let alpha = parseInt(`${input[3]}${input[3]}`, 16); + + return { r: rgb.r, g: rgb.g, b: rgb.b, a: alpha / 255, type: "hex" }; + } else if (input.length == 6) { + let rgb = this.hexToRgb(input.substring(0, 6)); + return { r: rgb.r, g: rgb.g, b: rgb.b, a: 1, type: "hex" }; + } else if (input.length == 8) { + let rgb = this.hexToRgb(input.substring(0, 6)); + let alpha = parseInt(input.substring(6, 8), 16); + return { r: rgb.r, g: rgb.g, b: rgb.b, a: alpha / 255, type: "hex" }; + } + } + + hsvToRgba(h, s, v, a = 1) { + h /= 360; + let r, g, b; + const i = Math.floor(h * 6); + const f = h * 6 - i; + const p = v * (1 - s); + const q = v * (1 - f * s); + const t = v * (1 - (1 - f) * s); + + switch (i % 6) { + case 0: r = v, g = t, b = p; break; + case 1: r = q, g = v, b = p; break; + case 2: r = p, g = v, b = t; break; + case 3: r = p, g = q, b = v; break; + case 4: r = t, g = p, b = v; break; + case 5: r = v, g = p, b = q; break; + } + return { + r: Math.round(r * 255), + g: Math.round(g * 255), + b: Math.round(b * 255), + a: a, + type: "hsv/hsva" + }; + } + + hslToRgb(h, s, l, a = 1) { + let r, g, b; + + if (s === 0) { + r = g = b = l; // achromatic + } else { + const hue2rgb = (p, q, t) => { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + }; + + const q = l < 0.5 ? l * (1 + s) : l + s - l * s; + const p = 2 * l - q; + r = hue2rgb(p, q, h + 1 / 3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1 / 3); + } + + return { + r: Math.round(r * 255), + g: Math.round(g * 255), + b: Math.round(b * 255), + a: a, + type: "hsl/hsla" + }; + } + + rgbToHsl(r, g, b) { + r /= 255, g /= 255, b /= 255; + + let max = Math.max(r, g, b), min = Math.min(r, g, b); + let h, s, l = (max + min) / 2; + + if (max == min) { + h = s = 0; // achromatic + } else { + let d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + + switch (max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + + h /= 6; + } + + return {h, s, l}; + } + + hwbToRgb(h, w, b, a = 1) { + // First convert to HSL + const l = (1 - w - b) / 2; + const s = l === 0 || l === 1 ? 0 : (1 - w / (1 - b)) / 2; + + // Then convert HSL to RGB + return hslToRgb(h, s, l, a); + } + + labToRgb(l, a, b, alpha = 1) { + // LAB to XYZ + let y = (l + 16) / 116; + let x = a / 500 + y; + let z = y - b / 200; + + [x, y, z] = [x, y, z].map(value => { + if (Math.pow(value, 3) > 0.008856) { + return Math.pow(value, 3); + } else { + return (value - 16 / 116) / 7.787; + } + }); + + // XYZ to RGB + let r = 3.2404542 * x - 1.5371385 * y - 0.4985314 * z; + let g = -0.9692660 * x + 1.8760108 * y + 0.0415560 * z; + let b1 = 0.0556434 * x - 0.2040259 * y + 1.0572252 * z; + + [r, g, b1] = [r, g, b1].map(value => { + if (value > 0.0031308) { + return 1.055 * Math.pow(value, 1 / 2.4) - 0.055; + } else { + return 12.92 * value; + } + }); + + return { + r: Math.round(r * 255), + g: Math.round(g * 255), + b: Math.round(b1 * 255), + a: alpha, + type: "lab/laba" + }; + } + + lchToRgb(l, c, h, alpha = 1) { + // Convert LCH to LAB + const a = c * Math.cos(h * Math.PI / 180); + const b = c * Math.sin(h * Math.PI / 180); + + // Then convert LAB to RGB + return labToRgb(l, a, b, alpha); + } + + rgbToHsv(r, g, b) { + r /= 255, g /= 255, b /= 255; + const max = Math.max(r, g, b), min = Math.min(r, g, b); + let h, s, v = max; + const d = max - min; + s = max === 0 ? 0 : d / max; + if (max === min) { + h = 0; + } else { + switch (max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + return { h: h * 360, s: s, v: v }; + } + + rgbToHex(r, g, b) { + r = Math.min(255, Math.max(0, r)); + g = Math.min(255, Math.max(0, g)); + b = Math.min(255, Math.max(0, b)); + return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); + } + + hexToRgb(hex) { + hex = hex.replace(/^#/, ''); + let bigint = parseInt(hex, 16); + let r = (bigint >> 16) & 255; + let g = (bigint >> 8) & 255; + let b = bigint & 255; + return { r, g, b }; + } + + isValidColor(color) { + const s = new Option().style; + s.color = color; + return s.color !== ''; + } + + parseColor(color) { + const s = new Option().style; + s.color = color; + return { + r: parseInt(s.color.match(/\d+/g)[0]), + g: parseInt(s.color.match(/\d+/g)[1]), + b: parseInt(s.color.match(/\d+/g)[2]), + a: s.color.match(/\d+/g)[3] ? parseFloat(s.color.match(/\d+/g)[3]) : 1 + }; + } +} + +document.addEventListener("DOMContentLoaded", (evt) => { + document.querySelectorAll('.neo_color').forEach((e) => { + new ColorPicker(e); + }); +}); diff --git a/AvocadoEdition_Light/adm/js/theme.js b/AvocadoEdition_Light/adm/js/theme.js new file mode 100644 index 0000000..6ff4daa --- /dev/null +++ b/AvocadoEdition_Light/adm/js/theme.js @@ -0,0 +1,80 @@ +$(function () { + $(".theme_active").on("click", function () { + var theme = $(this).data("theme"); + var name = $(this).data("name"); + + if (!confirm(name + " 테마를 적용하시겠습니까?")) + return false; + + var set_default_skin = 0; + if ($(this).data("set_default_skin") == true) { + if (confirm("기본환경설정, 1:1문의, 쇼핑몰 스킨을 테마에서 설정된 스킨으로 변경하시겠습니까?\n\n변경을 선택하시면 테마에서 지정된 스킨으로 회원스킨 등이 변경됩니다.")) + set_default_skin = 1; + } + + $.ajax({ + type: "POST", + url: "./theme_update.php", + data: { + "theme": theme, + "set_default_skin": set_default_skin + }, + cache: false, + async: false, + success: function (data) { + if (data) { + alert(data); + return false; + } + + document.location.reload(); + } + }); + }); + + $(".theme_deactive").on("click", function () { + var theme = $(this).data("theme"); + var name = $(this).data("name"); + + if (!confirm(name + " 테마 사용설정을 해제하시겠습니까?\n\n테마 설정을 해제하셔도 게시판 등의 스킨은 변경되지 않으므로 개별 변경작업이 필요합니다.")) + return false; + + $.ajax({ + type: "POST", + url: "./theme_update.php", + data: { + "theme": theme, + "type": "reset" + }, + cache: false, + async: false, + success: function (data) { + if (data) { + alert(data); + return false; + } + + document.location.reload(); + } + }); + }); + + $(".theme_preview").on("click", function () { + var theme = $(this).data("theme"); + + $("#theme_detail").remove(); + + $.ajax({ + type: "POST", + url: "./theme_detail.php", + data: { + "theme": theme + }, + cache: false, + async: false, + success: function (data) { + $("#theme_list").after(data); + } + }); + }); +}); diff --git a/AvocadoEdition_Light/adm/menu_list.php b/AvocadoEdition_Light/adm/menu_list.php index 04c3ab1..25a02f6 100644 --- a/AvocadoEdition_Light/adm/menu_list.php +++ b/AvocadoEdition_Light/adm/menu_list.php @@ -97,8 +97,8 @@ $colspan = 8;
';
+
+ if ($config['cf_theme'] == $theme[$i]) {
+ $btn_active = '사용중';
+ } else {
+ $tconfig = get_theme_config_value($theme[$i], 'set_default_skin');
+ if ($tconfig['set_default_skin'])
+ $set_default_skin = 'true';
+ else
+ $set_default_skin = 'false';
+
+ $btn_active = '';
+ }
+ ?>
+ 설치된 테마가 없습니다.
+'; +else + $screenshot = '
';
+
+if ($info['theme_uri']) {
+ $name = '' . $name . '';
+}
+
+$maker = get_text($info['maker']);
+if ($info['maker_uri']) {
+ $maker = '' . $maker . '';
+}
+
+$license = get_text($info['license']);
+if ($info['license_uri']) {
+ $license = '' . $license . '';
+}
+?>
+
+| Version | ++ |
|---|---|
| Maker | ++ |
| License | ++ |