Compare commits
29 Commits
cybrespace
...
cybrespace
Author | SHA1 | Date |
---|---|---|
khr | 2a779205b7 | |
khr | f9722a0aec | |
nightpool | 631d141ad0 | |
nightpool | 5a4ab172e1 | |
khr | a0976ecb77 | |
khr | f7030554de | |
khr | 60af6dd3f1 | |
khr | 3591c7e5c4 | |
khr | 5d5a702103 | |
khr | a4af65d84f | |
chr | 785030c998 | |
khr | 1139634e40 | |
khr | a0cd0b061b | |
chr | d2e2033c03 | |
khr | d45e803a36 | |
khr | fed65044bc | |
chr | 39607248fa | |
Andrew | 0c9600eb14 | |
khr | a2aea63ae9 | |
Andrew | 4bfe7c37c2 | |
khr | ef859e16e8 | |
Andrew | 5977b75650 | |
khr | b5280695bd | |
Andrew | 899d149d9e | |
Andrew | 3d5943d761 | |
khr | 319488e77d | |
khr | 4cd6c2e7c5 | |
chr | da9fbb477d | |
khr | 5dc62786c0 |
70
AUTHORS.md
|
@ -9,18 +9,18 @@ and provided thanks to the work of the following contributors:
|
||||||
* [akihikodaki](https://github.com/akihikodaki)
|
* [akihikodaki](https://github.com/akihikodaki)
|
||||||
* [ThibG](https://github.com/ThibG)
|
* [ThibG](https://github.com/ThibG)
|
||||||
* [mjankowski](https://github.com/mjankowski)
|
* [mjankowski](https://github.com/mjankowski)
|
||||||
|
* [dependabot[bot]](https://github.com/apps/dependabot)
|
||||||
* [unarist](https://github.com/unarist)
|
* [unarist](https://github.com/unarist)
|
||||||
* [m4sk1n](https://github.com/m4sk1n)
|
* [m4sk1n](https://github.com/m4sk1n)
|
||||||
* [dependabot[bot]](https://github.com/apps/dependabot)
|
|
||||||
* [yiskah](https://github.com/yiskah)
|
* [yiskah](https://github.com/yiskah)
|
||||||
* [nolanlawson](https://github.com/nolanlawson)
|
* [nolanlawson](https://github.com/nolanlawson)
|
||||||
* [sorin-davidoi](https://github.com/sorin-davidoi)
|
|
||||||
* [ysksn](https://github.com/ysksn)
|
* [ysksn](https://github.com/ysksn)
|
||||||
|
* [sorin-davidoi](https://github.com/sorin-davidoi)
|
||||||
* [abcang](https://github.com/abcang)
|
* [abcang](https://github.com/abcang)
|
||||||
* [lynlynlynx](https://github.com/lynlynlynx)
|
* [lynlynlynx](https://github.com/lynlynlynx)
|
||||||
* [alpaca-tc](https://github.com/alpaca-tc)
|
|
||||||
* [mayaeh](https://github.com/mayaeh)
|
* [mayaeh](https://github.com/mayaeh)
|
||||||
* [renatolond](https://github.com/renatolond)
|
* [renatolond](https://github.com/renatolond)
|
||||||
|
* [alpaca-tc](https://github.com/alpaca-tc)
|
||||||
* [nclm](https://github.com/nclm)
|
* [nclm](https://github.com/nclm)
|
||||||
* [ineffyble](https://github.com/ineffyble)
|
* [ineffyble](https://github.com/ineffyble)
|
||||||
* [jeroenpraat](https://github.com/jeroenpraat)
|
* [jeroenpraat](https://github.com/jeroenpraat)
|
||||||
|
@ -28,9 +28,9 @@ and provided thanks to the work of the following contributors:
|
||||||
* [Quent-in](https://github.com/Quent-in)
|
* [Quent-in](https://github.com/Quent-in)
|
||||||
* [JantsoP](https://github.com/JantsoP)
|
* [JantsoP](https://github.com/JantsoP)
|
||||||
* [mabkenar](https://github.com/mabkenar)
|
* [mabkenar](https://github.com/mabkenar)
|
||||||
|
* [Kjwon15](https://github.com/Kjwon15)
|
||||||
* [nullkal](https://github.com/nullkal)
|
* [nullkal](https://github.com/nullkal)
|
||||||
* [yookoala](https://github.com/yookoala)
|
* [yookoala](https://github.com/yookoala)
|
||||||
* [Kjwon15](https://github.com/Kjwon15)
|
|
||||||
* [shuheiktgw](https://github.com/shuheiktgw)
|
* [shuheiktgw](https://github.com/shuheiktgw)
|
||||||
* [ashfurrow](https://github.com/ashfurrow)
|
* [ashfurrow](https://github.com/ashfurrow)
|
||||||
* [Quenty31](https://github.com/Quenty31)
|
* [Quenty31](https://github.com/Quenty31)
|
||||||
|
@ -48,16 +48,16 @@ and provided thanks to the work of the following contributors:
|
||||||
* [rkarabut](https://github.com/rkarabut)
|
* [rkarabut](https://github.com/rkarabut)
|
||||||
* [yukimochi](https://github.com/yukimochi)
|
* [yukimochi](https://github.com/yukimochi)
|
||||||
* [Artoria2e5](https://github.com/Artoria2e5)
|
* [Artoria2e5](https://github.com/Artoria2e5)
|
||||||
|
* [nightpool](https://github.com/nightpool)
|
||||||
* [marrus-sh](https://github.com/marrus-sh)
|
* [marrus-sh](https://github.com/marrus-sh)
|
||||||
* [krainboltgreene](https://github.com/krainboltgreene)
|
* [krainboltgreene](https://github.com/krainboltgreene)
|
||||||
* [patf](https://github.com/patf)
|
* [pfigel](https://github.com/pfigel)
|
||||||
* [Aldarone](https://github.com/Aldarone)
|
* [Aldarone](https://github.com/Aldarone)
|
||||||
* [BoFFire](https://github.com/BoFFire)
|
* [BoFFire](https://github.com/BoFFire)
|
||||||
* [clworld](https://github.com/clworld)
|
* [clworld](https://github.com/clworld)
|
||||||
* [dracos](https://github.com/dracos)
|
* [dracos](https://github.com/dracos)
|
||||||
* [SerCom_KC](mailto:sercom-kc@users.noreply.github.com)
|
* [SerCom_KC](mailto:sercom-kc@users.noreply.github.com)
|
||||||
* [Sylvhem](https://github.com/Sylvhem)
|
* [Sylvhem](https://github.com/Sylvhem)
|
||||||
* [nightpool](https://github.com/nightpool)
|
|
||||||
* [MasterGroosha](https://github.com/MasterGroosha)
|
* [MasterGroosha](https://github.com/MasterGroosha)
|
||||||
* [JeanGauthier](https://github.com/JeanGauthier)
|
* [JeanGauthier](https://github.com/JeanGauthier)
|
||||||
* [kschaper](https://github.com/kschaper)
|
* [kschaper](https://github.com/kschaper)
|
||||||
|
@ -77,11 +77,14 @@ and provided thanks to the work of the following contributors:
|
||||||
* [johnsudaar](https://github.com/johnsudaar)
|
* [johnsudaar](https://github.com/johnsudaar)
|
||||||
* [trebmuh](https://github.com/trebmuh)
|
* [trebmuh](https://github.com/trebmuh)
|
||||||
* [Rakib Hasan](mailto:rmhasan@gmail.com)
|
* [Rakib Hasan](mailto:rmhasan@gmail.com)
|
||||||
|
* [ashleyhull-versent](https://github.com/ashleyhull-versent)
|
||||||
* [lindwurm](https://github.com/lindwurm)
|
* [lindwurm](https://github.com/lindwurm)
|
||||||
* [victorhck](mailto:victorhck@geeko.site)
|
* [victorhck](mailto:victorhck@geeko.site)
|
||||||
* [voidsatisfaction](https://github.com/voidsatisfaction)
|
* [voidsatisfaction](https://github.com/voidsatisfaction)
|
||||||
|
* [rinsuki](https://github.com/rinsuki)
|
||||||
* [hikari-no-yume](https://github.com/hikari-no-yume)
|
* [hikari-no-yume](https://github.com/hikari-no-yume)
|
||||||
* [angristan](https://github.com/angristan)
|
* [angristan](https://github.com/angristan)
|
||||||
|
* [hinaloe](https://github.com/hinaloe)
|
||||||
* [seefood](https://github.com/seefood)
|
* [seefood](https://github.com/seefood)
|
||||||
* [jackjennings](https://github.com/jackjennings)
|
* [jackjennings](https://github.com/jackjennings)
|
||||||
* [spla](mailto:spla@mastodont.cat)
|
* [spla](mailto:spla@mastodont.cat)
|
||||||
|
@ -92,20 +95,20 @@ and provided thanks to the work of the following contributors:
|
||||||
* [dunn](https://github.com/dunn)
|
* [dunn](https://github.com/dunn)
|
||||||
* [xqus](https://github.com/xqus)
|
* [xqus](https://github.com/xqus)
|
||||||
* [hugogameiro](https://github.com/hugogameiro)
|
* [hugogameiro](https://github.com/hugogameiro)
|
||||||
|
* [ariasuni](https://github.com/ariasuni)
|
||||||
* [pfm-eyesightjp](https://github.com/pfm-eyesightjp)
|
* [pfm-eyesightjp](https://github.com/pfm-eyesightjp)
|
||||||
* [fakenine](https://github.com/fakenine)
|
* [fakenine](https://github.com/fakenine)
|
||||||
* [tsuwatch](https://github.com/tsuwatch)
|
* [tsuwatch](https://github.com/tsuwatch)
|
||||||
* [victorhck](https://github.com/victorhck)
|
* [victorhck](https://github.com/victorhck)
|
||||||
* [ashleyhull-versent](https://github.com/ashleyhull-versent)
|
|
||||||
* [kedamaDQ](https://github.com/kedamaDQ)
|
* [kedamaDQ](https://github.com/kedamaDQ)
|
||||||
* [puckipedia](https://github.com/puckipedia)
|
* [puckipedia](https://github.com/puckipedia)
|
||||||
* [fvh-P](https://github.com/fvh-P)
|
* [fvh-P](https://github.com/fvh-P)
|
||||||
* [contraexemplo](https://github.com/contraexemplo)
|
* [contraexemplo](https://github.com/contraexemplo)
|
||||||
|
* [Aditoo17](https://github.com/Aditoo17)
|
||||||
* [kazu9su](https://github.com/kazu9su)
|
* [kazu9su](https://github.com/kazu9su)
|
||||||
* [Komic](https://github.com/Komic)
|
* [Komic](https://github.com/Komic)
|
||||||
* [lmorchard](https://github.com/lmorchard)
|
* [lmorchard](https://github.com/lmorchard)
|
||||||
* [diomed](https://github.com/diomed)
|
* [diomed](https://github.com/diomed)
|
||||||
* [ariasuni](https://github.com/ariasuni)
|
|
||||||
* [Neetshin](mailto:neetshin@neetsh.in)
|
* [Neetshin](mailto:neetshin@neetsh.in)
|
||||||
* [rainyday](https://github.com/rainyday)
|
* [rainyday](https://github.com/rainyday)
|
||||||
* [ProgVal](https://github.com/ProgVal)
|
* [ProgVal](https://github.com/ProgVal)
|
||||||
|
@ -114,7 +117,8 @@ and provided thanks to the work of the following contributors:
|
||||||
* [goofy-bz](mailto:goofy@babelzilla.org)
|
* [goofy-bz](mailto:goofy@babelzilla.org)
|
||||||
* [kadiix](https://github.com/kadiix)
|
* [kadiix](https://github.com/kadiix)
|
||||||
* [kodacs](https://github.com/kodacs)
|
* [kodacs](https://github.com/kodacs)
|
||||||
* [rtucker](https://github.com/rtucker)
|
* [trwnh](https://github.com/trwnh)
|
||||||
|
* [JMendyk](https://github.com/JMendyk)
|
||||||
* [KScl](https://github.com/KScl)
|
* [KScl](https://github.com/KScl)
|
||||||
* [sterdev](https://github.com/sterdev)
|
* [sterdev](https://github.com/sterdev)
|
||||||
* [TheKinrar](https://github.com/TheKinrar)
|
* [TheKinrar](https://github.com/TheKinrar)
|
||||||
|
@ -125,16 +129,16 @@ and provided thanks to the work of the following contributors:
|
||||||
* [fhemberger](https://github.com/fhemberger)
|
* [fhemberger](https://github.com/fhemberger)
|
||||||
* [greysteil](https://github.com/greysteil)
|
* [greysteil](https://github.com/greysteil)
|
||||||
* [hensmith](https://github.com/hensmith)
|
* [hensmith](https://github.com/hensmith)
|
||||||
* [hinaloe](https://github.com/hinaloe)
|
|
||||||
* [d6rkaiz](https://github.com/d6rkaiz)
|
* [d6rkaiz](https://github.com/d6rkaiz)
|
||||||
* [Reverite](https://github.com/Reverite)
|
* [Reverite](https://github.com/Reverite)
|
||||||
* [JMendyk](https://github.com/JMendyk)
|
|
||||||
* [JohnD28](https://github.com/JohnD28)
|
* [JohnD28](https://github.com/JohnD28)
|
||||||
* [znz](https://github.com/znz)
|
* [znz](https://github.com/znz)
|
||||||
* [Naouak](https://github.com/Naouak)
|
* [Naouak](https://github.com/Naouak)
|
||||||
* [pawelngei](https://github.com/pawelngei)
|
* [pawelngei](https://github.com/pawelngei)
|
||||||
|
* [rtucker](https://github.com/rtucker)
|
||||||
* [reneklacan](https://github.com/reneklacan)
|
* [reneklacan](https://github.com/reneklacan)
|
||||||
* [ekiru](https://github.com/ekiru)
|
* [ekiru](https://github.com/ekiru)
|
||||||
|
* [noellabo](https://github.com/noellabo)
|
||||||
* [tcitworld](https://github.com/tcitworld)
|
* [tcitworld](https://github.com/tcitworld)
|
||||||
* [geta6](https://github.com/geta6)
|
* [geta6](https://github.com/geta6)
|
||||||
* [happycoloredbanana](https://github.com/happycoloredbanana)
|
* [happycoloredbanana](https://github.com/happycoloredbanana)
|
||||||
|
@ -144,9 +148,9 @@ and provided thanks to the work of the following contributors:
|
||||||
* [noraworld](https://github.com/noraworld)
|
* [noraworld](https://github.com/noraworld)
|
||||||
* [theboss](https://github.com/theboss)
|
* [theboss](https://github.com/theboss)
|
||||||
* [178inaba](https://github.com/178inaba)
|
* [178inaba](https://github.com/178inaba)
|
||||||
* [Aditoo17](https://github.com/Aditoo17)
|
|
||||||
* [alyssais](https://github.com/alyssais)
|
* [alyssais](https://github.com/alyssais)
|
||||||
* [kodnaplakal](https://github.com/kodnaplakal)
|
* [hiphref](https://github.com/hiphref)
|
||||||
|
* [BenLubar](https://github.com/BenLubar)
|
||||||
* [stalker314314](https://github.com/stalker314314)
|
* [stalker314314](https://github.com/stalker314314)
|
||||||
* [huertanix](https://github.com/huertanix)
|
* [huertanix](https://github.com/huertanix)
|
||||||
* [genesixx](https://github.com/genesixx)
|
* [genesixx](https://github.com/genesixx)
|
||||||
|
@ -157,6 +161,7 @@ and provided thanks to the work of the following contributors:
|
||||||
* [kmichl](https://github.com/kmichl)
|
* [kmichl](https://github.com/kmichl)
|
||||||
* [Kurtis Rainbolt-Greene](mailto:me@kurtisrainboltgreene.name)
|
* [Kurtis Rainbolt-Greene](mailto:me@kurtisrainboltgreene.name)
|
||||||
* [saper](https://github.com/saper)
|
* [saper](https://github.com/saper)
|
||||||
|
* [marek-lach](https://github.com/marek-lach)
|
||||||
* [nevillepark](https://github.com/nevillepark)
|
* [nevillepark](https://github.com/nevillepark)
|
||||||
* [ornithocoder](https://github.com/ornithocoder)
|
* [ornithocoder](https://github.com/ornithocoder)
|
||||||
* [pierreozoux](https://github.com/pierreozoux)
|
* [pierreozoux](https://github.com/pierreozoux)
|
||||||
|
@ -164,7 +169,6 @@ and provided thanks to the work of the following contributors:
|
||||||
* [Ram Lmn](mailto:ramlmn@users.noreply.github.com)
|
* [Ram Lmn](mailto:ramlmn@users.noreply.github.com)
|
||||||
* [harukasan](https://github.com/harukasan)
|
* [harukasan](https://github.com/harukasan)
|
||||||
* [stamak](https://github.com/stamak)
|
* [stamak](https://github.com/stamak)
|
||||||
* [noellabo](https://github.com/noellabo)
|
|
||||||
* [Technowix](mailto:technowix@users.noreply.github.com)
|
* [Technowix](mailto:technowix@users.noreply.github.com)
|
||||||
* [Eychics](https://github.com/Eychics)
|
* [Eychics](https://github.com/Eychics)
|
||||||
* [Thor Harald Johansen](mailto:thj@thj.no)
|
* [Thor Harald Johansen](mailto:thj@thj.no)
|
||||||
|
@ -179,21 +183,20 @@ and provided thanks to the work of the following contributors:
|
||||||
* [hoodie](mailto:hoodiekitten@outlook.com)
|
* [hoodie](mailto:hoodiekitten@outlook.com)
|
||||||
* [luzi82](https://github.com/luzi82)
|
* [luzi82](https://github.com/luzi82)
|
||||||
* [duxovni](https://github.com/duxovni)
|
* [duxovni](https://github.com/duxovni)
|
||||||
* [trwnh](https://github.com/trwnh)
|
* [tmm576](https://github.com/tmm576)
|
||||||
* [unsmell](https://github.com/unsmell)
|
* [unsmell](https://github.com/unsmell)
|
||||||
* [valerauko](https://github.com/valerauko)
|
* [valerauko](https://github.com/valerauko)
|
||||||
* [chriswmartin](https://github.com/chriswmartin)
|
* [chriswmartin](https://github.com/chriswmartin)
|
||||||
* [vahnj](https://github.com/vahnj)
|
* [vahnj](https://github.com/vahnj)
|
||||||
* [ikuradon](https://github.com/ikuradon)
|
* [ikuradon](https://github.com/ikuradon)
|
||||||
* [AndreLewin](https://github.com/AndreLewin)
|
* [AndreLewin](https://github.com/AndreLewin)
|
||||||
* [rinsuki](https://github.com/rinsuki)
|
|
||||||
* [0xflotus](https://github.com/0xflotus)
|
* [0xflotus](https://github.com/0xflotus)
|
||||||
* [redtachyons](https://github.com/redtachyons)
|
* [redtachyons](https://github.com/redtachyons)
|
||||||
* [thurloat](https://github.com/thurloat)
|
* [thurloat](https://github.com/thurloat)
|
||||||
* [aaribaud](https://github.com/aaribaud)
|
* [aaribaud](https://github.com/aaribaud)
|
||||||
|
* [pointlessone](https://github.com/pointlessone)
|
||||||
* [Andrew](mailto:andrewlchronister@gmail.com)
|
* [Andrew](mailto:andrewlchronister@gmail.com)
|
||||||
* [estuans](https://github.com/estuans)
|
* [estuans](https://github.com/estuans)
|
||||||
* [BenLubar](https://github.com/BenLubar)
|
|
||||||
* [dissolve](https://github.com/dissolve)
|
* [dissolve](https://github.com/dissolve)
|
||||||
* [PurpleBooth](https://github.com/PurpleBooth)
|
* [PurpleBooth](https://github.com/PurpleBooth)
|
||||||
* [bradurani](https://github.com/bradurani)
|
* [bradurani](https://github.com/bradurani)
|
||||||
|
@ -216,6 +219,7 @@ and provided thanks to the work of the following contributors:
|
||||||
* [ErikXXon](https://github.com/ErikXXon)
|
* [ErikXXon](https://github.com/ErikXXon)
|
||||||
* [ian-kelling](https://github.com/ian-kelling)
|
* [ian-kelling](https://github.com/ian-kelling)
|
||||||
* [immae](https://github.com/immae)
|
* [immae](https://github.com/immae)
|
||||||
|
* [J0WI](https://github.com/J0WI)
|
||||||
* [foozmeat](https://github.com/foozmeat)
|
* [foozmeat](https://github.com/foozmeat)
|
||||||
* [jasonrhodes](https://github.com/jasonrhodes)
|
* [jasonrhodes](https://github.com/jasonrhodes)
|
||||||
* [Jason Snell](mailto:jason@newrelic.com)
|
* [Jason Snell](mailto:jason@newrelic.com)
|
||||||
|
@ -230,6 +234,7 @@ and provided thanks to the work of the following contributors:
|
||||||
* [Lorenz Diener](mailto:halcyon@icosahedron.website)
|
* [Lorenz Diener](mailto:halcyon@icosahedron.website)
|
||||||
* [alimony](https://github.com/alimony)
|
* [alimony](https://github.com/alimony)
|
||||||
* [mig5](https://github.com/mig5)
|
* [mig5](https://github.com/mig5)
|
||||||
|
* [moritzheiber](https://github.com/moritzheiber)
|
||||||
* [ndarville](https://github.com/ndarville)
|
* [ndarville](https://github.com/ndarville)
|
||||||
* [Abzol](https://github.com/Abzol)
|
* [Abzol](https://github.com/Abzol)
|
||||||
* [pwoolcoc](https://github.com/pwoolcoc)
|
* [pwoolcoc](https://github.com/pwoolcoc)
|
||||||
|
@ -238,6 +243,7 @@ and provided thanks to the work of the following contributors:
|
||||||
* [ignisf](https://github.com/ignisf)
|
* [ignisf](https://github.com/ignisf)
|
||||||
* [raymestalez](https://github.com/raymestalez)
|
* [raymestalez](https://github.com/raymestalez)
|
||||||
* [remram44](https://github.com/remram44)
|
* [remram44](https://github.com/remram44)
|
||||||
|
* [sts10](https://github.com/sts10)
|
||||||
* [sascha-sl](https://github.com/sascha-sl)
|
* [sascha-sl](https://github.com/sascha-sl)
|
||||||
* [u1-liquid](https://github.com/u1-liquid)
|
* [u1-liquid](https://github.com/u1-liquid)
|
||||||
* [sim6](https://github.com/sim6)
|
* [sim6](https://github.com/sim6)
|
||||||
|
@ -288,6 +294,7 @@ and provided thanks to the work of the following contributors:
|
||||||
* [857b](https://github.com/857b)
|
* [857b](https://github.com/857b)
|
||||||
* [insom](https://github.com/insom)
|
* [insom](https://github.com/insom)
|
||||||
* [tachyons](https://github.com/tachyons)
|
* [tachyons](https://github.com/tachyons)
|
||||||
|
* [acid-chicken](https://github.com/acid-chicken)
|
||||||
* [Esteth](https://github.com/Esteth)
|
* [Esteth](https://github.com/Esteth)
|
||||||
* [unascribed](https://github.com/unascribed)
|
* [unascribed](https://github.com/unascribed)
|
||||||
* [Aguay-val](https://github.com/Aguay-val)
|
* [Aguay-val](https://github.com/Aguay-val)
|
||||||
|
@ -297,7 +304,6 @@ and provided thanks to the work of the following contributors:
|
||||||
* [unleashed](https://github.com/unleashed)
|
* [unleashed](https://github.com/unleashed)
|
||||||
* [alxrcs](https://github.com/alxrcs)
|
* [alxrcs](https://github.com/alxrcs)
|
||||||
* [console-cowboy](https://github.com/console-cowboy)
|
* [console-cowboy](https://github.com/console-cowboy)
|
||||||
* [pointlessone](https://github.com/pointlessone)
|
|
||||||
* [Alkarex](https://github.com/Alkarex)
|
* [Alkarex](https://github.com/Alkarex)
|
||||||
* [a2](https://github.com/a2)
|
* [a2](https://github.com/a2)
|
||||||
* [0xa](https://github.com/0xa)
|
* [0xa](https://github.com/0xa)
|
||||||
|
@ -329,6 +335,7 @@ and provided thanks to the work of the following contributors:
|
||||||
* [Motoma](https://github.com/Motoma)
|
* [Motoma](https://github.com/Motoma)
|
||||||
* [chriswk](https://github.com/chriswk)
|
* [chriswk](https://github.com/chriswk)
|
||||||
* [csu](https://github.com/csu)
|
* [csu](https://github.com/csu)
|
||||||
|
* [clarcharr](https://github.com/clarcharr)
|
||||||
* [kklleemm](https://github.com/kklleemm)
|
* [kklleemm](https://github.com/kklleemm)
|
||||||
* [colindean](https://github.com/colindean)
|
* [colindean](https://github.com/colindean)
|
||||||
* [dachinat](https://github.com/dachinat)
|
* [dachinat](https://github.com/dachinat)
|
||||||
|
@ -356,6 +363,7 @@ and provided thanks to the work of the following contributors:
|
||||||
* [espenronnevik](https://github.com/espenronnevik)
|
* [espenronnevik](https://github.com/espenronnevik)
|
||||||
* [Finariel](https://github.com/Finariel)
|
* [Finariel](https://github.com/Finariel)
|
||||||
* [siuying](https://github.com/siuying)
|
* [siuying](https://github.com/siuying)
|
||||||
|
* [zoc](https://github.com/zoc)
|
||||||
* [fwenzel](https://github.com/fwenzel)
|
* [fwenzel](https://github.com/fwenzel)
|
||||||
* [GenbuHase](https://github.com/GenbuHase)
|
* [GenbuHase](https://github.com/GenbuHase)
|
||||||
* [hattori6789](https://github.com/hattori6789)
|
* [hattori6789](https://github.com/hattori6789)
|
||||||
|
@ -416,6 +424,7 @@ and provided thanks to the work of the following contributors:
|
||||||
* [martymcguire](https://github.com/martymcguire)
|
* [martymcguire](https://github.com/martymcguire)
|
||||||
* [marvinkopf](https://github.com/marvinkopf)
|
* [marvinkopf](https://github.com/marvinkopf)
|
||||||
* [otsune](https://github.com/otsune)
|
* [otsune](https://github.com/otsune)
|
||||||
|
* [mbugowski](https://github.com/mbugowski)
|
||||||
* [Mathias B](mailto:10813340+mathias-b@users.noreply.github.com)
|
* [Mathias B](mailto:10813340+mathias-b@users.noreply.github.com)
|
||||||
* [matt-auckland](https://github.com/matt-auckland)
|
* [matt-auckland](https://github.com/matt-auckland)
|
||||||
* [webroo](https://github.com/webroo)
|
* [webroo](https://github.com/webroo)
|
||||||
|
@ -434,7 +443,6 @@ and provided thanks to the work of the following contributors:
|
||||||
* [premist](https://github.com/premist)
|
* [premist](https://github.com/premist)
|
||||||
* [Mnkai](https://github.com/Mnkai)
|
* [Mnkai](https://github.com/Mnkai)
|
||||||
* [mitchhentges](https://github.com/mitchhentges)
|
* [mitchhentges](https://github.com/mitchhentges)
|
||||||
* [moritzheiber](https://github.com/moritzheiber)
|
|
||||||
* [mouse-reeve](https://github.com/mouse-reeve)
|
* [mouse-reeve](https://github.com/mouse-reeve)
|
||||||
* [Mozinet-fr](https://github.com/Mozinet-fr)
|
* [Mozinet-fr](https://github.com/Mozinet-fr)
|
||||||
* [lae](https://github.com/lae)
|
* [lae](https://github.com/lae)
|
||||||
|
@ -458,17 +466,17 @@ and provided thanks to the work of the following contributors:
|
||||||
* [Pangoraw](https://github.com/Pangoraw)
|
* [Pangoraw](https://github.com/Pangoraw)
|
||||||
* [peterkeen](https://github.com/peterkeen)
|
* [peterkeen](https://github.com/peterkeen)
|
||||||
* [pgate](https://github.com/pgate)
|
* [pgate](https://github.com/pgate)
|
||||||
* [retokromer](https://github.com/retokromer)
|
* [Reto Kromer](mailto:retokromer@users.noreply.github.com)
|
||||||
* [rfwatson](https://github.com/rfwatson)
|
* [Rey Tucker](mailto:git@reytucker.us)
|
||||||
* [rfreebern](https://github.com/rfreebern)
|
* [Rob Watson](mailto:rfwatson@users.noreply.github.com)
|
||||||
|
* [Ryan Freebern](mailto:ryan@freebern.org)
|
||||||
* [Ryan Wade](mailto:ryan.wade@protonmail.com)
|
* [Ryan Wade](mailto:ryan.wade@protonmail.com)
|
||||||
* [sylph01](https://github.com/sylph01)
|
* [Ryo Kajiwara](mailto:kfe-fecn6.prussian@s01.info)
|
||||||
* [S-H-GAMELINKS](https://github.com/S-H-GAMELINKS)
|
* [S.H](mailto:gamelinks007@gmail.com)
|
||||||
* [staticsafe](https://github.com/staticsafe)
|
* [Sadiq Saif](mailto:staticsafe@users.noreply.github.com)
|
||||||
* [snwh](https://github.com/snwh)
|
* [Sam Hewitt](mailto:hewittsamuel@gmail.com)
|
||||||
* [sts10](https://github.com/sts10)
|
* [Satoshi KOJIMA](mailto:skoji@mac.com)
|
||||||
* [skoji](https://github.com/skoji)
|
* [ScienJus](mailto:i@scienjus.com)
|
||||||
* [ScienJus](https://github.com/ScienJus)
|
|
||||||
* [Scott Larkin](mailto:scott@codeclimate.com)
|
* [Scott Larkin](mailto:scott@codeclimate.com)
|
||||||
* [Sebastian Hübner](mailto:imolein@users.noreply.github.com)
|
* [Sebastian Hübner](mailto:imolein@users.noreply.github.com)
|
||||||
* [Sebastian Morr](mailto:sebastian@morr.cc)
|
* [Sebastian Morr](mailto:sebastian@morr.cc)
|
||||||
|
@ -483,6 +491,7 @@ and provided thanks to the work of the following contributors:
|
||||||
* [Sir-Boops](mailto:admin@boops.me)
|
* [Sir-Boops](mailto:admin@boops.me)
|
||||||
* [Soshi Kato](mailto:mail@sossii.com)
|
* [Soshi Kato](mailto:mail@sossii.com)
|
||||||
* [Spanky](mailto:2788886+spankyworks@users.noreply.github.com)
|
* [Spanky](mailto:2788886+spankyworks@users.noreply.github.com)
|
||||||
|
* [Stanislas](mailto:angristan@pm.me)
|
||||||
* [StefOfficiel](mailto:pichard.stephane@free.fr)
|
* [StefOfficiel](mailto:pichard.stephane@free.fr)
|
||||||
* [Steven Tappert](mailto:admin@dark-it.net)
|
* [Steven Tappert](mailto:admin@dark-it.net)
|
||||||
* [Svetlozar Todorov](mailto:svetlik@users.noreply.github.com)
|
* [Svetlozar Todorov](mailto:svetlik@users.noreply.github.com)
|
||||||
|
@ -532,6 +541,7 @@ and provided thanks to the work of the following contributors:
|
||||||
* [fsubal](mailto:fsubal@users.noreply.github.com)
|
* [fsubal](mailto:fsubal@users.noreply.github.com)
|
||||||
* [fusshi-](mailto:dikky1218@users.noreply.github.com)
|
* [fusshi-](mailto:dikky1218@users.noreply.github.com)
|
||||||
* [gentaro](mailto:gentaroooo@gmail.com)
|
* [gentaro](mailto:gentaroooo@gmail.com)
|
||||||
|
* [gol-cha](mailto:info@mevo.xyz)
|
||||||
* [hakoai](mailto:hk--76@qa2.so-net.ne.jp)
|
* [hakoai](mailto:hk--76@qa2.so-net.ne.jp)
|
||||||
* [haosbvnker](mailto:github@chaosbunker.com)
|
* [haosbvnker](mailto:github@chaosbunker.com)
|
||||||
* [isati](mailto:phil@juchnowi.cz)
|
* [isati](mailto:phil@juchnowi.cz)
|
||||||
|
@ -549,12 +559,12 @@ and provided thanks to the work of the following contributors:
|
||||||
* [luzpaz](mailto:luzpaz@users.noreply.github.com)
|
* [luzpaz](mailto:luzpaz@users.noreply.github.com)
|
||||||
* [maxypy](mailto:maxime@mpigou.fr)
|
* [maxypy](mailto:maxime@mpigou.fr)
|
||||||
* [mhe](mailto:mail@marcus-herrmann.com)
|
* [mhe](mailto:mail@marcus-herrmann.com)
|
||||||
|
* [mike castleman](mailto:m@mlcastle.net)
|
||||||
* [mimikun](mailto:dzdzble_effort_311@outlook.jp)
|
* [mimikun](mailto:dzdzble_effort_311@outlook.jp)
|
||||||
* [mshrtkch](mailto:mshrtkch@users.noreply.github.com)
|
* [mshrtkch](mailto:mshrtkch@users.noreply.github.com)
|
||||||
* [muan](mailto:muan@github.com)
|
* [muan](mailto:muan@github.com)
|
||||||
* [namelessGonbai](mailto:43787036+namelessgonbai@users.noreply.github.com)
|
* [namelessGonbai](mailto:43787036+namelessgonbai@users.noreply.github.com)
|
||||||
* [neetshin](mailto:neetshin@neetsh.in)
|
* [neetshin](mailto:neetshin@neetsh.in)
|
||||||
* [nightpool](mailto:nightpool@users.noreply.github.com)
|
|
||||||
* [rch850](mailto:rich850@gmail.com)
|
* [rch850](mailto:rich850@gmail.com)
|
||||||
* [roikale](mailto:roikale@users.noreply.github.com)
|
* [roikale](mailto:roikale@users.noreply.github.com)
|
||||||
* [rysiekpl](mailto:rysiek@hackerspace.pl)
|
* [rysiekpl](mailto:rysiek@hackerspace.pl)
|
||||||
|
|
72
CHANGELOG.md
|
@ -3,6 +3,78 @@ Changelog
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [2.7.3] - 2019-02-23
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add domain filter to the admin federation page ([ThibG](https://github.com/tootsuite/mastodon/pull/10071))
|
||||||
|
- Add quick link from admin account view to block/unblock instance ([ThibG](https://github.com/tootsuite/mastodon/pull/10073))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix video player width not being updated to fit container width ([ThibG](https://github.com/tootsuite/mastodon/pull/10069))
|
||||||
|
- Fix domain filter being shown in admin page when local filter is active ([ThibG](https://github.com/tootsuite/mastodon/pull/10074))
|
||||||
|
- Fix crash when conversations have no valid participants ([ThibG](https://github.com/tootsuite/mastodon/pull/10078))
|
||||||
|
- Fix error when performing admin actions on no statuses ([ThibG](https://github.com/tootsuite/mastodon/pull/10094))
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Change custom emojis to randomize stored file name ([hinaloe](https://github.com/tootsuite/mastodon/pull/10090))
|
||||||
|
|
||||||
|
## [2.7.2] - 2019-02-17
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add support for IPv6 in e-mail validation ([zoc](https://github.com/tootsuite/mastodon/pull/10009))
|
||||||
|
- Add record of IP address used for signing up ([ThibG](https://github.com/tootsuite/mastodon/pull/10026))
|
||||||
|
- Add tight rate-limit for API deletions (30 per 30 minutes) ([Gargron](https://github.com/tootsuite/mastodon/pull/10042))
|
||||||
|
- Add support for embedded `Announce` objects attributed to the same actor ([ThibG](https://github.com/tootsuite/mastodon/pull/9998), [Gargron](https://github.com/tootsuite/mastodon/pull/10065))
|
||||||
|
- Add spam filter for `Create` and `Announce` activities ([Gargron](https://github.com/tootsuite/mastodon/pull/10005), [Gargron](https://github.com/tootsuite/mastodon/pull/10041), [Gargron](https://github.com/tootsuite/mastodon/pull/10062))
|
||||||
|
- Add `registrations` attribute to `GET /api/v1/instance` ([Gargron](https://github.com/tootsuite/mastodon/pull/10060))
|
||||||
|
- Add `vapid_key` to `POST /api/v1/apps` and `GET /api/v1/apps/verify_credentials` ([Gargron](https://github.com/tootsuite/mastodon/pull/10058))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix link color and add link underlines in high-contrast theme ([Gargron](https://github.com/tootsuite/mastodon/pull/9949), [Gargron](https://github.com/tootsuite/mastodon/pull/10028))
|
||||||
|
- Fix unicode characters in URLs not being linkified ([JMendyk](https://github.com/tootsuite/mastodon/pull/8447), [hinaloe](https://github.com/tootsuite/mastodon/pull/9991))
|
||||||
|
- Fix URLs linkifier grabbing ending quotation as part of the link ([Gargron](https://github.com/tootsuite/mastodon/pull/9997))
|
||||||
|
- Fix authorized applications page design ([rinsuki](https://github.com/tootsuite/mastodon/pull/9969))
|
||||||
|
- Fix custom emojis not showing up in share page emoji picker ([rinsuki](https://github.com/tootsuite/mastodon/pull/9970))
|
||||||
|
- Fix too liberal application of whitespace in toots ([trwnh](https://github.com/tootsuite/mastodon/pull/9968))
|
||||||
|
- Fix misleading e-mail hint being displayed in admin view ([ThibG](https://github.com/tootsuite/mastodon/pull/9973))
|
||||||
|
- Fix tombstones not being cleared out ([abcang](https://github.com/tootsuite/mastodon/pull/9978))
|
||||||
|
- Fix some timeline jumps ([ThibG](https://github.com/tootsuite/mastodon/pull/9982), [ThibG](https://github.com/tootsuite/mastodon/pull/10001), [rinsuki](https://github.com/tootsuite/mastodon/pull/10046))
|
||||||
|
- Fix content warning input taking keyboard focus even when hidden ([hinaloe](https://github.com/tootsuite/mastodon/pull/10017))
|
||||||
|
- Fix hashtags select styling in default and high-contrast themes ([Gargron](https://github.com/tootsuite/mastodon/pull/10029))
|
||||||
|
- Fix style regressions on landing page ([Gargron](https://github.com/tootsuite/mastodon/pull/10030))
|
||||||
|
- Fix hashtag column not subscribing to stream on mount ([Gargron](https://github.com/tootsuite/mastodon/pull/10040))
|
||||||
|
- Fix relay enabling/disabling not resetting inbox availability status ([Gargron](https://github.com/tootsuite/mastodon/pull/10048))
|
||||||
|
- Fix mutes, blocks, domain blocks and follow requests not paginating ([Gargron](https://github.com/tootsuite/mastodon/pull/10057))
|
||||||
|
- Fix crash on public hashtag pages when streaming fails ([ThibG](https://github.com/tootsuite/mastodon/pull/10061))
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Change icon for unlisted visibility level ([clarcharr](https://github.com/tootsuite/mastodon/pull/9952))
|
||||||
|
- Change queue of actor deletes from push to pull for non-follower recipients ([ThibG](https://github.com/tootsuite/mastodon/pull/10016))
|
||||||
|
- Change robots.txt to exclude media proxy URLs ([nightpool](https://github.com/tootsuite/mastodon/pull/10038))
|
||||||
|
- Change upload description input to allow line breaks ([BenLubar](https://github.com/tootsuite/mastodon/pull/10036))
|
||||||
|
- Change `dist/mastodon-streaming.service` to recommend running node without intermediary npm command ([nolanlawson](https://github.com/tootsuite/mastodon/pull/10032))
|
||||||
|
- Change conversations to always show names of other participants ([Gargron](https://github.com/tootsuite/mastodon/pull/10047))
|
||||||
|
- Change buttons on timeline preview to open the interaction dialog ([Gargron](https://github.com/tootsuite/mastodon/pull/10054))
|
||||||
|
- Change error graphic to hover-to-play ([Gargron](https://github.com/tootsuite/mastodon/pull/10055))
|
||||||
|
|
||||||
|
## [2.7.1] - 2019-01-28
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix SSO authentication not working due to missing agreement boolean ([Gargron](https://github.com/tootsuite/mastodon/pull/9915))
|
||||||
|
- Fix slow fallback of CopyAccountStats migration setting stats to 0 ([Gargron](https://github.com/tootsuite/mastodon/pull/9930))
|
||||||
|
- Fix wrong command in migration error message ([angristan](https://github.com/tootsuite/mastodon/pull/9877))
|
||||||
|
- Fix initial value of volume slider in video player and handle volume changes ([ThibG](https://github.com/tootsuite/mastodon/pull/9929))
|
||||||
|
- Fix missing hotkeys for notifications ([ThibG](https://github.com/tootsuite/mastodon/pull/9927))
|
||||||
|
- Fix being able to attach unattached media created by other users ([ThibG](https://github.com/tootsuite/mastodon/pull/9921))
|
||||||
|
- Fix unrescued SSL error during link verification ([renatolond](https://github.com/tootsuite/mastodon/pull/9914))
|
||||||
|
- Fix Firefox scrollbar color regression ([trwnh](https://github.com/tootsuite/mastodon/pull/9908))
|
||||||
|
- Fix scheduled status with media immediately creating a status ([ThibG](https://github.com/tootsuite/mastodon/pull/9894))
|
||||||
|
- Fix missing strong style for landing page description ([Kjwon15](https://github.com/tootsuite/mastodon/pull/9892))
|
||||||
|
|
||||||
## [2.7.0] - 2019-01-20
|
## [2.7.0] - 2019-01-20
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ You can contribute in the following ways:
|
||||||
- Contributing code to Mastodon by fixing bugs or implementing features
|
- Contributing code to Mastodon by fixing bugs or implementing features
|
||||||
- Improving the documentation
|
- Improving the documentation
|
||||||
|
|
||||||
|
If your contributions are accepted into Mastodon, you can request to be paid through [our OpenCollective](https://opencollective.com/mastodon).
|
||||||
|
|
||||||
## Bug reports
|
## Bug reports
|
||||||
|
|
||||||
Bug reports and feature suggestions can be submitted to [GitHub Issues](https://github.com/tootsuite/mastodon/issues). Please make sure that you are not submitting duplicates, and that a similar report or request has not already been resolved or rejected in the past using the search function. Please also use descriptive, concise titles.
|
Bug reports and feature suggestions can be submitted to [GitHub Issues](https://github.com/tootsuite/mastodon/issues). Please make sure that you are not submitting duplicates, and that a similar report or request has not already been resolved or rejected in the past using the search function. Please also use descriptive, concise titles.
|
||||||
|
|
2
Gemfile
|
@ -23,7 +23,7 @@ gem 'paperclip-av-transcoder', '~> 0.6'
|
||||||
gem 'streamio-ffmpeg', '~> 3.0'
|
gem 'streamio-ffmpeg', '~> 3.0'
|
||||||
|
|
||||||
gem 'active_model_serializers', '~> 0.10'
|
gem 'active_model_serializers', '~> 0.10'
|
||||||
gem 'addressable', '~> 2.5'
|
gem 'addressable', '~> 2.6'
|
||||||
gem 'bootsnap', '~> 1.3', require: false
|
gem 'bootsnap', '~> 1.3', require: false
|
||||||
gem 'browser'
|
gem 'browser'
|
||||||
gem 'charlock_holmes', '~> 0.7.6'
|
gem 'charlock_holmes', '~> 0.7.6'
|
||||||
|
|
18
Gemfile.lock
|
@ -62,7 +62,7 @@ GEM
|
||||||
i18n (>= 0.7, < 2)
|
i18n (>= 0.7, < 2)
|
||||||
minitest (~> 5.1)
|
minitest (~> 5.1)
|
||||||
tzinfo (~> 1.1)
|
tzinfo (~> 1.1)
|
||||||
addressable (2.5.2)
|
addressable (2.6.0)
|
||||||
public_suffix (>= 2.0.2, < 4.0)
|
public_suffix (>= 2.0.2, < 4.0)
|
||||||
airbrussh (1.3.0)
|
airbrussh (1.3.0)
|
||||||
sshkit (>= 1.6.1, != 1.7.0)
|
sshkit (>= 1.6.1, != 1.7.0)
|
||||||
|
@ -290,8 +290,8 @@ GEM
|
||||||
json-ld (3.0.2)
|
json-ld (3.0.2)
|
||||||
multi_json (~> 1.12)
|
multi_json (~> 1.12)
|
||||||
rdf (>= 2.2.8, < 4.0)
|
rdf (>= 2.2.8, < 4.0)
|
||||||
json-ld-preloaded (3.0.0)
|
json-ld-preloaded (3.0.2)
|
||||||
json-ld (>= 2.2, < 4.0)
|
json-ld (~> 3.0)
|
||||||
multi_json (~> 1.12)
|
multi_json (~> 1.12)
|
||||||
rdf (~> 3.0)
|
rdf (~> 3.0)
|
||||||
jsonapi-renderer (0.2.0)
|
jsonapi-renderer (0.2.0)
|
||||||
|
@ -363,7 +363,7 @@ GEM
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
sidekiq (>= 3.5)
|
sidekiq (>= 3.5)
|
||||||
statsd-ruby (~> 1.4, >= 1.4.0)
|
statsd-ruby (~> 1.4, >= 1.4.0)
|
||||||
oj (3.7.7)
|
oj (3.7.8)
|
||||||
omniauth (1.9.0)
|
omniauth (1.9.0)
|
||||||
hashie (>= 3.4.6, < 3.7.0)
|
hashie (>= 3.4.6, < 3.7.0)
|
||||||
rack (>= 1.6.2, < 3)
|
rack (>= 1.6.2, < 3)
|
||||||
|
@ -389,7 +389,7 @@ 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.12.1)
|
parallel (1.13.0)
|
||||||
parallel_tests (2.27.1)
|
parallel_tests (2.27.1)
|
||||||
parallel
|
parallel
|
||||||
parser (2.6.0.0)
|
parser (2.6.0.0)
|
||||||
|
@ -420,7 +420,7 @@ GEM
|
||||||
pry (>= 0.10.4)
|
pry (>= 0.10.4)
|
||||||
public_suffix (3.0.3)
|
public_suffix (3.0.3)
|
||||||
puma (3.12.0)
|
puma (3.12.0)
|
||||||
pundit (2.0.0)
|
pundit (2.0.1)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
raabro (1.1.6)
|
raabro (1.1.6)
|
||||||
rack (2.0.6)
|
rack (2.0.6)
|
||||||
|
@ -513,7 +513,7 @@ GEM
|
||||||
rspec-mocks (3.8.0)
|
rspec-mocks (3.8.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.8.0)
|
rspec-support (~> 3.8.0)
|
||||||
rspec-rails (3.8.1)
|
rspec-rails (3.8.2)
|
||||||
actionpack (>= 3.0)
|
actionpack (>= 3.0)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
railties (>= 3.0)
|
railties (>= 3.0)
|
||||||
|
@ -525,7 +525,7 @@ GEM
|
||||||
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.8.0)
|
rspec-support (3.8.0)
|
||||||
rubocop (0.63.0)
|
rubocop (0.63.1)
|
||||||
jaro_winkler (~> 1.5.1)
|
jaro_winkler (~> 1.5.1)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 2.5, != 2.5.1.1)
|
parser (>= 2.5, != 2.5.1.1)
|
||||||
|
@ -655,7 +655,7 @@ PLATFORMS
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
active_model_serializers (~> 0.10)
|
active_model_serializers (~> 0.10)
|
||||||
active_record_query_trace (~> 1.5)
|
active_record_query_trace (~> 1.5)
|
||||||
addressable (~> 2.5)
|
addressable (~> 2.6)
|
||||||
annotate (~> 2.7)
|
annotate (~> 2.7)
|
||||||
aws-sdk-s3 (~> 1.30)
|
aws-sdk-s3 (~> 1.30)
|
||||||
better_errors (~> 2.5)
|
better_errors (~> 2.5)
|
||||||
|
|
|
@ -80,13 +80,13 @@ A **Vagrant** configuration is included for development purposes.
|
||||||
|
|
||||||
Mastodon is **free, open source software** licensed under **AGPLv3**.
|
Mastodon is **free, open source software** licensed under **AGPLv3**.
|
||||||
|
|
||||||
You can open issues for bugs you've found or features you think are missing. You can also submit pull requests to this repository, or submit translations using Weblate. To get started, take a look at [CONTRIBUTING.md](CONTRIBUTING.md)
|
You can open issues for bugs you've found or features you think are missing. You can also submit pull requests to this repository, or submit translations using Weblate. To get started, take a look at [CONTRIBUTING.md](CONTRIBUTING.md). If your contributions are accepted into Mastodon, you can request to be paid through [our OpenCollective](https://opencollective.com/mastodon).
|
||||||
|
|
||||||
**IRC channel**: #mastodon on irc.freenode.net
|
**IRC channel**: #mastodon on irc.freenode.net
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright (C) 2016-2018 Eugen Rochko & other Mastodon contributors (see [AUTHORS.md](AUTHORS.md))
|
Copyright (C) 2016-2019 Eugen Rochko & other Mastodon contributors (see [AUTHORS.md](AUTHORS.md))
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ class StatusesIndex < Chewy::Index
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
define_type ::Status.unscoped.without_reblogs do
|
define_type ::Status.unscoped.without_reblogs.includes(:media_attachments) do
|
||||||
crutch :mentions do |collection|
|
crutch :mentions do |collection|
|
||||||
data = ::Mention.where(status_id: collection.map(&:id)).pluck(:status_id, :account_id)
|
data = ::Mention.where(status_id: collection.map(&:id)).pluck(:status_id, :account_id)
|
||||||
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
|
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
|
||||||
|
@ -50,7 +50,7 @@ class StatusesIndex < Chewy::Index
|
||||||
root date_detection: false do
|
root date_detection: false do
|
||||||
field :account_id, type: 'long'
|
field :account_id, type: 'long'
|
||||||
|
|
||||||
field :text, type: 'text', value: ->(status) { [status.spoiler_text, Formatter.instance.plaintext(status)].join("\n\n") } do
|
field :text, type: 'text', value: ->(status) { [status.spoiler_text, Formatter.instance.plaintext(status)].concat(status.media_attachments.map(&:description)).join("\n\n") } do
|
||||||
field :stemmed, type: 'text', analyzer: 'content'
|
field :stemmed, type: 'text', analyzer: 'content'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,9 @@ module Admin
|
||||||
before_action :set_custom_emoji, except: [:index, :new, :create]
|
before_action :set_custom_emoji, except: [:index, :new, :create]
|
||||||
before_action :set_filter_params
|
before_action :set_filter_params
|
||||||
|
|
||||||
|
include ObfuscateFilename
|
||||||
|
obfuscate_filename [:custom_emoji, :image]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
authorize :custom_emoji, :index?
|
authorize :custom_emoji, :index?
|
||||||
@custom_emojis = filtered_custom_emojis.eager_load(:local_counterpart).page(params[:page])
|
@custom_emojis = filtered_custom_emojis.eager_load(:local_counterpart).page(params[:page])
|
||||||
|
|
|
@ -38,7 +38,7 @@ module Admin
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter_params
|
def filter_params
|
||||||
params.permit(:limited)
|
params.permit(:limited, :by_domain)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,6 +10,10 @@ module Admin
|
||||||
@form = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account, action: action_from_button))
|
@form = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account, action: action_from_button))
|
||||||
flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save
|
flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save
|
||||||
|
|
||||||
|
redirect_to admin_report_path(@report)
|
||||||
|
rescue ActionController::ParameterMissing
|
||||||
|
flash[:alert] = I18n.t('admin.statuses.no_status_selected')
|
||||||
|
|
||||||
redirect_to admin_report_path(@report)
|
redirect_to admin_report_path(@report)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,6 @@ class Api::V1::Apps::CredentialsController < Api::BaseController
|
||||||
respond_to :json
|
respond_to :json
|
||||||
|
|
||||||
def show
|
def show
|
||||||
render json: doorkeeper_token.application, serializer: REST::StatusSerializer::ApplicationSerializer
|
render json: doorkeeper_token.application, serializer: REST::ApplicationSerializer, fields: %i(name website vapid_key)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -28,6 +28,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
|
||||||
resource.invite_code = params[:invite_code] if resource.invite_code.blank?
|
resource.invite_code = params[:invite_code] if resource.invite_code.blank?
|
||||||
resource.agreement = true
|
resource.agreement = true
|
||||||
|
|
||||||
|
resource.current_sign_in_ip = request.remote_ip if resource.current_sign_in_ip.nil?
|
||||||
resource.build_account if resource.account.nil?
|
resource.build_account if resource.account.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,12 @@ module Localized
|
||||||
if ENV['DEFAULT_LOCALE'].present?
|
if ENV['DEFAULT_LOCALE'].present?
|
||||||
I18n.default_locale
|
I18n.default_locale
|
||||||
else
|
else
|
||||||
request_locale || I18n.default_locale
|
case request_locale
|
||||||
|
when /en\b/, nil
|
||||||
|
I18n.default_locale
|
||||||
|
else
|
||||||
|
request_locale
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicatio
|
||||||
|
|
||||||
before_action :store_current_location
|
before_action :store_current_location
|
||||||
before_action :authenticate_resource_owner!
|
before_action :authenticate_resource_owner!
|
||||||
|
before_action :set_body_classes
|
||||||
|
|
||||||
include Localized
|
include Localized
|
||||||
|
|
||||||
|
@ -15,6 +16,10 @@ class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicatio
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def set_body_classes
|
||||||
|
@body_classes = 'admin'
|
||||||
|
end
|
||||||
|
|
||||||
def store_current_location
|
def store_current_location
|
||||||
store_location_for(:user, request.url)
|
store_location_for(:user, request.url)
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,7 +6,7 @@ module Admin::FilterHelper
|
||||||
INVITE_FILTER = %i(available expired).freeze
|
INVITE_FILTER = %i(available expired).freeze
|
||||||
CUSTOM_EMOJI_FILTERS = %i(local remote by_domain shortcode).freeze
|
CUSTOM_EMOJI_FILTERS = %i(local remote by_domain shortcode).freeze
|
||||||
TAGS_FILTERS = %i(hidden).freeze
|
TAGS_FILTERS = %i(hidden).freeze
|
||||||
INSTANCES_FILTERS = %i(limited).freeze
|
INSTANCES_FILTERS = %i(limited by_domain).freeze
|
||||||
|
|
||||||
FILTERS = ACCOUNT_FILTERS + REPORT_FILTERS + INVITE_FILTER + CUSTOM_EMOJI_FILTERS + TAGS_FILTERS + INSTANCES_FILTERS
|
FILTERS = ACCOUNT_FILTERS + REPORT_FILTERS + INVITE_FILTER + CUSTOM_EMOJI_FILTERS + TAGS_FILTERS + INSTANCES_FILTERS
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
module SettingsHelper
|
module SettingsHelper
|
||||||
HUMAN_LOCALES = {
|
HUMAN_LOCALES = {
|
||||||
en: 'English',
|
en: 'English',
|
||||||
|
'en-CY': 'English (Cybre)',
|
||||||
ar: 'العربية',
|
ar: 'العربية',
|
||||||
ast: 'l\'asturianu',
|
ast: 'l\'asturianu',
|
||||||
bg: 'Български',
|
bg: 'Български',
|
||||||
|
|
|
@ -170,7 +170,7 @@ module StreamEntriesHelper
|
||||||
when 'public'
|
when 'public'
|
||||||
fa_icon 'globe fw'
|
fa_icon 'globe fw'
|
||||||
when 'unlisted'
|
when 'unlisted'
|
||||||
fa_icon 'unlock-alt fw'
|
fa_icon 'unlock fw'
|
||||||
when 'private'
|
when 'private'
|
||||||
fa_icon 'lock fw'
|
fa_icon 'lock fw'
|
||||||
when 'direct'
|
when 'direct'
|
||||||
|
|
After Width: | Height: | Size: 622 B |
After Width: | Height: | Size: 223 KiB |
After Width: | Height: | Size: 232 KiB |
After Width: | Height: | Size: 378 B |
After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 40 KiB |
|
@ -0,0 +1,64 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="384" version="1.1" height="384">
|
||||||
|
<g transform="translate(-282.71845,-76)" id="RenderLayer_LineSet">
|
||||||
|
<g id="strokes">
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path2" d="m 405.991,306.829 v 10 10 10 10 10 10 10 10 6.581 5.978 9.656 3.057" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path4" d="m 405.991,409.044 v 0 -9.656 -5.978 -10 -10 -10 -10 -10 -10 -10 -10 -6.581" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path6" d="m 370.692,127.899 v 1.329 10 1.4 10 0.947 4.955 2.701 10 10 10 10 10 9.658 10 10 10 10 10 10 1.283" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path8" d="m 439.906,283.073 v 0 h -10 -10 -10.303 -3.612 -10 -10 -10 -2.337 l -2.962,-2.901 v 0" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path10" d="m 373.654,283.073 -2.962,-2.901 v -10 -10 -10 -10 -10 -10 -1.283 -10 -10 -10 -10 -10 -9.658" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path12" d="m 370.692,127.899 h -7.383 -10 -2.899 -5.311 v 0 l -0.45,0.28 -0.37,0.387 -0.268,0.47 v 0.192 10 1.4 10 0.947 4.955 2.701 10 10 10 10 10 9.658 10 10 10 10 10 10 1.283 2.901 10 4.487 5.906 3.363 10 10 10 10 10 10 10 10 6.581 l 6.235,6.039 7.183,6.957 2.643,2.56 3.237,3.135 v 0 h 7.383 2.962 10 10 10 2.337 v 0 0 -3.057" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path14" d="m 584.095,303.466 3.074,3.363 v 10 10 10 10 10 10 10 10 6.581 6.183 9.988 10e-4 0.001 2.518 h 6.497 10 2.976 7.534 v 0 0" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path16" d="m 615.989,393.41 v -10 -10 -10 -10 -10 -10 -10 -10 -6.581 -3.363 -5.906 -10 -4.487 -2.901 -10 -10 -10 -10 -10 -10 -1.283 -10 -10 -10 -10 -10 -9.658 -2.701 -4.955 -10 -0.947 -10 -1.4 -0.061 l -0.299,-0.524 -0.394,-0.413 -0.019,-0.019 v 0" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path18" d="m 584.093,129.228 h -10 -10 -10 -10 l -10,-0.001 h -10 -5.476 -10 -10 -10 -10 -10 -10 l -10,-0.001 h -8.828 -10 -10 -10 -0.326 -3.615 l -10,0.001 h -10 l -10,0.001 h -2.205 -2.951 v 0" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path20" d="m 615.277,128.211 v 0 l -0.501,-0.312 v 0 0 h -8.134 -10 -2.976 -6.497 v 1.329" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path22" d="m 615.69,128.643 0.299,0.524 v 0.061 10 1.4 10 0.947 4.955 2.701 10 10 10 10 10 9.658 10 10 10 10 10 10 1.283 2.901 10 4.487 5.906 3.363 10 10 10 10 10 10 10 10 6.581 6.183 9.987 0.626 l -0.447,0.784 -0.617,0.644 -0.749,0.467" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path24" d="m 587.169,156.53 v 0 0 2.701 10 10 10 10 10 9.658 10 10 10 10 10 10 1.283 l -3.074,2.901 h -10 -10 -10 -10 -10 -10 -5.424" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path26" d="m 370.692,129.228 v -1.329 0 0" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path28" d="m 584.093,129.228 h 3.076" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path30" d="m 350.41,140.628 h 10 2.899 v 10 0.947 h -3.555 -9.344 v 0" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path32" d="m 587.169,129.228 v 10 1.4 10 0.947 4.955" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path34" d="m 350.41,151.575 v -10 -0.947" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path36" d="m 593.666,151.575 v -10 -0.947 0 h 10 2.976" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path38" d="m 606.642,140.628 v 10 0.947 h -10 -2.976 v 0 -10 -0.947" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path40" d="m 615.69,128.643 -0.394,-0.413 -0.019,-0.019 v 0 l -0.501,-0.312" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path42" d="m 615.989,393.41 v 6.183 9.987 0.626 l -0.447,0.783 -0.576,0.603 -0.041,0.042 v 0" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path44" d="m 614.925,411.634 v 0 l -0.749,0.467" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path46" d="m 615.69,128.643 -0.009,-0.01 -0.404,-0.422 -0.501,-0.312" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path48" d="m 614.176,412.101 0.749,-0.467 v 0 l 0.041,-0.042 0.576,-0.603 0.447,-0.783 v -0.626 -9.987 -6.183" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path50" d="m 406.223,306.613 -0.232,0.216 v 0 l 0.232,-0.216 3.38,-3.147 h 10 10 10.303 10 10 10 10 10 10 10 8.765 10 10 1.007" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path52" d="m 518.671,283.073 v 0 h -10 -2.247" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path54" d="m 615.277,128.211 0.404,0.422" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path56" d="m 383.445,273.927 h 10 10 10 10 10 6.461" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path58" d="m 576.555,273.927 2.03,-0.051 1.978,-0.302 1.707,-0.727" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path60" d="m 582.27,272.847 1.099,-1.131 0.456,-1.309 0.077,-1.342" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path62" d="m 583.902,269.065 v -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -9.834 0 -10 -7.959" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path64" d="m 583.902,141.272 -0.077,-1.344 -0.457,-1.309 -1.098,-1.13" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path66" d="m 582.27,137.489 -1.709,-0.727 -1.977,-0.301 -2.029,-0.051" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path68" d="m 576.555,136.41 h -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -3.11 l -2.03,0.051 -1.978,0.302 -1.707,0.726" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path70" d="m 377.73,137.489 -1.099,1.131 -0.456,1.309 -0.077,1.343" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path72" d="m 376.098,269.065 0.077,1.343 0.457,1.309 1.098,1.13" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path74" d="m 377.73,272.847 1.709,0.727 1.977,0.302 2.029,0.051" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path76" d="m 457.882,318.176 v 10 10 10 10 10 10 10 8.996 l -0.375,1.491 -0.542,1.03" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path78" d="m 456.965,399.693 h -10 -10 -8.726 l -0.542,-1.03 -0.375,-1.491" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path80" d="m 539.678,303.466 -0.064,-0.035 h -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10.198 l -1.889,1.029 -1.304,1.491" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path82" d="m 543.74,411.917 v -2.465 -0.024 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -2.742 l -1.686,-1.925 -2.376,-1.295" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path84" d="m 427.612,316.452 0.42,-0.797 h 10 10 8.933 l 0.542,1.03 0.375,1.491" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path86" d="m 427.322,317.607 0.29,-1.155" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path88" d="m 350.41,151.575 v -10 -0.947" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path90" d="m 370.692,127.899 v 0" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path92" d="m 376.098,141.272 v 10 7.954 0.005 10 10 10 10 10 10 10 10 10 10 9.834" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path94" d="m 405.991,409.044 v 3.057" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path96" d="m 406.223,305.951 v 0.662 0 0 0 10 10 10 10 10 10 10 10 10 10 2.333 0.098 2.873" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path98" d="m 427.322,397.172 v -10 -10 -10 -10 -10 -10 -10 -9.565" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path100" d="m 405.991,409.044 h 0.232" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path102" d="m 506.424,283.073 h -3.436 -10 -10 -10 -10 -6.548 -3.543 -10e-4 -10 -2.99" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path104" d="m 406.223,411.917 h 10 10 10 10 10 10 10 10 10 10 10 10 10 7.517" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path106" d="m 518.671,273.927 h 10 10 10 10 10 7.884" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path108" d="m 439.906,273.927 h 6.803 v 0 h 2.704 10 10 10 10 10 10.551 2.65 10e-4 6.056" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path110" d="m 539.678,303.466 h 10 10 10 10 4.417" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path112" d="m 587.169,156.53 v 0" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path114" d="m 543.74,409.452 10,0.029 10,0.03 10,0.03 9.999,0.029 3.43,0.01" />
|
||||||
|
<path style="fill:none;stroke:#87B97D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path116" d="m 615.989,393.41 v -10 -10 -10 -10 -10 -10 -10 -10 -6.581" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,64 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="384" version="1.1" height="384">
|
||||||
|
<g transform="translate(-282.71845,-76)" id="RenderLayer_LineSet">
|
||||||
|
<g id="strokes">
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path2" d="m 405.991,306.829 v 10 10 10 10 10 10 10 10 6.581 5.978 9.656 3.057" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path4" d="m 405.991,409.044 v 0 -9.656 -5.978 -10 -10 -10 -10 -10 -10 -10 -10 -6.581" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path6" d="m 370.692,127.899 v 1.329 10 1.4 10 0.947 4.955 2.701 10 10 10 10 10 9.658 10 10 10 10 10 10 1.283" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path8" d="m 439.906,283.073 v 0 h -10 -10 -10.303 -3.612 -10 -10 -10 -2.337 l -2.962,-2.901 v 0" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path10" d="m 373.654,283.073 -2.962,-2.901 v -10 -10 -10 -10 -10 -10 -1.283 -10 -10 -10 -10 -10 -9.658" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path12" d="m 370.692,127.899 h -7.383 -10 -2.899 -5.311 v 0 l -0.45,0.28 -0.37,0.387 -0.268,0.47 v 0.192 10 1.4 10 0.947 4.955 2.701 10 10 10 10 10 9.658 10 10 10 10 10 10 1.283 2.901 10 4.487 5.906 3.363 10 10 10 10 10 10 10 10 6.581 l 6.235,6.039 7.183,6.957 2.643,2.56 3.237,3.135 v 0 h 7.383 2.962 10 10 10 2.337 v 0 0 -3.057" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path14" d="m 584.095,303.466 3.074,3.363 v 10 10 10 10 10 10 10 10 6.581 6.183 9.988 10e-4 0.001 2.518 h 6.497 10 2.976 7.534 v 0 0" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path16" d="m 615.989,393.41 v -10 -10 -10 -10 -10 -10 -10 -10 -6.581 -3.363 -5.906 -10 -4.487 -2.901 -10 -10 -10 -10 -10 -10 -1.283 -10 -10 -10 -10 -10 -9.658 -2.701 -4.955 -10 -0.947 -10 -1.4 -0.061 l -0.299,-0.524 -0.394,-0.413 -0.019,-0.019 v 0" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path18" d="m 584.093,129.228 h -10 -10 -10 -10 l -10,-0.001 h -10 -5.476 -10 -10 -10 -10 -10 -10 l -10,-0.001 h -8.828 -10 -10 -10 -0.326 -3.615 l -10,0.001 h -10 l -10,0.001 h -2.205 -2.951 v 0" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path20" d="m 615.277,128.211 v 0 l -0.501,-0.312 v 0 0 h -8.134 -10 -2.976 -6.497 v 1.329" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path22" d="m 615.69,128.643 0.299,0.524 v 0.061 10 1.4 10 0.947 4.955 2.701 10 10 10 10 10 9.658 10 10 10 10 10 10 1.283 2.901 10 4.487 5.906 3.363 10 10 10 10 10 10 10 10 6.581 6.183 9.987 0.626 l -0.447,0.784 -0.617,0.644 -0.749,0.467" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path24" d="m 587.169,156.53 v 0 0 2.701 10 10 10 10 10 9.658 10 10 10 10 10 10 1.283 l -3.074,2.901 h -10 -10 -10 -10 -10 -10 -5.424" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path26" d="m 370.692,129.228 v -1.329 0 0" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path28" d="m 584.093,129.228 h 3.076" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path30" d="m 350.41,140.628 h 10 2.899 v 10 0.947 h -3.555 -9.344 v 0" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path32" d="m 587.169,129.228 v 10 1.4 10 0.947 4.955" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path34" d="m 350.41,151.575 v -10 -0.947" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path36" d="m 593.666,151.575 v -10 -0.947 0 h 10 2.976" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path38" d="m 606.642,140.628 v 10 0.947 h -10 -2.976 v 0 -10 -0.947" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path40" d="m 615.69,128.643 -0.394,-0.413 -0.019,-0.019 v 0 l -0.501,-0.312" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path42" d="m 615.989,393.41 v 6.183 9.987 0.626 l -0.447,0.783 -0.576,0.603 -0.041,0.042 v 0" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path44" d="m 614.925,411.634 v 0 l -0.749,0.467" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path46" d="m 615.69,128.643 -0.009,-0.01 -0.404,-0.422 -0.501,-0.312" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path48" d="m 614.176,412.101 0.749,-0.467 v 0 l 0.041,-0.042 0.576,-0.603 0.447,-0.783 v -0.626 -9.987 -6.183" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path50" d="m 406.223,306.613 -0.232,0.216 v 0 l 0.232,-0.216 3.38,-3.147 h 10 10 10.303 10 10 10 10 10 10 10 8.765 10 10 1.007" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path52" d="m 518.671,283.073 v 0 h -10 -2.247" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path54" d="m 615.277,128.211 0.404,0.422" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path56" d="m 383.445,273.927 h 10 10 10 10 10 6.461" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path58" d="m 576.555,273.927 2.03,-0.051 1.978,-0.302 1.707,-0.727" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path60" d="m 582.27,272.847 1.099,-1.131 0.456,-1.309 0.077,-1.342" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path62" d="m 583.902,269.065 v -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -9.834 0 -10 -7.959" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path64" d="m 583.902,141.272 -0.077,-1.344 -0.457,-1.309 -1.098,-1.13" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path66" d="m 582.27,137.489 -1.709,-0.727 -1.977,-0.301 -2.029,-0.051" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path68" d="m 576.555,136.41 h -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -3.11 l -2.03,0.051 -1.978,0.302 -1.707,0.726" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path70" d="m 377.73,137.489 -1.099,1.131 -0.456,1.309 -0.077,1.343" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path72" d="m 376.098,269.065 0.077,1.343 0.457,1.309 1.098,1.13" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path74" d="m 377.73,272.847 1.709,0.727 1.977,0.302 2.029,0.051" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path76" d="m 457.882,318.176 v 10 10 10 10 10 10 10 8.996 l -0.375,1.491 -0.542,1.03" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path78" d="m 456.965,399.693 h -10 -10 -8.726 l -0.542,-1.03 -0.375,-1.491" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path80" d="m 539.678,303.466 -0.064,-0.035 h -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10.198 l -1.889,1.029 -1.304,1.491" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path82" d="m 543.74,411.917 v -2.465 -0.024 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -2.742 l -1.686,-1.925 -2.376,-1.295" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path84" d="m 427.612,316.452 0.42,-0.797 h 10 10 8.933 l 0.542,1.03 0.375,1.491" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path86" d="m 427.322,317.607 0.29,-1.155" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path88" d="m 350.41,151.575 v -10 -0.947" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path90" d="m 370.692,127.899 v 0" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path92" d="m 376.098,141.272 v 10 7.954 0.005 10 10 10 10 10 10 10 10 10 10 9.834" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path94" d="m 405.991,409.044 v 3.057" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path96" d="m 406.223,305.951 v 0.662 0 0 0 10 10 10 10 10 10 10 10 10 10 2.333 0.098 2.873" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path98" d="m 427.322,397.172 v -10 -10 -10 -10 -10 -10 -10 -9.565" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path100" d="m 405.991,409.044 h 0.232" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path102" d="m 506.424,283.073 h -3.436 -10 -10 -10 -10 -6.548 -3.543 -10e-4 -10 -2.99" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path104" d="m 406.223,411.917 h 10 10 10 10 10 10 10 10 10 10 10 10 10 7.517" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path106" d="m 518.671,273.927 h 10 10 10 10 10 7.884" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path108" d="m 439.906,273.927 h 6.803 v 0 h 2.704 10 10 10 10 10 10.551 2.65 10e-4 6.056" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path110" d="m 539.678,303.466 h 10 10 10 10 4.417" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path112" d="m 587.169,156.53 v 0" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path114" d="m 543.74,409.452 10,0.029 10,0.03 10,0.03 9.999,0.029 3.43,0.01" />
|
||||||
|
<path style="fill:none;stroke:#A9713D;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path116" d="m 615.989,393.41 v -10 -10 -10 -10 -10 -10 -10 -10 -6.581" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,64 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="384" version="1.1" height="384">
|
||||||
|
<g transform="translate(-282.71845,-76)" id="RenderLayer_LineSet">
|
||||||
|
<g id="strokes">
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path2" d="m 405.991,306.829 v 10 10 10 10 10 10 10 10 6.581 5.978 9.656 3.057" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path4" d="m 405.991,409.044 v 0 -9.656 -5.978 -10 -10 -10 -10 -10 -10 -10 -10 -6.581" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path6" d="m 370.692,127.899 v 1.329 10 1.4 10 0.947 4.955 2.701 10 10 10 10 10 9.658 10 10 10 10 10 10 1.283" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path8" d="m 439.906,283.073 v 0 h -10 -10 -10.303 -3.612 -10 -10 -10 -2.337 l -2.962,-2.901 v 0" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path10" d="m 373.654,283.073 -2.962,-2.901 v -10 -10 -10 -10 -10 -10 -1.283 -10 -10 -10 -10 -10 -9.658" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path12" d="m 370.692,127.899 h -7.383 -10 -2.899 -5.311 v 0 l -0.45,0.28 -0.37,0.387 -0.268,0.47 v 0.192 10 1.4 10 0.947 4.955 2.701 10 10 10 10 10 9.658 10 10 10 10 10 10 1.283 2.901 10 4.487 5.906 3.363 10 10 10 10 10 10 10 10 6.581 l 6.235,6.039 7.183,6.957 2.643,2.56 3.237,3.135 v 0 h 7.383 2.962 10 10 10 2.337 v 0 0 -3.057" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path14" d="m 584.095,303.466 3.074,3.363 v 10 10 10 10 10 10 10 10 6.581 6.183 9.988 10e-4 0.001 2.518 h 6.497 10 2.976 7.534 v 0 0" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path16" d="m 615.989,393.41 v -10 -10 -10 -10 -10 -10 -10 -10 -6.581 -3.363 -5.906 -10 -4.487 -2.901 -10 -10 -10 -10 -10 -10 -1.283 -10 -10 -10 -10 -10 -9.658 -2.701 -4.955 -10 -0.947 -10 -1.4 -0.061 l -0.299,-0.524 -0.394,-0.413 -0.019,-0.019 v 0" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path18" d="m 584.093,129.228 h -10 -10 -10 -10 l -10,-0.001 h -10 -5.476 -10 -10 -10 -10 -10 -10 l -10,-0.001 h -8.828 -10 -10 -10 -0.326 -3.615 l -10,0.001 h -10 l -10,0.001 h -2.205 -2.951 v 0" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path20" d="m 615.277,128.211 v 0 l -0.501,-0.312 v 0 0 h -8.134 -10 -2.976 -6.497 v 1.329" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path22" d="m 615.69,128.643 0.299,0.524 v 0.061 10 1.4 10 0.947 4.955 2.701 10 10 10 10 10 9.658 10 10 10 10 10 10 1.283 2.901 10 4.487 5.906 3.363 10 10 10 10 10 10 10 10 6.581 6.183 9.987 0.626 l -0.447,0.784 -0.617,0.644 -0.749,0.467" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path24" d="m 587.169,156.53 v 0 0 2.701 10 10 10 10 10 9.658 10 10 10 10 10 10 1.283 l -3.074,2.901 h -10 -10 -10 -10 -10 -10 -5.424" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path26" d="m 370.692,129.228 v -1.329 0 0" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path28" d="m 584.093,129.228 h 3.076" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path30" d="m 350.41,140.628 h 10 2.899 v 10 0.947 h -3.555 -9.344 v 0" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path32" d="m 587.169,129.228 v 10 1.4 10 0.947 4.955" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path34" d="m 350.41,151.575 v -10 -0.947" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path36" d="m 593.666,151.575 v -10 -0.947 0 h 10 2.976" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path38" d="m 606.642,140.628 v 10 0.947 h -10 -2.976 v 0 -10 -0.947" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path40" d="m 615.69,128.643 -0.394,-0.413 -0.019,-0.019 v 0 l -0.501,-0.312" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path42" d="m 615.989,393.41 v 6.183 9.987 0.626 l -0.447,0.783 -0.576,0.603 -0.041,0.042 v 0" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path44" d="m 614.925,411.634 v 0 l -0.749,0.467" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path46" d="m 615.69,128.643 -0.009,-0.01 -0.404,-0.422 -0.501,-0.312" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path48" d="m 614.176,412.101 0.749,-0.467 v 0 l 0.041,-0.042 0.576,-0.603 0.447,-0.783 v -0.626 -9.987 -6.183" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path50" d="m 406.223,306.613 -0.232,0.216 v 0 l 0.232,-0.216 3.38,-3.147 h 10 10 10.303 10 10 10 10 10 10 10 8.765 10 10 1.007" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path52" d="m 518.671,283.073 v 0 h -10 -2.247" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path54" d="m 615.277,128.211 0.404,0.422" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path56" d="m 383.445,273.927 h 10 10 10 10 10 6.461" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path58" d="m 576.555,273.927 2.03,-0.051 1.978,-0.302 1.707,-0.727" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path60" d="m 582.27,272.847 1.099,-1.131 0.456,-1.309 0.077,-1.342" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path62" d="m 583.902,269.065 v -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -9.834 0 -10 -7.959" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path64" d="m 583.902,141.272 -0.077,-1.344 -0.457,-1.309 -1.098,-1.13" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path66" d="m 582.27,137.489 -1.709,-0.727 -1.977,-0.301 -2.029,-0.051" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path68" d="m 576.555,136.41 h -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -3.11 l -2.03,0.051 -1.978,0.302 -1.707,0.726" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path70" d="m 377.73,137.489 -1.099,1.131 -0.456,1.309 -0.077,1.343" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path72" d="m 376.098,269.065 0.077,1.343 0.457,1.309 1.098,1.13" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path74" d="m 377.73,272.847 1.709,0.727 1.977,0.302 2.029,0.051" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path76" d="m 457.882,318.176 v 10 10 10 10 10 10 10 8.996 l -0.375,1.491 -0.542,1.03" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path78" d="m 456.965,399.693 h -10 -10 -8.726 l -0.542,-1.03 -0.375,-1.491" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path80" d="m 539.678,303.466 -0.064,-0.035 h -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10.198 l -1.889,1.029 -1.304,1.491" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path82" d="m 543.74,411.917 v -2.465 -0.024 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -2.742 l -1.686,-1.925 -2.376,-1.295" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path84" d="m 427.612,316.452 0.42,-0.797 h 10 10 8.933 l 0.542,1.03 0.375,1.491" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path86" d="m 427.322,317.607 0.29,-1.155" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path88" d="m 350.41,151.575 v -10 -0.947" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path90" d="m 370.692,127.899 v 0" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path92" d="m 376.098,141.272 v 10 7.954 0.005 10 10 10 10 10 10 10 10 10 10 9.834" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path94" d="m 405.991,409.044 v 3.057" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path96" d="m 406.223,305.951 v 0.662 0 0 0 10 10 10 10 10 10 10 10 10 10 2.333 0.098 2.873" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path98" d="m 427.322,397.172 v -10 -10 -10 -10 -10 -10 -10 -9.565" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path100" d="m 405.991,409.044 h 0.232" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path102" d="m 506.424,283.073 h -3.436 -10 -10 -10 -10 -6.548 -3.543 -10e-4 -10 -2.99" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path104" d="m 406.223,411.917 h 10 10 10 10 10 10 10 10 10 10 10 10 10 7.517" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path106" d="m 518.671,273.927 h 10 10 10 10 10 7.884" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path108" d="m 439.906,273.927 h 6.803 v 0 h 2.704 10 10 10 10 10 10.551 2.65 10e-4 6.056" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path110" d="m 539.678,303.466 h 10 10 10 10 4.417" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path112" d="m 587.169,156.53 v 0" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path114" d="m 543.74,409.452 10,0.029 10,0.03 10,0.03 9.999,0.029 3.43,0.01" />
|
||||||
|
<path style="fill:none;stroke:#CB7590;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" id="path116" d="m 615.989,393.41 v -10 -10 -10 -10 -10 -10 -10 -10 -6.581" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 786 KiB |
After Width: | Height: | Size: 9.9 KiB |
After Width: | Height: | Size: 398 KiB |
After Width: | Height: | Size: 497 B |
After Width: | Height: | Size: 356 B |
After Width: | Height: | Size: 390 B |
After Width: | Height: | Size: 452 B |
After Width: | Height: | Size: 589 B |
After Width: | Height: | Size: 561 B |
After Width: | Height: | Size: 328 B |
After Width: | Height: | Size: 457 B |
After Width: | Height: | Size: 384 B |
After Width: | Height: | Size: 326 B |
After Width: | Height: | Size: 437 B |
After Width: | Height: | Size: 599 B |
After Width: | Height: | Size: 383 B |
After Width: | Height: | Size: 411 B |
After Width: | Height: | Size: 282 B |
After Width: | Height: | Size: 337 B |
After Width: | Height: | Size: 688 B |
After Width: | Height: | Size: 639 B |
After Width: | Height: | Size: 498 B |
After Width: | Height: | Size: 149 KiB |
After Width: | Height: | Size: 184 KiB |
After Width: | Height: | Size: 263 B |
|
@ -49,6 +49,8 @@ export const COMPOSE_UPLOAD_CHANGE_REQUEST = 'COMPOSE_UPLOAD_UPDATE_REQUEST'
|
||||||
export const COMPOSE_UPLOAD_CHANGE_SUCCESS = 'COMPOSE_UPLOAD_UPDATE_SUCCESS';
|
export const COMPOSE_UPLOAD_CHANGE_SUCCESS = 'COMPOSE_UPLOAD_UPDATE_SUCCESS';
|
||||||
export const COMPOSE_UPLOAD_CHANGE_FAIL = 'COMPOSE_UPLOAD_UPDATE_FAIL';
|
export const COMPOSE_UPLOAD_CHANGE_FAIL = 'COMPOSE_UPLOAD_UPDATE_FAIL';
|
||||||
|
|
||||||
|
export const COMPOSE_DOODLE_SET = 'COMPOSE_DOODLE_SET';
|
||||||
|
|
||||||
export function changeCompose(text) {
|
export function changeCompose(text) {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_CHANGE,
|
type: COMPOSE_CHANGE,
|
||||||
|
@ -182,6 +184,13 @@ export function submitComposeFail(error) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function doodleSet(options) {
|
||||||
|
return {
|
||||||
|
type: COMPOSE_DOODLE_SET,
|
||||||
|
options: options,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export function uploadCompose(files) {
|
export function uploadCompose(files) {
|
||||||
return function (dispatch, getState) {
|
return function (dispatch, getState) {
|
||||||
if (getState().getIn(['compose', 'media_attachments']).size > 3) {
|
if (getState().getIn(['compose', 'media_attachments']).size > 3) {
|
||||||
|
|
|
@ -88,7 +88,7 @@ class Account extends ImmutablePureComponent {
|
||||||
if (requested) {
|
if (requested) {
|
||||||
buttons = <IconButton disabled icon='hourglass' title={intl.formatMessage(messages.requested)} />;
|
buttons = <IconButton disabled icon='hourglass' title={intl.formatMessage(messages.requested)} />;
|
||||||
} else if (blocking) {
|
} else if (blocking) {
|
||||||
buttons = <IconButton active icon='unlock-alt' title={intl.formatMessage(messages.unblock, { name: account.get('username') })} onClick={this.handleBlock} />;
|
buttons = <IconButton active icon='unlock' title={intl.formatMessage(messages.unblock, { name: account.get('username') })} onClick={this.handleBlock} />;
|
||||||
} else if (muting) {
|
} else if (muting) {
|
||||||
let hidingNotificationsButton;
|
let hidingNotificationsButton;
|
||||||
if (account.getIn(['relationship', 'muting_notifications'])) {
|
if (account.getIn(['relationship', 'muting_notifications'])) {
|
||||||
|
|
|
@ -11,26 +11,36 @@ export default class DisplayName extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { account, others, localDomain } = this.props;
|
const { others, localDomain } = this.props;
|
||||||
const displayNameHtml = { __html: account.get('display_name_html') };
|
|
||||||
|
|
||||||
let suffix;
|
let displayName, suffix, account;
|
||||||
|
|
||||||
if (others && others.size > 1) {
|
if (others && others.size > 1) {
|
||||||
suffix = `+${others.size}`;
|
displayName = others.take(2).map(a => <bdi key={a.get('id')}><strong className='display-name__html' dangerouslySetInnerHTML={{ __html: a.get('display_name_html') }} /></bdi>).reduce((prev, cur) => [prev, ', ', cur]);
|
||||||
|
|
||||||
|
if (others.size - 2 > 0) {
|
||||||
|
suffix = `+${others.size - 2}`;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (others && others.size > 0) {
|
||||||
|
account = others.first();
|
||||||
|
} else {
|
||||||
|
account = this.props.account;
|
||||||
|
}
|
||||||
|
|
||||||
let acct = account.get('acct');
|
let acct = account.get('acct');
|
||||||
|
|
||||||
if (acct.indexOf('@') === -1 && localDomain) {
|
if (acct.indexOf('@') === -1 && localDomain) {
|
||||||
acct = `${acct}@${localDomain}`;
|
acct = `${acct}@${localDomain}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
displayName = <bdi><strong className='display-name__html' dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} /></bdi>;
|
||||||
suffix = <span className='display-name__account'>@{acct}</span>;
|
suffix = <span className='display-name__account'>@{acct}</span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className='display-name'>
|
<span className='display-name'>
|
||||||
<bdi><strong className='display-name__html' dangerouslySetInnerHTML={displayNameHtml} /></bdi> {suffix}
|
{displayName} {suffix}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ class Account extends ImmutablePureComponent {
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div className='domain__buttons'>
|
<div className='domain__buttons'>
|
||||||
<IconButton active icon='unlock-alt' title={intl.formatMessage(messages.unblockDomain, { domain })} onClick={this.handleDomainUnblock} />
|
<IconButton active icon='unlock' title={intl.formatMessage(messages.unblockDomain, { domain })} onClick={this.handleDomainUnblock} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -22,6 +22,7 @@ export default class IconButton extends React.PureComponent {
|
||||||
animate: PropTypes.bool,
|
animate: PropTypes.bool,
|
||||||
overlay: PropTypes.bool,
|
overlay: PropTypes.bool,
|
||||||
tabIndex: PropTypes.string,
|
tabIndex: PropTypes.string,
|
||||||
|
label: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
|
@ -42,14 +43,18 @@ export default class IconButton extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const style = {
|
let style = {
|
||||||
fontSize: `${this.props.size}px`,
|
fontSize: `${this.props.size}px`,
|
||||||
width: `${this.props.size * 1.28571429}px`,
|
|
||||||
height: `${this.props.size * 1.28571429}px`,
|
height: `${this.props.size * 1.28571429}px`,
|
||||||
lineHeight: `${this.props.size}px`,
|
lineHeight: `${this.props.size}px`,
|
||||||
...this.props.style,
|
...this.props.style,
|
||||||
...(this.props.active ? this.props.activeStyle : {}),
|
...(this.props.active ? this.props.activeStyle : {}),
|
||||||
};
|
};
|
||||||
|
if (!this.props.label) {
|
||||||
|
style.width = `${this.props.size * 1.28571429}px`;
|
||||||
|
} else {
|
||||||
|
style.textAlign = 'left';
|
||||||
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
active,
|
active,
|
||||||
|
@ -104,7 +109,8 @@ export default class IconButton extends React.PureComponent {
|
||||||
style={style}
|
style={style}
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
>
|
>
|
||||||
<i style={{ transform: `rotate(${rotate}deg)` }} className={`fa fa-fw fa-${icon}`} aria-hidden='true' />
|
<i style={{ transform: `rotate(${rotate}deg)` }} className={`fa fa-fw fa-${this.props.icon}`} aria-hidden='true' />
|
||||||
|
{this.props.label}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</Motion>
|
</Motion>
|
||||||
|
|
|
@ -65,7 +65,7 @@ export default class IntersectionObserverArticle extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStateAfterIntersection = (prevState) => {
|
updateStateAfterIntersection = (prevState) => {
|
||||||
if (prevState.isIntersecting && !this.entry.isIntersecting) {
|
if (prevState.isIntersecting !== false && !this.entry.isIntersecting) {
|
||||||
scheduleIdleTask(this.hideIfNotIntersecting);
|
scheduleIdleTask(this.hideIfNotIntersecting);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -194,6 +194,8 @@ class MediaGallery extends React.PureComponent {
|
||||||
height: PropTypes.number.isRequired,
|
height: PropTypes.number.isRequired,
|
||||||
onOpenMedia: PropTypes.func.isRequired,
|
onOpenMedia: PropTypes.func.isRequired,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
|
defaultWidth: PropTypes.number,
|
||||||
|
cacheWidth: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
|
@ -202,6 +204,7 @@ class MediaGallery extends React.PureComponent {
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
visible: displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all',
|
visible: displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all',
|
||||||
|
width: this.props.defaultWidth,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentWillReceiveProps (nextProps) {
|
componentWillReceiveProps (nextProps) {
|
||||||
|
@ -221,6 +224,7 @@ class MediaGallery extends React.PureComponent {
|
||||||
handleRef = (node) => {
|
handleRef = (node) => {
|
||||||
if (node /*&& this.isStandaloneEligible()*/) {
|
if (node /*&& this.isStandaloneEligible()*/) {
|
||||||
// offsetWidth triggers a layout, so only calculate when we need to
|
// offsetWidth triggers a layout, so only calculate when we need to
|
||||||
|
if (this.props.cacheWidth) this.props.cacheWidth(node.offsetWidth);
|
||||||
this.setState({
|
this.setState({
|
||||||
width: node.offsetWidth,
|
width: node.offsetWidth,
|
||||||
});
|
});
|
||||||
|
@ -233,8 +237,10 @@ class MediaGallery extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { media, intl, sensitive, height } = this.props;
|
const { media, intl, sensitive, height, defaultWidth } = this.props;
|
||||||
const { width, visible } = this.state;
|
const { visible } = this.state;
|
||||||
|
|
||||||
|
const width = this.state.width || defaultWidth;
|
||||||
|
|
||||||
let children;
|
let children;
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,8 @@ const getUnitDelay = units => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fallbackFormat = new Intl.DateTimeFormat('en', shortDateFormatOptions);
|
||||||
|
|
||||||
export const timeAgoString = (intl, date, now, year) => {
|
export const timeAgoString = (intl, date, now, year) => {
|
||||||
const delta = now - date.getTime();
|
const delta = now - date.getTime();
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ export default class ScrollableList extends PureComponent {
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
fullscreen: null,
|
fullscreen: null,
|
||||||
|
cachedMediaWidth: 250, // Default media/card width using default Mastodon theme
|
||||||
};
|
};
|
||||||
|
|
||||||
intersectionObserverWrapper = new IntersectionObserverWrapper();
|
intersectionObserverWrapper = new IntersectionObserverWrapper();
|
||||||
|
@ -130,6 +131,20 @@ export default class ScrollableList extends PureComponent {
|
||||||
this.handleScroll();
|
this.handleScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getScrollPosition = () => {
|
||||||
|
if (this.node && (this.node.scrollTop > 0 || this.mouseMovedRecently)) {
|
||||||
|
return { height: this.node.scrollHeight, top: this.node.scrollTop };
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateScrollBottom = (snapshot) => {
|
||||||
|
const newScrollTop = this.node.scrollHeight - snapshot;
|
||||||
|
|
||||||
|
this.setScrollTop(newScrollTop);
|
||||||
|
}
|
||||||
|
|
||||||
getSnapshotBeforeUpdate (prevProps) {
|
getSnapshotBeforeUpdate (prevProps) {
|
||||||
const someItemInserted = React.Children.count(prevProps.children) > 0 &&
|
const someItemInserted = React.Children.count(prevProps.children) > 0 &&
|
||||||
React.Children.count(prevProps.children) < React.Children.count(this.props.children) &&
|
React.Children.count(prevProps.children) < React.Children.count(this.props.children) &&
|
||||||
|
@ -150,6 +165,12 @@ export default class ScrollableList extends PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cacheMediaWidth = (width) => {
|
||||||
|
if (width && this.state.cachedMediaWidth !== width) {
|
||||||
|
this.setState({ cachedMediaWidth: width });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
this.clearMouseIdleTimer();
|
this.clearMouseIdleTimer();
|
||||||
this.detachScrollListener();
|
this.detachScrollListener();
|
||||||
|
@ -239,7 +260,12 @@ export default class ScrollableList extends PureComponent {
|
||||||
intersectionObserverWrapper={this.intersectionObserverWrapper}
|
intersectionObserverWrapper={this.intersectionObserverWrapper}
|
||||||
saveHeightKey={trackScroll ? `${this.context.router.route.location.key}:${scrollKey}` : null}
|
saveHeightKey={trackScroll ? `${this.context.router.route.location.key}:${scrollKey}` : null}
|
||||||
>
|
>
|
||||||
{child}
|
{React.cloneElement(child, {
|
||||||
|
getScrollPosition: this.getScrollPosition,
|
||||||
|
updateScrollBottom: this.updateScrollBottom,
|
||||||
|
cachedMediaWidth: this.state.cachedMediaWidth,
|
||||||
|
cacheMediaWidth: this.cacheMediaWidth,
|
||||||
|
})}
|
||||||
</IntersectionObserverArticleContainer>
|
</IntersectionObserverArticleContainer>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,10 @@ class Status extends ImmutablePureComponent {
|
||||||
onMoveUp: PropTypes.func,
|
onMoveUp: PropTypes.func,
|
||||||
onMoveDown: PropTypes.func,
|
onMoveDown: PropTypes.func,
|
||||||
showThread: PropTypes.bool,
|
showThread: PropTypes.bool,
|
||||||
|
getScrollPosition: PropTypes.func,
|
||||||
|
updateScrollBottom: PropTypes.func,
|
||||||
|
cacheMediaWidth: PropTypes.func,
|
||||||
|
cachedMediaWidth: PropTypes.number,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Avoid checking props that are functions (and whose equality will always
|
// Avoid checking props that are functions (and whose equality will always
|
||||||
|
@ -79,6 +83,43 @@ class Status extends ImmutablePureComponent {
|
||||||
'hidden',
|
'hidden',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Track height changes we know about to compensate scrolling
|
||||||
|
componentDidMount () {
|
||||||
|
this.didShowCard = !this.props.muted && !this.props.hidden && this.props.status && this.props.status.get('card');
|
||||||
|
}
|
||||||
|
|
||||||
|
getSnapshotBeforeUpdate () {
|
||||||
|
if (this.props.getScrollPosition) {
|
||||||
|
return this.props.getScrollPosition();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compensate height changes
|
||||||
|
componentDidUpdate (prevProps, prevState, snapshot) {
|
||||||
|
const doShowCard = !this.props.muted && !this.props.hidden && this.props.status && this.props.status.get('card');
|
||||||
|
if (doShowCard && !this.didShowCard) {
|
||||||
|
this.didShowCard = true;
|
||||||
|
if (snapshot !== null && this.props.updateScrollBottom) {
|
||||||
|
if (this.node && this.node.offsetTop < snapshot.top) {
|
||||||
|
this.props.updateScrollBottom(snapshot.height - snapshot.top);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
if (this.node && this.props.getScrollPosition) {
|
||||||
|
const position = this.props.getScrollPosition();
|
||||||
|
if (position !== null && this.node.offsetTop < position.top) {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.props.updateScrollBottom(position.height - position.top);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleClick = () => {
|
handleClick = () => {
|
||||||
if (this.props.onClick) {
|
if (this.props.onClick) {
|
||||||
this.props.onClick();
|
this.props.onClick();
|
||||||
|
@ -165,6 +206,10 @@ class Status extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleRef = c => {
|
||||||
|
this.node = c;
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let media = null;
|
let media = null;
|
||||||
let statusAvatar, prepend, rebloggedByText;
|
let statusAvatar, prepend, rebloggedByText;
|
||||||
|
@ -179,7 +224,7 @@ class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div ref={this.handleRef}>
|
||||||
{status.getIn(['account', 'display_name']) || status.getIn(['account', 'username'])}
|
{status.getIn(['account', 'display_name']) || status.getIn(['account', 'username'])}
|
||||||
{status.get('content')}
|
{status.get('content')}
|
||||||
</div>
|
</div>
|
||||||
|
@ -194,7 +239,7 @@ class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={minHandlers}>
|
<HotKeys handlers={minHandlers}>
|
||||||
<div className='status__wrapper status__wrapper--filtered focusable' tabIndex='0'>
|
<div className='status__wrapper status__wrapper--filtered focusable' tabIndex='0' ref={this.handleRef}>
|
||||||
<FormattedMessage id='status.filtered' defaultMessage='Filtered' />
|
<FormattedMessage id='status.filtered' defaultMessage='Filtered' />
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</HotKeys>
|
||||||
|
@ -242,11 +287,12 @@ class Status extends ImmutablePureComponent {
|
||||||
preview={video.get('preview_url')}
|
preview={video.get('preview_url')}
|
||||||
src={video.get('url')}
|
src={video.get('url')}
|
||||||
alt={video.get('description')}
|
alt={video.get('description')}
|
||||||
width={239}
|
width={this.props.cachedMediaWidth}
|
||||||
height={110}
|
height={110}
|
||||||
inline
|
inline
|
||||||
sensitive={status.get('sensitive')}
|
sensitive={status.get('sensitive')}
|
||||||
onOpenVideo={this.handleOpenVideo}
|
onOpenVideo={this.handleOpenVideo}
|
||||||
|
cacheWidth={this.props.cacheMediaWidth}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Bundle>
|
</Bundle>
|
||||||
|
@ -254,7 +300,16 @@ class Status extends ImmutablePureComponent {
|
||||||
} else {
|
} else {
|
||||||
media = (
|
media = (
|
||||||
<Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery}>
|
<Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery}>
|
||||||
{Component => <Component media={status.get('media_attachments')} sensitive={status.get('sensitive')} height={110} onOpenMedia={this.props.onOpenMedia} />}
|
{Component => (
|
||||||
|
<Component
|
||||||
|
media={status.get('media_attachments')}
|
||||||
|
sensitive={status.get('sensitive')}
|
||||||
|
height={110}
|
||||||
|
onOpenMedia={this.props.onOpenMedia}
|
||||||
|
cacheWidth={this.props.cacheMediaWidth}
|
||||||
|
defaultWidth={this.props.cachedMediaWidth}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Bundle>
|
</Bundle>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -264,11 +319,13 @@ class Status extends ImmutablePureComponent {
|
||||||
onOpenMedia={this.props.onOpenMedia}
|
onOpenMedia={this.props.onOpenMedia}
|
||||||
card={status.get('card')}
|
card={status.get('card')}
|
||||||
compact
|
compact
|
||||||
|
cacheWidth={this.props.cacheMediaWidth}
|
||||||
|
defaultWidth={this.props.cachedMediaWidth}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (otherAccounts) {
|
if (otherAccounts && otherAccounts.size > 0) {
|
||||||
statusAvatar = <AvatarComposite accounts={otherAccounts} size={48} />;
|
statusAvatar = <AvatarComposite accounts={otherAccounts} size={48} />;
|
||||||
} else if (account === undefined || account === null) {
|
} else if (account === undefined || account === null) {
|
||||||
statusAvatar = <Avatar account={status.get('account')} size={48} />;
|
statusAvatar = <Avatar account={status.get('account')} size={48} />;
|
||||||
|
@ -290,7 +347,7 @@ class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={handlers}>
|
<HotKeys handlers={handlers}>
|
||||||
<div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), read: unread === false, focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText, !status.get('hidden'))}>
|
<div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), read: unread === false, focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText, !status.get('hidden'))} ref={this.handleRef}>
|
||||||
{prepend}
|
{prepend}
|
||||||
|
|
||||||
<div className={classNames('status', `status-${status.get('visibility')}`, { 'status-reply': !!status.get('in_reply_to_id'), muted: this.props.muted, read: unread === false })} data-id={status.get('id')}>
|
<div className={classNames('status', `status-${status.get('visibility')}`, { 'status-reply': !!status.get('in_reply_to_id'), muted: this.props.muted, read: unread === false })} data-id={status.get('id')}>
|
||||||
|
@ -308,14 +365,15 @@ class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
<StatusContent status={status} onClick={this.handleClick} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} collapsable />
|
<StatusContent status={status} onClick={this.handleClick} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} collapsable />
|
||||||
|
|
||||||
{media}
|
|
||||||
|
|
||||||
{showThread && status.get('in_reply_to_id') && status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) && (
|
{showThread && status.get('in_reply_to_id') && status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) && (
|
||||||
<button className='status__content__read-more-button' onClick={this.handleClick}>
|
<button className='status__content__read-more-button' onClick={this.handleClick}>
|
||||||
|
<i className='fa fa-fw fa-sort-amount-desc status__prepend-icon' />
|
||||||
<FormattedMessage id='status.show_thread' defaultMessage='Show thread' />
|
<FormattedMessage id='status.show_thread' defaultMessage='Show thread' />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{media}
|
||||||
|
|
||||||
<StatusActionBar status={status} account={account} {...other} />
|
<StatusActionBar status={status} account={account} {...other} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -77,7 +77,11 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
]
|
]
|
||||||
|
|
||||||
handleReplyClick = () => {
|
handleReplyClick = () => {
|
||||||
|
if (me) {
|
||||||
this.props.onReply(this.props.status, this.context.router.history);
|
this.props.onReply(this.props.status, this.context.router.history);
|
||||||
|
} else {
|
||||||
|
this._openInteractionDialog('reply');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleShareClick = () => {
|
handleShareClick = () => {
|
||||||
|
@ -90,11 +94,23 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFavouriteClick = () => {
|
handleFavouriteClick = () => {
|
||||||
|
if (me) {
|
||||||
this.props.onFavourite(this.props.status);
|
this.props.onFavourite(this.props.status);
|
||||||
|
} else {
|
||||||
|
this._openInteractionDialog('favourite');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleReblogClick = (e) => {
|
handleReblogClick = e => {
|
||||||
|
if (me) {
|
||||||
this.props.onReblog(this.props.status, e);
|
this.props.onReblog(this.props.status, e);
|
||||||
|
} else {
|
||||||
|
this._openInteractionDialog('reblog');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_openInteractionDialog = type => {
|
||||||
|
window.open(`/interact/${this.props.status.get('id')}?type=${type}`, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDeleteClick = () => {
|
handleDeleteClick = () => {
|
||||||
|
@ -211,9 +227,9 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='status__action-bar'>
|
<div className='status__action-bar'>
|
||||||
<div className='status__action-bar__counter'><IconButton className='status__action-bar-button' disabled={anonymousAccess} title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} /><span className='status__action-bar__counter__label' >{obfuscatedCount(status.get('replies_count'))}</span></div>
|
<IconButton className='status__action-bar-button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} />
|
||||||
<IconButton className='status__action-bar-button' disabled={anonymousAccess || !publicStatus} active={status.get('reblogged')} pressed={status.get('reblogged')} title={!publicStatus ? intl.formatMessage(messages.cannot_reblog) : intl.formatMessage(messages.reblog)} icon={reblogIcon} onClick={this.handleReblogClick} />
|
<IconButton className='status__action-bar-button' disabled={!publicStatus} active={status.get('reblogged')} pressed={status.get('reblogged')} title={!publicStatus ? intl.formatMessage(messages.cannot_reblog) : intl.formatMessage(messages.reblog)} icon={reblogIcon} onClick={this.handleReblogClick} />
|
||||||
<IconButton className='status__action-bar-button star-icon' disabled={anonymousAccess} animate active={status.get('favourited')} pressed={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} />
|
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} pressed={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='floppy-o' onClick={this.handleFavouriteClick} />
|
||||||
{shareButton}
|
{shareButton}
|
||||||
|
|
||||||
<div className='status__action-bar-dropdown'>
|
<div className='status__action-bar-dropdown'>
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { IntlProvider, addLocaleData } from 'react-intl';
|
||||||
import { getLocale } from '../locales';
|
import { getLocale } from '../locales';
|
||||||
import Compose from '../features/standalone/compose';
|
import Compose from '../features/standalone/compose';
|
||||||
import initialState from '../initial_state';
|
import initialState from '../initial_state';
|
||||||
|
import { fetchCustomEmojis } from '../actions/custom_emojis';
|
||||||
|
|
||||||
const { localeData, messages } = getLocale();
|
const { localeData, messages } = getLocale();
|
||||||
addLocaleData(localeData);
|
addLocaleData(localeData);
|
||||||
|
@ -17,6 +18,8 @@ if (initialState) {
|
||||||
store.dispatch(hydrateStore(initialState));
|
store.dispatch(hydrateStore(initialState));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
store.dispatch(fetchCustomEmojis());
|
||||||
|
|
||||||
export default class TimelineContainer extends React.PureComponent {
|
export default class TimelineContainer extends React.PureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
|
|
@ -132,7 +132,7 @@ class Header extends ImmutablePureComponent {
|
||||||
} else if (account.getIn(['relationship', 'blocking'])) {
|
} else if (account.getIn(['relationship', 'blocking'])) {
|
||||||
actionBtn = (
|
actionBtn = (
|
||||||
<div className='account--action-button'>
|
<div className='account--action-button'>
|
||||||
<IconButton size={26} icon='unlock-alt' title={intl.formatMessage(messages.unblock, { name: account.get('username') })} onClick={this.props.onBlock} />
|
<IconButton size={26} icon='unlock' title={intl.formatMessage(messages.unblock, { name: account.get('username') })} onClick={this.props.onBlock} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ const messages = defineMessages({
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
accountIds: state.getIn(['user_lists', 'blocks', 'items']),
|
accountIds: state.getIn(['user_lists', 'blocks', 'items']),
|
||||||
|
hasMore: !!state.getIn(['user_lists', 'blocks', 'next']),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default @connect(mapStateToProps)
|
export default @connect(mapStateToProps)
|
||||||
|
@ -29,6 +30,7 @@ class Blocks extends ImmutablePureComponent {
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
shouldUpdateScroll: PropTypes.func,
|
shouldUpdateScroll: PropTypes.func,
|
||||||
accountIds: ImmutablePropTypes.list,
|
accountIds: ImmutablePropTypes.list,
|
||||||
|
hasMore: PropTypes.bool,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,7 +43,7 @@ class Blocks extends ImmutablePureComponent {
|
||||||
}, 300, { leading: true });
|
}, 300, { leading: true });
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl, accountIds, shouldUpdateScroll } = this.props;
|
const { intl, accountIds, shouldUpdateScroll, hasMore } = this.props;
|
||||||
|
|
||||||
if (!accountIds) {
|
if (!accountIds) {
|
||||||
return (
|
return (
|
||||||
|
@ -59,6 +61,7 @@ class Blocks extends ImmutablePureComponent {
|
||||||
<ScrollableList
|
<ScrollableList
|
||||||
scrollKey='blocks'
|
scrollKey='blocks'
|
||||||
onLoadMore={this.handleLoadMore}
|
onLoadMore={this.handleLoadMore}
|
||||||
|
hasMore={hasMore}
|
||||||
shouldUpdateScroll={shouldUpdateScroll}
|
shouldUpdateScroll={shouldUpdateScroll}
|
||||||
emptyMessage={emptyMessage}
|
emptyMessage={emptyMessage}
|
||||||
>
|
>
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
// Package imports //
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { injectIntl, defineMessages } from 'react-intl';
|
||||||
|
|
||||||
|
// Our imports //
|
||||||
|
import ComposeDropdown from './compose_dropdown';
|
||||||
|
import { uploadCompose } from '../../../actions/compose';
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
import { openModal } from '../../../actions/modal';
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
upload :
|
||||||
|
{ id: 'compose.attach.upload', defaultMessage: 'Upload a file' },
|
||||||
|
doodle :
|
||||||
|
{ id: 'compose.attach.doodle', defaultMessage: 'Draw something' },
|
||||||
|
attach :
|
||||||
|
{ id: 'compose.attach', defaultMessage: 'Attach...' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
// This horrible expression is copied from vanilla upload_button_container
|
||||||
|
disabled: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 3 || state.getIn(['compose', 'media_attachments']).some(m => m.get('type') === 'video')),
|
||||||
|
resetFileKey: state.getIn(['compose', 'resetFileKey']),
|
||||||
|
acceptContentTypes: state.getIn(['media_attachments', 'accept_content_types']),
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
onSelectFile (files) {
|
||||||
|
dispatch(uploadCompose(files));
|
||||||
|
},
|
||||||
|
onOpenDoodle () {
|
||||||
|
dispatch(openModal('DOODLE', { noEsc: true }));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
@injectIntl
|
||||||
|
@connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
export default class ComposeAttachOptions extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
intl : PropTypes.object.isRequired,
|
||||||
|
resetFileKey: PropTypes.number,
|
||||||
|
acceptContentTypes: ImmutablePropTypes.listOf(PropTypes.string).isRequired,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
onSelectFile: PropTypes.func.isRequired,
|
||||||
|
onOpenDoodle: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
handleItemClick = bt => {
|
||||||
|
if (bt === 'upload') {
|
||||||
|
this.fileElement.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bt === 'doodle') {
|
||||||
|
this.props.onOpenDoodle();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dropdown.setState({ open: false });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleFileChange = (e) => {
|
||||||
|
if (e.target.files.length > 0) {
|
||||||
|
this.props.onSelectFile(e.target.files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setFileRef = (c) => {
|
||||||
|
this.fileElement = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
setDropdownRef = (c) => {
|
||||||
|
this.dropdown = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { intl, resetFileKey, disabled, acceptContentTypes } = this.props;
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
{ icon: 'cloud-upload', text: messages.upload, name: 'upload' },
|
||||||
|
{ icon: 'paint-brush', text: messages.doodle, name: 'doodle' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const optionElems = options.map((item) => {
|
||||||
|
const hdl = () => this.handleItemClick(item.name);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
role='button'
|
||||||
|
tabIndex='0'
|
||||||
|
key={item.name}
|
||||||
|
onClick={hdl}
|
||||||
|
className='privacy-dropdown__option'
|
||||||
|
>
|
||||||
|
<div className='privacy-dropdown__option__icon'>
|
||||||
|
<i className={`fa fa-fw fa-${item.icon}`} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='privacy-dropdown__option__content'>
|
||||||
|
<strong>{intl.formatMessage(item.text)}</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ComposeDropdown
|
||||||
|
title={intl.formatMessage(messages.attach)}
|
||||||
|
icon='paperclip'
|
||||||
|
disabled={disabled}
|
||||||
|
ref={this.setDropdownRef}
|
||||||
|
>
|
||||||
|
{optionElems}
|
||||||
|
</ComposeDropdown>
|
||||||
|
<input
|
||||||
|
key={resetFileKey}
|
||||||
|
ref={this.setFileRef}
|
||||||
|
type='file'
|
||||||
|
multiple={false}
|
||||||
|
accept={acceptContentTypes.toArray().join(',')}
|
||||||
|
onChange={this.handleFileChange}
|
||||||
|
disabled={disabled}
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
// Package imports //
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
// Mastodon imports //
|
||||||
|
import IconButton from '../../../components/icon_button';
|
||||||
|
|
||||||
|
const iconStyle = {
|
||||||
|
height : null,
|
||||||
|
lineHeight : '27px',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class ComposeDropdown extends React.PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
title: PropTypes.string.isRequired,
|
||||||
|
icon: PropTypes.string,
|
||||||
|
highlight: PropTypes.bool,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
children: PropTypes.arrayOf(PropTypes.node).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
open: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
onGlobalClick = (e) => {
|
||||||
|
if (e.target !== this.node && !this.node.contains(e.target) && this.state.open) {
|
||||||
|
this.setState({ open: false });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
window.addEventListener('click', this.onGlobalClick);
|
||||||
|
window.addEventListener('touchstart', this.onGlobalClick);
|
||||||
|
}
|
||||||
|
componentWillUnmount () {
|
||||||
|
window.removeEventListener('click', this.onGlobalClick);
|
||||||
|
window.removeEventListener('touchstart', this.onGlobalClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
onToggleDropdown = () => {
|
||||||
|
if (this.props.disabled) return;
|
||||||
|
this.setState({ open: !this.state.open });
|
||||||
|
};
|
||||||
|
|
||||||
|
setRef = (c) => {
|
||||||
|
this.node = c;
|
||||||
|
};
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { open } = this.state;
|
||||||
|
let { highlight, title, icon, disabled } = this.props;
|
||||||
|
|
||||||
|
if (!icon) icon = 'ellipsis-h';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={this.setRef} className={`advanced-options-dropdown ${open ? 'open' : ''} ${highlight ? 'active' : ''} `}>
|
||||||
|
<div className='advanced-options-dropdown__value'>
|
||||||
|
<IconButton
|
||||||
|
className={'inverted'}
|
||||||
|
title={title}
|
||||||
|
icon={icon} active={open || highlight}
|
||||||
|
size={18}
|
||||||
|
style={iconStyle}
|
||||||
|
disabled={disabled}
|
||||||
|
onClick={this.onToggleDropdown}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='advanced-options-dropdown__dropdown'>
|
||||||
|
{this.props.children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ReplyIndicatorContainer from '../containers/reply_indicator_container';
|
import ReplyIndicatorContainer from '../containers/reply_indicator_container';
|
||||||
import AutosuggestTextarea from '../../../components/autosuggest_textarea';
|
import AutosuggestTextarea from '../../../components/autosuggest_textarea';
|
||||||
import UploadButtonContainer from '../containers/upload_button_container';
|
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
import SpoilerButtonContainer from '../containers/spoiler_button_container';
|
import SpoilerButtonContainer from '../containers/spoiler_button_container';
|
||||||
import PrivacyDropdownContainer from '../containers/privacy_dropdown_container';
|
import PrivacyDropdownContainer from '../containers/privacy_dropdown_container';
|
||||||
|
@ -17,6 +16,7 @@ import { isMobile } from '../../../is_mobile';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
import { countableText } from '../util/counter';
|
import { countableText } from '../util/counter';
|
||||||
|
import ComposeAttachOptions from './attach_options';
|
||||||
|
|
||||||
const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d';
|
const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d';
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
const { is_submitting, is_changing_upload, is_uploading, anyMedia } = this.props;
|
const { is_submitting, is_changing_upload, is_uploading, anyMedia } = this.props;
|
||||||
const fulltext = [this.props.spoiler_text, countableText(this.props.text)].join('');
|
const fulltext = [this.props.spoiler_text, countableText(this.props.text)].join('');
|
||||||
|
|
||||||
if (is_submitting || is_uploading || is_changing_upload || length(fulltext) > 500 || (fulltext.length !== 0 && fulltext.trim().length === 0 && !anyMedia)) {
|
if (is_submitting || is_uploading || is_changing_upload || length(fulltext) > 512 || (fulltext.length !== 0 && fulltext.trim().length === 0 && !anyMedia)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
const { intl, onPaste, showSearch, anyMedia } = this.props;
|
const { intl, onPaste, showSearch, anyMedia } = this.props;
|
||||||
const disabled = this.props.is_submitting;
|
const disabled = this.props.is_submitting;
|
||||||
const text = [this.props.spoiler_text, countableText(this.props.text)].join('');
|
const text = [this.props.spoiler_text, countableText(this.props.text)].join('');
|
||||||
const disabledButton = disabled || this.props.is_uploading || this.props.is_changing_upload || length(text) > 500 || (text.length !== 0 && text.trim().length === 0 && !anyMedia);
|
const disabledButton = disabled || this.props.is_uploading || this.props.is_changing_upload || length(text) > 512 || (text.length !== 0 && text.trim().length === 0 && !anyMedia);
|
||||||
let publishText = '';
|
let publishText = '';
|
||||||
|
|
||||||
if (this.props.privacy === 'private' || this.props.privacy === 'direct') {
|
if (this.props.privacy === 'private' || this.props.privacy === 'direct') {
|
||||||
|
@ -179,7 +179,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
<div className={`spoiler-input ${this.props.spoiler ? 'spoiler-input--visible' : ''}`}>
|
<div className={`spoiler-input ${this.props.spoiler ? 'spoiler-input--visible' : ''}`}>
|
||||||
<label>
|
<label>
|
||||||
<span style={{ display: 'none' }}>{intl.formatMessage(messages.spoiler_placeholder)}</span>
|
<span style={{ display: 'none' }}>{intl.formatMessage(messages.spoiler_placeholder)}</span>
|
||||||
<input placeholder={intl.formatMessage(messages.spoiler_placeholder)} value={this.props.spoiler_text} onChange={this.handleChangeSpoilerText} onKeyDown={this.handleKeyDown} type='text' className='spoiler-input__input' id='cw-spoiler-input' ref={this.setSpoilerText} />
|
<input placeholder={intl.formatMessage(messages.spoiler_placeholder)} value={this.props.spoiler_text} onChange={this.handleChangeSpoilerText} onKeyDown={this.handleKeyDown} tabIndex={this.props.spoiler ? 0 : -1} type='text' className='spoiler-input__input' id='cw-spoiler-input' ref={this.setSpoilerText} />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -208,12 +208,13 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
|
|
||||||
<div className='compose-form__buttons-wrapper'>
|
<div className='compose-form__buttons-wrapper'>
|
||||||
<div className='compose-form__buttons'>
|
<div className='compose-form__buttons'>
|
||||||
<UploadButtonContainer />
|
<ComposeAttachOptions />
|
||||||
<PrivacyDropdownContainer />
|
|
||||||
<SensitiveButtonContainer />
|
<SensitiveButtonContainer />
|
||||||
|
<div className='compose-form__buttons-separator' />
|
||||||
|
<PrivacyDropdownContainer />
|
||||||
<SpoilerButtonContainer />
|
<SpoilerButtonContainer />
|
||||||
</div>
|
</div>
|
||||||
<div className='character-counter__wrapper'><CharacterCounter max={500} text={text} /></div>
|
<div className='character-counter__wrapper'><CharacterCounter max={512} text={text} /></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='compose-form__publish'>
|
<div className='compose-form__publish'>
|
||||||
|
|
|
@ -357,8 +357,8 @@ class EmojiPickerDropdown extends React.PureComponent {
|
||||||
<div ref={this.setTargetRef} className='emoji-button' title={title} aria-label={title} aria-expanded={active} role='button' onClick={this.onToggle} onKeyDown={this.onToggle} tabIndex={0}>
|
<div ref={this.setTargetRef} className='emoji-button' title={title} aria-label={title} aria-expanded={active} role='button' onClick={this.onToggle} onKeyDown={this.onToggle} tabIndex={0}>
|
||||||
<img
|
<img
|
||||||
className={classNames('emojione', { 'pulse-loading': active && loading })}
|
className={classNames('emojione', { 'pulse-loading': active && loading })}
|
||||||
alt='🙂'
|
alt='🤔'
|
||||||
src={`${assetHost}/emoji/1f602.svg`}
|
src={`${assetHost}/emoji/1f914.svg`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -214,7 +214,7 @@ class PrivacyDropdown extends React.PureComponent {
|
||||||
|
|
||||||
this.options = [
|
this.options = [
|
||||||
{ icon: 'globe', value: 'public', text: formatMessage(messages.public_short), meta: formatMessage(messages.public_long) },
|
{ icon: 'globe', value: 'public', text: formatMessage(messages.public_short), meta: formatMessage(messages.public_long) },
|
||||||
{ icon: 'unlock-alt', value: 'unlisted', text: formatMessage(messages.unlisted_short), meta: formatMessage(messages.unlisted_long) },
|
{ icon: 'unlock', value: 'unlisted', text: formatMessage(messages.unlisted_short), meta: formatMessage(messages.unlisted_long) },
|
||||||
{ icon: 'lock', value: 'private', text: formatMessage(messages.private_short), meta: formatMessage(messages.private_long) },
|
{ icon: 'lock', value: 'private', text: formatMessage(messages.private_short), meta: formatMessage(messages.private_long) },
|
||||||
{ icon: 'envelope', value: 'direct', text: formatMessage(messages.direct_short), meta: formatMessage(messages.direct_long) },
|
{ icon: 'envelope', value: 'direct', text: formatMessage(messages.direct_short), meta: formatMessage(messages.direct_long) },
|
||||||
];
|
];
|
||||||
|
|
|
@ -107,9 +107,8 @@ class Upload extends ImmutablePureComponent {
|
||||||
<label>
|
<label>
|
||||||
<span style={{ display: 'none' }}>{intl.formatMessage(messages.description)}</span>
|
<span style={{ display: 'none' }}>{intl.formatMessage(messages.description)}</span>
|
||||||
|
|
||||||
<input
|
<textarea
|
||||||
placeholder={intl.formatMessage(messages.description)}
|
placeholder={intl.formatMessage(messages.description)}
|
||||||
type='text'
|
|
||||||
value={description}
|
value={description}
|
||||||
maxLength={420}
|
maxLength={420}
|
||||||
onFocus={this.handleInputFocus}
|
onFocus={this.handleInputFocus}
|
||||||
|
|
|
@ -12,13 +12,13 @@ const DEFAULTS = [
|
||||||
'+1',
|
'+1',
|
||||||
'grinning',
|
'grinning',
|
||||||
'kissing_heart',
|
'kissing_heart',
|
||||||
'heart_eyes',
|
'vhs',
|
||||||
'laughing',
|
'laughing',
|
||||||
'stuck_out_tongue_winking_eye',
|
'floppy_disk',
|
||||||
'sweat_smile',
|
'sweat_smile',
|
||||||
'joy',
|
'joy',
|
||||||
'yum',
|
'yum',
|
||||||
'disappointed',
|
'computer',
|
||||||
'thinking_face',
|
'thinking_face',
|
||||||
'weary',
|
'weary',
|
||||||
'sob',
|
'sob',
|
||||||
|
|
|
@ -19,6 +19,7 @@ const messages = defineMessages({
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
domains: state.getIn(['domain_lists', 'blocks', 'items']),
|
domains: state.getIn(['domain_lists', 'blocks', 'items']),
|
||||||
|
hasMore: !!state.getIn(['domain_lists', 'blocks', 'next']),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default @connect(mapStateToProps)
|
export default @connect(mapStateToProps)
|
||||||
|
@ -29,6 +30,7 @@ class Blocks extends ImmutablePureComponent {
|
||||||
params: PropTypes.object.isRequired,
|
params: PropTypes.object.isRequired,
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
shouldUpdateScroll: PropTypes.func,
|
shouldUpdateScroll: PropTypes.func,
|
||||||
|
hasMore: PropTypes.bool,
|
||||||
domains: ImmutablePropTypes.orderedSet,
|
domains: ImmutablePropTypes.orderedSet,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
@ -42,7 +44,7 @@ class Blocks extends ImmutablePureComponent {
|
||||||
}, 300, { leading: true });
|
}, 300, { leading: true });
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl, domains, shouldUpdateScroll } = this.props;
|
const { intl, domains, shouldUpdateScroll, hasMore } = this.props;
|
||||||
|
|
||||||
if (!domains) {
|
if (!domains) {
|
||||||
return (
|
return (
|
||||||
|
@ -60,6 +62,7 @@ class Blocks extends ImmutablePureComponent {
|
||||||
<ScrollableList
|
<ScrollableList
|
||||||
scrollKey='domain_blocks'
|
scrollKey='domain_blocks'
|
||||||
onLoadMore={this.handleLoadMore}
|
onLoadMore={this.handleLoadMore}
|
||||||
|
hasMore={hasMore}
|
||||||
shouldUpdateScroll={shouldUpdateScroll}
|
shouldUpdateScroll={shouldUpdateScroll}
|
||||||
emptyMessage={emptyMessage}
|
emptyMessage={emptyMessage}
|
||||||
>
|
>
|
||||||
|
|
|
@ -18,6 +18,7 @@ const messages = defineMessages({
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
accountIds: state.getIn(['user_lists', 'follow_requests', 'items']),
|
accountIds: state.getIn(['user_lists', 'follow_requests', 'items']),
|
||||||
|
hasMore: !!state.getIn(['user_lists', 'follow_requests', 'next']),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default @connect(mapStateToProps)
|
export default @connect(mapStateToProps)
|
||||||
|
@ -28,6 +29,7 @@ class FollowRequests extends ImmutablePureComponent {
|
||||||
params: PropTypes.object.isRequired,
|
params: PropTypes.object.isRequired,
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
shouldUpdateScroll: PropTypes.func,
|
shouldUpdateScroll: PropTypes.func,
|
||||||
|
hasMore: PropTypes.bool,
|
||||||
accountIds: ImmutablePropTypes.list,
|
accountIds: ImmutablePropTypes.list,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
@ -41,7 +43,7 @@ class FollowRequests extends ImmutablePureComponent {
|
||||||
}, 300, { leading: true });
|
}, 300, { leading: true });
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl, shouldUpdateScroll, accountIds } = this.props;
|
const { intl, shouldUpdateScroll, accountIds, hasMore } = this.props;
|
||||||
|
|
||||||
if (!accountIds) {
|
if (!accountIds) {
|
||||||
return (
|
return (
|
||||||
|
@ -59,6 +61,7 @@ class FollowRequests extends ImmutablePureComponent {
|
||||||
<ScrollableList
|
<ScrollableList
|
||||||
scrollKey='follow_requests'
|
scrollKey='follow_requests'
|
||||||
onLoadMore={this.handleLoadMore}
|
onLoadMore={this.handleLoadMore}
|
||||||
|
hasMore={hasMore}
|
||||||
shouldUpdateScroll={shouldUpdateScroll}
|
shouldUpdateScroll={shouldUpdateScroll}
|
||||||
emptyMessage={emptyMessage}
|
emptyMessage={emptyMessage}
|
||||||
>
|
>
|
||||||
|
|
|
@ -14,20 +14,20 @@ import { Link } from 'react-router-dom';
|
||||||
import NavigationBar from '../compose/components/navigation_bar';
|
import NavigationBar from '../compose/components/navigation_bar';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
|
home_timeline: { id: 'tabs_bar.home', defaultMessage: '/timelines/home' },
|
||||||
notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },
|
notifications: { id: 'tabs_bar.notifications', defaultMessage: '~/.notifications' },
|
||||||
public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },
|
public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: '/timelines/federated' },
|
||||||
settings_subheading: { id: 'column_subheading.settings', defaultMessage: 'Settings' },
|
settings_subheading: { id: 'column_subheading.settings', defaultMessage: 'Settings' },
|
||||||
community_timeline: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },
|
community_timeline: { id: 'navigation_bar.community_timeline', defaultMessage: '/timelines/local' },
|
||||||
direct: { id: 'navigation_bar.direct', defaultMessage: 'Direct messages' },
|
direct: { id: 'navigation_bar.direct', defaultMessage: '~/.dms' },
|
||||||
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
|
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'edit ~/.config' },
|
||||||
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: '~/.follow-requests' },
|
||||||
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },
|
favourites: { id: 'navigation_bar.favourites', defaultMessage: '~/.florps' },
|
||||||
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
|
blocks: { id: 'navigation_bar.blocks', defaultMessage: '~/.blocked' },
|
||||||
domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' },
|
domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: '~/.muted/domains' },
|
||||||
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
|
mutes: { id: 'navigation_bar.mutes', defaultMessage: '~/.muted' },
|
||||||
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },
|
pins: { id: 'navigation_bar.pins', defaultMessage: '~/.pinned' },
|
||||||
lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },
|
lists: { id: 'navigation_bar.lists', defaultMessage: '~/.lists' },
|
||||||
discover: { id: 'navigation_bar.discover', defaultMessage: 'Discover' },
|
discover: { id: 'navigation_bar.discover', defaultMessage: 'Discover' },
|
||||||
personal: { id: 'navigation_bar.personal', defaultMessage: 'Personal' },
|
personal: { id: 'navigation_bar.personal', defaultMessage: 'Personal' },
|
||||||
security: { id: 'navigation_bar.security', defaultMessage: 'Security' },
|
security: { id: 'navigation_bar.security', defaultMessage: 'Security' },
|
||||||
|
@ -158,11 +158,8 @@ class GettingStarted extends ImmutablePureComponent {
|
||||||
<ul>
|
<ul>
|
||||||
{invitesEnabled && <li><a href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a> · </li>}
|
{invitesEnabled && <li><a href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a> · </li>}
|
||||||
{multiColumn && <li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link> · </li>}
|
{multiColumn && <li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link> · </li>}
|
||||||
<li><a href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a> · </li>
|
|
||||||
<li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this instance' /></a> · </li>
|
<li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this instance' /></a> · </li>
|
||||||
<li><a href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Mobile apps' /></a> · </li>
|
|
||||||
<li><a href='/terms' target='_blank'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of service' /></a> · </li>
|
<li><a href='/terms' target='_blank'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of service' /></a> · </li>
|
||||||
<li><a href='/settings/applications' target='_blank'><FormattedMessage id='getting_started.developers' defaultMessage='Developers' /></a> · </li>
|
|
||||||
<li><a href='https://docs.joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a> · </li>
|
<li><a href='https://docs.joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a> · </li>
|
||||||
<li><a href='/auth/sign_out' data-method='delete'><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a></li>
|
<li><a href='/auth/sign_out' data-method='delete'><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -171,7 +168,7 @@ class GettingStarted extends ImmutablePureComponent {
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='getting_started.open_source_notice'
|
id='getting_started.open_source_notice'
|
||||||
defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.'
|
defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.'
|
||||||
values={{ github: <span><a href='https://github.com/tootsuite/mastodon' rel='noopener' target='_blank'>tootsuite/mastodon</a> (v{version})</span> }}
|
values={{ github: <a href='https://cybre.tech/cybrespace/mastodon' rel='noopener' target='_blank'>cybrespace/mastodon</a> }}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import Toggle from 'react-toggle';
|
import Toggle from 'react-toggle';
|
||||||
import AsyncSelect from 'react-select/lib/Async';
|
import AsyncSelect from 'react-select/lib/Async';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
placeholder: { id: 'hashtag.column_settings.select.placeholder', defaultMessage: 'Enter hashtags…' },
|
||||||
|
noOptions: { id: 'hashtag.column_settings.select.no_options_message', defaultMessage: 'No suggestions found' },
|
||||||
|
});
|
||||||
|
|
||||||
export default @injectIntl
|
export default @injectIntl
|
||||||
class ColumnSettings extends React.PureComponent {
|
class ColumnSettings extends React.PureComponent {
|
||||||
|
|
||||||
|
@ -25,6 +30,7 @@ class ColumnSettings extends React.PureComponent {
|
||||||
|
|
||||||
tags (mode) {
|
tags (mode) {
|
||||||
let tags = this.props.settings.getIn(['tags', mode]) || [];
|
let tags = this.props.settings.getIn(['tags', mode]) || [];
|
||||||
|
|
||||||
if (tags.toJSON) {
|
if (tags.toJSON) {
|
||||||
return tags.toJSON();
|
return tags.toJSON();
|
||||||
} else {
|
} else {
|
||||||
|
@ -32,33 +38,36 @@ class ColumnSettings extends React.PureComponent {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onSelect = (mode) => {
|
onSelect = mode => value => this.props.onChange(['tags', mode], value);
|
||||||
return (value) => {
|
|
||||||
this.props.onChange(['tags', mode], value);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
onToggle = () => {
|
onToggle = () => {
|
||||||
if (this.state.open && this.hasTags()) {
|
if (this.state.open && this.hasTags()) {
|
||||||
this.props.onChange('tags', {});
|
this.props.onChange('tags', {});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ open: !this.state.open });
|
this.setState({ open: !this.state.open });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
noOptionsMessage = () => this.props.intl.formatMessage(messages.noOptions);
|
||||||
|
|
||||||
modeSelect (mode) {
|
modeSelect (mode) {
|
||||||
return (
|
return (
|
||||||
<div className='column-settings__section'>
|
<div className='column-settings__row'>
|
||||||
|
<span className='column-settings__section'>
|
||||||
{this.modeLabel(mode)}
|
{this.modeLabel(mode)}
|
||||||
|
</span>
|
||||||
|
|
||||||
<AsyncSelect
|
<AsyncSelect
|
||||||
isMulti
|
isMulti
|
||||||
autoFocus
|
autoFocus
|
||||||
value={this.tags(mode)}
|
value={this.tags(mode)}
|
||||||
settings={this.props.settings}
|
|
||||||
settingPath={['tags', mode]}
|
|
||||||
onChange={this.onSelect(mode)}
|
onChange={this.onSelect(mode)}
|
||||||
loadOptions={this.props.onLoad}
|
loadOptions={this.props.onLoad}
|
||||||
classNamePrefix='column-settings__hashtag-select'
|
className='column-select__container'
|
||||||
|
classNamePrefix='column-select'
|
||||||
name='tags'
|
name='tags'
|
||||||
|
placeholder={this.props.intl.formatMessage(messages.placeholder)}
|
||||||
|
noOptionsMessage={this.noOptionsMessage}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -66,11 +75,15 @@ class ColumnSettings extends React.PureComponent {
|
||||||
|
|
||||||
modeLabel (mode) {
|
modeLabel (mode) {
|
||||||
switch(mode) {
|
switch(mode) {
|
||||||
case 'any': return <FormattedMessage id='hashtag.column_settings.tag_mode.any' defaultMessage='Any of these' />;
|
case 'any':
|
||||||
case 'all': return <FormattedMessage id='hashtag.column_settings.tag_mode.all' defaultMessage='All of these' />;
|
return <FormattedMessage id='hashtag.column_settings.tag_mode.any' defaultMessage='Any of these' />;
|
||||||
case 'none': return <FormattedMessage id='hashtag.column_settings.tag_mode.none' defaultMessage='None of these' />;
|
case 'all':
|
||||||
}
|
return <FormattedMessage id='hashtag.column_settings.tag_mode.all' defaultMessage='All of these' />;
|
||||||
|
case 'none':
|
||||||
|
return <FormattedMessage id='hashtag.column_settings.tag_mode.none' defaultMessage='None of these' />;
|
||||||
|
default:
|
||||||
return '';
|
return '';
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
@ -78,23 +91,21 @@ class ColumnSettings extends React.PureComponent {
|
||||||
<div>
|
<div>
|
||||||
<div className='column-settings__row'>
|
<div className='column-settings__row'>
|
||||||
<div className='setting-toggle'>
|
<div className='setting-toggle'>
|
||||||
<Toggle
|
<Toggle id='hashtag.column_settings.tag_toggle' onChange={this.onToggle} checked={this.state.open} />
|
||||||
id='hashtag.column_settings.tag_toggle'
|
|
||||||
onChange={this.onToggle}
|
|
||||||
checked={this.state.open}
|
|
||||||
/>
|
|
||||||
<span className='setting-toggle__label'>
|
<span className='setting-toggle__label'>
|
||||||
<FormattedMessage id='hashtag.column_settings.tag_toggle' defaultMessage='Include additional tags in this column' />
|
<FormattedMessage id='hashtag.column_settings.tag_toggle' defaultMessage='Include additional tags in this column' />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{this.state.open &&
|
|
||||||
|
{this.state.open && (
|
||||||
<div className='column-settings__hashtags'>
|
<div className='column-settings__hashtags'>
|
||||||
{this.modeSelect('any')}
|
{this.modeSelect('any')}
|
||||||
{this.modeSelect('all')}
|
{this.modeSelect('all')}
|
||||||
{this.modeSelect('none')}
|
{this.modeSelect('none')}
|
||||||
</div>
|
</div>
|
||||||
}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,15 +41,19 @@ class HashtagTimeline extends React.PureComponent {
|
||||||
|
|
||||||
title = () => {
|
title = () => {
|
||||||
let title = [this.props.params.id];
|
let title = [this.props.params.id];
|
||||||
|
|
||||||
if (this.additionalFor('any')) {
|
if (this.additionalFor('any')) {
|
||||||
title.push(' ', <FormattedMessage id='hashtag.column_header.tag_mode.any' values={{ additional: this.additionalFor('any') }} defaultMessage='or {additional}' />);
|
title.push(' ', <FormattedMessage key='any' id='hashtag.column_header.tag_mode.any' values={{ additional: this.additionalFor('any') }} defaultMessage='or {additional}' />);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.additionalFor('all')) {
|
if (this.additionalFor('all')) {
|
||||||
title.push(' ', <FormattedMessage id='hashtag.column_header.tag_mode.all' values={{ additional: this.additionalFor('all') }} defaultMessage='and {additional}' />);
|
title.push(' ', <FormattedMessage key='all' id='hashtag.column_header.tag_mode.all' values={{ additional: this.additionalFor('all') }} defaultMessage='and {additional}' />);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.additionalFor('none')) {
|
if (this.additionalFor('none')) {
|
||||||
title.push(' ', <FormattedMessage id='hashtag.column_header.tag_mode.none' values={{ additional: this.additionalFor('none') }} defaultMessage='without {additional}' />);
|
title.push(' ', <FormattedMessage key='none' id='hashtag.column_header.tag_mode.none' values={{ additional: this.additionalFor('none') }} defaultMessage='without {additional}' />);
|
||||||
}
|
}
|
||||||
|
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,9 +81,10 @@ class HashtagTimeline extends React.PureComponent {
|
||||||
let all = (tags.all || []).map(tag => tag.value);
|
let all = (tags.all || []).map(tag => tag.value);
|
||||||
let none = (tags.none || []).map(tag => tag.value);
|
let none = (tags.none || []).map(tag => tag.value);
|
||||||
|
|
||||||
[id, ...any].map((tag) => {
|
[id, ...any].map(tag => {
|
||||||
this.disconnects.push(dispatch(connectHashtagStream(id, tag, (status) => {
|
this.disconnects.push(dispatch(connectHashtagStream(id, tag, status => {
|
||||||
let tags = status.tags.map(tag => tag.name);
|
let tags = status.tags.map(tag => tag.name);
|
||||||
|
|
||||||
return all.filter(tag => tags.includes(tag)).length === all.length &&
|
return all.filter(tag => tags.includes(tag)).length === all.length &&
|
||||||
none.filter(tag => tags.includes(tag)).length === 0;
|
none.filter(tag => tags.includes(tag)).length === 0;
|
||||||
})));
|
})));
|
||||||
|
@ -95,12 +100,14 @@ class HashtagTimeline extends React.PureComponent {
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
const { id, tags } = this.props.params;
|
const { id, tags } = this.props.params;
|
||||||
|
|
||||||
|
this._subscribe(dispatch, id, tags);
|
||||||
dispatch(expandHashtagTimeline(id, { tags }));
|
dispatch(expandHashtagTimeline(id, { tags }));
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps (nextProps) {
|
componentWillReceiveProps (nextProps) {
|
||||||
const { dispatch, params } = this.props;
|
const { dispatch, params } = this.props;
|
||||||
const { id, tags } = nextProps.params;
|
const { id, tags } = nextProps.params;
|
||||||
|
|
||||||
if (id !== params.id || !isEqual(tags, params.tags)) {
|
if (id !== params.id || !isEqual(tags, params.tags)) {
|
||||||
this._unsubscribe();
|
this._unsubscribe();
|
||||||
this._subscribe(dispatch, id, tags);
|
this._subscribe(dispatch, id, tags);
|
||||||
|
|
|
@ -18,6 +18,7 @@ const messages = defineMessages({
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
accountIds: state.getIn(['user_lists', 'mutes', 'items']),
|
accountIds: state.getIn(['user_lists', 'mutes', 'items']),
|
||||||
|
hasMore: !!state.getIn(['user_lists', 'mutes', 'next']),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default @connect(mapStateToProps)
|
export default @connect(mapStateToProps)
|
||||||
|
@ -28,6 +29,7 @@ class Mutes extends ImmutablePureComponent {
|
||||||
params: PropTypes.object.isRequired,
|
params: PropTypes.object.isRequired,
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
shouldUpdateScroll: PropTypes.func,
|
shouldUpdateScroll: PropTypes.func,
|
||||||
|
hasMore: PropTypes.bool,
|
||||||
accountIds: ImmutablePropTypes.list,
|
accountIds: ImmutablePropTypes.list,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
@ -41,7 +43,7 @@ class Mutes extends ImmutablePureComponent {
|
||||||
}, 300, { leading: true });
|
}, 300, { leading: true });
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl, shouldUpdateScroll, accountIds } = this.props;
|
const { intl, shouldUpdateScroll, hasMore, accountIds } = this.props;
|
||||||
|
|
||||||
if (!accountIds) {
|
if (!accountIds) {
|
||||||
return (
|
return (
|
||||||
|
@ -59,6 +61,7 @@ class Mutes extends ImmutablePureComponent {
|
||||||
<ScrollableList
|
<ScrollableList
|
||||||
scrollKey='mutes'
|
scrollKey='mutes'
|
||||||
onLoadMore={this.handleLoadMore}
|
onLoadMore={this.handleLoadMore}
|
||||||
|
hasMore={hasMore}
|
||||||
shouldUpdateScroll={shouldUpdateScroll}
|
shouldUpdateScroll={shouldUpdateScroll}
|
||||||
emptyMessage={emptyMessage}
|
emptyMessage={emptyMessage}
|
||||||
>
|
>
|
||||||
|
|
|
@ -29,7 +29,15 @@ class Notification extends ImmutablePureComponent {
|
||||||
onMoveUp: PropTypes.func.isRequired,
|
onMoveUp: PropTypes.func.isRequired,
|
||||||
onMoveDown: PropTypes.func.isRequired,
|
onMoveDown: PropTypes.func.isRequired,
|
||||||
onMention: PropTypes.func.isRequired,
|
onMention: PropTypes.func.isRequired,
|
||||||
|
onFavourite: PropTypes.func.isRequired,
|
||||||
|
onReblog: PropTypes.func.isRequired,
|
||||||
|
onToggleHidden: PropTypes.func.isRequired,
|
||||||
|
status: PropTypes.option,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
|
getScrollPosition: PropTypes.func,
|
||||||
|
updateScrollBottom: PropTypes.func,
|
||||||
|
cacheMediaWidth: PropTypes.func,
|
||||||
|
cachedMediaWidth: PropTypes.number,
|
||||||
};
|
};
|
||||||
|
|
||||||
handleMoveUp = () => {
|
handleMoveUp = () => {
|
||||||
|
@ -64,14 +72,32 @@ class Notification extends ImmutablePureComponent {
|
||||||
onMention(notification.get('account'), this.context.router.history);
|
onMention(notification.get('account'), this.context.router.history);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleHotkeyFavourite = () => {
|
||||||
|
const { status } = this.props;
|
||||||
|
if (status) this.props.onFavourite(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleHotkeyBoost = e => {
|
||||||
|
const { status } = this.props;
|
||||||
|
if (status) this.props.onReblog(status, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleHotkeyToggleHidden = () => {
|
||||||
|
const { status } = this.props;
|
||||||
|
if (status) this.props.onToggleHidden(status);
|
||||||
|
}
|
||||||
|
|
||||||
getHandlers () {
|
getHandlers () {
|
||||||
return {
|
return {
|
||||||
moveUp: this.handleMoveUp,
|
reply: this.handleMention,
|
||||||
moveDown: this.handleMoveDown,
|
favourite: this.handleHotkeyFavourite,
|
||||||
|
boost: this.handleHotkeyBoost,
|
||||||
|
mention: this.handleMention,
|
||||||
open: this.handleOpen,
|
open: this.handleOpen,
|
||||||
openProfile: this.handleOpenProfile,
|
openProfile: this.handleOpenProfile,
|
||||||
mention: this.handleMention,
|
moveUp: this.handleMoveUp,
|
||||||
reply: this.handleMention,
|
moveDown: this.handleMoveDown,
|
||||||
|
toggleHidden: this.handleHotkeyToggleHidden,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,6 +132,10 @@ class Notification extends ImmutablePureComponent {
|
||||||
onMoveDown={this.handleMoveDown}
|
onMoveDown={this.handleMoveDown}
|
||||||
onMoveUp={this.handleMoveUp}
|
onMoveUp={this.handleMoveUp}
|
||||||
contextType='notifications'
|
contextType='notifications'
|
||||||
|
getScrollPosition={this.props.getScrollPosition}
|
||||||
|
updateScrollBottom={this.props.updateScrollBottom}
|
||||||
|
cachedMediaWidth={this.props.cachedMediaWidth}
|
||||||
|
cacheMediaWidth={this.props.cacheMediaWidth}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -118,7 +148,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
<div className='notification notification-favourite focusable' tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.favourite', defaultMessage: '{name} favourited your status' }, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
|
<div className='notification notification-favourite focusable' tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.favourite', defaultMessage: '{name} favourited your status' }, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
|
||||||
<div className='notification__message'>
|
<div className='notification__message'>
|
||||||
<div className='notification__favourite-icon-wrapper'>
|
<div className='notification__favourite-icon-wrapper'>
|
||||||
<i className='fa fa-fw fa-star star-icon' />
|
<i className='fa fa-fw fa-floppy-o star-icon' />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span title={notification.get('created_at')}>
|
<span title={notification.get('created_at')}>
|
||||||
|
@ -126,7 +156,17 @@ class Notification extends ImmutablePureComponent {
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<StatusContainer id={notification.get('status')} account={notification.get('account')} muted withDismiss hidden={!!this.props.hidden} />
|
<StatusContainer
|
||||||
|
id={notification.get('status')}
|
||||||
|
account={notification.get('account')}
|
||||||
|
muted
|
||||||
|
withDismiss
|
||||||
|
hidden={!!this.props.hidden}
|
||||||
|
getScrollPosition={this.props.getScrollPosition}
|
||||||
|
updateScrollBottom={this.props.updateScrollBottom}
|
||||||
|
cachedMediaWidth={this.props.cachedMediaWidth}
|
||||||
|
cacheMediaWidth={this.props.cacheMediaWidth}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</HotKeys>
|
||||||
);
|
);
|
||||||
|
@ -148,7 +188,17 @@ class Notification extends ImmutablePureComponent {
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<StatusContainer id={notification.get('status')} account={notification.get('account')} muted withDismiss hidden={this.props.hidden} />
|
<StatusContainer
|
||||||
|
id={notification.get('status')}
|
||||||
|
account={notification.get('account')}
|
||||||
|
muted
|
||||||
|
withDismiss
|
||||||
|
hidden={this.props.hidden}
|
||||||
|
getScrollPosition={this.props.getScrollPosition}
|
||||||
|
updateScrollBottom={this.props.updateScrollBottom}
|
||||||
|
cachedMediaWidth={this.props.cachedMediaWidth}
|
||||||
|
cacheMediaWidth={this.props.cacheMediaWidth}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</HotKeys>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,14 +1,31 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { makeGetNotification } from '../../../selectors';
|
import { makeGetNotification, makeGetStatus } from '../../../selectors';
|
||||||
import Notification from '../components/notification';
|
import Notification from '../components/notification';
|
||||||
|
import { openModal } from '../../../actions/modal';
|
||||||
import { mentionCompose } from '../../../actions/compose';
|
import { mentionCompose } from '../../../actions/compose';
|
||||||
|
import {
|
||||||
|
reblog,
|
||||||
|
favourite,
|
||||||
|
unreblog,
|
||||||
|
unfavourite,
|
||||||
|
} from '../../../actions/interactions';
|
||||||
|
import {
|
||||||
|
hideStatus,
|
||||||
|
revealStatus,
|
||||||
|
} from '../../../actions/statuses';
|
||||||
|
import { boostModal } from '../../../initial_state';
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
const makeMapStateToProps = () => {
|
||||||
const getNotification = makeGetNotification();
|
const getNotification = makeGetNotification();
|
||||||
|
const getStatus = makeGetStatus();
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => ({
|
const mapStateToProps = (state, props) => {
|
||||||
notification: getNotification(state, props.notification, props.accountId),
|
const notification = getNotification(state, props.notification, props.accountId);
|
||||||
});
|
return {
|
||||||
|
notification: notification,
|
||||||
|
status: notification.get('status') ? getStatus(state, { id: notification.get('status') }) : null,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
return mapStateToProps;
|
return mapStateToProps;
|
||||||
};
|
};
|
||||||
|
@ -17,6 +34,38 @@ const mapDispatchToProps = dispatch => ({
|
||||||
onMention: (account, router) => {
|
onMention: (account, router) => {
|
||||||
dispatch(mentionCompose(account, router));
|
dispatch(mentionCompose(account, router));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onModalReblog (status) {
|
||||||
|
dispatch(reblog(status));
|
||||||
|
},
|
||||||
|
|
||||||
|
onReblog (status, e) {
|
||||||
|
if (status.get('reblogged')) {
|
||||||
|
dispatch(unreblog(status));
|
||||||
|
} else {
|
||||||
|
if (e.shiftKey || !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));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onToggleHidden (status) {
|
||||||
|
if (status.get('hidden')) {
|
||||||
|
dispatch(revealStatus(status.get('id')));
|
||||||
|
} else {
|
||||||
|
dispatch(hideStatus(status.get('id')));
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(makeMapStateToProps, mapDispatchToProps)(Notification);
|
export default connect(makeMapStateToProps, mapDispatchToProps)(Notification);
|
||||||
|
|
|
@ -175,7 +175,7 @@ class ActionBar extends React.PureComponent {
|
||||||
<div className='detailed-status__action-bar'>
|
<div className='detailed-status__action-bar'>
|
||||||
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} /></div>
|
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} /></div>
|
||||||
<div className='detailed-status__button'><IconButton disabled={reblog_disabled} active={status.get('reblogged')} title={reblog_disabled ? intl.formatMessage(messages.cannot_reblog) : intl.formatMessage(messages.reblog)} icon={reblogIcon} onClick={this.handleReblogClick} /></div>
|
<div className='detailed-status__button'><IconButton disabled={reblog_disabled} active={status.get('reblogged')} title={reblog_disabled ? intl.formatMessage(messages.cannot_reblog) : intl.formatMessage(messages.reblog)} icon={reblogIcon} onClick={this.handleReblogClick} /></div>
|
||||||
<div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /></div>
|
<div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='floppy-o' onClick={this.handleFavouriteClick} /></div>
|
||||||
{shareButton}
|
{shareButton}
|
||||||
|
|
||||||
<div className='detailed-status__action-bar-dropdown'>
|
<div className='detailed-status__action-bar-dropdown'>
|
||||||
|
|
|
@ -60,6 +60,8 @@ export default class Card extends React.PureComponent {
|
||||||
maxDescription: PropTypes.number,
|
maxDescription: PropTypes.number,
|
||||||
onOpenMedia: PropTypes.func.isRequired,
|
onOpenMedia: PropTypes.func.isRequired,
|
||||||
compact: PropTypes.bool,
|
compact: PropTypes.bool,
|
||||||
|
defaultWidth: PropTypes.number,
|
||||||
|
cacheWidth: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
|
@ -68,7 +70,7 @@ export default class Card extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
width: 280,
|
width: this.props.defaultWidth || 280,
|
||||||
embedded: false,
|
embedded: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -111,6 +113,7 @@ export default class Card extends React.PureComponent {
|
||||||
|
|
||||||
setRef = c => {
|
setRef = c => {
|
||||||
if (c) {
|
if (c) {
|
||||||
|
if (this.props.cacheWidth) this.props.cacheWidth(c.offsetWidth);
|
||||||
this.setState({ width: c.offsetWidth });
|
this.setState({ width: c.offsetWidth });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const status = this.props.status.get('reblog') ? this.props.status.get('reblog') : this.props.status;
|
const status = (this.props.status && this.props.status.get('reblog')) ? this.props.status.get('reblog') : this.props.status;
|
||||||
const outerStyle = { boxSizing: 'border-box' };
|
const outerStyle = { boxSizing: 'border-box' };
|
||||||
const { compact } = this.props;
|
const { compact } = this.props;
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
|
||||||
if (this.context.router) {
|
if (this.context.router) {
|
||||||
favouriteLink = (
|
favouriteLink = (
|
||||||
<Link to={`/statuses/${status.get('id')}/favourites`} className='detailed-status__link'>
|
<Link to={`/statuses/${status.get('id')}/favourites`} className='detailed-status__link'>
|
||||||
<i className='fa fa-star' />
|
<i className='fa fa-floppy-o' />
|
||||||
<span className='detailed-status__favorites'>
|
<span className='detailed-status__favorites'>
|
||||||
<FormattedNumber value={status.get('favourites_count')} />
|
<FormattedNumber value={status.get('favourites_count')} />
|
||||||
</span>
|
</span>
|
||||||
|
@ -181,7 +181,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
|
||||||
} else {
|
} else {
|
||||||
favouriteLink = (
|
favouriteLink = (
|
||||||
<a href={`/interact/${status.get('id')}?type=favourite`} className='detailed-status__link' onClick={this.handleModalLink}>
|
<a href={`/interact/${status.get('id')}?type=favourite`} className='detailed-status__link' onClick={this.handleModalLink}>
|
||||||
<i className='fa fa-star' />
|
<i className='fa fa-floppy-o' />
|
||||||
<span className='detailed-status__favorites'>
|
<span className='detailed-status__favorites'>
|
||||||
<FormattedNumber value={status.get('favourites_count')} />
|
<FormattedNumber value={status.get('favourites_count')} />
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -0,0 +1,614 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Button from '../../../components/button';
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
import Atrament from 'atrament'; // the doodling library
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import { doodleSet, uploadCompose } from '../../../actions/compose';
|
||||||
|
import IconButton from '../../../components/icon_button';
|
||||||
|
import { debounce, mapValues } from 'lodash';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
// palette nicked from MyPaint, CC0
|
||||||
|
const palette = [
|
||||||
|
['rgb( 0, 0, 0)', 'Black'],
|
||||||
|
['rgb( 38, 38, 38)', 'Gray 15'],
|
||||||
|
['rgb( 77, 77, 77)', 'Grey 30'],
|
||||||
|
['rgb(128, 128, 128)', 'Grey 50'],
|
||||||
|
['rgb(171, 171, 171)', 'Grey 67'],
|
||||||
|
['rgb(217, 217, 217)', 'Grey 85'],
|
||||||
|
['rgb(255, 255, 255)', 'White'],
|
||||||
|
['rgb(128, 0, 0)', 'Maroon'],
|
||||||
|
['rgb(209, 0, 0)', 'English-red'],
|
||||||
|
['rgb(255, 54, 34)', 'Tomato'],
|
||||||
|
['rgb(252, 60, 3)', 'Orange-red'],
|
||||||
|
['rgb(255, 140, 105)', 'Salmon'],
|
||||||
|
['rgb(252, 232, 32)', 'Cadium-yellow'],
|
||||||
|
['rgb(243, 253, 37)', 'Lemon yellow'],
|
||||||
|
['rgb(121, 5, 35)', 'Dark crimson'],
|
||||||
|
['rgb(169, 32, 62)', 'Deep carmine'],
|
||||||
|
['rgb(255, 140, 0)', 'Orange'],
|
||||||
|
['rgb(255, 168, 18)', 'Dark tangerine'],
|
||||||
|
['rgb(217, 144, 88)', 'Persian orange'],
|
||||||
|
['rgb(194, 178, 128)', 'Sand'],
|
||||||
|
['rgb(255, 229, 180)', 'Peach'],
|
||||||
|
['rgb(100, 54, 46)', 'Bole'],
|
||||||
|
['rgb(108, 41, 52)', 'Dark cordovan'],
|
||||||
|
['rgb(163, 65, 44)', 'Chestnut'],
|
||||||
|
['rgb(228, 136, 100)', 'Dark salmon'],
|
||||||
|
['rgb(255, 195, 143)', 'Apricot'],
|
||||||
|
['rgb(255, 219, 188)', 'Unbleached silk'],
|
||||||
|
['rgb(242, 227, 198)', 'Straw'],
|
||||||
|
['rgb( 53, 19, 13)', 'Bistre'],
|
||||||
|
['rgb( 84, 42, 14)', 'Dark chocolate'],
|
||||||
|
['rgb(102, 51, 43)', 'Burnt sienna'],
|
||||||
|
['rgb(184, 66, 0)', 'Sienna'],
|
||||||
|
['rgb(216, 153, 12)', 'Yellow ochre'],
|
||||||
|
['rgb(210, 180, 140)', 'Tan'],
|
||||||
|
['rgb(232, 204, 144)', 'Dark wheat'],
|
||||||
|
['rgb( 0, 49, 83)', 'Prussian blue'],
|
||||||
|
['rgb( 48, 69, 119)', 'Dark grey blue'],
|
||||||
|
['rgb( 0, 71, 171)', 'Cobalt blue'],
|
||||||
|
['rgb( 31, 117, 254)', 'Blue'],
|
||||||
|
['rgb(120, 180, 255)', 'Bright french blue'],
|
||||||
|
['rgb(171, 200, 255)', 'Bright steel blue'],
|
||||||
|
['rgb(208, 231, 255)', 'Ice blue'],
|
||||||
|
['rgb( 30, 51, 58)', 'Medium jungle green'],
|
||||||
|
['rgb( 47, 79, 79)', 'Dark slate grey'],
|
||||||
|
['rgb( 74, 104, 93)', 'Dark grullo green'],
|
||||||
|
['rgb( 0, 128, 128)', 'Teal'],
|
||||||
|
['rgb( 67, 170, 176)', 'Turquoise'],
|
||||||
|
['rgb(109, 174, 199)', 'Cerulean frost'],
|
||||||
|
['rgb(173, 217, 186)', 'Tiffany green'],
|
||||||
|
['rgb( 22, 34, 29)', 'Gray-asparagus'],
|
||||||
|
['rgb( 36, 48, 45)', 'Medium dark teal'],
|
||||||
|
['rgb( 74, 104, 93)', 'Xanadu'],
|
||||||
|
['rgb(119, 198, 121)', 'Mint'],
|
||||||
|
['rgb(175, 205, 182)', 'Timberwolf'],
|
||||||
|
['rgb(185, 245, 246)', 'Celeste'],
|
||||||
|
['rgb(193, 255, 234)', 'Aquamarine'],
|
||||||
|
['rgb( 29, 52, 35)', 'Cal Poly Pomona'],
|
||||||
|
['rgb( 1, 68, 33)', 'Forest green'],
|
||||||
|
['rgb( 42, 128, 0)', 'Napier green'],
|
||||||
|
['rgb(128, 128, 0)', 'Olive'],
|
||||||
|
['rgb( 65, 156, 105)', 'Sea green'],
|
||||||
|
['rgb(189, 246, 29)', 'Green-yellow'],
|
||||||
|
['rgb(231, 244, 134)', 'Bright chartreuse'],
|
||||||
|
['rgb(138, 23, 137)', 'Purple'],
|
||||||
|
['rgb( 78, 39, 138)', 'Violet'],
|
||||||
|
['rgb(193, 75, 110)', 'Dark thulian pink'],
|
||||||
|
['rgb(222, 49, 99)', 'Cerise'],
|
||||||
|
['rgb(255, 20, 147)', 'Deep pink'],
|
||||||
|
['rgb(255, 102, 204)', 'Rose pink'],
|
||||||
|
['rgb(255, 203, 219)', 'Pink'],
|
||||||
|
['rgb(255, 255, 255)', 'White'],
|
||||||
|
['rgb(229, 17, 1)', 'RGB Red'],
|
||||||
|
['rgb( 0, 255, 0)', 'RGB Green'],
|
||||||
|
['rgb( 0, 0, 255)', 'RGB Blue'],
|
||||||
|
['rgb( 0, 255, 255)', 'CMYK Cyan'],
|
||||||
|
['rgb(255, 0, 255)', 'CMYK Magenta'],
|
||||||
|
['rgb(255, 255, 0)', 'CMYK Yellow'],
|
||||||
|
];
|
||||||
|
|
||||||
|
// re-arrange to the right order for display
|
||||||
|
let palReordered = [];
|
||||||
|
for (let row = 0; row < 7; row++) {
|
||||||
|
for (let col = 0; col < 11; col++) {
|
||||||
|
palReordered.push(palette[col * 7 + row]);
|
||||||
|
}
|
||||||
|
palReordered.push(null); // null indicates a <br />
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility for converting base64 image to binary for upload
|
||||||
|
// https://stackoverflow.com/questions/35940290/how-to-convert-base64-string-to-javascript-file-object-like-as-from-file-input-f
|
||||||
|
function dataURLtoFile(dataurl, filename) {
|
||||||
|
let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
|
||||||
|
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
|
||||||
|
while(n--){
|
||||||
|
u8arr[n] = bstr.charCodeAt(n);
|
||||||
|
}
|
||||||
|
return new File([u8arr], filename, { type: mime });
|
||||||
|
}
|
||||||
|
|
||||||
|
const DOODLE_SIZES = {
|
||||||
|
normal: [500, 500, 'Square 500'],
|
||||||
|
tootbanner: [702, 330, 'Tootbanner'],
|
||||||
|
s640x480: [640, 480, '640×480 - 480p'],
|
||||||
|
s800x600: [800, 600, '800×600 - SVGA'],
|
||||||
|
s720x480: [720, 405, '720x405 - 16:9'],
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
options: state.getIn(['compose', 'doodle']),
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
/** Set options in the redux store */
|
||||||
|
setOpt: (opts) => dispatch(doodleSet(opts)),
|
||||||
|
/** Submit doodle for upload */
|
||||||
|
submit: (file) => dispatch(uploadCompose([file])),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Doodling dialog with drawing canvas
|
||||||
|
*
|
||||||
|
* Keyboard shortcuts:
|
||||||
|
* - Delete: Clear screen, fill with background color
|
||||||
|
* - Backspace, Ctrl+Z: Undo one step
|
||||||
|
* - Ctrl held while drawing: Use background color
|
||||||
|
* - Shift held while clicking screen: Use fill tool
|
||||||
|
*
|
||||||
|
* Palette:
|
||||||
|
* - Left mouse button: pick foreground
|
||||||
|
* - Ctrl + left mouse button: pick background
|
||||||
|
* - Right mouse button: pick background
|
||||||
|
*/
|
||||||
|
@connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
export default class DoodleModal extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
options: ImmutablePropTypes.map,
|
||||||
|
onClose: PropTypes.func.isRequired,
|
||||||
|
setOpt: PropTypes.func.isRequired,
|
||||||
|
submit: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
//region Option getters/setters
|
||||||
|
|
||||||
|
/** Foreground color */
|
||||||
|
get fg () {
|
||||||
|
return this.props.options.get('fg');
|
||||||
|
}
|
||||||
|
set fg (value) {
|
||||||
|
this.props.setOpt({ fg: value });
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Background color */
|
||||||
|
get bg () {
|
||||||
|
return this.props.options.get('bg');
|
||||||
|
}
|
||||||
|
set bg (value) {
|
||||||
|
this.props.setOpt({ bg: value });
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Swap Fg and Bg for drawing */
|
||||||
|
get swapped () {
|
||||||
|
return this.props.options.get('swapped');
|
||||||
|
}
|
||||||
|
set swapped (value) {
|
||||||
|
this.props.setOpt({ swapped: value });
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Mode - 'draw' or 'fill' */
|
||||||
|
get mode () {
|
||||||
|
return this.props.options.get('mode');
|
||||||
|
}
|
||||||
|
set mode (value) {
|
||||||
|
this.props.setOpt({ mode: value });
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Base line weight */
|
||||||
|
get weight () {
|
||||||
|
return this.props.options.get('weight');
|
||||||
|
}
|
||||||
|
set weight (value) {
|
||||||
|
this.props.setOpt({ weight: value });
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Drawing opacity */
|
||||||
|
get opacity () {
|
||||||
|
return this.props.options.get('opacity');
|
||||||
|
}
|
||||||
|
set opacity (value) {
|
||||||
|
this.props.setOpt({ opacity: value });
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adaptive stroke - change width with speed */
|
||||||
|
get adaptiveStroke () {
|
||||||
|
return this.props.options.get('adaptiveStroke');
|
||||||
|
}
|
||||||
|
set adaptiveStroke (value) {
|
||||||
|
this.props.setOpt({ adaptiveStroke: value });
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Smoothing (for mouse drawing) */
|
||||||
|
get smoothing () {
|
||||||
|
return this.props.options.get('smoothing');
|
||||||
|
}
|
||||||
|
set smoothing (value) {
|
||||||
|
this.props.setOpt({ smoothing: value });
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Size preset */
|
||||||
|
get size () {
|
||||||
|
return this.props.options.get('size');
|
||||||
|
}
|
||||||
|
set size (value) {
|
||||||
|
this.props.setOpt({ size: value });
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
/** Key up handler */
|
||||||
|
handleKeyUp = (e) => {
|
||||||
|
if (e.target.nodeName === 'INPUT') return;
|
||||||
|
|
||||||
|
if (e.key === 'Delete') {
|
||||||
|
e.preventDefault();
|
||||||
|
this.handleClearBtn();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.key === 'Backspace' || (e.key === 'z' && (e.ctrlKey || e.metaKey))) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.undo();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.key === 'Control' || e.key === 'Meta') {
|
||||||
|
this.controlHeld = false;
|
||||||
|
this.swapped = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.key === 'Shift') {
|
||||||
|
this.shiftHeld = false;
|
||||||
|
this.mode = 'draw';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Key down handler */
|
||||||
|
handleKeyDown = (e) => {
|
||||||
|
if (e.key === 'Control' || e.key === 'Meta') {
|
||||||
|
this.controlHeld = true;
|
||||||
|
this.swapped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.key === 'Shift') {
|
||||||
|
this.shiftHeld = true;
|
||||||
|
this.mode = 'fill';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component installed in the DOM, do some initial set-up
|
||||||
|
*/
|
||||||
|
componentDidMount () {
|
||||||
|
this.controlHeld = false;
|
||||||
|
this.shiftHeld = false;
|
||||||
|
this.swapped = false;
|
||||||
|
window.addEventListener('keyup', this.handleKeyUp, false);
|
||||||
|
window.addEventListener('keydown', this.handleKeyDown, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tear component down
|
||||||
|
*/
|
||||||
|
componentWillUnmount () {
|
||||||
|
window.removeEventListener('keyup', this.handleKeyUp, false);
|
||||||
|
window.removeEventListener('keydown', this.handleKeyDown, false);
|
||||||
|
if (this.sketcher) this.sketcher.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set reference to the canvas element.
|
||||||
|
* This is called during component init
|
||||||
|
*
|
||||||
|
* @param elem - canvas element
|
||||||
|
*/
|
||||||
|
setCanvasRef = (elem) => {
|
||||||
|
this.canvas = elem;
|
||||||
|
if (elem) {
|
||||||
|
elem.addEventListener('dirty', () => {
|
||||||
|
this.saveUndo();
|
||||||
|
this.sketcher._dirty = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
elem.addEventListener('click', () => {
|
||||||
|
// sketcher bug - does not fire dirty on fill
|
||||||
|
if (this.mode === 'fill') {
|
||||||
|
this.saveUndo();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// prevent context menu
|
||||||
|
elem.addEventListener('contextmenu', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
elem.addEventListener('mousedown', (e) => {
|
||||||
|
if (e.button === 2) {
|
||||||
|
this.swapped = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
elem.addEventListener('mouseup', (e) => {
|
||||||
|
if (e.button === 2) {
|
||||||
|
this.swapped = this.controlHeld;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.initSketcher(elem);
|
||||||
|
this.mode = 'draw'; // Reset mode - it's confusing if left at 'fill'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the sketcher instance
|
||||||
|
*
|
||||||
|
* @param canvas - canvas element. Null if we're just resizing
|
||||||
|
*/
|
||||||
|
initSketcher (canvas = null) {
|
||||||
|
const sizepreset = DOODLE_SIZES[this.size];
|
||||||
|
|
||||||
|
if (this.sketcher) this.sketcher.destroy();
|
||||||
|
this.sketcher = new Atrament(canvas || this.canvas, sizepreset[0], sizepreset[1]);
|
||||||
|
|
||||||
|
if (canvas) {
|
||||||
|
this.ctx = this.sketcher.context;
|
||||||
|
this.updateSketcherSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.clearScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Done button handler
|
||||||
|
*/
|
||||||
|
onDoneButton = () => {
|
||||||
|
const dataUrl = this.sketcher.toImage();
|
||||||
|
const file = dataURLtoFile(dataUrl, 'doodle.png');
|
||||||
|
this.props.submit(file);
|
||||||
|
this.props.onClose(); // close dialog
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel button handler
|
||||||
|
*/
|
||||||
|
onCancelButton = () => {
|
||||||
|
if (this.undos.length > 1 && !confirm('Discard doodle? All changes will be lost!')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.onClose(); // close dialog
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update sketcher options based on state
|
||||||
|
*/
|
||||||
|
updateSketcherSettings () {
|
||||||
|
if (!this.sketcher) return;
|
||||||
|
|
||||||
|
if (this.oldSize !== this.size) this.initSketcher();
|
||||||
|
|
||||||
|
this.sketcher.color = (this.swapped ? this.bg : this.fg);
|
||||||
|
this.sketcher.opacity = this.opacity;
|
||||||
|
this.sketcher.weight = this.weight;
|
||||||
|
this.sketcher.mode = this.mode;
|
||||||
|
this.sketcher.smoothing = this.smoothing;
|
||||||
|
this.sketcher.adaptiveStroke = this.adaptiveStroke;
|
||||||
|
|
||||||
|
this.oldSize = this.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill screen with background color
|
||||||
|
*/
|
||||||
|
clearScreen = () => {
|
||||||
|
this.ctx.fillStyle = this.bg;
|
||||||
|
this.ctx.fillRect(-1, -1, this.canvas.width+2, this.canvas.height+2);
|
||||||
|
this.undos = [];
|
||||||
|
|
||||||
|
this.doSaveUndo();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undo one step
|
||||||
|
*/
|
||||||
|
undo = () => {
|
||||||
|
if (this.undos.length > 1) {
|
||||||
|
this.undos.pop();
|
||||||
|
const buf = this.undos.pop();
|
||||||
|
|
||||||
|
this.sketcher.clear();
|
||||||
|
this.ctx.putImageData(buf, 0, 0);
|
||||||
|
this.doSaveUndo();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save canvas content into the undo buffer immediately
|
||||||
|
*/
|
||||||
|
doSaveUndo = () => {
|
||||||
|
this.undos.push(this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on each canvas change.
|
||||||
|
* Saves canvas content to the undo buffer after some period of inactivity.
|
||||||
|
*/
|
||||||
|
saveUndo = debounce(() => {
|
||||||
|
this.doSaveUndo();
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Palette left click.
|
||||||
|
* Selects Fg color (or Bg, if Control/Meta is held)
|
||||||
|
*
|
||||||
|
* @param e - event
|
||||||
|
*/
|
||||||
|
onPaletteClick = (e) => {
|
||||||
|
const c = e.target.dataset.color;
|
||||||
|
|
||||||
|
if (this.controlHeld) {
|
||||||
|
this.bg = c;
|
||||||
|
} else {
|
||||||
|
this.fg = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.target.blur();
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Palette right click.
|
||||||
|
* Selects Bg color
|
||||||
|
*
|
||||||
|
* @param e - event
|
||||||
|
*/
|
||||||
|
onPaletteRClick = (e) => {
|
||||||
|
this.bg = e.target.dataset.color;
|
||||||
|
e.target.blur();
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle click on the Draw mode button
|
||||||
|
*
|
||||||
|
* @param e - event
|
||||||
|
*/
|
||||||
|
setModeDraw = (e) => {
|
||||||
|
this.mode = 'draw';
|
||||||
|
e.target.blur();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle click on the Fill mode button
|
||||||
|
*
|
||||||
|
* @param e - event
|
||||||
|
*/
|
||||||
|
setModeFill = (e) => {
|
||||||
|
this.mode = 'fill';
|
||||||
|
e.target.blur();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle click on Smooth checkbox
|
||||||
|
*
|
||||||
|
* @param e - event
|
||||||
|
*/
|
||||||
|
tglSmooth = (e) => {
|
||||||
|
this.smoothing = !this.smoothing;
|
||||||
|
e.target.blur();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle click on Adaptive checkbox
|
||||||
|
*
|
||||||
|
* @param e - event
|
||||||
|
*/
|
||||||
|
tglAdaptive = (e) => {
|
||||||
|
this.adaptiveStroke = !this.adaptiveStroke;
|
||||||
|
e.target.blur();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle change of the Weight input field
|
||||||
|
*
|
||||||
|
* @param e - event
|
||||||
|
*/
|
||||||
|
setWeight = (e) => {
|
||||||
|
this.weight = +e.target.value || 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set size - clalback from the select box
|
||||||
|
*
|
||||||
|
* @param e - event
|
||||||
|
*/
|
||||||
|
changeSize = (e) => {
|
||||||
|
let newSize = e.target.value;
|
||||||
|
if (newSize === this.oldSize) return;
|
||||||
|
|
||||||
|
if (this.undos.length > 1 && !confirm('Change size? This will erase your drawing!')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.size = newSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
handleClearBtn = () => {
|
||||||
|
if (this.undos.length > 1 && !confirm('Clear screen? This will erase your drawing!')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.clearScreen();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the component
|
||||||
|
*/
|
||||||
|
render () {
|
||||||
|
this.updateSketcherSettings();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='modal-root__modal doodle-modal'>
|
||||||
|
<div className='doodle-modal__container'>
|
||||||
|
<canvas ref={this.setCanvasRef} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='doodle-modal__action-bar'>
|
||||||
|
<div className='doodle-toolbar'>
|
||||||
|
<Button text='Done' onClick={this.onDoneButton} />
|
||||||
|
<Button text='Cancel' onClick={this.onCancelButton} />
|
||||||
|
</div>
|
||||||
|
<div className='filler' />
|
||||||
|
<div className='doodle-toolbar with-inputs'>
|
||||||
|
<div>
|
||||||
|
<label htmlFor='dd_smoothing'>Smoothing</label>
|
||||||
|
<span className='val'>
|
||||||
|
<input type='checkbox' id='dd_smoothing' onChange={this.tglSmooth} checked={this.smoothing} />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor='dd_adaptive'>Adaptive</label>
|
||||||
|
<span className='val'>
|
||||||
|
<input type='checkbox' id='dd_adaptive' onChange={this.tglAdaptive} checked={this.adaptiveStroke} />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor='dd_weight'>Weight</label>
|
||||||
|
<span className='val'>
|
||||||
|
<input type='number' min={1} id='dd_weight' value={this.weight} onChange={this.setWeight} />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<select aria-label='Canvas size' onInput={this.changeSize} defaultValue={this.size}>
|
||||||
|
{ Object.values(mapValues(DOODLE_SIZES, (val, k) =>
|
||||||
|
<option key={k} value={k}>{val[2]}</option>
|
||||||
|
)) }
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='doodle-toolbar'>
|
||||||
|
<IconButton icon='pencil' title='Draw' label='Draw' onClick={this.setModeDraw} size={18} active={this.mode === 'draw'} inverted />
|
||||||
|
<IconButton icon='bath' title='Fill' label='Fill' onClick={this.setModeFill} size={18} active={this.mode === 'fill'} inverted />
|
||||||
|
<IconButton icon='undo' title='Undo' label='Undo' onClick={this.undo} size={18} inverted />
|
||||||
|
<IconButton icon='trash' title='Clear' label='Clear' onClick={this.handleClearBtn} size={18} inverted />
|
||||||
|
</div>
|
||||||
|
<div className='doodle-palette'>
|
||||||
|
{
|
||||||
|
palReordered.map((c, i) =>
|
||||||
|
c === null ?
|
||||||
|
<br key={i} /> :
|
||||||
|
<button
|
||||||
|
key={i}
|
||||||
|
style={{ backgroundColor: c[0] }}
|
||||||
|
onClick={this.onPaletteClick}
|
||||||
|
onContextMenu={this.onPaletteRClick}
|
||||||
|
data-color={c[0]}
|
||||||
|
title={c[1]}
|
||||||
|
className={classNames({
|
||||||
|
'foreground': this.fg === c[0],
|
||||||
|
'background': this.bg === c[0],
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import ActionsModal from './actions_modal';
|
||||||
import MediaModal from './media_modal';
|
import MediaModal from './media_modal';
|
||||||
import VideoModal from './video_modal';
|
import VideoModal from './video_modal';
|
||||||
import BoostModal from './boost_modal';
|
import BoostModal from './boost_modal';
|
||||||
|
import DoodleModal from './doodle_modal';
|
||||||
import ConfirmationModal from './confirmation_modal';
|
import ConfirmationModal from './confirmation_modal';
|
||||||
import FocalPointModal from './focal_point_modal';
|
import FocalPointModal from './focal_point_modal';
|
||||||
import {
|
import {
|
||||||
|
@ -22,6 +23,7 @@ const MODAL_COMPONENTS = {
|
||||||
'MEDIA': () => Promise.resolve({ default: MediaModal }),
|
'MEDIA': () => Promise.resolve({ default: MediaModal }),
|
||||||
'VIDEO': () => Promise.resolve({ default: VideoModal }),
|
'VIDEO': () => Promise.resolve({ default: VideoModal }),
|
||||||
'BOOST': () => Promise.resolve({ default: BoostModal }),
|
'BOOST': () => Promise.resolve({ default: BoostModal }),
|
||||||
|
'DOODLE': () => Promise.resolve({ default: DoodleModal }),
|
||||||
'CONFIRM': () => Promise.resolve({ default: ConfirmationModal }),
|
'CONFIRM': () => Promise.resolve({ default: ConfirmationModal }),
|
||||||
'MUTE': MuteModal,
|
'MUTE': MuteModal,
|
||||||
'REPORT': ReportModal,
|
'REPORT': ReportModal,
|
||||||
|
@ -43,6 +45,16 @@ export default class ModalRoot extends React.PureComponent {
|
||||||
getSnapshotBeforeUpdate () {
|
getSnapshotBeforeUpdate () {
|
||||||
return { visible: !!this.props.type };
|
return { visible: !!this.props.type };
|
||||||
}
|
}
|
||||||
|
state = {
|
||||||
|
revealed: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
handleKeyUp = (e) => {
|
||||||
|
if ((e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27)
|
||||||
|
&& !!this.props.type && !this.props.props.noEsc) {
|
||||||
|
this.props.onClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentDidUpdate (prevProps, prevState, { visible }) {
|
componentDidUpdate (prevProps, prevState, { visible }) {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
|
@ -53,7 +65,7 @@ export default class ModalRoot extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLoading = modalId => () => {
|
renderLoading = modalId => () => {
|
||||||
return ['MEDIA', 'VIDEO', 'BOOST', 'CONFIRM', 'ACTIONS'].indexOf(modalId) === -1 ? <ModalLoading /> : null;
|
return ['MEDIA', 'VIDEO', 'BOOST', 'DOODLE', 'CONFIRM', 'ACTIONS'].indexOf(modalId) === -1 ? <ModalLoading /> : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderError = (props) => {
|
renderError = (props) => {
|
||||||
|
|
|
@ -99,6 +99,7 @@ class Video extends React.PureComponent {
|
||||||
onCloseVideo: PropTypes.func,
|
onCloseVideo: PropTypes.func,
|
||||||
detailed: PropTypes.bool,
|
detailed: PropTypes.bool,
|
||||||
inline: PropTypes.bool,
|
inline: PropTypes.bool,
|
||||||
|
cacheWidth: PropTypes.func,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -108,7 +109,7 @@ class Video extends React.PureComponent {
|
||||||
volume: 0.5,
|
volume: 0.5,
|
||||||
paused: true,
|
paused: true,
|
||||||
dragging: false,
|
dragging: false,
|
||||||
containerWidth: false,
|
containerWidth: this.props.width,
|
||||||
fullscreen: false,
|
fullscreen: false,
|
||||||
hovered: false,
|
hovered: false,
|
||||||
muted: false,
|
muted: false,
|
||||||
|
@ -128,6 +129,7 @@ class Video extends React.PureComponent {
|
||||||
this.player = c;
|
this.player = c;
|
||||||
|
|
||||||
if (c) {
|
if (c) {
|
||||||
|
if (this.props.cacheWidth) this.props.cacheWidth(this.player.offsetWidth);
|
||||||
this.setState({
|
this.setState({
|
||||||
containerWidth: c.offsetWidth,
|
containerWidth: c.offsetWidth,
|
||||||
});
|
});
|
||||||
|
@ -136,6 +138,9 @@ class Video extends React.PureComponent {
|
||||||
|
|
||||||
setVideoRef = c => {
|
setVideoRef = c => {
|
||||||
this.video = c;
|
this.video = c;
|
||||||
|
if (this.video) {
|
||||||
|
this.setState({ volume: this.video.volume, muted: this.video.muted });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setSeekRef = c => {
|
setSeekRef = c => {
|
||||||
|
@ -302,6 +307,10 @@ class Video extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleVolumeChange = () => {
|
||||||
|
this.setState({ volume: this.video.volume, muted: this.video.muted });
|
||||||
|
}
|
||||||
|
|
||||||
handleOpenVideo = () => {
|
handleOpenVideo = () => {
|
||||||
const { src, preview, width, height, alt } = this.props;
|
const { src, preview, width, height, alt } = this.props;
|
||||||
const media = fromJS({
|
const media = fromJS({
|
||||||
|
@ -337,7 +346,6 @@ class Video extends React.PureComponent {
|
||||||
width = containerWidth;
|
width = containerWidth;
|
||||||
height = containerWidth / (16/9);
|
height = containerWidth / (16/9);
|
||||||
|
|
||||||
playerStyle.width = width;
|
|
||||||
playerStyle.height = height;
|
playerStyle.height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,6 +395,7 @@ class Video extends React.PureComponent {
|
||||||
onTimeUpdate={this.handleTimeUpdate}
|
onTimeUpdate={this.handleTimeUpdate}
|
||||||
onLoadedData={this.handleLoadedData}
|
onLoadedData={this.handleLoadedData}
|
||||||
onProgress={this.handleProgress}
|
onProgress={this.handleProgress}
|
||||||
|
onVolumeChange={this.handleVolumeChange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<button type='button' className={classNames('video-player__spoiler', { active: !revealed })} onClick={this.toggleReveal}>
|
<button type='button' className={classNames('video-player__spoiler', { active: !revealed })} onClick={this.toggleReveal}>
|
||||||
|
@ -409,7 +418,7 @@ class Video extends React.PureComponent {
|
||||||
<div className='video-player__buttons-bar'>
|
<div className='video-player__buttons-bar'>
|
||||||
<div className='video-player__buttons left'>
|
<div className='video-player__buttons left'>
|
||||||
<button type='button' aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay}><i className={classNames('fa fa-fw', { 'fa-play': paused, 'fa-pause': !paused })} /></button>
|
<button type='button' aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay}><i className={classNames('fa fa-fw', { 'fa-play': paused, 'fa-pause': !paused })} /></button>
|
||||||
<button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onMouseEnter={this.volumeSlider} onMouseLeave={this.volumeSlider} onClick={this.toggleMute}><i className={classNames('fa fa-fw', { 'fa-volume-off': muted, 'fa-volume-up': !muted })} /></button>
|
<button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><i className={classNames('fa fa-fw', { 'fa-volume-off': muted, 'fa-volume-up': !muted })} /></button>
|
||||||
<div className='video-player__volume' onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}>
|
<div className='video-player__volume' onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}>
|
||||||
<div className='video-player__volume__current' style={{ width: `${volumeWidth}px` }} />
|
<div className='video-player__volume__current' style={{ width: `${volumeWidth}px` }} />
|
||||||
<span
|
<span
|
||||||
|
|
|
@ -0,0 +1,293 @@
|
||||||
|
{
|
||||||
|
"account.block": "Block @{name}",
|
||||||
|
"account.block_domain": "Hide everything from {domain}",
|
||||||
|
"account.blocked": "Blocked",
|
||||||
|
"account.disclaimer_full": "THESE NUMBERS ARE THE STUFF WHAT YOUR SERVER KNOWS ABOUT AND THERE MIGHT BE MORE THAT IT DONT KNOW ABOUT.",
|
||||||
|
"account.domain_blocked": "Domain hidden",
|
||||||
|
"account.edit_profile": "edit ~/.profile",
|
||||||
|
"account.follow": "Follow",
|
||||||
|
"account.followers": "Followers",
|
||||||
|
"account.follows": "Follows",
|
||||||
|
"account.follows_you": "Follows you",
|
||||||
|
"account.hide_reblogs": "Hide boosts from @{name}",
|
||||||
|
"account.media": "Media",
|
||||||
|
"account.mention": "Mention @{name}",
|
||||||
|
"account.moved_to": "{name} has moved to:",
|
||||||
|
"account.mute": "Mute @{name}",
|
||||||
|
"account.mute_notifications": "Mute notifications from @{name}",
|
||||||
|
"account.muted": "Muted",
|
||||||
|
"account.posts": "Pings",
|
||||||
|
"account.posts_with_replies": "Pings with replies",
|
||||||
|
"account.report": "Report @{name}",
|
||||||
|
"account.requested": "Awaiting approval. Click to cancel follow request",
|
||||||
|
"account.share": "Share @{name}'s profile",
|
||||||
|
"account.show_reblogs": "Show boosts from @{name}",
|
||||||
|
"account.unblock": "Unblock @{name}",
|
||||||
|
"account.unblock_domain": "Unhide {domain}",
|
||||||
|
"account.unfollow": "Unfollow",
|
||||||
|
"account.unmute": "Unmute @{name}",
|
||||||
|
"account.unmute_notifications": "Unmute notifications from @{name}",
|
||||||
|
"account.view_full_profile": "View full profile",
|
||||||
|
"boost_modal.combo": "You can press {combo} to skip this next time",
|
||||||
|
"bundle_column_error.body": "Something went wrong while loading this component.",
|
||||||
|
"bundle_column_error.retry": "Try again",
|
||||||
|
"bundle_column_error.title": "Network error",
|
||||||
|
"bundle_modal_error.close": "Close",
|
||||||
|
"bundle_modal_error.message": "Something went wrong while loading this component.",
|
||||||
|
"bundle_modal_error.retry": "Try again",
|
||||||
|
"column.blocks": "~/.blocked",
|
||||||
|
"column.community": "/timelines/local",
|
||||||
|
"column.direct": "~/.dms",
|
||||||
|
"column.favourites": "~/.florps",
|
||||||
|
"column.follow_requests": "~/.follow-requests",
|
||||||
|
"column.home": "/timelines/home",
|
||||||
|
"column.lists": "Lists",
|
||||||
|
"column.mutes": "~/.muted",
|
||||||
|
"column.notifications": "~/.notifications",
|
||||||
|
"column.pins": "~/.pinned",
|
||||||
|
"column.public": "/timelines/federated",
|
||||||
|
"column_back_button.label": "Back",
|
||||||
|
"column_header.hide_settings": "Hide settings",
|
||||||
|
"column_header.moveLeft_settings": "Move column to the left",
|
||||||
|
"column_header.moveRight_settings": "Move column to the right",
|
||||||
|
"column_header.pin": "Pin",
|
||||||
|
"column_header.show_settings": "Show settings",
|
||||||
|
"column_header.unpin": "Unpin",
|
||||||
|
"column_subheading.navigation": "Navigation",
|
||||||
|
"column_subheading.settings": "Settings",
|
||||||
|
"compose.attach": "Attach...",
|
||||||
|
"compose.attach.doodle": "Draw something",
|
||||||
|
"compose.attach.upload": "Upload a file",
|
||||||
|
"compose_form.hashtag_warning": "This ping won't be listed under any hashtag as it is unlisted. Only public pings can be searched by hashtag.",
|
||||||
|
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
|
||||||
|
"compose_form.lock_disclaimer.lock": "locked",
|
||||||
|
"compose_form.placeholder": "What is in your databanks?",
|
||||||
|
"compose_form.publish": "Ping",
|
||||||
|
"compose_form.publish_loud": "{publish}!",
|
||||||
|
"compose_form.sensitive.marked": "Media is marked as sensitive",
|
||||||
|
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
|
||||||
|
"compose_form.spoiler.marked": "Text is hidden behind warning",
|
||||||
|
"compose_form.spoiler.unmarked": "Text is not hidden",
|
||||||
|
"compose_form.spoiler_placeholder": "Write your warning here",
|
||||||
|
"confirmation_modal.cancel": "Cancel",
|
||||||
|
"confirmations.block.confirm": "Block",
|
||||||
|
"confirmations.block.message": "Are you sure you want to block {name}?",
|
||||||
|
"confirmations.delete.confirm": "Delete",
|
||||||
|
"confirmations.delete.message": "Are you sure you want to delete this status?",
|
||||||
|
"confirmations.delete_list.confirm": "Delete",
|
||||||
|
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
||||||
|
"confirmations.domain_block.confirm": "Hide entire domain",
|
||||||
|
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
|
||||||
|
"confirmations.mute.confirm": "Mute",
|
||||||
|
"confirmations.mute.message": "Are you sure you want to mute {name}?",
|
||||||
|
"confirmations.unfollow.confirm": "Unfollow",
|
||||||
|
"confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
|
||||||
|
"doodle_button.label": "Add a drawing",
|
||||||
|
"embed.instructions": "Embed this status on your website by copying the code below.",
|
||||||
|
"embed.preview": "Here is what it will look like:",
|
||||||
|
"emoji_button.activity": "Activity",
|
||||||
|
"emoji_button.custom": "Custom",
|
||||||
|
"emoji_button.flags": "Flags",
|
||||||
|
"emoji_button.food": "Food & Drink",
|
||||||
|
"emoji_button.label": "Insert emoji",
|
||||||
|
"emoji_button.nature": "Nature",
|
||||||
|
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
|
||||||
|
"emoji_button.objects": "Objects",
|
||||||
|
"emoji_button.people": "People",
|
||||||
|
"emoji_button.recent": "Frequently used",
|
||||||
|
"emoji_button.search": "Search...",
|
||||||
|
"emoji_button.search_results": "Search results",
|
||||||
|
"emoji_button.symbols": "Symbols",
|
||||||
|
"emoji_button.travel": "Travel & Places",
|
||||||
|
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
|
||||||
|
"empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
|
||||||
|
"empty_column.hashtag": "There is nothing in this hashtag yet.",
|
||||||
|
"empty_column.home": "Your home timeline is empty! Visit {public} or use query to get started and meet other users.",
|
||||||
|
"empty_column.home.public_timeline": "the public timeline",
|
||||||
|
"empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.",
|
||||||
|
"empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.",
|
||||||
|
"empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up",
|
||||||
|
"follow_request.authorize": "Authorize",
|
||||||
|
"follow_request.reject": "Reject",
|
||||||
|
"getting_started.appsshort": "Apps",
|
||||||
|
"getting_started.faq": "FAQ",
|
||||||
|
"getting_started.heading": "Getting started",
|
||||||
|
"getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.",
|
||||||
|
"getting_started.userguide": "User Guide",
|
||||||
|
"home.column_settings.advanced": "Advanced",
|
||||||
|
"home.column_settings.basic": "Basic",
|
||||||
|
"home.column_settings.filter_regex": "Filter out by regular expressions",
|
||||||
|
"home.column_settings.show_reblogs": "Show relays",
|
||||||
|
"home.column_settings.show_replies": "Show replies",
|
||||||
|
"home.settings": "Column settings",
|
||||||
|
"keyboard_shortcuts.back": "to navigate back",
|
||||||
|
"keyboard_shortcuts.boost": "to boost",
|
||||||
|
"keyboard_shortcuts.column": "to focus a status in one of the columns",
|
||||||
|
"keyboard_shortcuts.compose": "to focus the compose textarea",
|
||||||
|
"keyboard_shortcuts.description": "Description",
|
||||||
|
"keyboard_shortcuts.down": "to move down in the list",
|
||||||
|
"keyboard_shortcuts.enter": "to open status",
|
||||||
|
"keyboard_shortcuts.favourite": "to favourite",
|
||||||
|
"keyboard_shortcuts.heading": "Keyboard Shortcuts",
|
||||||
|
"keyboard_shortcuts.hotkey": "Hotkey",
|
||||||
|
"keyboard_shortcuts.legend": "to display this legend",
|
||||||
|
"keyboard_shortcuts.mention": "to mention author",
|
||||||
|
"keyboard_shortcuts.reply": "to reply",
|
||||||
|
"keyboard_shortcuts.search": "to focus search",
|
||||||
|
"keyboard_shortcuts.toot": "to start a brand new ping",
|
||||||
|
"keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
|
||||||
|
"keyboard_shortcuts.up": "to move up in the list",
|
||||||
|
"lightbox.close": "Close",
|
||||||
|
"lightbox.next": "Next",
|
||||||
|
"lightbox.previous": "Previous",
|
||||||
|
"lists.account.add": "Add to list",
|
||||||
|
"lists.account.remove": "Remove from list",
|
||||||
|
"lists.delete": "Delete list",
|
||||||
|
"lists.edit": "Edit list",
|
||||||
|
"lists.new.create": "Add list",
|
||||||
|
"lists.new.title_placeholder": "New list title",
|
||||||
|
"lists.search": "Search among people you follow",
|
||||||
|
"lists.subheading": "Your lists",
|
||||||
|
"loading_indicator.label": "Loading...",
|
||||||
|
"media_gallery.toggle_visible": "Toggle visibility",
|
||||||
|
"missing_indicator.label": "Not found",
|
||||||
|
"missing_indicator.sublabel": "This resource could not be found",
|
||||||
|
"mute_modal.hide_notifications": "Hide notifications from this user?",
|
||||||
|
"navigation_bar.blocks": "~/.blocks",
|
||||||
|
"navigation_bar.community_timeline": "/timelines/local",
|
||||||
|
"navigation_bar.direct": "~/.dms",
|
||||||
|
"navigation_bar.edit_profile": "edit ~/.profile",
|
||||||
|
"navigation_bar.favourites": "~/.florps",
|
||||||
|
"navigation_bar.follow_requests": "~/.follow-requests",
|
||||||
|
"navigation_bar.info": "/about/more",
|
||||||
|
"navigation_bar.keyboard_shortcuts": "~/.kbd/shortcuts.conf",
|
||||||
|
"navigation_bar.lists": "~/.lists",
|
||||||
|
"navigation_bar.logout": "Jack out",
|
||||||
|
"navigation_bar.mutes": "~/.muted",
|
||||||
|
"navigation_bar.pins": "~/.pinned",
|
||||||
|
"navigation_bar.preferences": "edit ~/.config",
|
||||||
|
"navigation_bar.public_timeline": "/timelines/federated",
|
||||||
|
"notification.favourite": "{name} florped your ping",
|
||||||
|
"notification.follow": "{name} followed you",
|
||||||
|
"notification.mention": "{name} mentioned you",
|
||||||
|
"notification.reblog": "{name} relayed your ping",
|
||||||
|
"notifications.clear": "Clear notifications",
|
||||||
|
"notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?",
|
||||||
|
"notifications.column_settings.alert": "Desktop notifications",
|
||||||
|
"notifications.column_settings.favourite": "Favourites:",
|
||||||
|
"notifications.column_settings.follow": "New followers:",
|
||||||
|
"notifications.column_settings.mention": "Mentions:",
|
||||||
|
"notifications.column_settings.push": "Push notifications",
|
||||||
|
"notifications.column_settings.push_meta": "This device",
|
||||||
|
"notifications.column_settings.reblog": "Boosts:",
|
||||||
|
"notifications.column_settings.show": "Show in column",
|
||||||
|
"notifications.column_settings.sound": "Play sound",
|
||||||
|
"onboarding.done": "Done",
|
||||||
|
"onboarding.next": "Next",
|
||||||
|
"onboarding.page_five.public_timelines": "The local timeline shows public posts from everyone on {domain}. The federated timeline shows public posts from everyone who people on {domain} follow. These are the Public Timelines, a great way to discover new people.",
|
||||||
|
"onboarding.page_four.home": "The home timeline shows posts from people you follow.",
|
||||||
|
"onboarding.page_four.notifications": "The notifications column shows when someone interacts with you.",
|
||||||
|
"onboarding.page_one.federation": "Mastodon is a network of independent servers joining up to make one larger social network. We call these servers instances.",
|
||||||
|
"onboarding.page_one.full_handle": "Your full handle",
|
||||||
|
"onboarding.page_one.handle_hint": "This is what you would tell your friends to search for.",
|
||||||
|
"onboarding.page_one.welcome": "Welcome to Mastodon!",
|
||||||
|
"onboarding.page_six.admin": "Your instance's admin is {admin}.",
|
||||||
|
"onboarding.page_six.almost_done": "Almost done...",
|
||||||
|
"onboarding.page_six.appetoot": "Hang ten on the cybrewaves!",
|
||||||
|
"onboarding.page_six.apps_available": "There are {apps} available for iOS, Android and other platforms.",
|
||||||
|
"onboarding.page_six.github": "Mastodon is free open-source software. You can report bugs, request features, or contribute to the code on {github}.",
|
||||||
|
"onboarding.page_six.guidelines": "community guidelines",
|
||||||
|
"onboarding.page_six.read_guidelines": "Please read {domain}'s {guidelines}!",
|
||||||
|
"onboarding.page_six.various_app": "mobile apps",
|
||||||
|
"onboarding.page_three.profile": "Edit your profile to change your avatar, bio, and display name. There, you will also find other preferences.",
|
||||||
|
"onboarding.page_three.search": "Use the search bar to find people and look at hashtags, such as {illustration} and {introductions}. To look for a person who is not on this instance, use their full handle.",
|
||||||
|
"onboarding.page_two.compose": "Write posts from the compose column. You can upload images, change privacy settings, and add content warnings with the icons below.",
|
||||||
|
"onboarding.skip": "Skip",
|
||||||
|
"privacy.change": "Adjust status privacy",
|
||||||
|
"privacy.direct.long": "Post to mentioned users only",
|
||||||
|
"privacy.direct.short": "Direct",
|
||||||
|
"privacy.private.long": "Post to followers only",
|
||||||
|
"privacy.private.short": "Followers-only",
|
||||||
|
"privacy.public.long": "Post to public timelines",
|
||||||
|
"privacy.public.short": "Public",
|
||||||
|
"privacy.unlisted.long": "Do not post to public timelines",
|
||||||
|
"privacy.unlisted.short": "Unlisted",
|
||||||
|
"regeneration_indicator.label": "Loading…",
|
||||||
|
"regeneration_indicator.sublabel": "Your home feed is being prepared!",
|
||||||
|
"relative_time.days": "{number}d",
|
||||||
|
"relative_time.hours": "{number}h",
|
||||||
|
"relative_time.just_now": "now",
|
||||||
|
"relative_time.minutes": "{number}m",
|
||||||
|
"relative_time.seconds": "{number}s",
|
||||||
|
"reply_indicator.cancel": "Cancel",
|
||||||
|
"report.forward": "Forward to {target}",
|
||||||
|
"report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
|
||||||
|
"report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:",
|
||||||
|
"report.placeholder": "Additional comments",
|
||||||
|
"report.submit": "Submit",
|
||||||
|
"report.target": "Reporting {target}",
|
||||||
|
"search.placeholder": "Query...",
|
||||||
|
"search_popout.search_format": "Advanced search format",
|
||||||
|
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
|
||||||
|
"search_popout.tips.hashtag": "hashtag",
|
||||||
|
"search_popout.tips.status": "status",
|
||||||
|
"search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags",
|
||||||
|
"search_popout.tips.user": "user",
|
||||||
|
"search_results.accounts": "People",
|
||||||
|
"search_results.hashtags": "Hashtags",
|
||||||
|
"search_results.statuses": "Pings",
|
||||||
|
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
|
||||||
|
"standalone.public_title": "Peer into the data grid...",
|
||||||
|
"status.block": "Block @{name}",
|
||||||
|
"status.cannot_reblog": "This ping cannot be relayed",
|
||||||
|
"status.delete": "Delete",
|
||||||
|
"status.embed": "Embed",
|
||||||
|
"status.favourite": "Florp",
|
||||||
|
"status.load_more": "Load more",
|
||||||
|
"status.media_hidden": "Media hidden",
|
||||||
|
"status.mention": "Mention @{name}",
|
||||||
|
"status.more": "More",
|
||||||
|
"status.mute": "Mute @{name}",
|
||||||
|
"status.mute_conversation": "Mute conversation",
|
||||||
|
"status.open": "Expand this status",
|
||||||
|
"status.pin": "Pin on profile",
|
||||||
|
"status.pinned": "Pinned ping",
|
||||||
|
"status.reblog": "Relay",
|
||||||
|
"status.reblogged_by": "{name} relayed",
|
||||||
|
"status.reply": "Reply",
|
||||||
|
"status.replyAll": "Reply to thread",
|
||||||
|
"status.report": "Report @{name}",
|
||||||
|
"status.sensitive_toggle": "Click to view",
|
||||||
|
"status.sensitive_warning": "Sensitive content",
|
||||||
|
"status.share": "Share",
|
||||||
|
"status.show_less": "Show less",
|
||||||
|
"status.show_less_all": "Show less for all",
|
||||||
|
"status.show_more": "Show more",
|
||||||
|
"status.show_more_all": "Show more for all",
|
||||||
|
"status.unmute_conversation": "Unmute conversation",
|
||||||
|
"status.unpin": "Unpin from profile",
|
||||||
|
"tabs_bar.federated_timeline": "/timelines/federated",
|
||||||
|
"tabs_bar.home": "/timelines/home",
|
||||||
|
"tabs_bar.local_timeline": "/timelines/local",
|
||||||
|
"tabs_bar.notifications": "~/.notifications",
|
||||||
|
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||||
|
"upload_area.title": "Drag & drop to upload",
|
||||||
|
"upload_button.label": "Add media",
|
||||||
|
"upload_form.description": "Describe for the visually impaired",
|
||||||
|
"upload_form.focus": "Crop",
|
||||||
|
"upload_form.undo": "Undo",
|
||||||
|
"upload_progress.label": "Uploading...",
|
||||||
|
"video.close": "Close video",
|
||||||
|
"video.exit_fullscreen": "Exit full screen",
|
||||||
|
"video.expand": "Expand video",
|
||||||
|
"video.fullscreen": "Full screen",
|
||||||
|
"video.hide": "Hide video",
|
||||||
|
"video.mute": "Mute sound",
|
||||||
|
"video.pause": "Pause",
|
||||||
|
"video.play": "Play",
|
||||||
|
"video.unmute": "Unmute sound",
|
||||||
|
"video_player.expand": "Expand video",
|
||||||
|
"video_player.toggle_sound": "Toggle sound",
|
||||||
|
"video_player.toggle_visible": "Toggle visibility",
|
||||||
|
"video_player.video_error": "Video could not be played"
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
[
|
||||||
|
]
|
|
@ -28,6 +28,7 @@ import {
|
||||||
COMPOSE_UPLOAD_CHANGE_REQUEST,
|
COMPOSE_UPLOAD_CHANGE_REQUEST,
|
||||||
COMPOSE_UPLOAD_CHANGE_SUCCESS,
|
COMPOSE_UPLOAD_CHANGE_SUCCESS,
|
||||||
COMPOSE_UPLOAD_CHANGE_FAIL,
|
COMPOSE_UPLOAD_CHANGE_FAIL,
|
||||||
|
COMPOSE_DOODLE_SET,
|
||||||
COMPOSE_RESET,
|
COMPOSE_RESET,
|
||||||
} from '../actions/compose';
|
} from '../actions/compose';
|
||||||
import { TIMELINE_DELETE } from '../actions/timelines';
|
import { TIMELINE_DELETE } from '../actions/timelines';
|
||||||
|
@ -62,6 +63,17 @@ const initialState = ImmutableMap({
|
||||||
resetFileKey: Math.floor((Math.random() * 0x10000)),
|
resetFileKey: Math.floor((Math.random() * 0x10000)),
|
||||||
idempotencyKey: null,
|
idempotencyKey: null,
|
||||||
tagHistory: ImmutableList(),
|
tagHistory: ImmutableList(),
|
||||||
|
doodle: ImmutableMap({
|
||||||
|
fg: 'rgb( 0, 0, 0)',
|
||||||
|
bg: 'rgb(255, 255, 255)',
|
||||||
|
swapped: false,
|
||||||
|
mode: 'draw',
|
||||||
|
size: 'normal',
|
||||||
|
weight: 2,
|
||||||
|
opacity: 1,
|
||||||
|
adaptiveStroke: true,
|
||||||
|
smoothing: false,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
function statusToTextMentions(state, status) {
|
function statusToTextMentions(state, status) {
|
||||||
|
@ -330,6 +342,8 @@ export default function compose(state = initialState, action) {
|
||||||
map.set('spoiler_text', '');
|
map.set('spoiler_text', '');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
case COMPOSE_DOODLE_SET:
|
||||||
|
return state.mergeIn(['doodle'], action.options);
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,3 +8,5 @@ loadPolyfills().then(() => {
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
require('what-input');
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import ready from '../mastodon/ready';
|
||||||
|
|
||||||
|
ready(() => {
|
||||||
|
const image = document.querySelector('img');
|
||||||
|
|
||||||
|
image.addEventListener('mouseenter', () => {
|
||||||
|
image.src = '/oops.gif';
|
||||||
|
});
|
||||||
|
|
||||||
|
image.addEventListener('mouseleave', () => {
|
||||||
|
image.src = '/oops.png';
|
||||||
|
});
|
||||||
|
});
|
|
@ -18,6 +18,12 @@ window.addEventListener('message', e => {
|
||||||
id: data.id,
|
id: data.id,
|
||||||
height: document.getElementsByTagName('html')[0].scrollHeight,
|
height: document.getElementsByTagName('html')[0].scrollHeight,
|
||||||
}, '*');
|
}, '*');
|
||||||
|
|
||||||
|
if (document.fonts && document.fonts.ready) {
|
||||||
|
document.fonts.ready.then(sizeBioText);
|
||||||
|
} else {
|
||||||
|
sizeBioText();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -116,6 +122,17 @@ function main() {
|
||||||
document.head.appendChild(scrollbarWidthStyle);
|
document.head.appendChild(scrollbarWidthStyle);
|
||||||
scrollbarWidthStyle.sheet.insertRule(`body.with-modals--active { margin-right: ${scrollbarWidth}px; }`, 0);
|
scrollbarWidthStyle.sheet.insertRule(`body.with-modals--active { margin-right: ${scrollbarWidth}px; }`, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[].forEach.call(document.querySelectorAll('[data-component="Card"]'), (content) => {
|
||||||
|
const props = JSON.parse(content.getAttribute('data-props'));
|
||||||
|
ReactDOM.render(<CardContainer locale={locale} {...props} />, content);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (document.fonts && document.fonts.ready) {
|
||||||
|
document.fonts.ready.then(sizeBioText);
|
||||||
|
} else {
|
||||||
|
sizeBioText();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
delegate(document, '.webapp-btn', 'click', ({ target, button }) => {
|
delegate(document, '.webapp-btn', 'click', ({ target, button }) => {
|
||||||
|
@ -214,6 +231,22 @@ function main() {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
delegate(document, '#account_note', 'input', sizeBioText);
|
||||||
|
|
||||||
|
function sizeBioText() {
|
||||||
|
const noteCounter = document.querySelector('.note-counter');
|
||||||
|
const bioTextArea = document.querySelector('#account_note');
|
||||||
|
|
||||||
|
if (noteCounter) {
|
||||||
|
noteCounter.textContent = 413 - length(bioTextArea.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bioTextArea) {
|
||||||
|
bioTextArea.style.height = 'auto';
|
||||||
|
bioTextArea.style.height = (bioTextArea.scrollHeight+3) + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadPolyfills().then(main).catch(error => {
|
loadPolyfills().then(main).catch(error => {
|
||||||
|
|
|
@ -12,3 +12,58 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rich-formatting a,
|
||||||
|
.rich-formatting p a,
|
||||||
|
.rich-formatting li a,
|
||||||
|
.landing-page__short-description p a,
|
||||||
|
.status__content a,
|
||||||
|
.reply-indicator__content a {
|
||||||
|
color: lighten($ui-highlight-color, 12%);
|
||||||
|
text-decoration: underline;
|
||||||
|
|
||||||
|
&.mention {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mention span {
|
||||||
|
text-decoration: underline;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:active {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:active {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.status__content__spoiler-link {
|
||||||
|
color: $secondary-text-color;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status__content__read-more-button {
|
||||||
|
text-decoration: underline;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:active {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.getting-started__footer a {
|
||||||
|
text-decoration: underline;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:active {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
|
||||||
|
@import 'application';
|
||||||
|
|
||||||
|
/* Allow columns to grow wider as the screen gets
|
||||||
|
* wider, but don't ever let them get more than
|
||||||
|
* 400px (some people have a bunch of columns!) */
|
||||||
|
@media screen and (min-width: 1300px) {
|
||||||
|
.column {
|
||||||
|
flex-grow: 1 !important;
|
||||||
|
max-width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer {
|
||||||
|
width: 17%; /* Not part of the flex fun */
|
||||||
|
max-width: 400px;
|
||||||
|
min-width: 330px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cap the column height at 100vh (fixed an old
|
||||||
|
* bug someone encountered in safari, but which
|
||||||
|
* I've seen resurface from time to time) */
|
||||||
|
.column {
|
||||||
|
max-height:100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't show outline around statuses if we're in
|
||||||
|
* mouse or touch mode (rather than keyboard) */
|
||||||
|
[data-whatinput="mouse"], [data-whatinput="touch"] {
|
||||||
|
.status__content:focus, .status:focus,
|
||||||
|
.status__wrapper:focus, .status__content__text:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Less emphatic show more */
|
||||||
|
.status__content__read-more-button {
|
||||||
|
font-size: 14px;
|
||||||
|
color: $dark-text-color;
|
||||||
|
|
||||||
|
.status__prepend-icon {
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show a little arrowey thing after the time in a
|
||||||
|
* status to signal that you can click it to see
|
||||||
|
* a detailed view */
|
||||||
|
.status time:after,
|
||||||
|
.detailed-status__datetime span:after {
|
||||||
|
font: normal normal normal 14px/1 FontAwesome;
|
||||||
|
content: "\00a0\00a0\f08e";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't display the elephant mascot (we have our
|
||||||
|
* own, thanks) */
|
||||||
|
.drawer__inner__mastodon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let the compose area/drawer be short, but
|
||||||
|
* expand if necessary */
|
||||||
|
.drawer .drawer__inner {
|
||||||
|
overflow: visible;
|
||||||
|
height:inherit;
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
.drawer__pager {
|
||||||
|
overflow-y:auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use display: none instead of visibility:hidden
|
||||||
|
* to hide the suggested follows list on non-mobile */
|
||||||
|
@media screen and (min-width: 630px) {
|
||||||
|
.search-results .trends {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@import 'fullwidth-media';
|
||||||
|
|
|
@ -0,0 +1,943 @@
|
||||||
|
$success-green: #B64579; // Padua
|
||||||
|
|
||||||
|
$ui-base-color: #f7e8ed; // "darkest"
|
||||||
|
$ui-base-alt: #f9f2f5;
|
||||||
|
$ui-base-lighter-color: darken($ui-base-color, 40%); // Lighter darkest
|
||||||
|
$ui-secondary-color: #ead0d6; // "lightest"
|
||||||
|
$ui-primary-color: #bf5677; // "lighter"
|
||||||
|
$ui-highlight-color: #bf5677; // "vibrant"
|
||||||
|
$primary-text-color: #382b32;
|
||||||
|
$dark-text-color: #ca748f;
|
||||||
|
$secondary-text-color: #382b32;
|
||||||
|
|
||||||
|
$header-color: $ui-primary-color;
|
||||||
|
$header-text-color: #fff;
|
||||||
|
$icon-button-inactive-color: lighten(desaturate($ui-base-lighter-color, 20%), 20%);
|
||||||
|
$action-button-color: $icon-button-inactive-color;
|
||||||
|
|
||||||
|
$about-page-text: $primary-text-color;
|
||||||
|
|
||||||
|
@import 'cybre-base';
|
||||||
|
|
||||||
|
$gold-star: #dd9d08;
|
||||||
|
|
||||||
|
/* cybre-specific additions */
|
||||||
|
|
||||||
|
.column .static-content.getting-started {
|
||||||
|
background-image: url('../images/logo-cybre-light.png');
|
||||||
|
background-size:auto 50%;
|
||||||
|
background-position: 50% 75%;
|
||||||
|
background-repeat:no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui, body {
|
||||||
|
background: $ui-base-color url('../images/background-cybre-light.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer__inner__mastodon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-page .header-wrapper {
|
||||||
|
background-image:url('../images/header-cybre-alt.jpg');
|
||||||
|
background-size:cover;
|
||||||
|
background-position:50% 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-page.alternative .header {
|
||||||
|
background-image:url('../images/header-cybre-colour.jpg');
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
background-size:contain;
|
||||||
|
height:45vh;
|
||||||
|
width: 100%;
|
||||||
|
position:absolute;
|
||||||
|
z-index: 1;
|
||||||
|
text-align:center;
|
||||||
|
|
||||||
|
display: unset!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-page.alternative .header img {
|
||||||
|
margin: auto;
|
||||||
|
max-height:45vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.landing-page.alternative .grid {
|
||||||
|
position: relative;
|
||||||
|
z-index:2;
|
||||||
|
margin-top:15vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-page.alternative .landing-page__hero img {
|
||||||
|
visibility: hidden;
|
||||||
|
max-height:170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-page.alternative .landing-page__forms {
|
||||||
|
height:auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-page.alternative .column-1 {
|
||||||
|
display:flex;
|
||||||
|
align-items:flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-page.alternative .column {
|
||||||
|
max-height:initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-page.alternative .row__mascot {
|
||||||
|
.floats {
|
||||||
|
position:absolute;
|
||||||
|
img {
|
||||||
|
width:100%;
|
||||||
|
height:100%;
|
||||||
|
}
|
||||||
|
transition: all 0.1s linear;
|
||||||
|
animation-name: floating;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
animation-direction: alternate;
|
||||||
|
animation-timing-function: ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.float-1 {
|
||||||
|
width:50px;
|
||||||
|
height:50px;
|
||||||
|
bottom:60px;
|
||||||
|
left:110px;
|
||||||
|
animation-duration: 3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.float-2 {
|
||||||
|
width:130px;
|
||||||
|
height:130px;
|
||||||
|
left:85px;
|
||||||
|
bottom: -60px;
|
||||||
|
animation-duration: 3.5s;
|
||||||
|
animation-delay: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.float-3 {
|
||||||
|
width:100px;
|
||||||
|
height:100px;
|
||||||
|
right: 50;
|
||||||
|
top: -10px;
|
||||||
|
animation-duration: 4s;
|
||||||
|
animation-delay: 0.5s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* about.scss */
|
||||||
|
|
||||||
|
.landing-page {
|
||||||
|
h1 {
|
||||||
|
color: $about-page-text;
|
||||||
|
small {
|
||||||
|
color: lighten($about-page-text, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p, li {
|
||||||
|
color: $about-page-text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-wrapper {
|
||||||
|
padding-top:0px;
|
||||||
|
|
||||||
|
background-size:cover;
|
||||||
|
background-position:50% 55%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-wrapper {
|
||||||
|
.mascot {
|
||||||
|
width:500px;
|
||||||
|
bottom:-52px;
|
||||||
|
left:-120px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container.links {
|
||||||
|
background-color: $ui-base-color;
|
||||||
|
border-top: 5px solid $ui-primary-color;
|
||||||
|
width:100%;
|
||||||
|
max-width:100%;
|
||||||
|
padding:0px calc(50% - 400px);
|
||||||
|
|
||||||
|
a {
|
||||||
|
&:hover {
|
||||||
|
color: lighten($ui-primary-color, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container.hero {
|
||||||
|
.floats {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.closed-registrations-message, form {
|
||||||
|
border-top: 50px solid #5f4770;
|
||||||
|
-webkit-box-shadow: 0 0 6px rgba(0,0,0,.1);
|
||||||
|
box-shadow: 0 0 6px rgba(0,0,0,.1);
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family:inherit;
|
||||||
|
line-height:inherit;
|
||||||
|
font-weight:normal;
|
||||||
|
color:white;
|
||||||
|
position:absolute;
|
||||||
|
top:-35px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.closed-registrations-message:before {
|
||||||
|
content: "Registrations closed";
|
||||||
|
}
|
||||||
|
|
||||||
|
form:before {
|
||||||
|
content: "Register now";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#mastodon-timeline {
|
||||||
|
.column-header {
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.features-list__row {
|
||||||
|
.text {
|
||||||
|
color: $about-page-text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.information-board {
|
||||||
|
.panel {
|
||||||
|
.panel-header {
|
||||||
|
color: $primary-text-color;
|
||||||
|
border-bottom: 1px solid lighten($ui-secondary-color, 4%);
|
||||||
|
|
||||||
|
a,
|
||||||
|
span {
|
||||||
|
font-weight: 400;
|
||||||
|
color: lighten($ui-primary-color, 4%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* components.scss */
|
||||||
|
|
||||||
|
.onboarding-modal__page {
|
||||||
|
p {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-header {
|
||||||
|
background: $header-color;
|
||||||
|
color: $header-text-color;
|
||||||
|
border-top-left-radius: 3px;
|
||||||
|
border-top-right-radius: 3px;
|
||||||
|
box-shadow: 0px 0px 3px rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-header__button {
|
||||||
|
background: $header-color;
|
||||||
|
color: $header-text-color;
|
||||||
|
border-top-right-radius: 3px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: darken($ui-base-color, 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: $primary-text-color;
|
||||||
|
background: darken($ui-base-color, 5%);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: darken($ui-base-color, 5%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-card, .status-card.compact {
|
||||||
|
border-color: $ui-highlight-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// selectivity -- needs to override .column-header > button
|
||||||
|
.column-header .column-header__back-button {
|
||||||
|
background: $header-color;
|
||||||
|
color:$header-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-back-button {
|
||||||
|
background: $header-color;
|
||||||
|
color:$header-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-header__collapsible-inner {
|
||||||
|
background: darken($ui-base-alt, 2%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-column-indicator,
|
||||||
|
.error-column {
|
||||||
|
color: darken($ui-base-lighter-color, 15%);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.compose-form {
|
||||||
|
.autosuggest-textarea__textarea,
|
||||||
|
.spoiler-input__input {
|
||||||
|
color: $primary-text-color;
|
||||||
|
border: 1px solid $ui-primary-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autosuggest-textarea__textarea {
|
||||||
|
border-bottom-width:0px;
|
||||||
|
}
|
||||||
|
.compose-form__modifiers {
|
||||||
|
border: 1px solid $ui-primary-color;
|
||||||
|
border-top-width:0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compose-form__buttons button.active:last-child {
|
||||||
|
border-radius:3px;
|
||||||
|
background: $ui-base-color;
|
||||||
|
color: $ui-primary-color;
|
||||||
|
}
|
||||||
|
.compose-form__buttons-wrapper {
|
||||||
|
background-color:$ui-primary-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button.inverted {
|
||||||
|
color:white;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color:$ui-secondary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button.icon-button {
|
||||||
|
&.disabled {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button {
|
||||||
|
&.inverted {
|
||||||
|
color: darken($ui-base-lighter-color, 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.overlayed {
|
||||||
|
background: rgba($base-overlay-background, 0.2);
|
||||||
|
color: rgba($white, 0.7);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba($base-overlay-background, 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
color: desaturate($icon-button-inactive-color, 5%);
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:active,
|
||||||
|
&:focus {
|
||||||
|
color: desaturate($icon-button-inactive-color, 5%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
color: $icon-button-inactive-color;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:active,
|
||||||
|
&:focus {
|
||||||
|
color: darken($icon-button-inactive-color, 5%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button.star-icon,
|
||||||
|
.icon-button.star-icon:active {
|
||||||
|
background:transparent;
|
||||||
|
border:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button.star-icon.active {
|
||||||
|
color: $gold-star;
|
||||||
|
&:active, &:hover, &:focus {
|
||||||
|
color: $gold-star;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-icon-button {
|
||||||
|
color: $white;
|
||||||
|
&.active {
|
||||||
|
background: $ui-base-color;
|
||||||
|
color: $ui-primary-color;
|
||||||
|
}
|
||||||
|
&:focus, &:hover {
|
||||||
|
color: darken($ui-base-color, 3%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.status.status-direct {
|
||||||
|
background: darken($ui-base-alt, 5%);
|
||||||
|
.icon-button.disabled {
|
||||||
|
color: lighten($ui-base-lighter-color, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.account__header, .account-card {
|
||||||
|
& > div {
|
||||||
|
background: rgba(lighten($ui-base-color, 4%), 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.account__header__content {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detailed-status__display-name .display-name strong {
|
||||||
|
color: $ui-highlight-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button {
|
||||||
|
&, &:hover {
|
||||||
|
color:desaturate($ui-base-lighter-color, 20%);
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
&, &:hover {
|
||||||
|
color:$ui-base-lighter-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.account__section-headline a {
|
||||||
|
&.active {
|
||||||
|
color: $primary-text-color;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border-bottom-color: $ui-base-alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border-bottom-color: $ui-base-alt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.privacy-dropdown.active .privacy-dropdown__value.active .icon-button {
|
||||||
|
color: $ui-primary-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.privacy-dropdown__option {
|
||||||
|
color: $primary-text-color;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&.active {
|
||||||
|
color: $white;
|
||||||
|
|
||||||
|
.privacy-dropdown__option__content {
|
||||||
|
color: $white;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-picker-dropdown__menu {
|
||||||
|
.emoji-search-wrapper {
|
||||||
|
border-color: darken($ui-base-color, 10%);
|
||||||
|
}
|
||||||
|
.emoji-search {
|
||||||
|
background: darken($ui-base-color, 5%);
|
||||||
|
border-color: darken($ui-base-color, 10%);
|
||||||
|
}
|
||||||
|
.emoji-mart {
|
||||||
|
color: $ui-primary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-popout {
|
||||||
|
background: $ui-base-color;
|
||||||
|
color: $ui-primary-color;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
color: $ui-primary-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
em {
|
||||||
|
color: $ui-highlight-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.search__icon .fa.active {
|
||||||
|
opacity:1.0;
|
||||||
|
}
|
||||||
|
.search-results__hashtag {
|
||||||
|
color: darken($ui-primary-color, 10%);
|
||||||
|
&:hover {
|
||||||
|
color: lighten($ui-primary-color, 5%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.static-content {
|
||||||
|
/*color: $primary-text-color;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
#Getting-started {
|
||||||
|
background: $ui-primary-color;
|
||||||
|
border-bottom:0px;
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.getting-started {
|
||||||
|
p {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: darken($ui-base-lighter-color, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.getting-started__wrapper {
|
||||||
|
flex: 0 0.5 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.getting-started {
|
||||||
|
.column-link {
|
||||||
|
background: lighten($ui-primary-color, 5%);
|
||||||
|
color:$white;
|
||||||
|
&:hover {
|
||||||
|
background: lighten($ui-primary-color, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.column-link__badge {
|
||||||
|
background: saturate(darken($ui-primary-color, 5%), 5%);
|
||||||
|
}
|
||||||
|
.column-subheading {
|
||||||
|
background: darken($ui-primary-color, 5%);
|
||||||
|
color:$white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-spoiler,
|
||||||
|
.video-player__spoiler.active {
|
||||||
|
color: $white;
|
||||||
|
&:hover {
|
||||||
|
color: darken($white, 5%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
border-bottom: 1px solid $ui-secondary-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status__relative-time, .status__display-name {
|
||||||
|
color: darken($ui-base-color, 40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status__content {
|
||||||
|
.status__content__spoiler-link {
|
||||||
|
background: $ui-base-lighter-color;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: lighten($ui-base-lighter-color, 5%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.muted .status__content p {
|
||||||
|
color: $icon-button-inactive-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu__item {
|
||||||
|
& > a {
|
||||||
|
color: $primary-text-color;
|
||||||
|
&:hover, &:active, &:focus {
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown--active .dropdown__content {
|
||||||
|
& > ul {
|
||||||
|
background: $ui-base-color;
|
||||||
|
box-shadow: 0 0 5px rgba($base-shadow-color, 0.2);
|
||||||
|
& > li > a {
|
||||||
|
background: $ui-base-color;
|
||||||
|
color: $primary-text-color;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $ui-highlight-color;
|
||||||
|
color: $ui-base-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.boost-modal,
|
||||||
|
.confirmation-modal,
|
||||||
|
.report-modal,
|
||||||
|
.actions-modal,
|
||||||
|
.mute-modal
|
||||||
|
{
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
.boost-modal__action-bar,
|
||||||
|
.confirmation-modal__action-bar,
|
||||||
|
.mute-modal__action-bar,
|
||||||
|
.report-modal__action-bar,
|
||||||
|
.mute-modal__action-bar {
|
||||||
|
& > div {
|
||||||
|
color: $ui-primary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-modal
|
||||||
|
{
|
||||||
|
ul {
|
||||||
|
li:not(:empty) {
|
||||||
|
a {
|
||||||
|
color: $primary-text-color;
|
||||||
|
button {
|
||||||
|
|
||||||
|
}
|
||||||
|
&.active, &:hover, &:active, &:focus {
|
||||||
|
color: $white;
|
||||||
|
button {
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-toggle-track {
|
||||||
|
background-color: $icon-button-inactive-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-modal__comment .setting-text {
|
||||||
|
color: $primary-text-color;
|
||||||
|
border-bottom-color: lighten($ui-primary-color, 10%);
|
||||||
|
&:focus, &:active {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status.light {
|
||||||
|
.status__content {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
.display-name strong {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-indicator__content a {
|
||||||
|
color: lighten($ui-highlight-color, 30%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status__content
|
||||||
|
{
|
||||||
|
a {
|
||||||
|
color: $ui-highlight-color;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.fa {
|
||||||
|
color: darken($ui-base-color, 40%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.detailed-status__display-name {
|
||||||
|
color: $ui-base-lighter-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer .drawer__inner {
|
||||||
|
overflow: visible;
|
||||||
|
height:inherit;
|
||||||
|
background:$ui-base-alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search__icon .fa {
|
||||||
|
color: $ui-highlight-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer__pager {
|
||||||
|
overflow-y:auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer .drawer__header {
|
||||||
|
background: $ui-base-color;
|
||||||
|
border-radius:3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.onboarding-modal__page h1 {
|
||||||
|
background-color: darken($ui-primary-color, 5%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* forms.scss */
|
||||||
|
.block-button, .button, button {
|
||||||
|
background-color: $ui-primary-color;
|
||||||
|
color: $white;
|
||||||
|
|
||||||
|
&.button-alternative {
|
||||||
|
color: $ui-base-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.logo-button {
|
||||||
|
color: $white;
|
||||||
|
svg path:first-child {
|
||||||
|
fill: $white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.simple_form {
|
||||||
|
p.hint {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-button, .button, button {
|
||||||
|
background-color: $ui-primary-color;
|
||||||
|
color: $white;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: lighten($ui-primary-color, 5%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active,
|
||||||
|
&:focus {
|
||||||
|
background-color: darken($ui-primary-color, 5%);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* admin.scss */
|
||||||
|
|
||||||
|
.table > thead > tr > th {
|
||||||
|
border-bottom-color: $ui-secondary-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.simple_form h4 {
|
||||||
|
border-bottom: 1px solid $ui-highlight-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-wrapper {
|
||||||
|
.content {
|
||||||
|
h2, p.hint, h4, h6 {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.muted-hint {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
.logo {
|
||||||
|
-webkit-filter: invert(100%);
|
||||||
|
filter: invert(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
ul {
|
||||||
|
a {
|
||||||
|
&.selected {
|
||||||
|
background-color: $ui-primary-color;
|
||||||
|
color: $white;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: lighten($ui-primary-color, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
&.selected {
|
||||||
|
background-color: $ui-primary-color;
|
||||||
|
color: $white;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: lighten($ui-primary-color, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination .current {
|
||||||
|
color: $ui-primary-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-accounts__item > strong {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-wrapper .content {
|
||||||
|
& > p {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
border-color: $ui-highlight-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* accounts.scss */
|
||||||
|
.card {
|
||||||
|
.name {
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.counter {
|
||||||
|
.counter-number {
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stream_entries.scss */
|
||||||
|
.activity-stream {
|
||||||
|
.entry {
|
||||||
|
}
|
||||||
|
.status.light {
|
||||||
|
.display-name {
|
||||||
|
strong {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.status__content {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.detailed-status.light {
|
||||||
|
.detailed-status__display-name {
|
||||||
|
.display-name {
|
||||||
|
strong {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.status__content {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
.status-card,
|
||||||
|
.status-card__title,
|
||||||
|
.status-card__description {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* accounts.scss */
|
||||||
|
.card {
|
||||||
|
.name {
|
||||||
|
color: darken($ui-primary-color, 15%);
|
||||||
|
}
|
||||||
|
.counter {
|
||||||
|
.counter-number {
|
||||||
|
color: darken($ui-primary-color, 15%);
|
||||||
|
}
|
||||||
|
border-color: $ui-primary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-stream-tabs {
|
||||||
|
a {
|
||||||
|
color: lighten($ui-primary-color, 10%);
|
||||||
|
&.active {
|
||||||
|
color: darken($ui-primary-color, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* uncategorized */
|
||||||
|
|
||||||
|
@media screen and (min-width: 1300px) {
|
||||||
|
.column {
|
||||||
|
flex-grow: 1 !important;
|
||||||
|
max-width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer {
|
||||||
|
width: 17%;
|
||||||
|
max-width: 400px;
|
||||||
|
min-width: 330px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status time:after,
|
||||||
|
.detailed-status__datetime span:after {
|
||||||
|
font: normal normal normal 14px/1 FontAwesome;
|
||||||
|
content: "\00a0\00a0\f08e";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.column {
|
||||||
|
max-height:100vh;
|
||||||
|
& > .scrollable {
|
||||||
|
background-color: $ui-base-alt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-column-indicator, .error-column {
|
||||||
|
background-color: $ui-base-alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions .button.button-alternative {
|
||||||
|
background: $ui-highlight-color;
|
||||||
|
color: $white;
|
||||||
|
|
||||||
|
&:active,
|
||||||
|
&:focus,
|
||||||
|
&:hover {
|
||||||
|
background-color: lighten($ui-highlight-color, 4%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.public-layout .header {
|
||||||
|
background: $ui-highlight-color;
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.public-layout .public-account-header__tabs__name h1 {
|
||||||
|
color: $white;
|
||||||
|
small {
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.public-layout .header .brand:hover,
|
||||||
|
.public-layout .header .brand:focus,
|
||||||
|
.public-layout .header .brand:active {
|
||||||
|
background: lighten($ui-highlight-color, 5%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.public-layout .container:last-child {
|
||||||
|
background:$ui-highlight-color;
|
||||||
|
padding-left: 100px;
|
||||||
|
padding-right: 100px;
|
||||||
|
border-radius: 4px;
|
||||||
|
h4 {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-layout, .modal-layout__mastodon > * {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard__widgets a:not(.name-tag) {
|
||||||
|
color: $primary-text-color;
|
||||||
|
}
|
|
@ -0,0 +1,272 @@
|
||||||
|
$ui-base-color: #181818; // darkest
|
||||||
|
$ui-highlight-color: #1ea21e; // vibrant
|
||||||
|
$ui-secondary-color: #E4F2E4; // lightest
|
||||||
|
$ui-primary-color: #E4F2E4; // lighter
|
||||||
|
$ui-primary-color-alt: #a0b49c; // darker, for external pages
|
||||||
|
|
||||||
|
$about-page-text: lighten($ui-base-color, 50%);
|
||||||
|
|
||||||
|
@import 'cybre-base';
|
||||||
|
|
||||||
|
@keyframes floating {
|
||||||
|
from {
|
||||||
|
transform: translate(0, 0);
|
||||||
|
}
|
||||||
|
65% {
|
||||||
|
transform: translate(0, 4px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translate(0, -0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body, body.about-body {
|
||||||
|
background: $ui-base-color url('../images/background-cybre.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
body.about-body {
|
||||||
|
// basics.scss &.about-body
|
||||||
|
background: darken($ui-base-color, 8%) url('../images/background-cybre.png');
|
||||||
|
|
||||||
|
background-position-y: 200px;
|
||||||
|
background-position-x: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-body .mascot {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.muted {
|
||||||
|
.status__content p, .status__content a {
|
||||||
|
color: lighten($ui-base-color, 35%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status__display-name strong {
|
||||||
|
color: lighten($ui-base-color, 35%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.compose-form__buttons button.active:last-child {
|
||||||
|
color:$ui-secondary-color;
|
||||||
|
background-color: $ui-highlight-color;
|
||||||
|
border-radius:3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.screenshot-with-signup {
|
||||||
|
min-height:300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container.hero .closed-registrations-message .clock {
|
||||||
|
font-size: 150%;
|
||||||
|
margin: 1em auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column .static-content.getting-started {
|
||||||
|
background-image: url('../images/logo-cybre.png'), url('../images/background-cybre.png');
|
||||||
|
background-size:auto 50%, cover;
|
||||||
|
background-position: 50% 75%, center center;
|
||||||
|
background-repeat:no-repeat, no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.columns-area {
|
||||||
|
background: $ui-base-color url('../images/background-cybre.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions .button.button-alternative {
|
||||||
|
background: $ui-highlight-color;
|
||||||
|
color: $ui-primary-color;
|
||||||
|
|
||||||
|
&:active,
|
||||||
|
&:focus,
|
||||||
|
&:hover {
|
||||||
|
background-color: lighten($ui-highlight-color, 4%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 1280px) {
|
||||||
|
.landing-page .container.links {
|
||||||
|
top: -15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-page.alternative .header {
|
||||||
|
background-image:url('../images/header-cybre-colour.jpg');
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
background-size:contain;
|
||||||
|
height:45vh;
|
||||||
|
width: 100%;
|
||||||
|
position:absolute;
|
||||||
|
z-index: 1;
|
||||||
|
text-align:center;
|
||||||
|
|
||||||
|
display: unset!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-page.alternative .header img {
|
||||||
|
margin: auto;
|
||||||
|
max-height:45vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.landing-page.alternative .grid {
|
||||||
|
position: relative;
|
||||||
|
z-index:2;
|
||||||
|
margin-top:15vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-page.alternative .landing-page__hero img {
|
||||||
|
visibility: hidden;
|
||||||
|
max-height:170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-page.alternative .landing-page__forms {
|
||||||
|
height:auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-page.alternative .column-1 {
|
||||||
|
display:flex;
|
||||||
|
align-items:flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-page.alternative .column {
|
||||||
|
max-height:initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-page.alternative .row__mascot {
|
||||||
|
.floats {
|
||||||
|
position:absolute;
|
||||||
|
img {
|
||||||
|
width:100%;
|
||||||
|
height:100%;
|
||||||
|
}
|
||||||
|
transition: all 0.1s linear;
|
||||||
|
animation-name: floating;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
animation-direction: alternate;
|
||||||
|
animation-timing-function: ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.float-1 {
|
||||||
|
width:50px;
|
||||||
|
height:50px;
|
||||||
|
bottom:60px;
|
||||||
|
left:110px;
|
||||||
|
animation-duration: 3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.float-2 {
|
||||||
|
width:130px;
|
||||||
|
height:130px;
|
||||||
|
left:85px;
|
||||||
|
bottom: -60px;
|
||||||
|
animation-duration: 3.5s;
|
||||||
|
animation-delay: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.float-3 {
|
||||||
|
width:100px;
|
||||||
|
height:100px;
|
||||||
|
right: 50;
|
||||||
|
top: -10px;
|
||||||
|
animation-duration: 4s;
|
||||||
|
animation-delay: 0.5s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-stream {
|
||||||
|
.status.light {
|
||||||
|
.status__header .status__meta .status__relative-time {
|
||||||
|
color: $ui-primary-color-alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.display-name span {
|
||||||
|
color: $ui-primary-color-alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status__content {
|
||||||
|
a.status__content__spoiler-link {
|
||||||
|
background: $ui-primary-color-alt;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: lighten($ui-primary-color-alt, 8%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.detailed-status.light {
|
||||||
|
.detailed-status__display-name .display-name span {
|
||||||
|
color: $ui-primary-color-alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status__content a.status__content__spoiler-link {
|
||||||
|
background: $ui-primary-color-alt;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: lighten($ui-primary-color-alt, 8%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.detailed-status__meta {
|
||||||
|
color: $ui-primary-color-alt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-spoiler {
|
||||||
|
background: $ui-primary-color-alt;
|
||||||
|
&:hover {
|
||||||
|
background: darken($ui-primary-color-alt, 5%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pre-header {
|
||||||
|
color: $ui-primary-color-alt;
|
||||||
|
.status__display-name.muted strong {
|
||||||
|
color: $ui-primary-color-alt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.embed .activity-stream .entry .detailed-status.light .button.button-secondary.logo-button {
|
||||||
|
color: $ui-primary-color-alt;
|
||||||
|
svg {
|
||||||
|
path:first-child {
|
||||||
|
fill: $ui-primary-color-alt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:active,
|
||||||
|
&:focus,
|
||||||
|
&:hover {
|
||||||
|
svg path:first-child {
|
||||||
|
fill: lighten($ui-primary-color-alt, 4%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-mart-search {
|
||||||
|
background: $simple-background-color;
|
||||||
|
input {
|
||||||
|
color: $ui-primary-color-alt;
|
||||||
|
border: 1px solid $ui-primary-color-alt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-mart-anchor {
|
||||||
|
color: $ui-primary-color-alt;
|
||||||
|
&:hover {
|
||||||
|
color: darken($ui-primary-color-alt, 8%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-popout {
|
||||||
|
background: $ui-base-color;
|
||||||
|
color: $ui-primary-color;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
color: $ui-primary-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
em {
|
||||||
|
color: $ui-highlight-color;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
$doodleBg: #d9e1e8;
|
||||||
|
.doodle-modal {
|
||||||
|
@extend .boost-modal;
|
||||||
|
width: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doodle-modal__container {
|
||||||
|
background: $doodleBg;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 0; // remove weird gap under canvas
|
||||||
|
canvas {
|
||||||
|
border: 5px solid $doodleBg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.doodle-modal__action-bar {
|
||||||
|
@extend .boost-modal__action-bar;
|
||||||
|
|
||||||
|
.filler {
|
||||||
|
flex-grow: 1;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doodle-toolbar {
|
||||||
|
line-height: 1;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 0;
|
||||||
|
justify-content: space-around;
|
||||||
|
|
||||||
|
&.with-inputs {
|
||||||
|
label {
|
||||||
|
display: inline-block;
|
||||||
|
width: 70px;
|
||||||
|
text-align: right;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="number"],input[type="text"] {
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
span.val {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: left;
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.doodle-palette {
|
||||||
|
padding-right: 0 !important;
|
||||||
|
border: 1px solid black;
|
||||||
|
line-height: .2rem;
|
||||||
|
flex-grow: 0;
|
||||||
|
background: white;
|
||||||
|
|
||||||
|
button {
|
||||||
|
appearance: none;
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
margin: 0; padding: 0;
|
||||||
|
text-align: center;
|
||||||
|
color: black;
|
||||||
|
text-shadow: 0 0 1px white;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: inset 0 0 1px rgba(white, .5);
|
||||||
|
border: 1px solid black;
|
||||||
|
outline-offset:-1px;
|
||||||
|
|
||||||
|
&.foreground {
|
||||||
|
outline: 1px dashed white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.background {
|
||||||
|
outline: 1px dashed red;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.foreground.background {
|
||||||
|
outline: 1px dashed red;
|
||||||
|
border-color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.compose-form__buttons-separator {
|
||||||
|
border-left: 1px solid #c3c3c3;
|
||||||
|
margin: 0 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compose-form__upload-button-icon {
|
||||||
|
line-height: 27px;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
|
||||||
|
.detailed-status > .media-spoiler,
|
||||||
|
.status > .media-spoiler,
|
||||||
|
.status .video-player,
|
||||||
|
.media-gallery,
|
||||||
|
.status .status-card.interactive {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-left: -68px;
|
||||||
|
width: calc(100% + 80px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detailed-status > .media-spoiler,
|
||||||
|
.status > .media-spoiler,
|
||||||
|
.video-player {
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there's no status text, add an extra margin on top */
|
||||||
|
.status .status__info + .media-gallery,
|
||||||
|
.status .status__info + .media-spoiler,
|
||||||
|
.status .status__info + .video-player,
|
||||||
|
.status .status__info + .status-card {
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status__video-player-video {
|
||||||
|
transform: unset;
|
||||||
|
top: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detailed-status .media-gallery {
|
||||||
|
margin-left: -10px;
|
||||||
|
width: calc(100% + 22px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.public-layout .status {
|
||||||
|
.status__content {
|
||||||
|
min-height: 15px;
|
||||||
|
}
|
||||||
|
& > .media-spoiler,
|
||||||
|
.video-player,
|
||||||
|
.media-gallery,
|
||||||
|
.status-card {
|
||||||
|
margin-top: 20px;
|
||||||
|
width: calc(100% + 94px);
|
||||||
|
margin-left: -78px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,3 +41,34 @@
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin search-popout() {
|
||||||
|
background: $simple-background-color;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
padding-bottom: 14px;
|
||||||
|
margin-top: 10px;
|
||||||
|
color: $light-text-color;
|
||||||
|
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: $light-text-color;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
em {
|
||||||
|
font-weight: 500;
|
||||||
|
color: $inverted-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|