Merge branch 'master' into federation
This commit is contained in:
commit
e823f55495
17 changed files with 143 additions and 78 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -14,4 +14,4 @@ build/
|
|||
ui/src/translations
|
||||
|
||||
# ide config
|
||||
.idea/
|
||||
.idea/
|
||||
|
|
4
ansible/templates/docker-compose.yml
vendored
4
ansible/templates/docker-compose.yml
vendored
|
@ -6,6 +6,8 @@ services:
|
|||
ports:
|
||||
- "127.0.0.1:8536:8536"
|
||||
restart: always
|
||||
environment:
|
||||
- RUST_LOG=debug
|
||||
volumes:
|
||||
- ./lemmy.hjson:/config/config.hjson:ro
|
||||
depends_on:
|
||||
|
@ -43,4 +45,4 @@ services:
|
|||
image: mwader/postfix-relay
|
||||
environment:
|
||||
- POSTFIX_myhostname={{ domain }}
|
||||
restart: "always"
|
||||
restart: "always"
|
||||
|
|
2
docker/dev/docker-compose.yml
vendored
2
docker/dev/docker-compose.yml
vendored
|
@ -18,6 +18,8 @@ services:
|
|||
ports:
|
||||
- "127.0.0.1:8536:8536"
|
||||
restart: always
|
||||
environment:
|
||||
- RUST_LOG=debug
|
||||
volumes:
|
||||
- ../lemmy.hjson:/config/config.hjson:ro
|
||||
depends_on:
|
||||
|
|
2
docker/prod/docker-compose.yml
vendored
2
docker/prod/docker-compose.yml
vendored
|
@ -16,6 +16,8 @@ services:
|
|||
ports:
|
||||
- "127.0.0.1:8536:8536"
|
||||
restart: always
|
||||
environment:
|
||||
- RUST_LOG=debug
|
||||
volumes:
|
||||
- ./lemmy.hjson:/config/config.hjson:ro
|
||||
depends_on:
|
||||
|
|
1
docs/src/SUMMARY.md
vendored
1
docs/src/SUMMARY.md
vendored
|
@ -15,4 +15,5 @@
|
|||
- [Local Development](contributing_local_development.md)
|
||||
- [Websocket/HTTP API](contributing_websocket_http_api.md)
|
||||
- [ActivityPub API Outline](contributing_apub_api_outline.md)
|
||||
- [Theming Guide](contributing_theming.md)
|
||||
- [Lemmy Council](lemmy_council.md)
|
||||
|
|
18
docs/src/contributing_theming.md
vendored
Normal file
18
docs/src/contributing_theming.md
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Theming Guide
|
||||
|
||||
Lemmy uses [Bootstrap v4](https://getbootstrap.com/), and very few custom css classes, so any bootstrap v4 compatible theme should work fine.
|
||||
|
||||
## Creating
|
||||
|
||||
- Use a tool like [bootstrap.build](https://bootstrap.build/) to create a bootstrap v4 theme. Export the `bootstrap.min.css` once you're done, and save the `_variables.scss` too.
|
||||
|
||||
## Testing
|
||||
|
||||
- To test out a theme, you can either use your browser's web tools, or a plugin like stylus to copy-paste a theme, when viewing Lemmy.
|
||||
|
||||
## Adding
|
||||
|
||||
1. Copy `{my-theme-name}.min.css` to `ui/assets/css/themes`. (You can also copy the `_variables.scss` here if you want).
|
||||
1. Go to `ui/src/utils.ts` and add `{my-theme-name}` to the themes list.
|
||||
1. Test locally
|
||||
1. Do a pull request with those changes.
|
4
install.sh
vendored
4
install.sh
vendored
|
@ -16,7 +16,7 @@ init_db_final=0
|
|||
while [ "$init_db_valid" == 0 ]
|
||||
do
|
||||
read -p "Initialize database (y/n)? " init_db
|
||||
case "${init_db,,}" in
|
||||
case "${init_db,,}" in
|
||||
y|yes ) init_db_valid=1; init_db_final=1;;
|
||||
n|no ) init_db_valid=1; init_db_final=0;;
|
||||
* ) echo "Invalid input" 1>&2;;
|
||||
|
@ -37,7 +37,7 @@ yarn build
|
|||
|
||||
# Build and run the backend
|
||||
cd ../server
|
||||
cargo run
|
||||
RUST_LOG=debug cargo run
|
||||
|
||||
# For live coding, where both the front and back end, automagically reload on any save, do:
|
||||
# cd ui && yarn start
|
||||
|
|
|
@ -2,6 +2,7 @@ use super::*;
|
|||
use crate::send_email;
|
||||
use crate::settings::Settings;
|
||||
use diesel::PgConnection;
|
||||
use log::error;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
@ -128,7 +129,7 @@ impl Perform<CommentResponse> for Oper<CreateComment> {
|
|||
// Let the uniqueness handle this fail
|
||||
match UserMention::create(&conn, &user_mention_form) {
|
||||
Ok(_mention) => (),
|
||||
Err(_e) => eprintln!("{}", &_e),
|
||||
Err(_e) => error!("{}", &_e),
|
||||
};
|
||||
|
||||
// Send an email to those users that have notifications on
|
||||
|
@ -145,7 +146,7 @@ impl Perform<CommentResponse> for Oper<CreateComment> {
|
|||
);
|
||||
match send_email(subject, &mention_email, &mention_user.name, html) {
|
||||
Ok(_o) => _o,
|
||||
Err(e) => eprintln!("{}", e),
|
||||
Err(e) => error!("{}", e),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -174,7 +175,7 @@ impl Perform<CommentResponse> for Oper<CreateComment> {
|
|||
);
|
||||
match send_email(subject, &comment_reply_email, &parent_user.name, html) {
|
||||
Ok(_o) => _o,
|
||||
Err(e) => eprintln!("{}", e),
|
||||
Err(e) => error!("{}", e),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -199,7 +200,7 @@ impl Perform<CommentResponse> for Oper<CreateComment> {
|
|||
);
|
||||
match send_email(subject, &post_reply_email, &parent_user.name, html) {
|
||||
Ok(_o) => _o,
|
||||
Err(e) => eprintln!("{}", e),
|
||||
Err(e) => error!("{}", e),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -318,7 +319,7 @@ impl Perform<CommentResponse> for Oper<EditComment> {
|
|||
// Let the uniqueness handle this fail
|
||||
match UserMention::create(&conn, &user_mention_form) {
|
||||
Ok(_mention) => (),
|
||||
Err(_e) => eprintln!("{}", &_e),
|
||||
Err(_e) => error!("{}", &_e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use crate::settings::Settings;
|
|||
use crate::{generate_random_string, send_email};
|
||||
use bcrypt::verify;
|
||||
use diesel::PgConnection;
|
||||
use log::error;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
@ -1008,7 +1009,7 @@ impl Perform<PrivateMessageResponse> for Oper<CreatePrivateMessage> {
|
|||
);
|
||||
match send_email(subject, &email, &recipient_user.name, html) {
|
||||
Ok(_o) => _o,
|
||||
Err(e) => eprintln!("{}", e),
|
||||
Err(e) => error!("{}", e),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ use lettre::smtp::extension::ClientId;
|
|||
use lettre::smtp::ConnectionReuseParameters;
|
||||
use lettre::{ClientSecurity, SmtpClient, Transport};
|
||||
use lettre_email::Email;
|
||||
use log::error;
|
||||
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
|
||||
use rand::distributions::Alphanumeric;
|
||||
use rand::{thread_rng, Rng};
|
||||
|
@ -192,7 +193,7 @@ fn fetch_iframely_and_pictshare_data(
|
|||
Some(url) => match fetch_iframely(&url) {
|
||||
Ok(res) => (res.title, res.description, res.thumbnail_url, res.html),
|
||||
Err(e) => {
|
||||
eprintln!("iframely err: {}", e);
|
||||
error!("iframely err: {}", e);
|
||||
(None, None, None, None)
|
||||
}
|
||||
},
|
||||
|
@ -204,7 +205,7 @@ fn fetch_iframely_and_pictshare_data(
|
|||
Some(iframely_thumbnail_url) => match fetch_pictshare(&iframely_thumbnail_url) {
|
||||
Ok(res) => Some(res.url),
|
||||
Err(e) => {
|
||||
eprintln!("pictshare err: {}", e);
|
||||
error!("pictshare err: {}", e);
|
||||
None
|
||||
}
|
||||
},
|
||||
|
|
|
@ -3,6 +3,7 @@ use actix::prelude::*;
|
|||
use actix_web::web;
|
||||
use actix_web::*;
|
||||
use actix_web_actors::ws;
|
||||
use log::{error, info};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
|
@ -99,7 +100,6 @@ impl Handler<WSMessage> for WSSession {
|
|||
type Result = ();
|
||||
|
||||
fn handle(&mut self, msg: WSMessage, ctx: &mut Self::Context) {
|
||||
// println!("id: {} msg: {}", self.id, msg.0);
|
||||
ctx.text(msg.0);
|
||||
}
|
||||
}
|
||||
|
@ -107,11 +107,10 @@ impl Handler<WSMessage> for WSSession {
|
|||
/// WebSocket message handler
|
||||
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WSSession {
|
||||
fn handle(&mut self, result: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
|
||||
// println!("WEBSOCKET MESSAGE: {:?} from id: {}", msg, self.id);
|
||||
let message = match result {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
println!("{}", e);
|
||||
error!("{}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
@ -125,7 +124,7 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WSSession {
|
|||
}
|
||||
ws::Message::Text(text) => {
|
||||
let m = text.trim().to_owned();
|
||||
println!("WEBSOCKET MESSAGE: {:?} from id: {}", &m, self.id);
|
||||
info!("Message received: {:?} from id: {}", &m, self.id);
|
||||
|
||||
self
|
||||
.cs_addr
|
||||
|
@ -138,14 +137,14 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WSSession {
|
|||
match res {
|
||||
Ok(res) => ctx.text(res),
|
||||
Err(e) => {
|
||||
eprintln!("{}", &e);
|
||||
error!("{}", &e);
|
||||
}
|
||||
}
|
||||
actix::fut::ready(())
|
||||
})
|
||||
.wait(ctx);
|
||||
}
|
||||
ws::Message::Binary(_bin) => println!("Unexpected binary"),
|
||||
ws::Message::Binary(_bin) => info!("Unexpected binary"),
|
||||
ws::Message::Close(_) => {
|
||||
ctx.stop();
|
||||
}
|
||||
|
@ -163,7 +162,7 @@ impl WSSession {
|
|||
// check client heartbeats
|
||||
if Instant::now().duration_since(act.hb) > CLIENT_TIMEOUT {
|
||||
// heartbeat timed out
|
||||
println!("Websocket Client heartbeat failed, disconnecting!");
|
||||
error!("Websocket Client heartbeat failed, disconnecting!");
|
||||
|
||||
// notify chat server
|
||||
act.cs_addr.do_send(Disconnect {
|
||||
|
|
|
@ -6,6 +6,7 @@ use actix::prelude::*;
|
|||
use diesel::r2d2::{ConnectionManager, Pool, PooledConnection};
|
||||
use diesel::PgConnection;
|
||||
use failure::Error;
|
||||
use log::{error, info, warn};
|
||||
use rand::{rngs::ThreadRng, Rng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
@ -343,7 +344,7 @@ impl ChatServer {
|
|||
}
|
||||
|
||||
if rate_limit.allowance < 1.0 {
|
||||
println!(
|
||||
warn!(
|
||||
"Rate limited IP: {}, time_passed: {}, allowance: {}",
|
||||
&info.ip, time_passed, rate_limit.allowance
|
||||
);
|
||||
|
@ -387,7 +388,7 @@ impl Handler<Connect> for ChatServer {
|
|||
fn handle(&mut self, msg: Connect, _ctx: &mut Context<Self>) -> Self::Result {
|
||||
// register session with random id
|
||||
let id = self.rng.gen::<usize>();
|
||||
println!("{} joined", &msg.ip);
|
||||
info!("{} joined", &msg.ip);
|
||||
|
||||
self.sessions.insert(
|
||||
id,
|
||||
|
@ -448,13 +449,16 @@ impl Handler<StandardMessage> for ChatServer {
|
|||
type Result = MessageResult<StandardMessage>;
|
||||
|
||||
fn handle(&mut self, msg: StandardMessage, _: &mut Context<Self>) -> Self::Result {
|
||||
let msg_out = match parse_json_message(self, msg) {
|
||||
Ok(m) => m,
|
||||
Err(e) => e.to_string(),
|
||||
};
|
||||
|
||||
println!("Message Sent: {}", msg_out);
|
||||
MessageResult(msg_out)
|
||||
match parse_json_message(self, msg) {
|
||||
Ok(m) => {
|
||||
info!("Message Sent: {}", m);
|
||||
MessageResult(m)
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Error during message handling {}", e);
|
||||
MessageResult(e.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
22
ui/src/components/comment-node.tsx
vendored
22
ui/src/components/comment-node.tsx
vendored
|
@ -198,9 +198,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
<span
|
||||
className={`unselectable pointer ${this.scoreColor}`}
|
||||
onClick={linkEvent(node, this.handleCommentUpvote)}
|
||||
data-tippy-content={i18n.t('number_of_points', {
|
||||
count: this.state.score,
|
||||
})}
|
||||
data-tippy-content={this.pointsTippy}
|
||||
>
|
||||
<svg class="icon icon-inline mr-1">
|
||||
<use xlinkHref="#icon-zap"></use>
|
||||
|
@ -916,6 +914,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
|
||||
WebSocketService.Instance.likeComment(form);
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
}
|
||||
|
||||
handleCommentDownvote(i: CommentNodeI) {
|
||||
|
@ -943,6 +942,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
|
||||
WebSocketService.Instance.likeComment(form);
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
}
|
||||
|
||||
handleModRemoveShow(i: CommentNode) {
|
||||
|
@ -1166,4 +1166,20 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
return 'text-muted';
|
||||
}
|
||||
}
|
||||
|
||||
get pointsTippy(): string {
|
||||
let points = i18n.t('number_of_points', {
|
||||
count: this.state.score,
|
||||
});
|
||||
|
||||
let upvotes = i18n.t('number_of_upvotes', {
|
||||
count: this.state.upvotes,
|
||||
});
|
||||
|
||||
let downvotes = i18n.t('number_of_downvotes', {
|
||||
count: this.state.downvotes,
|
||||
});
|
||||
|
||||
return `${points} • ${upvotes} • ${downvotes}`;
|
||||
}
|
||||
}
|
||||
|
|
26
ui/src/components/post-listing.tsx
vendored
26
ui/src/components/post-listing.tsx
vendored
|
@ -262,9 +262,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
</button>
|
||||
<div
|
||||
class={`unselectable pointer font-weight-bold text-muted px-1`}
|
||||
data-tippy-content={i18n.t('number_of_points', {
|
||||
count: this.state.score,
|
||||
})}
|
||||
data-tippy-content={this.pointsTippy}
|
||||
>
|
||||
{this.state.score}
|
||||
</div>
|
||||
|
@ -466,9 +464,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
<>
|
||||
<span
|
||||
class="unselectable pointer mr-2"
|
||||
data-tippy-content={i18n.t('number_of_points', {
|
||||
count: this.state.score,
|
||||
})}
|
||||
data-tippy-content={this.pointsTippy}
|
||||
>
|
||||
<li className="list-inline-item">
|
||||
<span className="text-muted">
|
||||
|
@ -1022,6 +1018,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
|
||||
WebSocketService.Instance.likePost(form);
|
||||
i.setState(i.state);
|
||||
setupTippy();
|
||||
}
|
||||
|
||||
handlePostDisLike(i: PostListing) {
|
||||
|
@ -1048,6 +1045,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
|
||||
WebSocketService.Instance.likePost(form);
|
||||
i.setState(i.state);
|
||||
setupTippy();
|
||||
}
|
||||
|
||||
handleEditClick(i: PostListing) {
|
||||
|
@ -1291,4 +1289,20 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
i.setState(i.state);
|
||||
setupTippy();
|
||||
}
|
||||
|
||||
get pointsTippy(): string {
|
||||
let points = i18n.t('number_of_points', {
|
||||
count: this.state.score,
|
||||
});
|
||||
|
||||
let upvotes = i18n.t('number_of_upvotes', {
|
||||
count: this.state.upvotes,
|
||||
});
|
||||
|
||||
let downvotes = i18n.t('number_of_downvotes', {
|
||||
count: this.state.downvotes,
|
||||
});
|
||||
|
||||
return `${points} • ${upvotes} • ${downvotes}`;
|
||||
}
|
||||
}
|
||||
|
|
76
ui/src/utils.ts
vendored
76
ui/src/utils.ts
vendored
|
@ -16,7 +16,7 @@ import 'moment/locale/ja';
|
|||
import {
|
||||
UserOperation,
|
||||
Comment,
|
||||
CommentNode,
|
||||
CommentNode as CommentNodeI,
|
||||
Post,
|
||||
PrivateMessage,
|
||||
User,
|
||||
|
@ -53,6 +53,39 @@ export const postRefetchSeconds: number = 60 * 1000;
|
|||
export const fetchLimit: number = 20;
|
||||
export const mentionDropdownFetchLimit = 10;
|
||||
|
||||
export const languages = [
|
||||
{ code: 'ca', name: 'Català' },
|
||||
{ code: 'en', name: 'English' },
|
||||
{ code: 'eo', name: 'Esperanto' },
|
||||
{ code: 'es', name: 'Español' },
|
||||
{ code: 'de', name: 'Deutsch' },
|
||||
{ code: 'fa', name: 'فارسی' },
|
||||
{ code: 'ja', name: '日本語' },
|
||||
{ code: 'pt_BR', name: 'Português Brasileiro' },
|
||||
{ code: 'zh', name: '中文' },
|
||||
{ code: 'fi', name: 'Suomi' },
|
||||
{ code: 'fr', name: 'Français' },
|
||||
{ code: 'sv', name: 'Svenska' },
|
||||
{ code: 'ru', name: 'Русский' },
|
||||
{ code: 'nl', name: 'Nederlands' },
|
||||
{ code: 'it', name: 'Italiano' },
|
||||
];
|
||||
|
||||
export const themes = [
|
||||
'litera',
|
||||
'materia',
|
||||
'minty',
|
||||
'solar',
|
||||
'united',
|
||||
'cyborg',
|
||||
'darkly',
|
||||
'journal',
|
||||
'sketchy',
|
||||
'vaporwave',
|
||||
'vaporwave-dark',
|
||||
'i386',
|
||||
];
|
||||
|
||||
export function randomStr() {
|
||||
return Math.random()
|
||||
.toString(36)
|
||||
|
@ -275,24 +308,6 @@ export function debounce(
|
|||
};
|
||||
}
|
||||
|
||||
export const languages = [
|
||||
{ code: 'ca', name: 'Català' },
|
||||
{ code: 'en', name: 'English' },
|
||||
{ code: 'eo', name: 'Esperanto' },
|
||||
{ code: 'es', name: 'Español' },
|
||||
{ code: 'de', name: 'Deutsch' },
|
||||
{ code: 'fa', name: 'فارسی' },
|
||||
{ code: 'ja', name: '日本語' },
|
||||
{ code: 'pt_BR', name: 'Português Brasileiro' },
|
||||
{ code: 'zh', name: '中文' },
|
||||
{ code: 'fi', name: 'Suomi' },
|
||||
{ code: 'fr', name: 'Français' },
|
||||
{ code: 'sv', name: 'Svenska' },
|
||||
{ code: 'ru', name: 'Русский' },
|
||||
{ code: 'nl', name: 'Nederlands' },
|
||||
{ code: 'it', name: 'Italiano' },
|
||||
];
|
||||
|
||||
export function getLanguage(): string {
|
||||
let user = UserService.Instance.user;
|
||||
let lang = user && user.lang ? user.lang : 'browser';
|
||||
|
@ -344,21 +359,6 @@ export function getMomentLanguage(): string {
|
|||
return lang;
|
||||
}
|
||||
|
||||
export const themes = [
|
||||
'litera',
|
||||
'materia',
|
||||
'minty',
|
||||
'solar',
|
||||
'united',
|
||||
'cyborg',
|
||||
'darkly',
|
||||
'journal',
|
||||
'sketchy',
|
||||
'vaporwave',
|
||||
'vaporwave-dark',
|
||||
'i386',
|
||||
];
|
||||
|
||||
export function setTheme(theme: string = 'darkly') {
|
||||
// unload all the other themes
|
||||
for (var i = 0; i < themes.length; i++) {
|
||||
|
@ -668,15 +668,15 @@ export function editPostRes(data: PostResponse, post: Post) {
|
|||
|
||||
export function commentsToFlatNodes(
|
||||
comments: Array<Comment>
|
||||
): Array<CommentNode> {
|
||||
let nodes: Array<CommentNode> = [];
|
||||
): Array<CommentNodeI> {
|
||||
let nodes: Array<CommentNodeI> = [];
|
||||
for (let comment of comments) {
|
||||
nodes.push({ comment: comment });
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export function commentSort(tree: Array<CommentNode>, sort: CommentSortType) {
|
||||
export function commentSort(tree: Array<CommentNodeI>, sort: CommentSortType) {
|
||||
// First, put removed and deleted comments at the bottom, then do your other sorts
|
||||
if (sort == CommentSortType.Top) {
|
||||
tree.sort(
|
||||
|
@ -716,7 +716,7 @@ export function commentSort(tree: Array<CommentNode>, sort: CommentSortType) {
|
|||
}
|
||||
}
|
||||
|
||||
export function commentSortSortType(tree: Array<CommentNode>, sort: SortType) {
|
||||
export function commentSortSortType(tree: Array<CommentNodeI>, sort: SortType) {
|
||||
commentSort(tree, convertCommentSortType(sort));
|
||||
}
|
||||
|
||||
|
|
4
ui/translations/en.json
vendored
4
ui/translations/en.json
vendored
|
@ -155,7 +155,11 @@
|
|||
"downvotes_disabled": "Downvotes disabled",
|
||||
"enable_downvotes": "Enable Downvotes",
|
||||
"upvote": "Upvote",
|
||||
"number_of_upvotes": "{{count}} Upvote",
|
||||
"number_of_upvotes_plural": "{{count}} Upvotes",
|
||||
"downvote": "Downvote",
|
||||
"number_of_downvotes": "{{count}} Downvote",
|
||||
"number_of_downvotes_plural": "{{count}} Downvotes",
|
||||
"open_registration": "Open Registration",
|
||||
"registration_closed": "Registration closed",
|
||||
"enable_nsfw": "Enable NSFW",
|
||||
|
|
6
ui/yarn.lock
vendored
6
ui/yarn.lock
vendored
|
@ -258,9 +258,9 @@ acorn-jsx@^5.1.0:
|
|||
integrity sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==
|
||||
|
||||
acorn@^5.0.3, acorn@^5.7.3:
|
||||
version "5.7.3"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
|
||||
integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
|
||||
version "5.7.4"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e"
|
||||
integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==
|
||||
|
||||
acorn@^7.1.0:
|
||||
version "7.1.0"
|
||||
|
|
Loading…
Reference in a new issue