[feature] Allow users to set custom css for their profiles + threads (#808)

* add custom css account property + db func to fetch

* allow account to get/set custom css

* serve custom css for an account

* go fmt

* use monospace for customcss, add link

* add custom css to account cache

* fix broken field

* add custom css docs to user guide

* add `accounts-allow-custom-css` config flag

* add allow custom css to /api/v1/instance response

* only show/set custom css if allowed to do so

* only set/serve custom account css if enabled

* update swagger docs

* chain promise

* make bool a bit clearer

* use cache for GetAccountCustomCSSByUsername
This commit is contained in:
tobi
2022-09-12 13:14:29 +02:00
committed by GitHub
parent 268f252e0d
commit b42469e4e0
40 changed files with 458 additions and 39 deletions

View File

@ -61,3 +61,7 @@ input, select, textarea {
rgb(70, 79, 88) 20px
) !important;
}
.mono {
font-family: monospace;
}

View File

@ -23,7 +23,7 @@ const Promise = require("bluebird");
const Submit = require("../../lib/submit");
module.exports = function Basic({oauth, account}) {
module.exports = function Basic({oauth, account, allowCustomCSS}) {
const [errorMsg, setError] = React.useState("");
const [statusMsg, setStatus] = React.useState("");
@ -36,6 +36,7 @@ module.exports = function Basic({oauth, account}) {
const [displayName, setDisplayName] = React.useState("");
const [bio, setBio] = React.useState("");
const [locked, setLocked] = React.useState(false);
const [customCSS, setCustomCSS] = React.useState("");
React.useEffect(() => {
setHeaderSrc(account.header);
@ -44,7 +45,8 @@ module.exports = function Basic({oauth, account}) {
setDisplayName(account.display_name);
setBio(account.source ? account.source.note : "");
setLocked(account.locked);
}, [account, setHeaderSrc, setAvatarSrc, setDisplayName, setBio, setLocked]);
setCustomCSS((allowCustomCSS && account.custom_css) ? account.custom_css : "");
}, [account, setHeaderSrc, setAvatarSrc, setDisplayName, setBio, setLocked, setCustomCSS]);
const headerOnChange = (e) => {
setHeaderFile(e.target.files[0]);
@ -75,7 +77,11 @@ module.exports = function Basic({oauth, account}) {
formDataInfo.set("display_name", displayName);
formDataInfo.set("note", bio);
formDataInfo.set("locked", locked);
if (allowCustomCSS) {
formDataInfo.set("custom_css", customCSS);
}
return oauth.apiRequest("/api/v1/accounts/update_credentials", "PATCH", formDataInfo, "form");
}).then((json) => {
setStatus("Saved!");
@ -86,6 +92,7 @@ module.exports = function Basic({oauth, account}) {
setDisplayName(json.display_name);
setBio(json.source.note);
setLocked(json.locked);
setCustomCSS(allowCustomCSS && json.custom_css ? json.custom_css : "");
}).catch((e) => {
setError(e.message);
setStatus("");
@ -126,6 +133,13 @@ module.exports = function Basic({oauth, account}) {
<label htmlFor="bio">Bio</label>
<textarea id="bio" value={bio} onChange={(e) => setBio(e.target.value)} placeholder="Just trying out GoToSocial, my pronouns are they/them and I like sloths."/>
</div>
{ !allowCustomCSS ? null :
<div className="labelinput">
<label htmlFor="customcss">Custom CSS</label>
<textarea className="mono" id="customcss" value={customCSS} onChange={(e) => setCustomCSS(e.target.value)}/>
<a href="https://docs.gotosocial.org/en/latest/user_guide/custom_css" target="_blank" className="moreinfolink" rel="noreferrer">Learn more about custom CSS (opens in a new tab)</a>
</div>
}
<div className="labelcheckbox">
<label htmlFor="locked">Manually approve follow requests</label>
<input id="locked" type="checkbox" checked={locked} onChange={(e) => setLocked(e.target.checked)}/>

View File

@ -33,26 +33,40 @@ require("./style.css");
function UserPanel({oauth}) {
const [account, setAccount] = React.useState({});
const [allowCustomCSS, setAllowCustomCSS] = React.useState(false);
const [errorMsg, setError] = React.useState("");
const [statusMsg, setStatus] = React.useState("Fetching user info");
React.useEffect(() => {
}, [oauth, setAllowCustomCSS, setError, setStatus]);
React.useEffect(() => {
Promise.try(() => {
return oauth.apiRequest("/api/v1/accounts/verify_credentials", "GET");
return oauth.apiRequest("/api/v1/instance", "GET");
}).then((json) => {
setAccount(json);
setAllowCustomCSS(json.configuration.accounts.allow_custom_css);
Promise.try(() => {
return oauth.apiRequest("/api/v1/accounts/verify_credentials", "GET");
}).then((json) => {
setAccount(json);
}).catch((e) => {
setError(e.message);
setStatus("");
});
}).catch((e) => {
setError(e.message);
setStatus("");
});
}, [oauth, setAccount, setError, setStatus]);
}, [oauth, setAllowCustomCSS, setAccount, setError, setStatus]);
return (
<React.Fragment>
<div>
<button className="logout" onClick={oauth.logout}>Log out of settings panel</button>
</div>
<Basic oauth={oauth} account={account}/>
<Basic oauth={oauth} account={account} allowCustomCSS={allowCustomCSS}/>
<Posts oauth={oauth} account={account}/>
<Security oauth={oauth}/>
</React.Fragment>