mirror of
				https://github.com/smartfrigde/armcord.git
				synced 2024-08-14 23:56:58 +00:00 
			
		
		
		
	formatting
a.k.a. "Install Prettier"
This commit is contained in:
		
							parent
							
								
									18bebfb421
								
							
						
					
					
						commit
						87920505db
					
				
					 32 changed files with 1382 additions and 1341 deletions
				
			
		
							
								
								
									
										1
									
								
								.husky/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.husky/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| _ | ||||
							
								
								
									
										5
									
								
								.husky/pre-commit
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										5
									
								
								.husky/pre-commit
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| #!/bin/sh | ||||
| . "$(dirname $0)/_/husky.sh" | ||||
| 
 | ||||
| npm run format | ||||
| git add -A | ||||
							
								
								
									
										11
									
								
								.prettierignore
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								.prettierignore
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| # Some prettier-specific files so it doesn't die. | ||||
| **/*.png | ||||
| **/*.ico | ||||
| LICENSE | ||||
| .gitignore | ||||
| 
 | ||||
| node_modules | ||||
| out/ | ||||
| dist | ||||
| ts-out/ | ||||
| ts-out | ||||
							
								
								
									
										46
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										46
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							|  | @ -1,12 +1,13 @@ | |||
| { | ||||
|   "name": "ArmCord", | ||||
|   "version": "3.0.4", | ||||
|   "version": "3.1.0", | ||||
|   "lockfileVersion": 2, | ||||
|   "requires": true, | ||||
|   "packages": { | ||||
|     "": { | ||||
|       "name": "ArmCord", | ||||
|       "version": "3.0.4", | ||||
|       "version": "3.1.0", | ||||
|       "hasInstallScript": true, | ||||
|       "license": "OSL-3.0", | ||||
|       "dependencies": { | ||||
|         "electron-context-menu": "^3.1.2", | ||||
|  | @ -21,6 +22,8 @@ | |||
|         "copyfiles": "^2.4.1", | ||||
|         "electron": "^17.1.0", | ||||
|         "electron-builder": "^22.14.13", | ||||
|         "husky": "^7.0.4", | ||||
|         "prettier": "^2.5.1", | ||||
|         "typescript": "^4.5.4" | ||||
|       } | ||||
|     }, | ||||
|  | @ -2020,6 +2023,21 @@ | |||
|         "node": ">= 6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/husky": { | ||||
|       "version": "7.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", | ||||
|       "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", | ||||
|       "dev": true, | ||||
|       "bin": { | ||||
|         "husky": "lib/bin.js" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=12" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/sponsors/typicode" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/iconv-corefoundation": { | ||||
|       "version": "1.1.7", | ||||
|       "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", | ||||
|  | @ -2724,6 +2742,18 @@ | |||
|         "node": ">=4" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/prettier": { | ||||
|       "version": "2.5.1", | ||||
|       "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", | ||||
|       "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", | ||||
|       "dev": true, | ||||
|       "bin": { | ||||
|         "prettier": "bin-prettier.js" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=10.13.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/process-nextick-args": { | ||||
|       "version": "2.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", | ||||
|  | @ -5191,6 +5221,12 @@ | |||
|         "debug": "4" | ||||
|       } | ||||
|     }, | ||||
|     "husky": { | ||||
|       "version": "7.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", | ||||
|       "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "iconv-corefoundation": { | ||||
|       "version": "1.1.7", | ||||
|       "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", | ||||
|  | @ -5728,6 +5764,12 @@ | |||
|       "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "prettier": { | ||||
|       "version": "2.5.1", | ||||
|       "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", | ||||
|       "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "process-nextick-args": { | ||||
|       "version": "2.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", | ||||
|  |  | |||
|  | @ -7,7 +7,9 @@ | |||
|     "build": "tsc && copyfiles -u 1 src/**/*.html src/**/**/*.css ts-out/ && copyfiles package.json ts-out/ && copyfiles assets/** ts-out/", | ||||
|     "watch": "tsc -w", | ||||
|     "start": "npm run build && electron ./ts-out/main.js", | ||||
|     "package": "npm run build && electron-builder" | ||||
|     "package": "npm run build && electron-builder", | ||||
|     "format": "prettier --write **/*", | ||||
|     "postinstall": "husky install" | ||||
|   }, | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
|  | @ -25,6 +27,8 @@ | |||
|     "copyfiles": "^2.4.1", | ||||
|     "electron": "^17.1.0", | ||||
|     "electron-builder": "^22.14.13", | ||||
|     "husky": "^7.0.4", | ||||
|     "prettier": "^2.5.1", | ||||
|     "typescript": "^4.5.4" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|  |  | |||
							
								
								
									
										14
									
								
								prettier.config.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								prettier.config.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| module.exports = { | ||||
|     printWidth: 120, | ||||
|     tabWidth: 4, | ||||
|     useTabs: false, | ||||
|     semi: true, | ||||
|     singleQuote: false, | ||||
|     quoteProps: "as-needed", | ||||
|     jsxSingleQuote: false, | ||||
|     trailingComma: "none", | ||||
|     bracketSpacing: false, | ||||
|     jsxBracketSameLine: false, | ||||
|     arrowParens: "always", | ||||
|     endOfLine: "auto" | ||||
| }; | ||||
|  | @ -1,12 +1,12 @@ | |||
| .info-3pQQBb:last-child:before { | ||||
|   content: "ArmCord Version: 3.1.0"!important; | ||||
|   height: auto; | ||||
|   line-height: 16px; | ||||
|   text-align: center; | ||||
|   color: var(--text-muted); | ||||
|   font-size: 12px; | ||||
|   text-transform: none; | ||||
|     content: "ArmCord Version: 3.1.0" !important; | ||||
|     height: auto; | ||||
|     line-height: 16px; | ||||
|     text-align: center; | ||||
|     color: var(--text-muted); | ||||
|     font-size: 12px; | ||||
|     text-transform: none; | ||||
| } | ||||
| .notice-2HEN-u { | ||||
|     display: none; | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -2,68 +2,68 @@ | |||
| @import url("https://kckarnige.github.io/femboi_owo/discord-font.css"); | ||||
| 
 | ||||
| :root { | ||||
|   background-color: #2c2f33 !important; | ||||
|   --header-secondary: #b9bbbe !important; | ||||
|   --header-primary: #fff !important; | ||||
|   --background-tertiary: #202225 !important; | ||||
|     background-color: #2c2f33 !important; | ||||
|     --header-secondary: #b9bbbe !important; | ||||
|     --header-primary: #fff !important; | ||||
|     --background-tertiary: #202225 !important; | ||||
| } | ||||
| body { | ||||
|   background-color: #2c2f33; | ||||
|   color: white; | ||||
|     background-color: #2c2f33; | ||||
|     color: white; | ||||
| } | ||||
| 
 | ||||
| p { | ||||
|   color: white; | ||||
|   text-align: center; | ||||
|   font-weight: 100; | ||||
|   font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif; | ||||
|   text-rendering: optimizeLegibility; | ||||
|     color: white; | ||||
|     text-align: center; | ||||
|     font-weight: 100; | ||||
|     font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif; | ||||
|     text-rendering: optimizeLegibility; | ||||
| } | ||||
| 
 | ||||
| .logo { | ||||
|   font-size: 0px; | ||||
|   text-align: center; | ||||
|   transform: translateY(-105%); | ||||
|     font-size: 0px; | ||||
|     text-align: center; | ||||
|     transform: translateY(-105%); | ||||
| } | ||||
| 
 | ||||
| .logo:before { | ||||
|   content: "ARM"; | ||||
|   color: #7289da; | ||||
|   font-weight: normal; | ||||
|   font-family: Helvetica, sans-serif; | ||||
|   font-size: 32px; | ||||
|     content: "ARM"; | ||||
|     color: #7289da; | ||||
|     font-weight: normal; | ||||
|     font-family: Helvetica, sans-serif; | ||||
|     font-size: 32px; | ||||
| } | ||||
| 
 | ||||
| .logo:after { | ||||
|   content: "Cord"; | ||||
|   color: #ffffff; | ||||
|   font-weight: normal; | ||||
|   font-family: Discordinated; | ||||
|   font-size: 32px; | ||||
|     content: "Cord"; | ||||
|     color: #ffffff; | ||||
|     font-weight: normal; | ||||
|     font-family: Discordinated; | ||||
|     font-size: 32px; | ||||
| } | ||||
| 
 | ||||
| span { | ||||
|   text-align: center; | ||||
|     text-align: center; | ||||
| } | ||||
| 
 | ||||
| .logo { | ||||
|   display: block; | ||||
|   margin-left: auto; | ||||
|   margin-right: auto; | ||||
|   max-height: 204px; | ||||
|   max-width: 204px; | ||||
|   transform: translateY(5%); | ||||
|     display: block; | ||||
|     margin-left: auto; | ||||
|     margin-right: auto; | ||||
|     max-height: 204px; | ||||
|     max-width: 204px; | ||||
|     transform: translateY(5%); | ||||
| } | ||||
| 
 | ||||
| .container { | ||||
|   position: fixed; | ||||
|   top: 50%; | ||||
|   left: 50%; | ||||
|   color: #fff; | ||||
|   transform: translate(-50%, -50%); | ||||
|     position: fixed; | ||||
|     top: 50%; | ||||
|     left: 50%; | ||||
|     color: #fff; | ||||
|     transform: translate(-50%, -50%); | ||||
| } | ||||
| button#express { | ||||
|   margin-right: 84px; | ||||
|     margin-right: 84px; | ||||
| } | ||||
| button { | ||||
|     background-color: #7289da; | ||||
|  | @ -72,13 +72,13 @@ button { | |||
|     padding: 4px; | ||||
|     border-radius: 5px; | ||||
|     margin-top: 5px; | ||||
|      | ||||
| 
 | ||||
|     text-align: center; | ||||
|     border-style: none; | ||||
|     outline: none; | ||||
| } | ||||
| .setup-ask { | ||||
|   font-size: 20px; | ||||
|     font-size: 20px; | ||||
| } | ||||
| button:hover { | ||||
|     background-color: #687dc6; | ||||
|  | @ -87,25 +87,25 @@ button:hover { | |||
|     cursor: pointer; | ||||
| } | ||||
| select { | ||||
|   -webkit-appearance: button; | ||||
|   -moz-appearance: button; | ||||
|   -webkit-padding-end: 20px; | ||||
|   -moz-padding-end: 20px; | ||||
|   -webkit-padding-start: 2px; | ||||
|   -moz-padding-start: 2px; | ||||
|   background-color: #2c2f33; | ||||
|   background-position: center right; | ||||
|   background-repeat: no-repeat; | ||||
|   border: 1px solid #aaa; | ||||
|   border-radius: 2px; | ||||
|   box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1); | ||||
|   color: #fff; | ||||
|   font-size: inherit; | ||||
|   margin: 0; | ||||
|   overflow: hidden; | ||||
|   text-overflow: ellipsis; | ||||
|   white-space: nowrap; | ||||
|     -webkit-appearance: button; | ||||
|     -moz-appearance: button; | ||||
|     -webkit-padding-end: 20px; | ||||
|     -moz-padding-end: 20px; | ||||
|     -webkit-padding-start: 2px; | ||||
|     -moz-padding-start: 2px; | ||||
|     background-color: #2c2f33; | ||||
|     background-position: center right; | ||||
|     background-repeat: no-repeat; | ||||
|     border: 1px solid #aaa; | ||||
|     border-radius: 2px; | ||||
|     box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1); | ||||
|     color: #fff; | ||||
|     font-size: inherit; | ||||
|     margin: 0; | ||||
|     overflow: hidden; | ||||
|     text-overflow: ellipsis; | ||||
|     white-space: nowrap; | ||||
| } | ||||
| .center { | ||||
|   text-align: center; | ||||
| } | ||||
|     text-align: center; | ||||
| } | ||||
|  |  | |||
|  | @ -20,95 +20,95 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE.*/ | ||||
| :root { | ||||
|   --background-primary: #282b30; | ||||
|   --background-secondary: rgba(255, 255, 255, 0.1); | ||||
|   --brand-experiment: #5865f2; | ||||
|   --header-primary: #fff; | ||||
|   --text-muted: #72767d; | ||||
|     --background-primary: #282b30; | ||||
|     --background-secondary: rgba(255, 255, 255, 0.1); | ||||
|     --brand-experiment: #5865f2; | ||||
|     --header-primary: #fff; | ||||
|     --text-muted: #72767d; | ||||
| } | ||||
| 
 | ||||
| @font-face { | ||||
|   font-family: Whitney; | ||||
|   font-weight: 400; | ||||
|   font-style: normal; | ||||
|   src: url(https://armcord.smartfridge.space/whitney_400.woff) format("woff"); | ||||
|     font-family: Whitney; | ||||
|     font-weight: 400; | ||||
|     font-style: normal; | ||||
|     src: url(https://armcord.smartfridge.space/whitney_400.woff) format("woff"); | ||||
| } | ||||
| 
 | ||||
| html, | ||||
| body { | ||||
|   -webkit-app-region: drag; | ||||
|   overflow: hidden; | ||||
|     -webkit-app-region: drag; | ||||
|     overflow: hidden; | ||||
| 
 | ||||
|   margin: 0; | ||||
|   padding: 0; | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|     margin: 0; | ||||
|     padding: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
| 
 | ||||
|   background: var(--background-primary); | ||||
|     background: var(--background-primary); | ||||
| 
 | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
| } | ||||
| 
 | ||||
| * { | ||||
|   font-family: "Whitney", sans-serif; | ||||
|     font-family: "Whitney", sans-serif; | ||||
| 
 | ||||
|   box-sizing: border-box; | ||||
|   -webkit-user-select: none; | ||||
|   cursor: default; | ||||
|     box-sizing: border-box; | ||||
|     -webkit-user-select: none; | ||||
|     cursor: default; | ||||
| } | ||||
| 
 | ||||
| video { | ||||
|   width: 200px; | ||||
|   height: 150px; | ||||
|   object-fit: cover; | ||||
|     width: 200px; | ||||
|     height: 150px; | ||||
|     object-fit: cover; | ||||
| } | ||||
| 
 | ||||
| #text-splashscreen { | ||||
|   font-size: 7vw; | ||||
|   text-align: center; | ||||
|     font-size: 7vw; | ||||
|     text-align: center; | ||||
| 
 | ||||
|   color: var(--header-primary); | ||||
|   font-weight: 400; | ||||
|   font-style: italic; | ||||
|   font-size: 16px; | ||||
|     color: var(--header-primary); | ||||
|     font-weight: 400; | ||||
|     font-style: italic; | ||||
|     font-size: 16px; | ||||
| 
 | ||||
|   text-transform: uppercase; | ||||
|     text-transform: uppercase; | ||||
| 
 | ||||
|   width: 100%; | ||||
|     width: 100%; | ||||
| } | ||||
| 
 | ||||
| #bar-container, | ||||
| #bar-fill { | ||||
|   width: 180px; | ||||
|   height: 8px; | ||||
|     width: 180px; | ||||
|     height: 8px; | ||||
| 
 | ||||
|   border-radius: 4px; | ||||
|     border-radius: 4px; | ||||
| 
 | ||||
|   visibility: hidden; | ||||
|     visibility: hidden; | ||||
| } | ||||
| 
 | ||||
| #bar-container { | ||||
|   background-color: var(--background-secondary); | ||||
|     background-color: var(--background-secondary); | ||||
| 
 | ||||
|   position: relative; | ||||
|   margin-top: 12px; | ||||
|     position: relative; | ||||
|     margin-top: 12px; | ||||
| } | ||||
| 
 | ||||
| #bar-fill { | ||||
|   background-color: var(--brand-experiment); | ||||
|   width: 0; | ||||
|     background-color: var(--brand-experiment); | ||||
|     width: 0; | ||||
| } | ||||
| 
 | ||||
| #debug { | ||||
|   position: absolute; | ||||
|   bottom: 6px; | ||||
|   right: 6px; | ||||
|     position: absolute; | ||||
|     bottom: 6px; | ||||
|     right: 6px; | ||||
| 
 | ||||
|   text-align: right; | ||||
|   font-size: 10px; | ||||
|   color: var(--text-muted); | ||||
|   white-space: pre; | ||||
|     text-align: right; | ||||
|     font-size: 10px; | ||||
|     color: var(--text-muted); | ||||
|     white-space: pre; | ||||
| } | ||||
|  |  | |||
|  | @ -1,53 +1,53 @@ | |||
| @import url("https://kckarnige.github.io/femboi_owo/discord-font.css"); | ||||
| :root { | ||||
|   --window-buttons: var(--header-secondary); | ||||
|   --cord-color: var(--header-primary); | ||||
|   --armcord-color: #7289da; | ||||
|   --titlebar-color: var(--background-tertiary); | ||||
|     --window-buttons: var(--header-secondary); | ||||
|     --cord-color: var(--header-primary); | ||||
|     --armcord-color: #7289da; | ||||
|     --titlebar-color: var(--background-tertiary); | ||||
| } | ||||
| .tabs { | ||||
|   display: block; | ||||
|   top: 0; | ||||
|   left: 0; | ||||
|   right: 0; | ||||
|   flex-shrink: 0; | ||||
|   overflow: hidden; | ||||
|   zoom: 1; | ||||
|   box-sizing: border-box; | ||||
|   width: 100%; | ||||
|   clear: both; | ||||
|   height: 30px; | ||||
|   line-height: 30px; | ||||
|   background-color: #202225; | ||||
|   -webkit-app-region: drag; | ||||
|   width: 100%; | ||||
|   user-select: none; | ||||
|   -webkit-user-select: none; | ||||
|   position: fixed; | ||||
|   z-index: 99999; | ||||
|     display: block; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     right: 0; | ||||
|     flex-shrink: 0; | ||||
|     overflow: hidden; | ||||
|     zoom: 1; | ||||
|     box-sizing: border-box; | ||||
|     width: 100%; | ||||
|     clear: both; | ||||
|     height: 30px; | ||||
|     line-height: 30px; | ||||
|     background-color: #202225; | ||||
|     -webkit-app-region: drag; | ||||
|     width: 100%; | ||||
|     user-select: none; | ||||
|     -webkit-user-select: none; | ||||
|     position: fixed; | ||||
|     z-index: 99999; | ||||
| } | ||||
| 
 | ||||
| .tabs #tabs-controls-container { | ||||
|   float: left; | ||||
|   width: 150px; | ||||
|   height: 100%; | ||||
|   line-height: 30px; | ||||
|   background-color: #202225; | ||||
|   -webkit-app-region: no-drag; | ||||
|     float: left; | ||||
|     width: 150px; | ||||
|     height: 100%; | ||||
|     line-height: 30px; | ||||
|     background-color: #202225; | ||||
|     -webkit-app-region: no-drag; | ||||
| } | ||||
| .tabs-buttons { | ||||
|   color: white; | ||||
|   background-color: inherit; | ||||
|   float: left; | ||||
|   border: none; | ||||
|   outline: none; | ||||
|   cursor: pointer; | ||||
|   transition: 0.3s; | ||||
|   font-size: 20px; | ||||
|     color: white; | ||||
|     background-color: inherit; | ||||
|     float: left; | ||||
|     border: none; | ||||
|     outline: none; | ||||
|     cursor: pointer; | ||||
|     transition: 0.3s; | ||||
|     font-size: 20px; | ||||
| } | ||||
| .tabs-buttons:hover { | ||||
|   background-color: #4e515a; | ||||
|     background-color: #4e515a; | ||||
| } | ||||
| .withFrame-haYltI { | ||||
|   height: 30px !important; | ||||
|     height: 30px !important; | ||||
| } | ||||
|  |  | |||
|  | @ -1,108 +1,108 @@ | |||
| @import url("https://armcord.smartfridge.space/logofont.css"); | ||||
| :root { | ||||
|   --window-buttons: var(--header-secondary); | ||||
|   --cord-color: var(--header-primary); | ||||
|   --armcord-color: #7289da; | ||||
|   --titlebar-color: var(--background-tertiary); | ||||
|     --window-buttons: var(--header-secondary); | ||||
|     --cord-color: var(--header-primary); | ||||
|     --armcord-color: #7289da; | ||||
|     --titlebar-color: var(--background-tertiary); | ||||
| } | ||||
| .titlebar { | ||||
|   display: block; | ||||
|   top: 0; | ||||
|   left: 0; | ||||
|   right: 0; | ||||
|   flex-shrink: 0; | ||||
|   overflow: hidden; | ||||
|   zoom: 1; | ||||
|   box-sizing: border-box; | ||||
|   width: 100%; | ||||
|   clear: both; | ||||
|   height: 30px; | ||||
|   line-height: 30px; | ||||
|   background-color: #202225; | ||||
|   -webkit-app-region: drag; | ||||
|   width: 100%; | ||||
|   user-select: none; | ||||
|   -webkit-user-select: none; | ||||
|   position: fixed; | ||||
|   z-index: 99999; | ||||
|     display: block; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     right: 0; | ||||
|     flex-shrink: 0; | ||||
|     overflow: hidden; | ||||
|     zoom: 1; | ||||
|     box-sizing: border-box; | ||||
|     width: 100%; | ||||
|     clear: both; | ||||
|     height: 30px; | ||||
|     line-height: 30px; | ||||
|     background-color: #202225; | ||||
|     -webkit-app-region: drag; | ||||
|     width: 100%; | ||||
|     user-select: none; | ||||
|     -webkit-user-select: none; | ||||
|     position: fixed; | ||||
|     z-index: 99999; | ||||
| } | ||||
| .titlebar #window-title { | ||||
|   width: 30%; | ||||
|   height: 100%; | ||||
|   line-height: 30px; | ||||
|   float: left; | ||||
|   padding: 0 0 0 1em; | ||||
|     width: 30%; | ||||
|     height: 100%; | ||||
|     line-height: 30px; | ||||
|     float: left; | ||||
|     padding: 0 0 0 1em; | ||||
| } | ||||
| 
 | ||||
| .titlebar #window-controls-container { | ||||
|   float: right; | ||||
|   width: 150px; | ||||
|   height: 100%; | ||||
|   line-height: 30px; | ||||
|   background-color: #202225; | ||||
|   -webkit-app-region: no-drag; | ||||
|     float: right; | ||||
|     width: 150px; | ||||
|     height: 100%; | ||||
|     line-height: 30px; | ||||
|     background-color: #202225; | ||||
|     -webkit-app-region: no-drag; | ||||
| } | ||||
| 
 | ||||
| .titlebar #window-controls-container #minimize, | ||||
| .titlebar #window-controls-container #maximize, | ||||
| .titlebar #window-controls-container #quit { | ||||
|   float: left; | ||||
|   height: 100%; | ||||
|   width: 33%; | ||||
|   text-align: center; | ||||
|   color: #f7f7f7; | ||||
|   cursor: default; | ||||
|     float: left; | ||||
|     height: 100%; | ||||
|     width: 33%; | ||||
|     text-align: center; | ||||
|     color: #f7f7f7; | ||||
|     cursor: default; | ||||
| } | ||||
| 
 | ||||
| .titlebar #window-controls-container #minimize:hover { | ||||
|   background-color: #99aab5; | ||||
|     background-color: #99aab5; | ||||
| } | ||||
| .titlebar #window-controls-container #maximize:hover { | ||||
|   background-color: #99aab5; | ||||
|     background-color: #99aab5; | ||||
| } | ||||
| .titlebar #window-controls-container #quit:hover { | ||||
|   background-color: #f04747; | ||||
|     background-color: #f04747; | ||||
| } | ||||
| .titlebar #window-controls-container #quit { | ||||
|   background-color: #f7f7f7; | ||||
|   -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.279 5.5L11 10.221l-.779.779L5.5 6.279.779 11 0 10.221 4.721 5.5 0 .779.779 0 5.5 4.721 10.221 0 11 .779 6.279 5.5z' fill='%23000'/%3E%3C/svg%3E") | ||||
|     no-repeat 50% 50%; | ||||
|   mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.279 5.5L11 10.221l-.779.779L5.5 6.279.779 11 0 10.221 4.721 5.5 0 .779.779 0 5.5 4.721 10.221 0 11 .779 6.279 5.5z' fill='%23000'/%3E%3C/svg%3E") | ||||
|     no-repeat 50% 50%; | ||||
|     background-color: #f7f7f7; | ||||
|     -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.279 5.5L11 10.221l-.779.779L5.5 6.279.779 11 0 10.221 4.721 5.5 0 .779.779 0 5.5 4.721 10.221 0 11 .779 6.279 5.5z' fill='%23000'/%3E%3C/svg%3E") | ||||
|         no-repeat 50% 50%; | ||||
|     mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.279 5.5L11 10.221l-.779.779L5.5 6.279.779 11 0 10.221 4.721 5.5 0 .779.779 0 5.5 4.721 10.221 0 11 .779 6.279 5.5z' fill='%23000'/%3E%3C/svg%3E") | ||||
|         no-repeat 50% 50%; | ||||
| } | ||||
| .titlebar #window-controls-container #minimize { | ||||
|   background-color: #f7f7f7; | ||||
|   -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 4.399V5.5H0V4.399h11z' fill='%23000'/%3E%3C/svg%3E") | ||||
|     no-repeat 50% 50%; | ||||
|   mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 4.399V5.5H0V4.399h11z' fill='%23000'/%3E%3C/svg%3E") | ||||
|     no-repeat 50% 50%; | ||||
|     background-color: #f7f7f7; | ||||
|     -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 4.399V5.5H0V4.399h11z' fill='%23000'/%3E%3C/svg%3E") | ||||
|         no-repeat 50% 50%; | ||||
|     mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 4.399V5.5H0V4.399h11z' fill='%23000'/%3E%3C/svg%3E") | ||||
|         no-repeat 50% 50%; | ||||
| } | ||||
| .titlebar #window-controls-container #maximize { | ||||
|   background-color: #f7f7f7; | ||||
|   -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 0v11H0V0h11zM9.899 1.101H1.1V9.9h8.8V1.1z' fill='%23000'/%3E%3C/svg%3E") | ||||
|     no-repeat 50% 50%; | ||||
|   mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 0v11H0V0h11zM9.899 1.101H1.1V9.9h8.8V1.1z' fill='%23000'/%3E%3C/svg%3E") | ||||
|     no-repeat 50% 50%; | ||||
|     background-color: #f7f7f7; | ||||
|     -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 0v11H0V0h11zM9.899 1.101H1.1V9.9h8.8V1.1z' fill='%23000'/%3E%3C/svg%3E") | ||||
|         no-repeat 50% 50%; | ||||
|     mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 0v11H0V0h11zM9.899 1.101H1.1V9.9h8.8V1.1z' fill='%23000'/%3E%3C/svg%3E") | ||||
|         no-repeat 50% 50%; | ||||
| } | ||||
| .window-title:after { | ||||
|   content: "Cord"; | ||||
|   color: var(--cord-color) !important; | ||||
|   font-weight: normal; | ||||
|   font-size: 14px; | ||||
|   font-family: Discordinated; | ||||
|     content: "Cord"; | ||||
|     color: var(--cord-color) !important; | ||||
|     font-weight: normal; | ||||
|     font-size: 14px; | ||||
|     font-family: Discordinated; | ||||
| } | ||||
| .window-title:before { | ||||
|   content: "ARM"; | ||||
|   color: var(--armcord-color); | ||||
|   font-weight: normal; | ||||
|   font-size: 14px; | ||||
|   font-family: Helvetica, sans-serif; | ||||
|     content: "ARM"; | ||||
|     color: var(--armcord-color); | ||||
|     font-weight: normal; | ||||
|     font-size: 14px; | ||||
|     font-family: Helvetica, sans-serif; | ||||
| } | ||||
| .window-title { | ||||
|   font-size: 0px !important; | ||||
|   margin-left: initial !important; | ||||
|   transform: translate(10px, 0px); | ||||
|     font-size: 0px !important; | ||||
|     margin-left: initial !important; | ||||
|     transform: translate(10px, 0px); | ||||
| } | ||||
| .withFrame-haYltI { | ||||
|   height: 30px !important; | ||||
|     height: 30px !important; | ||||
| } | ||||
|  |  | |||
|  | @ -1,64 +1,60 @@ | |||
| <!--- This is awful and should be replaced in later versions. Possibly based of current settings as of 3.1.0 version. If you have time please PR a better setup screen. ---> | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
|   <head> | ||||
|     <link | ||||
|       rel="stylesheet" | ||||
|       href="https://cdn.metroui.org.ua/v4/css/metro-all.min.css" | ||||
|     /> | ||||
|     <meta charset="UTF-8" /> | ||||
|     <title>ArmCord Setup</title> | ||||
|     <style> | ||||
|       @import url("css/setup.css"); | ||||
|     </style> | ||||
|   </head> | ||||
|     <head> | ||||
|         <link rel="stylesheet" href="https://cdn.metroui.org.ua/v4/css/metro-all.min.css" /> | ||||
|         <meta charset="UTF-8" /> | ||||
|         <title>ArmCord Setup</title> | ||||
|         <style> | ||||
|             @import url("css/setup.css"); | ||||
|         </style> | ||||
|     </head> | ||||
| 
 | ||||
|   <body> | ||||
|     <div class="container"> | ||||
|       <h1 class="logo"></h1> | ||||
|       <div id="setup"> | ||||
|         <p>Select what kind of setup you want to perform:</p> | ||||
|         <button id="express" class="center">Express setup</button> | ||||
|         <button id="full" class="center">Full setup</button> | ||||
|       </div> | ||||
|     </div> | ||||
|     <script> | ||||
|     <body> | ||||
|         <div class="container"> | ||||
|             <h1 class="logo"></h1> | ||||
|             <div id="setup"> | ||||
|                 <p>Select what kind of setup you want to perform:</p> | ||||
|                 <button id="express" class="center">Express setup</button> | ||||
|                 <button id="full" class="center">Full setup</button> | ||||
|             </div> | ||||
|         </div> | ||||
|         <script> | ||||
|             function fade(element) { | ||||
|                 var op = 1; // initial opacity | ||||
|                 var timer = setInterval(function () { | ||||
|                     if (op <= 0.1) { | ||||
|                         clearInterval(timer); | ||||
|                         element.style.display = "none"; | ||||
|                     } | ||||
|                     element.style.opacity = op; | ||||
|                     element.style.filter = "alpha(opacity=" + op * 100 + ")"; | ||||
|                     op -= op * 0.1; | ||||
|                 }, 50); | ||||
|             } | ||||
| 
 | ||||
|       function fade(element) { | ||||
|         var op = 1; // initial opacity | ||||
|         var timer = setInterval(function () { | ||||
|           if (op <= 0.1) { | ||||
|             clearInterval(timer); | ||||
|             element.style.display = "none"; | ||||
|           } | ||||
|           element.style.opacity = op; | ||||
|           element.style.filter = "alpha(opacity=" + op * 100 + ")"; | ||||
|           op -= op * 0.1; | ||||
|         }, 50); | ||||
|       } | ||||
| 
 | ||||
|       if (window.navigator.onLine === false) { | ||||
|         document.getElementById("setup").innerHTML = | ||||
|           "You appear to be offline. Please connect to the internet and restart ArmCord Setup."; | ||||
|       } else { | ||||
|         console.log("Starting ArmCord Setup..."); | ||||
|         document.getElementById("express").addEventListener("click", function () { | ||||
|           window.armcordinternal.saveSettings({ | ||||
|             windowStyle: "default", | ||||
|             channel: "stable", | ||||
|             armcordCSP: true, | ||||
|             minimizeToTray: true, | ||||
|             automaticPatches: false, | ||||
|             mods: "cumcord", | ||||
|             blurType: "acrylic" | ||||
|           }) | ||||
|           fade(document.getElementById("setup")); | ||||
|                 setTimeout(function () { | ||||
|                   window.armcordinternal.restart() | ||||
|                 }, 5000); | ||||
|         }) | ||||
|         document.getElementById("full").addEventListener("click", function () { | ||||
|           document.getElementById("setup").innerHTML = ` | ||||
|             if (window.navigator.onLine === false) { | ||||
|                 document.getElementById("setup").innerHTML = | ||||
|                     "You appear to be offline. Please connect to the internet and restart ArmCord Setup."; | ||||
|             } else { | ||||
|                 console.log("Starting ArmCord Setup..."); | ||||
|                 document.getElementById("express").addEventListener("click", function () { | ||||
|                     window.armcordinternal.saveSettings({ | ||||
|                         windowStyle: "default", | ||||
|                         channel: "stable", | ||||
|                         armcordCSP: true, | ||||
|                         minimizeToTray: true, | ||||
|                         automaticPatches: false, | ||||
|                         mods: "cumcord", | ||||
|                         blurType: "acrylic" | ||||
|                     }); | ||||
|                     fade(document.getElementById("setup")); | ||||
|                     setTimeout(function () { | ||||
|                         window.armcordinternal.restart(); | ||||
|                     }, 5000); | ||||
|                 }); | ||||
|                 document.getElementById("full").addEventListener("click", function () { | ||||
|                     document.getElementById("setup").innerHTML = ` | ||||
|         <p class="text-center setup-ask">Choose your Discord channel/instance:</p> | ||||
|     <div class="center"> | ||||
|       <select name="channel" id="channel" class="dropdown-button"> | ||||
|  | @ -77,13 +73,11 @@ | |||
|       </div> | ||||
|       <button id="next" class="center">Next</button> | ||||
|       `; | ||||
|           document | ||||
|             .getElementById("next") | ||||
|             .addEventListener("click", function () { | ||||
|               var branch = document.getElementById("channel").value; | ||||
|               var csp = document.getElementById("csp").value; | ||||
|               if (csp === "true") { | ||||
|                 document.getElementById("setup").innerHTML = ` | ||||
|                     document.getElementById("next").addEventListener("click", function () { | ||||
|                         var branch = document.getElementById("channel").value; | ||||
|                         var csp = document.getElementById("csp").value; | ||||
|                         if (csp === "true") { | ||||
|                             document.getElementById("setup").innerHTML = ` | ||||
|         <p class="text-center setup-ask">Select a client mod you want to install:</p> | ||||
|     <div class="center"> | ||||
|       <select name="mod" id="mod" class="dropdown-button"> | ||||
|  | @ -95,42 +89,40 @@ | |||
|       <p>Why not all of them? Having many client mods at the same time can cause issues. If you really want to do it though, check our documentation ;)</p> | ||||
|       <button id="next" class="center">Next</button> | ||||
|       `; | ||||
|                 document | ||||
|                   .getElementById("next") | ||||
|                   .addEventListener("click", function () { | ||||
|                     var mod = document.getElementById("mod").value; | ||||
|                     window.armcordinternal.saveSettings({ | ||||
|                       windowStyle: "default", | ||||
|                       channel: branch, | ||||
|                       armcordCSP: true, | ||||
|                       minimizeToTray: true, | ||||
|                       automaticPatches: false, | ||||
|                       mods: mod, | ||||
|                       blurType: "acrylic" | ||||
|                     }) | ||||
|                     fade(document.getElementById("setup")); | ||||
|                     setTimeout(function () { | ||||
|                       window.armcordinternal.restart(); | ||||
|                     }, 5000); | ||||
|                   }); | ||||
|               } else { | ||||
|                 window.armcordinternal.saveSettings({ | ||||
|                   windowStyle: "default", | ||||
|                   channel: branch, | ||||
|                   armcordCSP: true, | ||||
|                   minimizeToTray: true, | ||||
|                   automaticPatches: false, | ||||
|                   mods: "none", | ||||
|                   blurType: "acrylic" | ||||
|                 }) | ||||
|                 fade(document.getElementById("setup")); | ||||
|                 setTimeout(function () { | ||||
|                   window.armcordinternal.restart() | ||||
|                 }, 5000); | ||||
|               } | ||||
|             }); | ||||
|         }); | ||||
|       } | ||||
|     </script> | ||||
|   </body> | ||||
|                             document.getElementById("next").addEventListener("click", function () { | ||||
|                                 var mod = document.getElementById("mod").value; | ||||
|                                 window.armcordinternal.saveSettings({ | ||||
|                                     windowStyle: "default", | ||||
|                                     channel: branch, | ||||
|                                     armcordCSP: true, | ||||
|                                     minimizeToTray: true, | ||||
|                                     automaticPatches: false, | ||||
|                                     mods: mod, | ||||
|                                     blurType: "acrylic" | ||||
|                                 }); | ||||
|                                 fade(document.getElementById("setup")); | ||||
|                                 setTimeout(function () { | ||||
|                                     window.armcordinternal.restart(); | ||||
|                                 }, 5000); | ||||
|                             }); | ||||
|                         } else { | ||||
|                             window.armcordinternal.saveSettings({ | ||||
|                                 windowStyle: "default", | ||||
|                                 channel: branch, | ||||
|                                 armcordCSP: true, | ||||
|                                 minimizeToTray: true, | ||||
|                                 automaticPatches: false, | ||||
|                                 mods: "none", | ||||
|                                 blurType: "acrylic" | ||||
|                             }); | ||||
|                             fade(document.getElementById("setup")); | ||||
|                             setTimeout(function () { | ||||
|                                 window.armcordinternal.restart(); | ||||
|                             }, 5000); | ||||
|                         } | ||||
|                     }); | ||||
|                 }); | ||||
|             } | ||||
|         </script> | ||||
|     </body> | ||||
| </html> | ||||
|  |  | |||
|  | @ -1,68 +1,63 @@ | |||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
|   <head> | ||||
|     <meta charset="UTF-8" /> | ||||
|     <title>ArmCord</title> | ||||
|     <style> | ||||
|       @import url("css/splash.css"); | ||||
|     </style> | ||||
|   </head> | ||||
|     <head> | ||||
|         <meta charset="UTF-8" /> | ||||
|         <title>ArmCord</title> | ||||
|         <style> | ||||
|             @import url("css/splash.css"); | ||||
|         </style> | ||||
|     </head> | ||||
| 
 | ||||
|   <body> | ||||
|     <div class="container"> | ||||
|       <video autoplay loop class="logo" id="splashscreen-armcord"> | ||||
|         <source | ||||
|           src="https://armcord.smartfridge.space/discord_loading.webm" | ||||
|           type="video/webm" | ||||
|         /> | ||||
|       </video> | ||||
|       <p id="text-splashscreen"></p> | ||||
|     </div> | ||||
|   </body> | ||||
|   <script> | ||||
|     const text = document.getElementById("text-splashscreen"); | ||||
|     if (window.navigator.onLine === false) { | ||||
|       text.innerHTML = | ||||
|         "You appear to be offline. Please connect to the internet and try again."; | ||||
|     } else { | ||||
|       text.innerHTML = "Starting ArmCord..."; | ||||
|       fetch("https://armcord.smartfridge.space/latest.json") | ||||
|         .then((response) => response.json()) | ||||
|         .then((data) => { | ||||
|           if (data.version !== window.armcord.version) { | ||||
|             var elem = document.createElement("img"); | ||||
|             elem.classList.add("logo"); | ||||
|             elem.src = "https://armcord.smartfridge.space/update.webp"; | ||||
|             document.body.prepend(elem); | ||||
|             document.getElementById("splashscreen-armcord").remove(); | ||||
|             text.innerHTML = | ||||
|               "A new version of ArmCord is available. Please update to the latest version."; | ||||
|           } else { | ||||
|             console.log("ArmCord is up to date.") | ||||
|           } | ||||
|         }); | ||||
|       setTimeout(() => { | ||||
|         window.armcordinternal.splashEnd(); | ||||
|         switch (window.armcord.channel) { | ||||
|         case "stable": | ||||
|           window.location.replace("https://discord.com/app"); | ||||
|           break; | ||||
|         case "canary": | ||||
|           window.location.replace("https://canary.discord.com/app"); | ||||
|           break; | ||||
|         case "ptb": | ||||
|           window.location.replace("https://ptb.discord.com/app"); | ||||
|           break; | ||||
|         case "foss": | ||||
|           window.location.replace("https://dev.fosscord.com/app"); | ||||
|           break; | ||||
|         case undefined: | ||||
|           window.location.replace("https://discord.com/app"); | ||||
|           break; | ||||
|         default: | ||||
|           window.location.replace("https://discord.com/app"); | ||||
|       } | ||||
|       }, 5000); | ||||
|     } | ||||
|   </script> | ||||
|     <body> | ||||
|         <div class="container"> | ||||
|             <video autoplay loop class="logo" id="splashscreen-armcord"> | ||||
|                 <source src="https://armcord.smartfridge.space/discord_loading.webm" type="video/webm" /> | ||||
|             </video> | ||||
|             <p id="text-splashscreen"></p> | ||||
|         </div> | ||||
|     </body> | ||||
|     <script> | ||||
|         const text = document.getElementById("text-splashscreen"); | ||||
|         if (window.navigator.onLine === false) { | ||||
|             text.innerHTML = "You appear to be offline. Please connect to the internet and try again."; | ||||
|         } else { | ||||
|             text.innerHTML = "Starting ArmCord..."; | ||||
|             fetch("https://armcord.smartfridge.space/latest.json") | ||||
|                 .then((response) => response.json()) | ||||
|                 .then((data) => { | ||||
|                     if (data.version !== window.armcord.version) { | ||||
|                         var elem = document.createElement("img"); | ||||
|                         elem.classList.add("logo"); | ||||
|                         elem.src = "https://armcord.smartfridge.space/update.webp"; | ||||
|                         document.body.prepend(elem); | ||||
|                         document.getElementById("splashscreen-armcord").remove(); | ||||
|                         text.innerHTML = "A new version of ArmCord is available. Please update to the latest version."; | ||||
|                     } else { | ||||
|                         console.log("ArmCord is up to date."); | ||||
|                     } | ||||
|                 }); | ||||
|             setTimeout(() => { | ||||
|                 window.armcordinternal.splashEnd(); | ||||
|                 switch (window.armcord.channel) { | ||||
|                     case "stable": | ||||
|                         window.location.replace("https://discord.com/app"); | ||||
|                         break; | ||||
|                     case "canary": | ||||
|                         window.location.replace("https://canary.discord.com/app"); | ||||
|                         break; | ||||
|                     case "ptb": | ||||
|                         window.location.replace("https://ptb.discord.com/app"); | ||||
|                         break; | ||||
|                     case "foss": | ||||
|                         window.location.replace("https://dev.fosscord.com/app"); | ||||
|                         break; | ||||
|                     case undefined: | ||||
|                         window.location.replace("https://discord.com/app"); | ||||
|                         break; | ||||
|                     default: | ||||
|                         window.location.replace("https://discord.com/app"); | ||||
|                 } | ||||
|             }, 5000); | ||||
|         } | ||||
|     </script> | ||||
| </html> | ||||
|  |  | |||
|  | @ -11,59 +11,55 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI | |||
| import electron from "electron"; | ||||
| import * as storage from "electron-json-storage"; | ||||
| const otherMods = { | ||||
|   generic: { | ||||
|     electronProxy: require("util").types.isProxy(electron), // Many modern mods overwrite electron with a proxy with a custom BrowserWindow (copied from PowerCord)
 | ||||
|   }, | ||||
|     generic: { | ||||
|         electronProxy: require("util").types.isProxy(electron) // Many modern mods overwrite electron with a proxy with a custom BrowserWindow (copied from PowerCord)
 | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| const unstrictCSP = () => { | ||||
|   console.log("Setting up CSP unstricter..."); | ||||
|     console.log("Setting up CSP unstricter..."); | ||||
| 
 | ||||
|   const cspAllowAll = ["connect-src", "style-src", "img-src", "font-src"]; | ||||
|     const cspAllowAll = ["connect-src", "style-src", "img-src", "font-src"]; | ||||
| 
 | ||||
|   const corsAllowUrls = [ | ||||
|     "https://github.com/GooseMod/GooseMod/releases/download/dev/index.js", | ||||
|     "https://github-releases.githubusercontent.com/", | ||||
|     "https://api.goosemod.com/inject.js", | ||||
|     "https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/build.js", | ||||
|     "https://raw.githubusercontent.com/Cumcord/Cumcord/master/dist/build.js", | ||||
|     "https://raw.githubusercontent.com/FlickerMod/dist/main/build.js", | ||||
|   ]; | ||||
|     const corsAllowUrls = [ | ||||
|         "https://github.com/GooseMod/GooseMod/releases/download/dev/index.js", | ||||
|         "https://github-releases.githubusercontent.com/", | ||||
|         "https://api.goosemod.com/inject.js", | ||||
|         "https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/build.js", | ||||
|         "https://raw.githubusercontent.com/Cumcord/Cumcord/master/dist/build.js", | ||||
|         "https://raw.githubusercontent.com/FlickerMod/dist/main/build.js" | ||||
|     ]; | ||||
| 
 | ||||
|   electron.session.defaultSession.webRequest.onHeadersReceived( | ||||
|     ({ responseHeaders, url }, done) => { | ||||
|       let csp = responseHeaders!["content-security-policy"]; | ||||
|     electron.session.defaultSession.webRequest.onHeadersReceived(({responseHeaders, url}, done) => { | ||||
|         let csp = responseHeaders!["content-security-policy"]; | ||||
| 
 | ||||
|       if (otherMods.generic.electronProxy) { | ||||
|         // Since patch v16, override other mod's onHeadersRecieved (Electron only allows 1 listener); because they rely on 0 CSP at all (GM just unrestricts some areas), remove it fully if we detect other mods
 | ||||
|         delete responseHeaders!["content-security-policy"]; | ||||
|         csp = []; | ||||
|       } | ||||
| 
 | ||||
|       if (csp) { | ||||
|         for (let p of cspAllowAll) { | ||||
|           csp[0] = csp[0].replace(`${p}`, `${p} * blob: data:`); // * does not include data: URIs
 | ||||
|         if (otherMods.generic.electronProxy) { | ||||
|             // Since patch v16, override other mod's onHeadersRecieved (Electron only allows 1 listener); because they rely on 0 CSP at all (GM just unrestricts some areas), remove it fully if we detect other mods
 | ||||
|             delete responseHeaders!["content-security-policy"]; | ||||
|             csp = []; | ||||
|         } | ||||
| 
 | ||||
|         // Fix Discord's broken CSP which disallows unsafe-inline due to having a nonce (which they don't even use?)
 | ||||
|         csp[0] = csp[0].replace(/'nonce-.*?' /, ""); | ||||
|       } | ||||
|         if (csp) { | ||||
|             for (let p of cspAllowAll) { | ||||
|                 csp[0] = csp[0].replace(`${p}`, `${p} * blob: data:`); // * does not include data: URIs
 | ||||
|             } | ||||
| 
 | ||||
|       if (corsAllowUrls.some((x) => url.startsWith(x))) { | ||||
|         responseHeaders!["access-control-allow-origin"] = ["*"]; | ||||
|       } | ||||
|             // Fix Discord's broken CSP which disallows unsafe-inline due to having a nonce (which they don't even use?)
 | ||||
|             csp[0] = csp[0].replace(/'nonce-.*?' /, ""); | ||||
|         } | ||||
| 
 | ||||
|       done({ responseHeaders }); | ||||
|     } | ||||
|   ); | ||||
|         if (corsAllowUrls.some((x) => url.startsWith(x))) { | ||||
|             responseHeaders!["access-control-allow-origin"] = ["*"]; | ||||
|         } | ||||
| 
 | ||||
|         done({responseHeaders}); | ||||
|     }); | ||||
| }; | ||||
| storage.get("settings", function (error, data: any) { | ||||
|   if (error) throw error; | ||||
|   if (data.armcordCSP) { | ||||
|     unstrictCSP(); | ||||
|   } else { | ||||
|     console.log( | ||||
|       "ArmCord CSP is disabled. The CSP should be managed by third-party plugin." | ||||
|     ); | ||||
|   } | ||||
|     if (error) throw error; | ||||
|     if (data.armcordCSP) { | ||||
|         unstrictCSP(); | ||||
|     } else { | ||||
|         console.log("ArmCord CSP is disabled. The CSP should be managed by third-party plugin."); | ||||
|     } | ||||
| }); | ||||
|  |  | |||
|  | @ -1,26 +1,20 @@ | |||
| import * as fs from 'fs'; | ||||
| import { app, session } from 'electron'; | ||||
| import * as fs from "fs"; | ||||
| import {app, session} from "electron"; | ||||
| const userDataPath = app.getPath("userData"); | ||||
| const pluginFolder = userDataPath + "/plugins/"; | ||||
| if (!fs.existsSync(pluginFolder)) { | ||||
|     fs.mkdirSync(pluginFolder); | ||||
|     console.log("Created missing plugin folder"); | ||||
|   } | ||||
| } | ||||
| app.whenReady().then(() => { | ||||
|   fs.readdirSync(pluginFolder).forEach((file) => { | ||||
|     try { | ||||
|       const manifest = fs.readFileSync( | ||||
|         `${userDataPath}/plugins/${file}/manifest.json`, | ||||
|         "utf8" | ||||
|       ); | ||||
|       var pluginFile = JSON.parse(manifest); | ||||
|       session.defaultSession.loadExtension(`${userDataPath}/plugins/${file}`); | ||||
|       console.log( | ||||
|         `%cLoaded ${pluginFile.name} made by ${pluginFile.author}`, | ||||
|         "color:red" | ||||
|       ); | ||||
|     } catch (err) { | ||||
|       console.error(err); | ||||
|     } | ||||
|   }); | ||||
|     fs.readdirSync(pluginFolder).forEach((file) => { | ||||
|         try { | ||||
|             const manifest = fs.readFileSync(`${userDataPath}/plugins/${file}/manifest.json`, "utf8"); | ||||
|             var pluginFile = JSON.parse(manifest); | ||||
|             session.defaultSession.loadExtension(`${userDataPath}/plugins/${file}`); | ||||
|             console.log(`%cLoaded ${pluginFile.name} made by ${pluginFile.author}`, "color:red"); | ||||
|         } catch (err) { | ||||
|             console.error(err); | ||||
|         } | ||||
|     }); | ||||
| }); | ||||
|  |  | |||
							
								
								
									
										158
									
								
								src/ipc.ts
									
										
									
									
									
								
							
							
						
						
									
										158
									
								
								src/ipc.ts
									
										
									
									
									
								
							|  | @ -1,83 +1,81 @@ | |||
| //ipc stuff
 | ||||
| import { app, ipcMain, shell, desktopCapturer } from "electron"; | ||||
| import { createTabsGuest, mainWindow } from "./window"; | ||||
| import { saveSettings, getVersion } from "./utils"; | ||||
| import { settings, customTitlebar, tabs } from "./main"; | ||||
| import { createSettingsWindow } from "./settings/main"; | ||||
| import {app, ipcMain, shell, desktopCapturer} from "electron"; | ||||
| import {createTabsGuest, mainWindow} from "./window"; | ||||
| import {saveSettings, getVersion} from "./utils"; | ||||
| import {settings, customTitlebar, tabs} from "./main"; | ||||
| import {createSettingsWindow} from "./settings/main"; | ||||
| export function registerIpc() { | ||||
|   ipcMain.on("get-app-path", (event, arg) => { | ||||
|     event.reply("app-path", app.getAppPath()); | ||||
|   }); | ||||
|   ipcMain.on("openTab", (event, number: number) => { | ||||
|     createTabsGuest(number); | ||||
|   }); | ||||
|   ipcMain.on("open-external-link", (event, href: string) => { | ||||
|     shell.openExternal(href); | ||||
|   }); | ||||
|   ipcMain.on("win-maximize", (event, arg) => { | ||||
|     mainWindow.maximize(); | ||||
|   }); | ||||
|   ipcMain.on("win-isMaximized", (event, arg) => { | ||||
|     event.returnValue = mainWindow.isMaximized(); | ||||
|   }); | ||||
|   ipcMain.on("win-minimize", (event, arg) => { | ||||
|     mainWindow.minimize(); | ||||
|   }); | ||||
|   ipcMain.on("win-unmaximize", (event, arg) => { | ||||
|     mainWindow.unmaximize(); | ||||
|   }); | ||||
|   ipcMain.on("win-show", (event, arg) => { | ||||
|     mainWindow.show(); | ||||
|   }); | ||||
|   ipcMain.on("win-hide", (event, arg) => { | ||||
|     mainWindow.hide(); | ||||
|   }); | ||||
|   ipcMain.on("win-quit", (event, arg) => { | ||||
|     app.exit(); | ||||
|   }); | ||||
|   ipcMain.on("get-app-version", (event) => { | ||||
|     event.returnValue = getVersion(); | ||||
|   }); | ||||
|   ipcMain.on("splashEnd", (event, arg) => { | ||||
|     mainWindow.setSize(800, 600); | ||||
|   }); | ||||
|   ipcMain.on("restart", (event, arg) => { | ||||
|     app.relaunch(); | ||||
|     app.exit(); | ||||
|   }); | ||||
|   ipcMain.on("saveSettings", (event, args) => { | ||||
|     saveSettings(args); | ||||
|   }); | ||||
|   ipcMain.on("minimizeToTray", (event) => { | ||||
|     console.log(settings.minimizeToTray); | ||||
|     event.returnValue = settings.minimizeToTray; | ||||
|   }); | ||||
|   ipcMain.on("channel", (event) => { | ||||
|     event.returnValue = settings.channel; | ||||
|   }); | ||||
|   ipcMain.on("clientmod", (event, arg) => { | ||||
|     event.returnValue = settings.mods; | ||||
|   }); | ||||
|   ipcMain.on("titlebar", (event, arg) => { | ||||
|     event.returnValue = customTitlebar; | ||||
|   }); | ||||
|   ipcMain.on("tabs", (event, arg) => { | ||||
|     event.returnValue = tabs; | ||||
|   }); | ||||
|   ipcMain.on("shouldPatch", (event, arg) => { | ||||
|     event.returnValue = settings.automaticPatches; | ||||
|   }); | ||||
|   ipcMain.on("openSettingsWindow", (event, arg) => { | ||||
|     createSettingsWindow(); | ||||
|   }); | ||||
|   ipcMain.on("setting-armcordCSP", (event) => { | ||||
|     if (settings.armcordCSP) { | ||||
|       event.returnValue = true; | ||||
|     } else { | ||||
|       event.returnValue = false; | ||||
|     } | ||||
|   }); | ||||
|   ipcMain.handle("DESKTOP_CAPTURER_GET_SOURCES", (event, opts) => | ||||
|     desktopCapturer.getSources(opts) | ||||
|   ); | ||||
|     ipcMain.on("get-app-path", (event, arg) => { | ||||
|         event.reply("app-path", app.getAppPath()); | ||||
|     }); | ||||
|     ipcMain.on("openTab", (event, number: number) => { | ||||
|         createTabsGuest(number); | ||||
|     }); | ||||
|     ipcMain.on("open-external-link", (event, href: string) => { | ||||
|         shell.openExternal(href); | ||||
|     }); | ||||
|     ipcMain.on("win-maximize", (event, arg) => { | ||||
|         mainWindow.maximize(); | ||||
|     }); | ||||
|     ipcMain.on("win-isMaximized", (event, arg) => { | ||||
|         event.returnValue = mainWindow.isMaximized(); | ||||
|     }); | ||||
|     ipcMain.on("win-minimize", (event, arg) => { | ||||
|         mainWindow.minimize(); | ||||
|     }); | ||||
|     ipcMain.on("win-unmaximize", (event, arg) => { | ||||
|         mainWindow.unmaximize(); | ||||
|     }); | ||||
|     ipcMain.on("win-show", (event, arg) => { | ||||
|         mainWindow.show(); | ||||
|     }); | ||||
|     ipcMain.on("win-hide", (event, arg) => { | ||||
|         mainWindow.hide(); | ||||
|     }); | ||||
|     ipcMain.on("win-quit", (event, arg) => { | ||||
|         app.exit(); | ||||
|     }); | ||||
|     ipcMain.on("get-app-version", (event) => { | ||||
|         event.returnValue = getVersion(); | ||||
|     }); | ||||
|     ipcMain.on("splashEnd", (event, arg) => { | ||||
|         mainWindow.setSize(800, 600); | ||||
|     }); | ||||
|     ipcMain.on("restart", (event, arg) => { | ||||
|         app.relaunch(); | ||||
|         app.exit(); | ||||
|     }); | ||||
|     ipcMain.on("saveSettings", (event, args) => { | ||||
|         saveSettings(args); | ||||
|     }); | ||||
|     ipcMain.on("minimizeToTray", (event) => { | ||||
|         console.log(settings.minimizeToTray); | ||||
|         event.returnValue = settings.minimizeToTray; | ||||
|     }); | ||||
|     ipcMain.on("channel", (event) => { | ||||
|         event.returnValue = settings.channel; | ||||
|     }); | ||||
|     ipcMain.on("clientmod", (event, arg) => { | ||||
|         event.returnValue = settings.mods; | ||||
|     }); | ||||
|     ipcMain.on("titlebar", (event, arg) => { | ||||
|         event.returnValue = customTitlebar; | ||||
|     }); | ||||
|     ipcMain.on("tabs", (event, arg) => { | ||||
|         event.returnValue = tabs; | ||||
|     }); | ||||
|     ipcMain.on("shouldPatch", (event, arg) => { | ||||
|         event.returnValue = settings.automaticPatches; | ||||
|     }); | ||||
|     ipcMain.on("openSettingsWindow", (event, arg) => { | ||||
|         createSettingsWindow(); | ||||
|     }); | ||||
|     ipcMain.on("setting-armcordCSP", (event) => { | ||||
|         if (settings.armcordCSP) { | ||||
|             event.returnValue = true; | ||||
|         } else { | ||||
|             event.returnValue = false; | ||||
|         } | ||||
|     }); | ||||
|     ipcMain.handle("DESKTOP_CAPTURER_GET_SOURCES", (event, opts) => desktopCapturer.getSources(opts)); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										160
									
								
								src/main.ts
									
										
									
									
									
								
							
							
						
						
									
										160
									
								
								src/main.ts
									
										
									
									
									
								
							|  | @ -1,114 +1,108 @@ | |||
| // Modules to control application life and create native browser window
 | ||||
| import { | ||||
|   app, | ||||
|   BrowserWindow, | ||||
|   session, | ||||
| } from "electron"; | ||||
| import {app, BrowserWindow, session} from "electron"; | ||||
| import * as path from "path"; | ||||
| import "v8-compile-cache"; | ||||
| import * as storage from "electron-json-storage"; | ||||
| import { getConfigUnsafe, setup } from "./utils"; | ||||
| import {getConfigUnsafe, setup} from "./utils"; | ||||
| import "./extensions/mods"; | ||||
| import "./extensions/plugin"; | ||||
| import "./tray"; | ||||
| import { mainWindow, createCustomWindow, createNativeWindow, createGlasstronWindow, createTabsHost } from "./window"; | ||||
| import {mainWindow, createCustomWindow, createNativeWindow, createGlasstronWindow, createTabsHost} from "./window"; | ||||
| import "./shortcuts"; | ||||
| export var contentPath: string; | ||||
| var channel: string; | ||||
| export var settings: any; | ||||
| export var customTitlebar: boolean; | ||||
| export var tabs: boolean; | ||||
| async function appendSwitch(){ | ||||
|   if (await getConfigUnsafe("windowStyle") == "glasstron") { | ||||
|     console.log("Enabling transparency visuals."); | ||||
|     app.commandLine.appendSwitch("enable-transparent-visuals"); | ||||
|   } | ||||
| async function appendSwitch() { | ||||
|     if ((await getConfigUnsafe("windowStyle")) == "glasstron") { | ||||
|         console.log("Enabling transparency visuals."); | ||||
|         app.commandLine.appendSwitch("enable-transparent-visuals"); | ||||
|     } | ||||
| } | ||||
| appendSwitch(); | ||||
|   storage.has("settings", function (error, hasKey) { | ||||
| storage.has("settings", function (error, hasKey) { | ||||
|     if (error) throw error; | ||||
| 
 | ||||
|     if (!hasKey) { | ||||
|       console.log("First run of the ArmCord. Starting setup."); | ||||
|       setup(); | ||||
|       contentPath = path.join(__dirname, "/content/setup.html"); | ||||
|       if (!contentPath.includes("ts-out")) { | ||||
|         contentPath = path.join(__dirname, "/ts-out/content/setup.html"); | ||||
|       } | ||||
|         console.log("First run of the ArmCord. Starting setup."); | ||||
|         setup(); | ||||
|         contentPath = path.join(__dirname, "/content/setup.html"); | ||||
|         if (!contentPath.includes("ts-out")) { | ||||
|             contentPath = path.join(__dirname, "/ts-out/content/setup.html"); | ||||
|         } | ||||
|     } else { | ||||
|       console.log("ArmCord has been run before. Skipping setup."); | ||||
|       contentPath = path.join(__dirname, "/content/splash.html"); | ||||
|       if (!contentPath.includes("ts-out")) { | ||||
|         contentPath = path.join(__dirname, "/ts-out/content/splash.html"); | ||||
|       } | ||||
|         console.log("ArmCord has been run before. Skipping setup."); | ||||
|         contentPath = path.join(__dirname, "/content/splash.html"); | ||||
|         if (!contentPath.includes("ts-out")) { | ||||
|             contentPath = path.join(__dirname, "/ts-out/content/splash.html"); | ||||
|         } | ||||
|     } | ||||
|   }); | ||||
| }); | ||||
| storage.get("settings", function (error, data: any) { | ||||
|   if (error) throw error; | ||||
|   console.log(data); | ||||
|   channel = data.channel; | ||||
|   settings = data; | ||||
|     if (error) throw error; | ||||
|     console.log(data); | ||||
|     channel = data.channel; | ||||
|     settings = data; | ||||
| }); | ||||
| app.whenReady().then(async () => { | ||||
|   switch (await getConfigUnsafe("windowStyle")) { | ||||
|     case "default": | ||||
|       createCustomWindow(); | ||||
|       customTitlebar = true; | ||||
|       break; | ||||
|     case "native": | ||||
|       createNativeWindow(); | ||||
|       break; | ||||
|     case "glasstron": | ||||
|       setTimeout( | ||||
|         createGlasstronWindow, | ||||
|         process.platform == "linux" ? 1000 : 0 | ||||
|         // Electron has a bug on linux where it
 | ||||
|         // won't initialize properly when using
 | ||||
|         // transparency. To work around that, it
 | ||||
|         // is necessary to delay the window
 | ||||
|         // spawn function.
 | ||||
|       ); | ||||
|       break; | ||||
|     case "tabs": | ||||
|       createTabsHost(); | ||||
|       tabs = true; | ||||
|       break; | ||||
|     default: | ||||
|       createCustomWindow(); | ||||
|       customTitlebar = true; | ||||
|       break; | ||||
|   } | ||||
|   session | ||||
|     .fromPartition("some-partition") | ||||
|     .setPermissionRequestHandler((webContents, permission, callback) => { | ||||
|       if (permission === "notifications") { | ||||
|         // Approves the permissions request
 | ||||
|         callback(true); | ||||
|       } | ||||
|       if (permission === "media") { | ||||
|         // Approves the permissions request
 | ||||
|         callback(true); | ||||
|       } | ||||
|     }); | ||||
|   app.on("activate", async function () { | ||||
|     if (BrowserWindow.getAllWindows().length === 0) | ||||
|       switch (await getConfigUnsafe("windowStyle")) { | ||||
|     switch (await getConfigUnsafe("windowStyle")) { | ||||
|         case "default": | ||||
|           createCustomWindow(); | ||||
|           break; | ||||
|             createCustomWindow(); | ||||
|             customTitlebar = true; | ||||
|             break; | ||||
|         case "native": | ||||
|           createNativeWindow(); | ||||
|           break; | ||||
|             createNativeWindow(); | ||||
|             break; | ||||
|         case "glasstron": | ||||
|           createGlasstronWindow(); | ||||
|           break; | ||||
|             setTimeout( | ||||
|                 createGlasstronWindow, | ||||
|                 process.platform == "linux" ? 1000 : 0 | ||||
|                 // Electron has a bug on linux where it
 | ||||
|                 // won't initialize properly when using
 | ||||
|                 // transparency. To work around that, it
 | ||||
|                 // is necessary to delay the window
 | ||||
|                 // spawn function.
 | ||||
|             ); | ||||
|             break; | ||||
|         case "tabs": | ||||
|             createTabsHost(); | ||||
|             tabs = true; | ||||
|             break; | ||||
|         default: | ||||
|           createCustomWindow(); | ||||
|           break; | ||||
|       } | ||||
|   }); | ||||
|             createCustomWindow(); | ||||
|             customTitlebar = true; | ||||
|             break; | ||||
|     } | ||||
|     session.fromPartition("some-partition").setPermissionRequestHandler((webContents, permission, callback) => { | ||||
|         if (permission === "notifications") { | ||||
|             // Approves the permissions request
 | ||||
|             callback(true); | ||||
|         } | ||||
|         if (permission === "media") { | ||||
|             // Approves the permissions request
 | ||||
|             callback(true); | ||||
|         } | ||||
|     }); | ||||
|     app.on("activate", async function () { | ||||
|         if (BrowserWindow.getAllWindows().length === 0) | ||||
|             switch (await getConfigUnsafe("windowStyle")) { | ||||
|                 case "default": | ||||
|                     createCustomWindow(); | ||||
|                     break; | ||||
|                 case "native": | ||||
|                     createNativeWindow(); | ||||
|                     break; | ||||
|                 case "glasstron": | ||||
|                     createGlasstronWindow(); | ||||
|                     break; | ||||
|                 default: | ||||
|                     createCustomWindow(); | ||||
|                     break; | ||||
|             } | ||||
|     }); | ||||
| }); | ||||
| 
 | ||||
| app.on("window-all-closed", function () { | ||||
|   if (process.platform !== "darwin") app.quit(); | ||||
|     if (process.platform !== "darwin") app.quit(); | ||||
| }); | ||||
|  |  | |||
|  | @ -1,33 +1,30 @@ | |||
| import { contextBridge, ipcRenderer } from "electron"; | ||||
| import { getDisplayMediaSelector } from "./capturer"; | ||||
| import { injectTitlebar } from "./titlebar"; | ||||
| import {contextBridge, ipcRenderer} from "electron"; | ||||
| import {getDisplayMediaSelector} from "./capturer"; | ||||
| import {injectTitlebar} from "./titlebar"; | ||||
| 
 | ||||
| contextBridge.exposeInMainWorld("armcord", { | ||||
|   window: { | ||||
|     show: () => ipcRenderer.send("win-show"), | ||||
|     hide: () => ipcRenderer.send("win-hide"), | ||||
|     minimize: () => ipcRenderer.send("win-minimize"), | ||||
|     maximize: () => ipcRenderer.send("win-maximize"), | ||||
|   }, | ||||
|   titlebar: { | ||||
|     injectTitlebar: () => injectTitlebar(), | ||||
|     isTitlebar: ipcRenderer.sendSync("titlebar"), | ||||
|   }, | ||||
|   electron: process.versions.electron, | ||||
|   channel: ipcRenderer.sendSync("channel"), | ||||
|   openTab: (number: number) => ipcRenderer.sendSync("openTab", number), | ||||
|   version: ipcRenderer.sendSync("get-app-version", "app-version"), | ||||
|   getDisplayMediaSelector: getDisplayMediaSelector, | ||||
|   openSettingsWindow: () => ipcRenderer.send("openSettingsWindow"), | ||||
|     window: { | ||||
|         show: () => ipcRenderer.send("win-show"), | ||||
|         hide: () => ipcRenderer.send("win-hide"), | ||||
|         minimize: () => ipcRenderer.send("win-minimize"), | ||||
|         maximize: () => ipcRenderer.send("win-maximize") | ||||
|     }, | ||||
|     titlebar: { | ||||
|         injectTitlebar: () => injectTitlebar(), | ||||
|         isTitlebar: ipcRenderer.sendSync("titlebar") | ||||
|     }, | ||||
|     electron: process.versions.electron, | ||||
|     channel: ipcRenderer.sendSync("channel"), | ||||
|     openTab: (number: number) => ipcRenderer.sendSync("openTab", number), | ||||
|     version: ipcRenderer.sendSync("get-app-version", "app-version"), | ||||
|     getDisplayMediaSelector: getDisplayMediaSelector, | ||||
|     openSettingsWindow: () => ipcRenderer.send("openSettingsWindow") | ||||
| }); | ||||
| //to be only used inside armcord internal setup/splash etc
 | ||||
| if ( | ||||
|   window.location.href.indexOf("splash.html") > -1 || | ||||
|   window.location.href.indexOf("setup.html") > -1 | ||||
| ) { | ||||
|   contextBridge.exposeInMainWorld("armcordinternal", { | ||||
|     restart: () => ipcRenderer.send("restart"), | ||||
|     saveSettings: (...args: any) => ipcRenderer.send("saveSettings", ...args), | ||||
|     splashEnd: () => ipcRenderer.send("splashEnd"), | ||||
|   }); | ||||
| } | ||||
| if (window.location.href.indexOf("splash.html") > -1 || window.location.href.indexOf("setup.html") > -1) { | ||||
|     contextBridge.exposeInMainWorld("armcordinternal", { | ||||
|         restart: () => ipcRenderer.send("restart"), | ||||
|         saveSettings: (...args: any) => ipcRenderer.send("saveSettings", ...args), | ||||
|         splashEnd: () => ipcRenderer.send("splashEnd") | ||||
|     }); | ||||
| } | ||||
|  |  | |||
|  | @ -1,37 +1,36 @@ | |||
| //Fixed context isolation version https://github.com/getferdi/ferdi/blob/develop/src/webview/screenshare.ts
 | ||||
| //original https://github.com/electron/electron/issues/16513#issuecomment-602070250
 | ||||
| import { ipcRenderer } from 'electron'; | ||||
| import {addStyle, addScript} from '../utils'; | ||||
| import {ipcRenderer} from "electron"; | ||||
| import {addStyle, addScript} from "../utils"; | ||||
| const desktopCapturer = { | ||||
|   getSources: (opts: any) => | ||||
|     ipcRenderer.invoke("DESKTOP_CAPTURER_GET_SOURCES", opts), | ||||
|     getSources: (opts: any) => ipcRenderer.invoke("DESKTOP_CAPTURER_GET_SOURCES", opts) | ||||
| }; | ||||
| const CANCEL_ID = 'desktop-capturer-selection__cancel'; | ||||
| const CANCEL_ID = "desktop-capturer-selection__cancel"; | ||||
| 
 | ||||
| interface IPCSources { | ||||
|   id: string; | ||||
|   name: string; | ||||
|   thumbnail: HTMLCanvasElement; | ||||
|     id: string; | ||||
|     name: string; | ||||
|     thumbnail: HTMLCanvasElement; | ||||
| } | ||||
| 
 | ||||
| export async function getDisplayMediaSelector() { | ||||
|   const sources: IPCSources[] = await desktopCapturer.getSources({ | ||||
|     types: ['screen', 'window'], | ||||
|   }); | ||||
|   return `<div class="desktop-capturer-selection__scroller">
 | ||||
|     const sources: IPCSources[] = await desktopCapturer.getSources({ | ||||
|         types: ["screen", "window"] | ||||
|     }); | ||||
|     return `<div class="desktop-capturer-selection__scroller">
 | ||||
|   <ul class="desktop-capturer-selection__list"> | ||||
|     ${sources | ||||
|       .map( | ||||
|         ({ id, name, thumbnail }) => ` | ||||
|         .map( | ||||
|             ({id, name, thumbnail}) => ` | ||||
|       <li class="desktop-capturer-selection__item"> | ||||
|         <button class="desktop-capturer-selection__btn" data-id="${id}" title="${name}"> | ||||
|           <img class="desktop-capturer-selection__thumbnail" src="${thumbnail.toDataURL()}" /> | ||||
|           <span class="desktop-capturer-selection__name">${name}</span> | ||||
|         </button> | ||||
|       </li> | ||||
|     `,
 | ||||
|       ) | ||||
|       .join('')} | ||||
|     ` | ||||
|         ) | ||||
|         .join("")} | ||||
|     <li class="desktop-capturer-selection__item"> | ||||
|       <button class="desktop-capturer-selection__btn" data-id="${CANCEL_ID}" title="Cancel"> | ||||
|         <span class="desktop-capturer-selection__name desktop-capturer-selection__name--cancel">Cancel</span> | ||||
|  | @ -154,9 +153,8 @@ window.navigator.mediaDevices.getDisplayMedia = () => new Promise(async (resolve | |||
| }); | ||||
| `;
 | ||||
| 
 | ||||
| document.addEventListener("DOMContentLoaded", function() { | ||||
|   addScript(screenShareJS); | ||||
|   addStyle(screenShareCSS); | ||||
|   console.log("Capturer injected.") | ||||
| document.addEventListener("DOMContentLoaded", function () { | ||||
|     addScript(screenShareJS); | ||||
|     addStyle(screenShareCSS); | ||||
|     console.log("Capturer injected."); | ||||
| }); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,22 +1,22 @@ | |||
| // What does this do?
 | ||||
| // In case of faulty update of ArmCord we can quickly push an update to the user and possibly try to fix it
 | ||||
| // This is completely optional and is disabled by default in settings
 | ||||
| import { ipcRenderer } from "electron"; | ||||
| import { injectJS } from "../utils"; | ||||
| import {ipcRenderer} from "electron"; | ||||
| import {injectJS} from "../utils"; | ||||
| 
 | ||||
| var patchEndpoint = "https://patch.armcord.xyz/"; | ||||
| var version = ipcRenderer.sendSync("get-app-version", "app-version"); | ||||
| if (ipcRenderer.sendSync("shouldPatch")) { | ||||
|   document.addEventListener("DOMContentLoaded", function () { | ||||
|     fetch(patchEndpoint + version + "/info.json", {cache: "no-store"}) //lmao
 | ||||
|       .then((res) => res.json()) | ||||
|       .then((res) => { | ||||
|         if (res.patch == true) { | ||||
|             console.log("Found a patch. Injecting..."); | ||||
|             injectJS(patchEndpoint + version + "/patch.js"); | ||||
|         } else { | ||||
|             console.log("No patches have been found.") | ||||
|         } | ||||
|       }); | ||||
|   }); | ||||
|     document.addEventListener("DOMContentLoaded", function () { | ||||
|         fetch(patchEndpoint + version + "/info.json", {cache: "no-store"}) //lmao
 | ||||
|             .then((res) => res.json()) | ||||
|             .then((res) => { | ||||
|                 if (res.patch == true) { | ||||
|                     console.log("Found a patch. Injecting..."); | ||||
|                     injectJS(patchEndpoint + version + "/patch.js"); | ||||
|                 } else { | ||||
|                     console.log("No patches have been found."); | ||||
|                 } | ||||
|             }); | ||||
|     }); | ||||
| } | ||||
|  |  | |||
|  | @ -1,51 +1,50 @@ | |||
| import "./bridge"; | ||||
| import "./capturer"; | ||||
| import "./patch" | ||||
| import "./patch"; | ||||
| import * as fs from "fs"; | ||||
| import * as path from "path"; | ||||
| import { injectTitlebar } from "./titlebar"; | ||||
| import { sleep, addStyle, injectJS } from "../utils"; | ||||
| import { ipcRenderer } from "electron"; | ||||
| import { injectTabs } from "./tabs"; | ||||
| import {injectTitlebar} from "./titlebar"; | ||||
| import {sleep, addStyle, injectJS} from "../utils"; | ||||
| import {ipcRenderer} from "electron"; | ||||
| import {injectTabs} from "./tabs"; | ||||
| declare global { | ||||
|   interface Window { | ||||
|     armcord: any; | ||||
|   } | ||||
|     interface Window { | ||||
|         armcord: any; | ||||
|     } | ||||
| } | ||||
| const clientMods = { | ||||
|   goosemod: "https://api.goosemod.com/inject.js", | ||||
|   cumcord: | ||||
|     "https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/build.js", | ||||
|   flicker: "https://raw.githubusercontent.com/FlickerMod/dist/main/build.js", | ||||
|     goosemod: "https://api.goosemod.com/inject.js", | ||||
|     cumcord: "https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/build.js", | ||||
|     flicker: "https://raw.githubusercontent.com/FlickerMod/dist/main/build.js" | ||||
| }; | ||||
| 
 | ||||
| console.log("ArmCord"); | ||||
| if (window.location.href.indexOf("splash.html") > -1) { | ||||
|   console.log("Skipping titlebar injection and client mod injection."); | ||||
|     console.log("Skipping titlebar injection and client mod injection."); | ||||
| } else { | ||||
|   if (ipcRenderer.sendSync("titlebar")) { | ||||
|     injectTitlebar(); | ||||
|   } | ||||
|   if (ipcRenderer.sendSync("tabs")) { | ||||
|     injectTabs(); | ||||
|   } | ||||
|   sleep(5000).then(() => { | ||||
|     const cssPath = path.join(__dirname, "../", "/content/css/discord.css"); | ||||
|     addStyle(fs.readFileSync(cssPath, "utf8")); | ||||
| 
 | ||||
|     switch (ipcRenderer.sendSync("clientmod")) { | ||||
|       case "goosemod": | ||||
|         injectJS(clientMods.goosemod); | ||||
|         console.log("Loading GooseMod..."); | ||||
|         break; | ||||
|       case "cumcord": | ||||
|         injectJS(clientMods.cumcord); | ||||
|         console.log("Loading Cumcord..."); | ||||
|         break; | ||||
|       case "flicker": | ||||
|         injectJS(clientMods.flicker); | ||||
|         console.log("Loading FlickerMod..."); | ||||
|         break; | ||||
|     if (ipcRenderer.sendSync("titlebar")) { | ||||
|         injectTitlebar(); | ||||
|     } | ||||
|   }); | ||||
|     if (ipcRenderer.sendSync("tabs")) { | ||||
|         injectTabs(); | ||||
|     } | ||||
|     sleep(5000).then(() => { | ||||
|         const cssPath = path.join(__dirname, "../", "/content/css/discord.css"); | ||||
|         addStyle(fs.readFileSync(cssPath, "utf8")); | ||||
| 
 | ||||
|         switch (ipcRenderer.sendSync("clientmod")) { | ||||
|             case "goosemod": | ||||
|                 injectJS(clientMods.goosemod); | ||||
|                 console.log("Loading GooseMod..."); | ||||
|                 break; | ||||
|             case "cumcord": | ||||
|                 injectJS(clientMods.cumcord); | ||||
|                 console.log("Loading Cumcord..."); | ||||
|                 break; | ||||
|             case "flicker": | ||||
|                 injectJS(clientMods.flicker); | ||||
|                 console.log("Loading FlickerMod..."); | ||||
|                 break; | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  |  | |||
|  | @ -1,10 +1,10 @@ | |||
| import { addStyle } from "../utils"; | ||||
| import {addStyle} from "../utils"; | ||||
| import * as fs from "fs"; | ||||
| import * as path from "path"; | ||||
| export function injectTabs() { | ||||
|   document.addEventListener("DOMContentLoaded", function (event) { | ||||
|     var elem = document.createElement("div"); | ||||
|     elem.innerHTML = `<nav class="tabs">
 | ||||
|     document.addEventListener("DOMContentLoaded", function (event) { | ||||
|         var elem = document.createElement("div"); | ||||
|         elem.innerHTML = `<nav class="tabs">
 | ||||
|           <div id="tabs-controls-container"> | ||||
|               <button class="tabs-buttons" onclick="armcord.openTab(1)">1</button> | ||||
|               <button class="tabs-buttons" onclick="armcord.openTab(2)">2</button> | ||||
|  | @ -14,12 +14,13 @@ export function injectTabs() { | |||
|               <p class="experimental">Experimental</p> | ||||
|           </div> | ||||
|         </nav>`;
 | ||||
|     elem.classList.add("withFrame-haYltI"); | ||||
|     if (document.getElementById("app-mount") == null) { | ||||
|       document.body.appendChild(elem); | ||||
|     } else { | ||||
|       document.getElementById("app-mount")!.prepend(elem); | ||||
|     } | ||||
|     const cssPath = path.join(__dirname, "../", "/content/css/tabs.css"); | ||||
|     addStyle(fs.readFileSync(cssPath, "utf8"));  | ||||
| })} | ||||
|         elem.classList.add("withFrame-haYltI"); | ||||
|         if (document.getElementById("app-mount") == null) { | ||||
|             document.body.appendChild(elem); | ||||
|         } else { | ||||
|             document.getElementById("app-mount")!.prepend(elem); | ||||
|         } | ||||
|         const cssPath = path.join(__dirname, "../", "/content/css/tabs.css"); | ||||
|         addStyle(fs.readFileSync(cssPath, "utf8")); | ||||
|     }); | ||||
| } | ||||
|  |  | |||
|  | @ -1,11 +1,11 @@ | |||
| import { ipcRenderer } from "electron"; | ||||
| import { addStyle } from "../utils"; | ||||
| import {ipcRenderer} from "electron"; | ||||
| import {addStyle} from "../utils"; | ||||
| import * as fs from "fs"; | ||||
| import * as path from "path"; | ||||
| export function injectTitlebar() { | ||||
|   document.addEventListener("DOMContentLoaded", function (event) { | ||||
|     var elem = document.createElement("div"); | ||||
|     elem.innerHTML = `<nav class="titlebar">
 | ||||
|     document.addEventListener("DOMContentLoaded", function (event) { | ||||
|         var elem = document.createElement("div"); | ||||
|         elem.innerHTML = `<nav class="titlebar">
 | ||||
|           <div class="window-title" id="window-title"></div> | ||||
|           <div id="window-controls-container"> | ||||
|               <div id="minimize"></div> | ||||
|  | @ -13,40 +13,40 @@ export function injectTitlebar() { | |||
|               <div id="quit"></div> | ||||
|           </div> | ||||
|         </nav>`;
 | ||||
|     elem.classList.add("withFrame-haYltI"); | ||||
|     if (document.getElementById("app-mount") == null) { | ||||
|       document.body.appendChild(elem); | ||||
|     } else { | ||||
|       document.getElementById("app-mount")!.prepend(elem); | ||||
|     } | ||||
|     const cssPath = path.join(__dirname, "../", "/content/css/titlebar.css"); | ||||
|     addStyle(fs.readFileSync(cssPath, "utf8")); | ||||
|         elem.classList.add("withFrame-haYltI"); | ||||
|         if (document.getElementById("app-mount") == null) { | ||||
|             document.body.appendChild(elem); | ||||
|         } else { | ||||
|             document.getElementById("app-mount")!.prepend(elem); | ||||
|         } | ||||
|         const cssPath = path.join(__dirname, "../", "/content/css/titlebar.css"); | ||||
|         addStyle(fs.readFileSync(cssPath, "utf8")); | ||||
| 
 | ||||
|     var minimize = document.getElementById("minimize"); | ||||
|     var maximize = document.getElementById("maximize"); | ||||
|     var quit = document.getElementById("quit"); | ||||
|         var minimize = document.getElementById("minimize"); | ||||
|         var maximize = document.getElementById("maximize"); | ||||
|         var quit = document.getElementById("quit"); | ||||
| 
 | ||||
|     minimize!.addEventListener("click", () => { | ||||
|       ipcRenderer.send("win-minimize"); | ||||
|         minimize!.addEventListener("click", () => { | ||||
|             ipcRenderer.send("win-minimize"); | ||||
|         }); | ||||
| 
 | ||||
|         maximize!.addEventListener("click", () => { | ||||
|             if (ipcRenderer.sendSync("win-isMaximized") == true) { | ||||
|                 ipcRenderer.send("win-unmaximize"); | ||||
|             } else { | ||||
|                 ipcRenderer.send("win-maximize"); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         quit!.addEventListener("click", () => { | ||||
|             if (ipcRenderer.sendSync("minimizeToTray") === true) { | ||||
|                 ipcRenderer.send("win-hide"); | ||||
|             } else if (ipcRenderer.sendSync("minimizeToTray") === false) { | ||||
|                 ipcRenderer.send("win-quit"); | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
| 
 | ||||
|     maximize!.addEventListener("click", () => { | ||||
|       if (ipcRenderer.sendSync("win-isMaximized") == true) { | ||||
|         ipcRenderer.send("win-unmaximize"); | ||||
|       } else { | ||||
|         ipcRenderer.send("win-maximize"); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     quit!.addEventListener("click", () => { | ||||
|       if (ipcRenderer.sendSync("minimizeToTray") === true) { | ||||
|         ipcRenderer.send("win-hide"); | ||||
|       } else if (ipcRenderer.sendSync("minimizeToTray") === false) { | ||||
|         ipcRenderer.send("win-quit"); | ||||
|       } | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
| export function removeTitlebar() { | ||||
|   document.querySelector("#titlebar")!.remove(); | ||||
|     document.querySelector("#titlebar")!.remove(); | ||||
| } | ||||
|  |  | |||
|  | @ -1,46 +1,46 @@ | |||
| import { BrowserWindow, shell, ipcMain } from "electron"; | ||||
| import * as storage from "electron-json-storage";  | ||||
| import {BrowserWindow, shell, ipcMain} from "electron"; | ||||
| import * as storage from "electron-json-storage"; | ||||
| import {getConfigUnsafe, saveSettings, Settings} from "../utils"; | ||||
| import path from "path"; | ||||
| var settings:any; | ||||
| var isAlreadyCreated:boolean = false; | ||||
| var settings: any; | ||||
| var isAlreadyCreated: boolean = false; | ||||
| storage.get("settings", function (error, data: any) { | ||||
|   if (error) throw error; | ||||
|   console.log(data); | ||||
|   settings = data; | ||||
|     if (error) throw error; | ||||
|     console.log(data); | ||||
|     settings = data; | ||||
| }); | ||||
| var settingsWindow:BrowserWindow; | ||||
| var settingsWindow: BrowserWindow; | ||||
| export function createSettingsWindow() { | ||||
|   if (isAlreadyCreated) { | ||||
|     settingsWindow.show(); | ||||
|   } else { | ||||
|   settingsWindow = new BrowserWindow({ | ||||
|     width: 500, | ||||
|     height: 500, | ||||
|     title: "ArmCord Settings", | ||||
|     darkTheme: true, | ||||
|     frame: true, | ||||
|     autoHideMenuBar: true, | ||||
|     webPreferences: { | ||||
|       preload: path.join(__dirname, "preload.js"), | ||||
|     }, | ||||
|   }); | ||||
|   ipcMain.on("saveSettings", (event, args: Settings) => { | ||||
|     console.log(args); | ||||
|     saveSettings(args); | ||||
|   }); | ||||
|   ipcMain.handle("getSetting", (event, toGet: string) => { | ||||
|     return getConfigUnsafe(toGet); | ||||
|   }); | ||||
|   settingsWindow.webContents.setWindowOpenHandler(({ url }) => { | ||||
|     shell.openExternal(url); | ||||
|     return { action: "deny" }; | ||||
|   }); | ||||
|   settingsWindow.loadURL(`file://${__dirname}/settings.html`); | ||||
|   settingsWindow.on("close", async (e) => { | ||||
|     e.preventDefault() | ||||
|     settingsWindow.hide() | ||||
|   }); | ||||
|   isAlreadyCreated = true; | ||||
| } | ||||
|     if (isAlreadyCreated) { | ||||
|         settingsWindow.show(); | ||||
|     } else { | ||||
|         settingsWindow = new BrowserWindow({ | ||||
|             width: 500, | ||||
|             height: 500, | ||||
|             title: "ArmCord Settings", | ||||
|             darkTheme: true, | ||||
|             frame: true, | ||||
|             autoHideMenuBar: true, | ||||
|             webPreferences: { | ||||
|                 preload: path.join(__dirname, "preload.js") | ||||
|             } | ||||
|         }); | ||||
|         ipcMain.on("saveSettings", (event, args: Settings) => { | ||||
|             console.log(args); | ||||
|             saveSettings(args); | ||||
|         }); | ||||
|         ipcMain.handle("getSetting", (event, toGet: string) => { | ||||
|             return getConfigUnsafe(toGet); | ||||
|         }); | ||||
|         settingsWindow.webContents.setWindowOpenHandler(({url}) => { | ||||
|             shell.openExternal(url); | ||||
|             return {action: "deny"}; | ||||
|         }); | ||||
|         settingsWindow.loadURL(`file://${__dirname}/settings.html`); | ||||
|         settingsWindow.on("close", async (e) => { | ||||
|             e.preventDefault(); | ||||
|             settingsWindow.hide(); | ||||
|         }); | ||||
|         isAlreadyCreated = true; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,6 +1,9 @@ | |||
| import {contextBridge, ipcRenderer} from "electron"; | ||||
| console.log("ArmCord Settings") | ||||
| console.log("ArmCord Settings"); | ||||
| contextBridge.exposeInMainWorld("settings", { | ||||
|   save: (...args: any) => ipcRenderer.send("saveSettings", ...args), | ||||
|   get: (toGet: string) => ipcRenderer.invoke('getSetting', toGet).then((result) => {return result}) //jank but works
 | ||||
| }); | ||||
|     save: (...args: any) => ipcRenderer.send("saveSettings", ...args), | ||||
|     get: (toGet: string) => | ||||
|         ipcRenderer.invoke("getSetting", toGet).then((result) => { | ||||
|             return result; | ||||
|         }) //jank but works
 | ||||
| }); | ||||
|  |  | |||
|  | @ -20,49 +20,49 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE.*/ | ||||
| :root { | ||||
|   --background-primary: #282b30; | ||||
|   --background-secondary: rgba(255, 255, 255, 0.1); | ||||
|   --brand-experiment: #5865f2; | ||||
|   --header-primary: #fff; | ||||
|   --text-muted: #72767d; | ||||
|     --background-primary: #282b30; | ||||
|     --background-secondary: rgba(255, 255, 255, 0.1); | ||||
|     --brand-experiment: #5865f2; | ||||
|     --header-primary: #fff; | ||||
|     --text-muted: #72767d; | ||||
| } | ||||
| 
 | ||||
| @font-face { | ||||
|   font-family: Whitney; | ||||
|   font-weight: 400; | ||||
|   font-style: normal; | ||||
|   src: url(https://armcord.smartfridge.space/whitney_400.woff) format("woff"); | ||||
|     font-family: Whitney; | ||||
|     font-weight: 400; | ||||
|     font-style: normal; | ||||
|     src: url(https://armcord.smartfridge.space/whitney_400.woff) format("woff"); | ||||
| } | ||||
| 
 | ||||
| html, | ||||
| body { | ||||
|   overflow: hidden; | ||||
|     overflow: hidden; | ||||
| 
 | ||||
|   margin: 0; | ||||
|   padding: 0; | ||||
|   margin: 2%; | ||||
|   background: var(--background-primary); | ||||
|     margin: 0; | ||||
|     padding: 0; | ||||
|     margin: 2%; | ||||
|     background: var(--background-primary); | ||||
| } | ||||
| 
 | ||||
| * { | ||||
|   font-family: "Whitney", sans-serif; | ||||
|     font-family: "Whitney", sans-serif; | ||||
| 
 | ||||
|   box-sizing: border-box; | ||||
|   cursor: default; | ||||
|     box-sizing: border-box; | ||||
|     cursor: default; | ||||
| } | ||||
| .left { | ||||
|     float:right; | ||||
|     vertical-align: right!important; | ||||
|     float: right; | ||||
|     vertical-align: right !important; | ||||
| } | ||||
| .switch { | ||||
|   vertical-align: middle; | ||||
|     vertical-align: middle; | ||||
| } | ||||
| .header { | ||||
|   color: white; | ||||
|   font-size: 1.5em; | ||||
|     color: white; | ||||
|     font-size: 1.5em; | ||||
| } | ||||
| .center { | ||||
|   text-align: center; | ||||
|     text-align: center; | ||||
| } | ||||
| /*buttons*/ | ||||
| button { | ||||
|  | @ -72,7 +72,7 @@ button { | |||
|     padding: 4px; | ||||
|     border-radius: 5px; | ||||
|     margin-top: 5px; | ||||
|      | ||||
| 
 | ||||
|     text-align: center; | ||||
|     border-style: none; | ||||
|     outline: none; | ||||
|  | @ -85,73 +85,92 @@ button:hover { | |||
|     cursor: pointer; | ||||
| } | ||||
| .tgl { | ||||
|   display: none; | ||||
|     display: none; | ||||
| } | ||||
| .tgl, .tgl:after, .tgl:before, .tgl *, .tgl *:after, .tgl *:before, .tgl + .tgl-btn { | ||||
|   box-sizing: border-box; | ||||
| .tgl, | ||||
| .tgl:after, | ||||
| .tgl:before, | ||||
| .tgl *, | ||||
| .tgl *:after, | ||||
| .tgl *:before, | ||||
| .tgl + .tgl-btn { | ||||
|     box-sizing: border-box; | ||||
| } | ||||
| .tgl::-moz-selection, .tgl:after::-moz-selection, .tgl:before::-moz-selection, .tgl *::-moz-selection, .tgl *:after::-moz-selection, .tgl *:before::-moz-selection, .tgl + .tgl-btn::-moz-selection { | ||||
|   background: none; | ||||
| .tgl::-moz-selection, | ||||
| .tgl:after::-moz-selection, | ||||
| .tgl:before::-moz-selection, | ||||
| .tgl *::-moz-selection, | ||||
| .tgl *:after::-moz-selection, | ||||
| .tgl *:before::-moz-selection, | ||||
| .tgl + .tgl-btn::-moz-selection { | ||||
|     background: none; | ||||
| } | ||||
| .tgl::selection, .tgl:after::selection, .tgl:before::selection, .tgl *::selection, .tgl *:after::selection, .tgl *:before::selection, .tgl + .tgl-btn::selection { | ||||
|   background: none; | ||||
| .tgl::selection, | ||||
| .tgl:after::selection, | ||||
| .tgl:before::selection, | ||||
| .tgl *::selection, | ||||
| .tgl *:after::selection, | ||||
| .tgl *:before::selection, | ||||
| .tgl + .tgl-btn::selection { | ||||
|     background: none; | ||||
| } | ||||
| .tgl + .tgl-btn { | ||||
|   outline: 0; | ||||
|   display: block; | ||||
|   width: 4em; | ||||
|   height: 2em; | ||||
|   position: relative; | ||||
|   cursor: pointer; | ||||
|   -webkit-user-select: none; | ||||
|      -moz-user-select: none; | ||||
|       -ms-user-select: none; | ||||
|           user-select: none; | ||||
|     outline: 0; | ||||
|     display: block; | ||||
|     width: 4em; | ||||
|     height: 2em; | ||||
|     position: relative; | ||||
|     cursor: pointer; | ||||
|     -webkit-user-select: none; | ||||
|     -moz-user-select: none; | ||||
|     -ms-user-select: none; | ||||
|     user-select: none; | ||||
| } | ||||
| .tgl + .tgl-btn:after, .tgl + .tgl-btn:before { | ||||
|   position: relative; | ||||
|   display: block; | ||||
|   content: ""; | ||||
|   width: 50%; | ||||
|   height: 100%; | ||||
| .tgl + .tgl-btn:after, | ||||
| .tgl + .tgl-btn:before { | ||||
|     position: relative; | ||||
|     display: block; | ||||
|     content: ""; | ||||
|     width: 50%; | ||||
|     height: 100%; | ||||
| } | ||||
| .tgl + .tgl-btn:after { | ||||
|   left: 0; | ||||
|     left: 0; | ||||
| } | ||||
| .tgl + .tgl-btn:before { | ||||
|   display: none; | ||||
|     display: none; | ||||
| } | ||||
| .tgl:checked + .tgl-btn:after { | ||||
|   left: 50%; | ||||
|     left: 50%; | ||||
| } | ||||
| 
 | ||||
| .tgl-light + .tgl-btn { | ||||
|   background: #5c5757; | ||||
|   border-radius: 2em; | ||||
|   padding: 2px; | ||||
|   transition: all 0.4s ease; | ||||
|     background: #5c5757; | ||||
|     border-radius: 2em; | ||||
|     padding: 2px; | ||||
|     transition: all 0.4s ease; | ||||
| } | ||||
| .tgl-light + .tgl-btn:after { | ||||
|   border-radius: 50%; | ||||
|   background: rgb(255, 255, 255); | ||||
|   transition: all 0.2s ease; | ||||
|     border-radius: 50%; | ||||
|     background: rgb(255, 255, 255); | ||||
|     transition: all 0.2s ease; | ||||
| } | ||||
| .tgl-light:checked + .tgl-btn { | ||||
|   background: #47ca5a; | ||||
|     background: #47ca5a; | ||||
| } | ||||
| select { | ||||
|   -webkit-appearance: button; | ||||
|   -moz-appearance: button; | ||||
|   background-color: #2c2f33; | ||||
|   background-position: center right; | ||||
|   background-repeat: no-repeat; | ||||
|   border: 1px solid #aaa; | ||||
|   border-radius: 2px; | ||||
|   box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1); | ||||
|   color: #fff; | ||||
|   font-size: 1.2em; | ||||
|   margin: 0; | ||||
|   overflow: hidden; | ||||
|   text-overflow: ellipsis; | ||||
|   white-space: nowrap; | ||||
| } | ||||
|     -webkit-appearance: button; | ||||
|     -moz-appearance: button; | ||||
|     background-color: #2c2f33; | ||||
|     background-position: center right; | ||||
|     background-repeat: no-repeat; | ||||
|     border: 1px solid #aaa; | ||||
|     border-radius: 2px; | ||||
|     box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1); | ||||
|     color: #fff; | ||||
|     font-size: 1.2em; | ||||
|     margin: 0; | ||||
|     overflow: hidden; | ||||
|     text-overflow: ellipsis; | ||||
|     white-space: nowrap; | ||||
| } | ||||
|  |  | |||
|  | @ -1,88 +1,92 @@ | |||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
|     <head> | ||||
|         <meta charset="UTF-8" /> | ||||
|         <title>ArmCord Settings</title> | ||||
|         <style> | ||||
|             @import url("settings.css"); | ||||
|         </style> | ||||
|     </head> | ||||
| 
 | ||||
| <head> | ||||
|   <meta charset="UTF-8" /> | ||||
|   <title>ArmCord Settings</title> | ||||
|   <style> | ||||
|     @import url("settings.css"); | ||||
|   </style> | ||||
| </head> | ||||
|     <body> | ||||
|         <div class="switch"> | ||||
|             <select name="theme" id="theme" class="left"> | ||||
|                 <option value="default">Default</option> | ||||
|                 <option value="native">Native</option> | ||||
|                 <option value="glasstron">Glasstron (experimental)</option> | ||||
|                 <option value="tabs">Tabs (experimental)</option> | ||||
|             </select> | ||||
|             <p class="header">ArmCord theme:</p> | ||||
|         </div> | ||||
|         <br /> | ||||
|         <div class="switch"> | ||||
|             <label class="header">ArmCord CSP</label> | ||||
|             <input class="tgl tgl-light left" id="csp" type="checkbox" /> | ||||
|             <label class="tgl-btn left" for="csp"></label> | ||||
|         </div> | ||||
|         <br /> | ||||
|         <div class="switch"> | ||||
|             <label class="header">Minimize to tray</label> | ||||
|             <input class="tgl tgl-light left" id="tray" type="checkbox" /> | ||||
|             <label class="tgl-btn left" for="tray"></label> | ||||
|         </div> | ||||
|         <br /> | ||||
|         <div class="switch"> | ||||
|             <label class="header">Automatic Patches</label> | ||||
|             <input class="tgl tgl-light left" id="patches" type="checkbox" /> | ||||
|             <label class="tgl-btn left" for="patches"></label> | ||||
|         </div> | ||||
|         <div class="switch"> | ||||
|             <select name="channel" id="channel" class="left"> | ||||
|                 <option value="stable">Stable</option> | ||||
|                 <option value="canary">Canary</option> | ||||
|                 <option value="ptb">PTB</option> | ||||
|                 <option value="foss">Fosscord</option> | ||||
|             </select> | ||||
|             <p class="header">Discord channel:</p> | ||||
|         </div> | ||||
|         <div class="switch"> | ||||
|             <select name="mod" id="mod" class="left"> | ||||
|                 <option value="cumcord">Cumcord</option> | ||||
|                 <option value="goosemod">GooseMod</option> | ||||
|                 <option value="flicker">Flicker</option> | ||||
|             </select> | ||||
|             <p class="header">Client mod:</p> | ||||
|         </div> | ||||
|         <div class="switch"> | ||||
|             <select name="blurType" id="blurType" class="left"> | ||||
|                 <option value="acrylic">Acrylic</option> | ||||
|                 <option value="blurbehind">Blur Behind</option> | ||||
|                 <option value="transparent">Transparent</option> | ||||
|                 <option value="none">None</option> | ||||
|             </select> | ||||
|             <p class="header">Glasstron blur type:</p> | ||||
|         </div> | ||||
|         <button id="save" class="center">Save settings</button> | ||||
|     </body> | ||||
| 
 | ||||
| <body> | ||||
| 
 | ||||
| <div class="switch"> | ||||
|     <select name="theme" id="theme" class="left"> | ||||
|       <option value="default">Default</option> | ||||
|       <option value="native">Native</option> | ||||
|       <option value="glasstron">Glasstron (experimental)</option> | ||||
|       <option value="tabs">Tabs (experimental)</option> | ||||
|     </select> | ||||
|     <p class="header">ArmCord theme:</p> | ||||
|   </div> | ||||
|   </br> | ||||
|   <div class="switch"> | ||||
|     <label class="header">ArmCord CSP</label> | ||||
|     <input class="tgl tgl-light left" id="csp" type="checkbox" /> | ||||
|     <label class="tgl-btn left" for="csp"></label> | ||||
|   </div> | ||||
|   </br> | ||||
|   <div class="switch"> | ||||
|     <label class="header">Minimize to tray</label> | ||||
|     <input class="tgl tgl-light left" id="tray" type="checkbox" /> | ||||
|     <label class="tgl-btn left" for="tray"></label> | ||||
|   </div> | ||||
|   </br> | ||||
|   <div class="switch"> | ||||
|     <label class="header">Automatic Patches</label> | ||||
|     <input class="tgl tgl-light left" id="patches" type="checkbox" /> | ||||
|     <label class="tgl-btn left" for="patches"></label> | ||||
|   </div> | ||||
|   <div class="switch"> | ||||
|     <select name="channel" id="channel" class="left"> | ||||
|       <option value="stable">Stable</option> | ||||
|       <option value="canary">Canary</option> | ||||
|       <option value="ptb">PTB</option> | ||||
|       <option value="foss">Fosscord</option> | ||||
|     </select> | ||||
|     <p class="header">Discord channel:</p> | ||||
|   </div> | ||||
|   <div class="switch"> | ||||
|     <select name="mod" id="mod" class="left"> | ||||
|       <option value="cumcord">Cumcord</option> | ||||
|       <option value="goosemod">GooseMod</option> | ||||
|       <option value="flicker">Flicker</option> | ||||
|     </select> | ||||
|     <p class="header">Client mod:</p> | ||||
|   </div> | ||||
|   <div class="switch"> | ||||
|     <select name="blurType" id="blurType" class="left"> | ||||
|       <option value="acrylic">Acrylic</option> | ||||
|       <option value="blurbehind">Blur Behind</option> | ||||
|       <option value="transparent">Transparent</option> | ||||
|       <option value="none">None</option> | ||||
|     </select> | ||||
|     <p class="header">Glasstron blur type:</p> | ||||
|   </div> | ||||
|   <button id="save" class="center">Save settings</button> | ||||
|    | ||||
| </body> | ||||
| 
 | ||||
| <script> | ||||
|   async function loadSettings() { | ||||
|     document.getElementById("csp").checked = await settings.get("armcordCSP"); | ||||
|     document.getElementById("tray").checked = await settings.get("minimizeToTray"); | ||||
|     document.getElementById("patches").value = await settings.get("automaticPatches"); | ||||
|     document.getElementById("mod").value = await settings.get("mods"); | ||||
|     document.getElementById("channel").value = await settings.get("channel"); | ||||
|     document.getElementById("theme").value = await settings.get("windowStyle"); | ||||
|     document.getElementById("blurType").value = await settings.get("blurType"); | ||||
|   } | ||||
|   loadSettings() | ||||
|   document.getElementById("save").addEventListener("click", function() { | ||||
|     //function saveSettings(windowStyle: string, channelSetting: string, armcordCSPSetting: boolean, minimizeToTray: boolean, automaticPatches: boolean,modsSetting: string, blurType: string)  | ||||
|     settings.save(document.getElementById("theme").value, document.getElementById("channel").value, document.getElementById("csp").checked, document.getElementById("tray").checked, document.getElementById("patches").checked, document.getElementById("mod").value, document.getElementById("blurType").value); | ||||
|   }); | ||||
| </script> | ||||
| 
 | ||||
| </html> | ||||
|     <script> | ||||
|         async function loadSettings() { | ||||
|             document.getElementById("csp").checked = await settings.get("armcordCSP"); | ||||
|             document.getElementById("tray").checked = await settings.get("minimizeToTray"); | ||||
|             document.getElementById("patches").value = await settings.get("automaticPatches"); | ||||
|             document.getElementById("mod").value = await settings.get("mods"); | ||||
|             document.getElementById("channel").value = await settings.get("channel"); | ||||
|             document.getElementById("theme").value = await settings.get("windowStyle"); | ||||
|             document.getElementById("blurType").value = await settings.get("blurType"); | ||||
|         } | ||||
|         loadSettings(); | ||||
|         document.getElementById("save").addEventListener("click", function () { | ||||
|             //function saveSettings(windowStyle: string, channelSetting: string, armcordCSPSetting: boolean, minimizeToTray: boolean, automaticPatches: boolean,modsSetting: string, blurType: string) | ||||
|             settings.save( | ||||
|                 document.getElementById("theme").value, | ||||
|                 document.getElementById("channel").value, | ||||
|                 document.getElementById("csp").checked, | ||||
|                 document.getElementById("tray").checked, | ||||
|                 document.getElementById("patches").checked, | ||||
|                 document.getElementById("mod").value, | ||||
|                 document.getElementById("blurType").value | ||||
|             ); | ||||
|         }); | ||||
|     </script> | ||||
| </html> | ||||
|  |  | |||
|  | @ -1,18 +1,18 @@ | |||
| import { app } from "electron"; | ||||
| import {mainWindow} from './window'; | ||||
| import {app} from "electron"; | ||||
| import {mainWindow} from "./window"; | ||||
| //https://github.com/electron/electron/issues/1334#issuecomment-716080005
 | ||||
| // TO-DO add more
 | ||||
| app.on("web-contents-created", (webContentsCreatedEvent, webContents) => { | ||||
|   webContents.on("before-input-event", (beforeInputEvent, input) => { | ||||
|     // console.log('Main console::', input)
 | ||||
|     const { code, alt, control, shift, meta } = input; | ||||
|     // Shortcut: toggle devTools
 | ||||
|     if (shift && control && !alt && !meta && code === "KeyI") { | ||||
|       mainWindow.webContents.toggleDevTools(); | ||||
|     } | ||||
|     // Shortcut: window reload
 | ||||
|     if (shift && control && !alt && !meta && code === "KeyR") { | ||||
|       mainWindow.reload(); | ||||
|     } | ||||
|   }); | ||||
|     webContents.on("before-input-event", (beforeInputEvent, input) => { | ||||
|         // console.log('Main console::', input)
 | ||||
|         const {code, alt, control, shift, meta} = input; | ||||
|         // Shortcut: toggle devTools
 | ||||
|         if (shift && control && !alt && !meta && code === "KeyI") { | ||||
|             mainWindow.webContents.toggleDevTools(); | ||||
|         } | ||||
|         // Shortcut: window reload
 | ||||
|         if (shift && control && !alt && !meta && code === "KeyR") { | ||||
|             mainWindow.reload(); | ||||
|         } | ||||
|     }); | ||||
| }); | ||||
|  |  | |||
							
								
								
									
										74
									
								
								src/tray.ts
									
										
									
									
									
								
							
							
						
						
									
										74
									
								
								src/tray.ts
									
										
									
									
									
								
							|  | @ -1,38 +1,38 @@ | |||
| import { app, Menu, Tray } from 'electron'; | ||||
| import {mainWindow} from './window'; | ||||
| import * as path from 'path' | ||||
| import { createSettingsWindow } from './settings/main'; | ||||
| let tray = null | ||||
| import {app, Menu, Tray} from "electron"; | ||||
| import {mainWindow} from "./window"; | ||||
| import * as path from "path"; | ||||
| import {createSettingsWindow} from "./settings/main"; | ||||
| let tray = null; | ||||
| app.whenReady().then(() => { | ||||
|   tray = new Tray(path.join(__dirname, "../", "/assets/ac_plug.png")) | ||||
|   const contextMenu = Menu.buildFromTemplate([ | ||||
|     { | ||||
|       label: "Open ArmCord", | ||||
|       click: function () { | ||||
|         mainWindow.show(); | ||||
|       }, | ||||
|     }, | ||||
|     { | ||||
|       label: "Open Settings", | ||||
|       click: function () { | ||||
|         createSettingsWindow(); | ||||
|       }, | ||||
|     }, | ||||
|     { | ||||
|       label: "Support Discord Server", | ||||
|       click: function () { | ||||
|         mainWindow.show(); | ||||
|         mainWindow.loadURL("https://discord.gg/pZtWQBFjk6"); | ||||
|       }, | ||||
|     }, | ||||
|     { | ||||
|       label: "Quit ArmCord", | ||||
|       click: function () { | ||||
|         app.quit(); | ||||
|       }, | ||||
|     }, | ||||
|   ]); | ||||
|    | ||||
|   tray.setToolTip('ArmCord ' + app.getVersion()) | ||||
|   tray.setContextMenu(contextMenu) | ||||
| }) | ||||
|     tray = new Tray(path.join(__dirname, "../", "/assets/ac_plug.png")); | ||||
|     const contextMenu = Menu.buildFromTemplate([ | ||||
|         { | ||||
|             label: "Open ArmCord", | ||||
|             click: function () { | ||||
|                 mainWindow.show(); | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             label: "Open Settings", | ||||
|             click: function () { | ||||
|                 createSettingsWindow(); | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             label: "Support Discord Server", | ||||
|             click: function () { | ||||
|                 mainWindow.show(); | ||||
|                 mainWindow.loadURL("https://discord.gg/pZtWQBFjk6"); | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             label: "Quit ArmCord", | ||||
|             click: function () { | ||||
|                 app.quit(); | ||||
|             } | ||||
|         } | ||||
|     ]); | ||||
| 
 | ||||
|     tray.setToolTip("ArmCord " + app.getVersion()); | ||||
|     tray.setContextMenu(contextMenu); | ||||
| }); | ||||
|  |  | |||
							
								
								
									
										142
									
								
								src/types/glasstron.d.ts
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										142
									
								
								src/types/glasstron.d.ts
									
										
									
									
										vendored
									
									
								
							|  | @ -1,86 +1,70 @@ | |||
| declare module "glasstron" { | ||||
|   export class BrowserWindow extends Electron.BrowserWindow { | ||||
|     getBlur(): Promise<boolean>; | ||||
|     setBlur(value: boolean): Promise<boolean>; | ||||
|     blurType: WindowsBlurType; | ||||
|     setVibrancy(vibrancy: MacOSVibrancy): void; | ||||
|   } | ||||
|   /** | ||||
|    * @deprecated | ||||
|    */ | ||||
|   export function init(): void; | ||||
|   /** | ||||
|    * @deprecated | ||||
|    */ | ||||
|   export function update( | ||||
|     window: Electron.BrowserWindow, | ||||
|     values: { | ||||
|       windows?: { | ||||
|     export class BrowserWindow extends Electron.BrowserWindow { | ||||
|         getBlur(): Promise<boolean>; | ||||
|         setBlur(value: boolean): Promise<boolean>; | ||||
|         blurType: WindowsBlurType; | ||||
|       }; | ||||
|       macos?: { | ||||
|         vibrancy: MacOSVibrancy; | ||||
|       }; | ||||
|       linux?: { | ||||
|         requestBlur: boolean; | ||||
|       }; | ||||
|         setVibrancy(vibrancy: MacOSVibrancy): void; | ||||
|     } | ||||
|   ): void; | ||||
|   export class Hacks { | ||||
|     static injectOnElectron(): void; | ||||
|     static delayReadyEvent(): void; | ||||
|   } | ||||
|   export type WindowsBlurType = | ||||
|     | "acrylic" | ||||
|     | "blurbehind" | ||||
|     | "transparent" | ||||
|     | "none"; | ||||
|   export type MacOSVibrancy = | ||||
|     | ( | ||||
|         | "appearance-based" | ||||
|         | "light" | ||||
|         | "dark" | ||||
|         | "titlebar" | ||||
|         | "selection" | ||||
|         | "menu" | ||||
|         | "popover" | ||||
|         | "sidebar" | ||||
|         | "medium-light" | ||||
|         | "ultra-dark" | ||||
|         | "header" | ||||
|         | "sheet" | ||||
|         | "window" | ||||
|         | "hud" | ||||
|         | "fullscreen-ui" | ||||
|         | "tooltip" | ||||
|         | "content" | ||||
|         | "under-window" | ||||
|         | "under-page" | ||||
|       ) | ||||
|     | null; | ||||
|     /** | ||||
|      * @deprecated | ||||
|      */ | ||||
|     export function init(): void; | ||||
|     /** | ||||
|      * @deprecated | ||||
|      */ | ||||
|     export function update( | ||||
|         window: Electron.BrowserWindow, | ||||
|         values: { | ||||
|             windows?: { | ||||
|                 blurType: WindowsBlurType; | ||||
|             }; | ||||
|             macos?: { | ||||
|                 vibrancy: MacOSVibrancy; | ||||
|             }; | ||||
|             linux?: { | ||||
|                 requestBlur: boolean; | ||||
|             }; | ||||
|         } | ||||
|     ): void; | ||||
|     export class Hacks { | ||||
|         static injectOnElectron(): void; | ||||
|         static delayReadyEvent(): void; | ||||
|     } | ||||
|     export type WindowsBlurType = "acrylic" | "blurbehind" | "transparent" | "none"; | ||||
|     export type MacOSVibrancy = | ||||
|         | ( | ||||
|               | "appearance-based" | ||||
|               | "light" | ||||
|               | "dark" | ||||
|               | "titlebar" | ||||
|               | "selection" | ||||
|               | "menu" | ||||
|               | "popover" | ||||
|               | "sidebar" | ||||
|               | "medium-light" | ||||
|               | "ultra-dark" | ||||
|               | "header" | ||||
|               | "sheet" | ||||
|               | "window" | ||||
|               | "hud" | ||||
|               | "fullscreen-ui" | ||||
|               | "tooltip" | ||||
|               | "content" | ||||
|               | "under-window" | ||||
|               | "under-page" | ||||
|           ) | ||||
|         | null; | ||||
| } | ||||
| 
 | ||||
| declare module "glasstron/src/utils" { | ||||
|   class Utils { | ||||
|     static getSavePath(): string; | ||||
|     static copyToPath( | ||||
|       innerFile: string, | ||||
|       outerFilename?: string, | ||||
|       flags?: number | ||||
|     ): void; | ||||
|     static removeFromPath(filename: string): void; | ||||
|     static isInPath(filename: string): boolean; | ||||
|     static getPlatform(): any; | ||||
|     static parseKeyValString( | ||||
|       string: string, | ||||
|       keyvalSeparator?: string, | ||||
|       pairSeparator?: string | ||||
|     ): any; | ||||
|     static makeKeyValString( | ||||
|       object: any, | ||||
|       keyvalSeparator?: string, | ||||
|       pairSeparator?: string | ||||
|     ): string; | ||||
|   } | ||||
|   export = Utils; | ||||
|     class Utils { | ||||
|         static getSavePath(): string; | ||||
|         static copyToPath(innerFile: string, outerFilename?: string, flags?: number): void; | ||||
|         static removeFromPath(filename: string): void; | ||||
|         static isInPath(filename: string): boolean; | ||||
|         static getPlatform(): any; | ||||
|         static parseKeyValString(string: string, keyvalSeparator?: string, pairSeparator?: string): any; | ||||
|         static makeKeyValString(object: any, keyvalSeparator?: string, pairSeparator?: string): string; | ||||
|     } | ||||
|     export = Utils; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										140
									
								
								src/utils.ts
									
										
									
									
									
								
							
							
						
						
									
										140
									
								
								src/utils.ts
									
										
									
									
									
								
							|  | @ -1,103 +1,101 @@ | |||
| import * as storage from "electron-json-storage"; | ||||
| import * as fs from "fs"; | ||||
| import { app } from "electron"; | ||||
| import {app} from "electron"; | ||||
| import path from "path"; | ||||
| export var firstRun: boolean; | ||||
| 
 | ||||
| //utillity functions that are used all over the codebase or just too obscure to be put in the file used in
 | ||||
| export function addStyle(styleString: string) { | ||||
|   const style = document.createElement("style"); | ||||
|   style.textContent = styleString; | ||||
|   document.head.append(style); | ||||
|     const style = document.createElement("style"); | ||||
|     style.textContent = styleString; | ||||
|     document.head.append(style); | ||||
| } | ||||
| 
 | ||||
| export function addScript(scriptString: string) { | ||||
|   var script = document.createElement("script"); | ||||
|   script.textContent = scriptString; | ||||
|   document.body.append(script); | ||||
|     var script = document.createElement("script"); | ||||
|     script.textContent = scriptString; | ||||
|     document.body.append(script); | ||||
| } | ||||
| 
 | ||||
| export async function sleep(ms: number) { | ||||
|   return new Promise((resolve) => setTimeout(resolve, ms)); | ||||
|     return new Promise((resolve) => setTimeout(resolve, ms)); | ||||
| } | ||||
| 
 | ||||
| export async function checkIfConfigIsNew() { | ||||
|   if (await getConfigUnsafe("automaticPatches") == undefined) { | ||||
|     firstRun = true; | ||||
|   } | ||||
|     if ((await getConfigUnsafe("automaticPatches")) == undefined) { | ||||
|         firstRun = true; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export interface Settings { | ||||
|   windowStyle: string, | ||||
|   channel: string, | ||||
|   armcordCSP: boolean, | ||||
|   minimizeToTray: boolean, | ||||
|   automaticPatches: boolean, | ||||
|   mods: string, | ||||
|   blurType: string | ||||
|     windowStyle: string; | ||||
|     channel: string; | ||||
|     armcordCSP: boolean; | ||||
|     minimizeToTray: boolean; | ||||
|     automaticPatches: boolean; | ||||
|     mods: string; | ||||
|     blurType: string; | ||||
| } | ||||
| export function setup() { | ||||
|   console.log("Setting up temporary ArmCord settings."); | ||||
|   const defaults: Settings = { | ||||
|     windowStyle: "default", | ||||
|     channel: "stable", | ||||
|     armcordCSP: true, | ||||
|     minimizeToTray: true, | ||||
|     automaticPatches: false, | ||||
|     mods: "cumcord", | ||||
|     blurType: "acrylic", | ||||
|   } | ||||
|   storage.set( | ||||
|     "settings", | ||||
|     { | ||||
|       ...defaults, | ||||
|       doneSetup: true, | ||||
|     }, | ||||
|     function (error) { | ||||
|       if (error) throw error; | ||||
|     } | ||||
|   ); | ||||
|     console.log("Setting up temporary ArmCord settings."); | ||||
|     const defaults: Settings = { | ||||
|         windowStyle: "default", | ||||
|         channel: "stable", | ||||
|         armcordCSP: true, | ||||
|         minimizeToTray: true, | ||||
|         automaticPatches: false, | ||||
|         mods: "cumcord", | ||||
|         blurType: "acrylic" | ||||
|     }; | ||||
|     storage.set( | ||||
|         "settings", | ||||
|         { | ||||
|             ...defaults, | ||||
|             doneSetup: true | ||||
|         }, | ||||
|         function (error) { | ||||
|             if (error) throw error; | ||||
|         } | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| export function saveSettings( | ||||
|   settings: Settings | ||||
| ) { | ||||
|   console.log("Setting up ArmCord settings."); | ||||
|   storage.set( | ||||
|     "settings", | ||||
|     { | ||||
|       ...settings, | ||||
|       doneSetup: true | ||||
|     }, | ||||
|     function (error) { | ||||
|       if (error) throw error; | ||||
|     } | ||||
|   ); | ||||
| export function saveSettings(settings: Settings) { | ||||
|     console.log("Setting up ArmCord settings."); | ||||
|     storage.set( | ||||
|         "settings", | ||||
|         { | ||||
|             ...settings, | ||||
|             doneSetup: true | ||||
|         }, | ||||
|         function (error) { | ||||
|             if (error) throw error; | ||||
|         } | ||||
|     ); | ||||
| } | ||||
| export async function getConfigUnsafe(object: string) { | ||||
|   try { | ||||
|     const userDataPath = app.getPath("userData"); | ||||
|     const storagePath = path.join(userDataPath, "/storage/"); | ||||
|     let rawdata = fs.readFileSync(storagePath + "settings.json", "utf-8"); | ||||
|     let returndata = JSON.parse(rawdata); | ||||
|     console.log(returndata[object]); | ||||
|     return returndata[object]; | ||||
|   } catch (e) { | ||||
|     console.log("Config probably doesn't exist yet. Returning setup value."); | ||||
|     firstRun = true; | ||||
|     return "setup"; | ||||
|   } | ||||
|     try { | ||||
|         const userDataPath = app.getPath("userData"); | ||||
|         const storagePath = path.join(userDataPath, "/storage/"); | ||||
|         let rawdata = fs.readFileSync(storagePath + "settings.json", "utf-8"); | ||||
|         let returndata = JSON.parse(rawdata); | ||||
|         console.log(returndata[object]); | ||||
|         return returndata[object]; | ||||
|     } catch (e) { | ||||
|         console.log("Config probably doesn't exist yet. Returning setup value."); | ||||
|         firstRun = true; | ||||
|         return "setup"; | ||||
|     } | ||||
| } | ||||
| export function getVersion() { | ||||
|   //to-do better way of doing this
 | ||||
|   return "3.1.0"; | ||||
|     //to-do better way of doing this
 | ||||
|     return "3.1.0"; | ||||
| } | ||||
| export async function injectJS(inject: string) { | ||||
|   const js = await (await fetch(`${inject}`)).text(); | ||||
|     const js = await (await fetch(`${inject}`)).text(); | ||||
| 
 | ||||
|   const el = document.createElement("script"); | ||||
|     const el = document.createElement("script"); | ||||
| 
 | ||||
|   el.appendChild(document.createTextNode(js)); | ||||
|     el.appendChild(document.createTextNode(js)); | ||||
| 
 | ||||
|   document.body.appendChild(el); | ||||
| } | ||||
|     document.body.appendChild(el); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										326
									
								
								src/window.ts
									
										
									
									
									
								
							
							
						
						
									
										326
									
								
								src/window.ts
									
										
									
									
									
								
							|  | @ -2,193 +2,185 @@ | |||
| // I had to add most of the window creation code here to split both into seperete functions
 | ||||
| // WHY? Because I can't use the same code for both due to annoying bug with value `frame` not responding to variables
 | ||||
| // I'm sorry for this mess but I'm not sure how to fix it.
 | ||||
| import { BrowserWindow, shell, app, ipcMain } from "electron"; | ||||
| import {BrowserWindow, shell, app, ipcMain} from "electron"; | ||||
| import path from "path"; | ||||
| import { contentPath } from "./main"; | ||||
| import { checkIfConfigIsNew, firstRun, getConfigUnsafe } from "./utils"; | ||||
| import { registerIpc } from "./ipc"; | ||||
| import {contentPath} from "./main"; | ||||
| import {checkIfConfigIsNew, firstRun, getConfigUnsafe} from "./utils"; | ||||
| import {registerIpc} from "./ipc"; | ||||
| import contextMenu from "electron-context-menu"; | ||||
| export let mainWindow: BrowserWindow; | ||||
| import * as glasstron from "glasstron"; | ||||
| 
 | ||||
| let guestWindows: BrowserWindow [] = []; | ||||
| let guestWindows: BrowserWindow[] = []; | ||||
| contextMenu({ | ||||
|   showSaveImageAs: true, | ||||
|   showCopyImageAddress: true, | ||||
|   showSearchWithGoogle: true, | ||||
| 
 | ||||
|     showSaveImageAs: true, | ||||
|     showCopyImageAddress: true, | ||||
|     showSearchWithGoogle: true | ||||
| }); | ||||
| 
 | ||||
| function doAfterDefiningTheWindow() { | ||||
|   checkIfConfigIsNew(); | ||||
|   registerIpc(); | ||||
|   mainWindow.webContents.userAgent = | ||||
|     "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36"; //fake useragent for screenshare to work
 | ||||
|   mainWindow.webContents.setWindowOpenHandler(({ url }) => { | ||||
|     shell.openExternal(url); | ||||
|     return { action: "deny" }; | ||||
|   }); | ||||
|   mainWindow.webContents.session.webRequest.onBeforeRequest( | ||||
|     (details, callback) => { | ||||
|       if (/api\/v\d\/science$/g.test(details.url)) | ||||
|         return callback({ cancel: true }); | ||||
|       return callback({}); | ||||
|     checkIfConfigIsNew(); | ||||
|     registerIpc(); | ||||
|     mainWindow.webContents.userAgent = | ||||
|         "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36"; //fake useragent for screenshare to work
 | ||||
|     mainWindow.webContents.setWindowOpenHandler(({url}) => { | ||||
|         shell.openExternal(url); | ||||
|         return {action: "deny"}; | ||||
|     }); | ||||
|     mainWindow.webContents.session.webRequest.onBeforeRequest((details, callback) => { | ||||
|         if (/api\/v\d\/science$/g.test(details.url)) return callback({cancel: true}); | ||||
|         return callback({}); | ||||
|     }); | ||||
|     mainWindow.on("close", async (e) => { | ||||
|         if (await getConfigUnsafe("minimizeToTray")) { | ||||
|             e.preventDefault(); | ||||
|             mainWindow.hide(); | ||||
|         } else if (!(await getConfigUnsafe("minimizeToTray"))) { | ||||
|             e.preventDefault(); | ||||
|             app.exit(); | ||||
|             app.quit(); | ||||
|         } | ||||
|     }); | ||||
|     console.log(contentPath); | ||||
|     try { | ||||
|         mainWindow.loadFile(contentPath); | ||||
|     } catch (e) { | ||||
|         console.log( | ||||
|             "Major error detected while starting up. User is most likely on Windows platform. Fallback to alternative startup." | ||||
|         ); | ||||
|         console.log(process.platform); | ||||
|         if (process.platform === "win32") { | ||||
|             if (firstRun) { | ||||
|                 mainWindow.loadURL(`file://${__dirname}/content/setup.html`); | ||||
|             } else { | ||||
|                 mainWindow.loadURL(`file://${__dirname}/content/splash.html`); | ||||
|             } | ||||
|         } else { | ||||
|             if (firstRun) { | ||||
|                 mainWindow.loadURL(`file://${__dirname}/ts-out/content/setup.html`); | ||||
|             } else { | ||||
|                 mainWindow.loadURL(`file://${__dirname}/ts-out/content/splash.html`); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   ); | ||||
|   mainWindow.on("close", async (e) => { | ||||
|     if (await getConfigUnsafe("minimizeToTray")) { | ||||
|       e.preventDefault(); | ||||
|       mainWindow.hide(); | ||||
|     } else if (!await getConfigUnsafe("minimizeToTray")) { | ||||
|       e.preventDefault(); | ||||
|       app.exit(); | ||||
|       app.quit() | ||||
|     } | ||||
|   }); | ||||
|   console.log(contentPath); | ||||
|   try { | ||||
|     mainWindow.loadFile(contentPath); | ||||
|   } catch (e) { | ||||
|     console.log( | ||||
|       "Major error detected while starting up. User is most likely on Windows platform. Fallback to alternative startup." | ||||
|     ); | ||||
|     console.log(process.platform); | ||||
|     if (process.platform === "win32") { | ||||
|       if (firstRun) { | ||||
|         mainWindow.loadURL(`file://${__dirname}/content/setup.html`); | ||||
|       } else { | ||||
|         mainWindow.loadURL(`file://${__dirname}/content/splash.html`); | ||||
|       } | ||||
|     } else { | ||||
|       if (firstRun) { | ||||
|         mainWindow.loadURL(`file://${__dirname}/ts-out/content/setup.html`); | ||||
|       } else { | ||||
|         mainWindow.loadURL(`file://${__dirname}/ts-out/content/splash.html`); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| export function createCustomWindow() { | ||||
|   mainWindow = new BrowserWindow({ | ||||
|     width: 300, | ||||
|     height: 350, | ||||
|     title: "ArmCord", | ||||
|     darkTheme: true, | ||||
|     icon: path.join(__dirname, "/assets/icon_transparent.png"), | ||||
|     frame: false, | ||||
|     autoHideMenuBar: true, | ||||
|     webPreferences: { | ||||
|       preload: path.join(__dirname, "preload/preload.js"), | ||||
|       spellcheck: true, | ||||
|     }, | ||||
|   }); | ||||
|   doAfterDefiningTheWindow(); | ||||
|     mainWindow = new BrowserWindow({ | ||||
|         width: 300, | ||||
|         height: 350, | ||||
|         title: "ArmCord", | ||||
|         darkTheme: true, | ||||
|         icon: path.join(__dirname, "/assets/icon_transparent.png"), | ||||
|         frame: false, | ||||
|         autoHideMenuBar: true, | ||||
|         webPreferences: { | ||||
|             preload: path.join(__dirname, "preload/preload.js"), | ||||
|             spellcheck: true | ||||
|         } | ||||
|     }); | ||||
|     doAfterDefiningTheWindow(); | ||||
| } | ||||
| export function createNativeWindow() { | ||||
|   mainWindow = new BrowserWindow({ | ||||
|     width: 300, | ||||
|     height: 350, | ||||
|     title: "ArmCord", | ||||
|     darkTheme: true, | ||||
|     icon: path.join(__dirname, "/assets/icon_transparent.png"), | ||||
|     frame: true, | ||||
|     autoHideMenuBar: true, | ||||
|     webPreferences: { | ||||
|       preload: path.join(__dirname, "preload/preload.js"), | ||||
|       spellcheck: true, | ||||
|     }, | ||||
|   }); | ||||
|   doAfterDefiningTheWindow(); | ||||
|     mainWindow = new BrowserWindow({ | ||||
|         width: 300, | ||||
|         height: 350, | ||||
|         title: "ArmCord", | ||||
|         darkTheme: true, | ||||
|         icon: path.join(__dirname, "/assets/icon_transparent.png"), | ||||
|         frame: true, | ||||
|         autoHideMenuBar: true, | ||||
|         webPreferences: { | ||||
|             preload: path.join(__dirname, "preload/preload.js"), | ||||
|             spellcheck: true | ||||
|         } | ||||
|     }); | ||||
|     doAfterDefiningTheWindow(); | ||||
| } | ||||
| export function createGlasstronWindow() { | ||||
|   mainWindow = new glasstron.BrowserWindow({ | ||||
|     width: 300, | ||||
|     height: 350, | ||||
|     title: "ArmCord", | ||||
|     darkTheme: true, | ||||
|     icon: path.join(__dirname, "/assets/icon_transparent.png"), | ||||
|     frame: true, | ||||
|     autoHideMenuBar: true, | ||||
|     webPreferences: { | ||||
|       preload: path.join(__dirname, "preload/preload.js"), | ||||
|       spellcheck: true, | ||||
|     }, | ||||
|   }); | ||||
|     mainWindow = new glasstron.BrowserWindow({ | ||||
|         width: 300, | ||||
|         height: 350, | ||||
|         title: "ArmCord", | ||||
|         darkTheme: true, | ||||
|         icon: path.join(__dirname, "/assets/icon_transparent.png"), | ||||
|         frame: true, | ||||
|         autoHideMenuBar: true, | ||||
|         webPreferences: { | ||||
|             preload: path.join(__dirname, "preload/preload.js"), | ||||
|             spellcheck: true | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
|   //@ts-expect-error
 | ||||
|   mainWindow.blurType = getConfigUnsafe("blurType"); | ||||
|   //@ts-expect-error
 | ||||
|   mainWindow.setBlur(true); | ||||
|   doAfterDefiningTheWindow(); | ||||
|     //@ts-expect-error
 | ||||
|     mainWindow.blurType = getConfigUnsafe("blurType"); | ||||
|     //@ts-expect-error
 | ||||
|     mainWindow.setBlur(true); | ||||
|     doAfterDefiningTheWindow(); | ||||
| } | ||||
| export function createTabsHost() { | ||||
|   guestWindows[1] = mainWindow; | ||||
|   mainWindow = new BrowserWindow({ | ||||
|     width: 300, | ||||
|     height: 350, | ||||
|     title: "ArmCord", | ||||
|     darkTheme: true, | ||||
|     icon: path.join(__dirname, "/assets/icon_transparent.png"), | ||||
|     frame: true, | ||||
|     autoHideMenuBar: true, | ||||
|     webPreferences: { | ||||
|       preload: path.join(__dirname, "preload/preload.js"), | ||||
|     }, | ||||
|   }); | ||||
|   doAfterDefiningTheWindow(); | ||||
|     guestWindows[1] = mainWindow; | ||||
|     mainWindow = new BrowserWindow({ | ||||
|         width: 300, | ||||
|         height: 350, | ||||
|         title: "ArmCord", | ||||
|         darkTheme: true, | ||||
|         icon: path.join(__dirname, "/assets/icon_transparent.png"), | ||||
|         frame: true, | ||||
|         autoHideMenuBar: true, | ||||
|         webPreferences: { | ||||
|             preload: path.join(__dirname, "preload/preload.js") | ||||
|         } | ||||
|     }); | ||||
|     doAfterDefiningTheWindow(); | ||||
| } | ||||
| export function createTabsGuest(number: number) { | ||||
|   console.log(guestWindows) | ||||
|   if (guestWindows[number] !== undefined || null) { | ||||
|   try { | ||||
|       console.log("Showing Guest Window " + number); | ||||
|       mainWindow.hide() | ||||
|       guestWindows[number].show(); | ||||
|       mainWindow = guestWindows[number]; | ||||
|     } catch (e) { | ||||
|       console.error(e); | ||||
|     } | ||||
|   } else { | ||||
|   console.log("Creating Guest Window " + number); | ||||
|   mainWindow.hide(); | ||||
|     console.log(guestWindows); | ||||
|     if (guestWindows[number] !== undefined || null) { | ||||
|         try { | ||||
|             console.log("Showing Guest Window " + number); | ||||
|             mainWindow.hide(); | ||||
|             guestWindows[number].show(); | ||||
|             mainWindow = guestWindows[number]; | ||||
|         } catch (e) { | ||||
|             console.error(e); | ||||
|         } | ||||
|     } else { | ||||
|         console.log("Creating Guest Window " + number); | ||||
|         mainWindow.hide(); | ||||
| 
 | ||||
|   guestWindows[number] = new BrowserWindow({ | ||||
|     width: 800, | ||||
|     height: 600, | ||||
|     title: "ArmCord Guest Window " + number, | ||||
|     darkTheme: true, | ||||
|     icon: path.join(__dirname, "/assets/icon_transparent.png"), | ||||
|     frame: true, | ||||
|     autoHideMenuBar: true, | ||||
|     webPreferences: { | ||||
|       preload: path.join(__dirname, "preload/preload.js"), | ||||
|     }, | ||||
|   }); | ||||
|    | ||||
|   mainWindow = guestWindows[number]; | ||||
|   ipcMain.on("tab" + number, (event) => { | ||||
|     event.returnValue = true; //return true so we know the tab exists
 | ||||
|   }); | ||||
|    | ||||
|   guestWindows[number].webContents.userAgent = | ||||
|     "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36"; //fake useragent for screenshare to work
 | ||||
|    | ||||
|   guestWindows[number].webContents.setWindowOpenHandler(({ url }) => { | ||||
|     shell.openExternal(url); | ||||
|     return { action: "deny" }; | ||||
|   }); | ||||
|    | ||||
|   guestWindows[number].webContents.session.webRequest.onBeforeRequest( | ||||
|     ( | ||||
|       details: { url: string }, | ||||
|       callback: (arg0: { cancel?: boolean }) => any | ||||
|     ) => { | ||||
|       if (/api\/v\d\/science$/g.test(details.url)) | ||||
|         return callback({ cancel: true }); | ||||
|       return callback({}); | ||||
|         guestWindows[number] = new BrowserWindow({ | ||||
|             width: 800, | ||||
|             height: 600, | ||||
|             title: "ArmCord Guest Window " + number, | ||||
|             darkTheme: true, | ||||
|             icon: path.join(__dirname, "/assets/icon_transparent.png"), | ||||
|             frame: true, | ||||
|             autoHideMenuBar: true, | ||||
|             webPreferences: { | ||||
|                 preload: path.join(__dirname, "preload/preload.js") | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         mainWindow = guestWindows[number]; | ||||
|         ipcMain.on("tab" + number, (event) => { | ||||
|             event.returnValue = true; //return true so we know the tab exists
 | ||||
|         }); | ||||
| 
 | ||||
|         guestWindows[number].webContents.userAgent = | ||||
|             "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36"; //fake useragent for screenshare to work
 | ||||
| 
 | ||||
|         guestWindows[number].webContents.setWindowOpenHandler(({url}) => { | ||||
|             shell.openExternal(url); | ||||
|             return {action: "deny"}; | ||||
|         }); | ||||
| 
 | ||||
|         guestWindows[number].webContents.session.webRequest.onBeforeRequest( | ||||
|             (details: {url: string}, callback: (arg0: {cancel?: boolean}) => any) => { | ||||
|                 if (/api\/v\d\/science$/g.test(details.url)) return callback({cancel: true}); | ||||
|                 return callback({}); | ||||
|             } | ||||
|         ); | ||||
| 
 | ||||
|         guestWindows[number].loadURL("https://discord.com/app"); | ||||
|     } | ||||
|   ); | ||||
|    | ||||
|   guestWindows[number].loadURL("https://discord.com/app"); | ||||
|   } | ||||
| } | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue