const ELEMENT_NODE = 1 const TEXT_NODE = 3 const IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i function merge(...objects) { return Object.assign({}, ...objects) } function isValidNodeType(obj) { return obj != null && typeof obj !== 'boolean' } function isSameNode(a, b) { return a.tag === b.tag && a.key === b.key } function isSameNodeType(a, b) { if (a.type !== b.type) { return false } if (a.type === TEXT_NODE && a.text !== b.text) { return false } if (a.tag !== b.tag) { return false } return true } function createClass(value) { if (typeof value === 'string') { return value } let output = '' if (Array.isArray(value) && value.length > 0) { for (let i = 0, len = value.length, tmp; i < len; i++) { if ((tmp = createClass(value[i])) !== '') { output += (output && ' ') + tmp } } } else { for (const cls in value) { if (value[cls]) { output += (output && ' ') + cls } } } return output } function createKeyToIndexMap(children, beginIndex, endIndex) { const map = {} for (let i = beginIndex; i <= endIndex; ++i) { const child = children[i] const key = child && child.key if (key != null) { map[key] = i } } return map } function createVNode(tag, props, children, node = null) { return { type: ELEMENT_NODE, tag, props, children, key: props.key || null, node, } } function createTextVNode(text, node = null) { return { type: TEXT_NODE, text: String(text), node, } } function normalizeChildren(children) { return children.flat(Infinity).reduce((vnodes, vnode) => { if (isValidNodeType(vnode)) { const type = typeof vnode if (type === 'string' || type === 'number') { vnode = createTextVNode(vnode) } vnodes.push(vnode) } return vnodes }, []) } function recycle(node) { if (node.nodeType === 3) { return createTextVNode(node.data, node) } if (node.nodeType === 1) { return createVNode( node.nodeName.toLowerCase(), Array.from(node.attributes).reduce((map, attr) => { const name = attr.name, value = attr.value if (name !== 'style') { map[name] = value } if (name === 'key') { node.removeAttribute('key') } return map }, {}), Array.from(node.childNodes).map(recycle), node ) } } function createElement(vnode, isSvg) { let node if (vnode.type === TEXT_NODE) { node = document.createTextNode(vnode.text) } else { const { tag, props, children } = vnode const length = children.length isSvg = isSvg || tag === 'svg' node = isSvg ? document.createElementNS('http://www.w3.org/2000/svg', tag) : document.createElement(tag) Object.keys(props).forEach((name) => patchProperty(node, name, null, props[name], isSvg)) if (length === 1) { node.appendChild(createElement(children[0], isSvg)) } else if (length > 1) { node.appendChild( children.reduce( (frag, vchild) => frag.appendChild(createElement(vchild, isSvg)) && frag, document.createDocumentFragment() ) ) } } vnode.node = node return node } function setStyle(element, name, value) { if (name.startsWith('--')) { element.style.setProperty(name, value == null ? '' : value) } else if (value == null) { element.style[name] = '' } else if (typeof value != 'number' || IS_NON_DIMENSIONAL.test(name)) { element.style[name] = value } else { element.style[name] = value + 'px' } } function patchProperty(element, name, prevVal, nextVal, isSvg) { if (name === 'key' || name === 'children') { return } if (name === 'style') { if (typeof nextVal === 'string') { element.style.cssText = nextVal } else { if (typeof prevVal === 'string') { element.style.cssText = prevVal = '' } for (const key in merge(nextVal, prevVal)) { setStyle(element, key, nextVal == null ? '' : nextVal[key]) } } } else if (name.startsWith('on') && (typeof prevVal === 'function' || typeof nextVal === 'function')) { name = name.toLowerCase() in element ? name.toLowerCase().slice(2) : name.slice(2) if (nextVal) { element.addEventListener(name, nextVal) } if (prevVal) { element.removeEventListener(name, prevVal) } } else if (typeof nextVal !== 'function') { if (nextVal != null && (name === 'class' || name === 'className')) { nextVal = createClass(nextVal) } if (!isSvg && name === 'class') { name = 'className' } if ( !isSvg && name !== 'width' && name !== 'height' && name !== 'href' && name !== 'list' && name !== 'form' && name !== 'tabIndex' && name !== 'download' && name !== 'rowSpan' && name !== 'colSpan' && name !== 'role' && name in element ) { try { element[name] = nextVal == null ? '' : nextVal return } catch (e) {} // eslint-disable-line no-empty } if (nextVal != null && (nextVal !== false || name.indexOf('-') != -1)) { element.setAttribute(name, nextVal) } else { element.removeAttribute(name) } } } function patchChildren(parent, prevChildren, nextChildren, isSvg) { let prevStartIndex = 0 let prevEndIndex = prevChildren.length - 1 let prevStartChild = prevChildren[0] let prevEndChild = prevChildren[prevEndIndex] let nextStartIndex = 0 let nextEndIndex = nextChildren.length - 1 let nextStartChild = nextChildren[0] let nextEndChild = nextChildren[nextEndIndex] let prevKeyToIdx while (prevStartIndex <= prevEndIndex && nextStartIndex <= nextEndIndex) { if (!prevStartChild) { prevStartChild = prevChildren[++prevStartIndex] } else if (!prevEndChild) { prevEndChild = prevChildren[--prevEndIndex] } else if (isSameNode(prevStartChild, nextStartChild)) { patchElement(parent, prevStartChild, nextStartChild, isSvg) prevStartChild = prevChildren[++prevStartIndex] nextStartChild = nextChildren[++nextStartIndex] } else if (isSameNode(prevEndChild, nextEndChild)) { patchElement(parent, prevEndChild, nextEndChild, isSvg) prevEndChild = prevChildren[--prevEndIndex] nextEndChild = nextChildren[--nextEndIndex] } else if (isSameNode(prevStartChild, nextEndChild)) { patchElement(parent, prevStartChild, nextEndChild, isSvg) parent.insertBefore(prevStartChild.node, prevEndChild.node.nextSibling) prevStartChild = prevChildren[++prevStartIndex] nextEndChild = nextChildren[--nextEndIndex] } else if (isSameNode(prevEndChild, nextStartChild)) { patchElement(parent, prevEndChild, nextStartChild, isSvg) parent.insertBefore(prevEndChild.node, prevStartChild.node) prevEndChild = prevChildren[--prevEndIndex] nextStartChild = nextChildren[++nextStartIndex] } else { if (!prevKeyToIdx) { prevKeyToIdx = createKeyToIndexMap(prevChildren, prevStartIndex, prevEndIndex) } const key = nextStartChild.key const prevIndex = key ? prevKeyToIdx[key] : null if (prevIndex == null) { parent.insertBefore(createElement(nextStartChild, isSvg), prevStartChild.node) nextStartChild = nextChildren[++nextStartIndex] } else { let prevChildToMove = prevChildren[prevIndex] patchElement(parent, prevChildToMove, nextStartChild, isSvg) prevChildren[prevIndex] = undefined parent.insertBefore(prevChildToMove.node, prevStartChild.node) nextStartChild = nextChildren[++nextStartIndex] } } } if (prevStartIndex > prevEndIndex) { const subsequentElement = nextChildren[nextEndIndex + 1] ? nextChildren[nextEndIndex + 1].node : null for (let i = nextStartIndex; i <= nextEndIndex; i++) { parent.insertBefore(createElement(nextChildren[i], isSvg), subsequentElement) } } else if (nextStartIndex > nextEndIndex) { for (let i = prevStartIndex; i <= prevEndIndex; i++) { const child = prevChildren[i] if (child && child.node) { parent.removeChild(child.node) } } } return nextChildren } function patchElement(parent, prevVNode, nextVNode, isSvg) { if (prevVNode === nextVNode) { if (prevVNode == null) { return null } return prevVNode.node } if (prevVNode == null) { return parent.appendChild(createElement(nextVNode, isSvg)) } let element = prevVNode.node if (nextVNode == null) { return parent.removeChild(element) && null } if (prevVNode.type === TEXT_NODE && nextVNode.type === TEXT_NODE) { if (prevVNode.text !== nextVNode.text) { element.data = nextVNode.text } } else if (!isSameNodeType(nextVNode, prevVNode)) { const nextElement = createElement(nextVNode, isSvg) parent.replaceChild(nextElement, element) element = nextElement } else { isSvg = isSvg || nextVNode.tag === 'svg' const activeElement = document.activeElement const prevVProps = prevVNode.props const nextVProps = nextVNode.props for (const name in merge(nextVProps, prevVProps)) { if ( (name === 'value' || name === 'selected' || name === 'checked' ? element[name] : prevVProps[name]) !== nextVProps[name] ) { patchProperty(element, name, prevVProps[name], nextVProps[name], isSvg) } } patchChildren(element, prevVNode.children, nextVNode.children, isSvg) if (activeElement !== document.body) { activeElement.focus() } } nextVNode.node = element return element } function render(parent, nextVNode) { let prevVNode = parent._vnode || null if (!prevVNode && parent.childNodes.length > 0) { prevVNode = Array.from(parent.childNodes).map(recycle) } const prevIsArray = Array.isArray(prevVNode) const nextIsArray = Array.isArray(nextVNode) parent._vnode = nextVNode if (prevIsArray || nextIsArray) { const prevVChildren = (prevIsArray ? prevVNode : [prevVNode]).filter(isValidNodeType) const nextVChildren = (nextIsArray ? nextVNode : [nextVNode]).filter(isValidNodeType) const root = patchChildren(parent, prevVChildren, nextVChildren) return root.length === 0 ? null : root.length === 1 ? root[0].node : root.map((vnode) => vnode.node) } return patchElement(parent, prevVNode, nextVNode) } function h(tag, props, ...children) { if (!props || props.type === ELEMENT_NODE || props.type === TEXT_NODE || typeof props.concat === 'function') { children = [].concat(props || [], ...children) props = null } props = props || {} children = normalizeChildren(children) if (typeof tag === 'function') { return tag({ children, ...props }) } return createVNode(tag, props, children) } function text(str) { return createTextVNode(str) } let CSS_STATEMENT_RE = /([^{};]*)([;{}])/g let LINE_BREAK_RE = /(\r\n|\r|\n)+/g let TAB_RE = /\t/g let EXTRA_SPACES_RE = /\s{2,}/g let COMMENTS_RE = /\/\*[\W\w]*?\*\//g let TRAILING_SEPARATOR_SPACES_RE = /\s*([:;{}])\s*/g let UNNECESSARY_SEPARATOR_RE = /\};+/g let TRAILING_SEPARATORS_RE = /([^:;{}])}/g function normalize(css) { return css .replace(LINE_BREAK_RE, ' ') .replace(TAB_RE, ' ') .replace(EXTRA_SPACES_RE, ' ') .replace(COMMENTS_RE, '') .trim() .replace(TRAILING_SEPARATOR_SPACES_RE, '$1') .replace(UNNECESSARY_SEPARATOR_RE, '}') .replace(TRAILING_SEPARATORS_RE, '$1;}') } function walk(css, callback) { css = normalize(css) CSS_STATEMENT_RE.lastIndex = 0 for (let m; (m = CSS_STATEMENT_RE.exec(css)) != null; ) { callback(m[1], m[2]) } } function compileTaggedTemplate(strings, values, callback) { return strings.raw.reduce((acc, str, i) => acc + callback(values[i - 1]) + str) } let stylesheet let CLASS_PREFIX = 's' let SELECTOR_GROUP_RE = /([\s\S]+,[\s\S]+)/m function parseNestedCSS(css) { let ast = [{ children: [] }] let depth = 0 walk(css, (style, char) => { if (char == '{') { ast[++depth] = { selector: style, rules: '', children: [], } } else if (char == '}') { ast[depth].rules += style ast[--depth].children.push(ast.pop()) } else if (char == ';') { ast[depth].rules += style + char } }) return ast[0].children } function buildCSS(ast, parent) { return ast.reduce((css, block) => { let selector = block.selector.trim() if (selector[0] === '@') { css += selector + '{' if (block.children.length > 0) { css += buildCSS(block.children, parent) + '}' } } else { if (parent && selector[0] === '&') { selector = parent + selector.substring(1).replace(SELECTOR_GROUP_RE, ':is($1)') } else if (parent) { selector = parent + ' ' + selector.replace(SELECTOR_GROUP_RE, ':is($1)') } else { selector = selector.replace(SELECTOR_GROUP_RE, ':is($1)') } css += selector + '{' + block.rules + '}' if (block.children.length > 0) { css += buildCSS(block.children, selector) } } return css }, '') } function compileCSS(css) { return buildCSS(parseNestedCSS(css)) } function resolveValue(value) { if (typeof value === 'function') { return resolveValue(value()) } if (value && value.nodeType === 1 && value.nodeName === 'STYLE') { return value.textContent } return value } function appendCSS(css) { if (!stylesheet) { stylesheet = document.createElement('style') document.head.appendChild(stylesheet) } stylesheet.textContent += css + '\n\n' } function style(strings, ...values) { throw 'dead' let styles = compileTaggedTemplate(strings, values, resolveValue) let className = CLASS_PREFIX + uuid() appendCSS(compileCSS(`.${className} { ${styles} }`)) return className } function css(strings, ...values) { let styles = compileTaggedTemplate(strings, values, resolveValue) appendCSS(compileCSS(styles)) } let id = 0 function CreateStyle(table) { id += 1 let className = 's' + id let styles = '' for (let key in table) { let value = table[key] styles = styles.concat('\t', key, ': ', value, ';', '\n') } appendCSS(`.${className} {\n${styles}}`) return className } function AddStyleTo(className, pseudo, table) { let styles = '' for (let key in table) { let value = table[key] styles = styles.concat('\t', key, ': ', value, ';', '\n') } appendCSS(`.${className}:${pseudo} {\n${styles}}`) return className } function AddStyle(className, table) { let styles = '' for (let key in table) { let value = table[key] styles = styles.concat('\t', key, ': ', value, ';', '\n') } appendCSS(`${className} {\n${styles}}`) return className } AddStyle('body', { '-webkit-user-select': 'none', 'background-color': 'var(--block-bg-color)', 'color-scheme': 'var(--tg-color-scheme)', 'color': 'var(--text-color)', 'cursor': 'default', 'font-family': 'var(--default-font)', 'font-size': '13px', 'font-weight': '400', 'line-height': '16px', 'margin': '0', 'min-width': '100%', 'padding': '0', 'user-select': 'none', 'width': '1px', }) AddStyle(':root', { '--default-font': '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"', '--accent-text-color': 'var(--tg-theme-accent-text-color)', '--animation': '0.15s ease', '--bg-color': 'var(--tg-theme-bg-color)', '--bottom-bar-bg-color': 'var(--tg-theme-bottom-bar-bg-color)', '--button-color': 'var(--tg-theme-button-color)', '--button-text-color': 'var(--tg-theme-button-text-color)', '--destructive-text-color': 'var(--tg-theme-destructive-text-color)', '--header-bg-color': 'var(--tg-theme-header-bg-color)', '--hint-color': 'var(--tg-theme-hint-color)', '--link-color': 'var(--tg-theme-link-color)', '--page-animation-duration': '0.3s', '--page-animation': 'var(--page-animation-duration) ease', '--page-hint-color': '#83878a', '--placeholder-color': '#999da1', '--ripple-duration': '0.45s', '--ripple-end-duration': '0.3s', '--secondary-bg-color': 'var(--tg-theme-secondary-bg-color)', '--section-bg-color': 'var(--tg-theme-section-bg-color)', '--section-header-text-color': 'var(--tg-theme-section-header-text-color)', '--section-separator-color': 'var(--tg-theme-section-separator-color)', '--status-height': '48px', '--subtitle-text-color': 'var(--tg-theme-subtitle-text-color)', '--text-color': 'var(--tg-theme-text-color)', }) AddStyle('*', { '-webkit-tap-highlight-color': 'transparent', }) AddStyle('button', { 'cursor': 'pointer', }) let StyleStoreItem = CreateStyle({ 'background-color': 'var(--secondary-bg-color)', 'border-radius': '7px', 'box-sizing': 'border-box', 'overflow': 'hidden', 'padding': '8px', 'position': 'relative', 'text-align': 'center', 'width': 'calc(100% / 2.05)', }) let StyleStoreBlock = CreateStyle({ '-webkit-box-shadow': '0 0.5px rgba(0, 0, 0, 0.07)', 'background-color': 'var(--block-bg-color)', 'box-shadow': '0 0.5px rgba(0, 0, 0, 0.07)', }) let StyleStoreItems = CreateStyle({ 'align-content': 'flex-start', 'display': 'flex', 'flex-wrap': 'wrap', 'justify-content': 'space-between', 'margin': '10px', 'max-width': '480px', 'overflow': 'hidden', 'row-gap': '8px', 'transition': 'max-height var(--page-animation), opacity var(--page-animation)', // "width": "fit-content", }) let StyleStoreCategory = CreateStyle({ 'background-color': 'var(--secondary-bg-color)', 'border-radius': '7px', 'box-sizing': 'border-box', 'height': '182px', 'overflow': 'hidden', 'padding': '8px', 'position': 'relative', 'text-align': 'center', 'transition': 'all var(--animation)', 'width': 'calc(100% / 2.05)', }) AddStyleTo(StyleStoreCategory, 'hover', { 'transform': 'scale(1.05)', }) AddStyleTo(StyleStoreCategory, 'active', { 'transform': 'scale(1.05)', }) let StyleStoreItemPhoto = CreateStyle({ 'height': '150px', 'position': 'relative', }) let StyleStoreItemImage = CreateStyle({ 'bottom': '0', 'display': 'inline-block', 'height': '100%', 'left': '0', 'margin': '0 auto', 'position': 'relative', 'right': '0', 'top': '0', 'vertical-align': 'top', 'width': '100%', // 'position': 'absolute', // 'width': '146px', }) let StyleStoreItemBadge = CreateStyle({ 'border-radius': '4px', 'border': 'none', 'box-sizing': 'border-box', 'color': '#fff', 'display': 'inline-block', 'font-family': 'var(--default-font)', 'font-size': '13px', 'font-weight': '500', 'left': '5px', 'line-height': '14px', 'outline': 'none', 'padding': '2px 4px', 'position': 'absolute', 'text-transform': 'uppercase', 'top': '5px', 'transform': 'rotate(-12deg)', }) let StyleStoreItemLabel = CreateStyle({ 'align-items': 'flex-start', 'display': 'flex', 'flex-direction': 'column', 'font-size': '15px', 'gap': '6px', 'margin': '0 1px', 'overflow': 'hidden', 'text-overflow': 'ellipsis', 'white-space': 'nowrap', }) let StyleStoreItemTitle = CreateStyle({}) let StyleStoreItemPrice = CreateStyle({ 'font-weight': '700', 'white-space': 'nowrap', }) let StyleStoreItemButtons = CreateStyle({ 'display': 'flex', 'margin': '8px auto 0', 'position': 'relative', 'transition': 'all var(--animation)', }) let StyleStoreItemCounter = CreateStyle({ 'animation': 'var(--animation) both', 'font-size': '20px', 'height': '32px', 'line-height': '32px', 'margin': '12px', 'min-width': '32px', 'pointer-events': 'none', 'position': 'absolute', 'right': '0', 'text-align': 'center', 'top': '0', 'transform': 'scale3d(0, 0, 1)', 'vertical-align': 'middle', 'z-index': '3', }) let StyleNumberInput = CreateStyle({ 'border-radius': '0', 'border': 'none', 'box-sizing': 'border-box', 'color': 'var(--text-color)', 'cursor': 'auto', 'display': 'block', 'font-family': 'var(--default-font)', 'font-size': '17px', 'height': '32px', 'line-height': '21px', 'outline': 'none', 'padding': '0px 10px', 'resize': 'none', 'user-select': 'auto', 'width': '48px', }) let StyleLoadingContainer = CreateStyle({ '-webkit-transform': 'translate(-50%, -50%)', 'left': '50%', 'position': 'absolute', 'top': '50%', 'transform': 'translate(-50%, -50%)', }) let StyleItemTitle = CreateStyle({ 'font-size': '18px', 'font-weight': '700', 'line-height': '18px', 'overflow': 'hidden', 'padding': '3px 0', 'white-space': 'nowrap', 'width': '200px', }) let StyleStatusWrap = CreateStyle({ 'left': '0', 'position': 'fixed', 'right': '0', 'top': '0', 'transform': 'translateY(var(--tg-viewport-height, 100vh))', 'z-index': '1', }) AddStyle('.cafe-order-header-wrap', { 'align-items': 'center', 'display': 'flex', 'padding': '21px 20px 14px', }) AddStyle('.cafe-order-header', { 'flex-grow': '1', 'font-size': '17px', 'line-height': '21px', 'margin': '0', 'padding': '0', 'text-transform': 'uppercase', }) AddStyle('.cafe-item-buy-button', { 'background-color': 'var(--accent-color)', 'position': 'absolute !important', 'right': '0', 'top': '0', 'transition': 'width var(--animation)', 'width': '80px', }) AddStyle('.cafe-item-incr-button', { 'transition': 'all var(--animation)', 'width': '100%', // "position": "absolute !important", // "right": "0", // "top": "0", }) // AddStyle(".cafe-item-decr-button", { // background-color: #e64d44; // pointer-events: none; // transform: scale3d(0.9, 0.9, 1); // transition: transform var(--animation), visibility var(--animation); // visibility: hidden; // }) css` .cafe-status { position: fixed; bottom: 0; left: 0; right: 0; display: block; width: 100%; padding: 8px 20px; display: flex; justify-content: center; align-items: center; border-radius: 0; background-color: #e64d44; box-shadow: 0 var(--status-height) #e64d44; color: #fff; height: var(--status-height); transition: transform var(--animation), visibility var(--animation); transform: translateY(var(--status-height)); box-sizing: border-box; pointer-events: none; visibility: hidden; z-index: 11; } ` css` button, .cafe-item-counter { display: inline-block; font-family: var(--default-font); font-weight: 700; font-size: 13px; line-height: 18px; height: 30px; border-radius: 7px; box-sizing: border-box; background-color: var(--link-color); color: #fff; outline: none; border: none; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; display: flex; justify-content: center; align-items: center; } ` css` .cafe-item-incr-button:active { transform: scale(1.1); } ` css` .selected .cafe-item-incr-button { width: 48%; } ` css` .cafe-item-decr-button { position: relative; width: 48%; } ` css` .selected .cafe-item-decr-button { pointer-events: auto; transform: scale3d(1, 1, 1); visibility: visible; transition: all 0.1s; } ` css` .cafe-item-decr-button:active { transform: scale(1.1); } ` css` .cafe-item-incr-button:before, .cafe-item-incr-button:after { background-color: rgba(255, 255, 255, 0); transition: background-color var(--animation); } ` css` .selected .cafe-item-incr-button:before, .selected .cafe-item-incr-button:after { background-color: #fff; } ` css` .cafe-item-incr-button .button-item-label { transition: transform var(--animation); } ` css` .selected .cafe-item-incr-button .button-item-label { transform: scale3d(0.4, 0, 1); display: none; } ` css` .cafe-item-incr-button:after { width: 3px; height: 14px; } ` css` .cafe-status.shown { pointer-events: auto; visibility: visible; transform: translateY(0); } ` css` .cafe-order-overview { font-family: var(--default-font); background-color: var(--bg-color); transition: opacity var(--page-animation); } ` css` .cafe-order-edit { font-size: 15px; line-height: 18px; font-weight: 500; color: var(--link-color); } ` css` .cafe-order-item { display: flex; padding: 5px 20px 5px 14px; } ` css` .cafe-order-item-label { flex-grow: 1; } ` css` .cafe-order-item-photo { text-align: center; width: 50px; height: 50px; margin-right: 11px; } ` css` .cafe-order-item-photo .cafe-item-emoji { font-size: 38px; line-height: 50px; } ` css` .cafe-order-item-photo .cafe-item-lottie { width: 40px; margin: 4px 0; } ` css` .cafe-order-item-counter { color: var(--link-color); } ` css` .cafe-order-item-description { font-size: 14px; line-height: 17px; -webkit-font-smoothing: antialiased; color: var(--page-hint-color); padding: 2px 0; } ` css` .cafe-order-item-price { font-size: 14px; line-height: 17px; font-weight: 500; padding: 4px 0; } ` css` .cafe-text-field { font-family: var(--default-font); font-size: 17px; line-height: 21px; -webkit-font-smoothing: antialiased; padding: 12px 20px 13px; box-sizing: border-box; display: block; outline: none; border: none; border-radius: 0; resize: none; color: var(--text-color); -webkit-user-select: auto; user-select: auto; cursor: auto; width: 100%; } ` css` .cafe-text-field::-webkit-input-placeholder { transition: color var(--animation); color: var(--placeholder-color); text-overflow: ellipsis; } ` css` .cafe-text-field::-moz-placeholder { transition: color var(--animation); color: var(--placeholder-color); text-overflow: ellipsis; } ` css` .cafe-text-field:-ms-input-placeholder { transition: color var(--animation); color: var(--placeholder-color); text-overflow: ellipsis; } ` css` .cafe-text-field::placeholder { text-overflow: ellipsis; } ` css` .cafe-text-field-hint { font-family: var(--default-font); font-size: 14px; line-height: 18px; -webkit-font-smoothing: antialiased; padding: 10px 20px 24px; color: var(--hint-color); } ` css` .button-item-label { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; vertical-align: top; position: relative; z-index: 1; } ` css` .cafe-switch-block { height: 32px; padding: 10px 20px; display: flex; align-items: center; justify-content: space-between; } ` css` .cafe-switch-label { font-family: var(--default-font); font-size: 17px; } ` css` .switch { position: relative; display: inline-block; width: 60px; height: 32px; } ` css` .switch input { opacity: 0; width: 0; height: 0; } ` css` .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: var(--tg-theme-bg-color); -webkit-transition: 0.2s; transition: 0.2s; } ` css` .slider:before { position: absolute; content: ''; height: 24px; width: 24px; left: 5px; bottom: 4px; background-color: var(--bg-color); -webkit-transition: 0.2s; transition: 0.2s; } ` css` input:checked + .slider { background-color: var(--link-color); } ` css` input:focus + .slider { box-shadow: 0 0 1px var(--link-color); } ` css` input:checked + .slider:before { -webkit-transform: translateX(25px); -ms-transform: translateX(25px); transform: translateX(25px); } ` css` @keyframes rotate-circle { from { transform: rotateZ(-90deg); } to { transform: rotateZ(630deg); } } ` css` @keyframes resize-circle { from { stroke-dashoffset: 0; } to { stroke-dashoffset: 12500px; } } ` css` @keyframes badge-incr { from, to { transform: scale3d(1, 1, 1); } 40% { transform: scale3d(1.2, 1.2, 1); } } ` css` @keyframes badge-incr2 { from, to { transform: scale3d(1, 1, 1); } 40% { transform: scale3d(1.2, 1.2, 1); } } ` css` @keyframes badge-decr { from, to { transform: scale3d(1, 1, 1); } 40% { transform: scale3d(0.8, 0.8, 1); } } ` css` @keyframes badge-decr2 { from, to { transform: scale3d(1, 1, 1); } 40% { transform: scale3d(0.8, 0.8, 1); } } ` css` @keyframes badge-show { from { transform: scale3d(0.5, 0.5, 1); opacity: 0; visibility: hidden; } 30% { transform: scale3d(1.2, 1.2, 1); } to { transform: scale3d(1, 1, 1); opacity: 1; visibility: visible; } } ` css` @keyframes badge-hide { from { transform: scale3d(1, 1, 1); opacity: 1; visibility: visible; } to { transform: scale3d(0.5, 0.5, 1); opacity: 0; visibility: hidden; } } ` css` .loader { width: 4px; color: var(--link-color); aspect-ratio: 1; box-shadow: 19px -19px 0 0px, 38px -19px 0 0px, 57px -19px 0 0px, 19px 0 0 5px, 38px 0 0 5px, 57px 0 0 5px, 19px 19px 0 0px, 38px 19px 0 0px, 57px 19px 0 0px; transform: translateX(-38px); animation: l26 2s infinite linear; } ` css` @keyframes l26 { 12.5% { box-shadow: 19px -19px 0 0px, 38px -19px 0 0px, 57px -19px 0 5px, 19px 0 0 5px, 38px 0 0 0px, 57px 0 0 5px, 19px 19px 0 0px, 38px 19px 0 0px, 57px 19px 0 0px; } 25% { box-shadow: 19px -19px 0 5px, 38px -19px 0 0px, 57px -19px 0 5px, 19px 0 0 0px, 38px 0 0 0px, 57px 0 0 0px, 19px 19px 0 0px, 38px 19px 0 5px, 57px 19px 0 0px; } 50% { box-shadow: 19px -19px 0 5px, 38px -19px 0 5px, 57px -19px 0 0px, 19px 0 0 0px, 38px 0 0 0px, 57px 0 0 0px, 19px 19px 0 0px, 38px 19px 0 0px, 57px 19px 0 5px; } 62.5% { box-shadow: 19px -19px 0 0px, 38px -19px 0 0px, 57px -19px 0 0px, 19px 0 0 5px, 38px 0 0 0px, 57px 0 0 0px, 19px 19px 0 0px, 38px 19px 0 5px, 57px 19px 0 5px; } 75% { box-shadow: 19px -19px 0 0px, 38px -19px 0 5px, 57px -19px 0 0px, 19px 0 0 0px, 38px 0 0 0px, 57px 0 0 5px, 19px 19px 0 0px, 38px 19px 0 0px, 57px 19px 0 5px; } 87.5% { box-shadow: 19px -19px 0 0px, 38px -19px 0 5px, 57px -19px 0 0px, 19px 0 0 0px, 38px 0 0 5px, 57px 0 0 0px, 19px 19px 0 5px, 38px 19px 0 0px, 57px 19px 0 0px; } } ` css` .gg-math-plus { display: inline-block; width: 2em; height: 2em; background-repeat: no-repeat; background-size: 100% 100%; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='white' d='M19 12.998h-6v6h-2v-6H5v-2h6v-6h2v6h6z'/%3E%3C/svg%3E"); } ` css` .gg-math-minus { display: inline-block; width: 2em; height: 2em; background-repeat: no-repeat; background-size: 100% 100%; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='white' d='M19 12.998H5v-2h14z'/%3E%3C/svg%3E"); } ` css` img::before { content: ''; display: inline-block; width: 75%; height: 100%; mask-repeat: no-repeat; mask-size: 100% 100%; mask-image: url("data:image/svg+xml;charset=UTF-8,%3c?xml version='1.0' encoding='utf-8'?%3e%3csvg width='800px' height='800px' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M7.828 5l-1-1H22v15.172l-1-1v-.69l-3.116-3.117-.395.296-.714-.714.854-.64a.503.503 0 0 1 .657.046L21 16.067V5zM3 20v-.519l2.947-2.947a1.506 1.506 0 0 0 .677.163 1.403 1.403 0 0 0 .997-.415l2.916-2.916-.706-.707-2.916 2.916a.474.474 0 0 1-.678-.048.503.503 0 0 0-.704.007L3 18.067V5.828l-1-1V21h16.172l-1-1zM17 8.5A1.5 1.5 0 1 1 15.5 7 1.5 1.5 0 0 1 17 8.5zm-1 0a.5.5 0 1 0-.5.5.5.5 0 0 0 .5-.5zm5.646 13.854l.707-.707-20-20-.707.707z'/%3e%3cpath fill='none' d='M0 0h24v24H0z'/%3e%3c/svg%3e"); opacity: 0.25; background-color: var(--link-color); } ` css` .button-item-icon { display: none; } ` css` .selected .button-item-icon { display: inline-block; } ` css` .checkcontainer { display: block; position: relative; padding-left: 35px; margin-bottom: 12px; cursor: pointer; font-size: 22px; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } ` css` .checkcontainer input { position: absolute; opacity: 0; cursor: pointer; height: 0; width: 0; } ` css` .radiobtn { position: absolute; top: 0; left: 0; height: 25px; width: 25px; background-color: var(--block-bg-color); border-radius: 50%; } ` css` .checkcontainer:hover input ~ .radiobtn { background-color: var(--accent-color); } ` css` .checkcontainer input:checked ~ .radiobtn { background-color: var(--link-color); } ` css` .radiobtn:after { content: ''; position: absolute; display: none; } ` css` .checkcontainer input:checked ~ .radiobtn:after { display: block; } ` css` .checkcontainer .radiobtn:after { top: 9px; left: 9px; width: 8px; height: 8px; border-radius: 50%; background: white; } ` let LoginData = {} function LoadLoginData() { let base64Decoded = window.location.search base64Decoded = base64Decoded.substring(1) let jsonDecoded try { jsonDecoded = Base64UrlDecodeString(base64Decoded) LoginData = JSON.parse(jsonDecoded) } catch (error) { return } } let StoreData = {} function LoadStoreData() { fetch('/api/store_info') .then((response) => response.json()) .then((data) => { StoreData = data redraw() }) .catch((error) => {}) } let ShoppingCard = [] let ScreenId = { Unknown: 0, Category: 1, Item: 2, } var NavigationState = { ScreenStack: [], } function RestoreNavigationState() { let base64Decoded = window.location.hash base64Decoded = base64Decoded.substring(1) let jsonDecoded try { jsonDecoded = Base64UrlDecodeString(base64Decoded) NavigationState = JSON.parse(jsonDecoded) } catch (error) { return } } function SaveNavigationState() { let jsonEncoded = JSON.stringify(NavigationState) let base64Encoded = Base64UrlEncodeString(jsonEncoded) window.history.pushState(null, '', '#' + base64Encoded) } function PushScreen(id, data) { NavigationState.ScreenStack.push({ Id: id, ...data }) SaveNavigationState() window.scrollTo({ top: 0, behavior: 'instant' }) redraw() } function PopScreen() { NavigationState.ScreenStack.pop() SaveNavigationState() window.scrollTo({ top: 0, behavior: 'instant' }) redraw() } function FirstScreen() { NavigationState.ScreenStack = [] PushScreen({ id: ScreenId.Main }) } function GetCurrentScreen() { let length = NavigationState.ScreenStack.length if (length > 0) { return NavigationState.ScreenStack[length - 1] } return {} } function IsSelected(categoryId) { if (categoryId % 2 == 0) { return StyleStoreCategory } else { return StyleStoreCategorySelected } } function StoreCategory(categoryId, category) { return h( 'div', { // class: IsSelected(categoryId), class: StyleStoreCategory, onclick: function () { PushScreen(ScreenId.Category, { CategoryId: categoryId }) }, }, h( 'div', { class: StyleStoreItemPhoto }, h('img', { class: StyleStoreItemImage, src: StoreData.Categories[categoryId].FileUrl, }) ), h('div', { class: StyleStoreItemLabel }, h('span', { class: StyleStoreItemTitle }, category.Name)) ) } function StoreItem() { return h( 'div.cafe-item', {}, h( StyleStoreItemCounter, { onupdate: function (_vnode) { if (!vnode.state.dirty) { return } vnode.state.dirty = false delta = vnode.state.count - vnode.state.oldCount var cur_anim_name = _vnode.dom.style['animation-name'] var anim_name = '' if (vnode.state.count > 0) { anim_name = 'badge-show' if (delta > 0) { anim_name = 'badge-incr' } else if (delta < 0) { anim_name = 'badge-decr' } if ((anim_name == 'badge-incr' || anim_name == 'badge-decr') && anim_name == cur_anim_name) { anim_name += '2' } } else if (cur_anim_name != '') { anim_name = 'badge-hide' } _vnode.dom.style['animation-name'] = anim_name }, }, vnode.state.count ), h( '.cafe-item-photo', h( 'picture.cafe-item-lottie', h('img', { src: Data.general.items[vnode.state.id].file_url }) ), h( 'span.cafe-item-new', { style: { 'background-color': Data.general.items[vnode.state.id].badge_color, }, }, Data.general.items[vnode.state.id].badge_text ) ) ) } function StoreItem(itemId, item) { return h( 'div', { class: StyleStoreItem, onclick: function () { if (StoreData.Items[itemId].OptionsGroupIds) { PushScreen(ScreenId.Item, { ItemId: itemId }) } else { ShoppingCard.push(itemId) redraw() } }, }, h( 'div', { class: StyleStoreItemPhoto }, h('img', { class: StyleStoreItemImage, src: StoreData.Items[itemId].FileUrl, }) ), h( 'div', { class: StyleStoreItemLabel }, h('span', { class: 'cafe-item-price' }, FormatPrice(StoreData.Items[itemId].Price)), h('span', { class: 'cafe-item-title' }, StoreData.Items[itemId].Name) ), h( 'div', { class: 'cafe-item-buttons' }, h( 'button', { class: 'cafe-item-decr-button button-item', onclick: function (e) { ShoppingCard.pop() }, }, h('span', { class: 'gg-math-minus' }) ), h( 'button', { class: 'cafe-item-incr-button button-item' }, h('span', { class: 'button-item-icon gg-math-plus' }), h('span', { class: 'button-item-label' }, 'В корзину') ) ) ) } function Main() { let currentScreen = GetCurrentScreen() switch (currentScreen.Id || ScreenId.Category) { case ScreenId.Unknown: break case ScreenId.Category: if (Object.keys(StoreData).length > 0) { let categories = [] let currentCategoryId = currentScreen.CategoryId for (let [_categoryId, category] of Object.entries(StoreData.Categories)) { let categoryId = Number(_categoryId) if (category.ParentCategoryId != currentCategoryId) { continue } categories.push(StoreCategory(categoryId, category)) } let items = [] for (let [_itemId, item] of Object.entries(StoreData.Items)) { let itemId = Number(_itemId) if (item.CategoryId != currentCategoryId) { continue } items.push(StoreItem(itemId, item)) } return h('div', { class: StyleStoreItems }, ...categories, ...items) } break } return h('div', { class: StyleLoadingContainer }, h('div', { class: 'loader' })) } function GetShoppingCardTotal() { let total = 0 // for (i in scores) { // } return total } function UpdateTelegramStuff() { Telegram.WebApp.isClosingConfirmationEnabled = !!ShoppingCard.length if (NavigationState.ScreenStack.length > 0) { Telegram.WebApp.BackButton.show() } else { Telegram.WebApp.BackButton.hide() } if (ShoppingCard.length > 0) { if (false) { Telegram.WebApp.MainButton.setParams({ is_visible: true, has_shine_effect: true, }) } else { Telegram.WebApp.MainButton.setParams({ // is_visible: !!Data.CanPay, text: 'Оплатить ' + FormatPrice(GetShoppingCardTotal()), }).hideProgress() } } else { Telegram.WebApp.MainButton.setParams({ // is_visible: !!Data.CanPay, text: 'Оформить заказ', }).hideProgress() } } let Page = { Store: 1, Chart: 2, } let drawId = 0 function redraw() { drawId += 1 let startTime = performance.now() UpdateTelegramStuff() switch (LoginData.Page) { case Page.Store: // return; let a = Main() console.log(`redraw ${drawId}`) render(document.body, a) break case Page.Chart: render(document.body, ChartRender()) break } postRender() let endTime = performance.now() let t = Math.round((endTime - startTime) * 1000) console.log(`redraw ${drawId} took ${t} microseconds`) } function setThemeClass() { // document.documentElement.className = Telegram.WebApp.colorScheme; } function ChartRender() { return h( 'div', {}, h('canvas', { id: 'chart' }), h( 'button', { onclick: function () { index = 0 mode = 1 UpdateChart() }, }, 'Monthly' ), h( 'button', { onclick: function () { index = 0 mode = 2 UpdateChart() }, }, 'Weekly' ), h( 'button', { onclick: function () { index = 0 mode = 3 UpdateChart() }, }, 'Daily' ), h( 'button', { onclick: function () { index += 1 let maxIndex = Math.floor((getMaxIndex(mode) - 1) / MAX_PER_PAGE) console.log(maxIndex) if (index > maxIndex) { index = maxIndex } UpdateChart() }, }, 'plus' ), h( 'button', { onclick: function () { index -= 1 if (index < 0) { index = 0 } UpdateChart() }, }, 'minus' ) ) } let index = Number.MAX_SAFE_INTEGER let mode = 1 function UpdateChart() { ChartObj.data = getData(mode, index) ChartObj.update() } let ChartData = {} var Utf8Encoder = new TextEncoder() var Utf8Decoder = new TextDecoder('utf-8') function Base64UrlEncodeString(s) { return Base64UrlEncodeArray(Utf8Encoder.encode(s)) } function Base64UrlDecodeString(s) { return Utf8Decoder.decode(Base64UrlDecodeArray(s)) } function Base64UrlEncodeArray(buffer) { return btoa(Array.from(new Uint8Array(buffer), (b) => String.fromCharCode(b)).join('')) .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=+$/, '') } function Base64UrlDecodeArray(value) { let m = value.length % 4 return Uint8Array.from( atob( value .replace(/-/g, '+') .replace(/_/g, '/') .padEnd(value.length + (m === 0 ? 0 : 4 - m), '=') ), (c) => c.charCodeAt(0) ).buffer } function LoadChartData() { fetch( '/api/chart?' + new URLSearchParams({ UserId: LoginData.UserId, Token: Base64UrlEncodeArray(LoginData.Token), StoreId: LoginData.StoreId, }) ) .then((response) => response.json()) .then((data) => { ChartData = data redraw() }) .catch((error) => {}) } let ChartObj function postRender() { switch (LoginData.Page) { case Page.Store: break case Page.Chart: Chart.defaults.backgroundColor = Telegram.WebApp.themeParams.button_color Chart.defaults.borderColor = Telegram.WebApp.themeParams.hint_color Chart.defaults.color = Telegram.WebApp.themeParams.text_color let ctx = document.getElementById('chart') if (Object.keys(ChartData).length == 0) { return } ChartObj = new Chart(ctx, { type: 'line', data: getData(mode, index), options: { plugins: { legend: { display: false, }, }, scales: { y: { suggestedMin: 0, }, }, }, }) break } } let MAX_PER_PAGE = 10 function getMaxIndex(mode) { if (mode == 1) { return Object.keys(ChartData.Monthly).length } if (mode == 2) { return Object.keys(ChartData.Weekly).length } if (mode == 3) { return Object.keys(ChartData.Daily).length } } function getData(mode, index) { let data if (mode == 1) { data = ChartData.Monthly } if (mode == 2) { data = ChartData.Weekly } if (mode == 3) { data = ChartData.Daily } let keys = Object.keys(data) let values = Object.values(data) let newKeys = keys.map((key) => { let date = new Date(Number(key) / 1_000_000) return date.toLocaleDateString('ru-RU') }) let newValues = values.map((value) => value / 100) if (index < 0) { index = 0 } let maxIndex = Math.floor((getMaxIndex(mode) - 1) / MAX_PER_PAGE) if (index > maxIndex) { index = maxIndex } let start = MAX_PER_PAGE * (index + 0) let end = MAX_PER_PAGE * (index + 1) start = Math.max(0, start) end = Math.max(0, end) start = Math.min(newKeys.length, start) end = Math.min(newKeys.length, end) newKeys = newKeys.slice(start, end) newValues = newValues.slice(start, end) return { labels: newKeys, datasets: [ { label: 'Turkish lira', data: newValues, }, ], } } function init() { // console.log(Data.userId); // console.log(Data.token); // if (!Data.token) { // Data.isClosed = true; // Data.error = "Заведение временно закрыто"; // // ShowStatus("Заведение временно закрыто"); // return; // } // $(".js-item").each(function (i) { // if (i == 0) { // return; // } // var itemEl = $(this); // itemEl.hide(); // }); // $('.js-order-edit').on('click', Store.EditClicked); // $(".js-status").on("click", Store.StatusClicked); // Telegram.WebApp.MainButton.setParams({ // // text_color: '#fff', // shine_effect: true, // }).onClick(Store.MainBtnClicked); Telegram.WebApp.ready() Telegram.WebApp.setHeaderColor('bg_color') Telegram.WebApp.expand() Telegram.WebApp.onEvent('themeChanged', setThemeClass) setThemeClass() // document.documentElement.style = document.documentElement.style + variables; // document.head.appendChild(bodyStyle); Telegram.WebApp.BackButton.onClick(function () { PopScreen() }) RestoreNavigationState() LoadLoginData() LoadStoreData() LoadChartData() } init() redraw() function UpdateItem(itemEl, delta) { var price = +itemEl.data('item-price') var count = +itemEl.data('item-count') || 0 var counterEl = $('.js-item-counter', itemEl) counterEl.text(count ? count : 1) var isSelected = itemEl.hasClass('selected') var anim_name = isSelected ? (delta > 0 ? 'badge-incr' : count > 0 ? 'badge-decr' : 'badge-hide') : 'badge-show' var cur_anim_name = counterEl.css('animation-name') if ((anim_name == 'badge-incr' || anim_name == 'badge-decr') && anim_name == cur_anim_name) { anim_name += '2' } counterEl.css('animation-name', anim_name) itemEl.toggleClass('selected', count > 0) var orderItemEl = Store.GetOrderItem(itemEl) var orderCounterEl = $('.js-order-item-counter', orderItemEl) orderCounterEl.text(count ? count : 1) orderItemEl.toggleClass('selected', count > 0) var orderPriceEl = $('.js-order-item-price', orderItemEl) var item_price = count * price orderPriceEl.text(Store.FormatPrice(item_price)) Store.UpdateTotalPrice() } function FormatPrice(price) { return Math.trunc(price / 100) + ' ' + StoreData.CurrencySign } function StoreItemLine(id) { return h( 'div.cafe-order-item', h( 'div.cafe-order-item-photo', h('picture.cafe-item-lottie', h('img', { src: Data.general.items[id].file_url })) ), h( 'div.cafe-order-item-label', h( 'div', { class: StyleItemTitle }, Data.general.items[id].name, ' ', h('span.cafe-order-item-counter', `${Data.ShoppingCard} шт`) ), h('div.cafe-order-item-description', 'test') ), h('div.cafe-order-item-price', FormatPrice(Data.general.items[id].price)) ) } function StoreTakeout() { return h( 'div.cafe-order-overview', h( '.cafe-block', h( '.cafe-order-items', Object.entries(Data.general.items).map(function (d) { shopItemId = d[0] return h(StoreItemLine, { id: shopItemId }) }) ) ), h( '.cafe-switch-block', h('.cafe-switch-label', 'Забрать на кассе'), h('.cafe-switch', h('label.switch', h('input', { type: 'checkbox' }), h('span.slider'))) ), h( '.cafe-switch-block', h('.cafe-switch-label', 'Номер столика'), h('input', { class: StyleNumberInput }, { type: 'text' }) ), h( '.cafe-text-field-wrap', h('textarea.cafe-text-field cafe-block', { rows: 1, placeholder: 'Добавить комментарий…', style: 'overflow: hidden visible; overflow-wrap: break-word;', oninput: function (_vnode) { autosize(this) }, }) ) ) } function StoreDelivery() { return h( 'div.cafe-order-overview', h('.cafe-block'), h( '.cafe-switch-block', h('.cafe-switch-label', 'Забрать на кассе'), h('.cafe-switch', h('label.switch', h('input', { type: 'checkbox' }), h('span.slider'))) ), h( '.cafe-switch-block', h('.cafe-switch-label', 'Номер столика'), h('input', { class: StyleNumberInput }, { type: 'text' }) ), h( '.cafe-text-field-wrap', h('textarea.cafe-text-field cafe-block', { rows: 1, placeholder: 'Добавить комментарий…', style: 'overflow: hidden visible; overflow-wrap: break-word;', oninput: function (_vnode) { autosize(this) }, }) ) ) } function StoreCasher() { return h( 'div.cafe-order-overview', h('.cafe-block'), h( '.cafe-switch-block', h('.cafe-switch-label', 'Наличные'), h('label.checkcontainer', h('input', { type: 'radio', name: 'radio' }), h('span.radiobtn')) ), h( '.cafe-switch-block', h('.cafe-switch-label', 'Безналичные'), h('label.checkcontainer', h('input', { type: 'radio', name: 'radio' }), h('span.radiobtn')) ), h( '.cafe-switch-block', h('.cafe-switch-label', 'Баланс'), h('label.checkcontainer', h('input', { type: 'radio', name: 'radio' }), h('span.radiobtn')) ), h( '.cafe-switch-block', h('.cafe-switch-label', 'Скидка'), h('input', { class: StyleNumberInput }, { type: 'text' }) ), h( '.cafe-text-field-wrap', h('textarea.cafe-text-field cafe-block', { rows: 1, placeholder: 'Добавить комментарий…', style: 'overflow: hidden visible; overflow-wrap: break-word;', oninput: function (_vnode) { autosize(this) }, }) ) ) } function StoreOptions() { return h('.xxx') } function Main1() { categoryId = '' len = NavigationState.ScreenStateStack.length if (len > 0) { categoryId = NavigationState.ScreenStateStack[len - 1].CategoryId } if (NavigationState.ScreenStateStack.length > 0) { Telegram.WebApp.BackButton.show() } else { Telegram.WebApp.BackButton.hide() } UpdateMainButton() if (Data.error) { return h('div', { class: StyleStatusWrap }, m('.cafe-status .shown', Data.error)) } else if (Data.general.categories) { // return m(StoreTakeout); return m( '.cafe-items start', Object.entries(Data.general.categories).map(function (d) { shopCategoryId = d[0] parent_category_id = Data.general.categories[shopCategoryId].parent_category_id || '' if (parent_category_id != categoryId) { return } return h(StoreCategory, { id: shopCategoryId }) }), Object.entries(Data.general.items).map(function (d) { shopItemId = d[0] if (Data.general.items[shopItemId].category_id != categoryId) { return } return h(StoreItem, { id: shopItemId }) }) ) } else { return h('div', { class: StyleLoadingContainer }, m('.loader')) } }