开源软件名称(OpenSource Name):kofigumbs/multi开源软件地址(OpenSource Url):https://github.com/kofigumbs/multi开源编程语言(OpenSource Language):Swift 72.0%开源软件介绍(OpenSource Introduction):MultiCreate a custom, lightweight macOS app from a group of websites, complete with:
Watch me create a Slack clone from scratch in 30 seconds (high res video): Table of contents
I've also written a few blog posts that discuss some of the decisions behind Multi:
InstallationThe easiest method is to use Homebrew:
Alternatively, you can manually download and run the latest JSON configurationMulti apps store their configuration in a single JSON file.
If your app is named
The
Here's the bare minimum example used in the Slack demo video above: { "tabs": [{ "title": "Slack Lite", "url": "https://app.slack.com/client" }] } Here's a fancier example that uses the optional fields referenced above: {
"tabs": [
{
"title": "Dancing",
"url": "https://rc.kofi.sexy/bathroom-floss",
"basicAuthUser": "user",
"basicAuthPassword": "password",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.6 Safari/605.1.15"
},
{
"title": "Walking",
"url": "https://kofi.sexy/cel-shading",
"customJs": [ "https://raw.githubusercontent.com/kofigumbs/multi/2.x/Assets/test.js" ],
"customCss": [ "https://raw.githubusercontent.com/kofigumbs/multi/2.x/Assets/test.css" ]
}
],
"windowed": true,
"alwaysNotify": true,
"openNewWindowsWith": "com.apple.Safari",
"openNewWindowsInBackground": true
} If your configuration file fails to decode for any reason, your Multi app will open to the preferences window, where you can fix any issues. User-agent tipBefore v2.2.0, Multi included a hard-coded user-agent that made it appear like Safari. This behavior caused subtle issues and confusion when the hard-coded user-agent didn't reflect the system WebKit version. Recent Multi versions remove the hard-coded user-agent, but now sites like Slack and WhatsApp complain that your browser is out of date. (Ideally these sites would use feature detection instead of user-agent sniffing to gracefully degrade behavior; alas, the world does not work ideally.) If your site doesn't work because it thinks you're using an outdated browser, try setting the
Using the CLI: |
MULTI_ICON_PATH |
PNG or ICNS path to icon image |
MULTI_JSON_CONFIG |
See JSON configuration |
MULTI_OVERWRITE |
Set to 1 to replace an existing Multi app with the same name |
Multi lets you customize any site by injecting JavaScript and CSS on every page in your app. Each custom JS/CSS file is specified with a URL, which gives you a few options for how you want to manage your customizations:
https://raw.githubusercontent.com/kofigumbs/dotfiles/master/example.js
file:///Users/kofi/workspace/dotfiles/example.js
data:,console.log%28%27Hello%2C%20from%20Multi%21%27%29%3B%0A
Custom JS/CSS is one of the most important parts of Multi. It lets the main project stay small and focused, while letting you extend it with new features that fit your use case. If you have a neat JS/CSS snippet, you'd like to share, please open an Issue or Pull Request! Here are a few that have come up before:
Google seems to be doing some trickery here. Instead of allowing the browser to handle the links, they use JS to open a blank popup window, then dynamically set the URL to google.com/url?q=REAL_URL_HERE. Presumably all of this is so that they can track you for a few moments on your way out of their app. Custom JS solution:
(() => {
const listener = e => e.stopPropagation();
const query = () => document.querySelectorAll('a[target=_blank]').forEach(a => {
a.removeEventListener('click', listener);
a.addEventListener('click', listener, true);
});
query();
setInterval(query, 400); // wait time between DOM queries, in milliseconds
})();
Sometimes Slack's WebSocket disconnects and stops loading new messages. It seems like this is either an issue with WebKit or Slack.com. Custom JS solution:
setInterval(() => {
if (document.body.innerText.includes('Load new messages.'))
window.location.reload();
}, 90000);
Multi doesn't include any search functionality (Cmd-F). Custom JS solution:
(() => {
const highlightResults = (text, color) => {
document.designMode = "on"; // https://stackoverflow.com/a/5887719
var selection = window.getSelection();
selection.collapse(document.body, 0);
while (window.find(text)) {
document.execCommand("HiliteColor", false, color);
selection.collapseToEnd();
}
document.designMode = "off";
};
let mostRecentSearchText = "";
const search = text => {
highlightResults(mostRecentSearchText, "transparent");
highlightResults(text, "rgb(255 255 1 / 50%)");
mostRecentSearchText = text;
};
const input = document.createElement("input");
input.placeholder = "Search...";
input.style.padding = "10px 15px";
input.style.fontSize = "15px";
input.style.borderRadius = "3px";
input.style.border = "solid 1px lightgray";
const form = document.createElement("form");
form.style.display = "none";
form.style.position = "fixed";
form.style.top = "15px";
form.style.right = "15px";
form.style.zIndex = "2147483647"; // https://stackoverflow.com/a/856569
form.addEventListener("submit", e => {
e.preventDefault();
search(input.value);
});
const close = document.createElement("a");
close.innerText = "⨯";
close.href = "javascript:void(0)";
close.style.fontSize = "30px";
close.style.padding = "15px";
close.style.textDecoration = "none";
close.addEventListener("click", e => {
e.preventDefault();
search("");
form.style.display = "none";
});
form.appendChild(input);
form.appendChild(close);
document.body.appendChild(form);
document.addEventListener("keydown", event => {
if (event.metaKey && event.key === "f") {
event.preventDefault();
form.style.display = "block";
input.focus();
}
});
})();
Sometimes you have a URL outside of Multi (maybe in an email), and you want to open it in Multi. Custom JS solution:
document.addEventListener("dragover", e => e.preventDefault());
Multi doesn't include any hover-to-preview-link-target functionality. Custom CSS solution:
a:hover::after {
content: attr(href);
position: fixed;
left: 4px;
bottom: 4px;
padding: 4px;
font-size: 12px;
font-family: -apple-system, BlinkMacSystemFont;
font-weight: normal;
color: black;
background: ghostwhite;
border: solid 1px black;
border-radius: 1px;
}
Multi's shortcuts should basically match those of other macOS apps:
⌘X |
Cut | ⌘[ |
Back | |
⌘C |
Copy | ⌘] |
Forward | |
⌘V |
Paste | ⌘R |
Reload This Page | |
⌘↑V |
Paste and Match Style | ⌘+ /⌘- /⌘0 |
Zoom in/out/default | |
⌘A |
Select All | ^Tab |
Select Next Tab | |
⌘M |
Minimize | ^↑Tab |
Select Previous Tab | |
⌘H |
Hide | ⌘1 - ⌘9 |
Select Tab | |
⌘W |
Close Tab | ⌘L |
Copy current URL | |
⌘Q |
Quit | ⌘↑T |
Toggle Tab Bar | |
⌘↑\ |
Toggle Tab Overview |
As of Multi 2.1.4, Multi is free (as in beer).
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论