This commit is contained in:
zhx 2026-05-26 02:56:37 +08:00
parent 72f6110dc7
commit e0261a117a
106 changed files with 5497 additions and 803 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules/

6
.prettierignore Normal file
View File

@ -0,0 +1,6 @@
node_modules
dist
build
.git
.vscode
*.log

9
.prettierrc Normal file
View File

@ -0,0 +1,9 @@
{
"semi": true,
"singleQuote": true,
"tabWidth": 4,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "always",
"printWidth": 80
}

4
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"editor.tabSize": 4,
"editor.insertSpaces": true
}

View File

@ -1,3 +1,9 @@
common 里存放环境的js 如果有参数 ?env=test 就走test api
如果没有参数默认是 线上的api
如果env=local 就是本地的api
如果env=local 就是本地的api
H5 通用主题放在 common/theme.css新页面默认引用该文件。
当前通用主题为浅紫色,不使用流光、彩虹渐变或高饱和装饰效果:主色使用 --hy-theme-primary / --hy-theme-primary-strong按钮使用 --hy-theme-button页面背景使用 --hy-theme-bg卡片使用 --hy-theme-surface。
页面样式不要硬编码主色,优先消费 common/theme.css 里的 CSS 变量;只有 Figma 强制要求 100% 还原时才允许局部覆盖。
H5 多语言能力放在 common/i18n.js 和 common/locales/\*.json当前面向英语 en、阿拉伯语 ar、土耳其语 tr、西班牙语 es。页面文案使用 data-i18n / data-i18n-placeholder / data-i18n-aria 绑定语言包 key新增页面必须优先复用 common 的语言包机制,不在页面脚本里硬编码多语言字典。

View File

@ -1,179 +1,251 @@
var test_api = "https://api-test.global-interaction.com/";
var local_api = "http://localhost:13000/";
var default_api = "https://api.global-interaction.com/";
var test_api = 'https://api-test.global-interaction.com/';
var local_api = 'http://localhost:13000/';
var default_api = 'https://api.global-interaction.com/';
(function () {
var API_ENV_KEY = "hyapp_h5_env";
var ACCESS_TOKEN_KEY = "hyapp_access_token";
var APP_CODE_KEY = "hyapp_app_code";
var memoryEnv = "";
var memoryAccessToken = "";
var memoryAppCode = "";
var API_ENV_KEY = 'hyapp_h5_env';
var ACCESS_TOKEN_KEY = 'hyapp_access_token';
var APP_CODE_KEY = 'hyapp_app_code';
var memoryEnv = '';
var memoryAccessToken = '';
var memoryAppCode = '';
function readQuery(name) {
return new URLSearchParams(window.location.search).get(name);
}
function normalizeBaseURL(value) {
return String(value || "").replace(/\/+$/, "") + "/";
}
function isLocalDevOrigin() {
var host = window.location.hostname;
return host === "127.0.0.1" || host === "localhost" || host === "::1";
}
function shouldPersist() {
return !isLocalDevOrigin();
}
function clearLocalDevCache() {
if (shouldPersist()) return;
window.localStorage.removeItem(API_ENV_KEY);
window.localStorage.removeItem(ACCESS_TOKEN_KEY);
window.localStorage.removeItem(APP_CODE_KEY);
}
function devProxyBase(path) {
return normalizeBaseURL(window.location.origin + path);
}
function resolveEnv() {
var env = readQuery("env");
if (env === "test" || env === "local") {
memoryEnv = env;
if (shouldPersist()) window.localStorage.setItem(API_ENV_KEY, env);
return env;
}
if (memoryEnv) return memoryEnv;
if (!shouldPersist()) return "";
return window.localStorage.getItem(API_ENV_KEY) || "";
}
function resolveBaseURL() {
var env = resolveEnv();
if (env === "test") return isLocalDevOrigin() ? devProxyBase("/__api_test__/") : normalizeBaseURL(test_api);
if (env === "local") return isLocalDevOrigin() ? devProxyBase("/__api_local__/") : normalizeBaseURL(local_api);
return normalizeBaseURL(default_api);
}
function buildURL(path, query) {
var url = new URL(path.replace(/^\/+/, ""), resolveBaseURL());
if (query) {
Object.keys(query).forEach(function (key) {
var value = query[key];
if (value === undefined || value === null || value === "") return;
url.searchParams.set(key, value);
});
}
return url.toString();
}
function getAccessToken() {
if (memoryAccessToken) return memoryAccessToken;
if (!shouldPersist()) return "";
return window.localStorage.getItem(ACCESS_TOKEN_KEY) || "";
}
function getAppCode() {
var queryAppCode = readQuery("app_code") || readQuery("appCode");
if (queryAppCode) {
memoryAppCode = queryAppCode;
if (shouldPersist()) window.localStorage.setItem(APP_CODE_KEY, queryAppCode);
return queryAppCode;
}
if (memoryAppCode) return memoryAppCode;
if (!shouldPersist()) return "lalu";
return window.localStorage.getItem(APP_CODE_KEY) || "lalu";
}
function setAccessToken(token) {
memoryAccessToken = token || "";
if (token) {
if (shouldPersist()) window.localStorage.setItem(ACCESS_TOKEN_KEY, token);
return;
}
if (shouldPersist()) window.localStorage.removeItem(ACCESS_TOKEN_KEY);
}
function setAppCode(appCode) {
memoryAppCode = appCode || "";
if (appCode) {
if (shouldPersist()) window.localStorage.setItem(APP_CODE_KEY, appCode);
return;
}
if (shouldPersist()) window.localStorage.removeItem(APP_CODE_KEY);
}
function parseResponse(response) {
return response.text().then(function (text) {
var payload = text ? JSON.parse(text) : {};
if (!response.ok) {
var httpError = new Error(payload.message || response.statusText || "request_failed");
httpError.status = response.status;
httpError.payload = payload;
throw httpError;
}
var code = payload && payload.code;
var isErrorCode = (typeof code === "number" && code !== 0) || (typeof code === "string" && code !== "" && code !== "OK");
if (isErrorCode) {
var apiError = new Error(payload.message || "api_request_failed");
apiError.code = payload.code;
apiError.request_id = payload.request_id;
apiError.payload = payload;
throw apiError;
}
return payload && Object.prototype.hasOwnProperty.call(payload, "data") ? payload.data : payload;
});
}
function request(path, options) {
var opts = options || {};
var headers = Object.assign({}, opts.headers || {});
var token = getAccessToken();
var appCode = getAppCode();
if (token) headers.Authorization = "Bearer " + token;
if (appCode) headers["X-App-Code"] = appCode;
if (!shouldPersist()) headers["Cache-Control"] = "no-cache";
var body = opts.body;
if (body && typeof body === "object" && !(body instanceof FormData)) {
headers["Content-Type"] = headers["Content-Type"] || "application/json";
body = JSON.stringify(body);
function readQuery(name) {
return new URLSearchParams(window.location.search).get(name);
}
return window.fetch(buildURL(path, opts.query), {
method: opts.method || "GET",
headers: headers,
body: body,
cache: shouldPersist() ? "default" : "no-store",
credentials: opts.credentials || "omit"
}).then(parseResponse);
}
function normalizeBaseURL(value) {
return String(value || '').replace(/\/+$/, '') + '/';
}
window.HyAppAPI = {
baseURL: resolveBaseURL,
buildURL: buildURL,
getAccessToken: getAccessToken,
getAppCode: getAppCode,
setAccessToken: setAccessToken,
setAppCode: setAppCode,
request: request,
get: function (path, query) {
return request(path, { method: "GET", query: query });
function isLocalDevOrigin() {
var host = window.location.hostname;
return host === '127.0.0.1' || host === 'localhost' || host === '::1';
}
function shouldPersist() {
return !isLocalDevOrigin();
}
function clearLocalDevCache() {
if (shouldPersist()) return;
window.localStorage.removeItem(API_ENV_KEY);
window.localStorage.removeItem(ACCESS_TOKEN_KEY);
window.localStorage.removeItem(APP_CODE_KEY);
}
function devProxyBase(path) {
return normalizeBaseURL(window.location.origin + path);
}
function resolveEnv() {
var env = readQuery('env');
if (env === 'test' || env === 'local') {
memoryEnv = env;
if (shouldPersist()) window.localStorage.setItem(API_ENV_KEY, env);
return env;
}
if (memoryEnv) return memoryEnv;
if (!shouldPersist()) return '';
return window.localStorage.getItem(API_ENV_KEY) || '';
}
function resolveBaseURL() {
var env = resolveEnv();
if (env === 'test')
return isLocalDevOrigin()
? devProxyBase('/__api_test__/')
: normalizeBaseURL(test_api);
if (env === 'local')
return isLocalDevOrigin()
? devProxyBase('/__api_local__/')
: normalizeBaseURL(local_api);
return normalizeBaseURL(default_api);
}
function buildURL(path, query) {
var url = new URL(path.replace(/^\/+/, ''), resolveBaseURL());
if (query) {
Object.keys(query).forEach(function (key) {
var value = query[key];
if (value === undefined || value === null || value === '')
return;
url.searchParams.set(key, value);
});
}
return url.toString();
}
function getAccessToken() {
if (memoryAccessToken) return memoryAccessToken;
if (!shouldPersist()) return '';
return window.localStorage.getItem(ACCESS_TOKEN_KEY) || '';
}
function getAppCode() {
var queryAppCode = readQuery('app_code') || readQuery('appCode');
if (queryAppCode) {
memoryAppCode = queryAppCode;
if (shouldPersist())
window.localStorage.setItem(APP_CODE_KEY, queryAppCode);
return queryAppCode;
}
if (memoryAppCode) return memoryAppCode;
if (!shouldPersist()) return 'lalu';
return window.localStorage.getItem(APP_CODE_KEY) || 'lalu';
}
function setAccessToken(token) {
memoryAccessToken = token || '';
if (token) {
if (shouldPersist())
window.localStorage.setItem(ACCESS_TOKEN_KEY, token);
return;
}
if (shouldPersist()) window.localStorage.removeItem(ACCESS_TOKEN_KEY);
}
function setAppCode(appCode) {
memoryAppCode = appCode || '';
if (appCode) {
if (shouldPersist())
window.localStorage.setItem(APP_CODE_KEY, appCode);
return;
}
if (shouldPersist()) window.localStorage.removeItem(APP_CODE_KEY);
}
function parseResponse(response) {
return response.text().then(function (text) {
var payload = text ? JSON.parse(text) : {};
if (!response.ok) {
var httpError = new Error(
payload.message || response.statusText || 'request_failed'
);
httpError.status = response.status;
httpError.payload = payload;
throw httpError;
}
var code = payload && payload.code;
var isErrorCode =
(typeof code === 'number' && code !== 0) ||
(typeof code === 'string' && code !== '' && code !== 'OK');
if (isErrorCode) {
var apiError = new Error(
payload.message || 'api_request_failed'
);
apiError.code = payload.code;
apiError.request_id = payload.request_id;
apiError.payload = payload;
throw apiError;
}
return payload &&
Object.prototype.hasOwnProperty.call(payload, 'data')
? payload.data
: payload;
});
}
function request(path, options) {
var opts = options || {};
var headers = Object.assign({}, opts.headers || {});
var token = getAccessToken();
var appCode = getAppCode();
if (token) headers.Authorization = 'Bearer ' + token;
if (appCode) headers['X-App-Code'] = appCode;
if (!shouldPersist()) headers['Cache-Control'] = 'no-cache';
var body = opts.body;
if (body && typeof body === 'object' && !(body instanceof FormData)) {
headers['Content-Type'] =
headers['Content-Type'] || 'application/json';
body = JSON.stringify(body);
}
return window
.fetch(buildURL(path, opts.query), {
method: opts.method || 'GET',
headers: headers,
body: body,
cache: shouldPersist() ? 'default' : 'no-store',
credentials: opts.credentials || 'omit',
})
.then(parseResponse);
}
var vipAPI = {
me: function () {
return request('/api/v1/vip/me', { method: 'GET' });
},
packages: function () {
return request('/api/v1/vip/packages', { method: 'GET' });
},
purchase: function (payload) {
return request('/api/v1/vip/purchase', {
method: 'POST',
body: payload || {},
});
},
};
var hostAPI = {
searchAgencies: function (shortId, pageSize) {
return request('/api/v1/host/agencies/search', {
method: 'GET',
query: { short_id: shortId, page_size: pageSize || 20 },
});
},
applyToAgency: function (payload) {
return request('/api/v1/host/agency-applications', {
method: 'POST',
body: payload || {},
});
},
post: function (path, body, query) {
return request(path, { method: "POST", body: body, query: query });
},
put: function (path, body, query) {
return request(path, { method: "PUT", body: body, query: query });
},
patch: function (path, body, query) {
return request(path, { method: "PATCH", body: body, query: query });
},
delete: function (path, query) {
return request(path, { method: "DELETE", query: query });
}
};
clearLocalDevCache();
var levelAPI = {
overview: function () {
return request("/api/v1/levels/me/overview", { method: "GET" });
},
track: function (track) {
return request("/api/v1/levels/tracks/" + encodeURIComponent(track || ""), {
method: "GET",
});
},
rewards: function (query) {
return request("/api/v1/levels/rewards", {
method: "GET",
query: query || {},
});
},
};
window.HyAppAPI = {
baseURL: resolveBaseURL,
buildURL: buildURL,
getAccessToken: getAccessToken,
getAppCode: getAppCode,
setAccessToken: setAccessToken,
setAppCode: setAppCode,
request: request,
get: function (path, query) {
return request(path, { method: 'GET', query: query });
},
post: function (path, body, query) {
return request(path, { method: 'POST', body: body, query: query });
},
put: function (path, body, query) {
return request(path, { method: 'PUT', body: body, query: query });
},
patch: function (path, body, query) {
return request(path, { method: 'PATCH', body: body, query: query });
},
delete: function (path, query) {
return request(path, { method: 'DELETE', query: query });
},
vip: vipAPI,
host: hostAPI,
level: levelAPI,
};
clearLocalDevCache();
})();

159
common/i18n.js Normal file
View File

@ -0,0 +1,159 @@
(function () {
var STORAGE_KEY = 'hyapp_h5_lang';
var DEFAULT_LANG = 'en';
var SUPPORTED = ['en', 'ar', 'tr', 'es'];
var messages = {};
var currentLang = '';
function queryLang() {
return new URLSearchParams(window.location.search).get('lang') || '';
}
function normalizeLang(value) {
var lang = String(value || '')
.trim()
.toLowerCase()
.replace('_', '-');
if (!lang) return '';
if (lang.indexOf('ar') === 0) return 'ar';
if (lang.indexOf('tr') === 0) return 'tr';
if (lang.indexOf('es') === 0) return 'es';
return SUPPORTED.indexOf(lang) >= 0 ? lang : '';
}
function resolveLang() {
return (
normalizeLang(queryLang()) ||
normalizeLang(window.localStorage.getItem(STORAGE_KEY)) ||
normalizeLang(window.navigator.language) ||
DEFAULT_LANG
);
}
function load(lang) {
var normalized = normalizeLang(lang) || DEFAULT_LANG;
return window
.fetch('../common/locales/' + normalized + '.json', {
cache: 'no-store',
})
.then(function (response) {
if (!response.ok) throw new Error('locale_not_found');
return response.json();
})
.then(function (json) {
messages = json || {};
currentLang = normalized;
window.localStorage.setItem(STORAGE_KEY, currentLang);
apply();
return messages;
})
.catch(function () {
if (normalized === DEFAULT_LANG) {
messages = {};
currentLang = DEFAULT_LANG;
apply();
return messages;
}
return load(DEFAULT_LANG);
});
}
function t(key, fallback) {
return Object.prototype.hasOwnProperty.call(messages, key)
? messages[key]
: fallback || key;
}
function apply(root) {
var scope = root || document;
document.documentElement.lang = currentLang || DEFAULT_LANG;
document.documentElement.dir = currentLang === 'ar' ? 'rtl' : 'ltr';
scope.querySelectorAll('[data-i18n]').forEach(function (node) {
node.textContent = t(
node.getAttribute('data-i18n'),
node.textContent
);
});
scope
.querySelectorAll('[data-i18n-placeholder]')
.forEach(function (node) {
node.setAttribute(
'placeholder',
t(
node.getAttribute('data-i18n-placeholder'),
node.getAttribute('placeholder') || ''
)
);
});
scope.querySelectorAll('[data-i18n-aria]').forEach(function (node) {
node.setAttribute(
'aria-label',
t(
node.getAttribute('data-i18n-aria'),
node.getAttribute('aria-label') || ''
)
);
});
scope.querySelectorAll('[data-lang-option]').forEach(function (node) {
node.classList.toggle(
'is-active',
node.getAttribute('data-lang-option') === currentLang
);
});
scope.querySelectorAll('[data-current-lang]').forEach(function (node) {
node.textContent = (currentLang || DEFAULT_LANG).toUpperCase();
});
window.dispatchEvent(
new CustomEvent('hyapp:i18n-ready', {
detail: { lang: currentLang, messages: messages },
})
);
}
function initLanguageMenu() {
document.addEventListener('click', function (event) {
var toggle = event.target.closest('[data-language-toggle]');
var menu = document.querySelector('[data-language-menu]');
if (toggle && menu) {
var expanded = toggle.getAttribute('aria-expanded') === 'true';
toggle.setAttribute(
'aria-expanded',
expanded ? 'false' : 'true'
);
menu.hidden = expanded;
return;
}
var option = event.target.closest('[data-lang-option]');
if (option) {
if (menu) menu.hidden = true;
var button = document.querySelector('[data-language-toggle]');
if (button) button.setAttribute('aria-expanded', 'false');
load(option.getAttribute('data-lang-option'));
return;
}
if (menu && !event.target.closest('.language-switcher')) {
menu.hidden = true;
var languageButton = document.querySelector(
'[data-language-toggle]'
);
if (languageButton)
languageButton.setAttribute('aria-expanded', 'false');
}
});
}
window.HyAppI18n = {
load: load,
apply: apply,
t: t,
lang: function () {
return currentLang || DEFAULT_LANG;
},
supported: SUPPORTED.slice(),
};
document.addEventListener('DOMContentLoaded', function () {
initLanguageMenu();
load(resolveLang());
});
})();

View File

@ -1,8 +0,0 @@
(function () {
if (!window.HyAppBridge) {
var script = document.createElement("script");
var current = document.currentScript && document.currentScript.src;
script.src = current ? current.replace(/jsbrdge\.js(?:\?.*)?$/, "jsbridge.js") : "/common/jsbridge.js";
document.head.appendChild(script);
}
})();

View File

@ -1,43 +1,69 @@
(function () {
function post(action, payload) {
var message = JSON.stringify({ action: action, payload: payload || {} });
function post(action, payload) {
var message = JSON.stringify({
action: action,
payload: payload || {},
});
if (window.flutter_inappwebview && window.flutter_inappwebview.callHandler) {
return window.flutter_inappwebview.callHandler("HyAppBridge", action, payload || {});
}
if (window.HyAppBridgeChannel && window.HyAppBridgeChannel.postMessage) {
window.HyAppBridgeChannel.postMessage(message);
return Promise.resolve();
}
if (window.FlutterBridge && window.FlutterBridge.postMessage) {
window.FlutterBridge.postMessage(message);
return Promise.resolve();
}
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.HyAppBridge) {
window.webkit.messageHandlers.HyAppBridge.postMessage({ action: action, payload: payload || {} });
return Promise.resolve();
if (
window.flutter_inappwebview &&
window.flutter_inappwebview.callHandler
) {
return window.flutter_inappwebview.callHandler(
'HyAppBridge',
action,
payload || {}
);
}
if (
window.HyAppBridgeChannel &&
window.HyAppBridgeChannel.postMessage
) {
window.HyAppBridgeChannel.postMessage(message);
return Promise.resolve();
}
if (window.FlutterBridge && window.FlutterBridge.postMessage) {
window.FlutterBridge.postMessage(message);
return Promise.resolve();
}
if (
window.webkit &&
window.webkit.messageHandlers &&
window.webkit.messageHandlers.HyAppBridge
) {
window.webkit.messageHandlers.HyAppBridge.postMessage({
action: action,
payload: payload || {},
});
return Promise.resolve();
}
window.dispatchEvent(
new CustomEvent('hyapp:bridge-message', {
detail: { action: action, payload: payload || {} },
})
);
return Promise.resolve();
}
window.dispatchEvent(new CustomEvent("hyapp:bridge-message", { detail: { action: action, payload: payload || {} } }));
return Promise.resolve();
}
window.HyAppBridge = {
post: post,
back: function () {
return post("back");
},
openUser: function (userId) {
return post("openUser", { user_id: String(userId || "") });
},
openRoom: function (roomId) {
return post("openRoom", { room_id: String(roomId || "") });
},
openRankNote: function (boardType) {
return post("openRankNote", { board_type: String(boardType || "") });
},
ready: function (payload) {
return post("ready", payload || {});
}
};
window.HyAppBridge = {
post: post,
back: function () {
return post('back');
},
openUser: function (userId) {
return post('openUser', { user_id: String(userId || '') });
},
openRoom: function (roomId) {
return post('openRoom', { room_id: String(roomId || '') });
},
openRankNote: function (boardType) {
return post('openRankNote', {
board_type: String(boardType || ''),
});
},
ready: function (payload) {
return post('ready', payload || {});
},
};
})();

22
common/locales/ar.json Normal file
View File

@ -0,0 +1,22 @@
{
"host_center.title": "مركز المضيف",
"host_center.back": "رجوع",
"host_center.change_language": "تغيير اللغة",
"host_center.profile_name": "Namenamename",
"host_center.uid": "UID: 12345678",
"host_center.join_title": "انضم إلى وكالة",
"host_center.join_text": "ابحث عن رقم الوكالة ثم أرسل طلبك.",
"host_center.join_now": "انضم الآن",
"host_center.agency_id": "رقم الوكالة",
"host_center.enter_agency_id": "أدخل رقم الوكالة",
"host_center.search": "بحث",
"host_center.agency": "الوكالة",
"host_center.apply": "تقديم",
"host_center.search_required": "أدخل رقم الوكالة.",
"host_center.searching": "جار البحث...",
"host_center.no_agency": "لم يتم العثور على وكالة في منطقتك.",
"host_center.search_failed": "فشل البحث. حاول لاحقا.",
"host_center.apply_failed": "فشل إرسال الطلب. حاول لاحقا.",
"host_center.apply_success": "تم إرسال الطلب.",
"host_center.applying": "جار الإرسال..."
}

22
common/locales/en.json Normal file
View File

@ -0,0 +1,22 @@
{
"host_center.title": "Host Center",
"host_center.back": "Back",
"host_center.change_language": "Change language",
"host_center.profile_name": "Namenamename",
"host_center.uid": "UID: 12345678",
"host_center.join_title": "Join Agency",
"host_center.join_text": "Search for an agency ID and submit your application.",
"host_center.join_now": "Join now",
"host_center.agency_id": "Agency ID",
"host_center.enter_agency_id": "Enter agency ID",
"host_center.search": "Search",
"host_center.agency": "Agency",
"host_center.apply": "Apply",
"host_center.search_required": "Enter an agency ID.",
"host_center.searching": "Searching...",
"host_center.no_agency": "No agency found in your region.",
"host_center.search_failed": "Search failed. Try again later.",
"host_center.apply_failed": "Application failed. Try again later.",
"host_center.apply_success": "Application submitted.",
"host_center.applying": "Submitting..."
}

22
common/locales/es.json Normal file
View File

@ -0,0 +1,22 @@
{
"host_center.title": "Centro de anfitrión",
"host_center.back": "Volver",
"host_center.change_language": "Cambiar idioma",
"host_center.profile_name": "Namenamename",
"host_center.uid": "UID: 12345678",
"host_center.join_title": "Unirse a una agencia",
"host_center.join_text": "Busca un ID de agencia y envía tu solicitud.",
"host_center.join_now": "Unirse ahora",
"host_center.agency_id": "ID de agencia",
"host_center.enter_agency_id": "Ingresa el ID de agencia",
"host_center.search": "Buscar",
"host_center.agency": "Agencia",
"host_center.apply": "Solicitar",
"host_center.search_required": "Ingresa un ID de agencia.",
"host_center.searching": "Buscando...",
"host_center.no_agency": "No se encontró ninguna agencia en tu región.",
"host_center.search_failed": "La búsqueda falló. Inténtalo más tarde.",
"host_center.apply_failed": "La solicitud falló. Inténtalo más tarde.",
"host_center.apply_success": "Solicitud enviada.",
"host_center.applying": "Enviando..."
}

22
common/locales/id.json Normal file
View File

@ -0,0 +1,22 @@
{
"host_center.title": "Pusat Host",
"host_center.back": "Kembali",
"host_center.change_language": "Ganti bahasa",
"host_center.profile_name": "Namenamename",
"host_center.uid": "UID: 12345678",
"host_center.join_title": "Gabung Agency",
"host_center.join_text": "Cari ID agency lalu kirim pengajuan.",
"host_center.join_now": "Gabung sekarang",
"host_center.agency_id": "ID Agency",
"host_center.enter_agency_id": "Masukkan ID agency",
"host_center.search": "Cari",
"host_center.agency": "Agency",
"host_center.apply": "Ajukan",
"host_center.search_required": "Masukkan ID agency.",
"host_center.searching": "Mencari...",
"host_center.no_agency": "Agency tidak ditemukan di wilayah Anda.",
"host_center.search_failed": "Pencarian gagal. Coba lagi nanti.",
"host_center.apply_failed": "Pengajuan gagal. Coba lagi nanti.",
"host_center.apply_success": "Pengajuan terkirim.",
"host_center.applying": "Mengirim..."
}

22
common/locales/tr.json Normal file
View File

@ -0,0 +1,22 @@
{
"host_center.title": "Host Center",
"host_center.back": "Geri",
"host_center.change_language": "Dili değiştir",
"host_center.profile_name": "Namenamename",
"host_center.uid": "UID: 12345678",
"host_center.join_title": "Ajansa Katıl",
"host_center.join_text": "Ajans ID'sini arayın ve başvurunuzu gönderin.",
"host_center.join_now": "Hemen katıl",
"host_center.agency_id": "Ajans ID",
"host_center.enter_agency_id": "Ajans ID girin",
"host_center.search": "Ara",
"host_center.agency": "Ajans",
"host_center.apply": "Başvur",
"host_center.search_required": "Ajans ID girin.",
"host_center.searching": "Aranıyor...",
"host_center.no_agency": "Bölgenizde ajans bulunamadı.",
"host_center.search_failed": "Arama başarısız. Daha sonra deneyin.",
"host_center.apply_failed": "Başvuru başarısız. Daha sonra deneyin.",
"host_center.apply_success": "Başvuru gönderildi.",
"host_center.applying": "Gönderiliyor..."
}

22
common/locales/zh.json Normal file
View File

@ -0,0 +1,22 @@
{
"host_center.title": "主播中心",
"host_center.back": "返回",
"host_center.change_language": "切换语言",
"host_center.profile_name": "Namenamename",
"host_center.uid": "UID: 12345678",
"host_center.join_title": "加入公会",
"host_center.join_text": "搜索公会短 ID 并提交申请。",
"host_center.join_now": "立即加入",
"host_center.agency_id": "公会 ID",
"host_center.enter_agency_id": "输入公会 ID",
"host_center.search": "搜索",
"host_center.agency": "公会",
"host_center.apply": "申请",
"host_center.search_required": "请输入公会 ID。",
"host_center.searching": "搜索中...",
"host_center.no_agency": "未找到同区域公会。",
"host_center.search_failed": "搜索失败,请稍后重试。",
"host_center.apply_failed": "申请失败,请稍后重试。",
"host_center.apply_success": "申请已提交。",
"host_center.applying": "提交中..."
}

View File

@ -1,72 +1,83 @@
(function () {
var TOKEN_KEYS = ["token", "access_token", "accessToken"];
var APP_CODE_KEYS = ["app_code", "appCode"];
var USER_READY_EVENT = "hyapp:user-ready";
var USER_ERROR_EVENT = "hyapp:user-error";
var TOKEN_KEYS = ['token', 'access_token', 'accessToken'];
var APP_CODE_KEYS = ['app_code', 'appCode'];
var USER_READY_EVENT = 'hyapp:user-ready';
var USER_ERROR_EVENT = 'hyapp:user-error';
function query() {
var params = new URLSearchParams(window.location.search);
var hash = window.location.hash || "";
if (hash.indexOf("?") >= 0) {
new URLSearchParams(hash.split("?").slice(1).join("?")).forEach(function (value, key) {
if (!params.has(key)) params.set(key, value);
});
}
return params;
}
function first(params, keys) {
for (var i = 0; i < keys.length; i += 1) {
var value = params.get(keys[i]);
if (value) return value;
}
return "";
}
function parse() {
var params = query();
var token = first(params, TOKEN_KEYS);
var appCode = first(params, APP_CODE_KEYS) || window.localStorage.getItem("hyapp_app_code") || "lalu";
if (window.HyAppAPI) {
if (token) window.HyAppAPI.setAccessToken(token);
if (appCode) window.HyAppAPI.setAppCode(appCode);
function query() {
var params = new URLSearchParams(window.location.search);
var hash = window.location.hash || '';
if (hash.indexOf('?') >= 0) {
new URLSearchParams(hash.split('?').slice(1).join('?')).forEach(
function (value, key) {
if (!params.has(key)) params.set(key, value);
}
);
}
return params;
}
return {
token: token || (window.HyAppAPI && window.HyAppAPI.getAccessToken ? window.HyAppAPI.getAccessToken() : ""),
app_code: appCode,
raw: params
function first(params, keys) {
for (var i = 0; i < keys.length; i += 1) {
var value = params.get(keys[i]);
if (value) return value;
}
return '';
}
function parse() {
var params = query();
var token = first(params, TOKEN_KEYS);
var appCode =
first(params, APP_CODE_KEYS) ||
window.localStorage.getItem('hyapp_app_code') ||
'lalu';
if (window.HyAppAPI) {
if (token) window.HyAppAPI.setAccessToken(token);
if (appCode) window.HyAppAPI.setAppCode(appCode);
}
return {
token:
token ||
(window.HyAppAPI && window.HyAppAPI.getAccessToken
? window.HyAppAPI.getAccessToken()
: ''),
app_code: appCode,
raw: params,
};
}
function emit(name, detail) {
window.dispatchEvent(new CustomEvent(name, { detail: detail }));
}
function loadUser() {
var current = parse();
if (!current.token || !window.HyAppAPI) {
return Promise.resolve(null);
}
return window.HyAppAPI.get('/api/v1/users/me/overview')
.then(function (userInfo) {
current.user = userInfo;
window.HyAppParams.current = current;
emit(USER_READY_EVENT, current);
return current;
})
.catch(function (error) {
current.error = error;
window.HyAppParams.current = current;
emit(USER_ERROR_EVENT, current);
throw error;
});
}
window.HyAppParams = {
parse: parse,
loadUser: loadUser,
current: parse(),
USER_READY_EVENT: USER_READY_EVENT,
USER_ERROR_EVENT: USER_ERROR_EVENT,
};
}
function emit(name, detail) {
window.dispatchEvent(new CustomEvent(name, { detail: detail }));
}
function loadUser() {
var current = parse();
if (!current.token || !window.HyAppAPI) {
return Promise.resolve(null);
}
return window.HyAppAPI.get("/api/v1/users/me/overview").then(function (userInfo) {
current.user = userInfo;
window.HyAppParams.current = current;
emit(USER_READY_EVENT, current);
return current;
}).catch(function (error) {
current.error = error;
window.HyAppParams.current = current;
emit(USER_ERROR_EVENT, current);
throw error;
});
}
window.HyAppParams = {
parse: parse,
loadUser: loadUser,
current: parse(),
USER_READY_EVENT: USER_READY_EVENT,
USER_ERROR_EVENT: USER_ERROR_EVENT
};
})();

24
common/theme.css Normal file
View File

@ -0,0 +1,24 @@
:root {
--hy-theme-bg: #fbf8ff;
--hy-theme-surface: rgba(255, 255, 255, 0.96);
--hy-theme-surface-soft: #fdfaff;
--hy-theme-text: #282333;
--hy-theme-muted: #8d879a;
--hy-theme-line: #f0e8fb;
--hy-theme-primary: #dbc8ff;
--hy-theme-primary-strong: #c5a6f6;
--hy-theme-primary-deep: #7d57c7;
--hy-theme-primary-soft: #f4ebff;
--hy-theme-accent: #cfb8fb;
--hy-theme-success: #31c6a8;
--hy-theme-danger: #d95d72;
--hy-theme-shadow: 0 10px 24px rgba(132, 90, 212, 0.075);
--hy-theme-button: #c5a6f6;
--hy-theme-button-shadow: 0 8px 18px rgba(132, 90, 212, 0.11);
--hy-theme-hero: linear-gradient(
151deg,
#f0e6ff 0%,
#fffbff 58%,
rgba(251, 248, 255, 0.88) 100%
);
}

View File

@ -24,22 +24,22 @@ https://{h5-domain}/rank/index.html?token={access_token}&app_code=lalu
`env` 规则:
| 参数 | 说明 |
| --- | --- |
| 不传 | H5 请求 `https://api.global-interaction.com/` |
| `env=test` | H5 请求 `https://api-test.global-interaction.com/` |
| 参数 | 说明 |
| ----------- | -------------------------------------------------------- |
| 不传 | H5 请求 `https://api.global-interaction.com/` |
| `env=test` | H5 请求 `https://api-test.global-interaction.com/` |
| `env=local` | H5 请求 `http://localhost:13000/`,用于本机 gateway 联调 |
## URL 参数
| 参数 | 必填 | 说明 |
| --- | --- | --- |
| `token` | 是 | App 登录后拿到的 access token。H5 会作为 `Authorization: Bearer <token>` 调后端。 |
| `access_token` | 否 | `token` 的兼容别名。 |
| `accessToken` | 否 | `token` 的兼容别名。 |
| `app_code` | 是 | App 编码,当前传 `lalu`。H5 会作为 `X-App-Code` 请求头。 |
| `appCode` | 否 | `app_code` 的兼容别名。 |
| `env` | 否 | API 环境切换,见上表。 |
| 参数 | 必填 | 说明 |
| -------------- | ---- | --------------------------------------------------------------------------------- |
| `token` | 是 | App 登录后拿到的 access token。H5 会作为 `Authorization: Bearer <token>` 调后端。 |
| `access_token` | 否 | `token` 的兼容别名。 |
| `accessToken` | 否 | `token` 的兼容别名。 |
| `app_code` | 是 | App 编码,当前传 `lalu`。H5 会作为 `X-App-Code` 请求头。 |
| `appCode` | 否 | `app_code` 的兼容别名。 |
| `env` | 否 | API 环境切换,见上表。 |
H5 启动后会调用:
@ -61,19 +61,19 @@ X-App-Code: lalu
页面内包含三个榜单,通过 tab 切换:
| H5 Tab | 后端 `board_type` | 说明 |
| --- | --- | --- |
| `Wealth` | `sent` | 财富榜,按用户送礼总金币排行 |
| `Room` | `room` | 房间榜,按房间收礼总金币排行 |
| `Charm` | `received` | 魅力榜,按用户收礼总金币排行 |
| H5 Tab | 后端 `board_type` | 说明 |
| -------- | ----------------- | ---------------------------- |
| `Wealth` | `sent` | 财富榜,按用户送礼总金币排行 |
| `Room` | `room` | 房间榜,按房间收礼总金币排行 |
| `Charm` | `received` | 魅力榜,按用户收礼总金币排行 |
时间维度:
| H5 Tab | 后端 `period` |
| --- | --- |
| `Daily` | `today` |
| `Weekly` | `week` |
| `Monthly` | `month` |
| H5 Tab | 后端 `period` |
| --------- | ------------- |
| `Daily` | `today` |
| `Weekly` | `week` |
| `Monthly` | `month` |
排行榜接口:
@ -102,29 +102,29 @@ Flutter 只需要实现其中一种即可。推荐统一注册 `HyAppBridge`。
```json
{
"action": "openUser",
"payload": {
"user_id": "10001"
}
"action": "openUser",
"payload": {
"user_id": "10001"
}
}
```
### H5 发出的 action
| action | payload | 触发场景 | Flutter 行为 |
| --- | --- | --- | --- |
| `ready` | `{ "page": "rank" }` | H5 初始化完成 | 可关闭加载态 |
| `back` | `{}` | 用户点击左上角返回 | 关闭 WebView 或返回上一页 |
| `openUser` | `{ "user_id": "10001" }` | 点击财富榜/魅力榜用户头像、榜单项 | 打开用户详情页 |
| `openRoom` | `{ "room_id": "room_id" }` | 点击房间榜房间头像、榜单项 | 进入或打开房间详情 |
| `openRankNote` | `{ "board_type": "sent" }` | 点击右上角问号 | 当前 H5 已内置说明页Flutter 可只打点,不需要跳转 |
| action | payload | 触发场景 | Flutter 行为 |
| -------------- | -------------------------- | --------------------------------- | -------------------------------------------------- |
| `ready` | `{ "page": "rank" }` | H5 初始化完成 | 可关闭加载态 |
| `back` | `{}` | 用户点击左上角返回 | 关闭 WebView 或返回上一页 |
| `openUser` | `{ "user_id": "10001" }` | 点击财富榜/魅力榜用户头像、榜单项 | 打开用户详情页 |
| `openRoom` | `{ "room_id": "room_id" }` | 点击房间榜房间头像、榜单项 | 进入或打开房间详情 |
| `openRankNote` | `{ "board_type": "sent" }` | 点击右上角问号 | 当前 H5 已内置说明页Flutter 可只打点,不需要跳转 |
`board_type` 取值:
| 值 | 说明 |
| --- | --- |
| `sent` | 财富榜 |
| `room` | 房间榜 |
| 值 | 说明 |
| ---------- | ------ |
| `sent` | 财富榜 |
| `room` | 房间榜 |
| `received` | 魅力榜 |
## Flutter 示例
@ -218,19 +218,19 @@ final controller = WebViewController()
H5 依赖以下 Gateway HTTP 接口:
| 接口 | 说明 |
| --- | --- |
| `GET /api/v1/users/me/overview` | 解析 token 后获取当前用户信息 |
| `GET /api/v1/activities/user-leaderboards` | 获取排行榜 |
| 接口 | 说明 |
| ------------------------------------------ | ----------------------------- |
| `GET /api/v1/users/me/overview` | 解析 token 后获取当前用户信息 |
| `GET /api/v1/activities/user-leaderboards` | 获取排行榜 |
业务接口返回 envelope
```json
{
"code": "OK",
"message": "ok",
"request_id": "req_xxx",
"data": {}
"code": "OK",
"message": "ok",
"request_id": "req_xxx",
"data": {}
}
```

200
host-center/index.html Normal file
View File

@ -0,0 +1,200 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
/>
<title>Host Center</title>
<link rel="stylesheet" href="../common/theme.css" />
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<div
class="host-center"
aria-label="Host Center"
data-loading="false"
data-view="join-agency"
>
<div class="hero-bg" aria-hidden="true"></div>
<nav class="title-bar">
<button
class="back-button"
id="backButton"
type="button"
aria-label="Back"
data-i18n-aria="host_center.back"
>
<svg viewBox="0 0 32 32" aria-hidden="true">
<path d="M20 8 12 16l8 8" />
</svg>
</button>
<h1 data-i18n="host_center.title">Host Center</h1>
<div class="language-switcher">
<button
class="language-button"
type="button"
aria-label="Change language"
aria-expanded="false"
data-language-toggle
data-current-lang
data-i18n-aria="host_center.change_language"
>
EN
</button>
<div class="language-menu" data-language-menu hidden>
<button type="button" data-lang-option="en">EN</button>
<button type="button" data-lang-option="ar">AR</button>
<button type="button" data-lang-option="tr">TR</button>
<button type="button" data-lang-option="es">ES</button>
</div>
</div>
</nav>
<main class="content">
<section class="card profile-card">
<div class="avatar-shell"></div>
<div class="profile-copy">
<div
class="name"
id="profileName"
data-i18n="host_center.profile_name"
>
Namenamename
</div>
<div
class="meta"
id="profileUID"
data-i18n="host_center.uid"
>
UID: 12345678
</div>
<button class="agency" type="button" hidden>
<span>Agency</span>
</button>
</div>
</section>
<section class="card join-agency-card" id="joinAgencyCard">
<div class="join-agency-copy">
<div
class="join-agency-title"
data-i18n="host_center.join_title"
>
Join Agency
</div>
<div
class="join-agency-text"
data-i18n="host_center.join_text"
>
Search for an agency ID and submit your application.
</div>
</div>
<button
class="join-agency-action"
type="button"
data-i18n="host_center.join_now"
>
Join now
</button>
</section>
<section
class="join-agency-dialog-static"
aria-label="Join Agency"
data-i18n-aria="host_center.join_title"
>
<div class="join-agency-head">
<h2 data-i18n="host_center.join_title">Join Agency</h2>
</div>
<div class="join-agency-modal-body">
<form
class="join-agency-search-form"
id="joinAgencyForm"
>
<label class="join-agency-field">
<span data-i18n="host_center.agency_id"
>Agency ID</span
>
<div class="join-agency-search-control">
<input
id="agencySearchInput"
type="text"
inputmode="numeric"
autocomplete="off"
placeholder="Enter agency ID"
data-i18n-placeholder="host_center.enter_agency_id"
/>
<button
class="join-agency-search-button"
id="agencySearchButton"
type="submit"
data-i18n="host_center.search"
>
Search
</button>
</div>
</label>
</form>
<div
class="join-agency-status"
id="joinAgencyStatus"
role="status"
hidden
></div>
<section
class="join-agency-modal-card"
id="joinAgencyResult"
hidden
>
<div
class="join-agency-section-title"
data-i18n="host_center.agency"
>
Agency
</div>
<div class="join-agency-profile-row">
<div class="join-agency-avatar">
<span id="agencyInitial">A</span>
</div>
<div class="join-agency-profile-copy">
<div
class="join-agency-profile-name"
id="agencyName"
>
Agency Name
</div>
<div
class="join-agency-profile-account"
id="agencyAccount"
>
ID: 87654321
</div>
</div>
</div>
<button
class="join-agency-apply-button"
id="joinAgencyApplyButton"
type="button"
data-i18n="host_center.apply"
>
Apply
</button>
</section>
</div>
</section>
</main>
<div class="home-indicator" aria-hidden="true"></div>
</div>
<script src="../common/api.js"></script>
<script src="../common/params.js"></script>
<script src="../common/jsbridge.js"></script>
<script src="../common/i18n.js"></script>
<script src="./script.js"></script>
</body>
</html>

180
host-center/script.js Normal file
View File

@ -0,0 +1,180 @@
(function () {
var selectedAgency = null;
function $(id) {
return document.getElementById(id);
}
function t(key, fallback) {
return window.HyAppI18n && window.HyAppI18n.t
? window.HyAppI18n.t(key, fallback)
: fallback || key;
}
function setStatus(key, kind) {
var node = $('joinAgencyStatus');
if (!node) return;
if (!key) {
node.hidden = true;
node.textContent = '';
node.className = 'join-agency-status';
return;
}
node.hidden = false;
node.className = 'join-agency-status' + (kind ? ' is-' + kind : '');
node.textContent = t(key);
}
function setSearching(searching) {
var input = $('agencySearchInput');
var button = $('agencySearchButton');
if (input) input.disabled = searching;
if (button) {
button.disabled = searching;
button.textContent = searching
? t('host_center.searching', 'Searching...')
: t('host_center.search', 'Search');
}
}
function setApplying(applying) {
var button = $('joinAgencyApplyButton');
if (!button) return;
button.disabled = applying || !selectedAgency;
button.textContent = applying
? t('host_center.applying', 'Submitting...')
: t('host_center.apply', 'Apply');
}
function agencyID(agency) {
return String((agency && (agency.agency_id || agency.agencyId)) || '');
}
function agencyName(agency) {
return String((agency && agency.name) || '');
}
function renderAgency(agency) {
selectedAgency = agency || null;
var result = $('joinAgencyResult');
if (!result) return;
if (!selectedAgency) {
result.hidden = true;
setApplying(false);
return;
}
var name =
agencyName(selectedAgency) || t('host_center.agency', 'Agency');
result.hidden = false;
$('agencyName').textContent = name;
$('agencyAccount').textContent = 'ID: ' + agencyID(selectedAgency);
$('agencyInitial').textContent =
name.trim().charAt(0).toUpperCase() || 'A';
setApplying(false);
}
function searchAgency(event) {
if (event) event.preventDefault();
if (!window.HyAppAPI || !window.HyAppAPI.host) return;
var input = $('agencySearchInput');
var shortID = input ? input.value.trim() : '';
selectedAgency = null;
renderAgency(null);
if (!shortID) {
setStatus('host_center.search_required', 'error');
return;
}
setStatus('host_center.searching');
setSearching(true);
window.HyAppAPI.host
.searchAgencies(shortID, 20)
.then(function (data) {
var items = (data && (data.items || data.agencies)) || [];
if (!items.length) {
setStatus('host_center.no_agency', 'error');
return;
}
setStatus('');
renderAgency(items[0]);
})
.catch(function () {
setStatus('host_center.search_failed', 'error');
})
.finally(function () {
setSearching(false);
});
}
function applyAgency() {
if (!selectedAgency || !window.HyAppAPI || !window.HyAppAPI.host)
return;
setStatus('host_center.applying');
setApplying(true);
window.HyAppAPI.host
.applyToAgency({
agency_id: agencyID(selectedAgency),
command_id:
'host_apply_' +
Date.now() +
'_' +
Math.random().toString(16).slice(2),
})
.then(function () {
setStatus('host_center.apply_success', 'success');
})
.catch(function () {
setStatus('host_center.apply_failed', 'error');
})
.finally(function () {
setApplying(false);
});
}
function renderUser(current) {
var user = current && current.user;
var profile = user && (user.profile || user.user || user);
if (!profile) return;
var name = profile.username || profile.name || profile.nickname || '';
var uid =
profile.display_user_id ||
profile.displayUserId ||
profile.user_id ||
profile.userId ||
'';
if (name && $('profileName')) {
$('profileName').removeAttribute('data-i18n');
$('profileName').textContent = name;
}
if (uid && $('profileUID')) {
$('profileUID').removeAttribute('data-i18n');
$('profileUID').textContent = 'UID: ' + uid;
}
}
function init() {
if (window.HyAppParams) {
window.HyAppParams.parse();
window.HyAppParams.loadUser()
.then(renderUser)
.catch(function () {});
}
var form = $('joinAgencyForm');
if (form) form.addEventListener('submit', searchAgency);
var applyButton = $('joinAgencyApplyButton');
if (applyButton) applyButton.addEventListener('click', applyAgency);
var backButton = $('backButton');
if (backButton) {
backButton.addEventListener('click', function () {
if (window.HyAppBridge) window.HyAppBridge.back();
});
}
setApplying(false);
}
window.addEventListener('hyapp:i18n-ready', function () {
setSearching(false);
setApplying(false);
});
document.addEventListener('DOMContentLoaded', init);
})();

1420
host-center/style.css Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 605 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 605 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 605 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 769 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 769 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -0,0 +1,12 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 54 54" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 2090055542">
<rect id="Rectangle 346254111" width="54" height="54" rx="27" fill="url(#paint0_linear_0_5)"/>
<path id="Union" d="M29.0098 11.5957L31.4375 10.3252L33.1572 12.1826L34.9785 11.2051L34.1602 15.3232C38.9189 17.8052 42.1571 22.6822 42.1572 28.2891C42.1571 36.4089 35.3666 42.9999 27 43C18.6333 43 11.8429 36.409 11.8428 28.2891C11.8429 22.8375 14.9035 18.0752 19.4473 15.5342L18.5908 11.2051L20.4111 12.1826L22.1309 10.3252L24.5586 11.5957L26.7842 9.05371L29.0098 11.5957ZM26.877 21.3721C23.5263 21.3722 20.797 24.0032 20.7969 27.252C20.7969 29.3246 21.9037 31.133 23.5713 32.1768C20.6802 33.0863 18.3263 35.1637 17.1191 37.8369C19.6444 40.2987 23.1391 41.8232 27 41.8232C30.7734 41.8232 34.1963 40.3661 36.707 38.002C35.5269 35.2498 33.1439 33.1048 30.1826 32.1768C31.8501 31.1329 32.957 29.3246 32.957 27.252C32.9569 24.0031 30.2277 21.3721 26.877 21.3721ZM20.917 12.6709L22.6367 13.6484L23.9521 12.1826L22.1309 11.3027L20.917 12.6709ZM29.4141 12.1826L30.6279 13.6484L32.3477 12.6709L31.1338 11.3027L29.4141 12.1826ZM26.6836 7.00098C27.0881 7.00124 27.4921 7.39233 27.4922 7.7832C27.4921 8.17405 27.189 8.56522 26.6836 8.56543C26.279 8.56543 25.8742 8.17416 25.874 7.7832C25.8741 7.3922 26.1778 7.00098 26.6836 7.00098Z" fill="var(--fill-0, white)"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_5" x1="27" y1="0" x2="27" y2="54" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFBE5F"/>
<stop offset="1" stop-color="#F46E00"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,12 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 54 54" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 2090055541">
<rect id="Rectangle 346254111" width="54" height="54" rx="27" fill="url(#paint0_linear_0_14)"/>
<path id="Vector" d="M43.1127 20.9313H39.9276C39.7823 20.9338 39.6387 20.973 39.5124 21.0439L38.0771 16.6802C37.619 14.1992 35.8865 13 33.7595 13H20.2702C17.8271 13 16.3447 14.6073 15.9518 16.6777L14.5124 21.0556C14.3789 20.9752 14.2269 20.9318 14.0716 20.9296H10.8873C10.7709 20.9294 10.6556 20.9523 10.5481 20.9972C10.4405 21.042 10.3427 21.1079 10.2603 21.191C10.1779 21.2741 10.1125 21.3727 10.0678 21.4814C10.0232 21.59 10.0001 21.7065 10 21.8242V22.6003C10 23.0935 10.397 23.4957 10.8873 23.4957L12.0923 23.7044C11.6877 24.5129 11.4829 25.4086 11.4956 26.3147L11.0491 31.4637C11.0491 31.6123 11.0598 31.7641 11.078 31.9177C11.0601 32.014 11.0504 32.1118 11.0491 32.2098V38.4044C11.0491 39.2865 11.7572 40 12.6313 40H15.0456C15.2532 40.0004 15.4588 39.9595 15.6508 39.8795C15.8427 39.7996 16.0172 39.6821 16.1642 39.5339C16.3112 39.3858 16.4279 39.2097 16.5076 39.0159C16.5873 38.8221 16.6284 38.6143 16.6287 38.4044V36.4149H37.4002V38.4044C37.4002 39.2865 38.1084 40 38.9825 40H41.3984C41.6059 40.0003 41.8115 39.9593 42.0033 39.8793C42.1952 39.7993 42.3695 39.6818 42.5165 39.5336C42.6634 39.3855 42.78 39.2095 42.8597 39.0157C42.9393 38.822 42.9804 38.6142 42.9807 38.4044V32.2089C42.9807 32.1113 42.9699 32.0137 42.9509 31.9177C42.9691 31.7641 42.9807 31.6123 42.9807 31.4629L42.5333 26.3139C42.5333 25.3116 42.3154 24.4529 41.9341 23.7002L43.1119 23.4982C43.2284 23.4986 43.3438 23.4756 43.4516 23.4308C43.5593 23.3859 43.6572 23.32 43.7397 23.2369C43.8222 23.1537 43.8877 23.0549 43.9324 22.946C43.977 22.8372 44 22.7206 44 22.6028V21.8267C43.9989 21.5891 43.9049 21.3616 43.7385 21.1939C43.5721 21.0261 43.3469 20.9317 43.1119 20.9313H43.1127ZM17.0149 20.0158L18.0689 17.1851L18.0822 17.1183C18.187 16.5475 18.4206 16.4441 18.7672 16.0034H35.2732C35.6232 16.4574 35.8411 16.5726 35.936 17.1142L37.0082 20.0183L37.4011 21.5955C37.3119 22.7497 35.936 23.661 34.7945 23.661H19.2286C18.0846 23.661 16.7087 22.7497 16.6204 21.5947L17.0149 20.0158ZM17.7528 33.4782C17.4326 33.4736 17.1166 33.404 16.8235 33.2736C16.5304 33.1432 16.2661 32.9547 16.0464 32.7193C15.8266 32.4838 15.6558 32.2061 15.5441 31.9027C15.4324 31.5992 15.382 31.2762 15.396 30.9528C15.41 30.6293 15.488 30.312 15.6255 30.0196C15.7629 29.7271 15.957 29.4656 16.1962 29.2504C16.4355 29.0352 16.715 28.8707 17.0182 28.7666C17.3215 28.6626 17.6423 28.6211 17.9616 28.6447C18.5827 28.6906 19.1616 28.9793 19.5756 29.4497C19.9895 29.92 20.2059 30.535 20.1787 31.164C20.1515 31.793 19.883 32.3865 19.43 32.8186C18.9771 33.2507 18.3755 33.4873 17.7528 33.4782ZM31.1414 31.6949C31.1407 31.8857 31.0653 32.0684 30.9316 32.2031C30.7979 32.3378 30.6169 32.4134 30.4282 32.4134H23.7038C23.5153 32.4134 23.3344 32.3379 23.2007 32.2034C23.0671 32.0689 22.9916 31.8864 22.9907 31.6957V29.6753C22.9907 29.2781 23.311 28.9568 23.7038 28.9568H30.4282C30.8211 28.9568 31.1414 29.2781 31.1414 29.6745V31.6949ZM36.2703 33.4782C35.9559 33.4788 35.6445 33.4167 35.3538 33.2955C35.0631 33.1744 34.7989 32.9965 34.5763 32.7721C34.3536 32.5476 34.1768 32.2811 34.0561 31.9875C33.9354 31.694 33.873 31.3794 33.8726 31.0615C33.873 30.7436 33.9354 30.4289 34.0561 30.1354C34.1768 29.8419 34.3536 29.5753 34.5763 29.3509C34.7989 29.1265 35.0631 28.9486 35.3538 28.8274C35.6445 28.7062 35.9559 28.6442 36.2703 28.6447C36.5846 28.6443 36.896 28.7064 37.1865 28.8277C37.4771 28.9489 37.7412 29.1268 37.9638 29.3512C38.1864 29.5756 38.363 29.8421 38.4837 30.1356C38.6044 30.429 38.6668 30.7437 38.6672 31.0615C38.6659 31.7032 38.4127 32.3181 37.9633 32.7713C37.5139 33.2244 36.905 33.4787 36.2703 33.4782Z" fill="var(--fill-0, white)"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_14" x1="27" y1="0" x2="27" y2="54" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFBE5F"/>
<stop offset="1" stop-color="#F46E00"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,12 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 54 54" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 2090055541">
<path id="Rectangle 346254111" d="M0 27C0 12.0883 12.0883 0 27 0V0C41.9117 0 54 12.0883 54 27V27C54 41.9117 41.9117 54 27 54V54C12.0883 54 0 41.9117 0 27V27Z" fill="url(#paint0_linear_0_6)"/>
<path id="Vector" d="M42.8277 31.0058C41.787 21.6828 39.9456 15 34.1012 15C31.139 15 29.6178 18.1352 26.9758 18.3827C24.2538 18.1352 22.8127 15 19.8505 15C14.0061 15 12.1647 21.6828 11.204 30.9233C10.6436 35.8736 11.1239 39.9988 14.0862 39.9988C18.2493 39.9988 18.4094 36.1211 21.3716 34.306C22.4925 33.7285 24.9743 33.4809 27.0559 33.3984C29.1375 33.4809 31.6193 33.7285 32.7402 34.306C35.7024 36.1211 35.8625 39.9988 40.0256 39.9988C42.9078 40.0813 43.3081 35.9561 42.8277 31.0058ZM19.9306 30.1808C17.6088 30.1808 15.7674 28.2007 15.7674 25.8906C15.7674 23.5804 17.6088 21.6003 19.9306 21.6003C22.2523 21.6003 24.0937 23.4979 24.0937 25.8906C24.0937 28.2832 22.1722 30.1808 19.9306 30.1808ZM38.5846 26.7156H35.3021V30.0983H33.7009V26.7156H30.4184V25.0655H33.7009V21.7653H35.3021V25.0655H38.5846V26.7156Z" fill="var(--fill-0, white)"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_6" x1="27" y1="0" x2="27" y2="54" gradientUnits="userSpaceOnUse">
<stop stop-color="#13D026"/>
<stop offset="1" stop-color="#18A56A"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,12 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 54 54" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 2090055540">
<rect id="Rectangle 346254111" width="54" height="54" rx="27" fill="url(#paint0_linear_0_4)"/>
<path id="Vector" d="M27.9375 28.3424V38.9703C27.9375 39.0943 27.832 39.1958 27.7031 39.1958H26.2969C26.168 39.1958 26.0625 39.0943 26.0625 38.9703V28.3424H13.875V39.1958C13.875 40.1909 14.7158 41 15.75 41H38.25C39.2871 41 40.125 40.1909 40.125 39.1958V28.3424H27.9375ZM38.25 18.4474H37.0195C36.832 18.4474 36.7207 18.2445 36.8262 18.095C37.2832 17.441 37.5059 16.7222 37.459 16.0089C37.4033 15.1576 36.958 14.419 36.1758 13.8721C35.6133 13.4802 34.8662 13.1955 34.0752 13.0658C32.6396 12.8347 31.1191 13.2265 29.7891 14.1737C29.0742 14.684 28.4238 15.3352 27.8437 16.1245C27.4717 16.6291 26.6895 16.6291 26.3174 16.1245C25.7373 15.3352 25.0869 14.6811 24.3721 14.1737C23.0449 13.2265 21.5244 12.8318 20.0889 13.0658C19.2979 13.1955 18.5508 13.4802 17.9883 13.8721C17.2061 14.4162 16.7607 15.1547 16.7051 16.0089C16.6582 16.7222 16.8779 17.441 17.3379 18.095C17.4434 18.2445 17.335 18.4474 17.1445 18.4474H15.75C13.6787 18.4474 12 20.0628 12 22.0558V25.6642C12 26.0843 12.2988 26.4395 12.7031 26.5382H41.2969C41.7012 26.4395 42 26.0843 42 25.6642V22.0558C42 20.0628 40.3213 18.4474 38.25 18.4474ZM28.7607 18.112C30.3193 15.3915 32.2939 14.605 33.7617 14.8446C33.9404 14.8728 35.5195 15.1576 35.5869 16.1245C35.6426 16.9674 34.6758 18.0838 33.0088 18.4474H28.9658C28.7871 18.4474 28.6758 18.2642 28.7607 18.112ZM18.5742 16.1245C18.6387 15.1576 20.2178 14.8757 20.3994 14.8446C21.8701 14.6078 23.8447 15.3915 25.4004 18.112C25.4883 18.2614 25.374 18.4474 25.1953 18.4474H21.1523C19.4883 18.0809 18.5186 16.9674 18.5742 16.1245Z" fill="var(--fill-0, white)"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_4" x1="27" y1="0" x2="27" y2="54" gradientUnits="userSpaceOnUse">
<stop stop-color="#E25FFF"/>
<stop offset="1" stop-color="#9200F4"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,12 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 54 54" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 2090055540">
<rect id="Rectangle 346254111" width="54" height="54" rx="27" fill="url(#paint0_linear_0_17)"/>
<path id="Vector" d="M27.9375 28.3424V38.9703C27.9375 39.0943 27.832 39.1958 27.7031 39.1958H26.2969C26.168 39.1958 26.0625 39.0943 26.0625 38.9703V28.3424H13.875V39.1958C13.875 40.1909 14.7158 41 15.75 41H38.25C39.2871 41 40.125 40.1909 40.125 39.1958V28.3424H27.9375ZM38.25 18.4474H37.0195C36.832 18.4474 36.7207 18.2445 36.8262 18.095C37.2832 17.441 37.5059 16.7222 37.459 16.0089C37.4033 15.1576 36.958 14.419 36.1758 13.8721C35.6133 13.4802 34.8662 13.1955 34.0752 13.0658C32.6396 12.8347 31.1191 13.2265 29.7891 14.1737C29.0742 14.684 28.4238 15.3352 27.8437 16.1245C27.4717 16.6291 26.6895 16.6291 26.3174 16.1245C25.7373 15.3352 25.0869 14.6811 24.3721 14.1737C23.0449 13.2265 21.5244 12.8318 20.0889 13.0658C19.2979 13.1955 18.5508 13.4802 17.9883 13.8721C17.2061 14.4162 16.7607 15.1547 16.7051 16.0089C16.6582 16.7222 16.8779 17.441 17.3379 18.095C17.4434 18.2445 17.335 18.4474 17.1445 18.4474H15.75C13.6787 18.4474 12 20.0628 12 22.0558V25.6642C12 26.0843 12.2988 26.4395 12.7031 26.5382H41.2969C41.7012 26.4395 42 26.0843 42 25.6642V22.0558C42 20.0628 40.3213 18.4474 38.25 18.4474ZM28.7607 18.112C30.3193 15.3915 32.2939 14.605 33.7617 14.8446C33.9404 14.8728 35.5195 15.1576 35.5869 16.1245C35.6426 16.9674 34.6758 18.0838 33.0088 18.4474H28.9658C28.7871 18.4474 28.6758 18.2642 28.7607 18.112ZM18.5742 16.1245C18.6387 15.1576 20.2178 14.8757 20.3994 14.8446C21.8701 14.6078 23.8447 15.3915 25.4004 18.112C25.4883 18.2614 25.374 18.4474 25.1953 18.4474H21.1523C19.4883 18.0809 18.5186 16.9674 18.5742 16.1245Z" fill="var(--fill-0, white)"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_17" x1="27" y1="0" x2="27" y2="54" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFBE5F"/>
<stop offset="1" stop-color="#F46E00"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

341
level/index.html Normal file
View File

@ -0,0 +1,341 @@
<!doctype html>
<html lang="en" translate="no">
<head>
<meta charset="utf-8">
<meta name="google" content="notranslate">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover">
<title>Level</title>
<link rel="stylesheet" href="../common/theme.css">
<style>
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
:root { --app-scale: 1; }
html, body { margin: 0; width: 100%; min-height: 100%; overflow-x: hidden; background: #130a2b; color: #fff; font-family: Arial, Helvetica, sans-serif; }
button { border: 0; padding: 0; background: transparent; color: inherit; font: inherit; cursor: pointer; outline: none; }
.app-viewport { position: relative; width: 375px; height: 826px; margin: 0 auto; transform: scale(var(--app-scale)); transform-origin: top center; }
.page { position: relative; width: 375px; height: 826px; overflow: hidden; background: #130a2b; }
.page-bg { position: absolute; left: -28px; top: -297px; width: 599px; height: 1123px; object-fit: cover; opacity: .54; pointer-events: none; }
.home-indicator { position: absolute; left: 121px; bottom: 8px; z-index: 8; width: 134px; height: 5px; border-radius: 100px; background: #fff; }
.nav { position: absolute; left: 0; top: 0; z-index: 5; width: 375px; height: 44px; }
.back { position: absolute; left: 16px; top: 10px; width: 24px; height: 24px; }
.back::before { content: ""; position: absolute; left: 7px; top: 5px; width: 13px; height: 13px; border-left: 2px solid #fff; border-bottom: 2px solid #fff; transform: rotate(45deg); }
.title { position: absolute; left: 0; top: 13px; width: 375px; font-size: 18px; line-height: 18px; font-weight: 500; text-align: center; text-transform: capitalize; }
.tabs { position: absolute; left: 0; top: 58px; z-index: 5; width: 375px; height: 30px; }
.tab { position: absolute; top: 0; width: 92px; height: 30px; color: rgba(255,255,255,.5); font-size: 18px; line-height: 18px; font-weight: 700; text-align: center; text-transform: capitalize; }
.tab[data-track="wealth"] { left: 16px; }
.tab[data-track="charm"] { left: 142px; }
.tab[data-track="game"] { left: 266px; }
.tab.active { color: #fff; opacity: 1; }
.tab.active::after { content: ""; position: absolute; left: 50%; top: 24px; width: 16px; height: 3px; margin-left: -8px; border-radius: 31px; background: #fff; }
.level-card { position: absolute; left: 16px; top: 111px; z-index: 2; width: 343px; height: 111px; overflow: hidden; background: transparent; }
.level-card-bg { display: block; width: 343px; height: 111px; object-fit: cover; }
.card-decor { position: absolute; left: 24px; top: 99px; z-index: 3; width: 164px; height: 27px; object-fit: cover; }
.card-decor.right { left: 188px; transform: rotate(180deg) scaleY(-1); }
.level-name { position: absolute; left: 40px; top: 133px; z-index: 4; font-size: 16px; line-height: 16px; font-weight: 900; text-transform: capitalize; color: var(--title-fill, #fff); text-shadow: 0 2px 0 var(--title-shadow); }
.avatar-wrap { position: absolute; left: 259px; top: 126px; z-index: 4; width: 80px; height: 80px; }
.avatar { position: absolute; left: 11px; top: 11px; width: 58px; height: 58px; border-radius: 50%; object-fit: cover; }
.avatar-frame { position: absolute; inset: 0; width: 80px; height: 80px; object-fit: cover; }
.progress { position: absolute; left: 40px; top: 171px; z-index: 4; width: 182px; height: 38px; color: var(--progress-text); }
.lv-current, .lv-next { position: absolute; top: 7px; font-size: 12px; line-height: 12px; text-transform: capitalize; }
.lv-current { left: 0; }
.lv-next { left: 159px; }
.progress-percent { position: absolute; left: 67px; top: 0; width: 45px; font-size: 8px; line-height: 8px; text-align: center; }
.progress-track { position: absolute; left: 24px; top: 12px; width: 133px; height: 4px; border-radius: 3px; background: var(--progress-track); }
.progress-fill { width: 40%; height: 4px; border-radius: 3px; background: var(--progress-fill); }
.need { position: absolute; left: 0; top: 27px; width: 220px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 8px; line-height: 8px; color: var(--need-text); }
.level-table { position: absolute; left: 16px; top: 238px; z-index: 2; width: 343px; height: 318px; border-radius: 12px; background: rgba(67,0,255,.11); }
.table-head { position: absolute; top: 16px; height: 16px; font-size: 16px; line-height: 16px; font-weight: 500; text-align: center; text-transform: capitalize; white-space: nowrap; }
.head-range { left: 19px; width: 49px; }
.head-icons { left: 124px; width: 42px; }
.head-frame { left: 226px; width: 96px; }
.tier-row { position: absolute; left: 0; z-index: 2; width: 343px; height: 46px; }
.tier-row.r1 { top: 44px; }
.tier-row.r2 { top: 98px; }
.tier-row.r3 { top: 152px; }
.tier-row.r4 { top: 206px; }
.tier-row.r5 { top: 260px; }
.range { position: absolute; left: 29px; top: 16px; width: 30px; font-size: 14px; line-height: 14px; text-align: center; }
.badge-icon { position: absolute; left: 113px; top: 11px; width: 62px; height: 24px; object-fit: contain; }
.frame-icon { position: absolute; left: 250px; top: 0; width: 46px; height: 46px; object-fit: contain; }
.upgrade-title { position: absolute; left: 0; top: 574px; z-index: 3; width: 375px; color: var(--upgrade-title); font-size: 20px; line-height: 20px; font-weight: 700; text-align: center; }
.upgrade-list { position: absolute; left: 0; top: 616px; z-index: 3; width: 375px; height: 98px; }
.upgrade-item { position: absolute; top: 0; width: 119px; text-align: center; }
.upgrade-one { left: 128px; width: 120px; }
.upgrade-three:nth-child(1) { left: 1px; }
.upgrade-three:nth-child(2) { left: 128px; }
.upgrade-three:nth-child(3) { left: 255px; }
.upgrade-icon { display: block; width: 54px; height: 54px; margin: 0 auto; object-fit: contain; }
.upgrade-name { margin-top: 10px; font-size: 14px; line-height: 14px; font-weight: 500; white-space: nowrap; }
.upgrade-exp { margin-top: 8px; font-size: 14px; line-height: 14px; white-space: nowrap; }
.consume { position: absolute; left: 43px; top: 736px; z-index: 4; width: 289px; height: 50px; overflow: hidden; border: 1.5px solid #fff09b; background: #2a1351; color: #fff; font-size: 18px; line-height: 49px; font-weight: 700; text-align: center; }
.consume-bg { position: absolute; inset: -26px -38px; width: 363px; height: 104px; object-fit: cover; opacity: .8; mix-blend-mode: plus-lighter; pointer-events: none; }
.consume.gold .consume-bg { inset: -38px -79px; width: 447px; height: 127px; opacity: 1; mix-blend-mode: normal; }
.consume span { position: relative; z-index: 2; }
.corner { position: absolute; z-index: 3; width: 16px; height: 16px; object-fit: contain; }
.corner.c1 { left: 0; top: 0; }
.corner.c2 { right: 0; top: 0; transform: rotate(90deg); }
.corner.c3 { right: 0; bottom: 0; transform: rotate(180deg); }
.corner.c4 { left: 0; bottom: 0; transform: rotate(270deg); }
.hit { position: absolute; z-index: 7; border-radius: 8px; }
.hit-consume { left: 43px; top: 736px; width: 289px; height: 50px; }
.loading-overlay { position: absolute; inset: 0; z-index: 20; display: none; align-items: center; justify-content: center; background: rgba(19,10,43,.32); backdrop-filter: blur(1px); pointer-events: auto; }
.loading-overlay.active { display: flex; }
.cat-loader { width: 72px; height: 72px; display: flex; align-items: center; justify-content: center; border-radius: 50%; background: rgba(0,0,0,.18); box-shadow: 0 8px 28px rgba(0,0,0,.28); }
.cat-loader svg { width: 54px; height: 54px; overflow: visible; animation: cat-float 1.1s ease-in-out infinite; }
.cat-line { fill: none; stroke: #fff; stroke-width: 3.4; stroke-linecap: round; stroke-linejoin: round; }
.cat-eye { transform-origin: center; animation: cat-blink 1.6s ease-in-out infinite; }
.cat-whisker { opacity: .9; animation: cat-whisker 1.1s ease-in-out infinite; }
.toast { position: fixed; left: 50%; bottom: calc(34px * var(--app-scale)); z-index: 60; max-width: 300px; transform: translateX(-50%); padding: 8px 12px; border-radius: 16px; background: rgba(0,0,0,.62); color: #fff; font-size: 12px; line-height: 16px; text-align: center; opacity: 0; pointer-events: none; transition: opacity .18s ease; }
.toast.show { opacity: 1; }
@keyframes cat-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }
@keyframes cat-blink { 0%, 72%, 100% { transform: scaleY(1); } 80%, 88% { transform: scaleY(.18); } }
@keyframes cat-whisker { 0%, 100% { opacity: .62; } 50% { opacity: 1; } }
</style>
</head>
<body>
<div id="appViewport" class="app-viewport">
<main id="page" class="page">
<img id="pageBg" class="page-bg" alt="">
<nav class="nav" aria-label="Level navigation">
<button id="backButton" class="back" aria-label="Back"></button>
<div class="title">Level</div>
</nav>
<div id="tabs" class="tabs">
<button class="tab" data-track="wealth">Wealth</button>
<button class="tab" data-track="charm">Charm</button>
<button class="tab" data-track="game">Game</button>
</div>
<section class="level-card" aria-label="Current level"><img id="cardBg" class="level-card-bg" alt=""></section>
<img id="decorLeft" class="card-decor" alt="">
<img id="decorRight" class="card-decor right" alt="">
<div id="levelName" class="level-name">Level 0</div>
<div class="avatar-wrap">
<img id="avatar" class="avatar" alt="">
<img id="avatarFrame" class="avatar-frame" alt="">
</div>
<div class="progress">
<div id="lvCurrent" class="lv-current">Lv.0</div>
<div id="progressPercent" class="progress-percent">40%</div>
<div class="progress-track"><div id="progressFill" class="progress-fill"></div></div>
<div id="lvNext" class="lv-next">Lv.1</div>
<div id="needText" class="need">You need 12,345,600 more experience points</div>
</div>
<section class="level-table" aria-label="Level tiers">
<div class="table-head head-range">Range</div>
<div class="table-head head-icons">Icons</div>
<div class="table-head head-frame">Profile Frame</div>
<div id="tierRows"></div>
</section>
<div id="upgradeTitle" class="upgrade-title">How to upgrade</div>
<div id="upgradeList" class="upgrade-list"></div>
<button id="consumeButton" class="consume" aria-label="To consume"></button>
<button id="consumeHit" class="hit hit-consume" aria-label="To consume"></button>
<div class="home-indicator"></div>
<div id="loadingOverlay" class="loading-overlay" aria-hidden="true">
<div class="cat-loader" aria-label="Loading">
<svg viewBox="0 0 64 64" role="img" aria-hidden="true">
<path class="cat-line" d="M15 31 C15 19 24 14 32 14 C40 14 49 19 49 31 C49 43 42 50 32 50 C22 50 15 43 15 31 Z"/>
<path class="cat-line" d="M20 18 L16 7 L27 14"/>
<path class="cat-line" d="M44 18 L48 7 L37 14"/>
<path class="cat-line cat-eye" d="M25 31 L25 32"/>
<path class="cat-line cat-eye" d="M39 31 L39 32"/>
<path class="cat-line" d="M32 35 L29 38 L35 38 Z"/>
<path class="cat-line cat-whisker" d="M11 32 H23"/>
<path class="cat-line cat-whisker" d="M10 40 L23 37"/>
<path class="cat-line cat-whisker" d="M41 32 H53"/>
<path class="cat-line cat-whisker" d="M41 37 L54 40"/>
</svg>
</div>
</div>
</main>
</div>
<div id="toast" class="toast"></div>
<script src="../common/api.js"></script>
<script src="../common/params.js"></script>
<script src="../common/jsbridge.js"></script>
<script>
(function () {
var A = "assets/component/";
var tracks = {
charm: {
bg: A + "bg-charm.png", cardBg: A + "card-charm.png", decor: A + "decor-charm.png", avatar: A + "avatar-charm.png", frame: A + "avatar-frame-charm.png",
card: "#130828", texture: "url('" + A + "button-purple.png')", textureOpacity: .26, glow: "linear-gradient(176deg, #462a78 36%, rgba(59,36,100,0) 63%)",
titleFill: "#ffffff", titleShadow: "#be1e21", titleGradient: "linear-gradient(135deg, #fff 27%, #f4cbff 49%, #fff 72%)",
progress: "#fff", progressTrack: "rgba(255,255,255,.2)", progressFill: "#fff", need: "rgba(255,255,255,.6)", upgrade: "#f718e9",
button: "purple", upgrades: [{ icon: A + "upgrade-gift-charm.svg", name: "Receive a gift", exp: "1 Coins = 1 EXP" }]
},
wealth: {
bg: A + "bg-wealth.png", cardBg: A + "card-wealth.png", decor: A + "decor-wealth.png", avatar: A + "avatar-wealth.png", frame: A + "avatar-frame-wealth.png",
card: "#ffa85c", texture: "url('" + A + "button-gold.png')", textureOpacity: .41, glow: "linear-gradient(165deg, rgba(255,242,130,.62) 35%, rgba(255,242,130,0) 48%), linear-gradient(-12deg, rgba(255,242,130,.55) 26%, rgba(255,242,130,0) 28%)",
titleFill: "#fff7e8", titleShadow: "#be561e", titleGradient: "linear-gradient(135deg, #fff 27%, #ffdfcb 49%, #fff 72%)",
progress: "#b7420c", progressTrack: "rgba(183,66,12,.2)", progressFill: "#b7420c", need: "rgba(183,66,12,.6)", upgrade: "#ffbe5f",
button: "gold", upgrades: [
{ icon: A + "upgrade-gift-wealth.svg", name: "Receive a Gift", exp: "1 Coins = 1 EXP" },
{ icon: A + "upgrade-car-wealth.svg", name: "Buy a car", exp: "1 Coins = 1 EXP" },
{ icon: A + "upgrade-avatar-wealth.svg", name: "Buy Avatar Frame", exp: "1 Coins = 1 EXP" }
]
},
game: {
bg: A + "bg-game.png", cardBg: A + "card-game.png", decor: A + "decor-game.png", avatar: A + "avatar-game.png", frame: A + "avatar-frame-game.png",
card: "#118624", texture: "url('" + A + "button-purple.png')", textureOpacity: .38, glow: "linear-gradient(165deg, rgba(255,242,130,.34) 35%, rgba(255,242,130,0) 48%), linear-gradient(-12deg, rgba(255,242,130,.3) 26%, rgba(255,242,130,0) 28%)",
titleFill: "#f2fff2", titleShadow: "#5ba626", titleGradient: "linear-gradient(135deg, #fff 27%, #cbffd7 49%, #fff 72%)",
progress: "#fff", progressTrack: "rgba(255,255,255,.2)", progressFill: "#fff", need: "rgba(255,255,255,.6)", upgrade: "#ffbe5f",
button: "purple", upgrades: [{ icon: A + "upgrade-game.svg", name: "Earned through gameplay", exp: "1 Coins = 1 EXP" }]
}
};
var state = { track: new URLSearchParams(window.location.search).get("track") || "charm", loading: false, details: {}, toastTimer: 0 };
function byId(id) { return document.getElementById(id); }
function track() { return tracks[state.track] ? state.track : "charm"; }
function fmt(n) { return Number(n || 0).toLocaleString("en-US"); }
function ratio(d) {
var o = d && d.overview ? d.overview : {};
var cur = Number(o.current_level_required_value || 0);
var next = Number(o.next_level_required_value || 0);
var total = Number(o.total_value || 0);
if (next <= cur) return .4;
return Math.max(0, Math.min(1, (total - cur) / (next - cur)));
}
function resizeApp() {
var scale = Math.min(window.innerWidth / 375, 1.25);
document.documentElement.style.setProperty("--app-scale", String(scale));
byId("appViewport").style.height = "826px";
document.body.style.minHeight = Math.ceil(826 * scale) + "px";
}
function syncLoading() {
var overlay = byId("loadingOverlay");
overlay.classList.toggle("active", state.loading);
overlay.setAttribute("aria-hidden", state.loading ? "false" : "true");
}
function showToast(message) {
var toast = byId("toast");
toast.textContent = message;
toast.classList.add("show");
window.clearTimeout(state.toastTimer);
state.toastTimer = window.setTimeout(function () { toast.classList.remove("show"); }, 1800);
}
function rowsHTML(name, detail) {
var tiers = ((detail && detail.tiers) || []).slice().sort(function (a, b) {
return Number(a.min_level || 0) - Number(b.min_level || 0);
});
function rangeText(index) {
var tier = tiers[index - 1];
if (!tier) return "1-10";
var min = Number(tier.min_level || 0);
var max = Number(tier.max_level || 0);
if (!min && !max) return "1-10";
return min + "-" + max;
}
return [1, 2, 3, 4, 5].map(function (i) {
return '<div class="tier-row r' + i + '"><div class="range">' + rangeText(i) + '</div><img class="badge-icon" src="' + A + name + '-icon-' + i + '.png" alt=""><img class="frame-icon" src="' + A + name + '-frame-' + i + '.png" alt=""></div>';
}).join("");
}
function upgradesHTML(cfg) {
var cls = cfg.upgrades.length === 3 ? "upgrade-three" : "upgrade-one";
return cfg.upgrades.map(function (item) {
return '<div class="upgrade-item ' + cls + '"><img class="upgrade-icon" src="' + item.icon + '" alt=""><div class="upgrade-name">' + item.name + '</div><div class="upgrade-exp">' + item.exp + '</div></div>';
}).join("");
}
function buttonHTML(cfg) {
var corner = cfg.button === "gold" ? A + "corner-gold.png" : A + "corner-purple.png";
var texture = cfg.button === "gold" ? A + "button-gold.png" : A + "button-purple.png";
return '<img class="consume-bg" src="' + texture + '" alt=""><img class="corner c1" src="' + corner + '" alt=""><img class="corner c2" src="' + corner + '" alt=""><img class="corner c3" src="' + corner + '" alt=""><img class="corner c4" src="' + corner + '" alt=""><span>To consume</span>';
}
function applyData() {
var d = state.details[state.track];
var o = d && d.overview ? d.overview : {};
var level = Number(o.level || 0);
var next = Number(o.next_level || level + 1);
var percent = Math.round(ratio(d) * 100);
byId("levelName").textContent = "Level " + level;
byId("lvCurrent").textContent = "Lv." + level;
byId("lvNext").textContent = "Lv." + next;
byId("progressPercent").textContent = percent + "%";
byId("progressFill").style.width = percent + "%";
var need = Math.max(0, Number(o.next_level_required_value || 12345600) - Number(o.total_value || 0));
byId("needText").textContent = "You need " + fmt(need) + " more experience points";
}
function render() {
state.track = track();
var cfg = tracks[state.track];
byId("pageBg").src = cfg.bg;
byId("cardBg").src = cfg.cardBg;
byId("decorLeft").src = cfg.decor;
byId("decorRight").src = cfg.decor;
byId("avatar").src = cfg.avatar;
byId("avatarFrame").src = cfg.frame;
byId("tierRows").innerHTML = rowsHTML(state.track, state.details[state.track]);
byId("upgradeList").innerHTML = upgradesHTML(cfg);
byId("consumeButton").className = "consume " + (cfg.button === "gold" ? "gold" : "");
byId("consumeButton").innerHTML = buttonHTML(cfg);
document.documentElement.style.setProperty("--card-texture", cfg.texture);
document.documentElement.style.setProperty("--card-texture-opacity", cfg.textureOpacity);
document.documentElement.style.setProperty("--card-glow", cfg.glow);
document.documentElement.style.setProperty("--title-shadow", cfg.titleShadow);
document.documentElement.style.setProperty("--title-fill", cfg.titleFill);
document.documentElement.style.setProperty("--title-gradient", cfg.titleGradient);
document.documentElement.style.setProperty("--progress-text", cfg.progress);
document.documentElement.style.setProperty("--progress-track", cfg.progressTrack);
document.documentElement.style.setProperty("--progress-fill", cfg.progressFill);
document.documentElement.style.setProperty("--need-text", cfg.need);
document.documentElement.style.setProperty("--upgrade-title", cfg.upgrade);
document.querySelectorAll(".tab").forEach(function (node) { node.classList.toggle("active", node.dataset.track === state.track); });
applyData();
syncLoading();
resizeApp();
}
function loadOverview() {
if (!window.HyAppAPI || !window.HyAppAPI.level || !window.HyAppAPI.getAccessToken()) return Promise.resolve(null);
return window.HyAppAPI.level.overview().then(function (data) {
((data && data.tracks) || []).forEach(function (item) {
if (!item || !item.track || !tracks[item.track]) return;
if (!state.details[item.track]) state.details[item.track] = {};
state.details[item.track].overview = item;
});
render();
return data;
}).catch(function () { return null; });
}
function loadTrack(name) {
state.track = tracks[name] ? name : "charm";
if (window.history && window.history.replaceState) {
var url = new URL(window.location.href);
url.searchParams.set("track", state.track);
window.history.replaceState(null, "", url.toString());
}
render();
if (!window.HyAppAPI || !window.HyAppAPI.level || !window.HyAppAPI.getAccessToken()) return Promise.resolve(null);
state.loading = true;
render();
return window.HyAppAPI.level.track(state.track).then(function (data) {
state.details[state.track] = data;
}).catch(function (error) {
showToast((error && error.message) || "Network error");
}).finally(function () {
state.loading = false;
render();
});
}
byId("tabs").addEventListener("click", function (event) {
var target = event.target.closest("[data-track]");
if (!target) return;
loadTrack(target.dataset.track);
});
byId("backButton").addEventListener("click", function () { window.HyAppBridge.back(); });
byId("consumeHit").addEventListener("click", function () { window.HyAppBridge.post("openLevelConsume", { track: state.track }); });
window.addEventListener("resize", resizeApp);
window.addEventListener("orientationchange", function () { window.requestAnimationFrame(resizeApp); });
render();
window.HyAppBridge.ready({ page: "level" });
loadTrack(state.track).finally(function () {
loadOverview();
window.HyAppParams.loadUser().catch(function () { return null; });
});
})();
</script>
</body>
</html>

31
package-lock.json generated Normal file
View File

@ -0,0 +1,31 @@
{
"name": "hyapp-h5",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "hyapp-h5",
"version": "1.0.0",
"devDependencies": {
"prettier": "^3.0.0"
}
},
"node_modules/prettier": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
"integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
}
}
}

12
package.json Normal file
View File

@ -0,0 +1,12 @@
{
"name": "hyapp-h5",
"version": "1.0.0",
"description": "H5 project",
"scripts": {
"format": "prettier --write \"**/*.{js,html,css,json,md}\"",
"format:check": "prettier --check \"**/*.{js,html,css,json,md}\""
},
"devDependencies": {
"prettier": "^3.0.0"
}
}

File diff suppressed because it is too large Load Diff

BIN
vip/assets/avatar-frame.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 KiB

9
vip/assets/back.png Normal file
View File

@ -0,0 +1,9 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="icon_20_&#232;&#191;&#148;&#229;&#155;&#158;">
<g id="Vector">
</g>
<g id="Vector_2">
</g>
<path id="Vector_3" d="M16 4L8 12L16 20" stroke="var(--stroke-0, white)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 419 B

BIN
vip/assets/badge-vip7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 KiB

BIN
vip/assets/bg-meteor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
vip/assets/bg-palace.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
vip/assets/bg-starry.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

BIN
vip/assets/coin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
vip/assets/corner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 B

BIN
vip/assets/divider.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

BIN
vip/assets/entry-effect.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

BIN
vip/assets/entry-frame.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 KiB

View File

@ -0,0 +1,7 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 375 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 594">
<g id="Vector">
</g>
<path id="Vector_2" d="M252.5 10H123.5C122.119 10 121 11.1193 121 12.5C121 13.8807 122.119 15 123.5 15H252.5C253.881 15 255 13.8807 255 12.5C255 11.1193 253.881 10 252.5 10Z" fill="var(--fill-0, white)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 428 B

3
vip/assets/icon-id.png Normal file
View File

@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 24 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M2.48242 0.25C3.03402 0.250028 3.56802 0.464819 3.97949 0.855469C4.33989 1.19768 4.58346 1.6537 4.6748 2.15332L4.70508 2.36914L4.71582 2.60742V18.1699C4.71549 18.7756 4.49169 19.3557 4.09473 19.791C3.69804 20.226 3.15899 20.483 2.58984 20.5117C2.02064 20.5404 1.46054 20.3388 1.02637 19.9463C0.646121 19.6025 0.388046 19.1346 0.291992 18.6191L0.260742 18.3955L0.25 18.1582V2.5957C0.25 2.28616 0.308792 1.97976 0.421875 1.69434C0.534949 1.40903 0.700373 1.1499 0.908203 0.932617C1.11598 0.7155 1.36191 0.543656 1.63184 0.426758C1.83437 0.339049 2.04769 0.283116 2.26465 0.260742L2.48242 0.25ZM10.6455 0.439453C14.8132 0.0464864 18.0777 0.720107 20.2988 2.36914C22.5268 4.02341 23.75 6.69278 23.75 10.3828C23.75 14.0496 22.5414 16.743 20.3271 18.4619C18.1041 20.1876 14.8255 20.9636 10.625 20.6992C10.0609 20.6637 9.52873 20.4045 9.1377 19.9707C8.74639 19.5366 8.52598 18.9609 8.52539 18.3604V2.78613C8.52519 2.19857 8.7355 1.63381 9.11133 1.20215C9.48693 0.770774 10.0012 0.503178 10.5518 0.449219L10.6455 0.439453ZM12.9912 16.0557L13.251 16.0459L13.4346 16.0381V16.0391L13.4404 16.0381C15.4117 15.9205 16.8559 15.4475 17.8193 14.5518C18.7881 13.651 19.2293 12.3623 19.2793 10.709V10.7051L19.2842 10.3867V10.3828C19.2842 8.64828 18.8893 7.30818 17.9326 6.39648C16.9802 5.48882 15.5194 5.05241 13.5 5.00684H13.498L13.2451 5.00391L12.9912 5V16.0557Z" fill="var(--fill-0, white)" stroke="var(--stroke-0, #3D2766)" stroke-width="0.5"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 28 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M24.6678 0C25.6791 0 26.4873 0.254516 27.0924 0.763547C27.6975 1.27258 28 2.04433 28 3.07882V16.7488C28 17.1921 27.9171 17.6108 27.7513 18.0049C27.5856 18.399 27.3576 18.7438 27.0675 19.0394C26.7774 19.335 26.4375 19.569 26.048 19.7414C25.6584 19.9138 25.2481 20 24.8171 20H3.13321C2.70219 20 2.29603 19.9179 1.91474 19.7537C1.53345 19.5895 1.20189 19.3719 0.920071 19.101C0.638247 18.83 0.414446 18.514 0.248668 18.1527C0.0828893 17.7915 0 17.4056 0 16.9951V3.02956C0 2.14286 0.273535 1.41626 0.820604 0.849754C1.36767 0.283251 2.13854 0 3.13321 0H24.6678ZM6.98757 4.55665C6.67259 4.55665 6.37419 4.61412 6.09236 4.72906C5.81054 4.84401 5.56187 5.00411 5.34636 5.20936C5.13085 5.41461 4.96092 5.66092 4.83659 5.94828C4.71226 6.23563 4.65009 6.54351 4.65009 6.87192C4.65009 7.20033 4.71226 7.50411 4.83659 7.78325C4.96092 8.0624 5.13085 8.3087 5.34636 8.52217C5.56187 8.73563 5.81054 8.90394 6.09236 9.02709C6.37419 9.15025 6.67259 9.21182 6.98757 9.21182C7.3357 9.21182 7.65482 9.15025 7.94494 9.02709C8.23505 8.90394 8.48372 8.73563 8.69094 8.52217C8.89816 8.3087 9.06394 8.0624 9.18828 7.78325C9.31261 7.50411 9.37478 7.20033 9.37478 6.87192C9.37478 6.19869 9.15098 5.6445 8.70337 5.20936C8.25577 4.77422 7.68384 4.55665 6.98757 4.55665ZM10.8917 13.0788C10.8917 12.7668 10.8295 12.4672 10.7052 12.1798C10.5808 11.8924 10.415 11.6461 10.2078 11.4409C10.0006 11.2356 9.75192 11.0714 9.46181 10.9483C9.1717 10.8251 8.86915 10.7635 8.55417 10.7635H5.44583C4.79929 10.7635 4.25222 10.9893 3.80462 11.4409C3.35702 11.8924 3.13321 12.4384 3.13321 13.0788V13.1773V15.3941H10.8917V13.1773V13.0788ZM22.4298 15.5172C22.7614 15.5172 23.0059 15.4351 23.1634 15.2709C23.3209 15.1067 23.3996 14.9097 23.3996 14.6798C23.3996 14.4499 23.3085 14.2488 23.1261 14.0764C22.9438 13.9039 22.6868 13.8177 22.3552 13.8177H14.9449C14.6134 13.8177 14.3647 13.9039 14.1989 14.0764C14.0332 14.2488 13.9503 14.4499 13.9503 14.6798C13.9503 14.9097 14.0332 15.1067 14.1989 15.2709C14.3647 15.4351 14.6051 15.5172 14.9201 15.5172H22.4298ZM22.4547 12.3399C22.7863 12.3399 23.0266 12.2578 23.1758 12.0936C23.325 11.9294 23.3996 11.7323 23.3996 11.5025C23.3996 11.2562 23.3292 11.0509 23.1883 10.8867C23.0474 10.7225 22.8111 10.6404 22.4796 10.6404H14.8703C14.5388 10.6404 14.2984 10.7225 14.1492 10.8867C14 11.0509 13.9254 11.2562 13.9254 11.5025C13.9254 11.7323 13.9959 11.9294 14.1368 12.0936C14.2777 12.2578 14.5139 12.3399 14.8455 12.3399H22.4547ZM22.4796 9.21182C22.7282 9.21182 22.9438 9.12972 23.1261 8.96552C23.3085 8.80131 23.3996 8.60427 23.3996 8.37438C23.3996 8.1445 23.3085 7.95977 23.1261 7.8202C22.9438 7.68062 22.7282 7.61084 22.4796 7.61084H17.4316C17.1829 7.61084 16.9716 7.68062 16.7975 7.8202C16.6234 7.95977 16.5364 8.1445 16.5364 8.37438C16.5364 8.60427 16.6234 8.80131 16.7975 8.96552C16.9716 9.12972 17.1829 9.21182 17.4316 9.21182H22.4796Z" fill="var(--fill-0, white)"/>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M6.75417 3.89333C7.09232 3.89333 7.41713 3.96 7.72859 4.09333C8.04004 4.22667 8.30701 4.40444 8.52948 4.62667C8.75195 4.84889 8.92992 5.11111 9.0634 5.41333C9.19688 5.71555 9.26363 6.03556 9.26363 6.37333C9.26363 7.06667 9.01891 7.65333 8.52948 8.13333C8.04004 8.61333 7.44828 8.85333 6.75417 8.85333C6.41602 8.85333 6.09566 8.79111 5.7931 8.66667C5.49054 8.54222 5.22803 8.36444 5.00556 8.13333C4.78309 7.90222 4.60512 7.64 4.47164 7.34667C4.33815 7.05333 4.27141 6.72889 4.27141 6.37333C4.27141 6.03556 4.33815 5.71555 4.47164 5.41333C4.60512 5.11111 4.78309 4.84889 5.00556 4.62667C5.22803 4.40444 5.49054 4.22667 5.7931 4.09333C6.09566 3.96 6.41602 3.89333 6.75417 3.89333ZM21.4905 0C22.3982 0 23.0434 0.253333 23.426 0.76C23.8087 1.26667 24 1.92889 24 2.74667V21.8933C24 22.1422 23.9422 22.3956 23.8265 22.6533C23.7108 22.9111 23.5506 23.1378 23.3459 23.3333C23.1413 23.5289 22.9055 23.6889 22.6385 23.8133C22.3715 23.9378 22.0779 24 21.7575 24H2.08231C1.53059 24 1.04561 23.7778 0.627364 23.3333C0.209121 22.8889 0 22.3556 0 21.7333V2.21333C0 1.57333 0.177976 1.04444 0.533927 0.626667C0.889878 0.208889 1.36151 0 1.94883 0H21.4905ZM21.5973 3.12C21.5973 2.92444 21.5217 2.75111 21.3704 2.6C21.2191 2.44889 21.0367 2.37333 20.8231 2.37333H3.15017C2.9366 2.37333 2.75862 2.44889 2.61624 2.6C2.47386 2.75111 2.40267 2.92444 2.40267 3.12V3.14667V12.6933C2.58065 12.9067 2.81646 13.1511 3.11012 13.4267C3.40378 13.7022 3.75083 13.96 4.15128 14.2C4.55172 14.44 5.00556 14.6444 5.51279 14.8133C6.02002 14.9822 6.58509 15.0667 7.20801 15.0667C8.16908 15.0667 9.01446 14.9111 9.74416 14.6C10.4739 14.2889 11.1635 13.9067 11.8131 13.4533C12.4627 13 13.099 12.5022 13.7219 11.96C14.3448 11.4178 15.0256 10.9111 15.7642 10.44C16.5028 9.96889 17.3437 9.56889 18.287 9.24C19.2303 8.91111 20.3337 8.72 21.5973 8.66667V3.12Z" fill="var(--fill-0, white)"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

3
vip/assets/icon-room.png Normal file
View File

@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 27.6922 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Union" d="M23.7363 13.0576V22C23.7363 23 22.7477 23.9998 21.7588 24H5.93357C4.94458 23.9998 3.95603 22.9999 3.95603 22V13.0576L13.8457 4.36035L23.7363 13.0576ZM12.8574 14C11.765 14 10.879 14.8956 10.8789 16V21H16.8135V16C16.8134 14.8956 15.9273 14 14.8349 14H12.8574ZM13.8457 0C14.3595 0 14.8736 0.179713 15.2793 0.537109L18.791 3.62793V2C18.791 1.44728 19.2336 1 19.7803 1H20.7695C21.3161 1.00011 21.7588 1.44735 21.7588 2V6.23828L27.332 11.1436C27.6604 11.4307 27.7776 11.8965 27.6279 12.3115L27.5615 12.46C27.3826 12.7899 27.0418 13 26.664 13H25.1787L13.8457 3.03516L2.51365 13H1.0283C0.596574 13 0.213206 12.7256 0.0644332 12.3115C-0.0852492 11.8965 0.0310485 11.4306 0.359355 11.1436L12.4131 0.537109C12.8186 0.179942 13.3321 8.0822e-05 13.8457 0Z" fill="var(--fill-0, white)"/>
</svg>

After

Width:  |  Height:  |  Size: 976 B

Some files were not shown because too many files have changed in this diff Show More