allen-env-switch

Switch Web Environment

  1. // ==UserScript==
  2. // @name allen-env-switch
  3. // @namespace allen/allen-env-switch
  4. // @version 0.0.6
  5. // @author yulei@addcn.com
  6. // @description Switch Web Environment
  7. // @license MIT
  8. // @include *
  9. // @require https://cdn.jsdelivr.net/npm/vue@3.5.3/dist/vue.global.prod.js
  10. // @grant GM_addStyle
  11. // @grant GM_getValue
  12. // @grant GM_log
  13. // @grant GM_registerMenuCommand
  14. // @grant GM_setValue
  15. // @grant unsafeWindow
  16. // ==/UserScript==
  17.  
  18. (r=>{if(typeof GM_addStyle=="function"){GM_addStyle(r);return}const n=document.createElement("style");n.textContent=r,document.head.append(n)})(" dialog::backdrop{background:#0009}.hue[data-v-0b9826d7]{background:linear-gradient(45deg,#5fddcc,#ff004d);animation:hueRotate-0b9826d7 2s infinite alternate}@keyframes hueRotate-0b9826d7{0%{filter:hue-rotate(0deg)}to{filter:hue-rotate(360deg)}}*,:before,:after{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / .5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }::backdrop{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / .5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.left-0{left:0}.right-30px{right:30px}.top-0{top:0}.top-18px{top:18px}.z-9999{z-index:9999}.grid{display:grid}.mb-2{margin-bottom:.5rem}.mb-6{margin-bottom:1.5rem}.mt-20px{margin-top:20px}.block{display:block}.h-60px{height:60px}.h-80\\%{height:80%}.h2{height:.5rem}.w-80\\%{width:80%}.w-full{width:100%}.inline-flex{display:inline-flex}.cursor-pointer{cursor:pointer}.place-items-center{place-items:center}.items-center{align-items:center}.border{border-width:1px}.border-b-2px{border-bottom-width:2px}.border-gray-300{--un-border-opacity:1;border-color:rgb(209 213 219 / var(--un-border-opacity))}.dark .dark\\:border-gray-600{--un-border-opacity:1;border-color:rgb(75 85 99 / var(--un-border-opacity))}.dark .dark\\:focus\\:border-blue-500:focus{--un-border-opacity:1;border-color:rgb(59 130 246 / var(--un-border-opacity))}.focus\\:border-blue-500:focus{--un-border-opacity:1;border-color:rgb(59 130 246 / var(--un-border-opacity))}.b-b-\\#eee{--un-border-opacity:1;--un-border-bottom-opacity:var(--un-border-opacity);border-bottom-color:rgb(238 238 238 / var(--un-border-bottom-opacity))}.rounded-10px{border-radius:10px}.rounded-lg{border-radius:.5rem}.border-none{border-style:none}.b-b-solid{border-bottom-style:solid}.bg-\\#fff{--un-bg-opacity:1;background-color:rgb(255 255 255 / var(--un-bg-opacity))}.bg-blue-700{--un-bg-opacity:1;background-color:rgb(29 78 216 / var(--un-bg-opacity))}.bg-gray-50{--un-bg-opacity:1;background-color:rgb(249 250 251 / var(--un-bg-opacity))}.dark .dark\\:bg-gray-700{--un-bg-opacity:1;background-color:rgb(55 65 81 / var(--un-bg-opacity))}.hover\\:bg-blue-800:hover{--un-bg-opacity:1;background-color:rgb(30 64 175 / var(--un-bg-opacity))}.p-2\\.5{padding:.625rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-2\\.5{padding-top:.625rem;padding-bottom:.625rem}.pb-10px{padding-bottom:10px}.text-center{text-align:center}.text-16px{font-size:16px}.text-22px{font-size:22px}.dark .dark\\:text-white,.text-\\#fff,.text-white{--un-text-opacity:1;color:rgb(255 255 255 / var(--un-text-opacity))}.text-gray-900{--un-text-opacity:1;color:rgb(17 24 39 / var(--un-text-opacity))}.color-\\#333{--un-text-opacity:1;color:rgb(51 51 51 / var(--un-text-opacity))}.font-medium{font-weight:500}.leading-24px{line-height:24px}.not-italic{font-style:normal}.outline-none{outline:2px solid transparent;outline-offset:2px}.focus\\:ring-4:focus{--un-ring-width:4px;--un-ring-offset-shadow:var(--un-ring-inset) 0 0 0 var(--un-ring-offset-width) var(--un-ring-offset-color);--un-ring-shadow:var(--un-ring-inset) 0 0 0 calc(var(--un-ring-width) + var(--un-ring-offset-width)) var(--un-ring-color);box-shadow:var(--un-ring-offset-shadow),var(--un-ring-shadow),var(--un-shadow)}.dark .dark\\:focus\\:ring-blue-500:focus{--un-ring-opacity:1;--un-ring-color:rgb(59 130 246 / var(--un-ring-opacity)) }.dark .dark\\:focus\\:ring-blue-900:focus{--un-ring-opacity:1;--un-ring-color:rgb(30 58 138 / var(--un-ring-opacity)) }.focus\\:ring-blue-200:focus{--un-ring-opacity:1;--un-ring-color:rgb(191 219 254 / var(--un-ring-opacity)) }.focus\\:ring-blue-500:focus{--un-ring-opacity:1;--un-ring-color:rgb(59 130 246 / var(--un-ring-opacity)) }.filter{filter:var(--un-blur) var(--un-brightness) var(--un-contrast) var(--un-drop-shadow) var(--un-grayscale) var(--un-hue-rotate) var(--un-invert) var(--un-saturate) var(--un-sepia)}.dark .dark\\:placeholder-gray-400::placeholder{--un-placeholder-opacity:1;color:rgb(156 163 175 / var(--un-placeholder-opacity))}@media (min-width: 768px){.md\\:h-45px{height:45px}.md\\:text-22px{font-size:22px}.md\\:leading-45px{line-height:45px}} ");
  19.  
  20. (function (vue) {
  21. 'use strict';
  22.  
  23. var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
  24. var _GM_log = /* @__PURE__ */ (() => typeof GM_log != "undefined" ? GM_log : void 0)();
  25. var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
  26. var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
  27. var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
  28. const _hoisted_1$1 = { class: "mb-6 mt-20px" };
  29. const _sfc_main$2 = /* @__PURE__ */ vue.defineComponent({
  30. __name: "Settings",
  31. emits: ["close"],
  32. setup(__props, { emit: __emit }) {
  33. const emits = __emit;
  34. const domain = vue.ref(_GM_getValue("domain", ""));
  35. const configs = vue.ref(_GM_getValue("configs", ""));
  36. const dialog = vue.ref(null);
  37. async function save() {
  38. await _GM_setValue("domain", domain.value);
  39. await _GM_setValue("configs", configs.value);
  40. _unsafeWindow.alert("Saved!");
  41. close();
  42. }
  43. vue.onMounted(() => {
  44. var _a;
  45. const clientWidth = document.documentElement.clientWidth;
  46. if (clientWidth < 640) {
  47. _unsafeWindow.alert("Please use a larger screen to view the settings.");
  48. emits("close");
  49. } else {
  50. (_a = dialog.value) == null ? void 0 : _a.showModal();
  51. }
  52. });
  53. vue.onUnmounted(() => {
  54. var _a;
  55. (_a = dialog.value) == null ? void 0 : _a.close();
  56. });
  57. function close() {
  58. var _a;
  59. (_a = dialog.value) == null ? void 0 : _a.close();
  60. emits("close");
  61. }
  62. return (_ctx, _cache) => {
  63. return vue.openBlock(), vue.createElementBlock("dialog", {
  64. ref_key: "dialog",
  65. ref: dialog,
  66. class: "bg-#fff w-80% h-80% border-none outline-none rounded-10px relative"
  67. }, [
  68. _cache[4] || (_cache[4] = vue.createElementVNode("h2", { class: "border-b-2px b-b-#eee b-b-solid pb-10px" }, " Switch Settings ", -1)),
  69. vue.createElementVNode("i", {
  70. class: "absolute right-30px top-18px cursor-pointer text-22px color-#333 not-italic",
  71. title: "关闭",
  72. onClick: close
  73. }, "ⓧ"),
  74. vue.createElementVNode("div", null, [
  75. vue.createElementVNode("div", _hoisted_1$1, [
  76. _cache[2] || (_cache[2] = vue.createElementVNode("label", {
  77. for: "domain",
  78. class: "block mb-2 font-medium text-gray-900 dark:text-white text-16px"
  79. }, "domian", -1)),
  80. vue.withDirectives(vue.createElementVNode("input", {
  81. id: "domain",
  82. "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => domain.value = $event),
  83. type: "input",
  84. class: "bg-gray-50 border border-gray-300 text-gray-900 text-16px rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500",
  85. placeholder: ".google.com",
  86. required: ""
  87. }, null, 512), [
  88. [vue.vModelText, domain.value]
  89. ])
  90. ]),
  91. _cache[3] || (_cache[3] = vue.createElementVNode("label", {
  92. for: "configs",
  93. class: "block mb-2 text-16px font-medium text-gray-900 dark:text-white"
  94. }, "Configs", -1)),
  95. vue.withDirectives(vue.createElementVNode("textarea", {
  96. id: "configs",
  97. "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => configs.value = $event),
  98. rows: "14",
  99. class: "block p-2.5 w-full text-16px text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500",
  100. placeholder: "Write your configs here..."
  101. }, null, 512), [
  102. [vue.vModelText, configs.value]
  103. ]),
  104. vue.createElementVNode("button", {
  105. type: "button",
  106. class: "inline-flex items-center px-5 py-2.5 text-16px font-medium text-center text-white bg-blue-700 rounded-lg focus:ring-4 focus:ring-blue-200 dark:focus:ring-blue-900 hover:bg-blue-800 mt-20px cursor-pointer",
  107. onClick: save
  108. }, " Save ")
  109. ])
  110. ], 512);
  111. };
  112. }
  113. });
  114. const _hoisted_1 = {
  115. key: 0,
  116. class: "grid place-items-center w-full text-center fixed top-0 left-0 z-9999 text-16px h-60px leading-24px text-#fff md:h-45px md:leading-45px md:text-22px hue"
  117. };
  118. const _sfc_main$1 = /* @__PURE__ */ vue.defineComponent({
  119. __name: "Home",
  120. setup(__props) {
  121. const gm_domain = _GM_getValue("domain", "");
  122. const gm_configs = _GM_getValue("configs", "");
  123. if (!gm_configs) {
  124. _GM_log("Please set the configuration first");
  125. }
  126. const domain = vue.ref(gm_domain);
  127. const configs = vue.ref(gm_configs ? JSON.parse(gm_configs) : []);
  128. const url = vue.ref("");
  129. const _window = _unsafeWindow;
  130. function shortcut(code = "Digit1", callback) {
  131. document.addEventListener("keydown", (event) => {
  132. if (event.code === code && event.altKey) {
  133. event.preventDefault();
  134. callback();
  135. }
  136. });
  137. }
  138. shortcut("Digit1", () => {
  139. handle("dev");
  140. });
  141. shortcut("Digit2", () => {
  142. handle("debug");
  143. });
  144. shortcut("Digit3", () => {
  145. handle("online");
  146. });
  147. const envMap = {
  148. dev: ".dev",
  149. debug: ".debug",
  150. online: ""
  151. };
  152. function handle(action) {
  153. const hostname = _window.location.hostname;
  154. const pathname = _window.location.pathname;
  155. const search = _window.location.search;
  156. const hosts = configs.value.filter((item2) => hostname.includes(item2.subdomain));
  157. const item = hosts.find((item2) => item2.action === action);
  158. const _protocol = (item == null ? void 0 : item.protocol) ? item == null ? void 0 : item.protocol : "https:";
  159. const _port = (item == null ? void 0 : item.port) ? `:${item.port}` : "";
  160. const _prefix = (item == null ? void 0 : item.prefix) ? item.prefix : "";
  161. if (item) {
  162. url.value = `${_protocol}//${_prefix}${item.subdomain}${item.env}${domain.value}${_port}${pathname}${search}`;
  163. } else if (hostname.includes(domain.value)) {
  164. const _env = envMap[action];
  165. const _subdomain = hostname.split(".")[0];
  166. url.value = `https://${_subdomain}${_env}${domain.value}${pathname}${search}`;
  167. }
  168. if (url.value) {
  169. if (url.value === _window.location.href) {
  170. _GM_log("The current environment is the same as the target environment");
  171. url.value = "";
  172. return;
  173. }
  174. _window.location.href = url.value;
  175. } else {
  176. _GM_log("No configuration found");
  177. }
  178. }
  179. const visible = vue.ref(false);
  180. _GM_registerMenuCommand("Settings", () => {
  181. visible.value = true;
  182. });
  183. return (_ctx, _cache) => {
  184. return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
  185. url.value ? (vue.openBlock(), vue.createElementBlock("section", _hoisted_1, [
  186. vue.createElementVNode("div", null, "Switch: " + vue.toDisplayString(url.value), 1)
  187. ])) : vue.createCommentVNode("", true),
  188. visible.value ? (vue.openBlock(), vue.createBlock(_sfc_main$2, {
  189. key: 1,
  190. onClose: _cache[0] || (_cache[0] = ($event) => visible.value = false)
  191. })) : vue.createCommentVNode("", true)
  192. ], 64);
  193. };
  194. }
  195. });
  196. const _export_sfc = (sfc, props) => {
  197. const target = sfc.__vccOpts || sfc;
  198. for (const [key, val] of props) {
  199. target[key] = val;
  200. }
  201. return target;
  202. };
  203. const Home = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-0b9826d7"]]);
  204. const _sfc_main = /* @__PURE__ */ vue.defineComponent({
  205. __name: "App",
  206. setup(__props) {
  207. return (_ctx, _cache) => {
  208. return vue.openBlock(), vue.createBlock(Home);
  209. };
  210. }
  211. });
  212. vue.createApp(_sfc_main).mount(
  213. (() => {
  214. const app = document.createElement("div");
  215. document.body.append(app);
  216. return app;
  217. })()
  218. );
  219.  
  220. })(Vue);