Compare commits
667 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
3fa8512474 | ||
|
0e20de9f89 | ||
|
24d645b7d0 | ||
|
7b23f79d41 | ||
|
3b4095cf1b | ||
|
28cbfb9f10 | ||
|
189a06d2a2 | ||
|
450441fc11 | ||
|
b619362a36 | ||
|
425d02287a | ||
|
2e429c0c25 | ||
|
e0e12b0fee | ||
|
62ca37884a | ||
|
f9180823bc | ||
|
4b0c667c09 | ||
|
1b732cad61 | ||
|
ecef03bb15 | ||
|
9642601126 | ||
|
3836d293a1 | ||
|
0734e1fe33 | ||
|
44cb08297c | ||
|
bd21afb5ed | ||
|
ef80ad17b3 | ||
|
9ea4f37e78 | ||
|
c48772fd3f | ||
|
860e257a68 | ||
|
902d9e34b4 | ||
|
2d97c898f2 | ||
|
f6a93fc150 | ||
|
019f3377bb | ||
|
4b11675bdc | ||
|
2531c5953b | ||
|
c6db416ff7 | ||
|
b00cb2aed3 | ||
|
7c67cb5997 | ||
|
a098d08d12 | ||
|
6267759607 | ||
|
bc39ad37c4 | ||
|
a6ba004bf5 | ||
|
b89ab7e69d | ||
|
33d7338779 | ||
|
cf4fe6cab8 | ||
|
2241a15ee9 | ||
|
bca334cd28 | ||
|
3e3ec9b2c8 | ||
|
a8736aab7a | ||
|
71b266377c | ||
|
08dce5e607 | ||
|
2469fd1cdc | ||
|
531c1bb245 | ||
|
58f5040ee8 | ||
|
838f51770b | ||
|
c52090dbfe | ||
|
807c192fcf | ||
|
3b59f9c6c2 | ||
|
135bdd149e | ||
|
3572138b16 | ||
|
9f69aa3cb1 | ||
|
f5c3d20e9c | ||
|
1ec7c87001 | ||
|
8e4d1cba00 | ||
|
676ba50601 | ||
|
bbc3db8b20 | ||
|
f937cad68f | ||
|
be83d450eb | ||
|
1fd18a61bd | ||
|
5d9f479538 | ||
|
3ce9ca4c99 | ||
|
2ca1f0737a | ||
|
19ecde8fe7 | ||
|
7ee5fc5d68 | ||
|
4289ed1d13 | ||
|
256e3adc1d | ||
|
152b4d54e8 | ||
|
ea2ef16ea4 | ||
|
1d3e0a5060 | ||
|
bf575a1f5e | ||
|
860ffc0560 | ||
|
7eb4abe20a | ||
|
1baa75f79f | ||
|
1d436a4322 | ||
|
8fd174298d | ||
|
9afd7dadbf | ||
|
8e84177305 | ||
|
a28ce13b3e | ||
|
e1b42e9aa0 | ||
|
b51398d0dd | ||
|
ec34ec63b1 | ||
|
4a4733b397 | ||
|
bda7391221 | ||
|
b9e8ffbd12 | ||
|
7966d3a872 | ||
|
422e4d897b | ||
|
cb2707776f | ||
|
48e7a22e34 | ||
|
2bb5486357 | ||
|
60e2b951de | ||
|
a94c152fd3 | ||
|
9d04de1c8d | ||
|
73e4468ff3 | ||
|
fbbd80b40b | ||
|
361a606edb | ||
|
df92f010ad | ||
|
07af8c05fd | ||
|
aa662cecad | ||
|
84608c3ff8 | ||
|
b69365e397 | ||
|
a478af92c3 | ||
|
7fba4cb3d1 | ||
|
a4c757767f | ||
|
2af5cd96fe | ||
|
860f408475 | ||
|
440441ccb3 | ||
|
3eb13307ca | ||
|
756db8103a | ||
|
20c0054460 | ||
|
ae78d012ac | ||
|
ef900789bc | ||
|
d78f555254 | ||
|
c2f70829d9 | ||
|
b280c387c8 | ||
|
b75f13927e | ||
|
22cb286ad7 | ||
|
8f4b7c1820 | ||
|
2e112e2406 | ||
|
812fe90eca | ||
|
6c1122a1d9 | ||
|
d3be2b582a | ||
|
419226d1f6 | ||
|
f554807563 | ||
|
d972845ff6 | ||
|
2c405aed55 | ||
|
da0a18a318 | ||
|
8ed3fa1693 | ||
|
60fe9983ee | ||
|
724fc3cbdf | ||
|
de475cf8d3 | ||
|
b369fc2de4 | ||
|
8c5eaf7ae9 | ||
|
7eb8b2efad | ||
|
b6f6152e26 | ||
|
f8ee136c29 | ||
|
f1ab70649b | ||
|
1548695c83 | ||
|
3da521a586 | ||
|
d22cec81fb | ||
|
d2e0edd721 | ||
|
3002a89419 | ||
|
17ba662004 | ||
|
db4119f971 | ||
|
4a3db71692 | ||
|
dc559d6b7a | ||
|
595e060347 | ||
|
8e4fc5d5d2 | ||
|
b8b7b506a2 | ||
|
550863198c | ||
|
198ae3e366 | ||
|
6e4c7d6211 | ||
|
d2542dcec0 | ||
|
f18a6c2cf2 | ||
|
25e5aa645d | ||
|
620d0d8029 | ||
|
8ec8410651 | ||
|
4cc8ddabe5 | ||
|
07e875972a | ||
|
79ef8b3653 | ||
|
b11c4326d2 | ||
|
390a2a8ab9 | ||
|
cf6f67997e | ||
|
4d1ce3c7ad | ||
|
76449df903 | ||
|
226c9836e4 | ||
|
05008f3930 | ||
|
59ceeae8ea | ||
|
b397f69633 | ||
|
5b3c7572ca | ||
|
e89e4355eb | ||
|
abe0d9421f | ||
|
7c1f3f8163 | ||
|
eab93992d1 | ||
|
0d59d7c680 | ||
|
1efda1c453 | ||
|
a51c8074df | ||
|
3722f90865 | ||
|
9bddb946f0 | ||
|
bbaac89eb0 | ||
|
0dfffb6dcb | ||
|
1b0a5658f1 | ||
|
682b68438e | ||
|
09ec6e504b | ||
|
a2a2af244c | ||
|
cb50ecdb07 | ||
|
1379124682 | ||
|
0b34ade66b | ||
|
191696ab30 | ||
|
af706583bd | ||
|
85c9496340 | ||
|
6ee3a10f17 | ||
|
d0dd9eb5b5 | ||
|
a588358f41 | ||
|
0a110d07b6 | ||
|
5f727f9068 | ||
|
72c8562cc9 | ||
|
882e4f5322 | ||
|
bc1a91f4cd | ||
|
aeb90b7c4a | ||
|
fb87e847bc | ||
|
657496b5a9 | ||
|
fd03a3d957 | ||
|
4bd0488a77 | ||
|
1b17da6ed9 | ||
|
dc5b746f42 | ||
|
89210781cb | ||
|
e9810cbad6 | ||
|
1027556614 | ||
|
3dcb5fa28f | ||
|
1d5dcfcd46 | ||
|
66ff9ed34e | ||
|
66328adf83 | ||
|
b65950bb2e | ||
|
0d70fe2659 | ||
|
a1fc2cfa09 | ||
|
b535966ab5 | ||
|
02412429ab | ||
|
5abdc77c80 | ||
|
b5a9c6b3d2 | ||
|
60f3230a05 | ||
|
0cb4b9205c | ||
|
43d754eb42 | ||
|
2cc0d56652 | ||
|
e0c3ed29d8 | ||
|
2991a7cfe6 | ||
|
44a3584e2d | ||
|
831386977e | ||
|
68035966fb | ||
|
62a98a3f0e | ||
|
888864ad5a | ||
|
654f4f62ed | ||
|
58bcd50f7f | ||
|
60ecfb87ae | ||
|
d0ef318eaa | ||
|
65f9db73b0 | ||
|
a822f7a05a | ||
|
a2c8da0185 | ||
|
88fd5cb688 | ||
|
c78e8c01a3 | ||
|
0ec77c5b3e | ||
|
2d000e9c4e | ||
|
b913746752 | ||
|
9cd3a6836b | ||
|
53c2274d48 | ||
|
7ff84cb07e | ||
|
e6fbf0334f | ||
|
72698bc3b4 | ||
|
65027657ec | ||
|
08949cca41 | ||
|
a231f915a0 | ||
|
c3ef5d5414 | ||
|
57a3d71c90 | ||
|
43db2cf5e7 | ||
|
cc9a6a710f | ||
|
2fba4196ef | ||
|
fd66f7cdc0 | ||
|
d142544159 | ||
|
7ac092513c | ||
|
2db53526c9 | ||
|
1f28d40c78 | ||
|
e2491680e6 | ||
|
3a38322a54 | ||
|
29d8313b28 | ||
|
682507bc3c | ||
|
441d6dc734 | ||
|
d5cabfe5c6 | ||
|
af6a84da14 | ||
|
08e94d1b19 | ||
|
2fba94b36e | ||
|
8c9116dc98 | ||
|
42eb841dc2 | ||
|
584b45530c | ||
|
f5cdea5122 | ||
|
f36a791227 | ||
|
ef226a6f22 | ||
|
7c249dfd88 | ||
|
5bea42412e | ||
|
04166c4a35 | ||
|
fed585e3f4 | ||
|
406229d927 | ||
|
7a7d12d27f | ||
|
cd830a2fab | ||
|
aef554d553 | ||
|
01c4c29b3a | ||
|
459bbfa4b2 | ||
|
7140def5c9 | ||
|
b85dec2b97 | ||
|
cbd673601c | ||
|
66a3979cba | ||
|
9de254c46e | ||
|
388e70b881 | ||
|
8c9aff0bef | ||
|
48594b18e6 | ||
|
b18504adfe | ||
|
bba537a7be | ||
|
0291b73de7 | ||
|
28e674bc6a | ||
|
9d84dda213 | ||
|
d63c291f86 | ||
|
6ad19036e3 | ||
|
3bdcf5d8f0 | ||
|
5c1f70b5c5 | ||
|
c7848f54ff | ||
|
267ed3d74b | ||
|
d3704fdb09 | ||
|
ca05bfaac7 | ||
|
e4b84c7ba5 | ||
|
983593ddf4 | ||
|
f14df43435 | ||
|
f000673599 | ||
|
5b6c2a1e72 | ||
|
d372068620 | ||
|
139d183485 | ||
|
d7c17c32af | ||
|
ee1486a7de | ||
|
b8ba719f73 | ||
|
ada8a6cb77 | ||
|
6c678b7472 | ||
|
bfbfaf9f9f | ||
|
df81bc4a97 | ||
|
87588fa894 | ||
|
74036a2c9d | ||
|
05b72368ed | ||
|
6f71cfeff9 | ||
|
59ca634b89 | ||
|
8009366231 | ||
|
bd71327180 | ||
|
67b7d3d3b6 | ||
|
6358a169fd | ||
|
99b9a0e5de | ||
|
aa235318fc | ||
|
a0b1951791 | ||
|
2d45794956 | ||
|
453fb84c9c | ||
|
59804abc3d | ||
|
496f466d73 | ||
|
fa033c4d5f | ||
|
b8e166894b | ||
|
1f15a15621 | ||
|
fd1e29c3f8 | ||
|
553e13144f | ||
|
494945ff4f | ||
|
7c0cd2597a | ||
|
37caf0b36e | ||
|
cf0b753209 | ||
|
ddc34feb58 | ||
|
3f5b994ff0 | ||
|
dacdfec973 | ||
|
72c30f8393 | ||
|
4e05751346 | ||
|
ee3e0a93f4 | ||
|
d1290fbd8f | ||
|
484c9709b6 | ||
|
d08f1112d5 | ||
|
bcfd9a2f8e | ||
|
886176f854 | ||
|
d397d0d681 | ||
|
20c37ed0f9 | ||
|
9501a87704 | ||
|
8f0f4a861a | ||
|
8c9ea9b849 | ||
|
4d22d03fab | ||
|
81584779cb | ||
|
61c33652ad | ||
|
f9d398e8fb | ||
|
74c8ca699c | ||
|
eddb95b012 | ||
|
84eb425f38 | ||
|
a50a87457e | ||
|
566e0a772d | ||
|
11077af52f | ||
|
0fc73a6e47 | ||
|
2bd132d458 | ||
|
91ddd345f2 | ||
|
75bd141e22 | ||
|
0cdcf32865 | ||
|
629a4d0fca | ||
|
e95983f5df | ||
|
e37e84d210 | ||
|
e57e6f509d | ||
|
bea117a4b6 | ||
|
908b96a370 | ||
|
13c16b4e95 | ||
|
4fcc0d5ac9 | ||
|
3b51581f1b | ||
|
db92eec876 | ||
|
44969307c7 | ||
|
4babdff72f | ||
|
c997091166 | ||
|
005f1fd360 | ||
|
8d4e7504b1 | ||
|
aa6a26a2d5 | ||
|
d91ba3c8d0 | ||
|
bafd22ecf4 | ||
|
dd9d57300b | ||
|
8c5ad23b24 | ||
|
53384b0ffe | ||
|
1c469ca98b | ||
|
e61ecf4091 | ||
|
90c00f075a | ||
|
38473f0aa0 | ||
|
24a5d13d60 | ||
|
383c0b7802 | ||
|
bf8031e984 | ||
|
ab307b816b | ||
|
40562fd266 | ||
|
5f9cb48882 | ||
|
2ab7dc9a55 | ||
|
2b9bc9c154 | ||
|
f5bf5ebb82 | ||
|
26bc591572 | ||
|
268dd32d76 | ||
|
bea97ea766 | ||
|
03f3223d72 | ||
|
7880671f35 | ||
|
b5eec34230 | ||
|
2128682162 | ||
|
e68c0ce5f6 | ||
|
54dddfe9b8 | ||
|
aea3aff4e4 | ||
|
46943b64c6 | ||
|
302c0d2046 | ||
|
22b1a70274 | ||
|
6f75c8451d | ||
|
b9b78549f3 | ||
|
438ce5809f | ||
|
f485fa31f3 | ||
|
34ae4cf511 | ||
|
298796cc7b | ||
|
a4859446ab | ||
|
7bffd16024 | ||
|
2bd46f442d | ||
|
11b706acdf | ||
|
33b9e8d461 | ||
|
f025cc6782 | ||
|
3988f2dade | ||
|
1899cf5f04 | ||
|
5259319cf5 | ||
|
b83bc0ae64 | ||
|
282427cdd9 | ||
|
c67d3c990b | ||
|
2e47fe3e1a | ||
|
e12bb39c20 | ||
|
5caa727e7e | ||
|
0a46201a66 | ||
|
3f248dcaae | ||
|
baa43e40a0 | ||
|
a6788662b0 | ||
|
4a5f73c8ae | ||
|
fdcf884cf7 | ||
|
964035b118 | ||
|
5135d609b7 | ||
|
f48cb3eb17 | ||
|
8325866c61 | ||
|
01e011bc90 | ||
|
e3b60b07d9 | ||
|
d0665726ca | ||
|
96c84da1d4 | ||
|
7d36a76180 | ||
|
197af5de70 | ||
|
27301312a6 | ||
|
8ac7fca5d0 | ||
|
a823509b99 | ||
|
298d28af51 | ||
|
439b2dceda | ||
|
9262f6968b | ||
|
71e73e36cd | ||
|
01c206326f | ||
|
9566893cc9 | ||
|
0e2589867f | ||
|
4acc386dd5 | ||
|
429480bb77 | ||
|
61067dc2e6 | ||
|
effb08edbb | ||
|
d1b4ebe07d | ||
|
5eef9dab80 | ||
|
2ca246d7d1 | ||
|
9a085e138e | ||
|
546b5a9dcf | ||
|
a39e719b39 | ||
|
f51b2cb2e7 | ||
|
9736753985 | ||
|
ea783d3632 | ||
|
074e9612a2 | ||
|
7406404fa3 | ||
|
010e4f2879 | ||
|
ebbbcfef1c | ||
|
3d776de2cb | ||
|
831ff60698 | ||
|
c25426ca47 | ||
|
09b93aaf85 | ||
|
d4fedf84e0 | ||
|
2af4f3c4e2 | ||
|
b8e7eee837 | ||
|
b48c9013aa | ||
|
b48f2cbc8b | ||
|
1736badf28 | ||
|
88725d6ce8 | ||
|
be0a01145b | ||
|
1f805a6377 | ||
|
e595ccb294 | ||
|
43a29a9d0f | ||
|
0dd71af5fa | ||
|
0618f09939 | ||
|
a23eaf720e | ||
|
9d3fc1281d | ||
|
8857cabca4 | ||
|
affd75936e | ||
|
3e78b7cc3a | ||
|
647a148d4d | ||
|
bb777c24ff | ||
|
0576daf5f9 | ||
|
c442cade78 | ||
|
6004b143a8 | ||
|
25cbb8454c | ||
|
416c9675fc | ||
|
6a1e287053 | ||
|
5bda32e460 | ||
|
6137268e79 | ||
|
234e931db2 | ||
|
fdcb55a0a6 | ||
|
d97a0525aa | ||
|
193dddb433 | ||
|
8fe36654ef | ||
|
8ee1af9530 | ||
|
e4c294432f | ||
|
3ebaeccec9 | ||
|
7177e37b99 | ||
|
fbc5099402 | ||
|
45b379abac | ||
|
6ae975996e | ||
|
5d26c70a9c | ||
|
322cbf83c8 | ||
|
fc99d11703 | ||
|
48652cb41e | ||
|
d4f7f11c3c | ||
|
1ce951d0be | ||
|
52c119052a | ||
|
9317ec8eb1 | ||
|
1b9447853b | ||
|
122d59ac41 | ||
|
8b5179d006 | ||
|
3ea5b948a4 | ||
|
164bad171f | ||
|
acc691851d | ||
|
d2159deaf2 | ||
|
17c591ffba | ||
|
bb04a9be52 | ||
|
338df98ddf | ||
|
da022e1e4f | ||
|
f098f55cab | ||
|
bc955eaf61 | ||
|
2d99c962df | ||
|
e59f5c8e13 | ||
|
b073b092c9 | ||
|
092fdc89fa | ||
|
d000a0b58a | ||
|
cf845fed38 | ||
|
72c984e105 | ||
|
3d3707a077 | ||
|
a0dd90a397 | ||
|
1e2a5dded7 | ||
|
549ce78cf5 | ||
|
1801a36414 | ||
|
501514960a | ||
|
ef5937da1f | ||
|
072c6f1527 | ||
|
55e32fe579 | ||
|
7ee8e50b9c | ||
|
995f0ad51c | ||
|
948dd26931 | ||
|
55e1e12b7d | ||
|
6e27e08cb4 | ||
|
d670f72830 | ||
|
57cd6546c3 | ||
|
1244630ab4 | ||
|
a9a4710fe1 | ||
|
cc83ee60fb | ||
|
89dc29affb | ||
|
85e09518b9 | ||
|
663f090c45 | ||
|
1cf9e14a41 | ||
|
0c2fe22bc1 | ||
|
6f0b3b069f | ||
|
9cd20a7062 | ||
|
219fb317ee | ||
|
66fd8e7821 | ||
|
83e3538181 | ||
|
723f25a999 | ||
|
59b1de0bcf | ||
|
df46864b39 | ||
|
cca41ea544 | ||
|
532bec6e56 | ||
|
ee82d8a876 | ||
|
1646ca75f0 | ||
|
f876665264 | ||
|
5817bae2da | ||
|
4cfc155560 | ||
|
a1174a6d7e | ||
|
5357329454 | ||
|
7fea36d155 | ||
|
2bf7e81ed5 | ||
|
ca8ae21b52 | ||
|
d0ec4fb828 | ||
|
4428cf6f07 | ||
|
fe43991d02 | ||
|
8565ba68f7 | ||
|
629d35e6f5 | ||
|
67dea31b0f | ||
|
6af21daac9 | ||
|
9d3be5579a | ||
|
05ac28f3e4 | ||
|
0f852c6f74 | ||
|
974ac467de | ||
|
af7d02da5d | ||
|
5abd543766 | ||
|
1948f9e767 | ||
|
27ea2a88c1 | ||
|
16cd648181 | ||
|
53b21ac1cd | ||
|
e4550811b2 | ||
|
704846a258 | ||
|
935aecdc32 | ||
|
1714f08d75 | ||
|
452dc6b5fe | ||
|
5c9aa2b732 | ||
|
78af88e1f4 | ||
|
74c474a652 | ||
|
5e33ad29d4 | ||
|
27a99b19e8 | ||
|
ee0c897bba | ||
|
ceecf96208 | ||
|
47a3036ea6 | ||
|
d2dc31a74a | ||
|
60a9b938b4 | ||
|
dd517b9a55 | ||
|
b3329c362e | ||
|
b00f4a0cf3 | ||
|
a0ed88a99b | ||
|
25d2853db2 | ||
|
1930051bde | ||
|
6c34eafe02 | ||
|
bbff431e3a | ||
|
3660a321f0 | ||
|
e06f307c2d | ||
|
3b342be2f2 | ||
|
2dda356e3f | ||
|
972f6bc861 | ||
|
d2514445e1 | ||
|
daa46f14c4 | ||
|
1ada494bb2 | ||
|
4df26b2621 | ||
|
556f68ab15 | ||
|
fdb2689a14 | ||
|
598d3defd5 | ||
|
7f8044d913 | ||
|
66b39ccaed | ||
|
cae2a26ee3 | ||
|
b79ba3db8a | ||
|
59a77923b3 |
61
.babelrc
61
.babelrc
@@ -1,7 +1,62 @@
|
|||||||
{
|
{
|
||||||
"presets": ["es2015", "react"],
|
"presets": [
|
||||||
|
"react",
|
||||||
|
[
|
||||||
|
"env",
|
||||||
|
{
|
||||||
|
"loose": true,
|
||||||
|
"modules": false,
|
||||||
|
"targets": {
|
||||||
|
"browsers": ["last 2 versions", "IE >= 11", "iOS >= 9"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"transform-decorators-legacy",
|
"syntax-dynamic-import",
|
||||||
"transform-object-rest-spread"
|
"transform-object-rest-spread",
|
||||||
|
"transform-class-properties",
|
||||||
|
[
|
||||||
|
"react-intl",
|
||||||
|
{
|
||||||
|
"messagesDir": "./build/messages"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"development": {
|
||||||
|
"plugins": [
|
||||||
|
"transform-react-jsx-source",
|
||||||
|
"transform-react-jsx-self"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"production": {
|
||||||
|
"plugins": [
|
||||||
|
"lodash",
|
||||||
|
[
|
||||||
|
"transform-react-remove-prop-types",
|
||||||
|
{
|
||||||
|
"mode": "remove",
|
||||||
|
"removeImport": true,
|
||||||
|
"additionalLibraries": [
|
||||||
|
"react-immutable-proptypes"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"transform-runtime",
|
||||||
|
{
|
||||||
|
"helpers": true,
|
||||||
|
"polyfill": false,
|
||||||
|
"regenerator": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"plugins": [
|
||||||
|
"transform-es2015-modules-commonjs"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1,2 +1,3 @@
|
|||||||
|
https://github.com/heroku/heroku-buildpack-apt
|
||||||
https://github.com/Scalingo/nodejs-buildpack
|
https://github.com/Scalingo/nodejs-buildpack
|
||||||
https://github.com/Scalingo/ruby-buildpack
|
https://github.com/Scalingo/ruby-buildpack
|
||||||
|
@@ -1,14 +1,21 @@
|
|||||||
engines:
|
engines:
|
||||||
|
brakeman:
|
||||||
|
enabled: true
|
||||||
|
bundler-audit:
|
||||||
|
enabled: true
|
||||||
duplication:
|
duplication:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
eslint:
|
||||||
|
enabled: true
|
||||||
rubocop:
|
rubocop:
|
||||||
enabled: true
|
enabled: true
|
||||||
eslint:
|
scss-lint:
|
||||||
enabled: true
|
enabled: true
|
||||||
ratings:
|
ratings:
|
||||||
paths:
|
paths:
|
||||||
- "**.rb"
|
- "**.rb"
|
||||||
- "**.js"
|
- "**.js"
|
||||||
|
- "**.scss"
|
||||||
exclude_paths:
|
exclude_paths:
|
||||||
- spec/
|
- spec/
|
||||||
- vendor/asset
|
- vendor/asset
|
||||||
|
@@ -9,3 +9,5 @@ vendor/bundle
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
*.swp
|
*.swp
|
||||||
*~
|
*~
|
||||||
|
postgres
|
||||||
|
redis
|
||||||
|
109
.env.nanobox
Normal file
109
.env.nanobox
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
# Service dependencies
|
||||||
|
# You may set REDIS_URL instead for more advanced options
|
||||||
|
REDIS_HOST=$DATA_REDIS_HOST
|
||||||
|
REDIS_PORT=6379
|
||||||
|
# REDIS_DB=0
|
||||||
|
|
||||||
|
# You may set DATABASE_URL instead for more advanced options
|
||||||
|
DB_HOST=$DATA_DB_HOST
|
||||||
|
DB_USER=$DATA_DB_USER
|
||||||
|
DB_NAME=gonano
|
||||||
|
DB_PASS=$DATA_DB_PASS
|
||||||
|
DB_PORT=5432
|
||||||
|
|
||||||
|
# Federation
|
||||||
|
# Note: Changing LOCAL_DOMAIN or LOCAL_HTTPS at a later time will cause unwanted side effects.
|
||||||
|
# LOCAL_DOMAIN should *NOT* contain the protocol part of the domain e.g https://example.com.
|
||||||
|
LOCAL_DOMAIN=${APP_NAME}.nanoapp.io
|
||||||
|
LOCAL_HTTPS=false
|
||||||
|
|
||||||
|
# Use this only if you need to run mastodon on a different domain than the one used for federation.
|
||||||
|
# You can read more about this option on https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Serving_a_different_domain.md
|
||||||
|
# DO *NOT* USE THIS UNLESS YOU KNOW *EXACTLY* WHAT YOU ARE DOING.
|
||||||
|
# WEB_DOMAIN=mastodon.example.com
|
||||||
|
|
||||||
|
# Use this if you want to have several aliases handler@example1.com
|
||||||
|
# handler@example2.com etc. for the same user. LOCAL_DOMAIN should not
|
||||||
|
# be added. Comma separated values
|
||||||
|
# ALTERNATE_DOMAINS=example1.com,example2.com
|
||||||
|
|
||||||
|
# Application secrets
|
||||||
|
# Generate each with the `rake secret` task (`nanobox run bundle exec rake secret`)
|
||||||
|
PAPERCLIP_SECRET=$PAPERCLIP_SECRET
|
||||||
|
SECRET_KEY_BASE=$SECRET_KEY_BASE
|
||||||
|
OTP_SECRET=$OTP_SECRET
|
||||||
|
|
||||||
|
# Registrations
|
||||||
|
# Single user mode will disable registrations and redirect frontpage to the first profile
|
||||||
|
# SINGLE_USER_MODE=true
|
||||||
|
# Prevent registrations with following e-mail domains
|
||||||
|
# EMAIL_DOMAIN_BLACKLIST=example1.com|example2.de|etc
|
||||||
|
# Only allow registrations with the following e-mail domains
|
||||||
|
# EMAIL_DOMAIN_WHITELIST=example1.com|example2.de|etc
|
||||||
|
|
||||||
|
# Optionally change default language
|
||||||
|
# DEFAULT_LOCALE=de
|
||||||
|
|
||||||
|
# E-mail configuration
|
||||||
|
# Note: Mailgun and SparkPost (https://sparkpo.st/smtp) each have good free tiers
|
||||||
|
# If you want to use an SMTP server without authentication (e.g local Postfix relay)
|
||||||
|
# then set SMTP_AUTH_METHOD and SMTP_OPENSSL_VERIFY_MODE to 'none' and
|
||||||
|
# *comment* SMTP_LOGIN and SMTP_PASSWORD (leaving them blank is not enough).
|
||||||
|
SMTP_SERVER=$SMTP_SERVER
|
||||||
|
SMTP_PORT=587
|
||||||
|
SMTP_LOGIN=$SMTP_LOGIN
|
||||||
|
SMTP_PASSWORD=$SMTP_PASSWORD
|
||||||
|
SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io
|
||||||
|
#SMTP_DOMAIN= # defaults to LOCAL_DOMAIN
|
||||||
|
#SMTP_DELIVERY_METHOD=smtp # delivery method can also be sendmail
|
||||||
|
#SMTP_AUTH_METHOD=plain
|
||||||
|
#SMTP_CA_FILE=/etc/ssl/certs/ca-certificates.crt
|
||||||
|
#SMTP_OPENSSL_VERIFY_MODE=peer
|
||||||
|
#SMTP_ENABLE_STARTTLS_AUTO=true
|
||||||
|
|
||||||
|
|
||||||
|
# Optional user upload path and URL (images, avatars). Default is :rails_root/public/system. If you set this variable, you are responsible for making your HTTP server (eg. nginx) serve these files.
|
||||||
|
# PAPERCLIP_ROOT_PATH=/var/lib/mastodon/public-system
|
||||||
|
# PAPERCLIP_ROOT_URL=/system
|
||||||
|
|
||||||
|
# Optional asset host for multi-server setups
|
||||||
|
# CDN_HOST=assets.example.com
|
||||||
|
|
||||||
|
# S3 (optional)
|
||||||
|
# S3_ENABLED=true
|
||||||
|
# S3_BUCKET=
|
||||||
|
# AWS_ACCESS_KEY_ID=
|
||||||
|
# AWS_SECRET_ACCESS_KEY=
|
||||||
|
# S3_REGION=
|
||||||
|
# S3_PROTOCOL=http
|
||||||
|
# S3_HOSTNAME=192.168.1.123:9000
|
||||||
|
|
||||||
|
# S3 (Minio Config (optional) Please check Minio instance for details)
|
||||||
|
# S3_ENABLED=true
|
||||||
|
# S3_BUCKET=
|
||||||
|
# AWS_ACCESS_KEY_ID=
|
||||||
|
# AWS_SECRET_ACCESS_KEY=
|
||||||
|
# S3_REGION=
|
||||||
|
# S3_PROTOCOL=https
|
||||||
|
# S3_HOSTNAME=
|
||||||
|
# S3_ENDPOINT=
|
||||||
|
# S3_SIGNATURE_VERSION=
|
||||||
|
|
||||||
|
# Optional alias for S3 if you want to use Cloudfront or Cloudflare in front
|
||||||
|
# S3_CLOUDFRONT_HOST=
|
||||||
|
|
||||||
|
# Streaming API integration
|
||||||
|
# STREAMING_API_BASE_URL=
|
||||||
|
|
||||||
|
# Advanced settings
|
||||||
|
# If you need to use pgBouncer, you need to disable prepared statements:
|
||||||
|
# PREPARED_STATEMENTS=false
|
||||||
|
|
||||||
|
# Cluster number setting for streaming API server.
|
||||||
|
# If you comment out following line, cluster number will be `numOfCpuCores - 1`.
|
||||||
|
STREAMING_CLUSTER_NUM=1
|
||||||
|
|
||||||
|
# Docker mastodon user
|
||||||
|
# If you use Docker, you may want to assign UID/GID manually.
|
||||||
|
# UID=1000
|
||||||
|
# GID=1000
|
@@ -1,7 +1,8 @@
|
|||||||
# Service dependencies
|
# Service dependencies
|
||||||
|
# You may set REDIS_URL instead for more advanced options
|
||||||
REDIS_HOST=redis
|
REDIS_HOST=redis
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
# REDIS_DB=0
|
# You may set DATABASE_URL instead for more advanced options
|
||||||
DB_HOST=db
|
DB_HOST=db
|
||||||
DB_USER=postgres
|
DB_USER=postgres
|
||||||
DB_NAME=postgres
|
DB_NAME=postgres
|
||||||
@@ -9,13 +10,21 @@ DB_PASS=
|
|||||||
DB_PORT=5432
|
DB_PORT=5432
|
||||||
|
|
||||||
# Federation
|
# Federation
|
||||||
|
# Note: Changing LOCAL_DOMAIN or LOCAL_HTTPS at a later time will cause unwanted side effects.
|
||||||
|
# LOCAL_DOMAIN should *NOT* contain the protocol part of the domain e.g https://example.com.
|
||||||
LOCAL_DOMAIN=example.com
|
LOCAL_DOMAIN=example.com
|
||||||
LOCAL_HTTPS=true
|
LOCAL_HTTPS=true
|
||||||
|
|
||||||
# Use this only if you need to run mastodon on a different domain than the one used for federation.
|
# Use this only if you need to run mastodon on a different domain than the one used for federation.
|
||||||
# Do not use this unless you know exactly what you are doing.
|
# You can read more about this option on https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Serving_a_different_domain.md
|
||||||
|
# DO *NOT* USE THIS UNLESS YOU KNOW *EXACTLY* WHAT YOU ARE DOING.
|
||||||
# WEB_DOMAIN=mastodon.example.com
|
# WEB_DOMAIN=mastodon.example.com
|
||||||
|
|
||||||
|
# Use this if you want to have several aliases handler@example1.com
|
||||||
|
# handler@example2.com etc. for the same user. LOCAL_DOMAIN should not
|
||||||
|
# be added. Comma separated values
|
||||||
|
# ALTERNATE_DOMAINS=example1.com,example2.com
|
||||||
|
|
||||||
# Application secrets
|
# Application secrets
|
||||||
# Generate each with the `rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose)
|
# Generate each with the `rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose)
|
||||||
PAPERCLIP_SECRET=
|
PAPERCLIP_SECRET=
|
||||||
@@ -36,8 +45,8 @@ OTP_SECRET=
|
|||||||
# E-mail configuration
|
# E-mail configuration
|
||||||
# Note: Mailgun and SparkPost (https://sparkpo.st/smtp) each have good free tiers
|
# Note: Mailgun and SparkPost (https://sparkpo.st/smtp) each have good free tiers
|
||||||
# If you want to use an SMTP server without authentication (e.g local Postfix relay)
|
# If you want to use an SMTP server without authentication (e.g local Postfix relay)
|
||||||
# then set SMTP_AUTH_METHOD to 'none' and *comment* SMTP_LOGIN and SMTP_PASSWORD.
|
# then set SMTP_AUTH_METHOD and SMTP_OPENSSL_VERIFY_MODE to 'none' and
|
||||||
# Leaving them blank is not enough for authentication method 'none'.
|
# *comment* SMTP_LOGIN and SMTP_PASSWORD (leaving them blank is not enough).
|
||||||
SMTP_SERVER=smtp.mailgun.org
|
SMTP_SERVER=smtp.mailgun.org
|
||||||
SMTP_PORT=587
|
SMTP_PORT=587
|
||||||
SMTP_LOGIN=
|
SMTP_LOGIN=
|
||||||
@@ -46,6 +55,7 @@ SMTP_FROM_ADDRESS=notifications@example.com
|
|||||||
#SMTP_DOMAIN= # defaults to LOCAL_DOMAIN
|
#SMTP_DOMAIN= # defaults to LOCAL_DOMAIN
|
||||||
#SMTP_DELIVERY_METHOD=smtp # delivery method can also be sendmail
|
#SMTP_DELIVERY_METHOD=smtp # delivery method can also be sendmail
|
||||||
#SMTP_AUTH_METHOD=plain
|
#SMTP_AUTH_METHOD=plain
|
||||||
|
#SMTP_CA_FILE=/etc/ssl/certs/ca-certificates.crt
|
||||||
#SMTP_OPENSSL_VERIFY_MODE=peer
|
#SMTP_OPENSSL_VERIFY_MODE=peer
|
||||||
#SMTP_ENABLE_STARTTLS_AUTO=true
|
#SMTP_ENABLE_STARTTLS_AUTO=true
|
||||||
|
|
||||||
@@ -90,3 +100,8 @@ SMTP_FROM_ADDRESS=notifications@example.com
|
|||||||
# Cluster number setting for streaming API server.
|
# Cluster number setting for streaming API server.
|
||||||
# If you comment out following line, cluster number will be `numOfCpuCores - 1`.
|
# If you comment out following line, cluster number will be `numOfCpuCores - 1`.
|
||||||
STREAMING_CLUSTER_NUM=1
|
STREAMING_CLUSTER_NUM=1
|
||||||
|
|
||||||
|
# Docker mastodon user
|
||||||
|
# If you use Docker, you may want to assign UID/GID manually.
|
||||||
|
# UID=1000
|
||||||
|
# GID=1000
|
||||||
|
79
.eslintrc
79
.eslintrc
@@ -1,79 +0,0 @@
|
|||||||
{
|
|
||||||
"env": {
|
|
||||||
"browser": true,
|
|
||||||
"node": false,
|
|
||||||
"es6": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"parser": "babel-eslint",
|
|
||||||
|
|
||||||
"plugins": [
|
|
||||||
"react",
|
|
||||||
"jsx-a11y"
|
|
||||||
],
|
|
||||||
|
|
||||||
"parserOptions": {
|
|
||||||
"sourceType": "module",
|
|
||||||
|
|
||||||
"ecmaFeatures": {
|
|
||||||
"arrowFunctions": true,
|
|
||||||
"jsx": true,
|
|
||||||
"destructuring": true,
|
|
||||||
"modules": true,
|
|
||||||
"spread": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"rules": {
|
|
||||||
"no-cond-assign": 2,
|
|
||||||
"no-console": 1,
|
|
||||||
"no-irregular-whitespace": 2,
|
|
||||||
"no-unreachable": 2,
|
|
||||||
"valid-typeof": 2,
|
|
||||||
"consistent-return": 2,
|
|
||||||
"dot-notation": 2,
|
|
||||||
"eqeqeq": 2,
|
|
||||||
"no-fallthrough": 2,
|
|
||||||
"no-unused-expressions": 2,
|
|
||||||
"strict": 0,
|
|
||||||
"no-catch-shadow": 2,
|
|
||||||
"indent": [1, 2],
|
|
||||||
"brace-style": 1,
|
|
||||||
"comma-spacing": [1, {"before": false, "after": true}],
|
|
||||||
"comma-style": [1, "last"],
|
|
||||||
"no-mixed-spaces-and-tabs": 1,
|
|
||||||
"no-nested-ternary": 1,
|
|
||||||
"no-trailing-spaces": 1,
|
|
||||||
|
|
||||||
"react/jsx-wrap-multilines": 2,
|
|
||||||
"react/self-closing-comp": 2,
|
|
||||||
"react/prop-types": 2,
|
|
||||||
"react/no-multi-comp": 0,
|
|
||||||
|
|
||||||
"jsx-a11y/accessible-emoji": 1,
|
|
||||||
"jsx-a11y/anchor-has-content": 1,
|
|
||||||
"jsx-a11y/aria-activedescendant-has-tabindex": 1,
|
|
||||||
"jsx-a11y/aria-props": 1,
|
|
||||||
"jsx-a11y/aria-proptypes": 1,
|
|
||||||
"jsx-a11y/aria-role": 1,
|
|
||||||
"jsx-a11y/aria-unsupported-elements": 1,
|
|
||||||
"jsx-a11y/heading-has-content": 1,
|
|
||||||
"jsx-a11y/href-no-hash": 1,
|
|
||||||
"jsx-a11y/html-has-lang": 1,
|
|
||||||
"jsx-a11y/iframe-has-title": 1,
|
|
||||||
"jsx-a11y/img-has-alt": 1,
|
|
||||||
"jsx-a11y/img-redundant-alt": 1,
|
|
||||||
"jsx-a11y/label-has-for": 1,
|
|
||||||
"jsx-a11y/mouse-events-have-key-events": 1,
|
|
||||||
"jsx-a11y/no-access-key": 1,
|
|
||||||
"jsx-a11y/no-distracting-elements": 1,
|
|
||||||
"jsx-a11y/no-onchange": 1,
|
|
||||||
"jsx-a11y/no-redundant-roles": 1,
|
|
||||||
"jsx-a11y/onclick-has-focus": 1,
|
|
||||||
"jsx-a11y/onclick-has-role": 1,
|
|
||||||
"jsx-a11y/role-has-required-aria-props": 1,
|
|
||||||
"jsx-a11y/role-supports-aria-props": 1,
|
|
||||||
"jsx-a11y/scope": 1,
|
|
||||||
"jsx-a11y/tabindex-no-positive": 1
|
|
||||||
}
|
|
||||||
}
|
|
88
.eslintrc.yml
Normal file
88
.eslintrc.yml
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
---
|
||||||
|
env:
|
||||||
|
browser: true
|
||||||
|
node: false
|
||||||
|
es6: true
|
||||||
|
|
||||||
|
parser: babel-eslint
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- react
|
||||||
|
- jsx-a11y
|
||||||
|
|
||||||
|
parserOptions:
|
||||||
|
sourceType: module
|
||||||
|
ecmaFeatures:
|
||||||
|
arrowFunctions: true
|
||||||
|
jsx: true
|
||||||
|
destructuring: true
|
||||||
|
modules: true
|
||||||
|
spread: true
|
||||||
|
|
||||||
|
rules:
|
||||||
|
|
||||||
|
no-cond-assign: error
|
||||||
|
no-console: warn
|
||||||
|
no-irregular-whitespace: error
|
||||||
|
no-unreachable: error
|
||||||
|
valid-typeof: error
|
||||||
|
consistent-return: error
|
||||||
|
dot-notation: error
|
||||||
|
eqeqeq: error
|
||||||
|
no-fallthrough: error
|
||||||
|
no-unused-expressions: error
|
||||||
|
strict: off
|
||||||
|
no-catch-shadow: error
|
||||||
|
indent:
|
||||||
|
- warn
|
||||||
|
- 2
|
||||||
|
brace-style: warn
|
||||||
|
comma-spacing:
|
||||||
|
- warn
|
||||||
|
- before: false
|
||||||
|
after: true
|
||||||
|
comma-style:
|
||||||
|
- warn
|
||||||
|
- last
|
||||||
|
no-mixed-spaces-and-tabs: warn
|
||||||
|
no-nested-ternary: warn
|
||||||
|
no-trailing-spaces: warn
|
||||||
|
semi: error
|
||||||
|
padded-blocks:
|
||||||
|
- error
|
||||||
|
- classes: always
|
||||||
|
comma-dangle:
|
||||||
|
- error
|
||||||
|
- always-multiline
|
||||||
|
|
||||||
|
react/jsx-wrap-multilines: error
|
||||||
|
react/jsx-no-bind: error
|
||||||
|
react/self-closing-comp: error
|
||||||
|
react/prop-types: error
|
||||||
|
react/no-multi-comp: off
|
||||||
|
|
||||||
|
jsx-a11y/accessible-emoji: warn
|
||||||
|
jsx-a11y/anchor-has-content: warn
|
||||||
|
jsx-a11y/aria-activedescendant-has-tabindex: warn
|
||||||
|
jsx-a11y/aria-props: warn
|
||||||
|
jsx-a11y/aria-proptypes: warn
|
||||||
|
jsx-a11y/aria-role: warn
|
||||||
|
jsx-a11y/aria-unsupported-elements: warn
|
||||||
|
jsx-a11y/heading-has-content: warn
|
||||||
|
jsx-a11y/href-no-hash: warn
|
||||||
|
jsx-a11y/html-has-lang: warn
|
||||||
|
jsx-a11y/iframe-has-title: warn
|
||||||
|
jsx-a11y/img-has-alt: warn
|
||||||
|
jsx-a11y/img-redundant-alt: warn
|
||||||
|
jsx-a11y/label-has-for: warn
|
||||||
|
jsx-a11y/mouse-events-have-key-events: warn
|
||||||
|
jsx-a11y/no-access-key: warn
|
||||||
|
jsx-a11y/no-distracting-elements: warn
|
||||||
|
jsx-a11y/no-onchange: warn
|
||||||
|
jsx-a11y/no-redundant-roles: warn
|
||||||
|
jsx-a11y/onclick-has-focus: warn
|
||||||
|
jsx-a11y/onclick-has-role: warn
|
||||||
|
jsx-a11y/role-has-required-aria-props: warn
|
||||||
|
jsx-a11y/role-supports-aria-props: warn
|
||||||
|
jsx-a11y/scope: warn
|
||||||
|
jsx-a11y/tabindex-no-positive: warn
|
14
.gitignore
vendored
14
.gitignore
vendored
@@ -19,10 +19,11 @@
|
|||||||
coverage
|
coverage
|
||||||
public/system
|
public/system
|
||||||
public/assets
|
public/assets
|
||||||
|
public/packs
|
||||||
.env
|
.env
|
||||||
.env.production
|
.env.production
|
||||||
node_modules/
|
node_modules/
|
||||||
neo4j/
|
build/
|
||||||
|
|
||||||
# Ignore Vagrant files
|
# Ignore Vagrant files
|
||||||
.vagrant/
|
.vagrant/
|
||||||
@@ -43,3 +44,14 @@ redis
|
|||||||
# Ignore vim files
|
# Ignore vim files
|
||||||
*~
|
*~
|
||||||
*.swp
|
*.swp
|
||||||
|
|
||||||
|
# Ignore npm debug log
|
||||||
|
npm-debug.log
|
||||||
|
|
||||||
|
# Ignore yarn log files
|
||||||
|
yarn-error.log
|
||||||
|
yarn-debug.log
|
||||||
|
|
||||||
|
# Ignore Docker option files
|
||||||
|
docker-compose.override.yml
|
||||||
|
|
||||||
|
108
.haml-lint.yml
Normal file
108
.haml-lint.yml
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# Whether to ignore frontmatter at the beginning of HAML documents for
|
||||||
|
# frameworks such as Jekyll/Middleman
|
||||||
|
skip_frontmatter: false
|
||||||
|
|
||||||
|
exclude:
|
||||||
|
- 'vendor/**/*'
|
||||||
|
- 'spec/**/*'
|
||||||
|
- 'lib/templates/**/*'
|
||||||
|
- 'app/views/kaminari/**/*'
|
||||||
|
|
||||||
|
linters:
|
||||||
|
AltText:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
ClassAttributeWithStaticValue:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
ClassesBeforeIds:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
ConsecutiveComments:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
ConsecutiveSilentScripts:
|
||||||
|
enabled: true
|
||||||
|
max_consecutive: 2
|
||||||
|
|
||||||
|
EmptyObjectReference:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
EmptyScript:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
FinalNewline:
|
||||||
|
enabled: true
|
||||||
|
present: true
|
||||||
|
|
||||||
|
HtmlAttributes:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
ImplicitDiv:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
LeadingCommentSpace:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
LineLength:
|
||||||
|
enabled: false
|
||||||
|
max: 80
|
||||||
|
|
||||||
|
MultilinePipe:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
MultilineScript:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
ObjectReferenceAttributes:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
RuboCop:
|
||||||
|
enabled: true
|
||||||
|
# These cops are incredibly noisy when it comes to HAML templates, so we
|
||||||
|
# ignore them.
|
||||||
|
ignored_cops:
|
||||||
|
- Lint/BlockAlignment
|
||||||
|
- Lint/EndAlignment
|
||||||
|
- Lint/Void
|
||||||
|
- Metrics/BlockLength
|
||||||
|
- Metrics/LineLength
|
||||||
|
- Style/AlignParameters
|
||||||
|
- Style/BlockNesting
|
||||||
|
- Style/ElseAlignment
|
||||||
|
- Style/EndOfLine
|
||||||
|
- Style/FileName
|
||||||
|
- Style/FinalNewline
|
||||||
|
- Style/FrozenStringLiteralComment
|
||||||
|
- Style/IfUnlessModifier
|
||||||
|
- Style/IndentationWidth
|
||||||
|
- Style/Next
|
||||||
|
- Style/TrailingBlankLines
|
||||||
|
- Style/TrailingWhitespace
|
||||||
|
- Style/WhileUntilModifier
|
||||||
|
|
||||||
|
RubyComments:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
SpaceBeforeScript:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
SpaceInsideHashAttributes:
|
||||||
|
enabled: true
|
||||||
|
style: space
|
||||||
|
|
||||||
|
Indentation:
|
||||||
|
enabled: true
|
||||||
|
character: space # or tab
|
||||||
|
|
||||||
|
TagName:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
TrailingWhitespace:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
UnnecessaryInterpolation:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
UnnecessaryStringOutput:
|
||||||
|
enabled: true
|
20
.nanoignore
Normal file
20
.nanoignore
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
.DS_Store
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
.bundle/
|
||||||
|
.cache/
|
||||||
|
config/deploy/*
|
||||||
|
coverage
|
||||||
|
docs/
|
||||||
|
.env
|
||||||
|
log/*.log
|
||||||
|
neo4j/
|
||||||
|
node_modules/
|
||||||
|
public/assets/
|
||||||
|
public/system/
|
||||||
|
spec/
|
||||||
|
storybook/
|
||||||
|
tmp/
|
||||||
|
.vagrant/
|
||||||
|
vendor/bundle/
|
8
.postcssrc.yml
Normal file
8
.postcssrc.yml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
plugins:
|
||||||
|
postcss-smart-import: {}
|
||||||
|
precss: {}
|
||||||
|
autoprefixer:
|
||||||
|
browsers:
|
||||||
|
- last 2 versions
|
||||||
|
- IE >= 11
|
||||||
|
- iOS >= 9
|
1
.profile
Normal file
1
.profile
Normal file
@@ -0,0 +1 @@
|
|||||||
|
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/app/.apt/lib/x86_64-linux-gnu:/app/.apt/usr/lib/x86_64-linux-gnu/mesa:/app/.apt/usr/lib/x86_64-linux-gnu/pulseaudio
|
@@ -74,9 +74,15 @@ Style/RegexpLiteral:
|
|||||||
Style/Lambda:
|
Style/Lambda:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
Style/GuardClause:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
Rails/HasAndBelongsToMany:
|
Rails/HasAndBelongsToMany:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
Bundler/OrderedGems:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
AllCops:
|
AllCops:
|
||||||
TargetRubyVersion: 2.3
|
TargetRubyVersion: 2.3
|
||||||
Exclude:
|
Exclude:
|
||||||
@@ -88,3 +94,4 @@ AllCops:
|
|||||||
- 'Rakefile'
|
- 'Rakefile'
|
||||||
- 'node_modules/**/*'
|
- 'node_modules/**/*'
|
||||||
- 'Vagrantfile'
|
- 'Vagrantfile'
|
||||||
|
- 'vendor/**/*'
|
||||||
|
264
.scss-lint.yml
Normal file
264
.scss-lint.yml
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
# Linter Documentation:
|
||||||
|
# https://github.com/brigade/scss-lint/blob/v0.42.2/lib/scss_lint/linter/README.md
|
||||||
|
|
||||||
|
scss_files: 'app/javascript/styles/**/*.scss'
|
||||||
|
|
||||||
|
exclude:
|
||||||
|
- app/javascript/styles/reset.scss
|
||||||
|
|
||||||
|
linters:
|
||||||
|
# Reports when you use improper spacing around ! (the "bang") in !default,
|
||||||
|
# !global, !important, and !optional flags.
|
||||||
|
BangFormat:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Whether or not to prefer `border: 0` over `border: none`.
|
||||||
|
BorderZero:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Reports when you define a rule set using a selector with chained classes
|
||||||
|
# (a.k.a. adjoining classes).
|
||||||
|
ChainedClasses:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Prefer hexadecimal color codes over color keywords.
|
||||||
|
# (e.g. `color: green` is a color keyword)
|
||||||
|
ColorKeyword:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Prefer color literals (keywords or hexadecimal codes) to be used only in
|
||||||
|
# variable declarations. They should be referred to via variables everywhere
|
||||||
|
# else.
|
||||||
|
ColorVariable:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Which form of comments to prefer in CSS.
|
||||||
|
Comment:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Reports @debug statements (which you probably left behind accidentally).
|
||||||
|
DebugStatement:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Rule sets should be ordered as follows:
|
||||||
|
# - @extend declarations
|
||||||
|
# - @include declarations without inner @content
|
||||||
|
# - properties, @include declarations with inner @content
|
||||||
|
# - nested rule sets.
|
||||||
|
DeclarationOrder:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# `scss-lint:disable` control comments should be preceded by a comment
|
||||||
|
# explaining why these linters are being disabled for this file.
|
||||||
|
# See https://github.com/brigade/scss-lint#disabling-linters-via-source for
|
||||||
|
# more information.
|
||||||
|
DisableLinterReason:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Reports when you define the same property twice in a single rule set.
|
||||||
|
DuplicateProperty:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Separate rule, function, and mixin declarations with empty lines.
|
||||||
|
EmptyLineBetweenBlocks:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Reports when you have an empty rule set.
|
||||||
|
EmptyRule:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Reports when you have an @extend directive.
|
||||||
|
ExtendDirective:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Files should always have a final newline. This results in better diffs
|
||||||
|
# when adding lines to the file, since SCM systems such as git won't
|
||||||
|
# think that you touched the last line.
|
||||||
|
FinalNewline:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# HEX colors should use three-character values where possible.
|
||||||
|
HexLength:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# HEX color values should use lower-case colors to differentiate between
|
||||||
|
# letters and numbers, e.g. `#E3E3E3` vs. `#e3e3e3`.
|
||||||
|
HexNotation:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Avoid using ID selectors.
|
||||||
|
IdSelector:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# The basenames of @imported SCSS partials should not begin with an
|
||||||
|
# underscore and should not include the filename extension.
|
||||||
|
ImportPath:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Avoid using !important in properties. It is usually indicative of a
|
||||||
|
# misunderstanding of CSS specificity and can lead to brittle code.
|
||||||
|
ImportantRule:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Indentation should always be done in increments of 2 spaces.
|
||||||
|
Indentation:
|
||||||
|
enabled: true
|
||||||
|
width: 2
|
||||||
|
|
||||||
|
# Don't write leading zeros for numeric values with a decimal point.
|
||||||
|
LeadingZero:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Reports when you define the same selector twice in a single sheet.
|
||||||
|
MergeableSelector:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Functions, mixins, variables, and placeholders should be declared
|
||||||
|
# with all lowercase letters and hyphens instead of underscores.
|
||||||
|
NameFormat:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Avoid nesting selectors too deeply.
|
||||||
|
NestingDepth:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Always use placeholder selectors in @extend.
|
||||||
|
PlaceholderInExtend:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Sort properties in a strict order.
|
||||||
|
PropertySortOrder:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Reports when you use an unknown or disabled CSS property
|
||||||
|
# (ignoring vendor-prefixed properties).
|
||||||
|
PropertySpelling:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Configure which units are allowed for property values.
|
||||||
|
PropertyUnits:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Pseudo-elements, like ::before, and ::first-letter, should be declared
|
||||||
|
# with two colons. Pseudo-classes, like :hover and :first-child, should
|
||||||
|
# be declared with one colon.
|
||||||
|
PseudoElement:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Avoid qualifying elements in selectors (also known as "tag-qualifying").
|
||||||
|
QualifyingElement:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Don't write selectors with a depth of applicability greater than 3.
|
||||||
|
SelectorDepth:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Selectors should always use hyphenated-lowercase, rather than camelCase or
|
||||||
|
# snake_case.
|
||||||
|
SelectorFormat:
|
||||||
|
enabled: false
|
||||||
|
convention: hyphenated_lowercase
|
||||||
|
|
||||||
|
# Prefer the shortest shorthand form possible for properties that support it.
|
||||||
|
Shorthand:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Each property should have its own line, except in the special case of
|
||||||
|
# single line rulesets.
|
||||||
|
SingleLinePerProperty:
|
||||||
|
enabled: true
|
||||||
|
allow_single_line_rule_sets: true
|
||||||
|
|
||||||
|
# Split selectors onto separate lines after each comma, and have each
|
||||||
|
# individual selector occupy a single line.
|
||||||
|
SingleLinePerSelector:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Commas in lists should be followed by a space.
|
||||||
|
SpaceAfterComma:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Properties should be formatted with a single space separating the colon
|
||||||
|
# from the property's value.
|
||||||
|
SpaceAfterPropertyColon:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Properties should be formatted with no space between the name and the
|
||||||
|
# colon.
|
||||||
|
SpaceAfterPropertyName:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Variables should be formatted with a single space separating the colon
|
||||||
|
# from the variable's value.
|
||||||
|
SpaceAfterVariableColon:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Variables should be formatted with no space between the name and the
|
||||||
|
# colon.
|
||||||
|
SpaceAfterVariableName:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Operators should be formatted with a single space on both sides of an
|
||||||
|
# infix operator.
|
||||||
|
SpaceAroundOperator:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Opening braces should be preceded by a single space.
|
||||||
|
SpaceBeforeBrace:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Parentheses should not be padded with spaces.
|
||||||
|
SpaceBetweenParens:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Enforces that string literals should be written with a consistent form
|
||||||
|
# of quotes (single or double).
|
||||||
|
StringQuotes:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Property values, @extend, @include, and @import directives, and variable
|
||||||
|
# declarations should always end with a semicolon.
|
||||||
|
TrailingSemicolon:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Reports lines containing trailing whitespace.
|
||||||
|
TrailingWhitespace:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Don't write trailing zeros for numeric values with a decimal point.
|
||||||
|
TrailingZero:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Don't use the `all` keyword to specify transition properties.
|
||||||
|
TransitionAll:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Numeric values should not contain unnecessary fractional portions.
|
||||||
|
UnnecessaryMantissa:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Do not use parent selector references (&) when they would otherwise
|
||||||
|
# be unnecessary.
|
||||||
|
UnnecessaryParentReference:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# URLs should be valid and not contain protocols or domain names.
|
||||||
|
UrlFormat:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# URLs should always be enclosed within quotes.
|
||||||
|
UrlQuotes:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Properties, like color and font, are easier to read and maintain
|
||||||
|
# when defined using variables rather than literals.
|
||||||
|
VariableForProperty:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Avoid vendor prefixes. Or rather: don't write them yourself.
|
||||||
|
VendorPrefix:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Omit length units on zero values, e.g. `0px` vs. `0`.
|
||||||
|
ZeroUnit:
|
||||||
|
enabled: true
|
39
.travis.yml
39
.travis.yml
@@ -1,7 +1,11 @@
|
|||||||
language: ruby
|
language: ruby
|
||||||
cache: bundler
|
cache:
|
||||||
|
bundler: true
|
||||||
|
yarn: true
|
||||||
|
directories:
|
||||||
|
- node_modules
|
||||||
dist: trusty
|
dist: trusty
|
||||||
sudo: required
|
sudo: false
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
@@ -11,9 +15,21 @@ env:
|
|||||||
- LOCAL_DOMAIN=cb6e6126.ngrok.io
|
- LOCAL_DOMAIN=cb6e6126.ngrok.io
|
||||||
- LOCAL_HTTPS=true
|
- LOCAL_HTTPS=true
|
||||||
- RAILS_ENV=test
|
- RAILS_ENV=test
|
||||||
- CXX=g++-4.8
|
- NOKOGIRI_USE_SYSTEM_LIBRARIES=true
|
||||||
|
- PARALLEL_TEST_PROCESSORS=2
|
||||||
|
- "PATH=$HOME:$PATH"
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
postgresql: 9.4
|
postgresql: 9.4
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
|
- trusty-media
|
||||||
|
packages:
|
||||||
|
- ffmpeg
|
||||||
|
- g++-6
|
||||||
|
- libprotobuf-dev
|
||||||
|
- protobuf-compiler
|
||||||
|
|
||||||
rvm:
|
rvm:
|
||||||
- 2.3.4
|
- 2.3.4
|
||||||
@@ -22,23 +38,18 @@ rvm:
|
|||||||
services:
|
services:
|
||||||
- redis-server
|
- redis-server
|
||||||
|
|
||||||
bundler_args: --without development production --retry=3 --jobs=3
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
|
||||||
- sudo add-apt-repository -y ppa:mc3man/trusty-media
|
|
||||||
- sudo apt-get -qq update
|
|
||||||
- sudo apt-get -qq install g++-4.8 ffmpeg
|
|
||||||
install:
|
install:
|
||||||
- nvm install
|
- nvm install
|
||||||
- npm install -g yarn
|
- npm install -g yarn
|
||||||
- bundle install
|
- bundle install --path=vendor/bundle --without development production --retry=3 --jobs=16
|
||||||
- yarn install
|
- yarn install
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- bundle exec rails db:create db:migrate
|
- bundle exec rake parallel:create parallel:load_schema parallel:prepare
|
||||||
|
- bundle exec rails assets:precompile
|
||||||
|
- ln -s /usr/bin/x86_64-linux-gnu-g++-6 "$HOME/g++"
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- bundle exec rspec
|
- bundle exec parallel_test spec/ --group-by filesize --type rspec
|
||||||
- npm test
|
- npm test
|
||||||
- i18n-tasks unused
|
- bundle exec i18n-tasks unused
|
||||||
|
5
Aptfile
Normal file
5
Aptfile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
protobuf-compiler
|
||||||
|
libprotobuf-dev
|
||||||
|
ffmpeg
|
||||||
|
libxdamage1
|
||||||
|
libxfixes3
|
2
Capfile
2
Capfile
@@ -1,3 +1,4 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
require 'capistrano/setup'
|
require 'capistrano/setup'
|
||||||
require 'capistrano/deploy'
|
require 'capistrano/deploy'
|
||||||
require 'capistrano/scm/git'
|
require 'capistrano/scm/git'
|
||||||
@@ -8,7 +9,6 @@ require 'capistrano/rbenv'
|
|||||||
require 'capistrano/bundler'
|
require 'capistrano/bundler'
|
||||||
require 'capistrano/yarn'
|
require 'capistrano/yarn'
|
||||||
require 'capistrano/rails/assets'
|
require 'capistrano/rails/assets'
|
||||||
require 'capistrano/faster_assets'
|
|
||||||
require 'capistrano/rails/migrations'
|
require 'capistrano/rails/migrations'
|
||||||
|
|
||||||
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
|
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
|
||||||
|
53
Dockerfile
53
Dockerfile
@@ -3,39 +3,52 @@ FROM ruby:2.4.1-alpine
|
|||||||
LABEL maintainer="https://github.com/tootsuite/mastodon" \
|
LABEL maintainer="https://github.com/tootsuite/mastodon" \
|
||||||
description="A GNU Social-compatible microblogging server"
|
description="A GNU Social-compatible microblogging server"
|
||||||
|
|
||||||
ENV RAILS_ENV=production \
|
ENV UID=991 GID=991 \
|
||||||
NODE_ENV=production
|
RAILS_SERVE_STATIC_FILES=true \
|
||||||
|
RAILS_ENV=production NODE_ENV=production
|
||||||
|
|
||||||
EXPOSE 3000 4000
|
EXPOSE 3000 4000
|
||||||
|
|
||||||
WORKDIR /mastodon
|
WORKDIR /mastodon
|
||||||
|
|
||||||
COPY Gemfile Gemfile.lock package.json yarn.lock /mastodon/
|
|
||||||
|
|
||||||
RUN echo "@edge https://nl.alpinelinux.org/alpine/edge/main" >> /etc/apk/repositories \
|
RUN echo "@edge https://nl.alpinelinux.org/alpine/edge/main" >> /etc/apk/repositories \
|
||||||
&& BUILD_DEPS=" \
|
&& apk -U upgrade \
|
||||||
postgresql-dev \
|
&& apk add -t build-dependencies \
|
||||||
|
build-base \
|
||||||
libxml2-dev \
|
libxml2-dev \
|
||||||
libxslt-dev \
|
libxslt-dev \
|
||||||
build-base" \
|
postgresql-dev \
|
||||||
&& apk -U upgrade && apk add \
|
protobuf-dev \
|
||||||
$BUILD_DEPS \
|
python \
|
||||||
nodejs@edge \
|
&& apk add \
|
||||||
nodejs-npm@edge \
|
ca-certificates \
|
||||||
|
ffmpeg \
|
||||||
|
file \
|
||||||
|
git \
|
||||||
|
imagemagick@edge \
|
||||||
libpq \
|
libpq \
|
||||||
libxml2 \
|
libxml2 \
|
||||||
libxslt \
|
libxslt \
|
||||||
ffmpeg \
|
nodejs-npm@edge \
|
||||||
file \
|
nodejs@edge \
|
||||||
imagemagick@edge \
|
protobuf \
|
||||||
|
su-exec \
|
||||||
|
tini \
|
||||||
&& npm install -g npm@3 && npm install -g yarn \
|
&& npm install -g npm@3 && npm install -g yarn \
|
||||||
&& bundle install --deployment --without test development \
|
&& update-ca-certificates \
|
||||||
&& yarn --ignore-optional \
|
|
||||||
&& yarn cache clean \
|
|
||||||
&& npm -g cache clean \
|
|
||||||
&& apk del $BUILD_DEPS \
|
|
||||||
&& rm -rf /tmp/* /var/cache/apk/*
|
&& rm -rf /tmp/* /var/cache/apk/*
|
||||||
|
|
||||||
|
COPY Gemfile Gemfile.lock package.json yarn.lock /mastodon/
|
||||||
|
|
||||||
|
RUN bundle install --deployment --without test development \
|
||||||
|
&& yarn --ignore-optional --pure-lockfile
|
||||||
|
|
||||||
COPY . /mastodon
|
COPY . /mastodon
|
||||||
|
|
||||||
VOLUME /mastodon/public/system /mastodon/public/assets
|
COPY docker_entrypoint.sh /usr/local/bin/run
|
||||||
|
|
||||||
|
RUN chmod +x /usr/local/bin/run
|
||||||
|
|
||||||
|
VOLUME /mastodon/public/system /mastodon/public/assets /mastodon/public/packs
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/local/bin/run"]
|
||||||
|
160
Gemfile
160
Gemfile
@@ -3,101 +3,101 @@
|
|||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
ruby '>= 2.3.0', '< 2.5.0'
|
ruby '>= 2.3.0', '< 2.5.0'
|
||||||
|
|
||||||
gem 'pkg-config'
|
gem 'pkg-config', '~> 1.2'
|
||||||
|
|
||||||
gem 'rails', '~> 5.0.2'
|
gem 'puma', '~> 3.8'
|
||||||
gem 'sass-rails', '~> 5.0'
|
gem 'rails', '~> 5.0'
|
||||||
gem 'uglifier', '>= 1.3.0'
|
gem 'uglifier', '~> 3.2'
|
||||||
gem 'jquery-rails'
|
|
||||||
gem 'puma'
|
|
||||||
|
|
||||||
gem 'hamlit-rails'
|
gem 'hamlit-rails', '~> 0.2'
|
||||||
gem 'pg'
|
gem 'pg', '~> 0.20'
|
||||||
gem 'pghero'
|
gem 'pghero', '~> 1.7'
|
||||||
gem 'dotenv-rails'
|
gem 'dotenv-rails', '~> 2.2'
|
||||||
gem 'font-awesome-rails'
|
|
||||||
gem 'best_in_place', '~> 3.0.1'
|
|
||||||
|
|
||||||
|
gem 'aws-sdk', '~> 2.9'
|
||||||
gem 'paperclip', '~> 5.1'
|
gem 'paperclip', '~> 5.1'
|
||||||
gem 'paperclip-av-transcoder'
|
gem 'paperclip-av-transcoder', '~> 0.6'
|
||||||
gem 'aws-sdk', '>= 2.0'
|
|
||||||
|
|
||||||
gem 'addressable'
|
gem 'addressable', '~> 2.5'
|
||||||
gem 'devise'
|
gem 'bootsnap', '~> 0.3'
|
||||||
gem 'devise-two-factor'
|
gem 'cld3', '~> 3.1'
|
||||||
gem 'doorkeeper'
|
gem 'devise', '~> 4.2'
|
||||||
gem 'fast_blank'
|
gem 'devise-two-factor', '~> 3.0'
|
||||||
gem 'goldfinger'
|
gem 'doorkeeper', '~> 4.2'
|
||||||
gem 'hiredis'
|
gem 'fast_blank', '~> 1.0'
|
||||||
gem 'htmlentities'
|
gem 'goldfinger', '~> 1.2'
|
||||||
gem 'http'
|
gem 'hiredis', '~> 0.6'
|
||||||
gem 'http_accept_language'
|
gem 'redis-namespace', '~> 1.5'
|
||||||
gem 'httplog'
|
gem 'htmlentities', '~> 4.3'
|
||||||
gem 'kaminari'
|
gem 'http', '~> 2.2'
|
||||||
gem 'link_header'
|
gem 'http_accept_language', '~> 2.1'
|
||||||
gem 'nokogiri'
|
gem 'httplog', '~> 0.99'
|
||||||
gem 'oj'
|
gem 'kaminari', '~> 1.0'
|
||||||
gem 'ostatus2', '~> 1.1'
|
gem 'link_header', '~> 0.0'
|
||||||
gem 'ox'
|
gem 'nokogiri', '~> 1.7'
|
||||||
gem 'rabl'
|
gem 'oj', '~> 3.0'
|
||||||
gem 'rack-attack'
|
gem 'ostatus2', '~> 2.0'
|
||||||
gem 'rack-cors', require: 'rack/cors'
|
gem 'ox', '~> 2.5'
|
||||||
gem 'rack-timeout'
|
gem 'rabl', '~> 0.13'
|
||||||
gem 'rails-i18n'
|
gem 'rack-attack', '~> 5.0'
|
||||||
gem 'rails-settings-cached'
|
gem 'rack-cors', '~> 0.4', require: 'rack/cors'
|
||||||
gem 'redis', '~>3.2', require: ['redis', 'redis/connection/hiredis']
|
gem 'rack-timeout', '~> 0.4'
|
||||||
gem 'rqrcode'
|
gem 'rails-i18n', '~> 5.0'
|
||||||
gem 'ruby-oembed', require: 'oembed'
|
gem 'rails-settings-cached', '~> 0.6'
|
||||||
gem 'sidekiq'
|
gem 'redis', '~> 3.3', require: ['redis', 'redis/connection/hiredis']
|
||||||
gem 'sidekiq-unique-jobs'
|
gem 'rqrcode', '~> 0.10'
|
||||||
gem 'simple-navigation'
|
gem 'ruby-oembed', '~> 0.12', require: 'oembed'
|
||||||
gem 'simple_form'
|
gem 'sanitize', '~> 4.4'
|
||||||
gem 'sprockets-rails', :require => 'sprockets/railtie'
|
gem 'sidekiq', '~> 5.0'
|
||||||
gem 'statsd-instrument'
|
gem 'sidekiq-scheduler', '~> 2.1'
|
||||||
gem 'twitter-text'
|
gem 'sidekiq-unique-jobs', '~> 5.0'
|
||||||
gem 'tzinfo-data'
|
gem 'simple-navigation', '~> 4.0'
|
||||||
gem 'whatlanguage'
|
gem 'simple_form', '~> 3.4'
|
||||||
|
gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie'
|
||||||
gem 'react-rails'
|
gem 'statsd-instrument', '~> 2.1'
|
||||||
gem 'browserify-rails'
|
gem 'twitter-text', '~> 1.14'
|
||||||
gem 'autoprefixer-rails'
|
gem 'tzinfo-data', '~> 1.2017'
|
||||||
|
gem 'webpacker', '~> 1.2'
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
gem 'rspec-rails'
|
gem 'fabrication', '~> 2.16'
|
||||||
gem 'pry-rails'
|
gem 'fuubar', '~> 2.2'
|
||||||
gem 'fuubar'
|
gem 'i18n-tasks', '~> 0.9', require: false
|
||||||
gem 'fabrication'
|
gem 'pry-rails', '~> 0.3'
|
||||||
gem 'i18n-tasks', '~> 0.9.6'
|
gem 'rspec-rails', '~> 3.6'
|
||||||
end
|
end
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
gem 'capybara'
|
gem 'capybara', '~> 2.14'
|
||||||
gem 'faker'
|
gem 'faker', '~> 1.7'
|
||||||
gem 'microformats2'
|
gem 'microformats2', '~> 3.0'
|
||||||
gem 'rails-controller-testing'
|
gem 'rails-controller-testing', '~> 1.0'
|
||||||
gem 'rspec-sidekiq'
|
gem 'rspec-sidekiq', '~> 3.0'
|
||||||
gem 'simplecov', require: false
|
gem 'simplecov', '~> 0.14', require: false
|
||||||
gem 'webmock'
|
gem 'webmock', '~> 3.0'
|
||||||
|
gem 'parallel_tests', '~> 2.14'
|
||||||
end
|
end
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
gem 'rubocop', require: false
|
gem 'active_record_query_trace', '~> 1.5'
|
||||||
gem 'better_errors'
|
gem 'annotate', '~> 2.7'
|
||||||
gem 'binding_of_caller'
|
gem 'better_errors', '~> 2.1'
|
||||||
gem 'letter_opener'
|
gem 'binding_of_caller', '~> 0.7'
|
||||||
gem 'letter_opener_web'
|
gem 'bullet', '~> 5.5'
|
||||||
gem 'bullet'
|
gem 'letter_opener', '~> 1.4'
|
||||||
gem 'active_record_query_trace'
|
gem 'letter_opener_web', '~> 1.3'
|
||||||
|
gem 'rubocop', '~> 0.48', require: false
|
||||||
|
gem 'brakeman', '~> 3.6', require: false
|
||||||
|
gem 'bundler-audit', '~> 0.5', require: false
|
||||||
|
gem 'scss_lint', '~> 0.53', require: false
|
||||||
|
|
||||||
gem 'capistrano', '3.8.0'
|
gem 'capistrano', '~> 3.8'
|
||||||
gem 'capistrano-rails'
|
gem 'capistrano-rails', '~> 1.2'
|
||||||
gem 'capistrano-rbenv'
|
gem 'capistrano-rbenv', '~> 2.1'
|
||||||
gem 'capistrano-yarn'
|
gem 'capistrano-yarn', '~> 2.0'
|
||||||
gem 'capistrano-faster-assets', '~> 1.0'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
group :production do
|
group :production do
|
||||||
gem 'rails_12factor'
|
gem 'lograge', '~> 0.5'
|
||||||
gem 'redis-rails'
|
gem 'redis-rails', '~> 5.0'
|
||||||
gem 'lograge'
|
|
||||||
end
|
end
|
||||||
|
470
Gemfile.lock
470
Gemfile.lock
@@ -1,40 +1,40 @@
|
|||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (5.0.2)
|
actioncable (5.0.3)
|
||||||
actionpack (= 5.0.2)
|
actionpack (= 5.0.3)
|
||||||
nio4r (>= 1.2, < 3.0)
|
nio4r (>= 1.2, < 3.0)
|
||||||
websocket-driver (~> 0.6.1)
|
websocket-driver (~> 0.6.1)
|
||||||
actionmailer (5.0.2)
|
actionmailer (5.0.3)
|
||||||
actionpack (= 5.0.2)
|
actionpack (= 5.0.3)
|
||||||
actionview (= 5.0.2)
|
actionview (= 5.0.3)
|
||||||
activejob (= 5.0.2)
|
activejob (= 5.0.3)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
actionpack (5.0.2)
|
actionpack (5.0.3)
|
||||||
actionview (= 5.0.2)
|
actionview (= 5.0.3)
|
||||||
activesupport (= 5.0.2)
|
activesupport (= 5.0.3)
|
||||||
rack (~> 2.0)
|
rack (~> 2.0)
|
||||||
rack-test (~> 0.6.3)
|
rack-test (~> 0.6.3)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||||
actionview (5.0.2)
|
actionview (5.0.3)
|
||||||
activesupport (= 5.0.2)
|
activesupport (= 5.0.3)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubis (~> 2.7.0)
|
erubis (~> 2.7.0)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
||||||
active_record_query_trace (1.5.4)
|
active_record_query_trace (1.5.4)
|
||||||
activejob (5.0.2)
|
activejob (5.0.3)
|
||||||
activesupport (= 5.0.2)
|
activesupport (= 5.0.3)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (5.0.2)
|
activemodel (5.0.3)
|
||||||
activesupport (= 5.0.2)
|
activesupport (= 5.0.3)
|
||||||
activerecord (5.0.2)
|
activerecord (5.0.3)
|
||||||
activemodel (= 5.0.2)
|
activemodel (= 5.0.3)
|
||||||
activesupport (= 5.0.2)
|
activesupport (= 5.0.3)
|
||||||
arel (~> 7.0)
|
arel (~> 7.0)
|
||||||
activesupport (5.0.2)
|
activesupport (5.0.3)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (~> 0.7)
|
i18n (~> 0.7)
|
||||||
minitest (~> 5.1)
|
minitest (~> 5.1)
|
||||||
@@ -43,45 +43,41 @@ GEM
|
|||||||
public_suffix (~> 2.0, >= 2.0.2)
|
public_suffix (~> 2.0, >= 2.0.2)
|
||||||
airbrussh (1.2.0)
|
airbrussh (1.2.0)
|
||||||
sshkit (>= 1.6.1, != 1.7.0)
|
sshkit (>= 1.6.1, != 1.7.0)
|
||||||
|
annotate (2.7.1)
|
||||||
|
activerecord (>= 3.2, < 6.0)
|
||||||
|
rake (>= 10.4, < 12.0)
|
||||||
arel (7.1.4)
|
arel (7.1.4)
|
||||||
ast (2.3.0)
|
ast (2.3.0)
|
||||||
attr_encrypted (3.0.3)
|
attr_encrypted (3.0.3)
|
||||||
encryptor (~> 3.0.0)
|
encryptor (~> 3.0.0)
|
||||||
autoprefixer-rails (6.7.7.1)
|
|
||||||
execjs
|
|
||||||
av (0.9.0)
|
av (0.9.0)
|
||||||
cocaine (~> 0.5.3)
|
cocaine (~> 0.5.3)
|
||||||
aws-sdk (2.9.6)
|
aws-sdk (2.9.21)
|
||||||
aws-sdk-resources (= 2.9.6)
|
aws-sdk-resources (= 2.9.21)
|
||||||
aws-sdk-core (2.9.6)
|
aws-sdk-core (2.9.21)
|
||||||
aws-sigv4 (~> 1.0)
|
aws-sigv4 (~> 1.0)
|
||||||
jmespath (~> 1.0)
|
jmespath (~> 1.0)
|
||||||
aws-sdk-resources (2.9.6)
|
aws-sdk-resources (2.9.21)
|
||||||
aws-sdk-core (= 2.9.6)
|
aws-sdk-core (= 2.9.21)
|
||||||
aws-sigv4 (1.0.0)
|
aws-sigv4 (1.0.0)
|
||||||
babel-source (5.8.35)
|
|
||||||
babel-transpiler (0.7.0)
|
|
||||||
babel-source (>= 4.0, < 6)
|
|
||||||
execjs (~> 2.0)
|
|
||||||
bcrypt (3.1.11)
|
bcrypt (3.1.11)
|
||||||
best_in_place (3.0.3)
|
|
||||||
actionpack (>= 3.2)
|
|
||||||
railties (>= 3.2)
|
|
||||||
better_errors (2.1.1)
|
better_errors (2.1.1)
|
||||||
coderay (>= 1.0.0)
|
coderay (>= 1.0.0)
|
||||||
erubis (>= 2.6.6)
|
erubis (>= 2.6.6)
|
||||||
rack (>= 0.9.0)
|
rack (>= 0.9.0)
|
||||||
binding_of_caller (0.7.2)
|
binding_of_caller (0.7.2)
|
||||||
debug_inspector (>= 0.0.1)
|
debug_inspector (>= 0.0.1)
|
||||||
browserify-rails (4.1.0)
|
bootsnap (0.3.0)
|
||||||
addressable (>= 2.4.0)
|
msgpack (~> 1.0)
|
||||||
railties (>= 4.0.0, < 5.1)
|
brakeman (3.6.1)
|
||||||
sprockets (>= 3.6.0)
|
|
||||||
builder (3.2.3)
|
builder (3.2.3)
|
||||||
bullet (5.5.1)
|
bullet (5.5.1)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
uniform_notifier (~> 1.10.0)
|
uniform_notifier (~> 1.10.0)
|
||||||
capistrano (3.8.0)
|
bundler-audit (0.5.0)
|
||||||
|
bundler (~> 1.2)
|
||||||
|
thor (~> 0.18)
|
||||||
|
capistrano (3.8.1)
|
||||||
airbrussh (>= 1.0.0)
|
airbrussh (>= 1.0.0)
|
||||||
i18n
|
i18n
|
||||||
rake (>= 10.0.0)
|
rake (>= 10.0.0)
|
||||||
@@ -89,17 +85,15 @@ GEM
|
|||||||
capistrano-bundler (1.2.0)
|
capistrano-bundler (1.2.0)
|
||||||
capistrano (~> 3.1)
|
capistrano (~> 3.1)
|
||||||
sshkit (~> 1.2)
|
sshkit (~> 1.2)
|
||||||
capistrano-faster-assets (1.0.2)
|
|
||||||
capistrano (>= 3.1)
|
|
||||||
capistrano-rails (1.2.3)
|
capistrano-rails (1.2.3)
|
||||||
capistrano (~> 3.1)
|
capistrano (~> 3.1)
|
||||||
capistrano-bundler (~> 1.1)
|
capistrano-bundler (~> 1.1)
|
||||||
capistrano-rbenv (2.1.0)
|
capistrano-rbenv (2.1.1)
|
||||||
capistrano (~> 3.1)
|
capistrano (~> 3.1)
|
||||||
sshkit (~> 1.3)
|
sshkit (~> 1.3)
|
||||||
capistrano-yarn (2.0.2)
|
capistrano-yarn (2.0.2)
|
||||||
capistrano (~> 3.0)
|
capistrano (~> 3.0)
|
||||||
capybara (2.13.0)
|
capybara (2.14.0)
|
||||||
addressable
|
addressable
|
||||||
mime-types (>= 1.16)
|
mime-types (>= 1.16)
|
||||||
nokogiri (>= 1.3.3)
|
nokogiri (>= 1.3.3)
|
||||||
@@ -107,7 +101,9 @@ GEM
|
|||||||
rack-test (>= 0.5.4)
|
rack-test (>= 0.5.4)
|
||||||
xpath (~> 2.0)
|
xpath (~> 2.0)
|
||||||
chunky_png (1.3.8)
|
chunky_png (1.3.8)
|
||||||
climate_control (0.1.0)
|
cld3 (3.1.2)
|
||||||
|
ffi (>= 1.1.0, < 1.10.0)
|
||||||
|
climate_control (0.2.0)
|
||||||
cocaine (0.5.8)
|
cocaine (0.5.8)
|
||||||
climate_control (>= 0.0.3, < 1.0)
|
climate_control (>= 0.0.3, < 1.0)
|
||||||
coderay (1.1.1)
|
coderay (1.1.1)
|
||||||
@@ -116,11 +112,12 @@ GEM
|
|||||||
connection_pool (2.2.1)
|
connection_pool (2.2.1)
|
||||||
crack (0.4.3)
|
crack (0.4.3)
|
||||||
safe_yaml (~> 1.0.0)
|
safe_yaml (~> 1.0.0)
|
||||||
debug_inspector (0.0.2)
|
crass (1.0.2)
|
||||||
devise (4.2.1)
|
debug_inspector (0.0.3)
|
||||||
|
devise (4.3.0)
|
||||||
bcrypt (~> 3.0)
|
bcrypt (~> 3.0)
|
||||||
orm_adapter (~> 0.1)
|
orm_adapter (~> 0.1)
|
||||||
railties (>= 4.1.0, < 5.1)
|
railties (>= 4.1.0, < 5.2)
|
||||||
responders
|
responders
|
||||||
warden (~> 1.2.3)
|
warden (~> 1.2.3)
|
||||||
devise-two-factor (3.0.0)
|
devise-two-factor (3.0.0)
|
||||||
@@ -135,29 +132,30 @@ GEM
|
|||||||
unf (>= 0.0.5, < 1.0.0)
|
unf (>= 0.0.5, < 1.0.0)
|
||||||
doorkeeper (4.2.5)
|
doorkeeper (4.2.5)
|
||||||
railties (>= 4.2)
|
railties (>= 4.2)
|
||||||
dotenv (2.2.0)
|
dotenv (2.2.1)
|
||||||
dotenv-rails (2.2.0)
|
dotenv-rails (2.2.1)
|
||||||
dotenv (= 2.2.0)
|
dotenv (= 2.2.1)
|
||||||
railties (>= 3.2, < 5.1)
|
railties (>= 3.2, < 5.2)
|
||||||
easy_translate (0.5.0)
|
easy_translate (0.5.0)
|
||||||
json
|
json
|
||||||
thread
|
thread
|
||||||
thread_safe
|
thread_safe
|
||||||
encryptor (3.0.0)
|
encryptor (3.0.0)
|
||||||
erubis (2.7.0)
|
erubis (2.7.0)
|
||||||
|
et-orbi (1.0.4)
|
||||||
|
tzinfo
|
||||||
execjs (2.7.0)
|
execjs (2.7.0)
|
||||||
fabrication (2.16.1)
|
fabrication (2.16.1)
|
||||||
faker (1.7.3)
|
faker (1.7.3)
|
||||||
i18n (~> 0.5)
|
i18n (~> 0.5)
|
||||||
fast_blank (1.0.0)
|
fast_blank (1.0.0)
|
||||||
font-awesome-rails (4.7.0.1)
|
ffi (1.9.18)
|
||||||
railties (>= 3.2, < 5.1)
|
|
||||||
fuubar (2.2.0)
|
fuubar (2.2.0)
|
||||||
rspec-core (~> 3.0)
|
rspec-core (~> 3.0)
|
||||||
ruby-progressbar (~> 1.4)
|
ruby-progressbar (~> 1.4)
|
||||||
globalid (0.3.7)
|
globalid (0.4.0)
|
||||||
activesupport (>= 4.1.0)
|
activesupport (>= 4.2.0)
|
||||||
goldfinger (1.1.2)
|
goldfinger (1.2.0)
|
||||||
addressable (~> 2.4)
|
addressable (~> 2.4)
|
||||||
http (~> 2.0)
|
http (~> 2.0)
|
||||||
nokogiri (~> 1.6)
|
nokogiri (~> 1.6)
|
||||||
@@ -170,24 +168,25 @@ GEM
|
|||||||
activesupport (>= 4.0.1)
|
activesupport (>= 4.0.1)
|
||||||
hamlit (>= 1.2.0)
|
hamlit (>= 1.2.0)
|
||||||
railties (>= 4.0.1)
|
railties (>= 4.0.1)
|
||||||
hashdiff (0.3.2)
|
hashdiff (0.3.4)
|
||||||
highline (1.7.8)
|
highline (1.7.8)
|
||||||
hiredis (0.6.1)
|
hiredis (0.6.1)
|
||||||
htmlentities (4.3.4)
|
htmlentities (4.3.4)
|
||||||
http (2.2.1)
|
http (2.2.2)
|
||||||
addressable (~> 2.3)
|
addressable (~> 2.3)
|
||||||
http-cookie (~> 1.0)
|
http-cookie (~> 1.0)
|
||||||
http-form_data (~> 1.0.1)
|
http-form_data (~> 1.0.1)
|
||||||
http_parser.rb (~> 0.6.0)
|
http_parser.rb (~> 0.6.0)
|
||||||
http-cookie (1.0.3)
|
http-cookie (1.0.3)
|
||||||
domain_name (~> 0.5)
|
domain_name (~> 0.5)
|
||||||
http-form_data (1.0.1)
|
http-form_data (1.0.3)
|
||||||
http_accept_language (2.1.0)
|
http_accept_language (2.1.0)
|
||||||
http_parser.rb (0.6.0)
|
http_parser.rb (0.6.0)
|
||||||
httplog (0.99.2)
|
httplog (0.99.3)
|
||||||
colorize
|
colorize
|
||||||
|
rack
|
||||||
i18n (0.8.1)
|
i18n (0.8.1)
|
||||||
i18n-tasks (0.9.13)
|
i18n-tasks (0.9.15)
|
||||||
activesupport (>= 4.0.2)
|
activesupport (>= 4.0.2)
|
||||||
ast (>= 2.1.0)
|
ast (>= 2.1.0)
|
||||||
easy_translate (>= 0.5.0)
|
easy_translate (>= 0.5.0)
|
||||||
@@ -198,11 +197,7 @@ GEM
|
|||||||
rainbow (~> 2.2)
|
rainbow (~> 2.2)
|
||||||
terminal-table (>= 1.5.1)
|
terminal-table (>= 1.5.1)
|
||||||
jmespath (1.3.1)
|
jmespath (1.3.1)
|
||||||
jquery-rails (4.3.1)
|
json (2.1.0)
|
||||||
rails-dom-testing (>= 1, < 3)
|
|
||||||
railties (>= 4.2.0)
|
|
||||||
thor (>= 0.14, < 2.0)
|
|
||||||
json (2.0.3)
|
|
||||||
kaminari (1.0.1)
|
kaminari (1.0.1)
|
||||||
activesupport (>= 4.1.0)
|
activesupport (>= 4.1.0)
|
||||||
kaminari-actionview (= 1.0.1)
|
kaminari-actionview (= 1.0.1)
|
||||||
@@ -224,17 +219,16 @@ GEM
|
|||||||
letter_opener (~> 1.0)
|
letter_opener (~> 1.0)
|
||||||
railties (>= 3.2)
|
railties (>= 3.2)
|
||||||
link_header (0.0.8)
|
link_header (0.0.8)
|
||||||
lograge (0.4.1)
|
lograge (0.5.1)
|
||||||
actionpack (>= 4, < 5.1)
|
actionpack (>= 4, < 5.2)
|
||||||
activesupport (>= 4, < 5.1)
|
activesupport (>= 4, < 5.2)
|
||||||
railties (>= 4, < 5.1)
|
railties (>= 4, < 5.2)
|
||||||
loofah (2.0.3)
|
loofah (2.0.3)
|
||||||
nokogiri (>= 1.5.9)
|
nokogiri (>= 1.5.9)
|
||||||
mail (2.6.4)
|
mail (2.6.5)
|
||||||
mime-types (>= 1.16, < 4)
|
mime-types (>= 1.16, < 4)
|
||||||
method_source (0.8.2)
|
method_source (0.8.2)
|
||||||
microformats2 (2.1.0)
|
microformats2 (3.1.0)
|
||||||
activesupport
|
|
||||||
json
|
json
|
||||||
nokogiri
|
nokogiri
|
||||||
mime-types (3.1)
|
mime-types (3.1)
|
||||||
@@ -242,22 +236,26 @@ GEM
|
|||||||
mime-types-data (3.2016.0521)
|
mime-types-data (3.2016.0521)
|
||||||
mimemagic (0.3.2)
|
mimemagic (0.3.2)
|
||||||
mini_portile2 (2.1.0)
|
mini_portile2 (2.1.0)
|
||||||
minitest (5.10.1)
|
minitest (5.10.2)
|
||||||
|
msgpack (1.1.0)
|
||||||
|
multi_json (1.12.1)
|
||||||
net-scp (1.2.1)
|
net-scp (1.2.1)
|
||||||
net-ssh (>= 2.6.5)
|
net-ssh (>= 2.6.5)
|
||||||
net-ssh (4.1.0)
|
net-ssh (4.1.0)
|
||||||
nio4r (2.0.0)
|
nio4r (2.0.0)
|
||||||
nokogiri (1.7.1)
|
nokogiri (1.7.2)
|
||||||
mini_portile2 (~> 2.1.0)
|
mini_portile2 (~> 2.1.0)
|
||||||
oj (2.18.5)
|
nokogumbo (1.4.11)
|
||||||
|
nokogiri
|
||||||
|
oj (3.0.9)
|
||||||
openssl (2.0.3)
|
openssl (2.0.3)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
ostatus2 (1.1.0)
|
ostatus2 (2.0.0)
|
||||||
addressable (~> 2.4)
|
addressable (~> 2.4)
|
||||||
http (~> 2.0)
|
http (~> 2.0)
|
||||||
nokogiri (~> 1.6)
|
nokogiri (~> 1.6)
|
||||||
openssl (~> 2.0)
|
openssl (~> 2.0)
|
||||||
ox (2.4.11)
|
ox (2.5.0)
|
||||||
paperclip (5.1.0)
|
paperclip (5.1.0)
|
||||||
activemodel (>= 4.2.0)
|
activemodel (>= 4.2.0)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
@@ -267,12 +265,15 @@ GEM
|
|||||||
paperclip-av-transcoder (0.6.4)
|
paperclip-av-transcoder (0.6.4)
|
||||||
av (~> 0.9.0)
|
av (~> 0.9.0)
|
||||||
paperclip (>= 2.5.2)
|
paperclip (>= 2.5.2)
|
||||||
|
parallel (1.11.2)
|
||||||
|
parallel_tests (2.14.1)
|
||||||
|
parallel
|
||||||
parser (2.4.0.0)
|
parser (2.4.0.0)
|
||||||
ast (~> 2.2)
|
ast (~> 2.2)
|
||||||
pg (0.20.0)
|
pg (0.20.0)
|
||||||
pghero (1.6.4)
|
pghero (1.7.0)
|
||||||
activerecord
|
activerecord
|
||||||
pkg-config (1.1.7)
|
pkg-config (1.2.0)
|
||||||
powerpack (0.1.1)
|
powerpack (0.1.1)
|
||||||
pry (0.10.4)
|
pry (0.10.4)
|
||||||
coderay (~> 1.1.0)
|
coderay (~> 1.1.0)
|
||||||
@@ -284,60 +285,50 @@ GEM
|
|||||||
puma (3.8.2)
|
puma (3.8.2)
|
||||||
rabl (0.13.1)
|
rabl (0.13.1)
|
||||||
activesupport (>= 2.3.14)
|
activesupport (>= 2.3.14)
|
||||||
rack (2.0.1)
|
rack (2.0.3)
|
||||||
rack-attack (5.0.1)
|
rack-attack (5.0.1)
|
||||||
rack
|
rack
|
||||||
rack-cors (0.4.1)
|
rack-cors (0.4.1)
|
||||||
rack-protection (1.5.3)
|
rack-protection (2.0.0)
|
||||||
rack
|
rack
|
||||||
rack-test (0.6.3)
|
rack-test (0.6.3)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
rack-timeout (0.4.2)
|
rack-timeout (0.4.2)
|
||||||
rails (5.0.2)
|
rails (5.0.3)
|
||||||
actioncable (= 5.0.2)
|
actioncable (= 5.0.3)
|
||||||
actionmailer (= 5.0.2)
|
actionmailer (= 5.0.3)
|
||||||
actionpack (= 5.0.2)
|
actionpack (= 5.0.3)
|
||||||
actionview (= 5.0.2)
|
actionview (= 5.0.3)
|
||||||
activejob (= 5.0.2)
|
activejob (= 5.0.3)
|
||||||
activemodel (= 5.0.2)
|
activemodel (= 5.0.3)
|
||||||
activerecord (= 5.0.2)
|
activerecord (= 5.0.3)
|
||||||
activesupport (= 5.0.2)
|
activesupport (= 5.0.3)
|
||||||
bundler (>= 1.3.0, < 2.0)
|
bundler (>= 1.3.0, < 2.0)
|
||||||
railties (= 5.0.2)
|
railties (= 5.0.3)
|
||||||
sprockets-rails (>= 2.0.0)
|
sprockets-rails (>= 2.0.0)
|
||||||
rails-controller-testing (1.0.1)
|
rails-controller-testing (1.0.2)
|
||||||
actionpack (~> 5.x)
|
actionpack (~> 5.x, >= 5.0.1)
|
||||||
actionview (~> 5.x)
|
actionview (~> 5.x, >= 5.0.1)
|
||||||
activesupport (~> 5.x)
|
activesupport (~> 5.x)
|
||||||
rails-dom-testing (2.0.2)
|
rails-dom-testing (2.0.3)
|
||||||
activesupport (>= 4.2.0, < 6.0)
|
activesupport (>= 4.2.0)
|
||||||
nokogiri (~> 1.6)
|
nokogiri (>= 1.6)
|
||||||
rails-html-sanitizer (1.0.3)
|
rails-html-sanitizer (1.0.3)
|
||||||
loofah (~> 2.0)
|
loofah (~> 2.0)
|
||||||
rails-i18n (5.0.3)
|
rails-i18n (5.0.4)
|
||||||
i18n (~> 0.7)
|
i18n (~> 0.7)
|
||||||
railties (~> 5.0)
|
railties (~> 5.0)
|
||||||
rails-settings-cached (0.6.5)
|
rails-settings-cached (0.6.5)
|
||||||
rails (>= 4.2.0)
|
rails (>= 4.2.0)
|
||||||
rails_12factor (0.0.3)
|
railties (5.0.3)
|
||||||
rails_serve_static_assets
|
actionpack (= 5.0.3)
|
||||||
rails_stdout_logging
|
activesupport (= 5.0.3)
|
||||||
rails_serve_static_assets (0.0.5)
|
|
||||||
rails_stdout_logging (0.0.5)
|
|
||||||
railties (5.0.2)
|
|
||||||
actionpack (= 5.0.2)
|
|
||||||
activesupport (= 5.0.2)
|
|
||||||
method_source
|
method_source
|
||||||
rake (>= 0.8.7)
|
rake (>= 0.8.7)
|
||||||
thor (>= 0.18.1, < 2.0)
|
thor (>= 0.18.1, < 2.0)
|
||||||
rainbow (2.2.1)
|
rainbow (2.2.2)
|
||||||
rake (12.0.0)
|
rake
|
||||||
react-rails (1.11.0)
|
rake (11.3.0)
|
||||||
babel-transpiler (>= 0.7.0)
|
|
||||||
connection_pool
|
|
||||||
execjs
|
|
||||||
railties (>= 3.2)
|
|
||||||
tilt
|
|
||||||
redis (3.3.3)
|
redis (3.3.3)
|
||||||
redis-actionpack (5.0.1)
|
redis-actionpack (5.0.1)
|
||||||
actionpack (>= 4.0, < 6)
|
actionpack (>= 4.0, < 6)
|
||||||
@@ -346,8 +337,10 @@ GEM
|
|||||||
redis-activesupport (5.0.2)
|
redis-activesupport (5.0.2)
|
||||||
activesupport (>= 3, < 6)
|
activesupport (>= 3, < 6)
|
||||||
redis-store (~> 1.3.0)
|
redis-store (~> 1.3.0)
|
||||||
redis-rack (2.0.1)
|
redis-namespace (1.5.3)
|
||||||
rack (>= 2.0, < 3)
|
redis (~> 3.0, >= 3.0.4)
|
||||||
|
redis-rack (2.0.2)
|
||||||
|
rack (>= 1.5, < 3)
|
||||||
redis-store (>= 1.2, < 1.4)
|
redis-store (>= 1.2, < 1.4)
|
||||||
redis-rails (5.0.2)
|
redis-rails (5.0.2)
|
||||||
redis-actionpack (>= 5.0, < 6)
|
redis-actionpack (>= 5.0, < 6)
|
||||||
@@ -355,31 +348,32 @@ GEM
|
|||||||
redis-store (>= 1.2, < 2)
|
redis-store (>= 1.2, < 2)
|
||||||
redis-store (1.3.0)
|
redis-store (1.3.0)
|
||||||
redis (>= 2.2)
|
redis (>= 2.2)
|
||||||
responders (2.3.0)
|
responders (2.4.0)
|
||||||
railties (>= 4.2.0, < 5.1)
|
actionpack (>= 4.2.0, < 5.3)
|
||||||
|
railties (>= 4.2.0, < 5.3)
|
||||||
rotp (2.1.2)
|
rotp (2.1.2)
|
||||||
rqrcode (0.10.1)
|
rqrcode (0.10.1)
|
||||||
chunky_png (~> 1.0)
|
chunky_png (~> 1.0)
|
||||||
rspec-core (3.5.4)
|
rspec-core (3.6.0)
|
||||||
rspec-support (~> 3.5.0)
|
rspec-support (~> 3.6.0)
|
||||||
rspec-expectations (3.5.0)
|
rspec-expectations (3.6.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.5.0)
|
rspec-support (~> 3.6.0)
|
||||||
rspec-mocks (3.5.0)
|
rspec-mocks (3.6.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.5.0)
|
rspec-support (~> 3.6.0)
|
||||||
rspec-rails (3.5.2)
|
rspec-rails (3.6.0)
|
||||||
actionpack (>= 3.0)
|
actionpack (>= 3.0)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
railties (>= 3.0)
|
railties (>= 3.0)
|
||||||
rspec-core (~> 3.5.0)
|
rspec-core (~> 3.6.0)
|
||||||
rspec-expectations (~> 3.5.0)
|
rspec-expectations (~> 3.6.0)
|
||||||
rspec-mocks (~> 3.5.0)
|
rspec-mocks (~> 3.6.0)
|
||||||
rspec-support (~> 3.5.0)
|
rspec-support (~> 3.6.0)
|
||||||
rspec-sidekiq (3.0.0)
|
rspec-sidekiq (3.0.1)
|
||||||
rspec-core (~> 3.0, >= 3.0.0)
|
rspec-core (~> 3.0, >= 3.0.0)
|
||||||
sidekiq (>= 2.4.0)
|
sidekiq (>= 2.4.0)
|
||||||
rspec-support (3.5.0)
|
rspec-support (3.6.0)
|
||||||
rubocop (0.48.1)
|
rubocop (0.48.1)
|
||||||
parser (>= 2.3.3.1, < 3.0)
|
parser (>= 2.3.3.1, < 3.0)
|
||||||
powerpack (~> 0.1)
|
powerpack (~> 0.1)
|
||||||
@@ -388,32 +382,40 @@ GEM
|
|||||||
unicode-display_width (~> 1.0, >= 1.0.1)
|
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||||
ruby-oembed (0.12.0)
|
ruby-oembed (0.12.0)
|
||||||
ruby-progressbar (1.8.1)
|
ruby-progressbar (1.8.1)
|
||||||
|
rufus-scheduler (3.4.0)
|
||||||
|
et-orbi (~> 1.0)
|
||||||
safe_yaml (1.0.4)
|
safe_yaml (1.0.4)
|
||||||
sass (3.4.23)
|
sanitize (4.4.0)
|
||||||
sass-rails (5.0.6)
|
crass (~> 1.0.2)
|
||||||
railties (>= 4.0.0, < 6)
|
nokogiri (>= 1.4.4)
|
||||||
sass (~> 3.1)
|
nokogumbo (~> 1.4.1)
|
||||||
sprockets (>= 2.8, < 4.0)
|
sass (3.4.24)
|
||||||
sprockets-rails (>= 2.0, < 4.0)
|
scss_lint (0.53.0)
|
||||||
tilt (>= 1.1, < 3)
|
rake (>= 0.9, < 13)
|
||||||
sidekiq (4.2.10)
|
sass (~> 3.4.20)
|
||||||
|
sidekiq (5.0.0)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
connection_pool (~> 2.2, >= 2.2.0)
|
connection_pool (~> 2.2, >= 2.2.0)
|
||||||
rack-protection (>= 1.5.0)
|
rack-protection (>= 1.5.0)
|
||||||
redis (~> 3.2, >= 3.2.1)
|
redis (~> 3.3, >= 3.3.3)
|
||||||
sidekiq-unique-jobs (5.0.0)
|
sidekiq-scheduler (2.1.4)
|
||||||
sidekiq (>= 4.0)
|
redis (~> 3)
|
||||||
thor
|
rufus-scheduler (~> 3.2)
|
||||||
|
sidekiq (>= 3)
|
||||||
|
tilt (>= 1.4.0)
|
||||||
|
sidekiq-unique-jobs (5.0.8)
|
||||||
|
sidekiq (>= 4.0, <= 6.0)
|
||||||
|
thor (~> 0)
|
||||||
simple-navigation (4.0.5)
|
simple-navigation (4.0.5)
|
||||||
activesupport (>= 2.3.2)
|
activesupport (>= 2.3.2)
|
||||||
simple_form (3.4.0)
|
simple_form (3.5.0)
|
||||||
actionpack (> 4, < 5.1)
|
actionpack (> 4, < 5.2)
|
||||||
activemodel (> 4, < 5.1)
|
activemodel (> 4, < 5.2)
|
||||||
simplecov (0.14.1)
|
simplecov (0.14.1)
|
||||||
docile (~> 1.1.0)
|
docile (~> 1.1.0)
|
||||||
json (>= 1.8, < 3)
|
json (>= 1.8, < 3)
|
||||||
simplecov-html (~> 0.10.0)
|
simplecov-html (~> 0.10.0)
|
||||||
simplecov-html (0.10.0)
|
simplecov-html (0.10.1)
|
||||||
slop (3.6.0)
|
slop (3.6.0)
|
||||||
sprockets (3.7.1)
|
sprockets (3.7.1)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
@@ -427,8 +429,8 @@ GEM
|
|||||||
net-ssh (>= 2.8.0)
|
net-ssh (>= 2.8.0)
|
||||||
statsd-instrument (2.1.2)
|
statsd-instrument (2.1.2)
|
||||||
temple (0.8.0)
|
temple (0.8.0)
|
||||||
terminal-table (1.7.3)
|
terminal-table (1.8.0)
|
||||||
unicode-display_width (~> 1.1.1)
|
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||||
thor (0.19.4)
|
thor (0.19.4)
|
||||||
thread (0.2.2)
|
thread (0.2.2)
|
||||||
thread_safe (0.3.6)
|
thread_safe (0.3.6)
|
||||||
@@ -443,19 +445,22 @@ GEM
|
|||||||
execjs (>= 0.3.0, < 3)
|
execjs (>= 0.3.0, < 3)
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
unf_ext (0.0.7.3)
|
unf_ext (0.0.7.4)
|
||||||
unicode-display_width (1.1.3)
|
unicode-display_width (1.2.1)
|
||||||
uniform_notifier (1.10.0)
|
uniform_notifier (1.10.0)
|
||||||
warden (1.2.7)
|
warden (1.2.7)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
webmock (2.3.2)
|
webmock (3.0.1)
|
||||||
addressable (>= 2.3.6)
|
addressable (>= 2.3.6)
|
||||||
crack (>= 0.3.2)
|
crack (>= 0.3.2)
|
||||||
hashdiff
|
hashdiff
|
||||||
|
webpacker (1.2)
|
||||||
|
activesupport (>= 4.2)
|
||||||
|
multi_json (~> 1.2)
|
||||||
|
railties (>= 4.2)
|
||||||
websocket-driver (0.6.5)
|
websocket-driver (0.6.5)
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
websocket-extensions (0.1.2)
|
websocket-extensions (0.1.2)
|
||||||
whatlanguage (1.0.6)
|
|
||||||
xpath (2.0.0)
|
xpath (2.0.0)
|
||||||
nokogiri (~> 1.3)
|
nokogiri (~> 1.3)
|
||||||
|
|
||||||
@@ -463,86 +468,87 @@ PLATFORMS
|
|||||||
ruby
|
ruby
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
active_record_query_trace
|
active_record_query_trace (~> 1.5)
|
||||||
addressable
|
addressable (~> 2.5)
|
||||||
autoprefixer-rails
|
annotate (~> 2.7)
|
||||||
aws-sdk (>= 2.0)
|
aws-sdk (~> 2.9)
|
||||||
best_in_place (~> 3.0.1)
|
better_errors (~> 2.1)
|
||||||
better_errors
|
binding_of_caller (~> 0.7)
|
||||||
binding_of_caller
|
bootsnap (~> 0.3)
|
||||||
browserify-rails
|
brakeman (~> 3.6)
|
||||||
bullet
|
bullet (~> 5.5)
|
||||||
capistrano (= 3.8.0)
|
bundler-audit (~> 0.5)
|
||||||
capistrano-faster-assets (~> 1.0)
|
capistrano (~> 3.8)
|
||||||
capistrano-rails
|
capistrano-rails (~> 1.2)
|
||||||
capistrano-rbenv
|
capistrano-rbenv (~> 2.1)
|
||||||
capistrano-yarn
|
capistrano-yarn (~> 2.0)
|
||||||
capybara
|
capybara (~> 2.14)
|
||||||
devise
|
cld3 (~> 3.1)
|
||||||
devise-two-factor
|
devise (~> 4.2)
|
||||||
doorkeeper
|
devise-two-factor (~> 3.0)
|
||||||
dotenv-rails
|
doorkeeper (~> 4.2)
|
||||||
fabrication
|
dotenv-rails (~> 2.2)
|
||||||
faker
|
fabrication (~> 2.16)
|
||||||
fast_blank
|
faker (~> 1.7)
|
||||||
font-awesome-rails
|
fast_blank (~> 1.0)
|
||||||
fuubar
|
fuubar (~> 2.2)
|
||||||
goldfinger
|
goldfinger (~> 1.2)
|
||||||
hamlit-rails
|
hamlit-rails (~> 0.2)
|
||||||
hiredis
|
hiredis (~> 0.6)
|
||||||
htmlentities
|
htmlentities (~> 4.3)
|
||||||
http
|
http (~> 2.2)
|
||||||
http_accept_language
|
http_accept_language (~> 2.1)
|
||||||
httplog
|
httplog (~> 0.99)
|
||||||
i18n-tasks (~> 0.9.6)
|
i18n-tasks (~> 0.9)
|
||||||
jquery-rails
|
kaminari (~> 1.0)
|
||||||
kaminari
|
letter_opener (~> 1.4)
|
||||||
letter_opener
|
letter_opener_web (~> 1.3)
|
||||||
letter_opener_web
|
link_header (~> 0.0)
|
||||||
link_header
|
lograge (~> 0.5)
|
||||||
lograge
|
microformats2 (~> 3.0)
|
||||||
microformats2
|
nokogiri (~> 1.7)
|
||||||
nokogiri
|
oj (~> 3.0)
|
||||||
oj
|
ostatus2 (~> 2.0)
|
||||||
ostatus2 (~> 1.1)
|
ox (~> 2.5)
|
||||||
ox
|
|
||||||
paperclip (~> 5.1)
|
paperclip (~> 5.1)
|
||||||
paperclip-av-transcoder
|
paperclip-av-transcoder (~> 0.6)
|
||||||
pg
|
parallel_tests (~> 2.14)
|
||||||
pghero
|
pg (~> 0.20)
|
||||||
pkg-config
|
pghero (~> 1.7)
|
||||||
pry-rails
|
pkg-config (~> 1.2)
|
||||||
puma
|
pry-rails (~> 0.3)
|
||||||
rabl
|
puma (~> 3.8)
|
||||||
rack-attack
|
rabl (~> 0.13)
|
||||||
rack-cors
|
rack-attack (~> 5.0)
|
||||||
rack-timeout
|
rack-cors (~> 0.4)
|
||||||
rails (~> 5.0.2)
|
rack-timeout (~> 0.4)
|
||||||
rails-controller-testing
|
rails (~> 5.0)
|
||||||
rails-i18n
|
rails-controller-testing (~> 1.0)
|
||||||
rails-settings-cached
|
rails-i18n (~> 5.0)
|
||||||
rails_12factor
|
rails-settings-cached (~> 0.6)
|
||||||
react-rails
|
redis (~> 3.3)
|
||||||
redis (~> 3.2)
|
redis-namespace (~> 1.5)
|
||||||
redis-rails
|
redis-rails (~> 5.0)
|
||||||
rqrcode
|
rqrcode (~> 0.10)
|
||||||
rspec-rails
|
rspec-rails (~> 3.6)
|
||||||
rspec-sidekiq
|
rspec-sidekiq (~> 3.0)
|
||||||
rubocop
|
rubocop (~> 0.48)
|
||||||
ruby-oembed
|
ruby-oembed (~> 0.12)
|
||||||
sass-rails (~> 5.0)
|
sanitize (~> 4.4)
|
||||||
sidekiq
|
scss_lint (~> 0.53)
|
||||||
sidekiq-unique-jobs
|
sidekiq (~> 5.0)
|
||||||
simple-navigation
|
sidekiq-scheduler (~> 2.1)
|
||||||
simple_form
|
sidekiq-unique-jobs (~> 5.0)
|
||||||
simplecov
|
simple-navigation (~> 4.0)
|
||||||
sprockets-rails
|
simple_form (~> 3.4)
|
||||||
statsd-instrument
|
simplecov (~> 0.14)
|
||||||
twitter-text
|
sprockets-rails (~> 3.2)
|
||||||
tzinfo-data
|
statsd-instrument (~> 2.1)
|
||||||
uglifier (>= 1.3.0)
|
twitter-text (~> 1.14)
|
||||||
webmock
|
tzinfo-data (~> 1.2017)
|
||||||
whatlanguage
|
uglifier (~> 3.2)
|
||||||
|
webmock (~> 3.0)
|
||||||
|
webpacker (~> 1.2)
|
||||||
|
|
||||||
RUBY VERSION
|
RUBY VERSION
|
||||||
ruby 2.4.1p111
|
ruby 2.4.1p111
|
||||||
|
2
Procfile
2
Procfile
@@ -1,2 +1,2 @@
|
|||||||
web: bundle exec puma -C config/puma.rb
|
web: bundle exec puma -C config/puma.rb
|
||||||
worker: bundle exec sidekiq -q default -q push -q pull -q mailers
|
worker: bundle exec sidekiq
|
||||||
|
4
Procfile.dev
Normal file
4
Procfile.dev
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
web: PORT=3000 bundle exec puma -C config/puma.rb
|
||||||
|
sidekiq: PORT=3000 bundle exec sidekiq
|
||||||
|
stream: PORT=4000 yarn run start
|
||||||
|
webpack: ./bin/webpack-dev-server --host 0.0.0.0
|
@@ -13,7 +13,7 @@ An alternative implementation of the GNU social project. Based on [ActivityStrea
|
|||||||
|
|
||||||
Click on the screenshot to watch a demo of the UI:
|
Click on the screenshot to watch a demo of the UI:
|
||||||
|
|
||||||
[][youtube_demo]
|
[][youtube_demo]
|
||||||
|
|
||||||
[youtube_demo]: https://www.youtube.com/watch?v=YO1jQ8_rAMU
|
[youtube_demo]: https://www.youtube.com/watch?v=YO1jQ8_rAMU
|
||||||
|
|
||||||
@@ -48,6 +48,10 @@ If you would like, you can [support the development of this project on Patreon][
|
|||||||
- **Deployable via Docker**
|
- **Deployable via Docker**
|
||||||
You don't need to mess with dependencies and configuration if you want to try Mastodon, if you have Docker and Docker Compose the deployment is extremely easy
|
You don't need to mess with dependencies and configuration if you want to try Mastodon, if you have Docker and Docker Compose the deployment is extremely easy
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
Please follow the [development guide](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Development-guide.md) from the documentation repository.
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
There are guides in the documentation repository for [deploying on various platforms](https://github.com/tootsuite/documentation#running-mastodon).
|
There are guides in the documentation repository for [deploying on various platforms](https://github.com/tootsuite/documentation#running-mastodon).
|
||||||
|
51
Vagrantfile
vendored
51
Vagrantfile
vendored
@@ -1,6 +1,8 @@
|
|||||||
# -*- mode: ruby -*-
|
# -*- mode: ruby -*-
|
||||||
# vi: set ft=ruby :
|
# vi: set ft=ruby :
|
||||||
|
|
||||||
|
ENV["PORT"] ||= "3000"
|
||||||
|
|
||||||
$provision = <<SCRIPT
|
$provision = <<SCRIPT
|
||||||
|
|
||||||
cd /vagrant # This is where the host folder/repo is mounted
|
cd /vagrant # This is where the host folder/repo is mounted
|
||||||
@@ -10,10 +12,10 @@ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
|
|||||||
sudo apt-add-repository 'deb https://dl.yarnpkg.com/debian/ stable main'
|
sudo apt-add-repository 'deb https://dl.yarnpkg.com/debian/ stable main'
|
||||||
|
|
||||||
# Add repo for NodeJS
|
# Add repo for NodeJS
|
||||||
curl -sL https://deb.nodesource.com/setup_4.x | sudo bash -
|
curl -sL https://deb.nodesource.com/setup_6.x | sudo bash -
|
||||||
|
|
||||||
# Add firewall rule to redirect 80 to 3000 and save
|
# Add firewall rule to redirect 80 to PORT and save
|
||||||
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 3000
|
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port #{ENV["PORT"]}
|
||||||
echo iptables-persistent iptables-persistent/autosave_v4 boolean true | sudo debconf-set-selections
|
echo iptables-persistent iptables-persistent/autosave_v4 boolean true | sudo debconf-set-selections
|
||||||
echo iptables-persistent iptables-persistent/autosave_v6 boolean true | sudo debconf-set-selections
|
echo iptables-persistent iptables-persistent/autosave_v6 boolean true | sudo debconf-set-selections
|
||||||
sudo apt-get install iptables-persistent -y
|
sudo apt-get install iptables-persistent -y
|
||||||
@@ -31,47 +33,40 @@ sudo apt-get install \
|
|||||||
redis-tools \
|
redis-tools \
|
||||||
postgresql \
|
postgresql \
|
||||||
postgresql-contrib \
|
postgresql-contrib \
|
||||||
|
protobuf-compiler \
|
||||||
yarn \
|
yarn \
|
||||||
|
libprotobuf-dev \
|
||||||
libreadline-dev \
|
libreadline-dev \
|
||||||
-y
|
-y
|
||||||
|
|
||||||
# Install rbenv
|
# Install rvm
|
||||||
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
|
read RUBY_VERSION < .ruby-version
|
||||||
cd ~/.rbenv && src/configure && make -C src
|
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
|
||||||
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
|
curl -sSL https://get.rvm.io | bash -s stable --ruby=$RUBY_VERSION
|
||||||
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
|
source /home/vagrant/.rvm/scripts/rvm
|
||||||
|
|
||||||
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
|
|
||||||
|
|
||||||
export PATH="$HOME/.rbenv/bin:$PATH"
|
|
||||||
eval "$(rbenv init -)"
|
|
||||||
|
|
||||||
cd /vagrant
|
|
||||||
|
|
||||||
echo "Compiling Ruby $(cat .ruby-version): warning, this takes a while!!!"
|
|
||||||
rbenv install $(cat .ruby-version)
|
|
||||||
rbenv global $(cat .ruby-version)
|
|
||||||
|
|
||||||
# Configure database
|
# Configure database
|
||||||
sudo -u postgres createuser -U postgres vagrant -s
|
sudo -u postgres createuser -U postgres vagrant -s
|
||||||
sudo -u postgres createdb -U postgres mastodon_development
|
sudo -u postgres createdb -U postgres mastodon_development
|
||||||
|
|
||||||
# Install gems and node modules
|
# Install gems and node modules
|
||||||
gem install bundler
|
gem install bundler foreman
|
||||||
bundle install
|
bundle install
|
||||||
yarn install
|
yarn install
|
||||||
|
|
||||||
# Build Mastodon
|
# Build Mastodon
|
||||||
|
export $(cat ".env.vagrant" | xargs)
|
||||||
bundle exec rails db:setup
|
bundle exec rails db:setup
|
||||||
bundle exec rails assets:precompile
|
|
||||||
|
# Configure automatic loading of environment variable
|
||||||
|
echo 'export $(cat "/vagrant/.env.vagrant" | xargs)' >> ~/.bash_profile
|
||||||
|
|
||||||
SCRIPT
|
SCRIPT
|
||||||
|
|
||||||
$start = <<SCRIPT
|
$start = <<SCRIPT
|
||||||
|
|
||||||
cd /vagrant
|
echo 'To start server'
|
||||||
export $(cat ".env.vagrant" | xargs)
|
echo ' $ vagrant ssh -c "cd /vagrant && foreman start"'
|
||||||
rails s -d -b 0.0.0.0
|
|
||||||
|
|
||||||
SCRIPT
|
SCRIPT
|
||||||
|
|
||||||
@@ -83,7 +78,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
|||||||
|
|
||||||
config.vm.provider :virtualbox do |vb|
|
config.vm.provider :virtualbox do |vb|
|
||||||
vb.name = "mastodon"
|
vb.name = "mastodon"
|
||||||
vb.customize ["modifyvm", :id, "--memory", "1024"]
|
vb.customize ["modifyvm", :id, "--memory", "2048"]
|
||||||
|
|
||||||
# Disable VirtualBox DNS proxy to skip long-delay IPv6 resolutions.
|
# Disable VirtualBox DNS proxy to skip long-delay IPv6 resolutions.
|
||||||
# https://github.com/mitchellh/vagrant/issues/1172
|
# https://github.com/mitchellh/vagrant/issues/1172
|
||||||
@@ -113,8 +108,10 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
|||||||
config.vm.synced_folder ".", "/vagrant"
|
config.vm.synced_folder ".", "/vagrant"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Otherwise, you can access the site at http://localhost:3000
|
# Otherwise, you can access the site at http://localhost:3000 and http://localhost:4000 , http://localhost:8080
|
||||||
config.vm.network :forwarded_port, guest: 80, host: 3000
|
config.vm.network :forwarded_port, guest: 3000, host: 3000
|
||||||
|
config.vm.network :forwarded_port, guest: 4000, host: 4000
|
||||||
|
config.vm.network :forwarded_port, guest: 8080, host: 8080
|
||||||
|
|
||||||
# Full provisioning script, only runs on first 'vagrant up' or with 'vagrant provision'
|
# Full provisioning script, only runs on first 'vagrant up' or with 'vagrant provision'
|
||||||
config.vm.provision :shell, inline: $provision, privileged: false
|
config.vm.provision :shell, inline: $provision, privileged: false
|
||||||
|
3
app.json
3
app.json
@@ -94,6 +94,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"buildpacks": [
|
"buildpacks": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/heroku/heroku-buildpack-apt"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"url": "heroku/nodejs"
|
"url": "heroku/nodejs"
|
||||||
},
|
},
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 244 KiB |
@@ -1,15 +0,0 @@
|
|||||||
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
|
||||||
// listed below.
|
|
||||||
//
|
|
||||||
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
|
||||||
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
|
||||||
//
|
|
||||||
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
|
||||||
// compiled file.
|
|
||||||
//
|
|
||||||
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
|
||||||
// about supported directives.
|
|
||||||
//
|
|
||||||
//= require jquery
|
|
||||||
//= require jquery_ujs
|
|
||||||
//= require components
|
|
@@ -1,8 +0,0 @@
|
|||||||
//= require jquery
|
|
||||||
//= require jquery_ujs
|
|
||||||
//= require extras
|
|
||||||
//= require best_in_place
|
|
||||||
|
|
||||||
$(function () {
|
|
||||||
$(".best_in_place").best_in_place();
|
|
||||||
});
|
|
@@ -1,15 +0,0 @@
|
|||||||
//= require_self
|
|
||||||
//= require react_ujs
|
|
||||||
|
|
||||||
window.React = require('react');
|
|
||||||
window.ReactDOM = require('react-dom');
|
|
||||||
window.Perf = require('react-addons-perf');
|
|
||||||
|
|
||||||
if (!window.Intl) {
|
|
||||||
require('intl');
|
|
||||||
require('intl/locale-data/jsonp/en.js');
|
|
||||||
}
|
|
||||||
|
|
||||||
//= require_tree ./components
|
|
||||||
|
|
||||||
window.Mastodon = require('./components/containers/mastodon');
|
|
@@ -1,64 +0,0 @@
|
|||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
|
|
||||||
const Avatar = React.createClass({
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
src: React.PropTypes.string.isRequired,
|
|
||||||
staticSrc: React.PropTypes.string,
|
|
||||||
size: React.PropTypes.number.isRequired,
|
|
||||||
style: React.PropTypes.object,
|
|
||||||
animate: React.PropTypes.bool
|
|
||||||
},
|
|
||||||
|
|
||||||
getDefaultProps () {
|
|
||||||
return {
|
|
||||||
animate: false
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialState () {
|
|
||||||
return {
|
|
||||||
hovering: false
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
handleMouseEnter () {
|
|
||||||
this.setState({ hovering: true });
|
|
||||||
},
|
|
||||||
|
|
||||||
handleMouseLeave () {
|
|
||||||
this.setState({ hovering: false });
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { src, size, staticSrc, animate } = this.props;
|
|
||||||
const { hovering } = this.state;
|
|
||||||
|
|
||||||
const style = {
|
|
||||||
...this.props.style,
|
|
||||||
width: `${size}px`,
|
|
||||||
height: `${size}px`,
|
|
||||||
backgroundSize: `${size}px ${size}px`
|
|
||||||
};
|
|
||||||
|
|
||||||
if (hovering || animate) {
|
|
||||||
style.backgroundImage = `url(${src})`;
|
|
||||||
} else {
|
|
||||||
style.backgroundImage = `url(${staticSrc})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className='avatar'
|
|
||||||
onMouseEnter={this.handleMouseEnter}
|
|
||||||
onMouseLeave={this.handleMouseLeave}
|
|
||||||
style={style}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Avatar;
|
|
@@ -1,62 +0,0 @@
|
|||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
|
|
||||||
const Button = React.createClass({
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
text: React.PropTypes.node,
|
|
||||||
onClick: React.PropTypes.func,
|
|
||||||
disabled: React.PropTypes.bool,
|
|
||||||
block: React.PropTypes.bool,
|
|
||||||
secondary: React.PropTypes.bool,
|
|
||||||
size: React.PropTypes.number,
|
|
||||||
style: React.PropTypes.object,
|
|
||||||
children: React.PropTypes.node
|
|
||||||
},
|
|
||||||
|
|
||||||
getDefaultProps () {
|
|
||||||
return {
|
|
||||||
size: 36
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
handleClick (e) {
|
|
||||||
if (!this.props.disabled) {
|
|
||||||
this.props.onClick();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const style = {
|
|
||||||
fontFamily: 'inherit',
|
|
||||||
display: this.props.block ? 'block' : 'inline-block',
|
|
||||||
width: this.props.block ? '100%' : 'auto',
|
|
||||||
position: 'relative',
|
|
||||||
boxSizing: 'border-box',
|
|
||||||
textAlign: 'center',
|
|
||||||
border: '10px none',
|
|
||||||
fontSize: '14px',
|
|
||||||
fontWeight: '500',
|
|
||||||
letterSpacing: '0',
|
|
||||||
padding: `0 ${this.props.size / 2.25}px`,
|
|
||||||
height: `${this.props.size}px`,
|
|
||||||
cursor: 'pointer',
|
|
||||||
lineHeight: `${this.props.size}px`,
|
|
||||||
borderRadius: '4px',
|
|
||||||
textDecoration: 'none',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
textOverflow: 'ellipsis',
|
|
||||||
overflow: 'hidden'
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button className={`button ${this.props.secondary ? 'button-secondary' : ''}`} disabled={this.props.disabled} onClick={this.handleClick} style={{ ...style, ...this.props.style }}>
|
|
||||||
{this.props.text || this.props.children}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Button;
|
|
@@ -1,44 +0,0 @@
|
|||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
|
|
||||||
const outerStyle = {
|
|
||||||
position: 'absolute',
|
|
||||||
right: '0',
|
|
||||||
top: '-48px',
|
|
||||||
padding: '15px',
|
|
||||||
fontSize: '16px',
|
|
||||||
flex: '0 0 auto',
|
|
||||||
cursor: 'pointer'
|
|
||||||
};
|
|
||||||
|
|
||||||
const iconStyle = {
|
|
||||||
display: 'inline-block',
|
|
||||||
marginRight: '5px'
|
|
||||||
};
|
|
||||||
|
|
||||||
const ColumnBackButtonSlim = React.createClass({
|
|
||||||
|
|
||||||
contextTypes: {
|
|
||||||
router: React.PropTypes.object
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
handleClick () {
|
|
||||||
this.context.router.push('/');
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<div style={{ position: 'relative' }}>
|
|
||||||
<div role='button' tabIndex='0' style={outerStyle} onClick={this.handleClick} className='column-back-button'>
|
|
||||||
<i className='fa fa-fw fa-chevron-left' style={iconStyle} />
|
|
||||||
<FormattedMessage id='column_back_button.label' defaultMessage='Back' />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default ColumnBackButtonSlim;
|
|
@@ -1,65 +0,0 @@
|
|||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
import { Motion, spring } from 'react-motion';
|
|
||||||
|
|
||||||
const iconStyle = {
|
|
||||||
fontSize: '16px',
|
|
||||||
padding: '15px',
|
|
||||||
position: 'absolute',
|
|
||||||
right: '0',
|
|
||||||
top: '-48px',
|
|
||||||
cursor: 'pointer',
|
|
||||||
zIndex: '3'
|
|
||||||
};
|
|
||||||
|
|
||||||
const ColumnCollapsable = React.createClass({
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
icon: React.PropTypes.string.isRequired,
|
|
||||||
title: React.PropTypes.string,
|
|
||||||
fullHeight: React.PropTypes.number.isRequired,
|
|
||||||
children: React.PropTypes.node,
|
|
||||||
onCollapse: React.PropTypes.func
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialState () {
|
|
||||||
return {
|
|
||||||
collapsed: true
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
handleToggleCollapsed () {
|
|
||||||
const currentState = this.state.collapsed;
|
|
||||||
|
|
||||||
this.setState({ collapsed: !currentState });
|
|
||||||
|
|
||||||
if (!currentState && this.props.onCollapse) {
|
|
||||||
this.props.onCollapse();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { icon, title, fullHeight, children } = this.props;
|
|
||||||
const { collapsed } = this.state;
|
|
||||||
const collapsedClassName = collapsed ? 'collapsable-collapsed' : 'collapsable';
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ position: 'relative' }}>
|
|
||||||
<div role='button' tabIndex='0' title={`${title}`} style={{...iconStyle }} className={`column-icon ${collapsedClassName}`} onClick={this.handleToggleCollapsed}>
|
|
||||||
<i className={`fa fa-${icon}`} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Motion defaultStyle={{ opacity: 0, height: 0 }} style={{ opacity: spring(collapsed ? 0 : 100), height: spring(collapsed ? 0 : fullHeight, collapsed ? undefined : { stiffness: 150, damping: 9 }) }}>
|
|
||||||
{({ opacity, height }) =>
|
|
||||||
<div style={{ overflow: height === fullHeight ? 'auto' : 'hidden', height: `${height}px`, opacity: opacity / 100, maxHeight: '70vh' }}>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</Motion>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default ColumnCollapsable;
|
|
@@ -1,27 +0,0 @@
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
import escapeTextContentForBrowser from 'escape-html';
|
|
||||||
import emojify from '../emoji';
|
|
||||||
|
|
||||||
const DisplayName = React.createClass({
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
account: ImmutablePropTypes.map.isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const displayName = this.props.account.get('display_name').length === 0 ? this.props.account.get('username') : this.props.account.get('display_name');
|
|
||||||
const displayNameHTML = { __html: emojify(escapeTextContentForBrowser(displayName)) };
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span style={{ display: 'block', maxWidth: '100%', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' }} className='display-name'>
|
|
||||||
<strong style={{ fontWeight: '500' }} dangerouslySetInnerHTML={displayNameHTML} /> <span style={{ fontSize: '14px' }}>@{this.props.account.get('acct')}</span>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default DisplayName;
|
|
@@ -1,72 +0,0 @@
|
|||||||
import Dropdown, { DropdownTrigger, DropdownContent } from 'react-simple-dropdown';
|
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
|
|
||||||
const DropdownMenu = React.createClass({
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
icon: React.PropTypes.string.isRequired,
|
|
||||||
items: React.PropTypes.array.isRequired,
|
|
||||||
size: React.PropTypes.number.isRequired,
|
|
||||||
direction: React.PropTypes.string
|
|
||||||
},
|
|
||||||
|
|
||||||
getDefaultProps () {
|
|
||||||
return {
|
|
||||||
direction: 'left'
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
setRef (c) {
|
|
||||||
this.dropdown = c;
|
|
||||||
},
|
|
||||||
|
|
||||||
handleClick (i, e) {
|
|
||||||
const { action } = this.props.items[i];
|
|
||||||
|
|
||||||
if (typeof action === 'function') {
|
|
||||||
e.preventDefault();
|
|
||||||
action();
|
|
||||||
this.dropdown.hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
renderItem (item, i) {
|
|
||||||
if (item === null) {
|
|
||||||
return <li key={i} className='dropdown__sep' />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { text, action, href = '#' } = item;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<li key={i}>
|
|
||||||
<a href={href} target='_blank' rel='noopener' onClick={this.handleClick.bind(this, i)}>
|
|
||||||
{text}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { icon, items, size, direction } = this.props;
|
|
||||||
const directionClass = (direction === "left") ? "dropdown__left" : "dropdown__right";
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dropdown ref={this.setRef}>
|
|
||||||
<DropdownTrigger className='icon-button' style={{ fontSize: `${size}px`, width: `${size}px`, lineHeight: `${size}px` }}>
|
|
||||||
<i className={`fa fa-fw fa-${icon}`} style={{ verticalAlign: 'middle' }} />
|
|
||||||
</DropdownTrigger>
|
|
||||||
|
|
||||||
<DropdownContent className={directionClass} style={{ lineHeight: '18px', textAlign: 'left' }}>
|
|
||||||
<ul>
|
|
||||||
{items.map(this.renderItem)}
|
|
||||||
</ul>
|
|
||||||
</DropdownContent>
|
|
||||||
</Dropdown>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default DropdownMenu;
|
|
@@ -1,28 +0,0 @@
|
|||||||
const Permalink = React.createClass({
|
|
||||||
|
|
||||||
contextTypes: {
|
|
||||||
router: React.PropTypes.object
|
|
||||||
},
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
href: React.PropTypes.string.isRequired,
|
|
||||||
to: React.PropTypes.string.isRequired,
|
|
||||||
children: React.PropTypes.node
|
|
||||||
},
|
|
||||||
|
|
||||||
handleClick (e) {
|
|
||||||
if (e.button === 0) {
|
|
||||||
e.preventDefault();
|
|
||||||
this.context.router.push(this.props.to);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { href, children, ...other } = this.props;
|
|
||||||
|
|
||||||
return <a href={href} onClick={this.handleClick} {...other}>{children}</a>;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Permalink;
|
|
@@ -1,18 +0,0 @@
|
|||||||
import { injectIntl, FormattedRelative } from 'react-intl';
|
|
||||||
|
|
||||||
const RelativeTimestamp = ({ intl, timestamp }) => {
|
|
||||||
const date = new Date(timestamp);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<time dateTime={timestamp} title={intl.formatDate(date, { hour12: false, year: 'numeric', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' })}>
|
|
||||||
<FormattedRelative value={date} />
|
|
||||||
</time>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
RelativeTimestamp.propTypes = {
|
|
||||||
intl: React.PropTypes.object.isRequired,
|
|
||||||
timestamp: React.PropTypes.string.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default injectIntl(RelativeTimestamp);
|
|
@@ -1,117 +0,0 @@
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import Avatar from './avatar';
|
|
||||||
import RelativeTimestamp from './relative_timestamp';
|
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
import DisplayName from './display_name';
|
|
||||||
import MediaGallery from './media_gallery';
|
|
||||||
import VideoPlayer from './video_player';
|
|
||||||
import AttachmentList from './attachment_list';
|
|
||||||
import StatusContent from './status_content';
|
|
||||||
import StatusActionBar from './status_action_bar';
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
import emojify from '../emoji';
|
|
||||||
import escapeTextContentForBrowser from 'escape-html';
|
|
||||||
|
|
||||||
const Status = React.createClass({
|
|
||||||
|
|
||||||
contextTypes: {
|
|
||||||
router: React.PropTypes.object
|
|
||||||
},
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
status: ImmutablePropTypes.map,
|
|
||||||
wrapped: React.PropTypes.bool,
|
|
||||||
onReply: React.PropTypes.func,
|
|
||||||
onFavourite: React.PropTypes.func,
|
|
||||||
onReblog: React.PropTypes.func,
|
|
||||||
onDelete: React.PropTypes.func,
|
|
||||||
onOpenMedia: React.PropTypes.func,
|
|
||||||
onOpenVideo: React.PropTypes.func,
|
|
||||||
onBlock: React.PropTypes.func,
|
|
||||||
me: React.PropTypes.number,
|
|
||||||
boostModal: React.PropTypes.bool,
|
|
||||||
autoPlayGif: React.PropTypes.bool,
|
|
||||||
muted: React.PropTypes.bool
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
handleClick () {
|
|
||||||
const { status } = this.props;
|
|
||||||
this.context.router.push(`/statuses/${status.getIn(['reblog', 'id'], status.get('id'))}`);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleAccountClick (id, e) {
|
|
||||||
if (e.button === 0) {
|
|
||||||
e.preventDefault();
|
|
||||||
this.context.router.push(`/accounts/${id}`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
let media = '';
|
|
||||||
const { status, ...other } = this.props;
|
|
||||||
|
|
||||||
if (status === null) {
|
|
||||||
return <div />;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status.get('reblog', null) !== null && typeof status.get('reblog') === 'object') {
|
|
||||||
let displayName = status.getIn(['account', 'display_name']);
|
|
||||||
|
|
||||||
if (displayName.length === 0) {
|
|
||||||
displayName = status.getIn(['account', 'username']);
|
|
||||||
}
|
|
||||||
|
|
||||||
const displayNameHTML = { __html: emojify(escapeTextContentForBrowser(displayName)) };
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ cursor: 'default' }}>
|
|
||||||
<div className='status__prepend'>
|
|
||||||
<div style={{ position: 'absolute', 'left': '-26px'}}><i className='fa fa-fw fa-retweet' /></div>
|
|
||||||
<FormattedMessage id='status.reblogged_by' defaultMessage='{name} reblogged' values={{ name: <a onClick={this.handleAccountClick.bind(this, status.getIn(['account', 'id']))} href={status.getIn(['account', 'url'])} className='status__display-name muted'><strong dangerouslySetInnerHTML={displayNameHTML} /></a> }} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Status {...other} wrapped={true} status={status.get('reblog')} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status.get('media_attachments').size > 0 && !this.props.muted) {
|
|
||||||
if (status.get('media_attachments').some(item => item.get('type') === 'unknown')) {
|
|
||||||
|
|
||||||
} else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
|
|
||||||
media = <VideoPlayer media={status.getIn(['media_attachments', 0])} sensitive={status.get('sensitive')} onOpenVideo={this.props.onOpenVideo} />;
|
|
||||||
} else {
|
|
||||||
media = <MediaGallery media={status.get('media_attachments')} sensitive={status.get('sensitive')} height={110} onOpenMedia={this.props.onOpenMedia} autoPlayGif={this.props.autoPlayGif} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={this.props.muted ? 'status muted' : 'status'}>
|
|
||||||
<div style={{ fontSize: '15px' }}>
|
|
||||||
<div style={{ float: 'right', fontSize: '14px' }}>
|
|
||||||
<a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener'><RelativeTimestamp timestamp={status.get('created_at')} /></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a onClick={this.handleAccountClick.bind(this, status.getIn(['account', 'id']))} href={status.getIn(['account', 'url'])} className='status__display-name' style={{ display: 'block', maxWidth: '100%', paddingRight: '25px' }}>
|
|
||||||
<div className='status__avatar' style={{ position: 'absolute', left: '10px', top: '10px', width: '48px', height: '48px' }}>
|
|
||||||
<Avatar src={status.getIn(['account', 'avatar'])} staticSrc={status.getIn(['account', 'avatar_static'])} size={48} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<DisplayName account={status.get('account')} />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<StatusContent status={status} onClick={this.handleClick} />
|
|
||||||
|
|
||||||
{media}
|
|
||||||
|
|
||||||
<StatusActionBar {...this.props} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Status;
|
|
@@ -1,124 +0,0 @@
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
import IconButton from './icon_button';
|
|
||||||
import DropdownMenu from './dropdown_menu';
|
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
delete: { id: 'status.delete', defaultMessage: 'Delete' },
|
|
||||||
mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' },
|
|
||||||
mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },
|
|
||||||
block: { id: 'account.block', defaultMessage: 'Block @{name}' },
|
|
||||||
reply: { id: 'status.reply', defaultMessage: 'Reply' },
|
|
||||||
replyAll: { id: 'status.replyAll', defaultMessage: 'Reply to thread' },
|
|
||||||
reblog: { id: 'status.reblog', defaultMessage: 'Reblog' },
|
|
||||||
favourite: { id: 'status.favourite', defaultMessage: 'Favourite' },
|
|
||||||
open: { id: 'status.open', defaultMessage: 'Expand this status' },
|
|
||||||
report: { id: 'status.report', defaultMessage: 'Report @{name}' }
|
|
||||||
});
|
|
||||||
|
|
||||||
const StatusActionBar = React.createClass({
|
|
||||||
|
|
||||||
contextTypes: {
|
|
||||||
router: React.PropTypes.object
|
|
||||||
},
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
status: ImmutablePropTypes.map.isRequired,
|
|
||||||
onReply: React.PropTypes.func,
|
|
||||||
onFavourite: React.PropTypes.func,
|
|
||||||
onReblog: React.PropTypes.func,
|
|
||||||
onDelete: React.PropTypes.func,
|
|
||||||
onMention: React.PropTypes.func,
|
|
||||||
onMute: React.PropTypes.func,
|
|
||||||
onBlock: React.PropTypes.func,
|
|
||||||
onReport: React.PropTypes.func,
|
|
||||||
me: React.PropTypes.number.isRequired,
|
|
||||||
intl: React.PropTypes.object.isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
handleReplyClick () {
|
|
||||||
this.props.onReply(this.props.status, this.context.router);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleFavouriteClick () {
|
|
||||||
this.props.onFavourite(this.props.status);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleReblogClick (e) {
|
|
||||||
this.props.onReblog(this.props.status, e);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleDeleteClick () {
|
|
||||||
this.props.onDelete(this.props.status);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleMentionClick () {
|
|
||||||
this.props.onMention(this.props.status.get('account'), this.context.router);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleMuteClick () {
|
|
||||||
this.props.onMute(this.props.status.get('account'));
|
|
||||||
},
|
|
||||||
|
|
||||||
handleBlockClick () {
|
|
||||||
this.props.onBlock(this.props.status.get('account'));
|
|
||||||
},
|
|
||||||
|
|
||||||
handleOpen () {
|
|
||||||
this.context.router.push(`/statuses/${this.props.status.get('id')}`);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleReport () {
|
|
||||||
this.props.onReport(this.props.status);
|
|
||||||
this.context.router.push('/report');
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { status, me, intl } = this.props;
|
|
||||||
let menu = [];
|
|
||||||
|
|
||||||
menu.push({ text: intl.formatMessage(messages.open), action: this.handleOpen });
|
|
||||||
menu.push(null);
|
|
||||||
|
|
||||||
if (status.getIn(['account', 'id']) === me) {
|
|
||||||
menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick });
|
|
||||||
} else {
|
|
||||||
menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });
|
|
||||||
menu.push(null);
|
|
||||||
menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
|
|
||||||
menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
|
|
||||||
menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });
|
|
||||||
}
|
|
||||||
|
|
||||||
let reblogIcon = 'retweet';
|
|
||||||
if (status.get('visibility') === 'direct') reblogIcon = 'envelope';
|
|
||||||
else if (status.get('visibility') === 'private') reblogIcon = 'lock';
|
|
||||||
let reply_icon;
|
|
||||||
let reply_title;
|
|
||||||
if (status.get('in_reply_to_id', null) === null) {
|
|
||||||
reply_icon = "reply";
|
|
||||||
reply_title = intl.formatMessage(messages.reply);
|
|
||||||
} else {
|
|
||||||
reply_icon = "reply-all";
|
|
||||||
reply_title = intl.formatMessage(messages.replyAll);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ marginTop: '10px', overflow: 'hidden' }}>
|
|
||||||
<div style={{ float: 'left', marginRight: '18px'}}><IconButton title={reply_title} icon={reply_icon} onClick={this.handleReplyClick} /></div>
|
|
||||||
<div style={{ float: 'left', marginRight: '18px'}}><IconButton disabled={status.get('visibility') === 'private' || status.get('visibility') === 'direct'} active={status.get('reblogged')} title={intl.formatMessage(messages.reblog)} icon={reblogIcon} onClick={this.handleReblogClick} /></div>
|
|
||||||
<div style={{ float: 'left', marginRight: '18px'}}><IconButton animate={true} active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} activeStyle={{ color: '#ca8f04' }} /></div>
|
|
||||||
|
|
||||||
<div style={{ width: '18px', height: '18px', float: 'left' }}>
|
|
||||||
<DropdownMenu items={menu} icon='ellipsis-h' size={18} direction="right" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default injectIntl(StatusActionBar);
|
|
@@ -1,128 +0,0 @@
|
|||||||
import Status from './status';
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
import { ScrollContainer } from 'react-router-scroll';
|
|
||||||
import StatusContainer from '../containers/status_container';
|
|
||||||
import LoadMore from './load_more';
|
|
||||||
|
|
||||||
const StatusList = React.createClass({
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
statusIds: ImmutablePropTypes.list.isRequired,
|
|
||||||
onScrollToBottom: React.PropTypes.func,
|
|
||||||
onScrollToTop: React.PropTypes.func,
|
|
||||||
onScroll: React.PropTypes.func,
|
|
||||||
trackScroll: React.PropTypes.bool,
|
|
||||||
isLoading: React.PropTypes.bool,
|
|
||||||
isUnread: React.PropTypes.bool,
|
|
||||||
hasMore: React.PropTypes.bool,
|
|
||||||
prepend: React.PropTypes.node,
|
|
||||||
emptyMessage: React.PropTypes.node
|
|
||||||
},
|
|
||||||
|
|
||||||
getDefaultProps () {
|
|
||||||
return {
|
|
||||||
trackScroll: true
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
handleScroll (e) {
|
|
||||||
const { scrollTop, scrollHeight, clientHeight } = e.target;
|
|
||||||
const offset = scrollHeight - scrollTop - clientHeight;
|
|
||||||
this._oldScrollPosition = scrollHeight - scrollTop;
|
|
||||||
|
|
||||||
if (250 > offset && this.props.onScrollToBottom && !this.props.isLoading) {
|
|
||||||
this.props.onScrollToBottom();
|
|
||||||
} else if (scrollTop < 100 && this.props.onScrollToTop) {
|
|
||||||
this.props.onScrollToTop();
|
|
||||||
} else if (this.props.onScroll) {
|
|
||||||
this.props.onScroll();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount () {
|
|
||||||
this.attachScrollListener();
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidUpdate (prevProps) {
|
|
||||||
if (this.node.scrollTop > 0 && (prevProps.statusIds.size < this.props.statusIds.size && prevProps.statusIds.first() !== this.props.statusIds.first() && !!this._oldScrollPosition)) {
|
|
||||||
this.node.scrollTop = this.node.scrollHeight - this._oldScrollPosition;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
componentWillUnmount () {
|
|
||||||
this.detachScrollListener();
|
|
||||||
},
|
|
||||||
|
|
||||||
attachScrollListener () {
|
|
||||||
this.node.addEventListener('scroll', this.handleScroll);
|
|
||||||
},
|
|
||||||
|
|
||||||
detachScrollListener () {
|
|
||||||
this.node.removeEventListener('scroll', this.handleScroll);
|
|
||||||
},
|
|
||||||
|
|
||||||
setRef (c) {
|
|
||||||
this.node = c;
|
|
||||||
},
|
|
||||||
|
|
||||||
handleLoadMore (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
this.props.onScrollToBottom();
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { statusIds, onScrollToBottom, trackScroll, isLoading, isUnread, hasMore, prepend, emptyMessage } = this.props;
|
|
||||||
|
|
||||||
let loadMore = '';
|
|
||||||
let scrollableArea = '';
|
|
||||||
let unread = '';
|
|
||||||
|
|
||||||
if (!isLoading && statusIds.size > 0 && hasMore) {
|
|
||||||
loadMore = <LoadMore onClick={this.handleLoadMore} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isUnread) {
|
|
||||||
unread = <div className='status-list__unread-indicator' />;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLoading || statusIds.size > 0 || !emptyMessage) {
|
|
||||||
scrollableArea = (
|
|
||||||
<div className='scrollable' ref={this.setRef}>
|
|
||||||
{unread}
|
|
||||||
|
|
||||||
<div>
|
|
||||||
{prepend}
|
|
||||||
|
|
||||||
{statusIds.map((statusId) => {
|
|
||||||
return <StatusContainer key={statusId} id={statusId} />;
|
|
||||||
})}
|
|
||||||
|
|
||||||
{loadMore}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
scrollableArea = (
|
|
||||||
<div className='empty-column-indicator' ref={this.setRef}>
|
|
||||||
{emptyMessage}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trackScroll) {
|
|
||||||
return (
|
|
||||||
<ScrollContainer scrollKey='status-list'>
|
|
||||||
{scrollableArea}
|
|
||||||
</ScrollContainer>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return scrollableArea;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default StatusList;
|
|
@@ -1,252 +0,0 @@
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
import IconButton from './icon_button';
|
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|
||||||
import { isIOS } from '../is_mobile';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
toggle_sound: { id: 'video_player.toggle_sound', defaultMessage: 'Toggle sound' },
|
|
||||||
toggle_visible: { id: 'video_player.toggle_visible', defaultMessage: 'Toggle visibility' },
|
|
||||||
expand_video: { id: 'video_player.expand', defaultMessage: 'Expand video' },
|
|
||||||
expand_video: { id: 'video_player.video_error', defaultMessage: 'Video could not be played' }
|
|
||||||
});
|
|
||||||
|
|
||||||
const videoStyle = {
|
|
||||||
position: 'relative',
|
|
||||||
zIndex: '1',
|
|
||||||
width: '100%',
|
|
||||||
height: '100%',
|
|
||||||
objectFit: 'cover',
|
|
||||||
top: '50%',
|
|
||||||
transform: 'translateY(-50%)'
|
|
||||||
};
|
|
||||||
|
|
||||||
const muteStyle = {
|
|
||||||
position: 'absolute',
|
|
||||||
top: '4px',
|
|
||||||
right: '4px',
|
|
||||||
color: 'white',
|
|
||||||
textShadow: "0px 1px 1px black, 1px 0px 1px black",
|
|
||||||
opacity: '0.8',
|
|
||||||
zIndex: '5'
|
|
||||||
};
|
|
||||||
|
|
||||||
const coverStyle = {
|
|
||||||
marginTop: '8px',
|
|
||||||
textAlign: 'center',
|
|
||||||
height: '100%',
|
|
||||||
cursor: 'pointer',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
flexDirection: 'column',
|
|
||||||
position: 'relative'
|
|
||||||
};
|
|
||||||
|
|
||||||
const spoilerSpanStyle = {
|
|
||||||
display: 'block',
|
|
||||||
fontSize: '14px'
|
|
||||||
};
|
|
||||||
|
|
||||||
const spoilerSubSpanStyle = {
|
|
||||||
display: 'block',
|
|
||||||
fontSize: '11px',
|
|
||||||
fontWeight: '500'
|
|
||||||
};
|
|
||||||
|
|
||||||
const spoilerButtonStyle = {
|
|
||||||
position: 'absolute',
|
|
||||||
top: '4px',
|
|
||||||
left: '4px',
|
|
||||||
color: 'white',
|
|
||||||
textShadow: "0px 1px 1px black, 1px 0px 1px black",
|
|
||||||
zIndex: '100'
|
|
||||||
};
|
|
||||||
|
|
||||||
const expandButtonStyle = {
|
|
||||||
position: 'absolute',
|
|
||||||
bottom: '4px',
|
|
||||||
right: '4px',
|
|
||||||
color: 'white',
|
|
||||||
textShadow: "0px 1px 1px black, 1px 0px 1px black",
|
|
||||||
zIndex: '100'
|
|
||||||
};
|
|
||||||
|
|
||||||
const VideoPlayer = React.createClass({
|
|
||||||
propTypes: {
|
|
||||||
media: ImmutablePropTypes.map.isRequired,
|
|
||||||
width: React.PropTypes.number,
|
|
||||||
height: React.PropTypes.number,
|
|
||||||
sensitive: React.PropTypes.bool,
|
|
||||||
intl: React.PropTypes.object.isRequired,
|
|
||||||
autoplay: React.PropTypes.bool,
|
|
||||||
onOpenVideo: React.PropTypes.func.isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
getDefaultProps () {
|
|
||||||
return {
|
|
||||||
width: 239,
|
|
||||||
height: 110
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialState () {
|
|
||||||
return {
|
|
||||||
visible: !this.props.sensitive,
|
|
||||||
preview: true,
|
|
||||||
muted: true,
|
|
||||||
hasAudio: true,
|
|
||||||
videoError: false
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
handleClick () {
|
|
||||||
this.setState({ muted: !this.state.muted });
|
|
||||||
},
|
|
||||||
|
|
||||||
handleVideoClick (e) {
|
|
||||||
e.stopPropagation();
|
|
||||||
|
|
||||||
const node = ReactDOM.findDOMNode(this).querySelector('video');
|
|
||||||
|
|
||||||
if (node.paused) {
|
|
||||||
node.play();
|
|
||||||
} else {
|
|
||||||
node.pause();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
handleOpen () {
|
|
||||||
this.setState({ preview: !this.state.preview });
|
|
||||||
},
|
|
||||||
|
|
||||||
handleVisibility () {
|
|
||||||
this.setState({
|
|
||||||
visible: !this.state.visible,
|
|
||||||
preview: true
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
handleExpand () {
|
|
||||||
this.video.pause();
|
|
||||||
this.props.onOpenVideo(this.props.media, this.video.currentTime);
|
|
||||||
},
|
|
||||||
|
|
||||||
setRef (c) {
|
|
||||||
this.video = c;
|
|
||||||
},
|
|
||||||
|
|
||||||
handleLoadedData () {
|
|
||||||
if (('WebkitAppearance' in document.documentElement.style && this.video.audioTracks.length === 0) || this.video.mozHasAudio === false) {
|
|
||||||
this.setState({ hasAudio: false });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
handleVideoError () {
|
|
||||||
this.setState({ videoError: true });
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount () {
|
|
||||||
if (!this.video) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.video.addEventListener('loadeddata', this.handleLoadedData);
|
|
||||||
this.video.addEventListener('error', this.handleVideoError);
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidUpdate () {
|
|
||||||
if (!this.video) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.video.addEventListener('loadeddata', this.handleLoadedData);
|
|
||||||
this.video.addEventListener('error', this.handleVideoError);
|
|
||||||
},
|
|
||||||
|
|
||||||
componentWillUnmount () {
|
|
||||||
if (!this.video) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.video.removeEventListener('loadeddata', this.handleLoadedData);
|
|
||||||
this.video.removeEventListener('error', this.handleVideoError);
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { media, intl, width, height, sensitive, autoplay } = this.props;
|
|
||||||
|
|
||||||
let spoilerButton = (
|
|
||||||
<div style={{...spoilerButtonStyle, display: !this.state.visible ? 'none' : 'block'}} >
|
|
||||||
<IconButton overlay title={intl.formatMessage(messages.toggle_visible)} icon={this.state.visible ? 'eye' : 'eye-slash'} onClick={this.handleVisibility} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
let expandButton = (
|
|
||||||
<div style={expandButtonStyle} >
|
|
||||||
<IconButton overlay title={intl.formatMessage(messages.expand_video)} icon='expand' onClick={this.handleExpand} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
let muteButton = '';
|
|
||||||
|
|
||||||
if (this.state.hasAudio) {
|
|
||||||
muteButton = (
|
|
||||||
<div style={muteStyle}>
|
|
||||||
<IconButton overlay title={intl.formatMessage(messages.toggle_sound)} icon={this.state.muted ? 'volume-off' : 'volume-up'} onClick={this.handleClick} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.state.visible) {
|
|
||||||
if (sensitive) {
|
|
||||||
return (
|
|
||||||
<div role='button' tabIndex='0' style={{...coverStyle, width: `${width}px`, height: `${height}px` }} className='media-spoiler' onClick={this.handleVisibility}>
|
|
||||||
{spoilerButton}
|
|
||||||
<span style={spoilerSpanStyle}><FormattedMessage id='status.sensitive_warning' defaultMessage='Sensitive content' /></span>
|
|
||||||
<span style={spoilerSubSpanStyle}><FormattedMessage id='status.sensitive_toggle' defaultMessage='Click to view' /></span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<div role='button' tabIndex='0' style={{...coverStyle, width: `${width}px`, height: `${height}px` }} className='media-spoiler' onClick={this.handleVisibility}>
|
|
||||||
{spoilerButton}
|
|
||||||
<span style={spoilerSpanStyle}><FormattedMessage id='status.media_hidden' defaultMessage='Media hidden' /></span>
|
|
||||||
<span style={spoilerSubSpanStyle}><FormattedMessage id='status.sensitive_toggle' defaultMessage='Click to view' /></span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.preview && !autoplay) {
|
|
||||||
return (
|
|
||||||
<div role='button' tabIndex='0' style={{ cursor: 'pointer', position: 'relative', marginTop: '8px', width: `${width}px`, height: `${height}px`, background: `url(${media.get('preview_url')}) no-repeat center`, backgroundSize: 'cover' }} onClick={this.handleOpen}>
|
|
||||||
{spoilerButton}
|
|
||||||
<div style={{ position: 'absolute', top: '50%', left: '50%', fontSize: '36px', transform: 'translate(-50%, -50%)', padding: '5px', borderRadius: '100px', color: 'rgba(255, 255, 255, 0.8)' }}><i className='fa fa-play' /></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.videoError) {
|
|
||||||
return (
|
|
||||||
<div style={{...coverStyle, width: `${width}px`, height: `${height}px` }} className='video-error-cover' >
|
|
||||||
<span style={spoilerSpanStyle}><FormattedMessage id='video_player.video_error' defaultMessage='Video could not be played' /></span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ cursor: 'default', marginTop: '8px', overflow: 'hidden', width: `${width}px`, height: `${height}px`, boxSizing: 'border-box', background: '#000', position: 'relative' }}>
|
|
||||||
{spoilerButton}
|
|
||||||
{muteButton}
|
|
||||||
{expandButton}
|
|
||||||
<video role='button' tabIndex='0' ref={this.setRef} src={media.get('url')} autoPlay={!isIOS()} loop={true} muted={this.state.muted} style={videoStyle} onClick={this.handleVideoClick} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default injectIntl(VideoPlayer);
|
|
@@ -1,97 +0,0 @@
|
|||||||
import { connect } from 'react-redux';
|
|
||||||
import Status from '../components/status';
|
|
||||||
import { makeGetStatus } from '../selectors';
|
|
||||||
import {
|
|
||||||
replyCompose,
|
|
||||||
mentionCompose
|
|
||||||
} from '../actions/compose';
|
|
||||||
import {
|
|
||||||
reblog,
|
|
||||||
favourite,
|
|
||||||
unreblog,
|
|
||||||
unfavourite
|
|
||||||
} from '../actions/interactions';
|
|
||||||
import {
|
|
||||||
blockAccount,
|
|
||||||
muteAccount
|
|
||||||
} from '../actions/accounts';
|
|
||||||
import { deleteStatus } from '../actions/statuses';
|
|
||||||
import { initReport } from '../actions/reports';
|
|
||||||
import { openModal } from '../actions/modal';
|
|
||||||
import { createSelector } from 'reselect'
|
|
||||||
import { isMobile } from '../is_mobile'
|
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
|
||||||
const getStatus = makeGetStatus();
|
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => ({
|
|
||||||
status: getStatus(state, props.id),
|
|
||||||
me: state.getIn(['meta', 'me']),
|
|
||||||
boostModal: state.getIn(['meta', 'boost_modal']),
|
|
||||||
autoPlayGif: state.getIn(['meta', 'auto_play_gif'])
|
|
||||||
});
|
|
||||||
|
|
||||||
return mapStateToProps;
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
|
||||||
|
|
||||||
onReply (status, router) {
|
|
||||||
dispatch(replyCompose(status, router));
|
|
||||||
},
|
|
||||||
|
|
||||||
onModalReblog (status) {
|
|
||||||
dispatch(reblog(status));
|
|
||||||
},
|
|
||||||
|
|
||||||
onReblog (status, e) {
|
|
||||||
if (status.get('reblogged')) {
|
|
||||||
dispatch(unreblog(status));
|
|
||||||
} else {
|
|
||||||
if (e.shiftKey || !this.boostModal) {
|
|
||||||
this.onModalReblog(status);
|
|
||||||
} else {
|
|
||||||
dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onFavourite (status) {
|
|
||||||
if (status.get('favourited')) {
|
|
||||||
dispatch(unfavourite(status));
|
|
||||||
} else {
|
|
||||||
dispatch(favourite(status));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onDelete (status) {
|
|
||||||
dispatch(deleteStatus(status.get('id')));
|
|
||||||
},
|
|
||||||
|
|
||||||
onMention (account, router) {
|
|
||||||
dispatch(mentionCompose(account, router));
|
|
||||||
},
|
|
||||||
|
|
||||||
onOpenMedia (media, index) {
|
|
||||||
dispatch(openModal('MEDIA', { media, index }));
|
|
||||||
},
|
|
||||||
|
|
||||||
onOpenVideo (media, time) {
|
|
||||||
dispatch(openModal('VIDEO', { media, time }));
|
|
||||||
},
|
|
||||||
|
|
||||||
onBlock (account) {
|
|
||||||
dispatch(blockAccount(account.get('id')));
|
|
||||||
},
|
|
||||||
|
|
||||||
onReport (status) {
|
|
||||||
dispatch(initReport(status.get('account'), status));
|
|
||||||
},
|
|
||||||
|
|
||||||
onMute (account) {
|
|
||||||
dispatch(muteAccount(account.get('id')));
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(makeMapStateToProps, mapDispatchToProps)(Status);
|
|
@@ -1,73 +0,0 @@
|
|||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import InnerHeader from '../../account/components/header';
|
|
||||||
import ActionBar from '../../account/components/action_bar';
|
|
||||||
import MissingIndicator from '../../../components/missing_indicator';
|
|
||||||
|
|
||||||
const Header = React.createClass({
|
|
||||||
contextTypes: {
|
|
||||||
router: React.PropTypes.object
|
|
||||||
},
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
account: ImmutablePropTypes.map,
|
|
||||||
me: React.PropTypes.number.isRequired,
|
|
||||||
onFollow: React.PropTypes.func.isRequired,
|
|
||||||
onBlock: React.PropTypes.func.isRequired,
|
|
||||||
onMention: React.PropTypes.func.isRequired,
|
|
||||||
onReport: React.PropTypes.func.isRequired,
|
|
||||||
onMute: React.PropTypes.func.isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
handleFollow () {
|
|
||||||
this.props.onFollow(this.props.account);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleBlock () {
|
|
||||||
this.props.onBlock(this.props.account);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleMention () {
|
|
||||||
this.props.onMention(this.props.account, this.context.router);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleReport () {
|
|
||||||
this.props.onReport(this.props.account);
|
|
||||||
this.context.router.push('/report');
|
|
||||||
},
|
|
||||||
|
|
||||||
handleMute() {
|
|
||||||
this.props.onMute(this.props.account);
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { account, me } = this.props;
|
|
||||||
|
|
||||||
if (account === null) {
|
|
||||||
return <MissingIndicator />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<InnerHeader
|
|
||||||
account={account}
|
|
||||||
me={me}
|
|
||||||
onFollow={this.handleFollow}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ActionBar
|
|
||||||
account={account}
|
|
||||||
me={me}
|
|
||||||
onBlock={this.handleBlock}
|
|
||||||
onMention={this.handleMention}
|
|
||||||
onReport={this.handleReport}
|
|
||||||
onMute={this.handleMute}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Header;
|
|
@@ -1,60 +0,0 @@
|
|||||||
import { connect } from 'react-redux';
|
|
||||||
import { makeGetAccount } from '../../../selectors';
|
|
||||||
import Header from '../components/header';
|
|
||||||
import {
|
|
||||||
followAccount,
|
|
||||||
unfollowAccount,
|
|
||||||
blockAccount,
|
|
||||||
unblockAccount,
|
|
||||||
muteAccount,
|
|
||||||
unmuteAccount
|
|
||||||
} from '../../../actions/accounts';
|
|
||||||
import { mentionCompose } from '../../../actions/compose';
|
|
||||||
import { initReport } from '../../../actions/reports';
|
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
|
||||||
const getAccount = makeGetAccount();
|
|
||||||
|
|
||||||
const mapStateToProps = (state, { accountId }) => ({
|
|
||||||
account: getAccount(state, Number(accountId)),
|
|
||||||
me: state.getIn(['meta', 'me'])
|
|
||||||
});
|
|
||||||
|
|
||||||
return mapStateToProps;
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
|
||||||
onFollow (account) {
|
|
||||||
if (account.getIn(['relationship', 'following'])) {
|
|
||||||
dispatch(unfollowAccount(account.get('id')));
|
|
||||||
} else {
|
|
||||||
dispatch(followAccount(account.get('id')));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onBlock (account) {
|
|
||||||
if (account.getIn(['relationship', 'blocking'])) {
|
|
||||||
dispatch(unblockAccount(account.get('id')));
|
|
||||||
} else {
|
|
||||||
dispatch(blockAccount(account.get('id')));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onMention (account, router) {
|
|
||||||
dispatch(mentionCompose(account, router));
|
|
||||||
},
|
|
||||||
|
|
||||||
onReport (account) {
|
|
||||||
dispatch(initReport(account));
|
|
||||||
},
|
|
||||||
|
|
||||||
onMute (account) {
|
|
||||||
if (account.getIn(['relationship', 'muting'])) {
|
|
||||||
dispatch(unmuteAccount(account.get('id')));
|
|
||||||
} else {
|
|
||||||
dispatch(muteAccount(account.get('id')));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(makeMapStateToProps, mapDispatchToProps)(Header);
|
|
@@ -1,16 +0,0 @@
|
|||||||
import Avatar from '../../../components/avatar';
|
|
||||||
import DisplayName from '../../../components/display_name';
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
|
|
||||||
const AutosuggestAccount = ({ account }) => (
|
|
||||||
<div style={{ overflow: 'hidden' }} className='autosuggest-account'>
|
|
||||||
<div style={{ float: 'left', marginRight: '5px' }}><Avatar src={account.get('avatar')} staticSrc={account.get('avatar_static')} size={18} /></div>
|
|
||||||
<DisplayName account={account} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
AutosuggestAccount.propTypes = {
|
|
||||||
account: ImmutablePropTypes.map.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AutosuggestAccount;
|
|
@@ -1,15 +0,0 @@
|
|||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
import DisplayName from '../../../components/display_name';
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
|
|
||||||
const AutosuggestStatus = ({ status }) => (
|
|
||||||
<div style={{ overflow: 'hidden' }} className='autosuggest-status'>
|
|
||||||
<FormattedMessage id='search.status_by' defaultMessage='Status by {name}' values={{ name: <strong>@{status.getIn(['account', 'acct'])}</strong> }} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
AutosuggestStatus.propTypes = {
|
|
||||||
status: ImmutablePropTypes.map.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AutosuggestStatus;
|
|
@@ -1,27 +0,0 @@
|
|||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
|
|
||||||
const CharacterCounter = React.createClass({
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
text: React.PropTypes.string.isRequired,
|
|
||||||
max: React.PropTypes.number.isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
checkRemainingText (diff) {
|
|
||||||
if (diff <= 0) {
|
|
||||||
return <span style={{ fontSize: '16px', cursor: 'default', color: '#ff5050' }}>{diff}</span>;
|
|
||||||
}
|
|
||||||
return <span style={{ fontSize: '16px', cursor: 'default' }}>{diff}</span>;
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const diff = this.props.max - this.props.text.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, "_").length;
|
|
||||||
|
|
||||||
return this.checkRemainingText(diff);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default CharacterCounter;
|
|
@@ -1,58 +0,0 @@
|
|||||||
import Dropdown, { DropdownTrigger, DropdownContent } from 'react-simple-dropdown';
|
|
||||||
import EmojiPicker from 'emojione-picker';
|
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' }
|
|
||||||
});
|
|
||||||
|
|
||||||
const settings = {
|
|
||||||
imageType: 'png',
|
|
||||||
sprites: false,
|
|
||||||
imagePathPNG: '/emoji/'
|
|
||||||
};
|
|
||||||
|
|
||||||
const style = {
|
|
||||||
position: 'absolute',
|
|
||||||
right: '5px',
|
|
||||||
top: '5px'
|
|
||||||
};
|
|
||||||
|
|
||||||
const EmojiPickerDropdown = React.createClass({
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
intl: React.PropTypes.object.isRequired,
|
|
||||||
onPickEmoji: React.PropTypes.func.isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
setRef (c) {
|
|
||||||
this.dropdown = c;
|
|
||||||
},
|
|
||||||
|
|
||||||
handleChange (data) {
|
|
||||||
this.dropdown.hide();
|
|
||||||
this.props.onPickEmoji(data);
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { intl } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dropdown ref={this.setRef} style={style}>
|
|
||||||
<DropdownTrigger className='emoji-button' title={intl.formatMessage(messages.emoji)} style={{ fontSize: `24px`, width: `24px`, lineHeight: `24px`, display: 'block', marginLeft: '2px' }}>
|
|
||||||
<img draggable="false" className="emojione" alt="🙂" src="/emoji/1f602.svg" />
|
|
||||||
</DropdownTrigger>
|
|
||||||
|
|
||||||
<DropdownContent className='dropdown__left light'>
|
|
||||||
<EmojiPicker emojione={settings} onChange={this.handleChange} search={true} />
|
|
||||||
</DropdownContent>
|
|
||||||
</Dropdown>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default injectIntl(EmojiPickerDropdown);
|
|
@@ -1,32 +0,0 @@
|
|||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import Avatar from '../../../components/avatar';
|
|
||||||
import IconButton from '../../../components/icon_button';
|
|
||||||
import DisplayName from '../../../components/display_name';
|
|
||||||
import Permalink from '../../../components/permalink';
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
import { Link } from 'react-router';
|
|
||||||
|
|
||||||
const NavigationBar = React.createClass({
|
|
||||||
propTypes: {
|
|
||||||
account: ImmutablePropTypes.map.isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<div className='navigation-bar'>
|
|
||||||
<Permalink href={this.props.account.get('url')} to={`/accounts/${this.props.account.get('id')}`} style={{ textDecoration: 'none' }}><Avatar src={this.props.account.get('avatar')} animate size={40} /></Permalink>
|
|
||||||
|
|
||||||
<div style={{ flex: '1 1 auto', marginLeft: '8px' }}>
|
|
||||||
<strong style={{ fontWeight: '500', display: 'block' }}>{this.props.account.get('acct')}</strong>
|
|
||||||
<a href='/settings/profile' style={{ color: 'inherit', textDecoration: 'none' }}><FormattedMessage id='navigation_bar.edit_profile' defaultMessage='Edit profile' /></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default NavigationBar;
|
|
@@ -1,31 +0,0 @@
|
|||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
|
|
||||||
const TextIconButton = React.createClass({
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
label: React.PropTypes.string.isRequired,
|
|
||||||
title: React.PropTypes.string,
|
|
||||||
active: React.PropTypes.bool,
|
|
||||||
onClick: React.PropTypes.func.isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
handleClick (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
this.props.onClick();
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { label, title, active } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button title={title} aria-label={title} className={`text-icon-button ${active ? 'active' : ''}`} onClick={this.handleClick}>
|
|
||||||
{label}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default TextIconButton;
|
|
@@ -1,53 +0,0 @@
|
|||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
import IconButton from '../../../components/icon_button';
|
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
upload: { id: 'upload_button.label', defaultMessage: 'Add media' }
|
|
||||||
});
|
|
||||||
|
|
||||||
const iconStyle = {
|
|
||||||
lineHeight: '27px',
|
|
||||||
height: null
|
|
||||||
};
|
|
||||||
|
|
||||||
const UploadButton = React.createClass({
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
disabled: React.PropTypes.bool,
|
|
||||||
onSelectFile: React.PropTypes.func.isRequired,
|
|
||||||
style: React.PropTypes.object,
|
|
||||||
resetFileKey: React.PropTypes.number,
|
|
||||||
intl: React.PropTypes.object.isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
handleChange (e) {
|
|
||||||
if (e.target.files.length > 0) {
|
|
||||||
this.props.onSelectFile(e.target.files);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
handleClick () {
|
|
||||||
this.fileElement.click();
|
|
||||||
},
|
|
||||||
|
|
||||||
setRef (c) {
|
|
||||||
this.fileElement = c;
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { intl, resetFileKey, disabled } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={this.props.style}>
|
|
||||||
<IconButton icon='camera' title={intl.formatMessage(messages.upload)} disabled={disabled} onClick={this.handleClick} style={iconStyle} size={18} inverted />
|
|
||||||
<input key={resetFileKey} ref={this.setRef} type='file' multiple={false} onChange={this.handleChange} disabled={disabled} style={{ display: 'none' }} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default injectIntl(UploadButton);
|
|
@@ -1,47 +0,0 @@
|
|||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import IconButton from '../../../components/icon_button';
|
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
|
||||||
import UploadProgressContainer from '../containers/upload_progress_container';
|
|
||||||
import { Motion, spring } from 'react-motion';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
undo: { id: 'upload_form.undo', defaultMessage: 'Undo' }
|
|
||||||
});
|
|
||||||
|
|
||||||
const UploadForm = React.createClass({
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
media: ImmutablePropTypes.list.isRequired,
|
|
||||||
onRemoveFile: React.PropTypes.func.isRequired,
|
|
||||||
intl: React.PropTypes.object.isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { intl, media } = this.props;
|
|
||||||
|
|
||||||
const uploads = media.map(attachment =>
|
|
||||||
<div key={attachment.get('id')} style={{ margin: '5px', flex: '1 1 0' }}>
|
|
||||||
<Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12 }) }}>
|
|
||||||
{({ scale }) =>
|
|
||||||
<div style={{ transform: `translateZ(0) scale(${scale})`, width: '100%', height: '100px', borderRadius: '4px', background: `url(${attachment.get('preview_url')}) no-repeat center`, backgroundSize: 'cover' }}>
|
|
||||||
<IconButton icon='times' title={intl.formatMessage(messages.undo)} size={36} onClick={this.props.onRemoveFile.bind(this, attachment.get('id'))} />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</Motion>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ overflow: 'hidden' }}>
|
|
||||||
<UploadProgressContainer />
|
|
||||||
<div style={{ display: 'flex', padding: '5px' }}>{uploads}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default injectIntl(UploadForm);
|
|
@@ -1,78 +0,0 @@
|
|||||||
import { connect } from 'react-redux';
|
|
||||||
import ComposeForm from '../components/compose_form';
|
|
||||||
import { uploadCompose } from '../../../actions/compose';
|
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
import {
|
|
||||||
changeCompose,
|
|
||||||
submitCompose,
|
|
||||||
clearComposeSuggestions,
|
|
||||||
fetchComposeSuggestions,
|
|
||||||
selectComposeSuggestion,
|
|
||||||
changeComposeSpoilerText,
|
|
||||||
insertEmojiCompose
|
|
||||||
} from '../../../actions/compose';
|
|
||||||
|
|
||||||
const getMentionedUsernames = createSelector(state => state.getIn(['compose', 'text']), text => text.match(/(?:^|[^\/\w])@([a-z0-9_]+@[a-z0-9\.\-]+)/ig));
|
|
||||||
|
|
||||||
const getMentionedDomains = createSelector(getMentionedUsernames, mentionedUsernamesWithDomains => {
|
|
||||||
return mentionedUsernamesWithDomains !== null ? [...new Set(mentionedUsernamesWithDomains.map(item => item.split('@')[2]))] : [];
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => {
|
|
||||||
const mentionedUsernames = getMentionedUsernames(state);
|
|
||||||
const mentionedUsernamesWithDomains = getMentionedDomains(state);
|
|
||||||
|
|
||||||
return {
|
|
||||||
text: state.getIn(['compose', 'text']),
|
|
||||||
suggestion_token: state.getIn(['compose', 'suggestion_token']),
|
|
||||||
suggestions: state.getIn(['compose', 'suggestions']),
|
|
||||||
spoiler: state.getIn(['compose', 'spoiler']),
|
|
||||||
spoiler_text: state.getIn(['compose', 'spoiler_text']),
|
|
||||||
privacy: state.getIn(['compose', 'privacy']),
|
|
||||||
focusDate: state.getIn(['compose', 'focusDate']),
|
|
||||||
preselectDate: state.getIn(['compose', 'preselectDate']),
|
|
||||||
is_submitting: state.getIn(['compose', 'is_submitting']),
|
|
||||||
is_uploading: state.getIn(['compose', 'is_uploading']),
|
|
||||||
me: state.getIn(['compose', 'me']),
|
|
||||||
needsPrivacyWarning: (state.getIn(['compose', 'privacy']) === 'private' || state.getIn(['compose', 'privacy']) === 'direct') && mentionedUsernames !== null,
|
|
||||||
mentionedDomains: mentionedUsernamesWithDomains
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
|
||||||
|
|
||||||
onChange (text) {
|
|
||||||
dispatch(changeCompose(text));
|
|
||||||
},
|
|
||||||
|
|
||||||
onSubmit () {
|
|
||||||
dispatch(submitCompose());
|
|
||||||
},
|
|
||||||
|
|
||||||
onClearSuggestions () {
|
|
||||||
dispatch(clearComposeSuggestions());
|
|
||||||
},
|
|
||||||
|
|
||||||
onFetchSuggestions (token) {
|
|
||||||
dispatch(fetchComposeSuggestions(token));
|
|
||||||
},
|
|
||||||
|
|
||||||
onSuggestionSelected (position, token, accountId) {
|
|
||||||
dispatch(selectComposeSuggestion(position, token, accountId));
|
|
||||||
},
|
|
||||||
|
|
||||||
onChangeSpoilerText (checked) {
|
|
||||||
dispatch(changeComposeSpoilerText(checked));
|
|
||||||
},
|
|
||||||
|
|
||||||
onPaste (files) {
|
|
||||||
dispatch(uploadCompose(files));
|
|
||||||
},
|
|
||||||
|
|
||||||
onPickEmoji (position, data) {
|
|
||||||
dispatch(insertEmojiCompose(position, data));
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(ComposeForm);
|
|
@@ -1,58 +0,0 @@
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import Permalink from '../../../components/permalink';
|
|
||||||
import Avatar from '../../../components/avatar';
|
|
||||||
import DisplayName from '../../../components/display_name';
|
|
||||||
import emojify from '../../../emoji';
|
|
||||||
import IconButton from '../../../components/icon_button';
|
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
authorize: { id: 'follow_request.authorize', defaultMessage: 'Authorize' },
|
|
||||||
reject: { id: 'follow_request.reject', defaultMessage: 'Reject' }
|
|
||||||
});
|
|
||||||
|
|
||||||
const outerStyle = {
|
|
||||||
padding: '14px 10px'
|
|
||||||
};
|
|
||||||
|
|
||||||
const panelStyle = {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
padding: '10px 0'
|
|
||||||
};
|
|
||||||
|
|
||||||
const btnStyle = {
|
|
||||||
flex: '1 1 auto',
|
|
||||||
textAlign: 'center'
|
|
||||||
};
|
|
||||||
|
|
||||||
const AccountAuthorize = ({ intl, account, onAuthorize, onReject }) => {
|
|
||||||
const content = { __html: emojify(account.get('note')) };
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div style={outerStyle}>
|
|
||||||
<Permalink href={account.get('url')} to={`/accounts/${account.get('id')}`} className='detailed-status__display-name' style={{ display: 'block', overflow: 'hidden', marginBottom: '15px' }}>
|
|
||||||
<div style={{ float: 'left', marginRight: '10px' }}><Avatar src={account.get('avatar')} staticSrc={account.get('avatar_static')} size={48} /></div>
|
|
||||||
<DisplayName account={account} />
|
|
||||||
</Permalink>
|
|
||||||
|
|
||||||
<div style={{ fontSize: '14px' }} className='account__header__content' dangerouslySetInnerHTML={content} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='account--panel' style={panelStyle}>
|
|
||||||
<div style={btnStyle}><IconButton title={intl.formatMessage(messages.authorize)} icon='check' onClick={onAuthorize} /></div>
|
|
||||||
<div style={btnStyle}><IconButton title={intl.formatMessage(messages.reject)} icon='times' onClick={onReject} /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
AccountAuthorize.propTypes = {
|
|
||||||
account: ImmutablePropTypes.map.isRequired,
|
|
||||||
onAuthorize: React.PropTypes.func.isRequired,
|
|
||||||
onReject: React.PropTypes.func.isRequired,
|
|
||||||
intl: React.PropTypes.object.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default injectIntl(AccountAuthorize);
|
|
@@ -1,60 +0,0 @@
|
|||||||
import Column from '../ui/components/column';
|
|
||||||
import ColumnLink from '../ui/components/column_link';
|
|
||||||
import { Link } from 'react-router';
|
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
|
|
||||||
public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },
|
|
||||||
community_timeline: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },
|
|
||||||
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
|
|
||||||
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
|
||||||
sign_out: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
|
|
||||||
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },
|
|
||||||
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
|
|
||||||
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
|
|
||||||
info: { id: 'navigation_bar.info', defaultMessage: 'Extended information' }
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
me: state.getIn(['accounts', state.getIn(['meta', 'me'])])
|
|
||||||
});
|
|
||||||
|
|
||||||
const GettingStarted = ({ intl, me }) => {
|
|
||||||
let followRequests = '';
|
|
||||||
|
|
||||||
if (me.get('locked')) {
|
|
||||||
followRequests = <ColumnLink icon='users' text={intl.formatMessage(messages.follow_requests)} to='/follow_requests' />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Column icon='asterisk' heading={intl.formatMessage(messages.heading)}>
|
|
||||||
<div style={{ position: 'relative' }}>
|
|
||||||
<ColumnLink icon='users' text={intl.formatMessage(messages.community_timeline)} to='/timelines/public/local' />
|
|
||||||
<ColumnLink icon='globe' text={intl.formatMessage(messages.public_timeline)} to='/timelines/public' />
|
|
||||||
<ColumnLink icon='cog' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />
|
|
||||||
<ColumnLink icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />
|
|
||||||
{followRequests}
|
|
||||||
<ColumnLink icon='ban' text={intl.formatMessage(messages.blocks)} to='/blocks' />
|
|
||||||
<ColumnLink icon='volume-off' text={intl.formatMessage(messages.mutes)} to='/mutes' />
|
|
||||||
<ColumnLink icon='book' text={intl.formatMessage(messages.info)} href='/about/more' />
|
|
||||||
<ColumnLink icon='sign-out' text={intl.formatMessage(messages.sign_out)} href='/auth/sign_out' method='delete' />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='scrollable optionally-scrollable' style={{ display: 'flex', flexDirection: 'column' }}>
|
|
||||||
<div className='static-content getting-started'>
|
|
||||||
<p><FormattedMessage id='getting_started.open_source_notice' defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}. {apps}.' values={{ github: <a href="https://github.com/tootsuite/mastodon" target="_blank">tootsuite/mastodon</a>, apps: <a href="https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md" target="_blank"><FormattedMessage id='getting_started.apps' defaultMessage='Various apps are available' /></a> }} /></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Column>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
GettingStarted.propTypes = {
|
|
||||||
intl: React.PropTypes.object.isRequired,
|
|
||||||
me: ImmutablePropTypes.map.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(injectIntl(GettingStarted));
|
|
@@ -1,41 +0,0 @@
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
|
|
||||||
const style = {
|
|
||||||
display: 'block',
|
|
||||||
fontFamily: 'inherit',
|
|
||||||
marginBottom: '10px',
|
|
||||||
padding: '7px 0',
|
|
||||||
boxSizing: 'border-box',
|
|
||||||
width: '100%'
|
|
||||||
};
|
|
||||||
|
|
||||||
const SettingText = React.createClass({
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
settings: ImmutablePropTypes.map.isRequired,
|
|
||||||
settingKey: React.PropTypes.array.isRequired,
|
|
||||||
label: React.PropTypes.string.isRequired,
|
|
||||||
onChange: React.PropTypes.func.isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
handleChange (e) {
|
|
||||||
this.props.onChange(this.props.settingKey, e.target.value)
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { settings, settingKey, label } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<input
|
|
||||||
style={style}
|
|
||||||
className='setting-text'
|
|
||||||
value={settings.getIn(settingKey)}
|
|
||||||
onChange={this.handleChange}
|
|
||||||
placeholder={label}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default SettingText;
|
|
@@ -1,39 +0,0 @@
|
|||||||
import { connect } from 'react-redux';
|
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
import StatusListContainer from '../ui/containers/status_list_container';
|
|
||||||
import Column from '../ui/components/column';
|
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|
||||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
|
||||||
import { Link } from 'react-router';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
title: { id: 'column.home', defaultMessage: 'Home' }
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
hasUnread: state.getIn(['timelines', 'home', 'unread']) > 0
|
|
||||||
});
|
|
||||||
|
|
||||||
const HomeTimeline = React.createClass({
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
intl: React.PropTypes.object.isRequired,
|
|
||||||
hasUnread: React.PropTypes.bool
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { intl, hasUnread } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Column icon='home' active={hasUnread} heading={intl.formatMessage(messages.title)}>
|
|
||||||
<ColumnSettingsContainer />
|
|
||||||
<StatusListContainer {...this.props} type='home' emptyMessage={<FormattedMessage id='empty_column.home' defaultMessage="You aren't following anyone yet. Visit {public} or use search to get started and meet other users." values={{ public: <Link to='/timelines/public'><FormattedMessage id='empty_column.home.public_timeline' defaultMessage='the public timeline' /></Link> }} />} />
|
|
||||||
</Column>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(injectIntl(HomeTimeline));
|
|
@@ -1,32 +0,0 @@
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import Toggle from 'react-toggle';
|
|
||||||
|
|
||||||
const labelStyle = {
|
|
||||||
display: 'block',
|
|
||||||
lineHeight: '24px',
|
|
||||||
verticalAlign: 'middle'
|
|
||||||
};
|
|
||||||
|
|
||||||
const labelSpanStyle = {
|
|
||||||
display: 'inline-block',
|
|
||||||
verticalAlign: 'middle',
|
|
||||||
marginBottom: '14px',
|
|
||||||
marginLeft: '8px'
|
|
||||||
};
|
|
||||||
|
|
||||||
const SettingToggle = ({ settings, settingKey, label, onChange, htmlFor = '' }) => (
|
|
||||||
<label htmlFor={htmlFor} style={labelStyle}>
|
|
||||||
<Toggle checked={settings.getIn(settingKey)} onChange={(e) => onChange(settingKey, e.target.checked)} />
|
|
||||||
<span className='setting-toggle' style={labelSpanStyle}>{label}</span>
|
|
||||||
</label>
|
|
||||||
);
|
|
||||||
|
|
||||||
SettingToggle.propTypes = {
|
|
||||||
settings: ImmutablePropTypes.map.isRequired,
|
|
||||||
settingKey: React.PropTypes.array.isRequired,
|
|
||||||
label: React.PropTypes.node.isRequired,
|
|
||||||
onChange: React.PropTypes.func.isRequired,
|
|
||||||
htmlFor: React.PropTypes.string
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SettingToggle;
|
|
@@ -1,90 +0,0 @@
|
|||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
import IconButton from '../../../components/icon_button';
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import DropdownMenu from '../../../components/dropdown_menu';
|
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
delete: { id: 'status.delete', defaultMessage: 'Delete' },
|
|
||||||
mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' },
|
|
||||||
reply: { id: 'status.reply', defaultMessage: 'Reply' },
|
|
||||||
reblog: { id: 'status.reblog', defaultMessage: 'Reblog' },
|
|
||||||
favourite: { id: 'status.favourite', defaultMessage: 'Favourite' },
|
|
||||||
report: { id: 'status.report', defaultMessage: 'Report @{name}' }
|
|
||||||
});
|
|
||||||
|
|
||||||
const ActionBar = React.createClass({
|
|
||||||
|
|
||||||
contextTypes: {
|
|
||||||
router: React.PropTypes.object
|
|
||||||
},
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
status: ImmutablePropTypes.map.isRequired,
|
|
||||||
onReply: React.PropTypes.func.isRequired,
|
|
||||||
onReblog: React.PropTypes.func.isRequired,
|
|
||||||
onFavourite: React.PropTypes.func.isRequired,
|
|
||||||
onDelete: React.PropTypes.func.isRequired,
|
|
||||||
onMention: React.PropTypes.func.isRequired,
|
|
||||||
onReport: React.PropTypes.func,
|
|
||||||
me: React.PropTypes.number.isRequired,
|
|
||||||
intl: React.PropTypes.object.isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
handleReplyClick () {
|
|
||||||
this.props.onReply(this.props.status);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleReblogClick (e) {
|
|
||||||
this.props.onReblog(this.props.status, e);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleFavouriteClick () {
|
|
||||||
this.props.onFavourite(this.props.status);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleDeleteClick () {
|
|
||||||
this.props.onDelete(this.props.status);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleMentionClick () {
|
|
||||||
this.props.onMention(this.props.status.get('account'), this.context.router);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleReport () {
|
|
||||||
this.props.onReport(this.props.status);
|
|
||||||
this.context.router.push('/report');
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { status, me, intl } = this.props;
|
|
||||||
|
|
||||||
let menu = [];
|
|
||||||
|
|
||||||
if (me === status.getIn(['account', 'id'])) {
|
|
||||||
menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick });
|
|
||||||
} else {
|
|
||||||
menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });
|
|
||||||
menu.push(null);
|
|
||||||
menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });
|
|
||||||
}
|
|
||||||
|
|
||||||
let reblogIcon = 'retweet';
|
|
||||||
if (status.get('visibility') === 'direct') reblogIcon = 'envelope';
|
|
||||||
else if (status.get('visibility') === 'private') reblogIcon = 'lock';
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='detailed-status__action-bar'>
|
|
||||||
<div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_id', null) === null ? 'reply' : 'reply-all'} onClick={this.handleReplyClick} /></div>
|
|
||||||
<div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton disabled={status.get('visibility') === 'direct' || status.get('visibility') === 'private'} active={status.get('reblogged')} title={intl.formatMessage(messages.reblog)} icon={reblogIcon} onClick={this.handleReblogClick} /></div>
|
|
||||||
<div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton animate={true} active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} activeStyle={{ color: '#ca8f04' }} /></div>
|
|
||||||
<div style={{ flex: '1 1 auto', textAlign: 'center' }}><DropdownMenu size={18} icon='ellipsis-h' items={menu} direction="left" /></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default injectIntl(ActionBar);
|
|
@@ -1,69 +0,0 @@
|
|||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
|
|
||||||
const contentStyle = {
|
|
||||||
flex: '1 1 auto',
|
|
||||||
padding: '8px',
|
|
||||||
paddingLeft: '14px',
|
|
||||||
overflow: 'hidden'
|
|
||||||
};
|
|
||||||
|
|
||||||
const imageStyle = {
|
|
||||||
display: 'block',
|
|
||||||
width: '100%',
|
|
||||||
height: 'auto',
|
|
||||||
margin: '0',
|
|
||||||
borderRadius: '4px 0 0 4px'
|
|
||||||
};
|
|
||||||
|
|
||||||
const hostStyle = {
|
|
||||||
display: 'block',
|
|
||||||
marginTop: '5px',
|
|
||||||
fontSize: '13px'
|
|
||||||
};
|
|
||||||
|
|
||||||
const getHostname = url => {
|
|
||||||
const parser = document.createElement('a');
|
|
||||||
parser.href = url;
|
|
||||||
return parser.hostname;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Card = React.createClass({
|
|
||||||
propTypes: {
|
|
||||||
card: ImmutablePropTypes.map
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { card } = this.props;
|
|
||||||
|
|
||||||
if (card === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let image = '';
|
|
||||||
|
|
||||||
if (card.get('image')) {
|
|
||||||
image = (
|
|
||||||
<div className='status-card__image'>
|
|
||||||
<img src={card.get('image')} alt={card.get('title')} style={imageStyle} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<a href={card.get('url')} className='status-card' target='_blank' rel='noopener'>
|
|
||||||
{image}
|
|
||||||
|
|
||||||
<div className='status-card__content' style={contentStyle}>
|
|
||||||
<strong className='status-card__title' title={card.get('title')}>{card.get('title')}</strong>
|
|
||||||
<p className='status-card__description'>{card.get('description').substring(0, 50)}</p>
|
|
||||||
<span className='status-card__host' style={hostStyle}>{getHostname(card.get('url'))}</span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Card;
|
|
@@ -1,37 +0,0 @@
|
|||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
|
|
||||||
const ColumnHeader = React.createClass({
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
icon: React.PropTypes.string,
|
|
||||||
type: React.PropTypes.string,
|
|
||||||
active: React.PropTypes.bool,
|
|
||||||
onClick: React.PropTypes.func
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
handleClick () {
|
|
||||||
this.props.onClick();
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { type, active } = this.props;
|
|
||||||
|
|
||||||
let icon = '';
|
|
||||||
|
|
||||||
if (this.props.icon) {
|
|
||||||
icon = <i className={`fa fa-fw fa-${this.props.icon}`} style={{ display: 'inline-block', marginRight: '5px' }} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div role='button' tabIndex='0' aria-label={type} className={`column-header ${active ? 'active' : ''}`} onClick={this.handleClick}>
|
|
||||||
{icon}
|
|
||||||
{type}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default ColumnHeader;
|
|
@@ -1,41 +0,0 @@
|
|||||||
import { Link } from 'react-router';
|
|
||||||
|
|
||||||
const outerStyle = {
|
|
||||||
display: 'block',
|
|
||||||
padding: '15px',
|
|
||||||
fontSize: '16px',
|
|
||||||
textDecoration: 'none'
|
|
||||||
};
|
|
||||||
|
|
||||||
const iconStyle = {
|
|
||||||
display: 'inline-block',
|
|
||||||
marginRight: '5px'
|
|
||||||
};
|
|
||||||
|
|
||||||
const ColumnLink = ({ icon, text, to, href, method }) => {
|
|
||||||
if (href) {
|
|
||||||
return (
|
|
||||||
<a href={href} style={outerStyle} className='column-link' data-method={method}>
|
|
||||||
<i className={`fa fa-fw fa-${icon}`} style={iconStyle} />
|
|
||||||
{text}
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<Link to={to} style={outerStyle} className='column-link'>
|
|
||||||
<i className={`fa fa-fw fa-${icon}`} style={iconStyle} />
|
|
||||||
{text}
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ColumnLink.propTypes = {
|
|
||||||
icon: React.PropTypes.string.isRequired,
|
|
||||||
text: React.PropTypes.string.isRequired,
|
|
||||||
to: React.PropTypes.string,
|
|
||||||
href: React.PropTypes.string,
|
|
||||||
method: React.PropTypes.string
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ColumnLink;
|
|
@@ -1,27 +0,0 @@
|
|||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
|
|
||||||
const style = {
|
|
||||||
display: 'flex',
|
|
||||||
flex: '1 1 auto',
|
|
||||||
overflowX: 'auto'
|
|
||||||
};
|
|
||||||
|
|
||||||
const ColumnsArea = React.createClass({
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
children: React.PropTypes.node
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<div className='columns-area' style={style}>
|
|
||||||
{this.props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default ColumnsArea;
|
|
@@ -1,33 +0,0 @@
|
|||||||
import Link from 'http-link-header';
|
|
||||||
import querystring from 'querystring';
|
|
||||||
|
|
||||||
Link.parseAttrs = (link, parts) => {
|
|
||||||
let match = null
|
|
||||||
let attr = ''
|
|
||||||
let value = ''
|
|
||||||
let attrs = ''
|
|
||||||
|
|
||||||
let uriAttrs = /<(.*)>;\s*(.*)/gi.exec(parts)
|
|
||||||
|
|
||||||
if(uriAttrs) {
|
|
||||||
attrs = uriAttrs[2]
|
|
||||||
link = Link.parseParams(link, uriAttrs[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
while(match = Link.attrPattern.exec(attrs)) { // eslint-disable-line no-cond-assign
|
|
||||||
attr = match[1].toLowerCase()
|
|
||||||
value = match[4] || match[3] || match[2]
|
|
||||||
|
|
||||||
if( /\*$/.test(attr)) {
|
|
||||||
Link.setAttr(link, attr, Link.parseExtendedValue(value))
|
|
||||||
} else if(/%/.test(value)) {
|
|
||||||
Link.setAttr(link, attr, querystring.decode(value))
|
|
||||||
} else {
|
|
||||||
Link.setAttr(link, attr, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return link
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Link;
|
|
@@ -1,68 +0,0 @@
|
|||||||
const bg = {
|
|
||||||
"column_back_button.label": "Назад",
|
|
||||||
"lightbox.close": "Затвори",
|
|
||||||
"loading_indicator.label": "Зареждане...",
|
|
||||||
"status.mention": "Споменаване",
|
|
||||||
"status.delete": "Изтриване",
|
|
||||||
"status.reply": "Отговор",
|
|
||||||
"status.reblog": "Споделяне",
|
|
||||||
"status.favourite": "Предпочитани",
|
|
||||||
"status.reblogged_by": "{name} сподели",
|
|
||||||
"status.sensitive_warning": "Деликатно съдържание",
|
|
||||||
"status.sensitive_toggle": "Покажи",
|
|
||||||
"video_player.toggle_sound": "Звук",
|
|
||||||
"account.mention": "Споменаване",
|
|
||||||
"account.edit_profile": "Редактирай профила си",
|
|
||||||
"account.unblock": "Не блокирай",
|
|
||||||
"account.unfollow": "Не следвай",
|
|
||||||
"account.block": "Блокирай",
|
|
||||||
"account.follow": "Последвай",
|
|
||||||
"account.posts": "Публикации",
|
|
||||||
"account.follows": "Следвам",
|
|
||||||
"account.followers": "Последователи",
|
|
||||||
"account.follows_you": "Твой последовател",
|
|
||||||
"account.requested": "В очакване на одобрение",
|
|
||||||
"getting_started.heading": "Първи стъпки",
|
|
||||||
"getting_started.about_addressing": "Можеш да последваш потребител, ако знаеш потребителското му име и домейна, на който се намира, като в полето за търсене ги въведеш по този начин: име@домейн",
|
|
||||||
"getting_started.about_shortcuts": "Ако с търсения потребител се намирате на един и същ домейн, достатъчно е да въведеш само името. Същото важи и за споменаване на хора в публикации.",
|
|
||||||
"getting_started.about_developer": "Можеш да потърсиш разработчика на този проект като: Gargron@mastodon.social",
|
|
||||||
"getting_started.open_source_notice": "Mastodon е софтуер с отворен код. Можеш да помогнеш или да докладваш за проблеми в Github: {github}.",
|
|
||||||
"column.home": "Начало",
|
|
||||||
"column.mentions": "Споменавания",
|
|
||||||
"column.public": "Публичен канал",
|
|
||||||
"column.notifications": "Известия",
|
|
||||||
"tabs_bar.compose": "Съставяне",
|
|
||||||
"tabs_bar.home": "Начало",
|
|
||||||
"tabs_bar.mentions": "Споменавания",
|
|
||||||
"tabs_bar.public": "Публичен канал",
|
|
||||||
"tabs_bar.notifications": "Известия",
|
|
||||||
"compose_form.placeholder": "Какво си мислиш?",
|
|
||||||
"compose_form.publish": "Раздумай",
|
|
||||||
"compose_form.sensitive": "Отбележи съдържанието като деликатно",
|
|
||||||
"compose_form.spoiler": "Скрий текста зад предупреждение",
|
|
||||||
"compose_form.private": "Отбележи като поверително",
|
|
||||||
"compose_form.privacy_disclaimer": "Поверителни публикации ще бъдат изпратени до споменатите потребители на {domains}. Доверяваш ли се на {domainsCount, plural, one {that server} other {those servers}}, че няма да издаде твоята публикация?",
|
|
||||||
"compose_form.unlisted": "Не показвай в публичния канал",
|
|
||||||
"navigation_bar.edit_profile": "Редактирай профил",
|
|
||||||
"navigation_bar.preferences": "Предпочитания",
|
|
||||||
"navigation_bar.public_timeline": "Публичен канал",
|
|
||||||
"navigation_bar.logout": "Излизане",
|
|
||||||
"reply_indicator.cancel": "Отказ",
|
|
||||||
"search.placeholder": "Търсене",
|
|
||||||
"search.account": "Акаунт",
|
|
||||||
"search.hashtag": "Хаштаг",
|
|
||||||
"upload_button.label": "Добави медия",
|
|
||||||
"upload_form.undo": "Отмяна",
|
|
||||||
"notification.follow": "{name} те последва",
|
|
||||||
"notification.favourite": "{name} хареса твоята публикация",
|
|
||||||
"notification.reblog": "{name} сподели твоята публикация",
|
|
||||||
"notification.mention": "{name} те спомена",
|
|
||||||
"notifications.column_settings.alert": "Десктоп известия",
|
|
||||||
"notifications.column_settings.show": "Покажи в колона",
|
|
||||||
"notifications.column_settings.follow": "Нови последователи:",
|
|
||||||
"notifications.column_settings.favourite": "Предпочитани:",
|
|
||||||
"notifications.column_settings.mention": "Споменавания:",
|
|
||||||
"notifications.column_settings.reblog": "Споделяния:",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default bg;
|
|
@@ -1,77 +0,0 @@
|
|||||||
const de = {
|
|
||||||
"column_back_button.label": "Zurück",
|
|
||||||
"lightbox.close": "Schließen",
|
|
||||||
"loading_indicator.label": "Lade…",
|
|
||||||
"status.mention": "Erwähnen",
|
|
||||||
"status.delete": "Löschen",
|
|
||||||
"status.reply": "Antworten",
|
|
||||||
"status.reblog": "Teilen",
|
|
||||||
"status.favourite": "Favorisieren",
|
|
||||||
"status.reblogged_by": "{name} teilte",
|
|
||||||
"status.sensitive_warning": "Heikle Inhalte",
|
|
||||||
"status.sensitive_toggle": "Klicke, um sie zu sehen",
|
|
||||||
"status.open": "Öffnen",
|
|
||||||
"video_player.toggle_sound": "Ton umschalten",
|
|
||||||
"account.mention": "Erwähnen",
|
|
||||||
"account.edit_profile": "Profil bearbeiten",
|
|
||||||
"account.unblock": "Entblocken",
|
|
||||||
"account.unfollow": "Entfolgen",
|
|
||||||
"account.block": "Blocken",
|
|
||||||
"account.follow": "Folgen",
|
|
||||||
"account.posts": "Beiträge",
|
|
||||||
"account.follows": "Folgt",
|
|
||||||
"account.followers": "Folgende",
|
|
||||||
"account.follows_you": "Folgt dir",
|
|
||||||
"account.requested": "Warte auf Erlaubnis",
|
|
||||||
"getting_started.heading": "Erste Schritte",
|
|
||||||
"getting_started.about_addressing": "Du kannst Leuten folgen, falls du ihren Nutzernamen und ihre Domain kennst, in dem du eine e-mail-artige Addresse in das Suchfeld oben auf der Seite eingibst.",
|
|
||||||
"getting_started.about_shortcuts": "Falls die Person auf derselben Domain ist wie du, reicht auch ihr Nutzername alleine. Das gilt auch für Erwähnungen in Beiträgen.",
|
|
||||||
"getting_started.about_developer": "Der Entwickler des Projekts kann unter Gargron@mastodon.social gefunden werden",
|
|
||||||
"getting_started.open_source_notice": "Mastodon ist quelloffene Software. Du kannst auf {github} dazu beitragen oder Probleme melden.",
|
|
||||||
"column.home": "Home",
|
|
||||||
"column.mentions": "Erwähnungen",
|
|
||||||
"column.public": "Gesamtes bekanntes Netz",
|
|
||||||
"column.notifications": "Mitteilungen",
|
|
||||||
"column.follow_requests": "Folgeanfragen",
|
|
||||||
"tabs_bar.compose": "Schreiben",
|
|
||||||
"tabs_bar.home": "Home",
|
|
||||||
"tabs_bar.mentions": "Erwähnungen",
|
|
||||||
"tabs_bar.public": "Gesamtes Netz",
|
|
||||||
"tabs_bar.notifications": "Mitteilungen",
|
|
||||||
"compose_form.placeholder": "Worüber möchtest du schreiben?",
|
|
||||||
"compose_form.publish": "Tröt",
|
|
||||||
"compose_form.sensitive": "Medien als heikel markieren",
|
|
||||||
"compose_form.private": "Als privat markieren",
|
|
||||||
"compose_form.unlisted": "Nicht öffentlich auflisten",
|
|
||||||
"navigation_bar.edit_profile": "Profil bearbeiten",
|
|
||||||
"navigation_bar.preferences": "Einstellungen",
|
|
||||||
"navigation_bar.public_timeline": "Öffentlich",
|
|
||||||
"navigation_bar.logout": "Abmelden",
|
|
||||||
"navigation_bar.follow_requests": "Folgeanfragen",
|
|
||||||
"reply_indicator.cancel": "Abbrechen",
|
|
||||||
"search.placeholder": "Suche",
|
|
||||||
"search.account": "Konto",
|
|
||||||
"search.hashtag": "Hashtag",
|
|
||||||
"upload_button.label": "Mediendatei hinzufügen",
|
|
||||||
"upload_form.undo": "Entfernen",
|
|
||||||
"notification.follow": "{name} folgt dir",
|
|
||||||
"notification.favourite": "{name} favorisierte deinen Status",
|
|
||||||
"notification.reblog": "{name} teilte deinen Status",
|
|
||||||
"notification.mention": "{name} erwähnte dich",
|
|
||||||
"notifications.column_settings.alert": "Desktop-Benachrichtigungen",
|
|
||||||
"notifications.column_settings.show": "In der Spalte anzeigen",
|
|
||||||
"notifications.column_settings.follow": "Neue Folgende:",
|
|
||||||
"notifications.column_settings.favourite": "Favorisierungen:",
|
|
||||||
"notifications.column_settings.mention": "Erwähnungen:",
|
|
||||||
"notifications.column_settings.reblog": "Geteilte Beiträge:",
|
|
||||||
"follow_request.authorize": "Erlauben",
|
|
||||||
"follow_request.reject": "Ablehnen",
|
|
||||||
"home.column_settings.basic": "Einfach",
|
|
||||||
"home.column_settings.advanced": "Fortgeschritten",
|
|
||||||
"home.column_settings.show_reblogs": "Geteilte Beiträge anzeigen",
|
|
||||||
"home.column_settings.show_replies": "Antworten anzeigen",
|
|
||||||
"home.column_settings.filter_regex": "Filter durch reguläre Ausdrücke",
|
|
||||||
"missing_indicator.label": "Nicht gefunden"
|
|
||||||
};
|
|
||||||
|
|
||||||
export default de;
|
|
@@ -1,68 +0,0 @@
|
|||||||
const eo = {
|
|
||||||
"column_back_button.label": "Reveni",
|
|
||||||
"lightbox.close": "Fermi",
|
|
||||||
"loading_indicator.label": "Ŝarĝanta...",
|
|
||||||
"status.mention": "Mencii @{name}",
|
|
||||||
"status.delete": "Forigi",
|
|
||||||
"status.reply": "Respondi",
|
|
||||||
"status.reblog": "Diskonigi",
|
|
||||||
"status.favourite": "Favori",
|
|
||||||
"status.reblogged_by": "{name} diskonigita",
|
|
||||||
"status.sensitive_warning": "Tikla enhavo",
|
|
||||||
"status.sensitive_toggle": "Alklaki por vidi",
|
|
||||||
"video_player.toggle_sound": "Aktivigi sonojn",
|
|
||||||
"account.mention": "Mencii @{name}",
|
|
||||||
"account.edit_profile": "Redakti la profilon",
|
|
||||||
"account.unblock": "Malbloki @{name}",
|
|
||||||
"account.unfollow": "Malsekvi",
|
|
||||||
"account.block": "Bloki @{name}",
|
|
||||||
"account.follow": "Sekvi",
|
|
||||||
"account.posts": "Mesaĝoj",
|
|
||||||
"account.follows": "Sekvatoj",
|
|
||||||
"account.followers": "Sekvantoj",
|
|
||||||
"account.follows_you": "Sekvas vin",
|
|
||||||
"account.requested": "Atendas aprobon",
|
|
||||||
"getting_started.heading": "Por komenci",
|
|
||||||
"getting_started.about_addressing": "Vi povas sekvi homojn se vi konas la uzantnomon kaj domajnon tajpinte retpoŝtecan adreson en la serĉilon.",
|
|
||||||
"getting_started.about_shortcuts": "Se la celita uzanto troviĝas en la sama domajno de vi, uzi nur la uzantnomon sufiĉos. La sama regulo validas por mencii aliajn uzantojn en mesaĝo.",
|
|
||||||
"getting_started.open_source_notice": "Mastodon estas malfermitkoda programo. Vi povas kontribui aŭ raporti problemojn en github je {github}. {apps}.",
|
|
||||||
"column.home": "Hejmo",
|
|
||||||
"column.community": "Loka tempolinio",
|
|
||||||
"column.public": "Fratara tempolinio",
|
|
||||||
"column.notifications": "Sciigoj",
|
|
||||||
"tabs_bar.compose": "Ekskribi",
|
|
||||||
"tabs_bar.home": "Hejmo",
|
|
||||||
"tabs_bar.mentions": "Sciigoj",
|
|
||||||
"tabs_bar.public": "Fratara tempolinio",
|
|
||||||
"tabs_bar.notifications": "Sciigoj",
|
|
||||||
"compose_form.placeholder": "Pri kio vi pensas?",
|
|
||||||
"compose_form.publish": "Hup",
|
|
||||||
"compose_form.sensitive": "Marki ke la enhavo estas tikla",
|
|
||||||
"compose_form.spoiler": "Kaŝi la tekston malantaŭ averto",
|
|
||||||
"compose_form.private": "Marki ke la enhavo estas privata",
|
|
||||||
"compose_form.privacy_disclaimer": "Via privata mesaĝo estos sendita nur al menciitaj uzantoj en {domains}. Ĉu vi fidas {domainsCount, plural, one {tiun servilon} other {tiujn servilojn}}? Mesaĝa privateco funkcias nur en aperaĵoj de Mastodon. Se {domains} {domainsCount, plural, one {ne estas aperaĵo de Mastodon} other {ne estas aperaĵoj de Mastodon}}, estos neniu indiko ke via mesaĝo estas privata, kaj ĝi povus esti diskonigita aŭ videbligita al necelitaj ricevantoj.",
|
|
||||||
"compose_form.unlisted": "Ne afiŝi en publikaj tempolinioj",
|
|
||||||
"navigation_bar.edit_profile": "Redakti la profilon",
|
|
||||||
"navigation_bar.preferences": "Preferoj",
|
|
||||||
"navigation_bar.community_timeline": "Loka tempolinio",
|
|
||||||
"navigation_bar.public_timeline": "Fratara tempolinio",
|
|
||||||
"navigation_bar.logout": "Elsaluti",
|
|
||||||
"reply_indicator.cancel": "Rezigni",
|
|
||||||
"search.placeholder": "Serĉi",
|
|
||||||
"search.account": "Konto",
|
|
||||||
"search.hashtag": "Kradvorto",
|
|
||||||
"upload_button.label": "Aldoni enhavaĵon",
|
|
||||||
"upload_form.undo": "Malfari",
|
|
||||||
"notification.follow": "{name} sekvis vin",
|
|
||||||
"notification.favourite": "{name} favoris vian mesaĝon",
|
|
||||||
"notification.reblog": "{name} diskonigis vian mesaĝon",
|
|
||||||
"notification.mention": "{name} menciis vin",
|
|
||||||
"notifications.column_settings.alert": "Retumilaj atentigoj",
|
|
||||||
"notifications.column_settings.show": "Montri en kolono",
|
|
||||||
"notifications.column_settings.follow": "Novaj sekvantoj:",
|
|
||||||
"notifications.column_settings.favourite": "Favoroj:",
|
|
||||||
"notifications.column_settings.mention": "Mencioj:",
|
|
||||||
"notifications.column_settings.reblog": "Diskonigoj:",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default eo;
|
|
@@ -1,93 +0,0 @@
|
|||||||
const es = {
|
|
||||||
"column_back_button.label": "Atrás",
|
|
||||||
"lightbox.close": "Cerrar",
|
|
||||||
"loading_indicator.label": "Cargando...",
|
|
||||||
"status.mention": "Mencionar",
|
|
||||||
"status.delete": "Borrar",
|
|
||||||
"status.reply": "Responder",
|
|
||||||
"status.reblog": "Retoot",
|
|
||||||
"status.favourite": "Favorito",
|
|
||||||
"status.reblogged_by": "Retooteado por {name}",
|
|
||||||
"status.sensitive_warning": "Contenido sensible",
|
|
||||||
"status.sensitive_toggle": "Click para ver",
|
|
||||||
"status.show_more": "Mostrar más",
|
|
||||||
"status.show_less": "Mostrar menos",
|
|
||||||
"status.open": "Expandir estado",
|
|
||||||
"status.report": "Reportar",
|
|
||||||
"video_player.toggle_sound": "Act/Desac. sonido",
|
|
||||||
"account.mention": "Mencionar",
|
|
||||||
"account.edit_profile": "Editar perfil",
|
|
||||||
"account.unblock": "Desbloquear",
|
|
||||||
"account.unfollow": "Dejar de seguir",
|
|
||||||
"account.mute": "Silenciar",
|
|
||||||
"account.block": "Bloquear",
|
|
||||||
"account.follow": "Seguir",
|
|
||||||
"account.posts": "Publicaciones",
|
|
||||||
"account.follows": "Seguir",
|
|
||||||
"account.followers": "Seguidores",
|
|
||||||
"account.follows_you": "Te sigue",
|
|
||||||
"account.requested": "Esperando aprobación",
|
|
||||||
"getting_started.heading": "Primeros pasos",
|
|
||||||
"getting_started.about_addressing": "Puedes seguir a gente si conoces su nombre de usuario y el dominio en el que están registrados, introduciendo algo similar a una dirección de correo electrónico en el formulario en la parte superior de la barra lateral.",
|
|
||||||
"getting_started.about_shortcuts": "Si el usuario que buscas está en el mismo dominio que tú, simplemente funcionará introduciendo el nombre de usuario. La misma regla se aplica para mencionar a usuarios.",
|
|
||||||
"getting_started.open_source_notice": "Mastodon es software libre. Puedes contribuir o reportar errores en {github}. {apps}.",
|
|
||||||
"column.home": "Inicio",
|
|
||||||
"column.community": "Historia local",
|
|
||||||
"column.public": "Historia federada",
|
|
||||||
"column.notifications": "Notificaciones",
|
|
||||||
"column.blocks": "Usuarios bloqueados",
|
|
||||||
"column.favourites": "Favoritos",
|
|
||||||
"column.follow_requests": "Solicitudes para seguirte",
|
|
||||||
"column.mutes": "Usuarios silenciados",
|
|
||||||
"tabs_bar.compose": "Redactar",
|
|
||||||
"tabs_bar.home": "Inicio",
|
|
||||||
"tabs_bar.mentions": "Menciones",
|
|
||||||
"tabs_bar.public": "Público",
|
|
||||||
"tabs_bar.notifications": "Notificaciones",
|
|
||||||
"compose_form.placeholder": "¿En qué estás pensando?",
|
|
||||||
"compose_form.publish": "Tootear",
|
|
||||||
"compose_form.sensitive": "Marcar contenido como sensible",
|
|
||||||
"compose_form.spoiler": "Ocultar texto tras advertencia",
|
|
||||||
"compose_form.spoiler_placeholder": "Advertencia de contenido",
|
|
||||||
"composer_form.private": "Marcar como privado",
|
|
||||||
"composer_form.privacy_disclaimer": "Tu estado se mostrará a los usuarios mencionados en {domains}. Tu estado podrá ser visto en otras instancias, quizás no quieras que tu estado sea visto por otros usuarios.",
|
|
||||||
"compose_form.unlisted": "No mostrar en la historia federada",
|
|
||||||
"navigation_bar.edit_profile": "Editar perfil",
|
|
||||||
"navigation_bar.preferences": "Preferencias",
|
|
||||||
"navigation_bar.community_timeline": "Historia local",
|
|
||||||
"navigation_bar.public_timeline": "Historia federada",
|
|
||||||
"navigation_bar.favourites": "Favoritos",
|
|
||||||
"navigation_bar.blocks": "Usuarios bloqueados",
|
|
||||||
"navigation_bar.info": "Información adicional",
|
|
||||||
"navigation_bar.logout": "Cerrar sesión",
|
|
||||||
"navigation_bar.follow_requests": "Solicitudes para seguirte",
|
|
||||||
"navigation_bar.mutes": "Usuarios silenciados",
|
|
||||||
"reply_indicator.cancel": "Cancelar",
|
|
||||||
"search.placeholder": "Buscar",
|
|
||||||
"search.account": "Cuenta",
|
|
||||||
"search.hashtag": "Etiqueta",
|
|
||||||
"upload_button.label": "Subir multimedia",
|
|
||||||
"upload_form.undo": "Deshacer",
|
|
||||||
"notification.follow": "{name} te empezó a seguir",
|
|
||||||
"notification.favourite": "{name} marcó tu estado como favorito",
|
|
||||||
"notification.reblog": "{name} ha retooteado tu estado",
|
|
||||||
"notification.mention": "{name} te ha mencionado",
|
|
||||||
"notifications.column_settings.alert": "Notificaciones de escritorio",
|
|
||||||
"notifications.column_settings.show": "Mostrar en columna",
|
|
||||||
"notifications.column_settings.follow": "Nuevos seguidores:",
|
|
||||||
"notifications.column_settings.favourite": "Favoritos:",
|
|
||||||
"notifications.column_settings.mention": "Menciones:",
|
|
||||||
"notifications.column_settings.reblog": "Retoots:",
|
|
||||||
"emoji_button.label": "Insertar emoji",
|
|
||||||
"privacy.public.short": "Público",
|
|
||||||
"privacy.public.long": "Mostrar en la historia federada",
|
|
||||||
"privacy.unlisted.short": "Sin federar",
|
|
||||||
"privacy.unlisted.long": "No mostrar en la historia federada",
|
|
||||||
"privacy.private.short": "Privado",
|
|
||||||
"privacy.private.long": "Sólo mostrar a seguidores",
|
|
||||||
"privacy.direct.short": "Directo",
|
|
||||||
"privacy.direct.long": "Sólo mostrar a los usuarios mencionados",
|
|
||||||
"privacy.change": "Ajustar privacidad"
|
|
||||||
};
|
|
||||||
|
|
||||||
export default es;
|
|
@@ -1,68 +0,0 @@
|
|||||||
const fi = {
|
|
||||||
"column_back_button.label": "Takaisin",
|
|
||||||
"lightbox.close": "Sulje",
|
|
||||||
"loading_indicator.label": "Ladataan...",
|
|
||||||
"status.mention": "Mainitse @{name}",
|
|
||||||
"status.delete": "Poista",
|
|
||||||
"status.reply": "Vastaa",
|
|
||||||
"status.reblog": "Buustaa",
|
|
||||||
"status.favourite": "Tykkää",
|
|
||||||
"status.reblogged_by": "{name} buustasi",
|
|
||||||
"status.sensitive_warning": "Arkaluontoista sisältöä",
|
|
||||||
"status.sensitive_toggle": "Klikkaa nähdäksesi",
|
|
||||||
"video_player.toggle_sound": "Äänet päälle/pois",
|
|
||||||
"account.mention": "Mainitse @{name}",
|
|
||||||
"account.edit_profile": "Muokkaa",
|
|
||||||
"account.unblock": "Salli @{name}",
|
|
||||||
"account.unfollow": "Lopeta seuraaminen",
|
|
||||||
"account.block": "Estä @{name}",
|
|
||||||
"account.follow": "Seuraa",
|
|
||||||
"account.posts": "Postit",
|
|
||||||
"account.follows": "Seuraa",
|
|
||||||
"account.followers": "Seuraajia",
|
|
||||||
"account.follows_you": "Seuraa sinua",
|
|
||||||
"account.requested": "Odottaa hyväksyntää",
|
|
||||||
"getting_started.heading": "Aloitus",
|
|
||||||
"getting_started.about_addressing": "Voit seurata ihmisiä jos tiedät heidän käyttäjänimensä ja domainin missä he ovat syöttämällä e-mail-esque osoitteen Etsi kenttään.",
|
|
||||||
"getting_started.about_shortcuts": "Jos etsimäsi henkilö on samassa domainissa kuin sinä, pelkkä käyttäjänimi kelpaa. Sama pätee kun mainitset ihmisiä statuksessasi",
|
|
||||||
"getting_started.open_source_notice": "Mastodon Mastodon on avoimen lähdekoodin ohjelma. Voit avustaa tai raportoida ongelmia GitHub palvelussa {github}. {apps}.",
|
|
||||||
"column.home": "Koti",
|
|
||||||
"column.community": "Paikallinen aikajana",
|
|
||||||
"column.public": "Yleinen aikajana",
|
|
||||||
"column.notifications": "Ilmoitukset",
|
|
||||||
"tabs_bar.compose": "Luo",
|
|
||||||
"tabs_bar.home": "Koti",
|
|
||||||
"tabs_bar.mentions": "Maininnat",
|
|
||||||
"tabs_bar.public": "Yleinen aikajana",
|
|
||||||
"tabs_bar.notifications": "Ilmoitukset",
|
|
||||||
"compose_form.placeholder": "Mitä sinulla on mielessä?",
|
|
||||||
"compose_form.publish": "Toot",
|
|
||||||
"compose_form.sensitive": "Merkitse media herkäksi",
|
|
||||||
"compose_form.spoiler": "Piiloita teksti varoituksen taakse",
|
|
||||||
"compose_form.private": "Merkitse yksityiseksi",
|
|
||||||
"compose_form.privacy_disclaimer": "Sinun yksityinen status toimitetaan mainitsemallesi käyttäjille domaineissa {domains}. Luotatko {domainsCount, plural, one {tähän palvelimeen} other {näihin palvelimiin}}? Postauksen yksityisyys toimii van Mastodon palvelimilla. Jos {domains} {domainsCount, plural, one {ei ole Mastodon palvelin} other {eivät ole Mastodon palvelin}}, viestiin ei tule Yksityinen-merkintää, ja sitä voidaan boostata tai muuten tehdä näkyväksi muille vastaanottajille.",
|
|
||||||
"compose_form.unlisted": "Älä näytä yleisillä aikajanoilla",
|
|
||||||
"navigation_bar.edit_profile": "Muokkaa profiilia",
|
|
||||||
"navigation_bar.preferences": "Ominaisuudet",
|
|
||||||
"navigation_bar.community_timeline": "Paikallinen aikajana",
|
|
||||||
"navigation_bar.public_timeline": "Yleinen aikajana",
|
|
||||||
"navigation_bar.logout": "Kirjaudu ulos",
|
|
||||||
"reply_indicator.cancel": "Peruuta",
|
|
||||||
"search.placeholder": "Hae",
|
|
||||||
"search.account": "Tili",
|
|
||||||
"search.hashtag": "Hashtag",
|
|
||||||
"upload_button.label": "Lisää mediaa",
|
|
||||||
"upload_form.undo": "Peru",
|
|
||||||
"notification.follow": "{name} seurasi sinua",
|
|
||||||
"notification.favourite": "{name} tykkäsi statuksestasi",
|
|
||||||
"notification.reblog": "{name} buustasi statustasi",
|
|
||||||
"notification.mention": "{name} mainitsi sinut",
|
|
||||||
"notifications.column_settings.alert": "Työpöytä ilmoitukset",
|
|
||||||
"notifications.column_settings.show": "Näytä sarakkeessa",
|
|
||||||
"notifications.column_settings.follow": "Uusia seuraajia:",
|
|
||||||
"notifications.column_settings.favourite": "Tykkäyksiä:",
|
|
||||||
"notifications.column_settings.mention": "Mainintoja:",
|
|
||||||
"notifications.column_settings.reblog": "Buusteja:",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default fi;
|
|
@@ -1,57 +0,0 @@
|
|||||||
const hu = {
|
|
||||||
"column_back_button.label": "Vissza",
|
|
||||||
"lightbox.close": "Bezárás",
|
|
||||||
"loading_indicator.label": "Betöltés...",
|
|
||||||
"status.mention": "Említés",
|
|
||||||
"status.delete": "Törlés",
|
|
||||||
"status.reply": "Válasz",
|
|
||||||
"status.reblog": "Reblog",
|
|
||||||
"status.favourite": "Kedvenc",
|
|
||||||
"status.reblogged_by": "{name} reblogolta",
|
|
||||||
"status.sensitive_warning": "Érzékeny tartalom",
|
|
||||||
"status.sensitive_toggle": "Katt a megtekintéshez",
|
|
||||||
"video_player.toggle_sound": "Hang kapcsolása",
|
|
||||||
"account.mention": "Említés",
|
|
||||||
"account.edit_profile": "Profil szerkesztése",
|
|
||||||
"account.unblock": "Blokkolás levétele",
|
|
||||||
"account.unfollow": "Követés abbahagyása",
|
|
||||||
"account.block": "Blokkolás",
|
|
||||||
"account.follow": "Követés",
|
|
||||||
"account.posts": "Posts",
|
|
||||||
"account.follows": "Követve",
|
|
||||||
"account.followers": "Követők",
|
|
||||||
"account.follows_you": "Követnek téged",
|
|
||||||
"getting_started.heading": "Első lépések",
|
|
||||||
"getting_started.about_addressing": "Követhetsz embereket felhasználónevük és a doménjük ismeretében, amennyiben megadod ezt az e-mail-szerű címet az oldalsáv tetején lévő rubrikában.",
|
|
||||||
"getting_started.about_shortcuts": "Ha a célzott személy azonos doménen tartózkodik, a felhasználónév elegendő. Ugyanez érvényes mikor személyeket említesz az állapotokban.",
|
|
||||||
"getting_started.about_developer": "A projekt fejlesztője követhető, mint Gargron@mastodon.social",
|
|
||||||
"column.home": "Kezdőlap",
|
|
||||||
"column.mentions": "Említések",
|
|
||||||
"column.public": "Nyilvános",
|
|
||||||
"column.notifications": "Értesítések",
|
|
||||||
"tabs_bar.compose": "Összeállítás",
|
|
||||||
"tabs_bar.home": "Kezdőlap",
|
|
||||||
"tabs_bar.mentions": "Említések",
|
|
||||||
"tabs_bar.public": "Nyilvános",
|
|
||||||
"tabs_bar.notifications": "Notifications",
|
|
||||||
"compose_form.placeholder": "Mire gondolsz?",
|
|
||||||
"compose_form.publish": "Tülk!",
|
|
||||||
"compose_form.sensitive": "Tartalom érzékenynek jelölése",
|
|
||||||
"compose_form.unlisted": "Listázatlan mód",
|
|
||||||
"navigation_bar.edit_profile": "Profil szerkesztése",
|
|
||||||
"navigation_bar.preferences": "Beállítások",
|
|
||||||
"navigation_bar.public_timeline": "Nyilvános időfolyam",
|
|
||||||
"navigation_bar.logout": "Kijelentkezés",
|
|
||||||
"reply_indicator.cancel": "Mégsem",
|
|
||||||
"search.placeholder": "Keresés",
|
|
||||||
"search.account": "Fiók",
|
|
||||||
"search.hashtag": "Hashtag",
|
|
||||||
"upload_button.label": "Média hozzáadása",
|
|
||||||
"upload_form.undo": "Mégsem",
|
|
||||||
"notification.follow": "{name} követ téged",
|
|
||||||
"notification.favourite": "{name} kedvencnek jelölte az állapotod",
|
|
||||||
"notification.reblog": "{name} reblogolta az állapotod",
|
|
||||||
"notification.mention": "{name} megemlített"
|
|
||||||
};
|
|
||||||
|
|
||||||
export default hu;
|
|
@@ -1,44 +0,0 @@
|
|||||||
import en from './en';
|
|
||||||
import de from './de';
|
|
||||||
import es from './es';
|
|
||||||
import hr from './hr';
|
|
||||||
import hu from './hu';
|
|
||||||
import it from './it';
|
|
||||||
import fr from './fr';
|
|
||||||
import nl from './nl';
|
|
||||||
import no from './no';
|
|
||||||
import oc from './oc';
|
|
||||||
import pt from './pt';
|
|
||||||
import pt_br from './pt-br';
|
|
||||||
import uk from './uk';
|
|
||||||
import fi from './fi';
|
|
||||||
import eo from './eo';
|
|
||||||
import ru from './ru';
|
|
||||||
import ja from './ja';
|
|
||||||
import zh_hk from './zh-hk';
|
|
||||||
import bg from './bg';
|
|
||||||
|
|
||||||
const locales = {
|
|
||||||
en,
|
|
||||||
de,
|
|
||||||
es,
|
|
||||||
hr,
|
|
||||||
hu,
|
|
||||||
it,
|
|
||||||
fr,
|
|
||||||
nl,
|
|
||||||
no,
|
|
||||||
pt,
|
|
||||||
'pt-BR': pt_br,
|
|
||||||
uk,
|
|
||||||
fi,
|
|
||||||
eo,
|
|
||||||
ru,
|
|
||||||
ja,
|
|
||||||
'zh-HK': zh_hk,
|
|
||||||
bg,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function getMessagesForLocale (locale) {
|
|
||||||
return locales[locale];
|
|
||||||
};
|
|
@@ -1,95 +0,0 @@
|
|||||||
const nl = {
|
|
||||||
"column_back_button.label": "terug",
|
|
||||||
"lightbox.close": "Sluiten",
|
|
||||||
"loading_indicator.label": "Laden…",
|
|
||||||
"status.mention": "@{name} vermelden",
|
|
||||||
"status.delete": "Verwijderen",
|
|
||||||
"status.reply": "Reageren",
|
|
||||||
"status.reblog": "Boost",
|
|
||||||
"status.favourite": "Favoriet",
|
|
||||||
"status.reblogged_by": "{name} boostte",
|
|
||||||
"status.sensitive_warning": "Gevoelige inhoud",
|
|
||||||
"status.sensitive_toggle": "Klik om te zien",
|
|
||||||
"video_player.toggle_sound": "Geluid in-/uitschakelen",
|
|
||||||
"account.mention": "Vermeld @{name}",
|
|
||||||
"account.edit_profile": "Profiel bewerken",
|
|
||||||
"account.unblock": "Deblokkeer @{name}",
|
|
||||||
"account.unfollow": "Ontvolgen",
|
|
||||||
"account.block": "Blokkeer @{name}",
|
|
||||||
"account.follow": "Volgen",
|
|
||||||
"account.posts": "Berichten",
|
|
||||||
"account.follows": "Volgt",
|
|
||||||
"account.followers": "Volgers",
|
|
||||||
"account.follows_you": "Volgt jou",
|
|
||||||
"account.requested": "Wacht op goedkeuring",
|
|
||||||
"account.mute": "Negeer @{name}",
|
|
||||||
"account.unmute": "Negeer @{name} niet meer",
|
|
||||||
"account.report": "Rapporteer @{name}",
|
|
||||||
"getting_started.heading": "Beginnen",
|
|
||||||
"getting_started.about_addressing": "Je kunt mensen volgen als je hun gebruikersnaam en het domein van hun server kent. Voer hiervoor het e-mailachtige adres in het zoekveld in.",
|
|
||||||
"getting_started.about_shortcuts": "Als de gezochte gebruiker op hetzelfde domein zit als jijzelf, is invoeren van de gebruikersnaam genoeg. Dat geldt ook als je mensen in toots wilt vermelden.",
|
|
||||||
"getting_started.open_source_notice": "Mastodon is open-sourcesoftware. Je kunt bijdragen of problemen melden op GitHub via {github}. {apps}.",
|
|
||||||
"getting_started.apps": "Er zijn meerdere apps beschikbaar",
|
|
||||||
"column.home": "Jouw tijdlijn",
|
|
||||||
"column.community": "Lokale tijdlijn",
|
|
||||||
"column.public": "Globale tijdlijn",
|
|
||||||
"column.notifications": "Meldingen",
|
|
||||||
"column.favourites": "Favorieten",
|
|
||||||
"column.blocks": "Geblokkeerde gebruikers",
|
|
||||||
"column.mutes": "Genegeerde gebruikers",
|
|
||||||
"tabs_bar.compose": "Schrijven",
|
|
||||||
"tabs_bar.home": "Jouw tijdlijn",
|
|
||||||
"tabs_bar.mentions": "Vermeldingen",
|
|
||||||
"tabs_bar.public": "Globale tijdlijn",
|
|
||||||
"tabs_bar.notifications": "Meldingen",
|
|
||||||
"compose_form.placeholder": "Waar ben je mee bezig?",
|
|
||||||
"compose_form.publish": "Toot",
|
|
||||||
"compose_form.sensitive": "Media als gevoelig markeren",
|
|
||||||
"compose_form.spoiler": "Tekst achter waarschuwing verbergen",
|
|
||||||
"compose_form.spoiler_placeholder": "Waarschuwingstekst",
|
|
||||||
"compose_form.private": "Als privé markeren",
|
|
||||||
"compose_form.privacy_disclaimer": "Jouw privétoot wordt afgeleverd aan de vermelde gebruikers op {domains}. Vertrouw jij {domainsCount, plural, one {die server} other {die servers}}? Het privé plaatsen van toots werkt alleen op Mastodon-servers. Wanneer {domains} {domainsCount, plural, one {geen Mastodon-server is} other {geen Mastodon-servers zijn}}, dan wordt er niet aangegeven dat de toot privé is, waardoor het kan worden geboost of op een andere manier zichtbaar wordt gemaakt voor mensen waarvoor het niet was bedoeld.",
|
|
||||||
"compose_form.unlisted": "Niet op openbare tijdlijnen tonen",
|
|
||||||
"navigation_bar.edit_profile": "Profiel bewerken",
|
|
||||||
"navigation_bar.preferences": "Voorkeuren",
|
|
||||||
"navigation_bar.community_timeline": "Lokale tijdlijn",
|
|
||||||
"navigation_bar.public_timeline": "Globale tijdlijn",
|
|
||||||
"navigation_bar.follow_requests": "Volgverzoeken",
|
|
||||||
"navigation_bar.info": "Uitgebreide informatie",
|
|
||||||
"navigation_bar.blocks": "Geblokkeerde gebruikers",
|
|
||||||
"navigation_bar.mutes": "Genegeerde gebruikers",
|
|
||||||
"navigation_bar.logout": "Afmelden",
|
|
||||||
"navigation_bar.favourites": "Favorieten",
|
|
||||||
"reply_indicator.cancel": "Annuleren",
|
|
||||||
"search.placeholder": "Zoeken",
|
|
||||||
"search.account": "Account",
|
|
||||||
"search.hashtag": "Hashtag",
|
|
||||||
"search_results.total": "{count, number} {count, plural, one {resultaat} other {resultaten}}",
|
|
||||||
"upload_button.label": "Media toevoegen",
|
|
||||||
"upload_form.undo": "Ongedaan maken",
|
|
||||||
"notification.follow": "{name} volgt jou nu",
|
|
||||||
"notification.favourite": "{name} markeerde jouw toot als favoriet",
|
|
||||||
"notification.reblog": "{name} boostte jouw toot",
|
|
||||||
"notification.mention": "{name} vermeldde jou",
|
|
||||||
"notifications.clear_confirmation": "Weet je zeker dat je al jouw meldingen wilt verwijderen?",
|
|
||||||
"notifications.clear": "Meldingen verwijderen",
|
|
||||||
"notifications.column_settings.alert": "Desktopmeldingen",
|
|
||||||
"notifications.column_settings.show": "In kolom tonen",
|
|
||||||
"notifications.column_settings.follow": "Nieuwe volgers:",
|
|
||||||
"notifications.column_settings.favourite": "Favorieten:",
|
|
||||||
"notifications.column_settings.mention": "Vermeldingen:",
|
|
||||||
"notifications.column_settings.reblog": "Boosts:",
|
|
||||||
"notifications.column_settings.sound": "Geluid afspelen",
|
|
||||||
"notifications.settings": "Kolom-instellingen",
|
|
||||||
"privacy.change": "Privacy toot aanpassen",
|
|
||||||
"privacy.direct.long": "Toot alleen naar vermelde gebruikers",
|
|
||||||
"privacy.direct.short": "Direct",
|
|
||||||
"privacy.private.long": "Toot alleen naar jouw volgers",
|
|
||||||
"privacy.private.short": "Privé",
|
|
||||||
"privacy.public.long": "Toot naar openbare tijdlijnen",
|
|
||||||
"privacy.public.short": "Openbaar",
|
|
||||||
"privacy.unlisted.long": "Niet op openbare tijdlijnen weergeven",
|
|
||||||
"privacy.unlisted.short": "Minder openbaar",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default nl;
|
|
@@ -1,128 +0,0 @@
|
|||||||
const oc = {
|
|
||||||
"column_back_button.label": "Tornar",
|
|
||||||
"lightbox.close": "Tampar",
|
|
||||||
"loading_indicator.label": "Cargament…",
|
|
||||||
"status.mention": "Mencionar",
|
|
||||||
"status.delete": "Escafar",
|
|
||||||
"status.reply": "Respondre",
|
|
||||||
"status.reblog": "Partejar",
|
|
||||||
"status.favourite": "Apondre als favorits",
|
|
||||||
"status.reblogged_by": "{name} a partejat :",
|
|
||||||
"status.sensitive_warning": "Contengut embarrassant",
|
|
||||||
"status.sensitive_toggle": "Clicar per mostrar",
|
|
||||||
"status.show_more": "Desplegar",
|
|
||||||
"status.show_less": "Tornar plegar",
|
|
||||||
"status.open": "Desplegar aqueste estatut",
|
|
||||||
"status.report": "Senhalar @{name}",
|
|
||||||
"status.load_more": "Cargar mai",
|
|
||||||
"status.media_hidden": "Mèdia rescondut",
|
|
||||||
"video_player.toggle_sound": "Activar/Desactivar lo son",
|
|
||||||
"video_player.toggle_visible": "Mostrar/Rescondre la vidèo",
|
|
||||||
"account.mention": "Mencionar",
|
|
||||||
"account.edit_profile": "Modificar lo perfil",
|
|
||||||
"account.unblock": "Desblocar",
|
|
||||||
"account.unfollow": "Quitar de sègre",
|
|
||||||
"account.block": "Blocar",
|
|
||||||
"account.mute": "Rescondre",
|
|
||||||
"account.unmute": "Quitar de rescondre",
|
|
||||||
"account.follow": "Sègre",
|
|
||||||
"account.posts": "Estatuts",
|
|
||||||
"account.follows": "Abonaments",
|
|
||||||
"account.followers": "Abonats",
|
|
||||||
"account.follows_you": "Vos sèc",
|
|
||||||
"account.requested": "Invitacion mandada",
|
|
||||||
"account.report": "Senhalar",
|
|
||||||
"account.disclaimer": "Aqueste compte es sus una autra instància. Los nombres pòdon èsser mai grandes.",
|
|
||||||
"getting_started.heading": "Per començar",
|
|
||||||
"getting_started.about_addressing": "Podètz sègre los estatuts de qualqu'un en picant son identificant e lo domeni de l'instància separat amb un @ coma una adreàa de corrièl dins lo camp de recèrca.",
|
|
||||||
"getting_started.about_shortcuts": "Se aquesta persona emplega la meteissa instància que vos l'identifican basta. Atal foncionan tanben las mencions dins vòstres estatuts.",
|
|
||||||
"getting_started.about_developer": "Per sègre lo desvolopaire d'aqueste projècte : Gargron@mastodon.social",
|
|
||||||
"getting_started.open_source_notice": "Mastodon es un logicial liure. Podètz contribuir e mandar vòstres comentaris e rapòrt de bug via{github} sus GitHub.",
|
|
||||||
"column.home": "Acuèlh",
|
|
||||||
"column.community": "Fil public local",
|
|
||||||
"column.public": "Fil public global",
|
|
||||||
"column.notifications": "Notificacions",
|
|
||||||
"column.blocks": "Utilizaires blocats",
|
|
||||||
"column.favourites": "Favorits",
|
|
||||||
"column.follow_requests": "Demandas d'abonament",
|
|
||||||
"empty_column.notifications": "Avètz pas encara de notificacions. Respondètz a qualqu'un per començar una conversacion.",
|
|
||||||
"empty_column.public": "I a pas res aquí ! Escribètz quicòm de public, o seguètz d'utilizaires d'autras instàncias per garnir lo fil public.",
|
|
||||||
"empty_column.home": "Pel moment segètz pas segun. Visitatz {public} o utilizatz la recèrca per vos connectar a d'autres personas.",
|
|
||||||
"empty_column.home.public_timeline": "lo fil public",
|
|
||||||
"empty_column.community": "Lo fil public local es void. Escribètz quicòm per lo garnir !",
|
|
||||||
"empty_column.hashtag": "I a pas encara de contengut ligat a aqueste hashtag",
|
|
||||||
"tabs_bar.compose": "Compausar",
|
|
||||||
"tabs_bar.home": "Acuèlh",
|
|
||||||
"tabs_bar.mentions": "Mencions",
|
|
||||||
"tabs_bar.public": "Fil public global",
|
|
||||||
"tabs_bar.notifications": "Notifications",
|
|
||||||
"tabs_bar.local_timeline": "Fil public local",
|
|
||||||
"tabs_bar.federated_timeline": "Fil public global",
|
|
||||||
"compose_form.placeholder": "Qué pensatz ?",
|
|
||||||
"compose_form.publish": "Tut",
|
|
||||||
"compose_form.sensitive": "Marcar lo mèdia coma embarrassant",
|
|
||||||
"compose_form.spoiler": "Rescondre lo tèxte darrièr un avertiment",
|
|
||||||
"compose_form.spoiler_placeholder": "Avertiment",
|
|
||||||
"compose_form.private": "Far venir privat",
|
|
||||||
"compose_form.privacy_disclaimer": "Vòstre estatut privat serà enviat a las personas mencionadas sus {domains}. Vos fisatz d'aqueste{domainsCount, plural, one { servidor} other {s servidors}} per divulgar pas vòstre estatut ? Los estatuts privats foncionan pas que sus las instàncias a Mastodons. Se {domains} {domainsCount, plural, one {es pas una instància a Mastodon} other {son pas d'instàncias a Mastodon}}, i aurà pas d'indicacion disent que vòstre estatut es privat e poirà èsser partejat o èsser visible a de mond pas prevists",
|
|
||||||
"compose_form.unlisted": "Mostrar pas dins los fils publics",
|
|
||||||
"emoji_button.label": "Inserir un emoji",
|
|
||||||
"navigation_bar.edit_profile": "Modificar lo perfil",
|
|
||||||
"navigation_bar.preferences": "Preferéncias",
|
|
||||||
"navigation_bar.community_timeline": "Fil public local",
|
|
||||||
"navigation_bar.public_timeline": "Fil public global",
|
|
||||||
"navigation_bar.blocks": "Utilizaires blocats",
|
|
||||||
"navigation_bar.favourites": "Favorits",
|
|
||||||
"navigation_bar.info": "Mai informacions",
|
|
||||||
"navigation_bar.logout": "Desconnexion",
|
|
||||||
"navigation_bar.follow_requests": "Demandas d'abonament",
|
|
||||||
"reply_indicator.cancel": "Anullar",
|
|
||||||
"search.placeholder": "Recercar",
|
|
||||||
"search.account": "Compte",
|
|
||||||
"search.hashtag": "Mot-clau",
|
|
||||||
"search_results.total": "{count, number} {count, plural, one {resultat} other {resultats}}",
|
|
||||||
"search.status_by": "Estatuts de {name}",
|
|
||||||
"upload_button.label": "Apondre un mèdia",
|
|
||||||
"upload_form.undo": "Anullar",
|
|
||||||
"upload_progress.label": "Mandadís…",
|
|
||||||
"upload_area.title": "Lisatz e depausatz per mandar",
|
|
||||||
"notification.follow": "{name} vos sèc.",
|
|
||||||
"notification.favourite": "{name} a apondut a sos favorits :",
|
|
||||||
"notification.reblog": "{name} a partejat vòstre estatut :",
|
|
||||||
"notification.mention": "{name} vos a mencionat :",
|
|
||||||
"notifications.column_settings.alert": "Notificacions localas",
|
|
||||||
"notifications.column_settings.show": "Mostrar dins la colomna",
|
|
||||||
"notifications.column_settings.sound": "Emetre un son",
|
|
||||||
"notifications.column_settings.follow": "Nòus abonats :",
|
|
||||||
"notifications.column_settings.favourite": "Favorits :",
|
|
||||||
"notifications.column_settings.mention": "Mencions :",
|
|
||||||
"notifications.column_settings.reblog": "Partatges :",
|
|
||||||
"notifications.clear": "Levar",
|
|
||||||
"notifications.clear_confirmation": "Volètz vertadièrament levar totas vòstras las notificacions ?",
|
|
||||||
"notifications.settings": "Paramètres de la colomna",
|
|
||||||
"privacy.public.short": "Public",
|
|
||||||
"privacy.public.long": "Mostrar dins los fils publics",
|
|
||||||
"privacy.unlisted.short": "Pas-listat",
|
|
||||||
"privacy.unlisted.long": "Mostrar pas dins los fils publics",
|
|
||||||
"privacy.private.short": "Privat",
|
|
||||||
"privacy.private.long": "Mostrar pas qu'a vòstres abonats",
|
|
||||||
"privacy.direct.short": "Dirècte",
|
|
||||||
"privacy.direct.long": "Mostrar pas qu'a las personas mencionadas",
|
|
||||||
"privacy.change": "Ajustar la confidencialitat del messatge",
|
|
||||||
"media_gallery.toggle_visible": "Modificar la visibilitat",
|
|
||||||
"missing_indicator.label": "Pas trobat",
|
|
||||||
"follow_request.authorize": "Autorizar",
|
|
||||||
"follow_request.reject": "Regetar",
|
|
||||||
"home.settings": "Paramètres de la colomna",
|
|
||||||
"home.column_settings.basic": "Basic",
|
|
||||||
"home.column_settings.show_reblogs": "Mostrar los partatges",
|
|
||||||
"home.column_settings.show_replies": "Mostrar las responsas",
|
|
||||||
"home.column_settings.advanced": "Avançat",
|
|
||||||
"home.column_settings.filter_regex": "Filtrar amb una expression racionala",
|
|
||||||
"report.heading": "Nòu senhalament",
|
|
||||||
"report.placeholder": "Comentaris addicionals",
|
|
||||||
"report.submit": "Mandat",
|
|
||||||
"report.target": "Senhalament"
|
|
||||||
};
|
|
||||||
|
|
||||||
export default oc;
|
|
@@ -1,57 +0,0 @@
|
|||||||
const uk = {
|
|
||||||
"column_back_button.label": "Назад",
|
|
||||||
"lightbox.close": "Закрити",
|
|
||||||
"loading_indicator.label": "Завантаження...",
|
|
||||||
"status.mention": "Згадати",
|
|
||||||
"status.delete": "Видалити",
|
|
||||||
"status.reply": "Відповісти",
|
|
||||||
"status.reblog": "Передмухнути",
|
|
||||||
"status.favourite": "Подобається",
|
|
||||||
"status.reblogged_by": "{name} передмухнув(-ла)",
|
|
||||||
"status.sensitive_warning": "Непристойний зміст",
|
|
||||||
"status.sensitive_toggle": "Натисніть, щоб подивитися",
|
|
||||||
"video_player.toggle_sound": "Увімкнути/вимкнути звук",
|
|
||||||
"account.mention": "Згадати",
|
|
||||||
"account.edit_profile": "Налаштування профілю",
|
|
||||||
"account.unblock": "Розблокувати",
|
|
||||||
"account.unfollow": "Відписатися",
|
|
||||||
"account.block": "Заблокувати",
|
|
||||||
"account.follow": "Підписатися",
|
|
||||||
"account.posts": "Пости",
|
|
||||||
"account.follows": "Підписки",
|
|
||||||
"account.followers": "Підписники",
|
|
||||||
"account.follows_you": "Підписаний",
|
|
||||||
"getting_started.heading": "Ласкаво просимо",
|
|
||||||
"getting_started.about_addressing": "Ви можете підписуватись на людей, якщо ви знаєте їх ім'я користувача чи домен, шляхом введення email-подібної адреси у верхньому рядку бокової панелі.",
|
|
||||||
"getting_started.about_shortcuts": "Якщо користувач, якого ви шукаєте, знаходиться на тому ж домені, що й ви, можна просто ввести ім'я користувача. Це правило стосується й згадування людей у статусах.",
|
|
||||||
"getting_started.about_developer": "Розробник проекту знаходиться за адресою Gargron@mastodon.social",
|
|
||||||
"column.home": "Головна",
|
|
||||||
"column.mentions": "Згадування",
|
|
||||||
"column.public": "Стіна",
|
|
||||||
"column.notifications": "Сповіщення",
|
|
||||||
"tabs_bar.compose": "Написати",
|
|
||||||
"tabs_bar.home": "Головна",
|
|
||||||
"tabs_bar.mentions": "Згадування",
|
|
||||||
"tabs_bar.public": "Стіна",
|
|
||||||
"tabs_bar.notifications": "Сповіщення",
|
|
||||||
"compose_form.placeholder": "Що у Вас на думці?",
|
|
||||||
"compose_form.publish": "Дмухнути",
|
|
||||||
"compose_form.sensitive": "Непристойний зміст",
|
|
||||||
"compose_form.unlisted": "Таємний режим",
|
|
||||||
"navigation_bar.edit_profile": "Редагувати профіль",
|
|
||||||
"navigation_bar.preferences": "Налаштування",
|
|
||||||
"navigation_bar.public_timeline": "Публічна стіна",
|
|
||||||
"navigation_bar.logout": "Вийти",
|
|
||||||
"reply_indicator.cancel": "Відмінити",
|
|
||||||
"search.placeholder": "Пошук",
|
|
||||||
"search.account": "Аккаунт",
|
|
||||||
"search.hashtag": "Хештеґ",
|
|
||||||
"upload_button.label": "Додати медіа",
|
|
||||||
"upload_form.undo": "Відмінити",
|
|
||||||
"notification.follow": "{name} підписався(-лась) на Вас",
|
|
||||||
"notification.favourite": "{name} сподобався ваш допис",
|
|
||||||
"notification.reblog": "{name} передмухнув(-ла) Ваш статус",
|
|
||||||
"notification.mention": "{name} згадав(-ла) Вас"
|
|
||||||
};
|
|
||||||
|
|
||||||
export default uk;
|
|
@@ -1,157 +0,0 @@
|
|||||||
import zh from 'react-intl/locale-data/zh';
|
|
||||||
|
|
||||||
const localeData = zh.reduce(function (acc, localeData) {
|
|
||||||
if (localeData.locale === "zh-Hans-CN") {
|
|
||||||
// rename the locale "zh-Hans-CN" as "zh-CN"
|
|
||||||
// (match the code usually used in Accepted-Language header)
|
|
||||||
acc.push(Object.assign({},
|
|
||||||
localeData,
|
|
||||||
{
|
|
||||||
"locale": "zh-CN",
|
|
||||||
"parentLocale": "zh-Hans-CN",
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
export { localeData as localeData };
|
|
||||||
|
|
||||||
const zh_cn = {
|
|
||||||
"account.block": "屏蔽 @{name}",
|
|
||||||
"account.disclaimer": "由于这个账户处于另一个服务站,实际数字会比这个更多。",
|
|
||||||
"account.edit_profile": "修改个人资料",
|
|
||||||
"account.follow": "关注",
|
|
||||||
"account.followers": "关注者",
|
|
||||||
"account.follows_you": "关注你",
|
|
||||||
"account.follows": "正关注",
|
|
||||||
"account.mention": "提及 @{name}",
|
|
||||||
"account.mute": "将 @{name} 静音",
|
|
||||||
"account.posts": "嘟文",
|
|
||||||
"account.report": "举报 @{name}",
|
|
||||||
"account.requested": "等候审批",
|
|
||||||
"account.unblock": "解除对 @{name} 的屏蔽",
|
|
||||||
"account.unfollow": "取消关注",
|
|
||||||
"account.unmute": "取消 @{name} 的静音",
|
|
||||||
"boost_modal.combo": "如你想在下次路过时显示,请按{combo},",
|
|
||||||
"column_back_button.label": "返回",
|
|
||||||
"column.blocks": "屏蔽用户",
|
|
||||||
"column.community": "本站时间轴",
|
|
||||||
// intentional departure from existing "推文" translation for posts:
|
|
||||||
// "推文" refers to "推特", the official translation for Twitter.
|
|
||||||
// Currently using a semi-phonetic translation "嘟", which refers
|
|
||||||
// to train horn sounds, for "toot".
|
|
||||||
"column.favourites": "赞过的嘟文",
|
|
||||||
"column.follow_requests": "关注请求",
|
|
||||||
"column.home": "主页",
|
|
||||||
"column.notifications": "通知",
|
|
||||||
"column.public": "跨站公共时间轴",
|
|
||||||
"compose_form.placeholder": "在想啥?",
|
|
||||||
"compose_form.privacy_disclaimer": "你的私人嘟文,将被发送至你所提及的 {domains} 用户。你是否信任 {domainsCount, plural, one {这个网站} other {这些网站}}?请留意,嘟文隐私设置只适用于各 Mastodon 服务站,如果 {domains} {domainsCount, plural, one {不是 Mastodon 服务站} other {之中有些不是 Mastodon 服务站}},对方将无法收到这篇嘟文的隐私设置,然后可能被转嘟给不能预知的用户阅读。",
|
|
||||||
"compose_form.private": "标示为“只有关注你的人能看”",
|
|
||||||
// Going "toot-toot!" here below.
|
|
||||||
"compose_form.publish": "嘟嘟!",
|
|
||||||
"compose_form.sensitive": "将媒体文件标示为“敏感内容”",
|
|
||||||
"compose_form.spoiler_placeholder": "敏感内容",
|
|
||||||
"compose_form.spoiler": "将部份文本藏于警告消息之后",
|
|
||||||
"compose_form.unlisted": "请勿在公共时间轴显示",
|
|
||||||
"emoji_button.label": "加入表情符号",
|
|
||||||
"empty_column.community": "本站时间轴暂时未有内容,快贴文来抢头香啊!",
|
|
||||||
"empty_column.hashtag": "这个标签暂时未有内容。",
|
|
||||||
"empty_column.home": "你还没有关注任何用户。快看看{public},向其他用户搭讪吧。",
|
|
||||||
"empty_column.home.public_timeline": "公共时间轴",
|
|
||||||
"empty_column.home": "你还没有关注任何用户。快看看{public},向其他用户搭讪吧。",
|
|
||||||
"empty_column.notifications": "你没有任何通知纪录,快向其他用户搭讪吧。",
|
|
||||||
"empty_column.public": "跨站公共时间轴暂时没有内容!快写一些公共的嘟文,或者关注另一些服务站的用户吧!你和本站、友站的交流,将决定这里出现的内容。",
|
|
||||||
"follow_request.authorize": "批准",
|
|
||||||
"follow_request.reject": "拒绝",
|
|
||||||
"getting_started.about_addressing": "只要你知道一位用户的用户名称和域名,你可以用“@用户名称@域名”的格式在搜索栏寻找该用户。",
|
|
||||||
"getting_started.about_shortcuts": "只要该用户是在你现在的服务站开立,你就可以直接输入用户名搜索。在嘟文中提及别的用户也是如此。",
|
|
||||||
"getting_started.apps": "手机或桌面应用程序",
|
|
||||||
"getting_started.heading": "开始使用",
|
|
||||||
"getting_started.open_source_notice": "Mastodon 是一个开放源码的软件。你可以在官方 GitHub ({github}) 贡献或者回报问题。你亦可通过{apps}阅读 Mastodon 上的消息。",
|
|
||||||
"home.column_settings.advanced": "高端",
|
|
||||||
"home.column_settings.basic": "基本",
|
|
||||||
"home.column_settings.filter_regex": "使用正则表达式 (regex) 过滤",
|
|
||||||
"home.column_settings.show_reblogs": "显示被转的嘟文",
|
|
||||||
"home.column_settings.show_replies": "显示回应嘟文",
|
|
||||||
"home.settings": "字段设置",
|
|
||||||
"lightbox.close": "关闭",
|
|
||||||
"loading_indicator.label": "加载中...",
|
|
||||||
"media_gallery.toggle_visible": "打开或关上",
|
|
||||||
"missing_indicator.label": "找不到内容",
|
|
||||||
"navigation_bar.blocks": "被屏蔽的用户",
|
|
||||||
"navigation_bar.community_timeline": "本站时间轴",
|
|
||||||
"navigation_bar.edit_profile": "修改个人资料",
|
|
||||||
"navigation_bar.favourites": "赞的内容",
|
|
||||||
"navigation_bar.follow_requests": "关注请求",
|
|
||||||
"navigation_bar.info": "关于本服务站",
|
|
||||||
"navigation_bar.logout": "注销",
|
|
||||||
// intentional departure from https://github.com/tootsuite/mastodon/blob/f864fee1/config/locales/zh-CN.yml#L126:
|
|
||||||
// clashes for settings/preferences
|
|
||||||
"navigation_bar.preferences": "首选项",
|
|
||||||
"navigation_bar.public_timeline": "跨站公共时间轴",
|
|
||||||
"notification.favourite": "{name} 赞你的嘟文",
|
|
||||||
"notification.follow": "{name} 开始关注你",
|
|
||||||
"notification.mention": "{name} 提及你",
|
|
||||||
"notification.reblog": "{name} 转嘟你的嘟文",
|
|
||||||
"notifications.clear_confirmation": "你确定要清空通知纪录吗?",
|
|
||||||
"notifications.clear": "清空通知纪录",
|
|
||||||
"notifications.column_settings.alert": "显示桌面通知",
|
|
||||||
"notifications.column_settings.favourite": "赞你的嘟文:",
|
|
||||||
"notifications.column_settings.follow": "关注你:",
|
|
||||||
"notifications.column_settings.mention": "提及你:",
|
|
||||||
"notifications.column_settings.reblog": "转你的嘟文:",
|
|
||||||
"notifications.column_settings.show": "在通知栏显示",
|
|
||||||
"notifications.column_settings.sound": "播放音效",
|
|
||||||
"notifications.settings": "字段设置",
|
|
||||||
"privacy.change": "调整隐私设置",
|
|
||||||
"privacy.direct.long": "只有提及的用户能看到",
|
|
||||||
"privacy.direct.short": "私人消息",
|
|
||||||
"privacy.private.long": "只有关注你用户能看到",
|
|
||||||
"privacy.private.short": "关注者",
|
|
||||||
"privacy.public.long": "在公共时间轴显示",
|
|
||||||
"privacy.public.short": "公共",
|
|
||||||
"privacy.unlisted.long": "公开,但不在公共时间轴显示",
|
|
||||||
"privacy.unlisted.short": "公开",
|
|
||||||
"reply_indicator.cancel": "取消",
|
|
||||||
"report.heading": "举报",
|
|
||||||
"report.placeholder": "额外消息",
|
|
||||||
"report.submit": "提交",
|
|
||||||
"report.target": "Reporting",
|
|
||||||
"search_results.total": "{count, number} 项结果",
|
|
||||||
"search.account": "用户",
|
|
||||||
"search.hashtag": "标签",
|
|
||||||
"search.placeholder": "搜索",
|
|
||||||
"search.status_by": "按{name}搜索嘟文",
|
|
||||||
"status.delete": "删除",
|
|
||||||
"status.favourite": "赞",
|
|
||||||
"status.load_more": "加载更多",
|
|
||||||
"status.media_hidden": "隐藏媒体内容",
|
|
||||||
"status.mention": "提及 @{name}",
|
|
||||||
"status.open": "展开嘟文",
|
|
||||||
"status.reblog": "转嘟",
|
|
||||||
"status.reblogged_by": "{name} 转嘟",
|
|
||||||
"status.reply": "回应",
|
|
||||||
"status.report": "举报 @{name}",
|
|
||||||
"status.sensitive_toggle": "点击显示",
|
|
||||||
"status.sensitive_warning": "敏感内容",
|
|
||||||
"status.show_less": "减少显示",
|
|
||||||
"status.show_more": "显示更多",
|
|
||||||
"tabs_bar.compose": "撰写",
|
|
||||||
"tabs_bar.federated_timeline": "跨站",
|
|
||||||
"tabs_bar.home": "主页",
|
|
||||||
"tabs_bar.local_timeline": "本站",
|
|
||||||
"tabs_bar.mentions": "提及",
|
|
||||||
"tabs_bar.notifications": "通知",
|
|
||||||
"tabs_bar.public": "跨站公共时间轴",
|
|
||||||
"upload_area.title": "将文件拖放至此上传",
|
|
||||||
"upload_button.label": "上传媒体文件",
|
|
||||||
"upload_form.undo": "还原",
|
|
||||||
"upload_progress.label": "上传中……",
|
|
||||||
"video_player.expand": "展开影片",
|
|
||||||
"video_player.toggle_sound": "开关音效",
|
|
||||||
"video_player.toggle_visible": "打开或关上",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default zh_cn;
|
|
@@ -1,150 +0,0 @@
|
|||||||
import zh from 'react-intl/locale-data/zh';
|
|
||||||
|
|
||||||
const localeData = zh.reduce(function (acc, localeData) {
|
|
||||||
if (localeData.locale === "zh-Hant-HK") {
|
|
||||||
// rename the locale "zh-Hant-HK" as "zh-HK"
|
|
||||||
// (match the code usually used in Accepted-Language header)
|
|
||||||
acc.push(Object.assign({},
|
|
||||||
localeData,
|
|
||||||
{
|
|
||||||
"locale": "zh-HK",
|
|
||||||
"parentLocale": "zh-Hant-HK",
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
export { localeData as localeData };
|
|
||||||
|
|
||||||
const zh_hk = {
|
|
||||||
"account.block": "封鎖 @{name}",
|
|
||||||
"account.disclaimer": "由於這個用戶在另一個服務站,實際數字會比這個更多。",
|
|
||||||
"account.edit_profile": "修改個人資料",
|
|
||||||
"account.follow": "關注",
|
|
||||||
"account.followers": "關注的人",
|
|
||||||
"account.follows_you": "關注你",
|
|
||||||
"account.follows": "正在關注",
|
|
||||||
"account.mention": "提及 @{name}",
|
|
||||||
"account.mute": "將 @{name} 靜音",
|
|
||||||
"account.posts": "文章",
|
|
||||||
"account.report": "舉報 @{name}",
|
|
||||||
"account.requested": "等候審批",
|
|
||||||
"account.unblock": "解除對 @{name} 的封鎖",
|
|
||||||
"account.unfollow": "取消關注",
|
|
||||||
"account.unmute": "取消 @{name} 的靜音",
|
|
||||||
"boost_modal.combo": "如你想在下次路過這顯示,請按{combo},",
|
|
||||||
"column_back_button.label": "返回",
|
|
||||||
"column.blocks": "封鎖用戶",
|
|
||||||
"column.community": "本站時間軸",
|
|
||||||
"column.favourites": "喜歡的文章",
|
|
||||||
"column.follow_requests": "關注請求",
|
|
||||||
"column.home": "主頁",
|
|
||||||
"column.notifications": "通知",
|
|
||||||
"column.public": "跨站公共時間軸",
|
|
||||||
"compose_form.placeholder": "你在想甚麼?",
|
|
||||||
"compose_form.privacy_disclaimer": "你的私人文章,將被遞送至你所提及的 {domains} 用戶。你是否信任 {domainsCount, plural, one {這個網站} other {這些網站}}?請留意,文章私隱設定只適用於各 Mastodon 服務站,如果 {domains} {domainsCount, plural, one {不是 Mastodon 服務站} other {之中有些不是 Mastodon 服務站}},對方將無法收到這篇文章的私隱設定,然後可能被轉推給不能預知的用戶閱讀。",
|
|
||||||
"compose_form.private": "標示為「只有關注你的人能看」",
|
|
||||||
"compose_form.publish": "發文",
|
|
||||||
"compose_form.sensitive": "將媒體檔案標示為「敏感內容」",
|
|
||||||
"compose_form.spoiler_placeholder": "敏感內容",
|
|
||||||
"compose_form.spoiler": "將部份文字藏於警告訊息之後",
|
|
||||||
"compose_form.unlisted": "請勿在公共時間軸顯示",
|
|
||||||
"emoji_button.label": "加入表情符號",
|
|
||||||
"empty_column.community": "本站時間軸暫時未有內容,快貼文來搶頭香啊!",
|
|
||||||
"empty_column.hashtag": "這個標籤暫時未有內容。",
|
|
||||||
"empty_column.home": "你還沒有關注任何用戶。快看看{public},向其他用戶搭訕吧。",
|
|
||||||
"empty_column.home.public_timeline": "公共時間軸",
|
|
||||||
"empty_column.home": "你還沒有關注任何用戶。快看看{public},向其他用戶搭訕吧。",
|
|
||||||
"empty_column.notifications": "你沒有任何通知紀錄,快向其他用戶搭訕吧。",
|
|
||||||
"empty_column.public": "跨站公共時間軸暫時沒有內容!快寫一些公共的文章,或者關注另一些服務站的用戶吧!你和本站、友站的交流,將決定這裏出現的內容。",
|
|
||||||
"follow_request.authorize": "批准",
|
|
||||||
"follow_request.reject": "拒絕",
|
|
||||||
"getting_started.about_addressing": "只要你知道一位用戶的用戶名稱和域名,你可以用「@用戶名稱@域名」的格式在搜尋欄尋找該用戶。",
|
|
||||||
"getting_started.about_shortcuts": "只要該用戶是在你現在的服務站開立,你可以直接輸入用戶𠱷搜尋。同樣的規則適用於在文章提及別的用戶。",
|
|
||||||
"getting_started.apps": "手機或桌面應用程式",
|
|
||||||
"getting_started.heading": "開始使用",
|
|
||||||
"getting_started.open_source_notice": "Mastodon 是一個開放源碼的軟件。你可以在官方 GitHub ({github}) 貢獻或者回報問題。你亦可透過{apps}閱讀 Mastodon 上的消息。",
|
|
||||||
"home.column_settings.advanced": "進階",
|
|
||||||
"home.column_settings.basic": "基本",
|
|
||||||
"home.column_settings.filter_regex": "使用正規表達式 (regular expression) 過濾",
|
|
||||||
"home.column_settings.show_reblogs": "顯示被轉推的文章",
|
|
||||||
"home.column_settings.show_replies": "顯示回應文章",
|
|
||||||
"home.settings": "欄位設定",
|
|
||||||
"lightbox.close": "Close",
|
|
||||||
"loading_indicator.label": "載入中...",
|
|
||||||
"media_gallery.toggle_visible": "打開或關上",
|
|
||||||
"missing_indicator.label": "找不到內容",
|
|
||||||
"navigation_bar.blocks": "被封鎖的用戶",
|
|
||||||
"navigation_bar.community_timeline": "本站時間軸",
|
|
||||||
"navigation_bar.edit_profile": "修改個人資料",
|
|
||||||
"navigation_bar.favourites": "喜歡的內容",
|
|
||||||
"navigation_bar.follow_requests": "關注請求",
|
|
||||||
"navigation_bar.info": "關於本服務站",
|
|
||||||
"navigation_bar.logout": "登出",
|
|
||||||
"navigation_bar.preferences": "偏好設定",
|
|
||||||
"navigation_bar.public_timeline": "跨站公共時間軸",
|
|
||||||
"notification.favourite": "{name} 喜歡你的文章",
|
|
||||||
"notification.follow": "{name} 開始關注你",
|
|
||||||
"notification.mention": "{name} 提及你",
|
|
||||||
"notification.reblog": "{name} 轉推你的文章",
|
|
||||||
"notifications.clear_confirmation": "你確定要清空通知紀錄嗎?",
|
|
||||||
"notifications.clear": "清空通知紀錄",
|
|
||||||
"notifications.column_settings.alert": "顯示桌面通知",
|
|
||||||
"notifications.column_settings.favourite": "喜歡你的文章:",
|
|
||||||
"notifications.column_settings.follow": "關注你:",
|
|
||||||
"notifications.column_settings.mention": "提及你:",
|
|
||||||
"notifications.column_settings.reblog": "轉推你的文章:",
|
|
||||||
"notifications.column_settings.show": "在通知欄顯示",
|
|
||||||
"notifications.column_settings.sound": "播放音效",
|
|
||||||
"notifications.settings": "欄位設定",
|
|
||||||
"privacy.change": "調整私隱設定",
|
|
||||||
"privacy.direct.long": "只有提及的用戶能看到",
|
|
||||||
"privacy.direct.short": "私人訊息",
|
|
||||||
"privacy.private.long": "只有關注你用戶能看到",
|
|
||||||
"privacy.private.short": "關注者",
|
|
||||||
"privacy.public.long": "在公共時間軸顯示",
|
|
||||||
"privacy.public.short": "公共",
|
|
||||||
"privacy.unlisted.long": "公開,但不在公共時間軸顯示",
|
|
||||||
"privacy.unlisted.short": "公開",
|
|
||||||
"reply_indicator.cancel": "取消",
|
|
||||||
"report.heading": "舉報",
|
|
||||||
"report.placeholder": "額外訊息",
|
|
||||||
"report.submit": "提交",
|
|
||||||
"report.target": "Reporting",
|
|
||||||
"search_results.total": "{count, number} 項結果",
|
|
||||||
"search.account": "用戶",
|
|
||||||
"search.hashtag": "標籤",
|
|
||||||
"search.placeholder": "搜尋",
|
|
||||||
"search.status_by": "按{name}搜尋文章",
|
|
||||||
"status.delete": "刪除",
|
|
||||||
"status.favourite": "喜歡",
|
|
||||||
"status.load_more": "載入更多",
|
|
||||||
"status.media_hidden": "隱藏媒體內容",
|
|
||||||
"status.mention": "提及 @{name}",
|
|
||||||
"status.open": "展開文章",
|
|
||||||
"status.reblog": "轉推",
|
|
||||||
"status.reblogged_by": "{name} 轉推",
|
|
||||||
"status.reply": "回應",
|
|
||||||
"status.report": "舉報 @{name}",
|
|
||||||
"status.sensitive_toggle": "點擊顯示",
|
|
||||||
"status.sensitive_warning": "敏感內容",
|
|
||||||
"status.show_less": "減少顯示",
|
|
||||||
"status.show_more": "顯示更多",
|
|
||||||
"tabs_bar.compose": "撰寫",
|
|
||||||
"tabs_bar.federated_timeline": "跨站",
|
|
||||||
"tabs_bar.home": "主頁",
|
|
||||||
"tabs_bar.local_timeline": "本站",
|
|
||||||
"tabs_bar.mentions": "提及",
|
|
||||||
"tabs_bar.notifications": "通知",
|
|
||||||
"tabs_bar.public": "跨站公共時間軸",
|
|
||||||
"upload_area.title": "將檔案拖放至此上載",
|
|
||||||
"upload_button.label": "上載媒體檔案",
|
|
||||||
"upload_form.undo": "還原",
|
|
||||||
"upload_progress.label": "上載中……",
|
|
||||||
"video_player.expand": "展開影片",
|
|
||||||
"video_player.toggle_sound": "開關音效",
|
|
||||||
"video_player.toggle_visible": "打開或關上",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default zh_hk;
|
|
@@ -1,22 +0,0 @@
|
|||||||
const play = audio => {
|
|
||||||
if (!audio.paused) {
|
|
||||||
audio.pause();
|
|
||||||
audio.fastSeek(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
audio.play();
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function soundsMiddleware() {
|
|
||||||
const soundCache = {
|
|
||||||
boop: new Audio(['/sounds/boop.mp3'])
|
|
||||||
};
|
|
||||||
|
|
||||||
return ({ dispatch }) => next => (action) => {
|
|
||||||
if (action.meta && action.meta.sound && soundCache[action.meta.sound]) {
|
|
||||||
play(soundCache[action.meta.sound]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return next(action);
|
|
||||||
};
|
|
||||||
};
|
|
@@ -1,40 +0,0 @@
|
|||||||
import emojify from './components/emoji'
|
|
||||||
|
|
||||||
$(() => {
|
|
||||||
$.each($('.emojify'), (_, content) => {
|
|
||||||
const $content = $(content);
|
|
||||||
$content.html(emojify($content.html()));
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.video-player video').on('click', e => {
|
|
||||||
if (e.target.paused) {
|
|
||||||
e.target.play();
|
|
||||||
} else {
|
|
||||||
e.target.pause();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.media-spoiler').on('click', e => {
|
|
||||||
$(e.target).hide();
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.webapp-btn').on('click', e => {
|
|
||||||
if (e.button === 0) {
|
|
||||||
e.preventDefault();
|
|
||||||
window.location.href = $(e.target).attr('href');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.status__content__spoiler-link').on('click', e => {
|
|
||||||
e.preventDefault();
|
|
||||||
const contentEl = $(e.target).parent().parent().find('div');
|
|
||||||
|
|
||||||
if (contentEl.is(':visible')) {
|
|
||||||
contentEl.hide();
|
|
||||||
$(e.target).parent().attr('style', 'margin-bottom: 0');
|
|
||||||
} else {
|
|
||||||
contentEl.show();
|
|
||||||
$(e.target).parent().attr('style', null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -1,10 +0,0 @@
|
|||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
src: font-url('montserrat/Montserrat-Regular.eot');
|
|
||||||
src: font-url('montserrat/Montserrat-Regular.eot?#iefix') format('embedded-opentype'),
|
|
||||||
font-url('montserrat/Montserrat-Regular.woff2') format('woff2'),
|
|
||||||
font-url('montserrat/Montserrat-Regular.woff') format('woff'),
|
|
||||||
font-url('montserrat/Montserrat-Regular.ttf') format('truetype');
|
|
||||||
font-weight: 400;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
@font-face {
|
|
||||||
font-family: 'Roboto Mono';
|
|
||||||
src: font-url('roboto-mono/robotomono-regular-webfont.eot');
|
|
||||||
src: font-url('roboto-mono/robotomono-regular-webfont.eot?#iefix') format('embedded-opentype'),
|
|
||||||
font-url('roboto-mono/robotomono-regular-webfont.woff2') format('woff2'),
|
|
||||||
font-url('roboto-mono/robotomono-regular-webfont.woff') format('woff'),
|
|
||||||
font-url('roboto-mono/robotomono-regular-webfont.ttf') format('truetype'),
|
|
||||||
font-url('roboto-mono/robotomono-regular-webfont.svg#roboto_monoregular') format('svg');
|
|
||||||
font-weight: 400;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
@@ -1,48 +0,0 @@
|
|||||||
@font-face {
|
|
||||||
font-family: 'Roboto';
|
|
||||||
src: font-url('roboto/roboto-italic-webfont.eot');
|
|
||||||
src: font-url('roboto/roboto-italic-webfont.eot?#iefix') format('embedded-opentype'),
|
|
||||||
font-url('roboto/roboto-italic-webfont.woff2') format('woff2'),
|
|
||||||
font-url('roboto/roboto-italic-webfont.woff') format('woff'),
|
|
||||||
font-url('roboto/roboto-italic-webfont.ttf') format('truetype'),
|
|
||||||
font-url('roboto/roboto-italic-webfont.svg#roboto-italic-webfont') format('svg');
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto';
|
|
||||||
src: font-url('roboto/roboto-bold-webfont.eot');
|
|
||||||
src: local('Roboto bold'), local('roboto-bold'),
|
|
||||||
font-url('roboto/roboto-bold-webfont.eot?#iefix') format('embedded-opentype'),
|
|
||||||
font-url('roboto/roboto-bold-webfont.woff2') format('woff2'),
|
|
||||||
font-url('roboto/roboto-bold-webfont.woff') format('woff'),
|
|
||||||
font-url('roboto/roboto-bold-webfont.ttf') format('truetype'),
|
|
||||||
font-url('roboto/roboto-bold-webfont.svg#roboto-bold-webfont') format('svg');
|
|
||||||
font-weight: bold;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto';
|
|
||||||
src: font-url('roboto/roboto-medium-webfont.eot');
|
|
||||||
src: font-url('roboto/roboto-medium-webfont.eot?#iefix') format('embedded-opentype'),
|
|
||||||
font-url('roboto/roboto-medium-webfont.woff2') format('woff2'),
|
|
||||||
font-url('roboto/roboto-medium-webfont.woff') format('woff'),
|
|
||||||
font-url('roboto/roboto-medium-webfont.ttf') format('truetype'),
|
|
||||||
font-url('roboto/roboto-medium-webfont.svg#roboto-medium-webfont') format('svg');
|
|
||||||
font-weight: 500;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto';
|
|
||||||
src: font-url('roboto/roboto-regular-webfont.eot');
|
|
||||||
src: font-url('roboto/roboto-regular-webfont.eot?#iefix') format('embedded-opentype'),
|
|
||||||
font-url('roboto/roboto-regular-webfont.woff2') format('woff2'),
|
|
||||||
font-url('roboto/roboto-regular-webfont.woff') format('woff'),
|
|
||||||
font-url('roboto/roboto-regular-webfont.ttf') format('truetype'),
|
|
||||||
font-url('roboto/roboto-regular-webfont.svg#roboto-regular-webfont') format('svg');
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
@@ -1,271 +0,0 @@
|
|||||||
code {
|
|
||||||
font-family: 'Roboto Mono', monospace;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-container {
|
|
||||||
max-width: 400px;
|
|
||||||
padding: 20px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.simple_form {
|
|
||||||
.input {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.hint {
|
|
||||||
display: block;
|
|
||||||
color: $color3;
|
|
||||||
font-size: 12px;
|
|
||||||
margin-top: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.hint {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
strong {
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label_input {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
label {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
width: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.input.file, .input.select, .input.radio_buttons {
|
|
||||||
padding: 15px 0;
|
|
||||||
margin-bottom: 0;
|
|
||||||
|
|
||||||
label {
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: 16px;
|
|
||||||
color: $color5;
|
|
||||||
display: block;
|
|
||||||
padding-top: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fields-group {
|
|
||||||
margin-bottom: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input.radio_buttons .radio label {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: 14px;
|
|
||||||
color: white;
|
|
||||||
display: block;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input.boolean {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
|
|
||||||
label {
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: 14px;
|
|
||||||
color: white;
|
|
||||||
display: block;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
label.checkbox {
|
|
||||||
position: relative;
|
|
||||||
padding-left: 25px;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=checkbox] {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 1px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hint {
|
|
||||||
padding-left: 25px;
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=text], input[type=number], input[type=email], input[type=password], textarea {
|
|
||||||
background: transparent;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border: 0;
|
|
||||||
border-bottom: 2px solid $color3;
|
|
||||||
border-radius: 2px 2px 0 0;
|
|
||||||
padding: 7px 4px;
|
|
||||||
font-size: 16px;
|
|
||||||
color: $color5;
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
outline: 0;
|
|
||||||
font-family: inherit;
|
|
||||||
resize: vertical;
|
|
||||||
|
|
||||||
&:invalid {
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus:invalid {
|
|
||||||
border-bottom-color: $color6;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:required:valid {
|
|
||||||
border-bottom-color: $color7;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active, &:focus {
|
|
||||||
border-bottom-color: $color4;
|
|
||||||
background: rgba($color8, 0.1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.input.field_with_errors {
|
|
||||||
label {
|
|
||||||
color: $color6;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=text], input[type=email], input[type=password] {
|
|
||||||
border-bottom-color: $color6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.error {
|
|
||||||
display: block;
|
|
||||||
font-weight: 500;
|
|
||||||
color: $color6;
|
|
||||||
margin-top: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
margin-top: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button, .block-button {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
border: 0;
|
|
||||||
border-radius: 4px;
|
|
||||||
background: $color4;
|
|
||||||
color: $color5;
|
|
||||||
font-size: 18px;
|
|
||||||
padding: 10px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
text-decoration: none;
|
|
||||||
text-align: center;
|
|
||||||
box-sizing: border-box;
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: 500;
|
|
||||||
outline: 0;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: lighten($color4, 5%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active, &:focus {
|
|
||||||
position: relative;
|
|
||||||
top: 1px;
|
|
||||||
background-color: darken($color4, 5%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.negative {
|
|
||||||
background: $color6;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: lighten($color6, 5%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active, &:focus {
|
|
||||||
background-color: darken($color6, 5%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.flash-message {
|
|
||||||
background: $color1;
|
|
||||||
color: $color3;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 15px 10px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
box-shadow: 0 0 5px rgba($color8, 0.2);
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
strong {
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-footer {
|
|
||||||
margin-top: 30px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: $color5;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-prompt, .follow-prompt {
|
|
||||||
margin-bottom: 30px;
|
|
||||||
text-align: center;
|
|
||||||
color: $color3;
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 16px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
strong {
|
|
||||||
color: $color2;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.qr-wrapper {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.qr-code {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
background: #fff;
|
|
||||||
padding: 4px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
box-shadow: 0 0 15px rgba($color8, 0.2);
|
|
||||||
display: inline-block;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
display: block;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.qr-alternative {
|
|
||||||
margin-left: 10px;
|
|
||||||
color: $color3;
|
|
||||||
|
|
||||||
samp {
|
|
||||||
display: block;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,8 +0,0 @@
|
|||||||
$color1: #282c37 !default; // darkest
|
|
||||||
$color2: #d9e1e8 !default; // lightest
|
|
||||||
$color3: #9baec8 !default; // lighter
|
|
||||||
$color4: #2b90d9 !default; // vibrant
|
|
||||||
$color5: #ffffff !default; // white
|
|
||||||
$color6: #df405a !default; // error red
|
|
||||||
$color7: #79bd9a !default; // succ green
|
|
||||||
$color8: #000000 !default; // black
|
|
@@ -6,12 +6,12 @@ class AccountsController < ApplicationController
|
|||||||
def show
|
def show
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html do
|
format.html do
|
||||||
@statuses = @account.statuses.permitted_for(@account, current_account).order('id desc').paginate_by_max_id(20, params[:max_id], params[:since_id])
|
@statuses = @account.statuses.permitted_for(@account, current_account).paginate_by_max_id(20, params[:max_id], params[:since_id])
|
||||||
@statuses = cache_collection(@statuses, Status)
|
@statuses = cache_collection(@statuses, Status)
|
||||||
end
|
end
|
||||||
|
|
||||||
format.atom do
|
format.atom do
|
||||||
@entries = @account.stream_entries.order('id desc').where(hidden: false).with_includes.paginate_by_max_id(20, params[:max_id], params[:since_id])
|
@entries = @account.stream_entries.where(hidden: false).with_includes.paginate_by_max_id(20, params[:max_id], params[:since_id])
|
||||||
render xml: AtomSerializer.render(AtomSerializer.new.feed(@account, @entries.to_a))
|
render xml: AtomSerializer.render(AtomSerializer.new.feed(@account, @entries.to_a))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@ -23,7 +23,11 @@ module Admin
|
|||||||
:by_domain,
|
:by_domain,
|
||||||
:silenced,
|
:silenced,
|
||||||
:recent,
|
:recent,
|
||||||
:suspended
|
:suspended,
|
||||||
|
:username,
|
||||||
|
:display_name,
|
||||||
|
:email,
|
||||||
|
:ip
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
16
app/controllers/admin/confirmations_controller.rb
Normal file
16
app/controllers/admin/confirmations_controller.rb
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Admin
|
||||||
|
class ConfirmationsController < BaseController
|
||||||
|
def create
|
||||||
|
account_user.confirm
|
||||||
|
redirect_to admin_accounts_path
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def account_user
|
||||||
|
Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
module Admin
|
module Admin
|
||||||
class DomainBlocksController < BaseController
|
class DomainBlocksController < BaseController
|
||||||
|
before_action :set_domain_block, only: [:show, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@blocks = DomainBlock.page(params[:page])
|
@domain_blocks = DomainBlock.page(params[:page])
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@@ -21,20 +23,25 @@ module Admin
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show; end
|
||||||
@domain_block = DomainBlock.find(params[:id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@domain_block = DomainBlock.find(params[:id])
|
UnblockDomainService.new.call(@domain_block, retroactive_unblock?)
|
||||||
UnblockDomainService.new.call(@domain_block, resource_params[:retroactive])
|
|
||||||
redirect_to admin_domain_blocks_path, notice: I18n.t('admin.domain_blocks.destroyed_msg')
|
redirect_to admin_domain_blocks_path, notice: I18n.t('admin.domain_blocks.destroyed_msg')
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def set_domain_block
|
||||||
|
@domain_block = DomainBlock.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
def resource_params
|
def resource_params
|
||||||
params.require(:domain_block).permit(:domain, :severity, :reject_media, :retroactive)
|
params.require(:domain_block).permit(:domain, :severity, :reject_media, :retroactive)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def retroactive_unblock?
|
||||||
|
ActiveRecord::Type.lookup(:boolean).cast(resource_params[:retroactive])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
module Admin
|
module Admin
|
||||||
class PubsubhubbubController < BaseController
|
class PubsubhubbubController < BaseController
|
||||||
def index
|
def index
|
||||||
@subscriptions = Subscription.order('id desc').includes(:account).page(params[:page])
|
@subscriptions = Subscription.order(id: :desc).includes(:account).page(params[:page])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@@ -2,17 +2,31 @@
|
|||||||
|
|
||||||
module Admin
|
module Admin
|
||||||
class ReportedStatusesController < BaseController
|
class ReportedStatusesController < BaseController
|
||||||
def destroy
|
before_action :set_report
|
||||||
status = Status.find params[:id]
|
before_action :set_status
|
||||||
|
|
||||||
RemovalWorker.perform_async(status.id)
|
def update
|
||||||
redirect_to admin_report_path(report)
|
@status.update(status_params)
|
||||||
|
redirect_to admin_report_path(@report)
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
RemovalWorker.perform_async(@status.id)
|
||||||
|
redirect_to admin_report_path(@report)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def report
|
def status_params
|
||||||
Report.find(params[:report_id])
|
params.require(:status).permit(:sensitive)
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_report
|
||||||
|
@report = Report.find(params[:report_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_status
|
||||||
|
@status = @report.statuses.find(params[:id])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user