Compare commits

...

56 Commits

Author SHA1 Message Date
Henrique Dias
0a4c803650 chore: version 1.6.0
Former-commit-id: 9b5297726d87eb6617a8c99a1f8e23c9b4d7f1e2 [formerly e227cf02e128ba194fba68f9aca3ea61476e65f4] [formerly 4d23059dc7db2615079ea2364ea5db10663a27e5 [formerly 5f9d216542]]
Former-commit-id: 7676703b8cf5c681fd671a7fe457f4bcdeafcdc2 [formerly 13e2b075b1db00a8de95742ac1a377bdb8272585]
Former-commit-id: 64bfe1b140a3d98c1e6c77b1d225cfb7e5ed5055
2018-03-10 09:00:46 +00:00
Henrique Dias
68c5b8cd52 chore: remove failing arches
Former-commit-id: bca9d8ef1c447c295b564711e52271c233ee76aa [formerly a8b9b2c7706199b9e655f77f51193540af9dcdaa] [formerly e03e1f77be77d2f9ae853472c03197183e3d000e [formerly 4c197176fc]]
Former-commit-id: 0a904664f8bf4177eb1e573a3dbd2e71ffbd86b4 [formerly 74c0785f2cd7b5c92c910f9043b9ccc06433acbc]
Former-commit-id: 70a547ce5220e833f393a9c94b1d70c76fa708d1
2018-03-10 09:00:24 +00:00
Equim
0cff87be24 alternative ReCaptcha, close #366
Former-commit-id: c8c9baff75891868283bd353c83a19d38e6bc0e9 [formerly 88aeffc35a402c44c9c92a534c8cd271124826a7] [formerly 39cfd0e090894509e913100aa2f9b325ad6e5b68 [formerly 6e1c6a4a8c]]
Former-commit-id: a49c1046af3ba28c469e93e7d88013f5a6b1d062 [formerly 07c801b64ed03b187bb1dd9bbfb502b92572af44]
Former-commit-id: aa69ed3d4d78f8942b8b2c924c73c8e4c4965520
2018-02-27 17:12:54 +00:00
Equim
a2fcb8b3b0 feat: 6 bytes version of share link, close #331
Former-commit-id: a4a4edf89a32e9b8338474eb3322de69e12da83e [formerly 57124e6118adfbf0ae38ec77ce6816f6351174ad] [formerly 6d9e5b81bf0f52373147cb46d3c71d7e8e1362a7 [formerly f0a703baa7]]
Former-commit-id: 7da431b8bf791bdfe66fca2b0f87fc4b4918543b [formerly 4d02e3f0a697b912fb639b09857ae5daa0851ebf]
Former-commit-id: 87af8b945b414dad82d1c6769d6ec014e097aa22
2018-02-27 17:06:23 +00:00
Equim
5eb9e95720 chore: use dep to manage vendor (#364)
Former-commit-id: a5262bb5a3ca329e8d9d7f68bbcd932bcd4f5aa0 [formerly 38cda564a25a09a12a849a5ac756b55e895d8ac7] [formerly b70c0cf897f19e468259148fc75e9a60de5252ab [formerly a184b775b3]]
Former-commit-id: 1de8ed7a5b316b7a64cad814c0efc80b67a9668f [formerly 5ef584fce122832b7e9200e6a7c6259a2b0e3c09]
Former-commit-id: 7e11fda1d06bd57d16a03a17d7c3a644e46c451a
2018-02-25 08:55:48 +00:00
Henrique Dias
967d4e28de chore: setting untracked version [ci skip]
Former-commit-id: 093104cb4d68178bf5de22289d58c465fca10552 [formerly 17499e5eec1c3c54f9e1c699818ea823be3d6728] [formerly 0e561b7ea77348ba12e29173607062c6badccc88 [formerly 4bd2e8e333]]
Former-commit-id: 992c37c538e5aa2aec9b6504cf836f2dd6aea2c9 [formerly cf3727500421de16876ddc84462d48b5600e1946]
Former-commit-id: af2ab326c2092bc169a44622e56b10000d6091dc
2018-02-24 08:45:44 +00:00
Henrique Dias
ee53803fc2 chore: version 1.5.5
Former-commit-id: cee33f264a3b98f9e635203f38793a5b4147792f [formerly 0619dbb1ca27fb4b3f030a77c2a1eae4233f3c87] [formerly eb56b144bfc0ec579fac4abd31aae495f3ba3498 [formerly 04096b6d1e]]
Former-commit-id: 4630f7870de9502b05b9bfd84c0feb022220b20b [formerly 029af42ac358788458facfba9236265e78bf681a]
Former-commit-id: b4471eb6375f7a46fe7344f6e301ea88722d389e
2018-02-24 08:45:16 +00:00
Henrique Dias
fa2ab280aa chore: bump frontend version
Former-commit-id: a381a7cf11629dc1fd8c847299f90b931accf2c6 [formerly 8da5f9853d69fb4a77a9d563be75408a1c0abf26] [formerly d7eaec9372fea8b12154755ccfb5a527e7d4a105 [formerly b0e3ec25ba]]
Former-commit-id: d745e4d51195a9d054bec17809f6a2c4da296c94 [formerly 03513fff5e0c16d3a2d694e5e2a76465157b1bb1]
Former-commit-id: c94620ff90019ee0e725fd1fa16017368a8d9715
2018-02-24 08:44:31 +00:00
Henrique Dias
395801016b chore: setting untracked version [ci skip]
Former-commit-id: f35ba7ce165f0d16b5943a26f713cfdd701d1ea1 [formerly 6a439c90d9c04a9d7c946444f1177b328f2b4735] [formerly 85ae45844946d0f4575b5fb1929fecb9a9a56b1b [formerly 52803ddb26]]
Former-commit-id: 1678fc7a028b881e4e7c7a721adaf51120877b04 [formerly c5a6dcf31959b2444d38a93705edb7ade958122d]
Former-commit-id: 73bd93eac053a1857d034f30af66a3f1fee3bd36
2018-02-18 12:27:49 +00:00
Henrique Dias
30ed82a70f chore: version 1.5.4
Former-commit-id: 1ad07843678a00d0f24d490dbdbbe5c211782c91 [formerly f0328a485087490f0f6fb1bdb8751ce0377edb63] [formerly 381a1863aa910ba03b89b47769b575f6dc2869d6 [formerly 83af6f2720]]
Former-commit-id: 8bdb8c1913820d84a3b504a7d55c98cd675baa58 [formerly 6b84fde09c4e03b8d9504d9786ae953e69d83402]
Former-commit-id: 9ddd4867df78fcbf7cd8302ab408fef3cdbf8906
2018-02-18 12:27:38 +00:00
Henrique Dias
ab643cd0c4 fix: not being able to change settings (#359)
Former-commit-id: 6230e0e979ca561a778be5f1aa245e85adb808e9 [formerly a14bfa497f716aa95a6b24d04e09361f06ff0b31] [formerly 008421161a7563ce29631cd103eef34597dd211a [formerly 7e962180b2]]
Former-commit-id: 3ac8515e4d0d2fff862af27ef14b23a8a66226a6 [formerly 83798c187f0df689f85f4118140661f04c051d60]
Former-commit-id: 1edf72e1db7824b1a64fbd97889835d20d9af500
2018-02-18 12:26:07 +00:00
Henrique Dias
85e5beaa4a chore: setting untracked version [ci skip]
Former-commit-id: c61d0cbd94e07432d75926fdc2c23dc365674351 [formerly f48aae15e3a532a9988b63be960185fd839db46d] [formerly 7807dcf654b3a05c2743b63fbd63d3a42e4381fc [formerly d117e4d005]]
Former-commit-id: a8fcba07f677764ee58f5bde4f10cb7dddf18bef [formerly aba5eff7c0ea571e728322e33070a977323f194c]
Former-commit-id: 3eb36b35a1672e254b046131309556ee22b1845d
2018-02-18 10:03:45 +00:00
Henrique Dias
3cab34c68b chore: version 1.5.3
Former-commit-id: fdf8f683da6bfb0c9c5f653f89969ed28a5fac86 [formerly ba0afcdbb13ea6040a77397d9b5cc1844b04d3df] [formerly c5625bc490f452970645719cec512f62796da98e [formerly 13030c7ace]]
Former-commit-id: d3fd31bf729a46295c53b3bbd9f7d2c09ce1ed13 [formerly 8278bc090fd8b99ef07b3d376d1243f14c8aa7aa]
Former-commit-id: ca391495213b2523fbde1c2aef1ee7a7818715e2
2018-02-18 10:03:34 +00:00
Henrique Dias
8299f8ed06 chore: go 1.10 and fix linters
Former-commit-id: 289bceb9a90eb2422a69010863e7f2691eae357f [formerly b0cbba626a1185f95c6ce98d453cce99ee208e97] [formerly 90388476afb899550d56c82f836203e3d7942df6 [formerly 5c188d9dd4]]
Former-commit-id: a318b0f544706102d05a1f6faaeb2bbbd11ede29 [formerly 05b5bf7216959990c8cdccebae5fd91769aa9596]
Former-commit-id: af8ef1c7dc5926a9f6912249b2c0a334452c239b
2018-02-18 09:59:49 +00:00
Henrique Dias
da05c5048e fix: bypass errors on symbolic links
Former-commit-id: 20cd8429be62bbe7c4f2ee48f7dddc2f389d5117 [formerly f857fe8d323a25e00e193f959aac605d742d7f15] [formerly 2c4ef521c756b902b7914a42958c163db85c2cc3 [formerly df453ca634]]
Former-commit-id: a638071b19674d82400639a142cb32085c20d1d9 [formerly aaabe20901f149ec00f4eea1ac730a6cf9f30856]
Former-commit-id: 43a13d56401f6b18fee8cff4806f960cd5683314
2018-02-18 09:49:40 +00:00
Henrique Dias
071e1ec19b chore: setting untracked version [ci skip]
Former-commit-id: d3e7532c6a00a899c1447cca4cd995e1f8feab73 [formerly 4d445abd785ae0adb8c8d0d748efbffa4ac2d001] [formerly 098e184c167f80cf3780e043ce941b3b36ddb41e [formerly 22327703fd]]
Former-commit-id: 84da73349f055e544276fafd9d3b4663ebe4e7d9 [formerly 28a71db5fb466aedb66045068a20647f192d12ad]
Former-commit-id: dbdc0c0a3953dbdd941cd3310bedbfc3d957362a
2018-02-04 00:40:16 +01:00
Henrique Dias
8884e68806 chore: version 1.5.2
Former-commit-id: 590181d208cd1a1addabbffa5c860afe234fbc60 [formerly d04974b17bc5cb290eca029c8e99af7d8a8555e8] [formerly a138ec0dba4609b2093dea1091ec8a4141504ae9 [formerly 60026f943b]]
Former-commit-id: 09ecb88b44745c160aa1db5262d299ce249b95bc [formerly 8458b1c621fa766998da3a886ac990495cf771ae]
Former-commit-id: 0a0bb60c235a1a2a8b98282d9e63ca5defb7d90f
2018-02-04 00:40:06 +01:00
Henrique Dias
68bfbe5103 feat: readd caddy to this repo
Former-commit-id: cf48e35cd8c5ceff57d1353c75ffacd1de96e9ad [formerly d62bc138c736881547184977110cd622f2d31847] [formerly 4270b9fb5c907097ce6babffcedafccb5a8b6356 [formerly 385cfba0ff]]
Former-commit-id: 04e6142a81d677781664c9a79e960465fadd3eb4 [formerly 2152b2410fb078914c788bf7f15ca8028af54c58]
Former-commit-id: e88a3fce1b9d16421ce9c1aa9c63c90705878bd2
2018-02-04 00:38:07 +01:00
Henrique Dias
4a7bdfc59b chore: setting untracked version [ci skip]
Former-commit-id: bf80464d9d029dbe2ad94e6a0578767051edcd0e [formerly 338f2cc8d8e86b6666d692fa1497da3acf0bd5f7] [formerly 2ed27b9f856328760b427bc0ad19eb62a04aabc0 [formerly 05cca04f2e]]
Former-commit-id: a7f4dd93d50011d538a206f6d5e317407c33f8bf [formerly 2386141b2825821c379d15bb183fddad6eb80b4d]
Former-commit-id: 5014565536c407489923ec844f0818b9f671d2f4
2018-02-03 00:15:05 +01:00
Henrique Dias
b54a5cda59 chore: version 1.5.1
Former-commit-id: 8b5c4c9bb6373d53f0e8aee54b338c717e53a8bb [formerly 67714d7f475bbfddf77427860f038cec27764eaf] [formerly 3d1eb5103718e6519089467f9e0e3daa0f40479b [formerly ce06238423]]
Former-commit-id: 3e2400fd4b834a53fe6ecd8392d0f23a40bf45ed [formerly f15d2d67c065605ca52cf4fe32a644fe5b1c3553]
Former-commit-id: 11c1a8703cbac67cb5b4aed103e81e3db99e5851
2018-02-03 00:14:53 +01:00
Henrique Dias
418ce4fa15 feat: add german translation
Former-commit-id: 5021b155e5e191373a738f209450e968faab5014 [formerly 1f22f637a5d4d33fbed4519ca07881a407e629c1] [formerly a4de3ae977d9bbf7562544d6b31e795877fba167 [formerly 7392c9637e]]
Former-commit-id: 058499b5e728c54e8d2530093e824fb06e969206 [formerly 2d351f9a003955c7b7ed9986a7cf8ecce099a755]
Former-commit-id: ea6d9c2dbc2d2b230977ac06a9ad1a947c3f9b3e
2018-02-03 00:14:31 +01:00
Henrique Dias
6e27059f25 chore: setting untracked version [ci skip]
Former-commit-id: dbd4a231305b18e0c44ed6bfe2579ce57daa86d3 [formerly 7b516acecac4a5115aeeea00069568d7a4258a73] [formerly 629208fd6a67debd2ce9914b4607a5c92cd4a278 [formerly 8bf8bc3a15]]
Former-commit-id: d7556c9c4943edf716afec49b87ef789e7544d8f [formerly 9cc4bf24fc00ff27f97ba391e4faf2fef341de3f]
Former-commit-id: 01c3a4ad98ec88352dd20fb7c371920d71668075
2018-02-01 16:19:18 +00:00
Henrique Dias
7dacc97e7b chore: version 1.5.0
Former-commit-id: 3bb87b07b493a17a5b06d189bf2b0081b1dd26c4 [formerly 89933c61a34d1b9c63204436e3b3a055c184d073] [formerly fe2b8550a40ab568af209454c9385a6c171fb607 [formerly bbb47d0bea]]
Former-commit-id: ed555f48c83a847f2972feb0bfc487c4f4647570 [formerly 81d38795a9f4b657ed150007f0aade3da04ae8f5]
Former-commit-id: 92aeac43ccfc83eee946217c8824636015432878
2018-02-01 16:19:05 +00:00
Henrique Dias
a89701b746 chore: add circle ci and use external assets
Former-commit-id: a474183e1779f03ebbf0feacb6c657a7c3f32fb1 [formerly c2c77a210a1a121f6d3ba5331093a8a0b5ed9f1e] [formerly 8cc259f949bcab23ea5bb402c2f551428fa7f22b [formerly 040455b4ac]]
Former-commit-id: e05cf0627cde1ae2266c06851590573e5bdecc6e [formerly 458fc2c269daa31cc18a4132a4c801f748a610af]
Former-commit-id: 946b8ed702254d3c11f1b791c790af606f2a68f4
2018-02-01 16:18:44 +00:00
Henrique Dias
7b58b1fbf6 refactor: moving repository
* refactor

* updates

* add circle

* update circle

* fix circle


Former-commit-id: bdc8ecd8766e35f9ab7a9e8bd9dd62206bffb37b [formerly 0d28166061f5c8e573e916797abef67e33a83cf2] [formerly efd85c08040565ba75e06b3d7d7b16366d36325a [formerly 613a3f2811]]
Former-commit-id: eca6ad66d686a6737d81dca5e00f1d46a75a217a [formerly a987246f7c0940e8812cb4d0c1b0514b708e8c44]
Former-commit-id: fd882cf0d2216dcfb035a703011eeb1a2f79da9f
2018-02-01 13:38:43 +00:00
Equim
4d93ec940c http: download: use PathEscape instead of QueryEscape (#340)
Former-commit-id: a85344dc54e40ff15cbd6d2a917df7d273a386ce [formerly 323a8d5bac3f44f7bda8e52bcaac16e9dc272fbe] [formerly a0960ca476d5840dbd25a8bbc600d21e7f3624f2 [formerly d97f17facb]]
Former-commit-id: fc84005e5d05d27829fdabd0b28a681969ed8942 [formerly a11d653f0ee1b370f6248ec4d671f3f200afc898]
Former-commit-id: 5c0d556c93fc37b8cafff8b01b09fa9572cc13ea
2018-01-23 08:28:08 +00:00
Henrique Dias
efac18bfef chore: setting untracked version [ci skip]
Former-commit-id: 08af2d65b6fd1d9fa6320f91f6cb2a53fa9c8776 [formerly 08212a5a691129b55478ad0f313217ad5373a15a] [formerly 0a949b0c99e245693aea091117549d999ce04b42 [formerly e171f7ac12]]
Former-commit-id: 163b87eedcebe4305dcaff878e5c3f990cc9e73d [formerly 583b87fd5df07143f6758bb2a7db8c6ed51c3485]
Former-commit-id: 4946b9e1b7889e090a75369a8693c7700cd0a1ab
2018-01-22 08:52:30 +00:00
Henrique Dias
7330997281 chore: version 1.4.6
Former-commit-id: 0e8638a2e0a27e9ef097eb634e3998e5dad64ebb [formerly b322f42236da92471bcd43dcefe54b0d64b9791a] [formerly bec8a75ad3e69c7d349099b7c6d926e3c704c642 [formerly 9cd462502a]]
Former-commit-id: 0ebf3bc0d6d3fd5d3e3fc876ab404b47ebbc6bf1 [formerly 1edceb43775dd729beabedabe44c9516811f4d44]
Former-commit-id: ab52b3a238c41709bea8165b0b2bd72da0b29322
2018-01-22 08:52:19 +00:00
Henrique Dias
0787522d7c chore: setting untracked version [ci skip]
Former-commit-id: be1de8b5ac1887c021b03467f49840377558c8af [formerly 2fd31a54ae462d951f6c1bb481c4ea08d588b552] [formerly 5cc7edf5823b540a486d7702c24bc6ba00c8694b [formerly 31b464e9c3]]
Former-commit-id: 0d7af8186f4957ab26a0be82ef7f1a4ae9632e3e [formerly 16a582826f79caa95807a160c2dd5ef2fa783c5c]
Former-commit-id: 1ccc51414cc6a787b1e330e68127b192e0168c05
2018-01-22 08:40:25 +00:00
Henrique Dias
46df72ac0e chore: version v1.4.6
Former-commit-id: fb9d41965a36f9be671b5a5166815fa361c92ce2 [formerly 58cc394693cb65256dc0e56f96ebc1eb86181e3c] [formerly bb622a876fb325725188139dead3758213af32d5 [formerly 5650610bb3]]
Former-commit-id: 2a292b4ee3ccc1fe54e244fd05a8e47f1b92d9cf [formerly e07f41821c62119a32a76f613eba7d6dda36ec2b]
Former-commit-id: 6b8543b02c91c3449dba8847b72086abd16397c3
2018-01-22 08:40:14 +00:00
Equim
6839c15a7b fix: recaptcha fixes, auth fixes and line endings
* http: auth: remove unnecessary fields in recaptcha validation

* http: render: never expose ReCaptchaSecret to public

* build: dos2unix build.sh


Former-commit-id: 21908028289e4a5d30b5a2c1961abf163b1a93b6 [formerly b634e3e4da4a616119f6bc15ae92f15073f019fa] [formerly 55efca9d070539f346215090517abde1ec788be4 [formerly 9b8c2862e2]]
Former-commit-id: 70df1f0443977f6f2b101b946698dc3466aa6db9 [formerly 15195d4c28060aa1eca8f03ad0b77576ac8d9181]
Former-commit-id: e22d026e74a0cc800ad7281c35e4157037849e37
2018-01-22 08:35:39 +00:00
Equim
d50dc90a54 frontend: share: fix #335 (#337)
Former-commit-id: 116629d99a0512b82772468331e829e2486af3d9 [formerly 71a073a0d7ee1e27b8a79afbb08b4387e94ec53c] [formerly 40fa722b1bee8aeee021455c20ea10788d87a739 [formerly 93566aceef]]
Former-commit-id: 4027d444c5d9b9915fa97e4b82711dfa5499f080 [formerly 1adda5ac2fcf49a27042541ae8fb0b1f3d820ddf]
Former-commit-id: 0504804487188a7bc9330e19ad1350a45fa6e5b9
2018-01-21 19:47:35 +00:00
Equim
4039efe4b2 fix: http wrong header (#333)
Former-commit-id: 6d65d8aac2314998c01c4a04e05395e1a2553045 [formerly 1ec8cd98f322298f5c5da4747f05189bc2f2ddf9] [formerly ea74b49f932daa9836df7cdf51b8e9cd6d043175 [formerly 53240ef9dd]]
Former-commit-id: 2cbd9e68f132a1170261b4b9549a2cb79b0059d8 [formerly c47d9063e48e8fcf77ece4ab75a10b588a8ecafa]
Former-commit-id: 203b0a61ef2045c62f3ccd94f62625f0e19435e4
2018-01-18 15:36:45 +00:00
Henrique Dias
2ab1ea44ff chore: setting untracked version [ci skip]
Former-commit-id: 1243e66e54147d73108374296220395f90c7aa92 [formerly e538d9176df83d4dc3b9b32d826489b89f1341e6] [formerly 6a72ab507b84de0adad11ba67831595eb90113ad [formerly 8fb3798c12]]
Former-commit-id: 1e142e2483cf4ef98b6ebfd048b2aff97b19c270 [formerly cd851d42b067f2ebb0f59124686c8a3d6eedc260]
Former-commit-id: e8426e1fc13beed881962cd62dc23f123e7a5ecb
2018-01-14 10:28:14 +00:00
Henrique Dias
23a2c60d9f chore: version 1.4.5
Former-commit-id: c1c687c85477814782ac1c37f1153222cbd66aac [formerly 62f611d73f4a94b1a8c38be469edbe4b9f15b128] [formerly b18279cba8d103941a0c999e212fba4b4c36d1f1 [formerly e1836e2274]]
Former-commit-id: e735874c31bd3f07fefcc528e63e83520b1ccf8a [formerly 121a4fd4096b00d3a03df57bb6872f02cca94a47]
Former-commit-id: 79f9ba3aff8aab04125277fc8298aaf3416d3648
2018-01-14 10:28:02 +00:00
Equim
54e66bbc05 http: download: improvement for range support and I/O (#330)
* http: download: adopt http.ServeContent

* http: download: deprecate unnecessary temp dir

* http: download: adopt http.ServeContent in inline mode


Former-commit-id: 9ad519b51bcd7bebd862ccb65153bf418aaccc24 [formerly 6c2ac9b647a5cd5a67b7f688502e185a6180a34d] [formerly fd8dab4db58c098dcd5fca47226a50fa99a52aeb [formerly 30efa23a85]]
Former-commit-id: 54cd985769d20c02f890ffaa64ed02153b9fcff9 [formerly 7f0bf159ebf192055fa2bc346a0545d0b3007721]
Former-commit-id: 58e72dbdd1dc8ae43f4d769632d892ace0a19400
2018-01-14 08:41:01 +00:00
Equim
69b262f91a fix(i18n): zh: minor fix (#329)
Former-commit-id: f923123d02d6aa875bc5c3a0171920df625b1787 [formerly 494e0f97f54b823fb14ed5b4ac028942dbf0077c] [formerly 933be3dd0a5b167e822d73a4877c1ebfb55ae4c0 [formerly 94648c92a2]]
Former-commit-id: e01ef36d8dbcee0ce16ea190b2d9afe6a9751c20 [formerly 59ca3451e6b26e9ad2811ba7c352778e8acec1ec]
Former-commit-id: 799fda14369c565d68c62133b7cd62ea7f1e75e9
2018-01-13 09:49:47 +00:00
Henrique Dias
731cc45e05 Update README.md
Former-commit-id: 3c5dc2c840b4ea82d2b88503b89515d8d6e1b590 [formerly aa5a9564be7917bc2bca82870eb61ccc2cc75347] [formerly f8f01920e7b54e52b012f469d917fb6f7e94d94a [formerly 300b55f2c7]]
Former-commit-id: daae1ff5c473b6fa583e270538830a046831eb2c [formerly 73ef7dac5d799cb3e321ba1b4969b125aa71c52b]
Former-commit-id: 715ce711701440e20da9512272fcd31922435323
2018-01-09 07:30:42 +00:00
Henrique Dias
a3960ff9a3 chore: setting untracked version [ci skip]
Former-commit-id: 9301c7f3b4a71d6ce1e41e48bb8b61a0f4878f44 [formerly 6e69aa23419cd7e42e474c7db9f1cb6dbe5955d9] [formerly 19b578c58faf698f3bfceaeae33cc085801b5d9d [formerly f2ac4dd262]]
Former-commit-id: ca520cd8264c71fb6cf0f0bfd88c065d8c55c08e [formerly 83d060fa29de8b601f40acac64857044f352a141]
Former-commit-id: 38ac4f4fc95e531027b5daa737987bfecccbd244
2018-01-07 12:40:42 +00:00
Henrique Dias
5f986901e9 chore: version 1.4.4
Former-commit-id: 0ab1627b929b5c4be5ebb66b97d7f81fcb480395 [formerly 6a569e0973cb86401d95dcc9285ae81b2b9b49ad] [formerly 571700b6bc7ddc08738f3f887a5cf9dfe127cbda [formerly 93b823e6d1]]
Former-commit-id: a875a5b56484e0d392ddf7a8c60cf022bb46099f [formerly 19a767e19ff83ff34a36b3845d6b8e91063c7167]
Former-commit-id: 4c98b119b38be29e52fc502d635a05491ea9e9a4
2018-01-07 12:40:28 +00:00
Henrique Dias
0b4d8df22d chore: update dependencies
Former-commit-id: 0e9c3b0caff7d2297e06985cf7361607e0e9205c [formerly 397e6c26097c550d8ca74e554237502964b337a2] [formerly 1fe8a4d39b94285a8c5ffb089f6388a38aacb12a [formerly f29e210e6b]]
Former-commit-id: 352a198a53b3589f40ca83148e64149a67f7c2a3 [formerly 93bf553394ea1d30190412fe77db0d456146d177]
Former-commit-id: c07af559899e9d0851ab4ac2573b57bbd8efaddd
2018-01-07 08:20:58 +00:00
Henrique Dias
9619b4ee1d update example
Former-commit-id: 41adc5e8fc05d20caa0d293224c3b987b3d18a9f [formerly 531a461aff8e332598842e2d98355f77ea8caa7c] [formerly 3f84ed6e4bbe7d14e2a1f6221edcb069b2b95dea [formerly b9a0ac4459]]
Former-commit-id: 1eece7e6b527ea1daaba2424399a76e1c702bb43 [formerly dc079172134ddafd696c910f440f4597be1983af]
Former-commit-id: ddb46ff3aae922ecb4818862cad0b8920d6899d0
2018-01-07 08:06:55 +00:00
Henrique Dias
c75f3e0f59 chore: update build and publish scripts
[ci skip]

Former-commit-id: 68fc4cab3e092dbf192f02a7b69cd1024be6095e [formerly af8599c8c136f466f33b3060c1aa0568054617fc] [formerly fcce660652925df3b7837a503114380f6eab269e [formerly 32106b537d]]
Former-commit-id: 42514c2f46abf0ec4533ed44edb2ed16ff1220da [formerly 0bf28005af9a16de599a99d7c0fc543b5208729f]
Former-commit-id: 2f1b4cbd7bce86943ceca8a3f0834a1ac81edb45
2018-01-05 10:15:26 +00:00
Henrique Dias
6d71ab08ce [ci skip] auto: setting untracked version
Former-commit-id: 2fed0803c7febc91e7b5bb3d33d85b7ff560d5d7 [formerly b7153111a10d7bb8374469aa4504b7b63c4f9999] [formerly acd233135fd878ba16bcf73bda9b4358f9a7473e [formerly 1218966226]]
Former-commit-id: e0a33076851b5927794180e4b5bfd1483d51ebfe [formerly e150034ec51997ec1ce075ea28e51a79b60c54d4]
Former-commit-id: 9a52d3ec859ed128606ae01d2bcf6a9ef08cb2b3
2018-01-05 10:10:49 +00:00
Henrique Dias
121c695c1a Version 1.4.3
Former-commit-id: 105f6e3a206963eb810ed178f5a3d05e4c05693f [formerly 95a0eef30242460e822aef2f93ec770f6d82702d] [formerly bb726ba819c7f01330db8dc7503b2f869ace40c0 [formerly 74f6ea6897]]
Former-commit-id: 9db1edc8d09521068b70bc7b81e5d2586ef949a8 [formerly e9e78572d9b296f160b5c311e57822a0e960d35a]
Former-commit-id: 4513e831114a23e30822734d62191a7a49d50555
2018-01-05 10:10:40 +00:00
Henrique Dias
6a1f9bbf69 [ci skip] auto: setting untracked version
Former-commit-id: 500c3e1726327fca7ca8421d70f46eebe76702bf [formerly 09a3811e6a1b87b159fe6ab562f968aef1eeef20] [formerly e85343d82a8de4c9b93f1d5e65e8654e85b67f5b [formerly 13c12b9130]]
Former-commit-id: 26e2c13658759ee83e6d2ec7d851a1cfc2b485c7 [formerly 4eb961b41d768ff23b4d00163f4c0e9512829fbd]
Former-commit-id: d6a362c2611bf9ef6267be25a08e47a8d7f58b1e
2018-01-05 10:02:58 +00:00
Henrique Dias
ab54bc3c57 Version 1.4.3
Former-commit-id: f47b39a9b2817c603578b2623919403e30d3af22 [formerly a8b23dd12fba701c0cbe91049f263318d33a8be9] [formerly 7de9b5f8f6d1c6a962b89c540625b68cd4cbac0a [formerly ac3f1482c6]]
Former-commit-id: 56c305fb8ea1a017daf051ce8f630c2ffddebb7b [formerly bcd1d113a852499dee8701bd64e49df8513f8538]
Former-commit-id: 95ca9218c8b98432f9c5e0019fe619c0dd417e34
2018-01-05 10:02:49 +00:00
Henrique Dias
8a10baa815 Update .goreleaser.yml
Former-commit-id: dce13b52b52d980f11ef90f08b229c99ef74548c [formerly 45b6e868899a14fad61e61b5603da5dbdf1704fc] [formerly 90aabc167231a2d164afee7ab966a465146afe63 [formerly d8f057757e]]
Former-commit-id: 43bae9e293b2e3cf0b8608c344dadff88de47380 [formerly beff2d7f954169e917950549a353f5efa033f906]
Former-commit-id: e77e853b8e818863bff7164b169b411eaa6732fe
2018-01-04 14:04:09 +00:00
Henrique Dias
98c22ece8d [ci skip] auto: setting untracked version
Former-commit-id: 8ddd21218dd4fb6e00cf083a80199d2a4339af2f [formerly 3406ebe12f6112ed751092e5f831c77ce459c6e0] [formerly 143f9d23f5fa5e5545fd63e6f44ae9228e6c093c [formerly 5bd60ce05a]]
Former-commit-id: d7362d24d7d872cb722d462fab45d2a48b37b1d5 [formerly c7c1cfd6d43642315e9a7956211ede7eb0a6b5e3]
Former-commit-id: c42269de8c2b7ecbdacaca0cf383c8a29dfd239b
2018-01-04 13:50:31 +00:00
Henrique Dias
63247f6e8c Version 1.4.2
Former-commit-id: 488d6575d81275f6c5e1c04280a5def6aa700117 [formerly fb198ae1767fc52ed8492657f33f5bd91d4d4283] [formerly b100a438db05a237c2e7a081fbdaed3a5ed6ebae [formerly e7b372f548]]
Former-commit-id: 3c418fc25a996e829e35be8f49eec0c43bf1829d [formerly 6568a1dd89e6a5640a2ad9fde224303813f219d0]
Former-commit-id: a1355be166395d2bc0d0a4a5a7170b36c73df094
2018-01-04 13:50:19 +00:00
Henrique Dias
58dd812008 fix #269
Former-commit-id: a0b8ed91061292e0f155cee9a7865609daacf836 [formerly e6bb9eaa82b5704f3fe29bdec50f6bb4f55304b2] [formerly b443cbf5c6d7946ff3cfa44493449b5f0d75d830 [formerly 02df167434]]
Former-commit-id: c193caff6faaf78a16375960893be9e253869d3c [formerly 6c84d234c9e1db432027bc159dbeeb77e9c35031]
Former-commit-id: a48c3851511472efc47bce07ee2509fdd8a44c4a
2018-01-04 13:49:41 +00:00
Henrique Dias
1575fafec8 [ci skip] auto: setting untracked version
Former-commit-id: c497913d120be4a71f7d2305600e2785190f0e2b [formerly 0126f289afd78bc006e5e0fe383670dbc9df4fd4] [formerly 12899a40ac7b8a94c3930dcdb3101d121c56cbc2 [formerly 9da06a7010]]
Former-commit-id: 866590120ccd5ddc189d36e352c637cabc82f81f [formerly af0b154bf6db52c01e9d0b10f3d6678319727bca]
Former-commit-id: ff3c428b12cc8028b21d8585a9927e826ebdf4cb
2018-01-04 12:41:34 +00:00
Henrique Dias
8c935eb51d Version 1.4.1
Former-commit-id: 77ee0108106777f2de0719eb6ea50bcad12f8635 [formerly 4dc3acf5b7eaaa687ccfced7fc463e2b7e7104ea] [formerly 3ec2bd1fe0b8e364621204b9aa1732cbc7828199 [formerly 44d6730073]]
Former-commit-id: efd15158f953966190c8a8e9310801a89049ea4e [formerly 56a49a89f919d70486b6db126e84e5997bd6d261]
Former-commit-id: 969b87ac24214cb7dfc9429253724c68aa0d46bc
2018-01-04 12:41:23 +00:00
Henrique Dias
7f3a26e1c0 fix: error when user have no commands; close #293
Former-commit-id: 9e1ebf686f12d76a202bf8a3b0b16f14f8eb713d [formerly bfc761cc181d6d8880fd86396e69bf5894806f6c] [formerly 774e09b49a2dff07becff48bf048b3b0bd8353ed [formerly 65d3c0fb9b]]
Former-commit-id: 8ab97c0103cde1a9bcf69c1e9af994241fb9d124 [formerly a25dc7feb0755122c7329e3a3bfa61f74418467b]
Former-commit-id: 92e21139ffe04ab23406352e0a5b6131e8cad084
2018-01-04 12:40:45 +00:00
Henrique Dias
fe834aa244 remove file
Former-commit-id: 95f665f00dc03c130afb5fc45e8076a869c30222 [formerly acae04da4a0d58e689b704ff405a749c4fa43c05] [formerly 482666a8335cc216fa706d5175c8a75cbdb073df [formerly 0781b961da]]
Former-commit-id: 57a2f201668aad631fead876207b2d5620e202dc [formerly 9f1344480aa6589652ce34dff2496dc36b9d631c]
Former-commit-id: 2760b12b251f53c4421b80d5d5122520eb92cf40
2017-12-29 17:31:21 +00:00
Henrique Dias
6620a1bf41 [ci skip] auto: setting untracked version
Former-commit-id: 0b2303648bf1c82d04b20f439a76d2ce37cfbc4c [formerly 8aedb0827d0538efa6ec0d88082e3df2e85b6e46] [formerly 91dc35e45674e83e44ecb66e7da2bb1d7634efb4 [formerly d431f5f0e4]]
Former-commit-id: 551cf4271e33f7893ecbd7290074d0d031827a94 [formerly 034d533f73603df46d2c7efccaddd17bb0f37814]
Former-commit-id: 1cf3cbcb484e5128ac9564516992f5fbdaddfc28
2017-12-29 16:46:22 +00:00
161 changed files with 1021 additions and 9833 deletions

View File

@@ -1,13 +0,0 @@
{
"presets": [
["env", { "modules": false }],
"stage-2"
],
"plugins": ["transform-runtime"],
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": [ "istanbul" ]
}
}
}

83
.circleci/config.yml Normal file
View File

@@ -0,0 +1,83 @@
version: 2
jobs:
linting:
docker:
- image: circleci/golang:1.10
working_directory: /go/src/github.com/filebrowser/filebrowser
steps:
- checkout
- run:
name: Install Dependencies
command: |
curl -sL -o $GOPATH/bin/dep https://github.com/golang/dep/releases/download/v0.4.1/dep-linux-amd64
chmod +x $GOPATH/bin/dep
dep ensure -v
go get github.com/alecthomas/gometalinter
gometalinter --install
- run:
name: Run linting
command: |
gometalinter --exclude="rice-box.go" \
--deadline=300s \
-D goconst \
-D gocyclo \
-D vetshadow \
-D errcheck \
-D golint \
-D gas
build:
docker:
- image: circleci/golang:1.10
working_directory: /go/src/github.com/filebrowser/filebrowser
steps:
- checkout
- run:
name: Install Dependencies
command: |
curl -sL -o $GOPATH/bin/dep https://github.com/golang/dep/releases/download/v0.4.1/dep-linux-amd64
chmod +x $GOPATH/bin/dep
dep ensure -v
- run:
name: Building
command: go build github.com/filebrowser/filebrowser/cmd/filebrowser
deploy:
docker:
- image: circleci/golang:1.10
working_directory: /go/src/github.com/filebrowser/filebrowser
steps:
- checkout
- run:
name: Install Dependencies
command: |
curl -sL -o $GOPATH/bin/dep https://github.com/golang/dep/releases/download/v0.4.1/dep-linux-amd64
chmod +x $GOPATH/bin/dep
dep ensure -v
- run:
name: Deploy
command: curl -sL https://git.io/goreleaser | bash
workflows:
version: 2
lint-build-deploy:
jobs:
- linting:
filters:
tags:
only: /.*/
branches:
only: /.*/
- build:
filters:
tags:
only: /.*/
branches:
only: /.*/
- deploy:
requires:
- linting
- build
filters:
tags:
only: /v[0-9]+(\.[0-9]+)*(-.*)*/
branches:
ignore: /.*/

View File

@@ -1,4 +1,2 @@
assets/
testdata/
caddy/
.github/

View File

@@ -1,14 +0,0 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
# 4 space indentation
[*.go]
indent_style = tab
indent_size = 4

View File

@@ -1,2 +0,0 @@
build/*.js
config/*.js

View File

@@ -1,27 +0,0 @@
// http://eslint.org/docs/user-guide/configuring
module.exports = {
root: true,
parser: 'babel-eslint',
parserOptions: {
sourceType: 'module'
},
env: {
browser: true,
},
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
extends: 'standard',
// required to lint *.vue files
plugins: [
'html'
],
// add your custom rules here
'rules': {
// allow paren-less arrow functions
'arrow-parens': 0,
// allow async-await
'generator-star-spacing': 0,
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
}
}

3
.gitignore vendored
View File

@@ -9,4 +9,5 @@ yarn-error.log*
.idea
.vscode
package-lock.json
yarn.lock
yarn.lock
vendor

View File

@@ -1,6 +1,6 @@
build:
main: cmd/filemanager/main.go
binary: filemanager
main: cmd/filebrowser/main.go
binary: filebrowser
goos:
- darwin
- linux
@@ -15,10 +15,6 @@ build:
- 386
- arm
- arm64
- mips
- mips64
- mipsle
- mips64le
ignore:
- goos: openbsd
goarch: arm
@@ -26,6 +22,8 @@ build:
- goos: freebsd
goarch: arm
goarm: 6
- goos: linux
goarch: arm64
archive:
name_template: "{{.Os}}-{{.Arch}}-{{ .ProjectName }}"

View File

@@ -1,22 +0,0 @@
language: go
go: 1.x
env:
- "PATH=/home/travis/gopath/bin:$PATH"
install:
- go get ./...
# Install gometalinter and certain linters
- go get github.com/alecthomas/gometalinter
- go get github.com/client9/misspell/cmd/misspell
- go get github.com/gordonklaus/ineffassign
- go get golang.org/x/tools/cmd/goimports
- go get github.com/tsenart/deadcode
script:
- gometalinter --disable-all -E gofmt -E misspell -E ineffassign -E goimports -E deadcode --exclude="rice-box.go" --tests ./...
- go test ./... -timeout 30s
after_success:
- test -n "$TRAVIS_TAG" && curl -sL https://git.io/goreleaser | bash

View File

@@ -1,46 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hacdias@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@@ -1,14 +0,0 @@
# Contributing
If you want to contribute or want to build the code from source, you will need to have the most recent version of Go and, if you want to change the static assets (JS, CSS, ...), Node.js installed on your computer. To start developing, you just need to do the following:
1. `go get github.com/hacdias/filemanager/cmd/filemanager`
2. `cd $GOPATH/src/github.com/hacdias/filemanager`
3. `npm install`
4. `npm run dev` - regenerates the static assets automatically
5. `go install github.com/hacdias/filemanager/cmd/filemanager`
6. Execute `$GOPATH/bin/filemanager`
The steps 3 and 4 are only required **if you want to develop the front-end**. Otherwise, you can ignore them. Before pulling, if you made any change on assets folder, you must run the `build.sh` script on the root of this repository.
If you are using this as a Caddy plugin, you should use its [official instructions for plugins](https://github.com/mholt/caddy/wiki/Extending-Caddy#2-plug-in-your-plugin) and import `github.com/hacdias/filemanager/caddy/filemanager`.

View File

@@ -1,23 +1,25 @@
FROM golang:alpine
COPY . /go/src/github.com/hacdias/filemanager
WORKDIR /go/src/github.com/hacdias/filemanager
RUN apk add --no-cache git
RUN go get ./...
WORKDIR /go/src/github.com/hacdias/filemanager/cmd/filemanager
RUN CGO_ENABLED=0 go build -a
RUN mv filemanager /go/bin/filemanager
FROM scratch
COPY --from=0 /go/bin/filemanager /filemanager
VOLUME /tmp
VOLUME /srv
EXPOSE 80
COPY Docker.json /config.json
ENTRYPOINT ["/filemanager"]
CMD ["--config", "/config.json"]
FROM golang:alpine
COPY . /go/src/github.com/filebrowser/filebrowser
WORKDIR /go/src/github.com/filebrowser/filebrowser
RUN apk add --no-cache git curl && \
curl -fsSL -o /usr/local/bin/dep https://github.com/golang/dep/releases/download/v0.4.1/dep-linux-amd64 && \
chmod +x /usr/local/bin/dep
RUN dep ensure -vendor-only
WORKDIR /go/src/github.com/filebrowser/filebrowser/cmd/filebrowser
RUN CGO_ENABLED=0 go build -a
RUN mv filebrowser /go/bin/filebrowser
FROM scratch
COPY --from=0 /go/bin/filebrowser /filebrowser
VOLUME /tmp
VOLUME /srv
EXPOSE 80
COPY Docker.json /config.json
ENTRYPOINT ["/filebrowser"]
CMD ["--config", "/config.json"]

423
Gopkg.lock generated Normal file
View File

@@ -0,0 +1,423 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "github.com/BurntSushi/toml"
packages = ["."]
revision = "a368813c5e648fee92e5f6c30e3944ff9d5e8895"
[[projects]]
branch = "master"
name = "github.com/GeertJohan/go.rice"
packages = [
".",
"embedded"
]
revision = "c02ca9a983da5807ddf7d796784928f5be4afd09"
[[projects]]
branch = "master"
name = "github.com/aead/chacha20"
packages = [
".",
"chacha"
]
revision = "c8d29375923a8e1d2a0f0dc0fc1d8a0aba5b97ba"
[[projects]]
name = "github.com/asdine/storm"
packages = [
".",
"codec",
"codec/json",
"index",
"internal",
"q"
]
revision = "68fc73b635f890fe7ba2f3b15ce80c85b28a744f"
version = "v2.0.2"
[[projects]]
branch = "master"
name = "github.com/bifurcation/mint"
packages = [
".",
"syntax"
]
revision = "340be3ae8c0ff8edce24cf59e7acdb1432bd5ce5"
[[projects]]
name = "github.com/chaseadamsio/goorgeous"
packages = ["."]
revision = "dcf1ef873b8987bf12596fe6951c48347986eb2f"
version = "v1.1.0"
[[projects]]
branch = "master"
name = "github.com/codahale/aesnicheck"
packages = ["."]
revision = "349fcc471aaccc29cd074e1275f1a494323826cd"
[[projects]]
name = "github.com/coreos/bbolt"
packages = ["."]
revision = "583e8937c61f1af6513608ccc75c97b6abdf4ff9"
version = "v1.3.0"
[[projects]]
branch = "master"
name = "github.com/daaku/go.zipexe"
packages = ["."]
revision = "a5fe2436ffcb3236e175e5149162b41cd28bd27d"
[[projects]]
name = "github.com/dgrijalva/jwt-go"
packages = [
".",
"request"
]
revision = "dbeaa9332f19a944acb5736b4456cfcc02140e29"
version = "v3.1.0"
[[projects]]
branch = "master"
name = "github.com/dsnet/compress"
packages = [
".",
"bzip2",
"bzip2/internal/sais",
"internal",
"internal/errors",
"internal/prefix"
]
revision = "cc9eb1d7ad760af14e8f918698f745e80377af4f"
[[projects]]
branch = "master"
name = "github.com/flynn/go-shlex"
packages = ["."]
revision = "3f9db97f856818214da2e1057f8ad84803971cff"
[[projects]]
name = "github.com/fsnotify/fsnotify"
packages = ["."]
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
version = "v1.4.7"
[[projects]]
name = "github.com/gohugoio/hugo"
packages = ["parser"]
revision = "25e88ccabe9b04c42ffb43528c86743f623fac46"
version = "v0.36.1"
[[projects]]
branch = "master"
name = "github.com/golang/snappy"
packages = ["."]
revision = "553a641470496b2327abcac10b36396bd98e45c9"
[[projects]]
name = "github.com/gorilla/websocket"
packages = ["."]
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
version = "v1.2.0"
[[projects]]
branch = "master"
name = "github.com/hacdias/fileutils"
packages = ["."]
revision = "76b1c6ab906773727a1ce2f7fb22830685166f85"
[[projects]]
branch = "master"
name = "github.com/hacdias/varutils"
packages = ["."]
revision = "82d3b57f667a756cfc4b1535951b46878881f3e1"
[[projects]]
branch = "master"
name = "github.com/hashicorp/go-syslog"
packages = ["."]
revision = "326bf4a7f709d263f964a6a96558676b103f3534"
[[projects]]
branch = "master"
name = "github.com/hashicorp/golang-lru"
packages = [
".",
"simplelru"
]
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
[[projects]]
branch = "master"
name = "github.com/hashicorp/hcl"
packages = [
".",
"hcl/ast",
"hcl/parser",
"hcl/scanner",
"hcl/strconv",
"hcl/token",
"json/parser",
"json/scanner",
"json/token"
]
revision = "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8"
[[projects]]
branch = "master"
name = "github.com/kardianos/osext"
packages = ["."]
revision = "ae77be60afb1dcacde03767a8c37337fad28ac14"
[[projects]]
branch = "master"
name = "github.com/lucas-clemente/aes12"
packages = ["."]
revision = "cd47fb39b79f867c6e4e5cd39cf7abd799f71670"
[[projects]]
branch = "master"
name = "github.com/lucas-clemente/fnv128a"
packages = ["."]
revision = "393af48d391698c6ae4219566bfbdfef67269997"
[[projects]]
name = "github.com/lucas-clemente/quic-go"
packages = [
".",
"h2quic",
"internal/ackhandler",
"internal/congestion",
"internal/crypto",
"internal/flowcontrol",
"internal/handshake",
"internal/protocol",
"internal/utils",
"internal/wire",
"qerr"
]
revision = "30851b9a3b4e958490b476fe72adafa67641361a"
version = "v0.7.0"
[[projects]]
branch = "master"
name = "github.com/lucas-clemente/quic-go-certificates"
packages = ["."]
revision = "d2f86524cced5186554df90d92529757d22c1cb6"
[[projects]]
name = "github.com/magiconair/properties"
packages = ["."]
revision = "c3beff4c2358b44d0493c7dda585e7db7ff28ae6"
version = "v1.7.6"
[[projects]]
name = "github.com/mholt/archiver"
packages = ["."]
revision = "26cf5bb32d07aa4e8d0de15f56ce516f4641d7df"
[[projects]]
name = "github.com/mholt/caddy"
packages = [
".",
"caddyfile",
"caddyhttp/httpserver",
"caddyhttp/staticfiles",
"caddytls"
]
revision = "d3f338ddab9ee24b376b5c9c51e202581e2d43ba"
version = "v0.10.11"
[[projects]]
name = "github.com/miekg/dns"
packages = ["."]
revision = "5364553f1ee9cddc7ac8b62dce148309c386695b"
version = "v1.0.4"
[[projects]]
branch = "master"
name = "github.com/mitchellh/mapstructure"
packages = ["."]
revision = "00c29f56e2386353d58c599509e8dc3801b0d716"
[[projects]]
branch = "master"
name = "github.com/nwaples/rardecode"
packages = ["."]
revision = "e06696f847aeda6f39a8f0b7cdff193b7690aef6"
[[projects]]
name = "github.com/pelletier/go-toml"
packages = ["."]
revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8"
version = "v1.1.0"
[[projects]]
name = "github.com/pierrec/lz4"
packages = ["."]
revision = "2fcda4cb7018ce05a25959d2fe08c83e3329f169"
version = "v1.1"
[[projects]]
name = "github.com/pierrec/xxHash"
packages = ["xxHash32"]
revision = "f051bb7f1d1aaf1b5a665d74fb6b0217712c69f7"
version = "v0.1.1"
[[projects]]
name = "github.com/robfig/cron"
packages = ["."]
revision = "b024fc5ea0e34bc3f83d9941c8d60b0622bfaca4"
version = "v1"
[[projects]]
name = "github.com/russross/blackfriday"
packages = ["."]
revision = "4048872b16cc0fc2c5fd9eacf0ed2c2fedaa0c8c"
version = "v1.5"
[[projects]]
branch = "master"
name = "github.com/shurcooL/sanitized_anchor_name"
packages = ["."]
revision = "86672fcb3f950f35f2e675df2240550f2a50762f"
[[projects]]
name = "github.com/spf13/afero"
packages = [
".",
"mem"
]
revision = "bb8f1927f2a9d3ab41c9340aa034f6b803f4359c"
version = "v1.0.2"
[[projects]]
name = "github.com/spf13/cast"
packages = ["."]
revision = "8965335b8c7107321228e3e3702cab9832751bac"
version = "v1.2.0"
[[projects]]
branch = "master"
name = "github.com/spf13/jwalterweatherman"
packages = ["."]
revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394"
[[projects]]
name = "github.com/spf13/pflag"
packages = ["."]
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
version = "v1.0.0"
[[projects]]
name = "github.com/spf13/viper"
packages = ["."]
revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7"
version = "v1.0.0"
[[projects]]
name = "github.com/ulikunitz/xz"
packages = [
".",
"internal/hash",
"internal/xlog",
"lzma"
]
revision = "0c6b41e72360850ca4f98dc341fd999726ea007f"
version = "v0.5.4"
[[projects]]
name = "github.com/xenolf/lego"
packages = ["acme"]
revision = "67c86d860a797ce2483f50d9174d4ed24984bef2"
version = "v0.4.1"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = [
"bcrypt",
"blowfish",
"curve25519",
"ed25519",
"ed25519/internal/edwards25519",
"hkdf",
"ocsp"
]
revision = "49796115aa4b964c318aad4f3084fdb41e9aa067"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = [
"bpf",
"http2",
"http2/hpack",
"idna",
"internal/iana",
"internal/socket",
"ipv4",
"ipv6",
"lex/httplex",
"publicsuffix"
]
revision = "cbe0f9307d0156177f9dd5dc85da1a31abc5f2fb"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "88d2dcc510266da9f7f8c7f34e1940716cab5f5c"
[[projects]]
name = "golang.org/x/text"
packages = [
"collate",
"collate/build",
"internal/colltab",
"internal/gen",
"internal/tag",
"internal/triegen",
"internal/ucd",
"language",
"secure/bidirule",
"transform",
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
"unicode/rangetable"
]
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[[projects]]
name = "gopkg.in/natefinch/lumberjack.v2"
packages = ["."]
revision = "a96e63847dc3c67d17befa69c303767e2f84e54f"
version = "v2.1"
[[projects]]
name = "gopkg.in/square/go-jose.v1"
packages = [
".",
"cipher",
"json"
]
revision = "aa2e30fdd1fe9dd3394119af66451ae790d50e0d"
version = "v1.1.0"
[[projects]]
name = "gopkg.in/yaml.v2"
packages = ["."]
revision = "7f97868eec74b32b0982dd158a51a446d1da7eb5"
version = "v2.1.1"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "1f68bed4490068370884abaa296aa651c27b3f2e0d0451a1ab567f059d44f820"
solver-name = "gps-cdcl"
solver-version = 1

70
Gopkg.toml Normal file
View File

@@ -0,0 +1,70 @@
[[constraint]]
branch = "master"
name = "github.com/GeertJohan/go.rice"
[[constraint]]
name = "github.com/asdine/storm"
version = "2.0.2"
[[constraint]]
name = "github.com/dgrijalva/jwt-go"
version = "3.1.0"
[[constraint]]
name = "github.com/gohugoio/hugo"
version = "0.36.1"
[[constraint]]
name = "github.com/gorilla/websocket"
version = "1.2.0"
[[constraint]]
branch = "master"
name = "github.com/hacdias/fileutils"
[[constraint]]
branch = "master"
name = "github.com/hacdias/varutils"
[[constraint]]
name = "github.com/mholt/archiver"
# TODO: switch to version when it's available
# this is for Archiver.Write() which was introduced in 548c791
revision = "26cf5bb32d07aa4e8d0de15f56ce516f4641d7df"
# version = "2.0.0"
[[constraint]]
name = "github.com/mholt/caddy"
version = "0.10.11"
[[constraint]]
branch = "master"
name = "github.com/mitchellh/mapstructure"
[[constraint]]
name = "github.com/robfig/cron"
version = "1.0.0"
[[constraint]]
name = "github.com/spf13/pflag"
version = "1.0.0"
[[constraint]]
name = "github.com/spf13/viper"
version = "1.0.0"
[[constraint]]
branch = "master"
name = "golang.org/x/crypto"
[[constraint]]
name = "gopkg.in/natefinch/lumberjack.v2"
version = "2.1.0"
[[override]]
name = "github.com/russross/blackfriday"
version = "^1.0.0"
[prune]
go-tests = true
unused-packages = true

202
LICENSE Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018 File Browser contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,13 +1,13 @@
![Preview](https://user-images.githubusercontent.com/5447088/28537288-39be4288-70a2-11e7-8ce9-0813d59f46b7.gif)
# filemanager
# filebrowser
[![Build](https://img.shields.io/travis/hacdias/filemanager.svg?style=flat-square)](https://travis-ci.org/hacdias/filemanager)
[![Go Report Card](https://goreportcard.com/badge/github.com/hacdias/filemanager?style=flat-square)](https://goreportcard.com/report/hacdias/filemanager)
[![Documentation](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/hacdias/filemanager)
[![Version](https://img.shields.io/github/release/hacdias/filemanager.svg?style=flat-square)](https://github.com/hacdias/filemanager/releases/latest)
[![CircleCI](https://img.shields.io/circleci/project/github/filebrowser/filebrowser.svg?style=flat-square)](https://circleci.com/gh/filebrowser/filebrowser)
[![Go Report Card](https://goreportcard.com/badge/github.com/filebrowser/filebrowser?style=flat-square)](https://goreportcard.com/report/github.com/filebrowser/filebrowser)
[![Documentation](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/filebrowser/filebrowser)
[![Version](https://img.shields.io/github/release/filebrowser/filebrowser.svg?style=flat-square)](https://github.com/filebrowser/filebrowser/releases/latest)
filemanager provides a file managing interface within a specified directory and it can be used to upload, delete, preview, rename and edit your files. It allows the creation of multiple users and each user can have its own directory. It can be used as a standalone app or as a middleware.
filebrowser provides a file managing interface within a specified directory and it can be used to upload, delete, preview, rename and edit your files. It allows the creation of multiple users and each user can have its own directory. It can be used as a standalone app or as a middleware.
# Table of contents
@@ -20,7 +20,7 @@ filemanager provides a file managing interface within a specified directory and
# Getting started
You can find the Getting Started guide on the [documentation](https://henriquedias.com/filemanager/quick-start/).
You can find the Getting Started guide on the [documentation](https://filebrowser.github.io/quick-start/).
# Features
@@ -50,7 +50,7 @@ We support multiple users and each user can have its own scope and custom styles
## Search
FileManager allows you to search through your files and it has some options. By default, your search will be something like this:
File Browser allows you to search through your files and it has some options. By default, your search will be something like this:
```
this are keywords
@@ -72,8 +72,4 @@ this are keywords case:insensitive
# Contributing
The contributing guidelines can be found [here](https://github.com/hacdias/filemanager/blob/master/CONTRIBUTING.md).
# Donate
Enjoying this project? You can [donate to its creator](https://henriquedias.com/donate/). He will appreciate.
The contributing guidelines can be found [here](https://github.com/filebrowser/community).

View File

@@ -1,31 +0,0 @@
require('./check-versions')()
process.env.NODE_ENV = 'production'
var ora = require('ora')
var rm = require('rimraf')
var path = require('path')
var chalk = require('chalk')
var webpack = require('webpack')
var config = require('./config')
var webpackConfig = require('./webpack.prod.conf')
var spinner = ora('building for production...')
spinner.start()
rm(path.join(config.assetsRoot, config.assetsSubDirectory), err => {
if (err) throw err
webpack(webpackConfig, function (err, stats) {
spinner.stop()
if (err) throw err
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + '\n\n')
console.log(chalk.cyan(' Build complete.\n'))
})
})

View File

@@ -1,48 +0,0 @@
var chalk = require('chalk')
var semver = require('semver')
var packageConfig = require('../../package.json')
var shell = require('shelljs')
function exec (cmd) {
return require('child_process').execSync(cmd).toString().trim()
}
var versionRequirements = [
{
name: 'node',
currentVersion: semver.clean(process.version),
versionRequirement: packageConfig.engines.node
}
]
if (shell.which('npm')) {
versionRequirements.push({
name: 'npm',
currentVersion: exec('npm --version'),
versionRequirement: packageConfig.engines.npm
})
}
module.exports = function () {
var warnings = []
for (var i = 0; i < versionRequirements.length; i++) {
var mod = versionRequirements[i]
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
warnings.push(mod.name + ': ' +
chalk.red(mod.currentVersion) + ' should be ' +
chalk.green(mod.versionRequirement)
)
}
}
if (warnings.length) {
console.log('')
console.log(chalk.yellow('To use this template, you must update following to modules:'))
console.log()
for (var i = 0; i < warnings.length; i++) {
var warning = warnings[i]
console.log(' ' + warning)
}
console.log()
process.exit(1)
}
}

View File

@@ -1,26 +0,0 @@
// see http://vuejs-templates.github.io/webpack for documentation.
var path = require('path')
module.exports = {
index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: '{{ .BaseURL }}/',
build: {
env: {
NODE_ENV: '"production"'
},
productionSourceMap: true,
// Run the build command with an extra argument to
// View the bundle analyzer report after build finishes:
// `npm run build --report`
// Set to `true` or `false` to always turn it on or off
bundleAnalyzerReport: process.env.npm_config_report
},
dev: {
env: {
NODE_ENV: '"development"'
},
produceSourceMap: true
}
}

View File

@@ -1,35 +0,0 @@
require('./check-versions')()
process.env.NODE_ENV = 'development'
var rm = require('rimraf')
var path = require('path')
var chalk = require('chalk')
var webpack = require('webpack')
var config = require('./config')
var webpackConfig = require('./webpack.dev.conf')
var fs = require('fs')
if (fs.existsSync('./rice-box.go')) {
fs.unlinkSync('./rice-box.go')
}
if (fs.existsSync('./plugins/rice-box.go')) {
fs.unlinkSync('./plugins/rice-box.go')
}
rm(path.join(config.assetsRoot, config.assetsSubDirectory), err => {
if (err) throw err
webpack(webpackConfig, function (err, stats) {
if (err) throw err
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + '\n\n')
console.log(chalk.cyan(' Build complete.\n'))
})
})

View File

@@ -1,17 +0,0 @@
// This service worker file is effectively a 'no-op' that will reset any
// previous service worker registered for the same host:port combination.
// In the production build, this file is replaced with an actual service worker
// file that will precache your site's local assets.
// See https://github.com/facebookincubator/create-react-app/issues/2272#issuecomment-302832432
self.addEventListener('install', () => self.skipWaiting());
self.addEventListener('activate', () => {
self.clients.matchAll({ type: 'window' }).then(windowClients => {
for (let windowClient of windowClients) {
// Force open pages to refresh, so that they have a chance to load the
// fresh navigation response from the local dev server.
windowClient.navigate(windowClient.url);
}
});
});

View File

@@ -1,55 +0,0 @@
(function() {
'use strict';
// Check to make sure service workers are supported in the current browser,
// and that the current page is accessed from a secure origin. Using a
// service worker from an insecure origin will trigger JS console errors.
const isLocalhost = Boolean(window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
window.addEventListener('load', function() {
if ('serviceWorker' in navigator &&
(window.location.protocol === 'https:' || isLocalhost)) {
navigator.serviceWorker.register('{{ .BaseURL }}/sw.js')
.then(function(registration) {
// updatefound is fired if service-worker.js changes.
registration.onupdatefound = function() {
// updatefound is also fired the very first time the SW is installed,
// and there's no need to prompt for a reload at that point.
// So check here to see if the page is already controlled,
// i.e. whether there's an existing service worker.
if (navigator.serviceWorker.controller) {
// The updatefound event implies that registration.installing is set
const installingWorker = registration.installing;
installingWorker.onstatechange = function() {
switch (installingWorker.state) {
case 'installed':
// At this point, the old content will have been purged and the
// fresh content will have been added to the cache.
// It's the perfect time to display a "New content is
// available; please refresh." message in the page's interface.
break;
case 'redundant':
throw new Error('The installing ' +
'service worker became redundant.');
default:
// Ignore
}
};
}
};
}).catch(function(e) {
console.error('Error during service worker registration:', e);
});
}
});
})();

View File

@@ -1,70 +0,0 @@
var path = require('path')
var config = require('./config')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
exports.assetsPath = function (_path) {
var assetsSubDirectory = config.assetsSubDirectory
return path.posix.join(assetsSubDirectory, _path)
}
exports.cssLoaders = function (options) {
options = options || {}
var cssLoader = {
loader: 'css-loader',
options: {
minimize: process.env.NODE_ENV === 'production',
sourceMap: options.sourceMap
}
}
// generate loader string to be used with extract text plugin
function generateLoaders (loader, loaderOptions) {
var loaders = [cssLoader]
if (loader) {
loaders.push({
loader: loader + '-loader',
options: Object.assign({}, loaderOptions, {
sourceMap: options.sourceMap
})
})
}
// Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
}
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
return {
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less'),
sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass'),
stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus')
}
}
// Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) {
var output = []
var loaders = exports.cssLoaders(options)
for (var extension in loaders) {
var loader = loaders[extension]
output.push({
test: new RegExp('\\.' + extension + '$'),
use: loader
})
}
return output
}

View File

@@ -1,12 +0,0 @@
var utils = require('./utils')
var config = require('./config')
var isProduction = process.env.NODE_ENV === 'production'
module.exports = {
loaders: utils.cssLoaders({
sourceMap: isProduction
? config.build.productionSourceMap
: config.dev.produceSourceMap,
extract: isProduction
})
}

View File

@@ -1,69 +0,0 @@
var path = require('path')
var utils = require('./utils')
var config = require('./config')
var vueLoaderConfig = require('./vue-loader.conf')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
entry: {
app: './assets/src/main.js'
},
output: {
path: config.assetsRoot,
filename: '[name].js',
publicPath: config.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src')
}
},
module: {
rules: [
{
test: /\.(yml|yaml)$/,
loader: 'yml-loader'
},
{
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: 'pre',
include: [resolve('src'), resolve('test')],
options: {
formatter: require('eslint-friendly-formatter')
}
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test')]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
// limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
}
}

View File

@@ -1,81 +0,0 @@
var fs = require('fs')
var path = require('path')
var utils = require('./utils')
var webpack = require('webpack')
var config = require('./config')
var merge = require('webpack-merge')
var baseWebpackConfig = require('./webpack.base.conf')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
var CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = merge(baseWebpackConfig, {
watch: true,
module: {
rules: utils.styleLoaders({
sourceMap: config.dev.produceSourceMap,
extract: true
})
},
devtool: '#cheap-module-eval-source-map',
output: {
path: config.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
plugins: [
new webpack.NoEmitOnErrorsPlugin(),
new FriendlyErrorsPlugin(),
new webpack.DefinePlugin({
'process.env': config.dev.env
}),
// extract css into its own file
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css')
}),
// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html
// see https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: config.index,
template: 'assets/index.html',
inject: true,
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency',
serviceWorkerLoader: `<script>${fs.readFileSync(path.join(__dirname,
'./service-worker-dev.js'), 'utf-8')}</script>`
}),
// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module, count) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../../node_modules')
) === 0
)
}
}),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
chunks: ['vendor']
}),
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.assetsSubDirectory,
ignore: ['.*']
},
{
from: path.resolve(__dirname, '../../node_modules/codemirror/mode/*/*'),
to: path.join(config.assetsSubDirectory, 'js/codemirror/mode/[name]/[name].js')
}
])
]
})

View File

@@ -1,127 +0,0 @@
var fs = require('fs')
var path = require('path')
var utils = require('./utils')
var webpack = require('webpack')
var config = require('./config')
var merge = require('webpack-merge')
var baseWebpackConfig = require('./webpack.base.conf')
var CopyWebpackPlugin = require('copy-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
var SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin')
var UglifyJS = require('uglify-js')
var env = config.build.env
var webpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true
})
},
devtool: config.build.productionSourceMap ? '#source-map' : false,
output: {
path: config.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
plugins: [
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.assetsSubDirectory,
ignore: ['.*']
},
{
from: path.resolve(__dirname, '../../node_modules/codemirror/mode/*/*'),
to: path.join(config.assetsSubDirectory, 'js/codemirror/mode/[name]/[name].js'),
transform: function (source, path) {
let result = UglifyJS.minify(source.toString('utf8'))
if (result.error !== undefined) {
return source
}
return result.code
}
}
]),
// http://vuejs.github.io/vue-loader/en/workflow/production.html
new webpack.DefinePlugin({
'process.env': env
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: true
}),
// extract css into its own file
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css')
}),
// Compress extracted CSS. We are using this plugin so that possible
// duplicated CSS from different components can be deduped.
new OptimizeCSSPlugin({
cssProcessorOptions: {
safe: true
}
}),
// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html
// see https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: config.index,
template: 'assets/index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true,
minifyCSS: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency',
serviceWorkerLoader: `<script>${fs.readFileSync(path.join(__dirname,
'./service-worker-prod.js'), 'utf-8')}</script>`
}),
// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module, count) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../../node_modules')
) === 0
)
}
}),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
chunks: ['vendor']
}),
// service worker caching
new SWPrecacheWebpackPlugin({
cacheId: 'File Manager',
filename: 'sw.js',
replacePrefix: '{{ .BaseURL }}/',
staticFileGlobs: ['dist/**/*.{js,html,css}'],
minify: true,
stripPrefix: 'dist/'
})
]
})
if (config.build.bundleAnalyzerReport) {
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig

View File

@@ -1,116 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<meta name="base" content="{{ .BaseURL }}">
<meta name="staticgen" content="{{ .StaticGen }}">
<meta name="noauth" content="{{ .NoAuth }}">
<meta name="version" content="{{ .Version }}">
<meta name="recaptcha" content="{{ .ReCaptchaKey }}">
<title>File Manager</title>
<link rel="icon" type="image/png" sizes="32x32" href="{{ .BaseURL }}/static/img/icons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="{{ .BaseURL }}/static/img/icons/favicon-16x16.png">
<!--[if IE]><link rel="shortcut icon" href="{{ .BaseURL }}/static/img/icons/favicon.ico"><![endif]-->
<!-- Add to home screen for Android and modern mobile browsers -->
<link rel="manifest" href="{{ .BaseURL }}/static/manifest.json">
<meta name="theme-color" content="#2979ff">
<!-- Add to home screen for Safari on iOS -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="assets">
<link rel="apple-touch-icon" href="{{ .BaseURL }}/static/img/icons/apple-touch-icon-152x152.png">
<!-- Add to home screen for Windows -->
<meta name="msapplication-TileImage" content="{{ .BaseURL }}/static/img/icons/msapplication-icon-144x144.png">
<meta name="msapplication-TileColor" content="#2979ff">
<script>CSS = "{{ .CSS }}"</script>
{{ if .ReCaptcha -}}
<script src='https://www.google.com/recaptcha/api.js?render=explicit'></script>
{{ end }}
<% for (var chunk of webpack.chunks) {
for (var file of chunk.files) {
if (file.match(/\.(js|css)$/)) { %>
<link rel="preload" href="{{ .BaseURL }}/<%= file %>" as="<%= file.match(/\.css$/)?'style':'script' %>"><% }}} %>
<style>
#loading {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fff;
z-index: 9999;
transition: .1s ease opacity;
-webkit-transition: .1s ease opacity;
}
#loading.done {
opacity: 0;
}
.spinner {
width: 70px;
text-align: center;
position: fixed;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.spinner > div {
width: 18px;
height: 18px;
background-color: #333;
border-radius: 100%;
display: inline-block;
-webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
}
.spinner .bounce1 {
-webkit-animation-delay: -0.32s;
animation-delay: -0.32s;
}
.spinner .bounce2 {
-webkit-animation-delay: -0.16s;
animation-delay: -0.16s;
}
@-webkit-keyframes sk-bouncedelay {
0%, 80%, 100% { -webkit-transform: scale(0) }
40% { -webkit-transform: scale(1.0) }
}
@keyframes sk-bouncedelay {
0%, 80%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
} 40% {
-webkit-transform: scale(1.0);
transform: scale(1.0);
}
}
</style>
</head>
<body>
<div id="app"></div>
<div id="loading">
<div class="spinner">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
</div>
<%= htmlWebpackPlugin.options.serviceWorkerLoader %>
</body>
</html>

View File

@@ -1,78 +0,0 @@
<template>
<router-view :dependencies="loaded" @update:css="updateCSS" @clean:css="cleanCSS"></router-view>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'app',
computed: mapState(['recaptcha']),
data () {
return {
loaded: false
}
},
mounted () {
if (this.recaptcha.length === 0) {
this.unload()
return
}
let check = () => {
if (typeof window.grecaptcha === 'undefined') {
setTimeout(check, 100)
return
}
this.unload()
}
check()
},
methods: {
unload () {
this.loaded = true
// Remove loading animation.
let loading = document.getElementById('loading')
loading.classList.add('done')
setTimeout(function () {
loading.parentNode.removeChild(loading)
}, 200)
this.updateCSS()
},
updateCSS (global = false) {
let css = this.$store.state.css
if (typeof this.$store.state.user.css === 'string' && !global) {
css += '\n' + this.$store.state.user.css
}
this.removeCSS()
let style = document.createElement('style')
style.title = 'custom-css'
style.type = 'text/css'
style.appendChild(document.createTextNode(css))
document.head.appendChild(style)
},
removeCSS () {
let style = document.querySelector('style[title="custom-css"]')
if (style === undefined || style === null) {
return
}
style.parentElement.removeChild(style)
},
cleanCSS () {
this.updateCSS(true)
}
}
}
</script>
<style>
@import './css/styles.css';
</style>

View File

@@ -1,5 +0,0 @@
<svg id="content" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 144 144">
<circle cx="72" cy="72" r="72" fill="#2979ff"/>
<circle cx="72" cy="72" r="48" fill="#40c4ff"/>
<circle cx="72" cy="72" r="24" fill="#fff"/>
</svg>

Before

Width:  |  Height:  |  Size: 239 B

View File

@@ -1,220 +0,0 @@
<template>
<header>
<div>
<button @click="openSidebar" :aria-label="$t('buttons.toggleSidebar')" :title="$t('buttons.toggleSidebar')" class="action">
<i class="material-icons">menu</i>
</button>
<img src="../assets/logo.svg" alt="File Manager">
<search></search>
</div>
<div>
<button @click="openSearch" :aria-label="$t('buttons.search')" :title="$t('buttons.search')" class="search-button action">
<i class="material-icons">search</i>
</button>
<button v-show="showSaveButton" :aria-label="$t('buttons.save')" :title="$t('buttons.save')" class="action" id="save-button">
<i class="material-icons">save</i>
</button>
<template v-if="staticGen.length > 0">
<button v-show="showPublishButton" :aria-label="$t('buttons.publish')" :title="$t('buttons.publish')" class="action" id="publish-button">
<i class="material-icons">send</i>
</button>
</template>
<button @click="openMore" id="more" :aria-label="$t('buttons.more')" :title="$t('buttons.more')" class="action">
<i class="material-icons">more_vert</i>
</button>
<!-- Menu that shows on listing AND mobile when there are files selected -->
<div id="file-selection" v-if="isMobile && req.kind === 'listing'">
<span v-if="selectedCount > 0">{{ selectedCount }} selected</span>
<share-button v-show="showRenameButton"></share-button>
<rename-button v-show="showRenameButton"></rename-button>
<copy-button v-show="showMoveButton"></copy-button>
<move-button v-show="showMoveButton"></move-button>
<delete-button v-show="showDeleteButton"></delete-button>
</div>
<!-- This buttons are shown on a dropdown on mobile phones -->
<div id="dropdown" :class="{ active: showMore }">
<div v-if="!isListing || !isMobile">
<share-button v-show="showRenameButton"></share-button>
<rename-button v-show="showRenameButton"></rename-button>
<copy-button v-show="showMoveButton"></copy-button>
<move-button v-show="showMoveButton"></move-button>
<delete-button v-show="showDeleteButton"></delete-button>
</div>
<template v-if="staticGen.length > 0">
<schedule-button v-show="showPublishButton"></schedule-button>
</template>
<switch-button v-show="showSwitchButton"></switch-button>
<download-button v-show="showCommonButton"></download-button>
<upload-button v-show="showUpload"></upload-button>
<info-button v-show="showCommonButton"></info-button>
<button v-show="showSelectButton" @click="openSelect" :aria-label="$t('buttons.selectMultiple')" :title="$t('buttons.selectMultiple')" class="action">
<i class="material-icons">check_circle</i>
<span>{{ $t('buttons.select') }}</span>
</button>
</div>
<div v-show="showOverlay" @click="resetPrompts" class="overlay"></div>
</div>
</header>
</template>
<script>
import Search from './Search'
import InfoButton from './buttons/Info'
import DeleteButton from './buttons/Delete'
import RenameButton from './buttons/Rename'
import UploadButton from './buttons/Upload'
import DownloadButton from './buttons/Download'
import SwitchButton from './buttons/SwitchView'
import MoveButton from './buttons/Move'
import CopyButton from './buttons/Copy'
import ScheduleButton from './buttons/Schedule'
import ShareButton from './buttons/Share'
import {mapGetters, mapState} from 'vuex'
import * as api from '@/utils/api'
import buttons from '@/utils/buttons'
export default {
name: 'main',
components: {
Search,
InfoButton,
DeleteButton,
ShareButton,
RenameButton,
DownloadButton,
CopyButton,
UploadButton,
SwitchButton,
MoveButton,
ScheduleButton
},
data: function () {
return {
width: window.innerWidth,
pluginData: {
api,
buttons,
'store': this.$store,
'router': this.$router
}
}
},
created () {
window.addEventListener('resize', () => {
this.width = window.innerWidth
})
},
computed: {
...mapGetters([
'selectedCount'
]),
...mapState([
'req',
'user',
'loading',
'reload',
'multiple',
'staticGen'
]),
isMobile () {
return this.width <= 736
},
isListing () {
return this.req.kind === 'listing'
},
showSelectButton () {
return this.req.kind === 'listing' && !this.loading && this.$route.name === 'Files'
},
showSaveButton () {
return (this.req.kind === 'editor' && !this.loading)
},
showPublishButton () {
return (this.req.kind === 'editor' && !this.loading && this.user.allowPublish)
},
showSwitchButton () {
return this.req.kind === 'listing' && this.$route.name === 'Files' && !this.loading
},
showCommonButton () {
return !(this.$route.name !== 'Files' || this.loading)
},
showUpload () {
if (this.$route.name !== 'Files' || this.loading) return false
if (this.req.kind === 'editor') return false
return this.user.allowNew
},
showDeleteButton () {
if (this.$route.name !== 'Files' || this.loading) return false
if (this.req.kind === 'listing') {
if (this.selectedCount === 0) {
return false
}
return this.user.allowEdit
}
return this.user.allowEdit
},
showRenameButton () {
if (this.$route.name !== 'Files' || this.loading) return false
if (this.req.kind === 'listing') {
if (this.selectedCount === 1) {
return this.user.allowEdit
}
return false
}
return this.user.allowEdit
},
showMoveButton () {
if (this.$route.name !== 'Files' || this.loading) return false
if (this.req.kind !== 'listing') {
return false
}
if (this.selectedCount > 0) {
return this.user.allowEdit
}
return false
},
showMore () {
if (this.$route.name !== 'Files' || this.loading) return false
return (this.$store.state.show === 'more')
},
showOverlay () {
return (this.$store.state.show === 'more')
}
},
methods: {
openSidebar () {
this.$store.commit('showHover', 'sidebar')
},
openMore () {
this.$store.commit('showHover', 'more')
},
openSearch () {
this.$store.commit('showHover', 'search')
},
openSelect () {
this.$store.commit('multiple', true)
this.resetPrompts()
},
resetPrompts () {
this.$store.commit('closeHovers')
}
}
}
</script>

View File

@@ -1,23 +0,0 @@
<template>
<select v-on:change="change" :value="selected">
<option value="en">{{ $t('languages.en') }}</option>
<option value="fr">{{ $t('languages.fr') }}</option>
<option value="pt">{{ $t('languages.pt') }}</option>
<option value="ja">{{ $t('languages.ja') }}</option>
<option value="zh-cn">{{ $t('languages.zhCN') }}</option>
<option value="zh-tw">{{ $t('languages.zhTW') }}</option>
<option value="es">{{ $t('languages.es') }}</option>
</select>
</template>
<script>
export default {
name: 'languages',
props: [ 'selected' ],
methods: {
change (event) {
this.$emit('update:selected', event.target.value)
}
}
}
</script>

View File

@@ -1,265 +0,0 @@
<template>
<div id="search" @click="open" v-bind:class="{ active , ongoing }">
<div id="input">
<button v-if="active" class="action" @click="close" :aria-label="$t('buttons.close')" :title="$t('buttons.close')">
<i class="material-icons">arrow_back</i>
</button>
<i v-else class="material-icons">search</i>
<input type="text"
@keyup="keyup"
@keyup.enter="submit"
ref="input"
:autofocus="active"
v-model.trim="value"
:aria-label="$t('search.writeToSearch')"
:placeholder="placeholder">
</div>
<div id="result">
<div>
<template v-if="search.length === 0 && commands.length === 0">
<p>{{ text }}</p>
<template v-if="value.length === 0">
<div class="boxes">
<h3>{{ $t('search.types') }}</h3>
<div>
<div tabindex="0"
role="button"
@click="init('type:image')"
:aria-label="$t('search.images')">
<i class="material-icons">insert_photo</i>
<p>{{ $t('search.images') }}</p>
</div>
<div tabindex="0"
role="button"
@click="init('type:audio')"
:aria-label="$t('search.music')">
<i class="material-icons">volume_up</i>
<p>{{ $t('search.music') }}</p>
</div>
<div tabindex="0"
role="button"
@click="init('type:video')"
:aria-label="$t('search.video')">
<i class="material-icons">movie</i>
<p>{{ $t('search.video') }}</p>
</div>
<div tabindex="0"
role="button"
@click="init('type:pdf')"
:aria-label="$t('search.pdf')">
<i class="material-icons">picture_as_pdf</i>
<p>{{ $t('search.pdf') }}</p>
</div>
</div>
</div>
</template>
</template>
<ul v-else-if="search.length > 0">
<li v-for="s in search">
<router-link @click.native="close" :to="'./' + s.path">
<i v-if="s.dir" class="material-icons">folder</i>
<i v-else class="material-icons">insert_drive_file</i>
<span>./{{ s.path }}</span>
</router-link>
</li>
</ul>
<pre v-else-if="commands.length > 0">
<template v-for="c in commands">{{ c }}</template>
</pre>
</div>
<p id="renew"><i class="material-icons spin">autorenew</i></p>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
import url from '@/utils/url'
import * as api from '@/utils/api'
export default {
name: 'search',
data: function () {
return {
value: '',
active: false,
ongoing: false,
scrollable: null,
search: [],
commands: [],
reload: false
}
},
watch: {
show (val, old) {
this.active = (val === 'search')
// If the hover was search and now it's something else
// we should blur the input.
if (old === 'search' && val !== 'search') {
if (this.reload) {
this.$store.commit('setReload', true)
}
document.body.style.overflow = 'auto'
this.reset()
this.$refs.input.blur()
}
// If we are starting to show the search box, we should
// focus the input.
if (val === 'search') {
this.reload = false
this.$refs.input.focus()
document.body.style.overflow = 'hidden'
}
}
},
computed: {
...mapState(['user', 'show']),
// Placeholder value.
placeholder: function () {
if (this.user.allowCommands && this.user.commands.length > 0) {
return this.$t('search.searchOrCommand')
}
return this.$t('search.search')
},
// The text that is shown on the results' box while
// there is no search result or command output to show.
text: function () {
if (this.ongoing) {
return ''
}
if (this.value.length === 0) {
if (this.user.allowCommands && this.user.commands.length > 0) {
return `${this.$t('search.searchOrSupportedCommand')} ${this.user.commands.join(', ')}.`
}
this.$t('search.type')
}
if (!this.supported() || !this.user.allowCommands) {
return this.$t('search.pressToSearch')
} else {
return this.$t('search.pressToExecute')
}
}
},
mounted: function () {
// Gets the result div which will be scrollable.
this.scrollable = document.querySelector('#search #result')
// Adds the keydown event on window for the ESC key, so
// when it's pressed, it closes the search window.
window.addEventListener('keydown', (event) => {
if (event.keyCode === 27) {
this.$store.commit('closeHovers')
}
})
},
methods: {
// Sets the search to active.
open (event) {
this.$store.commit('showHover', 'search')
},
// Closes the search and prevents the event
// of propagating so it doesn't trigger the
// click event on #search.
close (event) {
event.stopPropagation()
event.preventDefault()
this.$store.commit('closeHovers')
},
// Checks if the current input is a supported command.
supported () {
let pieces = this.value.split(' ')
for (let i = 0; i < this.user.commands.length; i++) {
if (pieces[0] === this.user.commands[i]) {
return true
}
}
return false
},
// Initializes the search with a default value.
init (string) {
this.value = string + ' '
this.$refs.input.focus()
},
// Resets the search box value.
reset () {
this.value = ''
this.active = false
this.ongoing = false
this.search = []
this.commands = []
},
// When the user presses a key, if it is ESC
// then it will close the search box. Otherwise,
// it will set the search box to active and clean
// the search results, as well as commands'.
keyup (event) {
if (event.keyCode === 27) {
this.close(event)
return
}
this.search.length = 0
this.commands.length = 0
},
// Submits the input to the server and sets ongoing to true.
submit (event) {
this.ongoing = true
let path = this.$route.path
if (this.$store.state.req.kind !== 'listing') {
path = url.removeLastDir(path) + '/'
}
// In case of being a command.
if (this.supported() && this.user.allowCommands) {
api.command(path, this.value,
(event) => {
this.commands.push(event.data)
this.scrollable.scrollTop = this.scrollable.scrollHeight
},
(event) => {
this.reload = true
this.ongoing = false
this.scrollable.scrollTop = this.scrollable.scrollHeight
}
)
return
}
// In case of being a search.
api.search(path, this.value,
(event) => {
let response = JSON.parse(event.data)
if (response.path[0] === '/') {
response.path = response.path.substring(1)
}
this.search.push(response)
this.scrollable.scrollTop = this.scrollable.scrollHeight
},
(event) => {
this.ongoing = false
this.scrollable.scrollTop = this.scrollable.scrollHeight
}
)
}
}
}
</script>

View File

@@ -1,90 +0,0 @@
<template>
<nav :class="{active}">
<router-link class="action" to="/files/" :aria-label="$t('sidebar.myFiles')" :title="$t('sidebar.myFiles')">
<i class="material-icons">folder</i>
<span>{{ $t('sidebar.myFiles') }}</span>
</router-link>
<div v-if="user.allowNew">
<button @click="$store.commit('showHover', 'newDir')" class="action" :aria-label="$t('sidebar.newFolder')" :title="$t('sidebar.newFolder')">
<i class="material-icons">create_new_folder</i>
<span>{{ $t('sidebar.newFolder') }}</span>
</button>
<button @click="$store.commit('showHover', 'newFile')" class="action" :aria-label="$t('sidebar.newFile')" :title="$t('sidebar.newFile')">
<i class="material-icons">note_add</i>
<span>{{ $t('sidebar.newFile') }}</span>
</button>
</div>
<div v-if="staticGen.length > 0">
<router-link to="/files/settings"
:aria-label="$t('sidebar.siteSettings')"
:title="$t('sidebar.siteSettings')"
class="action">
<i class="material-icons">settings</i>
<span>{{ $t('sidebar.siteSettings') }}</span>
</router-link>
<template v-if="staticGen === 'hugo'">
<button class="action"
:aria-label="$t('sidebar.hugoNew')"
:title="$t('sidebar.hugoNew')"
v-if="user.allowNew"
@click="$store.commit('showHover', 'new-archetype')">
<i class="material-icons">merge_type</i>
<span>{{ $t('sidebar.hugoNew') }}</span>
</button>
</template>
<button class="action"
:aria-label="$t('sidebar.preview')"
:title="$t('sidebar.preview')"
@click="preview">
<i class="material-icons">remove_red_eye</i>
<span>{{ $t('sidebar.preview') }}</span>
</button>
</div>
<div v-if="!$store.state.noAuth">
<router-link class="action" to="/settings" :aria-label="$t('sidebar.settings')" :title="$t('sidebar.settings')">
<i class="material-icons">settings_applications</i>
<span>{{ $t('sidebar.settings') }}</span>
</router-link>
<button @click="logout" class="action" id="logout" :aria-label="$t('sidebar.logout')" :title="$t('sidebar.logout')">
<i class="material-icons">exit_to_app</i>
<span>{{ $t('sidebar.logout') }}</span>
</button>
</div>
<p class="credits">
<span><a rel="noopener noreferrer" href="https://github.com/hacdias/filemanager">File Manager</a> v{{ version }}</span>
<span><a @click="help">{{ $t('sidebar.help') }}</a></span>
</p>
</nav>
</template>
<script>
import {mapState} from 'vuex'
import auth from '@/utils/auth'
export default {
name: 'sidebar',
computed: {
...mapState(['user', 'staticGen', 'version']),
active () {
return this.$store.state.show === 'sidebar'
}
},
methods: {
help () {
this.$store.commit('showHover', 'help')
},
preview () {
window.open(this.$store.state.baseURL + '/preview/')
},
logout: auth.logout
}
}
</script>

View File

@@ -1,17 +0,0 @@
<template>
<button @click="show" :aria-label="$t('buttons.copy')" :title="$t('buttons.copy')" class="action" id="copy-button">
<i class="material-icons">content_copy</i>
<span>{{ $t('buttons.copyFile') }}</span>
</button>
</template>
<script>
export default {
name: 'copy-button',
methods: {
show: function (event) {
this.$store.commit('showHover', 'copy')
}
}
}
</script>

View File

@@ -1,17 +0,0 @@
<template>
<button @click="show" :aria-label="$t('buttons.delete')" :title="$t('buttons.delete')" class="action" id="delete-button">
<i class="material-icons">delete</i>
<span>{{ $t('buttons.delete') }}</span>
</button>
</template>
<script>
export default {
name: 'delete-button',
methods: {
show: function (event) {
this.$store.commit('showHover', 'delete')
}
}
}
</script>

View File

@@ -1,39 +0,0 @@
<template>
<button @click="download" :aria-label="$t('buttons.download')" :title="$t('buttons.download')" id="download-button" class="action">
<i class="material-icons">file_download</i>
<span>{{ $t('buttons.download') }}</span>
<span v-if="selectedCount > 0" class="counter">{{ selectedCount }}</span>
</button>
</template>
<script>
import {mapGetters, mapState} from 'vuex'
import * as api from '@/utils/api'
export default {
name: 'download-button',
computed: {
...mapState(['req', 'selected']),
...mapGetters(['selectedCount'])
},
methods: {
download: function (event) {
// If we are not on a listing, download the current file.
if (this.req.kind !== 'listing') {
api.download(null, this.$route.path)
return
}
// If we are on a listing and there is one element selected,
// download it.
if (this.selectedCount === 1 && !this.req.items[this.selected[0]].isDir) {
api.download(null, this.req.items[this.selected[0]].url)
return
}
// Otherwise show the prompt to choose the formt of the download.
this.$store.commit('showHover', 'download')
}
}
}
</script>

View File

@@ -1,17 +0,0 @@
<template>
<button :title="$t('buttons.info')" :aria-label="$t('buttons.info')" class="action" @click="show">
<i class="material-icons">info</i>
<span>{{ $t('buttons.info') }}</span>
</button>
</template>
<script>
export default {
name: 'info-button',
methods: {
show: function (event) {
this.$store.commit('showHover', 'info')
}
}
}
</script>

View File

@@ -1,17 +0,0 @@
<template>
<button @click="show" :aria-label="$t('buttons.move')" :title="$t('buttons.move')" class="action" id="move-button">
<i class="material-icons">forward</i>
<span>{{ $t('buttons.moveFile') }}</span>
</button>
</template>
<script>
export default {
name: 'move-button',
methods: {
show: function (event) {
this.$store.commit('showHover', 'move')
}
}
}
</script>

View File

@@ -1,17 +0,0 @@
<template>
<button @click="show" :aria-label="$t('buttons.rename')" :title="$t('buttons.rename')" class="action" id="rename-button">
<i class="material-icons">mode_edit</i>
<span>{{ $t('buttons.rename') }}</span>
</button>
</template>
<script>
export default {
name: 'rename-button',
methods: {
show: function (event) {
this.$store.commit('showHover', 'rename')
}
}
}
</script>

View File

@@ -1,21 +0,0 @@
<template>
<button @click="show"
:aria-label="$t('buttons.schedule')"
:title="$t('buttons.schedule')"
id="schedule-button"
class="action">
<i class="material-icons">alarm</i>
<span>{{ $t('buttons.schedule') }}</span>
</button>
</template>
<script>
export default {
name: 'schedule-button',
methods: {
show: function (event) {
this.$store.commit('showHover', 'schedule')
}
}
}
</script>

View File

@@ -1,17 +0,0 @@
<template>
<button @click="show" :aria-label="$t('buttons.share')" :title="$t('buttons.share')" class="action">
<i class="material-icons">share</i>
<span>{{ $t('buttons.share') }}</span>
</button>
</template>
<script>
export default {
name: 'share-button',
methods: {
show (event) {
this.$store.commit('showHover', 'share')
}
}
}
</script>

View File

@@ -1,36 +0,0 @@
<template>
<button @click="change" :aria-label="$t('buttons.switchView')" :title="$t('buttons.switchView')" class="action" id="switch-view-button">
<i class="material-icons">{{ icon }}</i>
<span>{{ $t('buttons.switchView') }}</span>
</button>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
import { updateUser } from '@/utils/api'
export default {
name: 'switch-button',
computed: {
...mapState(['user']),
icon: function () {
if (this.user.viewMode === 'mosaic') return 'view_list'
return 'view_module'
}
},
methods: {
...mapMutations(['updateUser']),
change: function (event) {
// If we are on mobile we should close the dropdown.
this.$store.commit('closeHovers')
let user = {...this.user}
user.viewMode = (this.icon === 'view_list') ? 'list' : 'mosaic'
updateUser(user, 'partial').then(() => {
this.updateUser({ viewMode: user.viewMode })
}).catch(this.$showError)
}
}
}
</script>

View File

@@ -1,17 +0,0 @@
<template>
<button @click="upload" :aria-label="$t('buttons.upload')" :title="$t('buttons.upload')" class="action" id="upload-button">
<i class="material-icons">file_upload</i>
<span>{{ $t('buttons.upload') }}</span>
</button>
</template>
<script>
export default {
name: 'upload-button',
methods: {
upload: function (event) {
document.getElementById('upload-input').click()
}
}
}
</script>

View File

@@ -1,143 +0,0 @@
<template>
<form id="editor" :class="req.language">
<div v-if="hasMetadata" id="metadata">
<h2>{{ $t('files.metadata') }}</h2>
</div>
<h2 v-if="hasMetadata">{{ $t('files.body') }}</h2>
</form>
</template>
<script>
import { mapState } from 'vuex'
import CodeMirror from '@/utils/codemirror'
import * as api from '@/utils/api'
import buttons from '@/utils/buttons'
export default {
name: 'editor',
computed: {
...mapState(['req', 'schedule']),
hasMetadata: function () {
return (this.req.metadata !== undefined && this.req.metadata !== null)
}
},
data: function () {
return {
metadata: null,
metalang: null,
content: null
}
},
created () {
window.addEventListener('keydown', this.keyEvent)
document.getElementById('save-button').addEventListener('click', this.save)
let publish = document.getElementById('publish-button')
if (publish !== null) {
publish.addEventListener('click', this.publish)
}
},
beforeDestroy () {
window.removeEventListener('keydown', this.keyEvent)
document.getElementById('save-button').removeEventListener('click', this.save)
let publish = document.getElementById('publish-button')
if (publish !== null) {
publish.removeEventListener('click', this.publish)
}
},
mounted: function () {
if (this.req.content === undefined || this.req.content === null) {
this.req.content = ''
}
// Set up the main content editor.
this.content = CodeMirror(document.getElementById('editor'), {
value: this.req.content,
lineNumbers: (this.req.language !== 'markdown'),
viewportMargin: 500,
autofocus: true,
mode: this.req.language,
theme: (this.req.language === 'markdown') ? 'markdown' : 'ttcn',
lineWrapping: (this.req.language === 'markdown')
})
CodeMirror.autoLoadMode(this.content, this.req.language)
// Prevent of going on if there is no metadata.
if (!this.hasMetadata) {
return
}
this.parseMetadata()
// Set up metadata editor.
this.metadata = CodeMirror(document.getElementById('metadata'), {
value: this.req.metadata,
viewportMargin: Infinity,
lineWrapping: true,
theme: 'markdown',
mode: this.metalang
})
CodeMirror.autoLoadMode(this.metadata, this.metalang)
},
methods: {
// Saves the content when the user presses CTRL-S.
keyEvent (event) {
if (!event.ctrlKey && !event.metaKey) {
return
}
if (String.fromCharCode(event.which).toLowerCase() !== 's') {
return
}
event.preventDefault()
this.save()
},
// Parses the metadata and gets the language in which
// it is written.
parseMetadata () {
if (this.req.metadata.startsWith('{')) {
this.metalang = 'json'
}
if (this.req.metadata.startsWith('---')) {
this.metalang = 'yaml'
}
if (this.req.metadata.startsWith('+++')) {
this.metalang = 'toml'
}
},
// Publishes the file.
publish (event) {
this.save(event, true)
},
// Saves the file.
save (event, regenerate = false) {
let button = regenerate ? 'publish' : 'save'
if (this.schedule !== '') button = 'schedule'
let content = this.content.getValue()
buttons.loading(button)
if (this.hasMetadata) {
content = this.metadata.getValue() + '\n\n' + content
}
api.put(this.$route.path, content, regenerate, this.schedule)
.then(() => {
buttons.success(button)
this.$store.commit('setSchedule', '')
})
.catch(error => {
buttons.done(button)
this.$showError(error)
this.$store.commit('setSchedule', '')
})
}
}
}
</script>

View File

@@ -1,381 +0,0 @@
<template>
<div v-if="(req.numDirs + req.numFiles) == 0">
<h2 class="message">
<i class="material-icons">sentiment_dissatisfied</i>
<span>{{ $t('files.lonely') }}</span>
</h2>
<input style="display:none" type="file" id="upload-input" @change="uploadInput($event)" multiple>
</div>
<div v-else id="listing"
:class="user.viewMode"
@dragenter="dragEnter"
@dragend="dragEnd">
<div>
<div class="item header">
<div></div>
<div>
<p :class="{ active: nameSorted }" class="name"
role="button"
tabindex="0"
@click="sort('name')"
:title="$t('files.sortByName')"
:aria-label="$t('files.sortByName')">
<span>{{ $t('files.name') }}</span>
<i class="material-icons">{{ nameIcon }}</i>
</p>
<p :class="{ active: sizeSorted }" class="size"
role="button"
tabindex="0"
@click="sort('size')"
:title="$t('files.sortBySize')"
:aria-label="$t('files.sortBySize')">
<span>{{ $t('files.size') }}</span>
<i class="material-icons">{{ sizeIcon }}</i>
</p>
<p :class="{ active: modifiedSorted }" class="modified"
role="button"
tabindex="0"
@click="sort('modified')"
:title="$t('files.sortByLastModified')"
:aria-label="$t('files.sortByLastModified')">
<span>{{ $t('files.lastModified') }}</span>
<i class="material-icons">{{ modifiedIcon }}</i>
</p>
</div>
</div>
</div>
<h2 v-if="req.numDirs > 0">{{ $t('files.folders') }}</h2>
<div v-if="req.numDirs > 0">
<item v-for="(item, index) in req.items"
v-if="item.isDir"
:key="base64(item.name)"
v-bind:index="index"
v-bind:name="item.name"
v-bind:isDir="item.isDir"
v-bind:url="item.url"
v-bind:modified="item.modified"
v-bind:type="item.type"
v-bind:size="item.size">
</item>
</div>
<h2 v-if="req.numFiles > 0">{{ $t('files.files') }}</h2>
<div v-if="req.numFiles > 0">
<item v-for="(item, index) in req.items"
v-if="!item.isDir"
:key="base64(item.name)"
v-bind:index="index"
v-bind:name="item.name"
v-bind:isDir="item.isDir"
v-bind:url="item.url"
v-bind:modified="item.modified"
v-bind:type="item.type"
v-bind:size="item.size">
</item>
</div>
<input style="display:none" type="file" id="upload-input" @change="uploadInput($event)" multiple>
<div v-show="$store.state.multiple" :class="{ active: $store.state.multiple }" id="multiple-selection">
<p>{{ $t('files.multipleSelectionEnabled') }}</p>
<div @click="$store.commit('multiple', false)" tabindex="0" role="button" :title="$t('files.clear')" :aria-label="$t('files.clear')" class="action">
<i class="material-icons">clear</i>
</div>
</div>
</div>
</template>
<script>
import {mapState} from 'vuex'
import Item from './ListingItem'
import css from '@/utils/css'
import * as api from '@/utils/api'
import buttons from '@/utils/buttons'
export default {
name: 'listing',
components: { Item },
computed: {
...mapState(['req', 'selected', 'user']),
nameSorted () {
return (this.req.sort === 'name')
},
sizeSorted () {
return (this.req.sort === 'size')
},
modifiedSorted () {
return (this.req.sort === 'modified')
},
ascOrdered () {
return (this.req.order === 'asc')
},
nameIcon () {
if (this.nameSorted && !this.ascOrdered) {
return 'arrow_upward'
}
return 'arrow_downward'
},
sizeIcon () {
if (this.sizeSorted && this.ascOrdered) {
return 'arrow_downward'
}
return 'arrow_upward'
},
modifiedIcon () {
if (this.modifiedSorted && this.ascOrdered) {
return 'arrow_downward'
}
return 'arrow_upward'
}
},
mounted: function () {
// Check the columns size for the first time.
this.resizeEvent()
// Add the needed event listeners to the window and document.
window.addEventListener('keydown', this.keyEvent)
window.addEventListener('resize', this.resizeEvent)
document.addEventListener('dragover', this.preventDefault)
document.addEventListener('drop', this.drop)
},
beforeDestroy () {
// Remove event listeners before destroying this page.
window.removeEventListener('keydown', this.keyEvent)
window.removeEventListener('resize', this.resizeEvent)
document.removeEventListener('dragover', this.preventDefault)
document.removeEventListener('drop', this.drop)
},
methods: {
base64: function (name) {
return window.btoa(unescape(encodeURIComponent(name)))
},
keyEvent (event) {
if (!event.ctrlKey && !event.metaKey) {
return
}
let key = String.fromCharCode(event.which).toLowerCase()
switch (key) {
case 'f':
event.preventDefault()
this.$store.commit('showHover', 'search')
break
case 'c':
case 'x':
this.copyCut(event, key)
break
case 'v':
this.paste(event)
break
}
},
preventDefault (event) {
// Wrapper around prevent default.
event.preventDefault()
},
copyCut (event, key) {
event.preventDefault()
let items = []
for (let i of this.selected) {
items.push({
from: this.req.items[i].url,
name: encodeURIComponent(this.req.items[i].name)
})
}
this.$store.commit('updateClipboard', {
key: key,
items: items
})
},
paste (event) {
if (event.target.tagName.toLowerCase() === 'input') {
return
}
event.preventDefault()
let items = []
for (let item of this.$store.state.clipboard.items) {
items.push({
from: item.from,
to: this.$route.path + item.name
})
}
if (this.$store.state.clipboard.key === 'x') {
api.move(items).then(() => {
this.$store.commit('setReload', true)
}).catch(this.$showError)
return
}
api.copy(items).then(() => {
this.$store.commit('setReload', true)
}).catch(this.$showError)
},
resizeEvent () {
// Update the columns size based on the window width.
let columns = Math.floor(document.querySelector('main').offsetWidth / 300)
let items = css(['#listing.mosaic .item', '.mosaic#listing .item'])
if (columns === 0) columns = 1
items.style.width = `calc(${100 / columns}% - 1em)`
},
dragEnter (event) {
// When the user starts dragging an item, put every
// file on the listing with 50% opacity.
let items = document.getElementsByClassName('item')
Array.from(items).forEach(file => {
file.style.opacity = 0.5
})
},
dragEnd (event) {
this.resetOpacity()
},
drop: function (event) {
event.preventDefault()
this.resetOpacity()
let dt = event.dataTransfer
let files = dt.files
let el = event.target
if (files.length <= 0) return
for (let i = 0; i < 5; i++) {
if (el !== null && !el.classList.contains('item')) {
el = el.parentElement
}
}
let base = ''
if (el !== null && el.classList.contains('item') && el.dataset.dir === 'true') {
base = el.querySelector('.name').innerHTML + '/'
}
if (base !== '') {
api.fetch(this.$route.path + base)
.then(req => {
this.checkConflict(files, req.items, base)
})
.catch(this.$showError)
return
}
this.checkConflict(files, this.req.items, base)
},
checkConflict (files, items, base) {
if (typeof items === 'undefined' || items === null) {
items = []
}
let conflict = false
for (let i = 0; i < files.length; i++) {
let res = items.findIndex(function hasConflict (element) {
return (element.name === this)
}, files[i].name)
if (res >= 0) {
conflict = true
break
}
}
if (!conflict) {
this.handleFiles(files, base)
return
}
this.$store.commit('showHover', {
prompt: 'replace',
confirm: (event) => {
event.preventDefault()
this.$store.commit('closeHovers')
this.handleFiles(files, base, true)
}
})
},
uploadInput (event) {
this.checkConflict(event.currentTarget.files, this.req.items, '')
},
resetOpacity () {
let items = document.getElementsByClassName('item')
Array.from(items).forEach(file => {
file.style.opacity = 1
})
},
handleFiles (files, base, overwrite = false) {
buttons.loading('upload')
let promises = []
let progress = new Array(files.length).fill(0)
let onupload = (id) => (event) => {
progress[id] = (event.loaded / event.total) * 100
let sum = 0
for (let i = 0; i < progress.length; i++) {
sum += progress[i]
}
this.$store.commit('setProgress', Math.ceil(sum / progress.length))
}
for (let i = 0; i < files.length; i++) {
let file = files[i]
promises.push(api.post(this.$route.path + base + file.name, file, overwrite, onupload(i)))
}
let finish = () => {
buttons.success('upload')
this.$store.commit('setProgress', 0)
}
Promise.all(promises)
.then(() => {
finish()
this.$store.commit('setReload', true)
})
.catch(error => {
finish()
this.$showError(error)
})
return false
},
sort (sort) {
let order = 'desc'
if (sort === 'name') {
if (this.nameIcon === 'arrow_upward') {
order = 'asc'
}
} else if (sort === 'size') {
if (this.sizeIcon === 'arrow_upward') {
order = 'asc'
}
} else if (sort === 'modified') {
if (this.modifiedIcon === 'arrow_upward') {
order = 'asc'
}
}
let path = this.$store.state.baseURL
if (path === '') path = '/'
document.cookie = `sort=${sort}; max-age=31536000; path=${path}`
document.cookie = `order=${order}; max-age=31536000; path=${path}`
this.$store.commit('setReload', true)
}
}
}
</script>

View File

@@ -1,158 +0,0 @@
<template>
<div class="item"
role="button"
tabindex="0"
draggable="true"
@dragstart="dragStart"
@dragover="dragOver"
@drop="drop"
@click="click"
@dblclick="open"
@touchstart="touchstart"
:data-dir="isDir"
:aria-label="name"
:aria-selected="isSelected">
<div>
<i class="material-icons">{{ icon }}</i>
</div>
<div>
<p class="name">{{ name }}</p>
<p v-if="isDir" class="size" data-order="-1">&mdash;</p>
<p v-else class="size" :data-order="humanSize()">{{ humanSize() }}</p>
<p class="modified">
<time :datetime="modified">{{ humanTime() }}</time>
</p>
</div>
</div>
</template>
<script>
import { mapMutations, mapGetters, mapState } from 'vuex'
import filesize from 'filesize'
import moment from 'moment'
import * as api from '@/utils/api'
export default {
name: 'item',
data: function () {
return {
touches: 0
}
},
props: ['name', 'isDir', 'url', 'type', 'size', 'modified', 'index'],
computed: {
...mapState(['selected', 'req']),
...mapGetters(['selectedCount']),
isSelected () {
return (this.selected.indexOf(this.index) !== -1)
},
icon () {
if (this.isDir) return 'folder'
if (this.type === 'image') return 'insert_photo'
if (this.type === 'audio') return 'volume_up'
if (this.type === 'video') return 'movie'
return 'insert_drive_file'
}
},
methods: {
...mapMutations(['addSelected', 'removeSelected', 'resetSelected']),
humanSize: function () {
return filesize(this.size)
},
humanTime: function () {
return moment(this.modified).fromNow()
},
dragStart: function (event) {
if (this.selectedCount === 0) {
this.addSelected(this.index)
return
}
if (!this.isSelected) {
this.resetSelected()
this.addSelected(this.index)
}
},
dragOver: function (event) {
if (!this.isDir) return
event.preventDefault()
let el = event.target
for (let i = 0; i < 5; i++) {
if (!el.classList.contains('item')) {
el = el.parentElement
}
}
el.style.opacity = 1
},
drop: function (event) {
if (!this.isDir) return
event.preventDefault()
if (this.selectedCount === 0) return
let items = []
for (let i of this.selected) {
items.push({
from: this.req.items[i].url,
to: this.url + encodeURIComponent(this.req.items[i].name)
})
}
api.move(items)
.then(() => {
this.$store.commit('setReload', true)
})
.catch(this.$showError)
},
click: function (event) {
if (this.selectedCount !== 0) event.preventDefault()
if (this.$store.state.selected.indexOf(this.index) !== -1) {
this.removeSelected(this.index)
return
}
if (event.shiftKey && this.selected.length === 1) {
let fi = 0
let la = 0
if (this.index > this.selected[0]) {
fi = this.selected[0] + 1
la = this.index
} else {
fi = this.index
la = this.selected[0] - 1
}
for (; fi <= la; fi++) {
this.addSelected(fi)
}
return
}
if (!event.ctrlKey && !this.$store.state.multiple) this.resetSelected()
this.addSelected(this.index)
},
touchstart (event) {
setTimeout(() => {
this.touches = 0
}, 300)
this.touches++
if (this.touches > 1) {
this.open()
}
},
open: function (event) {
this.$router.push({path: this.url})
}
}
}
</script>

View File

@@ -1,139 +0,0 @@
<template>
<div id="previewer">
<div class="bar">
<button @click="back" class="action" :title="$t('files.closePreview')" :aria-label="$t('files.closePreview')" id="close">
<i class="material-icons">close</i>
</button>
<rename-button v-if="allowEdit()"></rename-button>
<delete-button v-if="allowEdit()"></delete-button>
<download-button></download-button>
<info-button></info-button>
</div>
<button class="action" @click="prev" v-show="hasPrevious" :aria-label="$t('buttons.previous')" :title="$t('buttons.previous')">
<i class="material-icons">chevron_left</i>
</button>
<button class="action" @click="next" v-show="hasNext" :aria-label="$t('buttons.next')" :title="$t('buttons.next')">
<i class="material-icons">chevron_right</i>
</button>
<div class="preview">
<img v-if="req.type == 'image'" :src="raw()">
<audio v-else-if="req.type == 'audio'" :src="raw()" autoplay controls></audio>
<video v-else-if="req.type == 'video'" :src="raw()" autoplay controls>
Sorry, your browser doesn't support embedded videos,
but don't worry, you can <a :href="download()">download it</a>
and watch it with your favorite video player!
</video>
<object v-else-if="req.extension == '.pdf'" class="pdf" :data="raw()"></object>
<a v-else-if="req.type == 'blob'" :href="download()">
<h2 class="message">{{ $t('buttons.download') }} <i class="material-icons">file_download</i></h2>
</a>
<pre v-else >{{ req.content }}</pre>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
import url from '@/utils/url'
import * as api from '@/utils/api'
import InfoButton from '@/components/buttons/Info'
import DeleteButton from '@/components/buttons/Delete'
import RenameButton from '@/components/buttons/Rename'
import DownloadButton from '@/components/buttons/Download'
export default {
name: 'preview',
components: {
InfoButton,
DeleteButton,
RenameButton,
DownloadButton
},
data: function () {
return {
previousLink: '',
nextLink: '',
listing: null
}
},
computed: {
...mapState(['req', 'oldReq']),
hasPrevious () {
return (this.previousLink !== '')
},
hasNext () {
return (this.nextLink !== '')
}
},
mounted () {
window.addEventListener('keyup', this.key)
api.fetch(url.removeLastDir(this.$route.path))
.then(req => {
this.listing = req
this.updateLinks()
})
.catch(this.$showError)
},
beforeDestroy () {
window.removeEventListener('keyup', this.key)
},
methods: {
download () {
let url = `${this.$store.state.baseURL}/api/download`
url += this.req.url.slice(6)
return url
},
raw () {
return `${this.download()}?&inline=true`
},
back (event) {
let uri = url.removeLastDir(this.$route.path) + '/'
this.$router.push({ path: uri })
},
prev () {
this.$router.push({ path: this.previousLink })
},
next () {
this.$router.push({ path: this.nextLink })
},
key (event) {
event.preventDefault()
if (event.which === 13 || event.which === 39) { // right arrow
if (this.hasNext) this.next()
} else if (event.which === 37) { // left arrow
if (this.hasPrevious) this.prev()
}
},
updateLinks () {
let pos = null
for (let i = 0; i < this.listing.items.length; i++) {
if (this.listing.items[i].name === this.req.name) {
pos = i
break
}
}
if (pos === null) {
return
}
if (pos !== 0) {
this.previousLink = this.listing.items[pos - 1].url
}
if (pos !== this.listing.items.length - 1) {
this.nextLink = this.listing.items[pos + 1].url
}
},
allowEdit (event) {
return this.$store.state.user.allowEdit
}
}
}
</script>

View File

@@ -1,69 +0,0 @@
<template>
<div class="card floating">
<div class="card-title">
<h2>{{ $t('prompts.copy') }}</h2>
</div>
<div class="card-content">
<p>{{ $t('prompts.copyMessage') }}</p>
<file-list @update:selected="val => dest = val"></file-list>
</div>
<div class="card-action">
<button class="cancel flat"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
<button class="flat"
@click="copy"
:disabled="$route.path === dest"
:aria-label="$t('buttons.copy')"
:title="$t('buttons.copy')">{{ $t('buttons.copy') }}</button>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
import FileList from './FileList'
import * as api from '@/utils/api'
import buttons from '@/utils/buttons'
export default {
name: 'copy',
components: { FileList },
data: function () {
return {
current: window.location.pathname,
dest: null
}
},
computed: mapState(['req', 'selected']),
methods: {
copy: function (event) {
event.preventDefault()
buttons.loading('copy')
let items = []
// Create a new promise for each file.
for (let item of this.selected) {
items.push({
from: this.req.items[item].url,
to: this.dest + encodeURIComponent(this.req.items[item].name)
})
}
// Execute the promises.
api.copy(items)
.then(() => {
buttons.success('copy')
this.$router.push({ path: this.dest })
})
.catch(error => {
buttons.done('copy')
this.$showError(error)
})
}
}
}
</script>

View File

@@ -1,80 +0,0 @@
<template>
<div class="card floating">
<div class="card-content">
<p v-if="req.kind !== 'listing'">{{ $t('prompts.deleteMessageSingle') }}</p>
<p v-else>{{ $t('prompts.deleteMessageMultiple', { count: selectedCount}) }}</p>
</div>
<div class="card-action">
<button @click="$store.commit('closeHovers')"
class="flat cancel"
:aria-label="$t('buttons.cancel')"
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
<button @click="submit"
class="flat"
:aria-label="$t('buttons.delete')"
:title="$t('buttons.delete')">{{ $t('buttons.delete') }}</button>
</div>
</div>
</template>
<script>
import {mapGetters, mapMutations, mapState} from 'vuex'
import { remove } from '@/utils/api'
import url from '@/utils/url'
import buttons from '@/utils/buttons'
export default {
name: 'delete',
computed: {
...mapGetters(['selectedCount']),
...mapState(['req', 'selected'])
},
methods: {
...mapMutations(['closeHovers']),
submit: function (event) {
this.closeHovers()
buttons.loading('delete')
// If we are not on a listing, delete the current
// opened file.
if (this.req.kind !== 'listing') {
remove(this.$route.path)
.then(() => {
buttons.success('delete')
this.$router.push({ path: url.removeLastDir(this.$route.path) + '/' })
})
.catch(error => {
buttons.done('delete')
this.$showError(error)
})
return
}
if (this.selectedCount === 0) {
// This shouldn't happen...
return
}
// Create the promises array and fill it with
// the delete request for every selected file.
let promises = []
for (let index of this.selected) {
promises.push(remove(this.req.items[index].url))
}
Promise.all(promises)
.then(() => {
buttons.success('delete')
this.$store.commit('setReload', true)
})
.catch(error => {
buttons.done('delete')
this.$store.commit('setReload', true)
this.$showError(error)
})
}
}
}
</script>

View File

@@ -1,47 +0,0 @@
<template>
<div class="card floating" id="download">
<div class="card-title">
<h2>{{ $t('prompts.download') }}</h2>
</div>
<div class="card-content">
<p>{{ $t('prompts.downloadMessage') }}</p>
<button class="block cancel" @click="download('zip')" autofocus>zip</button>
<button class="block cancel" @click="download('tar')" autofocus>tar</button>
<button class="block cancel" @click="download('targz')" autofocus>tar.gz</button>
<button class="block cancel" @click="download('tarbz2')" autofocus>tar.bz2</button>
<button class="block cancel" @click="download('tarxz')" autofocus>tar.xz</button>
</div>
</div>
</template>
<script>
import {mapGetters, mapState} from 'vuex'
import * as api from '@/utils/api'
export default {
name: 'download',
computed: {
...mapState(['selected', 'req']),
...mapGetters(['selectedCount'])
},
methods: {
download: function (format) {
if (this.selectedCount === 0) {
api.download(format, this.$route.path)
} else {
let files = []
for (let i of this.selected) {
files.push(this.req.items[i].url)
}
api.download(format, ...files)
}
this.$store.commit('closeHovers')
}
}
}
</script>

View File

@@ -1,140 +0,0 @@
<template>
<div>
<ul class="file-list">
<li @click="select"
@touchstart="touchstart"
@dblclick="next"
role="button"
tabindex="0"
:aria-label="item.name"
:aria-selected="selected == item.url"
:key="item.name" v-for="item in items"
:data-url="item.url">{{ item.name }}</li>
</ul>
<p>{{ $t('prompts.currentlyNavigating') }} <code>{{ nav }}</code>.</p>
</div>
</template>
<script>
import { mapState } from 'vuex'
import url from '@/utils/url'
import * as api from '@/utils/api'
export default {
name: 'file-list',
data: function () {
return {
items: [],
touches: {
id: '',
count: 0
},
selected: null,
current: window.location.pathname
}
},
computed: {
...mapState(['req']),
nav () {
return decodeURIComponent(this.current)
}
},
mounted () {
// If we're showing this on a listing,
// we can use the current request object
// to fill the move options.
if (this.req.kind === 'listing') {
this.fillOptions(this.req)
return
}
// Otherwise, we must be on a preview or editor
// so we fetch the data from the previous directory.
api.fetch(url.removeLastDir(this.$route.path))
.then(this.fillOptions)
.catch(this.$showError)
},
methods: {
fillOptions (req) {
// Sets the current path and resets
// the current items.
this.current = req.url
this.items = []
this.$emit('update:selected', this.current)
// If the path isn't the root path,
// show a button to navigate to the previous
// directory.
if (req.url !== '/files/') {
this.items.push({
name: '..',
url: url.removeLastDir(req.url) + '/'
})
}
// If this folder is empty, finish here.
if (req.items === null) return
// Otherwise we add every directory to the
// move options.
for (let item of req.items) {
if (!item.isDir) continue
this.items.push({
name: item.name,
url: item.url
})
}
},
next: function (event) {
// Retrieves the URL of the directory the user
// just clicked in and fill the options with its
// content.
let uri = event.currentTarget.dataset.url
api.fetch(uri)
.then(this.fillOptions)
.catch(this.$showError)
},
touchstart (event) {
let url = event.currentTarget.dataset.url
// In 300 milliseconds, we shall reset the count.
setTimeout(() => {
this.touches.count = 0
}, 300)
// If the element the user is touching
// is different from the last one he touched,
// reset the count.
if (this.touches.id !== url) {
this.touches.id = url
this.touches.count = 1
return
}
this.touches.count++
// If there is more than one touch already,
// open the next screen.
if (this.touches.count > 1) {
this.next(event)
}
},
select: function (event) {
// If the element is already selected, unselect it.
if (this.selected === event.currentTarget.dataset.url) {
this.selected = null
this.$emit('update:selected', this.current)
return
}
// Otherwise select the element.
this.selected = event.currentTarget.dataset.url
this.$emit('update:selected', this.selected)
}
}
}
</script>

View File

@@ -1,34 +0,0 @@
<template>
<div class="card floating help">
<div class="card-title">
<h2>{{ $t('help.help') }}</h2>
</div>
<div class="card-content">
<ul>
<li><strong>F1</strong> - {{ $t('help.f1') }}</li>
<li><strong>F2</strong> - {{ $t('help.f2') }}</li>
<li><strong>DEL</strong> - {{ $t('help.del') }}</li>
<li><strong>ESC</strong> - {{ $t('help.esc') }}</li>
<li><strong>CTRL + S</strong> - {{ $t('help.ctrl.s') }}</li>
<li><strong>CTRL + F</strong> - {{ $t('help.ctrl.f') }}</li>
<li><strong>CTRL + Click</strong> - {{ $t('help.ctrl.click') }}</li>
<li><strong>Click</strong> - {{ $t('help.click') }}</li>
<li><strong>Double click</strong> - {{ $t('help.doubleClick') }}</li>
</ul>
</div>
<div class="card-action">
<button type="submit"
@click="$store.commit('closeHovers')"
class="flat"
:aria-label="$t('buttons.ok')"
:title="$t('buttons.ok')">{{ $t('buttons.ok') }}</button>
</div>
</div>
</template>
<script>
export default {name: 'help'}
</script>

View File

@@ -1,122 +0,0 @@
<template>
<div class="card floating">
<div class="card-title">
<h2>{{ $t('prompts.fileInfo') }}</h2>
</div>
<div class="card-content">
<p v-if="selected.length > 1">{{ $t('prompts.filesSelected', { count: selected.length }) }}</p>
<p v-if="selected.length < 2"><strong>{{ $t('prompts.displayName') }}</strong> {{ name() }}</p>
<p><strong>{{ $t('prompts.size') }}:</strong> <span id="content_length"></span>{{ humanSize() }}</p>
<p v-if="selected.length < 2"><strong>{{ $t('prompts.lastModified') }}:</strong> {{ humanTime() }}</p>
<template v-if="dir() && selected.length === 0">
<p><strong>{{ $t('prompts.numberFiles') }}:</strong> {{ req.numFiles }}</p>
<p><strong>{{ $t('prompts.numberDirs') }}:</strong> {{ req.numDirs }}</p>
</template>
<template v-if="!dir()">
<p><strong>MD5:</strong> <code><a @click="checksum($event, 'md5')">{{ $t('prompts.show') }}</a></code></p>
<p><strong>SHA1:</strong> <code><a @click="checksum($event, 'sha1')">{{ $t('prompts.show') }}</a></code></p>
<p><strong>SHA256:</strong> <code><a @click="checksum($event, 'sha256')">{{ $t('prompts.show') }}</a></code></p>
<p><strong>SHA512:</strong> <code><a @click="checksum($event, 'sha512')">{{ $t('prompts.show') }}</a></code></p>
</template>
</div>
<div class="card-action">
<button type="submit"
@click="$store.commit('closeHovers')"
class="flat"
:aria-label="$t('buttons.ok')"
:title="$t('buttons.ok')">{{ $t('buttons.ok') }}</button>
</div>
</div>
</template>
<script>
import {mapState, mapGetters} from 'vuex'
import filesize from 'filesize'
import moment from 'moment'
import * as api from '@/utils/api'
export default {
name: 'info',
computed: {
...mapState(['req', 'selected']),
...mapGetters(['selectedCount'])
},
methods: {
humanSize: function () {
// If there are no files selected or this is not a listing
// show the human file size of the current request.
if (this.selectedCount === 0 || this.req.kind !== 'listing') {
return filesize(this.req.size)
}
// Otherwise, sum the sizes of each selected file and returns
// its human form.
var sum = 0
for (let i = 0; i < this.selectedCount; i++) {
sum += this.req.items[this.selected[i]].size
}
return filesize(sum)
},
humanTime: function () {
// If there are no selected files, return the current request
// modified time.
if (this.selectedCount === 0) {
return moment(this.req.modified).fromNow()
}
// Otherwise return the modified time of the first item
// that is selected since this should not appear when
// there is more than one file selected.
return moment(this.req.items[this.selected[0]]).fromNow()
},
name: function () {
// Return the name of the current opened file if there
// are no selected files.
if (this.selectedCount === 0) {
return this.req.name
}
// Otherwise, just return the name of the selected file.
// This field won't show when there is more than one
// file selected.
return this.req.items[this.selected[0]].name
},
dir: function () {
if (this.selectedCount > 1) {
// Don't show when multiple selected.
return true
}
if (this.selectedCount === 0) {
return this.req.isDir
}
return this.req.items[this.selected[0]].isDir
},
checksum: function (event, hash) {
// Gets the checksum of the current selected or
// opened file. Doesn't work for directories.
event.preventDefault()
let link
if (this.selectedCount) {
link = this.req.items[this.selected[0]].url
} else {
link = this.$route.path
}
api.checksum(link, hash)
.then((hash) => { event.target.innerHTML = hash })
.catch(this.$showError)
}
}
}
</script>

View File

@@ -1,70 +0,0 @@
<template>
<div class="card floating">
<div class="card-title">
<h2>{{ $t('prompts.move') }}</h2>
</div>
<div class="card-content">
<file-list @update:selected="val => dest = val"></file-list>
</div>
<div class="card-action">
<button class="flat cancel"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
<button class="flat"
@click="move"
:disabled="$route.path === dest"
:aria-label="$t('buttons.move')"
:title="$t('buttons.move')">{{ $t('buttons.move') }}</button>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
import FileList from './FileList'
import * as api from '@/utils/api'
import buttons from '@/utils/buttons'
export default {
name: 'move',
components: { FileList },
data: function () {
return {
current: window.location.pathname,
dest: null
}
},
computed: mapState(['req', 'selected']),
methods: {
move: function (event) {
event.preventDefault()
buttons.loading('move')
let items = []
// Create a new promise for each file.
for (let item of this.selected) {
items.push({
from: this.req.items[item].url,
to: this.dest + encodeURIComponent(this.req.items[item].name)
})
}
// Execute the promises.
api.move(items)
.then(() => {
buttons.success('move')
this.$router.push({ path: this.dest })
})
.catch(error => {
buttons.done('move')
this.$showError(error)
})
event.preventDefault()
}
}
}
</script>

View File

@@ -1,76 +0,0 @@
<template>
<div class="card floating">
<div class="card-title">
<h2>{{ $t('prompts.newFile') }}</h2>
</div>
<div class="card-content">
<p>{{ $t('prompts.newArchetype') }}</p>
<input autofocus type="text" @keyup.enter="submit" v-model.trim="name">
<input type="text" @keyup.enter="submit" v-model.trim="archetype">
</div>
<div class="card-action">
<button class="flat cancel"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
<button class="flat"
@click="submit"
:aria-label="$t('buttons.create')"
:title="$t('buttons.create')">{{ $t('buttons.create') }}</button>
</div>
</div>
</template>
<script>
import { removePrefix } from '@/utils/api'
export default {
name: 'new-archetype',
data: function () {
return {
name: '',
archetype: 'default'
}
},
methods: {
submit: function (event) {
event.preventDefault()
this.$store.commit('closeHovers')
this.new('/' + this.name, this.archetype)
.then((url) => {
this.$router.push({ path: url })
})
.catch(this.$showError)
},
new (url, type) {
url = removePrefix(url)
if (!url.endsWith('.md') && !url.endsWith('.markdown')) {
url += '.markdown'
}
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('POST', `${this.$store.state.baseURL}/api/resource${url}`, true)
if (!this.$store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${this.$store.state.jwt}`)
request.setRequestHeader('Archetype', encodeURIComponent(type))
request.onload = () => {
if (request.status === 200) {
resolve(request.getResponseHeader('Location'))
} else {
reject(request.responseText)
}
}
request.onerror = (error) => reject(error)
request.send()
})
}
}
}
</script>

View File

@@ -1,60 +0,0 @@
<template>
<div class="card floating">
<div class="card-title">
<h2>{{ $t('prompts.newDir') }}</h2>
</div>
<div class="card-content">
<p>{{ $t('prompts.newDirMessage') }}</p>
<input autofocus type="text" @keyup.enter="submit" v-model.trim="name">
</div>
<div class="card-action">
<button class="cancel flat"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
<button class="flat"
:aria-label="$t('buttons.create')"
:title="$t('buttons.create')"
@click="submit">{{ $t('buttons.create') }}</button>
</div>
</div>
</template>
<script>
import url from '@/utils/url'
import * as api from '@/utils/api'
export default {
name: 'new-dir',
data: function () {
return {
name: ''
}
},
methods: {
submit: function (event) {
event.preventDefault()
if (this.new === '') return
// Build the path of the new directory.
let uri = this.$route.path
if (this.$store.state.req.kind !== 'listing') {
uri = url.removeLastDir(uri) + '/'
}
uri += this.name + '/'
uri = uri.replace('//', '/')
api.post(uri)
.then(() => { this.$router.push({ path: uri }) })
.catch(this.$showError)
// Close the prompt
this.$store.commit('closeHovers')
}
}
}
</script>

View File

@@ -1,61 +0,0 @@
<template>
<div class="card floating">
<div class="card-title">
<h2>{{ $t('prompts.newFile') }}</h2>
</div>
<div class="card-content">
<p>{{ $t('prompts.newFileMessage') }}</p>
<input autofocus type="text" @keyup.enter="submit" v-model.trim="name">
</div>
<div class="card-action">
<button class="cancel flat"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
<button class="flat"
@click="submit"
:aria-label="$t('buttons.create')"
:title="$t('buttons.create')">{{ $t('buttons.create') }}</button>
</div>
</div>
</template>
<script>
import url from '@/utils/url'
import * as api from '@/utils/api'
export default {
name: 'new-file',
data: function () {
return {
name: ''
}
},
methods: {
submit: function (event) {
event.preventDefault()
if (this.new === '') return
// Build the path of the new file.
let uri = this.$route.path
if (this.$store.state.req.kind !== 'listing') {
uri = url.removeLastDir(uri) + '/'
}
uri += this.name
uri = uri.replace('//', '/')
// Create the new file.
api.post(uri)
.then(() => { this.$router.push({ path: uri }) })
.catch(this.$showError)
// Close the prompt.
this.$store.commit('closeHovers')
}
}
}
</script>

View File

@@ -1,87 +0,0 @@
<template>
<div>
<help v-if="showHelp" ></help>
<download v-else-if="showDownload"></download>
<new-file v-else-if="showNewFile"></new-file>
<new-dir v-else-if="showNewDir"></new-dir>
<rename v-else-if="showRename"></rename>
<delete v-else-if="showDelete"></delete>
<info v-else-if="showInfo"></info>
<move v-else-if="showMove"></move>
<copy v-else-if="showCopy"></copy>
<replace v-else-if="showReplace"></replace>
<schedule v-else-if="show === 'schedule'"></schedule>
<new-archetype v-else-if="show === 'new-archetype'"></new-archetype>
<share v-else-if="show === 'share'"></share>
<div v-show="showOverlay" @click="resetPrompts" class="overlay"></div>
</div>
</template>
<script>
import Help from './Help'
import Info from './Info'
import Delete from './Delete'
import Rename from './Rename'
import Download from './Download'
import Move from './Move'
import Copy from './Copy'
import NewFile from './NewFile'
import NewDir from './NewDir'
import NewArchetype from './NewArchetype'
import Replace from './Replace'
import Schedule from './Schedule'
import Share from './Share'
import { mapState } from 'vuex'
import buttons from '@/utils/buttons'
import * as api from '@/utils/api'
export default {
name: 'prompts',
components: {
Info,
Delete,
NewArchetype,
Schedule,
Rename,
Download,
Move,
Copy,
Share,
NewFile,
NewDir,
Help,
Replace
},
data: function () {
return {
pluginData: {
api,
buttons,
'store': this.$store,
'router': this.$router
}
}
},
computed: {
...mapState(['show', 'plugins']),
showInfo: function () { return this.show === 'info' },
showHelp: function () { return this.show === 'help' },
showDelete: function () { return this.show === 'delete' },
showRename: function () { return this.show === 'rename' },
showMove: function () { return this.show === 'move' },
showCopy: function () { return this.show === 'copy' },
showNewFile: function () { return this.show === 'newFile' },
showNewDir: function () { return this.show === 'newDir' },
showDownload: function () { return this.show === 'download' },
showReplace: function () { return this.show === 'replace' },
showOverlay: function () {
return (this.show !== null && this.show !== 'search' && this.show !== 'more')
}
},
methods: {
resetPrompts () {
this.$store.commit('closeHovers')
}
}
}
</script>

View File

@@ -1,84 +0,0 @@
<template>
<div class="card floating">
<div class="card-title">
<h2>{{ $t('prompts.rename') }}</h2>
</div>
<div class="card-content">
<p>{{ $t('prompts.renameMessage') }} <code>{{ oldName() }}</code>:</p>
<input autofocus type="text" @keyup.enter="submit" v-model.trim="name">
</div>
<div class="card-action">
<button class="cancel flat"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
<button @click="submit"
class="flat"
type="submit"
:aria-label="$t('buttons.rename')"
:title="$t('buttons.rename')">{{ $t('buttons.rename') }}</button>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
import url from '@/utils/url'
import * as api from '@/utils/api'
export default {
name: 'rename',
data: function () {
return {
name: ''
}
},
computed: mapState(['req', 'selected', 'selectedCount']),
methods: {
cancel: function (event) {
this.$store.commit('closeHovers')
},
oldName: function () {
// Get the current name of the file we are editing.
if (this.req.kind !== 'listing') {
return this.req.name
}
if (this.selectedCount === 0 || this.selectedCount > 1) {
// This shouldn't happen.
return
}
return this.req.items[this.selected[0]].name
},
submit: function (event) {
let oldLink = ''
let newLink = ''
if (this.req.kind !== 'listing') {
oldLink = this.req.url
} else {
oldLink = this.req.items[this.selected[0]].url
}
this.name = encodeURIComponent(this.name)
newLink = url.removeLastDir(oldLink) + '/' + this.name
api.move([{ from: oldLink, to: newLink }])
.then(() => {
if (this.req.kind !== 'listing') {
this.$router.push({ path: newLink })
return
}
this.$store.commit('setReload', true)
}).catch(error => {
this.$showError(error)
})
this.$store.commit('closeHovers')
}
}
}
</script>

View File

@@ -1,31 +0,0 @@
<template>
<div class="card floating">
<div class="card-title">
<h2>{{ $t('prompts.replace') }}</h2>
</div>
<div class="card-content">
<p>{{ $t('prompts.replaceMessage') }}</p>
</div>
<div class="card-action">
<button class="flat cancel"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
<button class="flat"
@click="showConfirm"
:aria-label="$t('buttons.replace')"
:title="$t('buttons.replace')">{{ $t('buttons.replace') }}</button>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'replace',
computed: mapState(['showConfirm'])
}
</script>

View File

@@ -1,47 +0,0 @@
<template>
<div class="card floating">
<div class="card-title">
<h2>{{ $t('prompts.schedule') }}</h2>
</div>
<div class="card-content">
<p>{{ $t('prompts.scheduleMessage') }}</p>
<input autofocus type="datetime-local" v-model="date">
</div>
<div class="card-action">
<button class="cancel flat"
@click="close"
:aria-label="$t('buttons.cancel')"
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
<button class="falt"
@click="submit"
:aria-label="$t('buttons.schedule')"
:title="$t('buttons.schedule')">{{ $t('buttons.schedule') }}</button>
</div>
</div>
</template>
<script>
export default {
name: 'schedule',
data: function () {
return {
date: ''
}
},
methods: {
close () {
this.$store.commit('closeHovers')
},
submit: function (event) {
event.preventDefault()
if (this.date === '') return
this.close()
this.$store.commit('setSchedule', this.date)
document.getElementById('save-button').click()
}
}
}
</script>

View File

@@ -1,162 +0,0 @@
<template>
<div class="card floating" id="share">
<div class="card-title">
<h2>{{ $t('buttons.share') }}</h2>
</div>
<div class="card-content">
<ul>
<li v-if="!hasPermanent">
<a @click="getPermalink" :aria-label="$t('buttons.permalink')">{{ $t('buttons.permalink') }}</a>
</li>
<li v-for="link in links" :key="link.hash">
<a :href="buildLink(link.hash)" target="_blank">
<template v-if="link.expires">{{ humanTime(link.expireDate) }}</template>
<template v-else>{{ $t('permanent') }}</template>
</a>
<button class="action"
@click="deleteLink($event, link)"
:aria-label="$t('buttons.delete')"
:title="$t('buttons.delete')"><i class="material-icons">delete</i></button>
<button class="action copy-clipboard"
:data-clipboard-text="buildLink(link.hash)"
:aria-label="$t('buttons.copyToClipboard')"
:title="$t('buttons.copyToClipboard')"><i class="material-icons">content_paste</i></button>
</li>
<li>
<input autofocus
type="number"
max="2147483647"
min="0"
@keyup.enter="submit"
v-model.trim="time">
<select v-model="unit" :aria-label="$t('time.unit')">
<option value="seconds">{{ $t('time.seconds') }}</option>
<option value="minutes">{{ $t('time.minutes') }}</option>
<option value="hours">{{ $t('time.hours') }}</option>
<option value="days">{{ $t('time.days') }}</option>
</select>
<button class="action"
@click="submit"
:aria-label="$t('buttons.create')"
:title="$t('buttons.create')"><i class="material-icons">add</i></button>
</li>
</ul>
</div>
<div class="card-action">
<button class="flat"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.close')"
:title="$t('buttons.close')">{{ $t('buttons.close') }}</button>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
import { getShare, deleteShare, share } from '@/utils/api'
import moment from 'moment'
import Clipboard from 'clipboard'
export default {
name: 'share',
data: function () {
return {
time: '',
unit: 'hours',
hasPermanent: false,
links: [],
clip: null
}
},
computed: {
...mapState([ 'baseURL', 'req', 'selected', 'selectedCount' ]),
url () {
// Get the current name of the file we are editing.
if (this.req.kind !== 'listing') {
return this.$route.path
}
if (this.selectedCount === 0 || this.selectedCount > 1) {
// This shouldn't happen.
return
}
return this.req.items[this.selected[0]].url
}
},
beforeMount () {
getShare(this.url)
.then(links => {
this.links = links
this.sort()
for (let link of this.links) {
if (!link.expires) {
this.hasPermanent = true
break
}
}
})
.catch(error => {
if (error === 404) return
this.$showError(error)
})
},
mounted () {
this.clip = new Clipboard('.copy-clipboard')
this.clip.on('success', (e) => {
this.$showSuccess(this.$t('success.linkCopied'))
})
},
beforeDestroy () {
this.clip.destroy()
},
methods: {
submit: function (event) {
if (!this.time) return
share(this.url, this.time, this.unit)
.then(result => { this.links.push(result); this.sort() })
.catch(this.$showError)
},
getPermalink (event) {
share(this.url)
.then(result => {
this.links.push(result)
this.sort()
this.hasPermanent = true
})
.catch(this.$showError)
},
deleteLink (event, link) {
event.preventDefault()
deleteShare(link.hash)
.then(() => {
if (!link.expires) this.hasPermanent = false
this.links = this.links.filter(item => item.hash !== link.hash)
})
.catch(this.$showError)
},
humanTime (time) {
return moment(time).fromNow()
},
buildLink (hash) {
return `${window.location.origin}${this.baseURL}/share/${hash}`
},
sort () {
this.links = this.links.sort((a, b) => {
if (!a.expires) return -1
if (!b.expires) return 1
return new Date(a.expireDate) - new Date(b.expireDate)
})
}
}
}
</script>

View File

@@ -1,214 +0,0 @@
body {
font-family: 'Roboto', sans-serif;
padding-top: 4em;
background-color: #fafafa;
color: #333333;
}
* {
box-sizing: border-box;
}
*,
*:hover,
*:active,
*:focus {
outline: 0
}
a {
text-decoration: none;
}
img {
max-width: 100%;
}
audio,
video {
width: 100%;
}
pre {
padding: 1em;
border: 1px solid #e6e6e6;
border-radius: 0.5em;
background-color: #f5f5f5;
white-space: pre-wrap;
white-space: -moz-pre-wrap;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
word-wrap: break-word;
}
input,
button {
outline: 0 !important;
}
input[type="submit"],
button {
border: 0;
padding: .5em 1em;
margin-left: .5em;
border-radius: .1em;
cursor: pointer;
background: #2196f3;
color: #fff;
border: 1px solid rgba(0, 0, 0, 0.05);
box-shadow: 0 0 5px rgba(0, 0, 0, 0.05);
transition: .1s ease all;
}
input[type="submit"]:hover,
button:hover {
background-color: #1E88E5;
}
input[type="submit"].block,
button.block {
display: block;
width: 100%;
margin: 0 0 1em;
}
button.delete {
background: #F44336;
}
button.delete:hover {
background: #D32F2F;
}
button.cancel {
background-color: #ECEFF1;
color: #37474F;
}
button.cancel:hover {
background-color: #e9eaeb;
}
button.flat,
input[type="submit"].flat {
color: #1E88E5;
background: transparent;
box-shadow: 0 0 0;
border: 0;
margin-left: 0;
text-transform: uppercase;
}
button.flat:hover,
input[type="submit"].flat:hover {
background: rgba(0,0,0,0.05)
}
button.flat.delete {
color: #F44336;
}
button.flat.cancel {
color: #ccc;
}
button.flat[disabled] {
color: #ccc;
cursor: not-allowed;
}
.mobile-only {
display: none !important;
}
.container {
width: 95%;
max-width: 960px;
margin: 1em auto 0;
}
i.spin {
animation: 1s spin linear infinite;
}
#app {
transition: .2s ease padding;
}
#app.multiple {
padding-bottom: 4em;
}
nav {
width: 16em;
position: fixed;
top: 4em;
left: 0;
}
nav .action {
width: 100%;
display: block;
border-radius: 0;
font-size: 1.1em;
padding: .5em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
nav>div {
border-top: 1px solid rgba(0, 0, 0, 0.05);
}
nav .action>* {
vertical-align: middle;
}
main {
min-height: 1em;
margin: 0 1em 1em auto;
width: calc(100% - 19em);
}
#breadcrumbs {
height: 3em;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
#breadcrumbs span,
#breadcrumbs {
display: flex;
align-items: center;
color: #6f6f6f;
}
#breadcrumbs a {
color: inherit;
transition: .1s ease-in;
border-radius: .125em;
}
#breadcrumbs a:hover {
background-color: rgba(0,0,0, 0.05);
}
#breadcrumbs span a {
padding: .2em;
}
#progress {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 3px;
z-index: 9999999999;
}
#progress div {
height: 100%;
background-color: #40c4ff;
width: 0;
transition: .2s ease width;
}

View File

@@ -1,420 +0,0 @@
.dashboard {
max-width: 600px;
margin: 1em 0;
}
a {
color: inherit
}
select,
textarea,
input[type="text"],
input[type="password"] {
padding: 0.5em 0;
line-height: 1;
display: block;
border: 0;
border-bottom: 1px solid #dddddd;
transition: .2s ease border;
width: 100%;
background: transparent;
}
textarea {
line-height: 1.15;
padding: .5em;
border: 1px solid #ddd;
font-family: monospace;
min-height: 10em;
resize: none;
border-radius: 2px;
}
.dashboard #locale,
.dashboard #username,
.dashboard #password,
.dashboard #scope {
max-width: 18em;
}
.dashboard #locale {
margin-top: .5em;
}
textarea:focus,
textarea:hover,
input[type="text"]:focus,
input[type="password"]:focus,
input[type="text"]:hover,
input[type="password"]:hover {
border-color: #2979ff;
}
input.red {
border-color: red;
}
input.green {
border-color: green;
}
.dashboard p label {
margin-bottom: .2em;
display: block;
font-size: .8em;
font-weight: 500;
color: rgba(0, 0, 0, 0.57);
}
li code,
p code {
background: rgba(0, 0, 0, 0.05);
padding: .1em;
border-radius: .2em;
}
.small {
font-size: .8em;
line-height: 1.5;
}
.dashboard #nav {
list-style: none;
display: flex;
color: rgb(84, 110, 122);
font-weight: 500;
margin: 0 0 1em;
font-size: .8em;
text-align: center;
justify-content: space-between;
padding: 0;
}
.dashboard #nav li {
width: 100%;
padding: 0 0 1em;
border-bottom: 2px solid rgba(0, 0, 0, 0.05);
}
.dashboard #nav li.active {
border-color: #2196f3
}
.dashboard #nav i {
font-size: 1em;
vertical-align: middle;
}
table {
border-collapse: collapse;
width: 100%;
}
table tr {
border-bottom: 1px solid #ccc;
}
table tr:last-child {
border: 0;
}
table th {
font-weight: 500;
color: #757575;
text-align: left;
}
table th,
table td {
padding: .5em 0;
}
table td.small {
width: 1em;
}
table tr>*:first-child {
padding-left: 1em;
}
table tr>*:last-child {
padding-right: 1em;
}
.card {
position: relative;
margin: .5rem 0 1rem 0;
background-color: #fff;
border-radius: 2px;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
}
.card.floating {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 99999;
max-width: 25em;
width: 90%;
max-height: 95%;
z-index: 99999;
animation: .1s show forwards;
}
.card>*>*:first-child {
margin-top: 0;
}
.card>*>*:last-child {
margin-bottom: 0;
}
.card .card-title {
padding: 1.5em 1em 1em;
display: flex;
}
.card .card-title>*:first-child {
margin-right: auto;
}
.card>div {
padding: 1em 1em;
}
.card>div:first-child {
padding-top: 1.5em;
}
.card>div:last-child {
padding-bottom: 1.5em;
}
.card .card-title * {
margin: 0;
}
.card .card-action {
text-align: right;
}
.card .card-content.full {
padding-bottom: 0;
}
.card h2 {
font-weight: 500;
}
.card h3 {
color: rgba(0, 0, 0, 0.53);
font-size: 1em;
font-weight: 500;
margin: 2em 0 1em;
}
.card-content table {
margin: 0 -1em;
width: calc(100% + 2em);
}
.card code {
word-wrap: break-word;
}
.card#download {
max-width: 15em;
}
.card#share ul {
list-style: none;
padding: 0;
margin: 0;
}
.card#share ul li {
display: flex;
justify-content: space-between;
align-items: center;
}
.card#share ul li a {
color: #2196F3;
cursor: pointer;
margin-right: auto;
}
.card#share ul li .action i {
font-size: 1em;
}
.card#share ul li input,
.card#share ul li select {
padding: .2em;
margin-right: .5em;
border: 1px solid #dadada;
}
.card#share .action.copy-clipboard::after {
content: 'Copied!';
position: absolute;
left: -25%;
width: 150%;
font-size: .6em;
text-align: center;
background: #44a6f5;
color: #fff;
padding: .5em .2em;
border-radius: .4em;
top: -2em;
transition: .1s ease opacity;
opacity: 0;
}
.card#share .action.copy-clipboard.active::after {
opacity: 1;
}
.overlay {
background-color: rgba(0, 0, 0, 0.5);
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 9999;
animation: .1s show forwards;
}
/* * * * * * * * * * * * * * * *
* PROMPT - MOVE *
* * * * * * * * * * * * * * * */
.file-list {
max-height: 50vh;
overflow: auto;
list-style: none;
margin: 0;
padding: 0;
width: 100%;
}
.file-list li {
width: 100%;
user-select: none;
border-radius: .2em;
padding: .3em;
}
.file-list li[aria-selected=true] {
background: #2196f3 !important;
color: #fff !important;
transition: .1s ease all;
}
.file-list li:hover {
background-color: #e9eaeb;
cursor: pointer;
}
.file-list li:before {
content: "folder";
color: #6f6f6f;
vertical-align: middle;
line-height: 1.4;
font-family: 'Material Icons';
font-size: 1.75em;
margin-right: .25em;
}
.file-list li[aria-selected=true]:before {
color: white;
}
.help {
max-width: 24em;
}
.help ul {
padding: 0;
margin: 1em 0;
list-style: none;
}
@keyframes show {
0% {
display: none;
opacity: 0;
}
1% {
display: block;
opacity: 0;
}
100% {
display: block;
opacity: 1;
}
}
.collapsible {
border-top: 1px solid rgba(0,0,0,0.1);
}
.collapsible:last-of-type {
border-bottom: 1px solid rgba(0,0,0,0.1);
}
.collapsible > input {
display: none;
}
.collapsible > label {
padding: 1em 0;
cursor: pointer;
border-right: 0;
border-left: 0;
display: flex;
justify-content: space-between;
}
.collapsible > label * {
margin: 0;
color: rgba(0,0,0,0.57);
}
.collapsible > label i {
transition: .2s ease transform;
user-select: none;
}
.collapsible .collapse {
max-height: 0;
overflow: hidden;
transition: .2s ease all;
}
.collapsible > input:checked ~ .collapse {
padding-top: 1em;
padding-bottom: 1em;
max-height: 20em;
}
.collapsible > input:checked ~ label i {
transform: rotate(180deg)
}
.card .collapsible {
width: calc(100% + 2em);
margin: 0 -1em;
}
.card .collapsible > label {
padding: 1em;
}
.card .collapsible .collapse {
padding: 0 1em;
}

View File

@@ -1,184 +0,0 @@
@import "~codemirror/lib/codemirror.css";
@import "~codemirror/theme/ttcn.css";
#editor {
max-width: 800px;
margin: 0 auto;
}
#editor .CodeMirror {
box-shadow: rgba(0, 0, 0, 0.06) 0px 1px 3px, rgba(0, 0, 0, 0.12) 0px 1px 2px;
margin: 2em 0;
border-radius: .5em;
}
#editor h2 {
color: rgba(0, 0, 0, 0.3);
font-weight: 500;
}
.CodeMirror {
height: auto;
}
.markdown .CodeMirror {
padding: .75em;
}
.cm-s-markdown .CodeMirror-gutter {
border-right: 1px solid #eff3f5;
padding-right: 5px;
margin-right: 15px;
min-width: 2.5em;
padding-bottom: 30px;
}
.cm-s-markdown .CodeMirror-cursor {
border-right: 2px solid #667880;
}
.cm-s-markdown .CodeMirror-lines {
margin: 0;
}
.cm-s-markdown {
color: #3D494E;
}
.cm-s-markdown span.cm-header {
color: #3D494E;
font-weight: bold;
}
.cm-s-markdown span.cm-variable-2 {
color: #3D494E;
}
.cm-s-markdown span.cm-meta {
color: #516066;
}
.cm-s-markdown span.cm-hr {
color: #516066;
}
.cm-s-markdown span.cm-comment {
color: #868f93;
}
.cm-s-markdown span.cm-qualifier {
color: #868f93;
}
.cm-s-markdown span.cm-number {
color: #197987;
}
.cm-s-markdown span.cm-variable {
color: #197987;
}
.cm-s-markdown span.cm-builtin {
color: #197987;
}
.cm-s-markdown span.cm-link {
color: #197987;
text-decoration: underline;
}
.cm-s-markdown span.cm-tag {
color: #197987;
}
.cm-s-markdown span.cm-string {
color: #48abb9;
}
.cm-s-markdown span.cm-string-2 {
color: #48abb9;
}
.cm-s-markdown span.cm-quote {
color: #48abb9;
}
.cm-s-markdown span.cm-atom {
color: #48abb9;
}
.cm-s-markdown span.cm-property {
color: #82a367;
}
.cm-s-markdown span.cm-operator {
color: #82a367;
}
.cm-s-markdown span.cm-variable-3 {
color: #82a367;
}
.cm-s-markdown span.cm-attribute {
color: #90bb74;
}
.cm-s-markdown span.cm-def {
color: #90bb74;
}
.cm-s-markdown span.cm-keyword {
color: #ec6c45;
}
.cm-s-markdown span.cm-bracket {
color: #ec6c45;
}
.cm-s-markdown span.cm-error {
color: #e45346;
}
.cm-s-markdown span.cm-em {
font-style: italic;
}
.cm-s-markdown span.cm-strong {
font-weight: bold;
}
.cm-s-markdown .cm-header-1 {
font-size: 200%;
line-height: 200%;
}
.cm-s-markdown .cm-header-2 {
font-size: 160%;
line-height: 160%;
}
.cm-s-markdown .cm-header-3 {
font-size: 125%;
line-height: 125%;
}
.cm-s-markdown .cm-header-4 {
font-size: 110%;
line-height: 110%;
}
.cm-s-markdown .cm-comment {
background: rgba(0, 0, 0, .05);
border-radius: 2px;
}
.cm-s-markdown .cm-link {
color: #7f8c8d;
}
.cm-s-markdown .cm-url {
color: #aab2b3;
}
.cm-s-markdown .cm-strikethrough {
text-decoration: line-through;
}

View File

@@ -1,137 +0,0 @@
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../assets/fonts/roboto/normal-cyrillic-ext.woff2) format('woff2');
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../assets/fonts/roboto/normal-cyrillic.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../assets/fonts/roboto/normal-greek-ext.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../assets/fonts/roboto/normal-greek.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../assets/fonts/roboto/normal-vietnamese.woff2) format('woff2');
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../assets/fonts/roboto/normal-latin-ext.woff2) format('woff2');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../assets/fonts/roboto/normal-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../assets/fonts/roboto/medium-cyrillic-ext.woff2) format('woff2');
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../assets/fonts/roboto/medium-cyrillic.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../assets/fonts/roboto/medium-greek-ext.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../assets/fonts/roboto/medium-greek.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../assets/fonts/roboto/medium-vietnamese.woff2) format('woff2');
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../assets/fonts/roboto/medium-latin-ext.woff2) format('woff2');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../assets/fonts/roboto/medium-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: local('Material Icons'), local('MaterialIcons-Regular'), url(../assets/fonts/material/icons.woff2) format('woff2');
}
.prompt .file-list ul li:before,
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
font-feature-settings: 'liga';
}

View File

@@ -1,260 +0,0 @@
header {
z-index: 1000;
background-color: #fff;
border-bottom: 1px solid rgba(0, 0, 0, 0.075);
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
position: fixed;
top: 0;
left: 0;
width: 100%;
padding: 0;
display: flex;
}
header .overlay {
width: 0;
height: 0;
}
header a,
header a:hover {
color: inherit;
}
header>div:first-child>.action,
header img {
margin-right: 1em;
}
header img {
height: 2.5em;
}
header>div:first-child>.action {
display: none;
}
header>div {
display: flex;
width: 100%;
padding: 0.5em 0.5em 0.5em 1em;
align-items: center;
}
header .action span {
display: none;
}
header>div div {
vertical-align: middle;
position: relative;
}
header>div:last-child div {
display: flex;
}
header>div:first-child {
height: 4em;
}
header>div:last-child {
justify-content: flex-end;
}
header .search-button {
display: none;
}
#more {
display: none;
}
#search {
position: relative;
height: 100%;
width: 100%;
max-width: 25em;
}
#search.active {
position: fixed;
top: 0;
right: 0;
width: 100%;
max-width: 100%;
height: 100%;
z-index: 9999;
}
#search #input {
background-color: #f5f5f5;
display: flex;
padding: 0.75em;
border-radius: 0.3em;
transition: .1s ease all;
align-items: center;
z-index: 2;
}
#search.active #input {
border-bottom: 1px solid rgba(0, 0, 0, 0.075);
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
background-color: #fff;
height: 4em;
}
#search.active>div {
border-radius: 0 !important;
}
#search.active i,
#search.active input {
color: #212121;
}
#search #input>.action,
#search #input>i {
margin-right: 0.3em;
user-select: none;
}
#search input {
width: 100%;
border: 0;
background-color: transparent;
line-height: 0;
padding: 0;
}
#search #result {
visibility: visible;
max-height: none;
background-color: #f8f8f8;
text-align: left;
padding: 0;
color: rgba(0, 0, 0, 0.6);
height: 0;
transition: .1s ease height, .1s ease padding;
overflow-x: hidden;
overflow-y: auto;
z-index: 1;
}
#search #result>div>*:first-child {
margin-top: 0;
}
#search.active #result {
padding: .5em;
height: calc(100% - 4em);
}
#search ul {
padding: 0;
margin: 0;
list-style: none;
}
#search li {
margin-bottom: .5em;
}
#search #result>div {
max-width: 45em;
margin: 0 auto;
}
#search #result #renew {
width: 100%;
text-align: center;
display: none;
margin: 0;
max-width: none;
}
#search.ongoing #result #renew {
display: block;
}
#search.active #result i {
color: #ccc;
}
#search.active #result>p>i {
text-align: center;
margin: 0 auto;
display: table;
}
#search.active #result ul li a {
display: flex;
align-items: center;
padding: .3em 0;
}
#search.active #result ul li a i {
margin-right: .3em;
}
#search::-webkit-input-placeholder {
color: rgba(255, 255, 255, .5);
}
#search:-moz-placeholder {
opacity: 1;
color: rgba(255, 255, 255, .5);
}
#search::-moz-placeholder {
opacity: 1;
color: rgba(255, 255, 255, .5);
}
#search:-ms-input-placeholder {
color: rgba(255, 255, 255, .5);
}
#search .boxes {
border: 1px solid rgba(0, 0, 0, 0.075);
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
background: #fff;
margin: 1em 0;
}
#search .boxes h3 {
margin: 0;
font-weight: 500;
font-size: 1em;
color: #212121;
padding: .5em;
}
#search .boxes>div {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
margin-right: -1em;
margin-bottom: -1em;
}
#search .boxes>div>div {
background: #2196F3;
color: #fff;
text-align: center;
width: 10em;
padding: 1em;
cursor: pointer;
margin-bottom: 1em;
margin-right: 1em;
flex-grow: 1;
}
#search .boxes p {
margin: 1em 0 0;
}
#search .boxes i {
color: #fff !important;
font-size: 3.5em;
}

View File

@@ -1,237 +0,0 @@
#listing h2 {
margin: 0 0 0 0.5em;
font-size: .9em;
color: rgba(0, 0, 0, 0.38);
font-weight: 500;
}
#listing .item div:last-of-type * {
text-overflow: ellipsis;
overflow: hidden;
}
#listing>div {
display: flex;
padding: 0;
flex-wrap: wrap;
justify-content: flex-start;
position: relative;
}
#listing .item {
background-color: #fff;
position: relative;
display: flex;
flex-wrap: nowrap;
color: #6f6f6f;
transition: .1s ease background, .1s ease opacity;
align-items: center;
cursor: pointer;
}
#listing .item div:last-of-type {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
#listing .item p {
margin: 0;
}
#listing .item .size,
#listing .item .modified {
font-size: 0.9em;
}
#listing .item .name {
font-weight: bold;
}
#listing .item i {
font-size: 4em;
margin-right: 0.1em;
vertical-align: bottom;
}
.message {
text-align: center;
font-size: 2em;
margin: 1em auto;
display: block !important;
width: 95%;
color: rgba(0, 0, 0, 0.3);
font-weight: 500;
}
.message i {
font-size: 2.5em;
margin-bottom: .2em;
display: block;
}
#listing.mosaic {
padding-top: 1em;
margin: 0 -0.5em;
}
#listing.mosaic .item {
width: calc(33% - 1em);
margin: .5em;
padding: 0.5em;
border-radius: 0.2em;
box-shadow: 0 1px 3px rgba(0, 0, 0, .06), 0 1px 2px rgba(0, 0, 0, .12);
}
#listing.mosaic .item:hover {
box-shadow: 0 1px 3px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .24) !important;
}
#listing.mosaic .header {
display: none;
}
#listing.mosaic .item div:first-of-type {
width: 5em;
}
#listing.mosaic .item div:last-of-type {
width: calc(100% - 5vw);
}
#listing.list {
flex-direction: column;
padding-top: 3.25em;
width: 100%;
max-width: 100%;
margin: 0;
}
#listing.list .item {
width: 100%;
margin: 0;
border: 1px solid rgba(0, 0, 0, 0.1);
padding: 1em;
border-top: 0;
}
#listing.list h2 {
display: none;
}
#listing .item[aria-selected=true] {
background: #2196f3 !important;
color: #fff !important;
}
#listing.list .item div:first-of-type {
width: 3em;
}
#listing.list .item div:first-of-type i {
font-size: 2em;
}
#listing.list .item div:last-of-type {
width: calc(100% - 3em);
display: flex;
align-items: center;
}
#listing.list .item .name {
width: 50%;
}
#listing.list .item .size {
width: 25%;
}
#listing .item.header {
display: none !important;
background-color: #ccc;
}
#listing.list .header i {
font-size: 1.5em;
vertical-align: middle;
margin-left: .2em;
}
#listing.list .item.header {
display: flex !important;
background: #fafafa;
position: fixed;
width: calc(100% - 19em);
top: 7em;
right: 1em;
z-index: 999;
padding: .85em;
border: 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
#listing.list .item.header>div:first-child {
width: 0;
}
#listing.list .item.header .name {
margin-right: 3em;
}
#listing.list .header a {
color: inherit;
}
#listing.list .item.header>div:first-child {
width: 0;
}
#listing.list .name {
font-weight: normal;
}
#listing.list .item.header .name {
margin-right: 3em;
}
#listing.list .header span {
vertical-align: middle;
}
#listing.list .header i {
opacity: 0;
transition: .1s ease all;
}
#listing.list .header p:hover i,
#listing.list .header .active i {
opacity: 1;
}
#listing.list .item.header .active {
font-weight: bold;
}
#listing #multiple-selection {
position: fixed;
bottom: -4em;
left: 0;
z-index: 99999;
width: 100%;
background-color: #2196f3;
height: 4em;
display: flex !important;
padding: 0.5em 0.5em 0.5em 1em;
justify-content: space-between;
align-items: center;
transition: .2s ease bottom;
}
#listing #multiple-selection.active {
bottom: 0;
}
#listing #multiple-selection p,
#listing #multiple-selection i {
color: #fff;
}

View File

@@ -1,76 +0,0 @@
#login {
background: #fff;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#login img {
width: 4em;
height: 4em;
margin: 0 auto;
display: block;
}
#login h1 {
text-align: center;
font-size: 2.5em;
margin: .4em 0 .67em;
}
#login form {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
max-width: 16em;
width: 90%;
}
#login.recaptcha form {
min-width: 304px;
}
#login #recaptcha {
margin: .5em 0 0;
}
#login input {
width: 100%;
width: 100%;
margin: .5em 0 0;
}
#login .wrong {
background: #F44336;
color: #fff;
padding: .5em;
text-align: center;
animation: .2s opac forwards;
}
@keyframes opac {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
#login input[type="text"],
#login input[type="password"] {
padding: .5em 1em;
border: 1px solid #e9e9e9;
transition: .2s ease border;
color: #333;
}
#login input[type="text"]:focus,
#login input[type="password"]:focus,
#login input[type="text"]:hover,
#login input[type="password"]:hover {
border-color: #9f9f9f;
}

View File

@@ -1,113 +0,0 @@
@media (max-width: 1024px) {
nav {
width: 10em
}
}
@media (max-width: 1024px) {
#listing.list .item.header,
main {
width: calc(100% - 13em)
}
}
@media (max-width: 736px) {
#more {
display: inherit
}
header .overlay {
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.1);
}
#dropdown {
position: fixed;
top: 1em;
right: 1em;
display: block;
background-color: #fff;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
transform: scale(0);
transition: .1s ease-in-out transform;
transform-origin: top right;
z-index: 99999;
}
#dropdown > div {
display: block;
}
#dropdown.active {
transform: scale(1);
}
#dropdown .action {
display: flex;
align-items: center;
border-radius: 0;
width: 100%;
}
#dropdown .action span:not(.counter) {
display: inline-block;
padding: .4em;
}
#dropdown .counter {
left: 2.25em;
}
#file-selection {
position: fixed;
bottom: 1em;
left: 50%;
transform: translateX(-50%);
display: flex;
align-items: center;
background: #fff;
box-shadow: rgba(0, 0, 0, 0.06) 0px 1px 3px, rgba(0, 0, 0, 0.12) 0px 1px 2px;
width: 95%;
max-width: 20em;
}
#file-selection .action {
border-radius: 50%;
width: auto;
}
#file-selection > span {
display: inline-block;
margin-left: 1em;
color: #6f6f6f;
margin-right: auto;
}
nav {
top: 0;
z-index: 99999;
background: #fff;
height: 100%;
width: 16em;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
transition: .1s ease left;
left: -17em;
}
nav.active {
left: 0;
}
header .search-button,
header>div:first-child>.action {
display: inherit;
}
header img {
display: none;
}
#listing {
margin-bottom: 5em;
}
#listing.list .item.header,
main {
width: calc(100% - 2em);
}
main {
margin: 0 1em;
width: calc(100% - 2em);
}
#search {
display: none;
}
#search.active {
display: block;
}
}

View File

@@ -1,228 +0,0 @@
@import "~normalize.css/normalize.css";
@import "~noty/lib/noty.css";
@import "./fonts.css";
@import "./base.css";
@import "./header.css";
@import "./listing.css";
@import "./editor.css";
@import "./dashboard.css";
@import "./login.css";
/* * * * * * * * * * * * * * * *
* ACTION *
* * * * * * * * * * * * * * * */
.action {
display: inline-block;
cursor: pointer;
transition: 0.2s ease all;
border: 0;
margin: 0;
color: #546E7A;
border-radius: 50%;
background: transparent;
padding: 0;
box-shadow: none;
vertical-align: middle;
text-align: left;
position: relative;
}
.action.disabled {
opacity: 0.2;
cursor: not-allowed;
}
.action i {
padding: 0.4em;
transition: .1s ease-in-out all;
border-radius: 50%;
}
.action:hover {
background-color: rgba(0, 0, 0, .1);
}
.action ul {
position: absolute;
top: 0;
color: #7d7d7d;
list-style: none;
margin: 0;
padding: 0;
flex-direction: column;
display: flex;
}
.action ul li {
line-height: 1;
padding: .7em;
transition: .1s ease background-color;
}
.action ul li:hover {
background-color: rgba(0, 0, 0, 0.04);
}
#click-overlay {
display: none;
position: fixed;
cursor: pointer;
top: 0;
left: 0;
height: 100%;
width: 100%;
}
#click-overlay.active {
display: block;
}
.action .counter {
display: block;
position: absolute;
bottom: 0;
right: 0;
background: #2196f3;
color: #fff;
border-radius: 50%;
font-size: .75em;
width: 1.5em;
height: 1.5em;
text-align: center;
line-height: 1.25em;
border: 2px solid white;
}
/* PREVIEWER */
#previewer {
background-color: rgba(0, 0, 0, 0.9);
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 9999;
overflow: hidden;
}
#previewer .bar {
width: 100%;
text-align: right;
display: flex;
padding: 0.5em;
height: 3.7em;
}
#previewer .action:first-of-type {
margin-right: auto;
}
#previewer .action i {
color: #fff;
}
#previewer .action:hover {
background-color: rgba(255, 255, 255, 0.3)
}
#previewer .action span {
display: none;
}
#previewer .preview {
margin: 2em auto 4em;
max-width: 80%;
text-align: center;
height: calc(100vh - 9.7em);
}
#previewer .preview pre {
text-align: left;
overflow: auto;
}
#previewer .preview pre,
#previewer .preview video,
#previewer .preview img {
max-height: 100%;
margin: 0;
}
#previewer .pdf {
width: 100%;
height: 100%;
}
#previewer h2.message {
color: rgba(255, 255, 255, 0.5)
}
#previewer>button {
margin: 0;
position: fixed;
top: 50%;
transform: translateY(-50%);
}
#previewer>button:first-of-type {
left: 0.5em;
}
#previewer>button:last-of-type {
right: 0.5em;
}
/* * * * * * * * * * * * * * * *
* PROMPT *
* * * * * * * * * * * * * * * */
.noty_buttons {
text-align: right;
padding: 0 10px 10px !important;
}
.noty_buttons button {
background: rgba(0, 0, 0, 0.05);
border: 1px solid rgba(0,0,0,0.1);
box-shadow: 0 0 0 0;
font-size: 14px;
}
/* * * * * * * * * * * * * * * *
* FOOTER *
* * * * * * * * * * * * * * * */
.credits {
font-size: 0.6em;
margin: 3em 2.5em;
color: #a5a5a5;
}
.credits span {
display: block;
margin: .3em 0;
}
.credits a,
.credits a:hover {
color: inherit;
cursor: pointer;
}
/* * * * * * * * * * * * * * * *
* ANIMATIONS *
* * * * * * * * * * * * * * * */
@keyframes spin {
100% {
-webkit-transform: rotate(-360deg);
transform: rotate(-360deg);
}
}
@import './mobile.css';

View File

@@ -1,201 +0,0 @@
permanent: Permanent
buttons:
cancel: Cancel
close: Close
copy: Copy
copyFile: Copy file
copyToClipboard: Copy to clipboard
create: Create
delete: Delete
download: Download
info: Info
more: More
move: Move
moveFile: Move file
new: New
next: Next
ok: OK
replace: Replace
previous: Previous
rename: Rename
reportIssue: Report Issue
save: Save
search: Search
select: Select
share: Share
publish: Publish
selectMultiple: Select multiple
schedule: Schedule
switchView: Switch view
toggleSidebar: Toggle sidebar
update: Update
upload: Upload
permalink: Get Permanent Link
success:
linkCopied: Link copied!
errors:
forbidden: You're not welcome here.
internal: Something really went wrong.
notFound: This location can't be reached.
files:
folders: Folders
files: Files
body: Body
clear: Clear
closePreview: Close preview
home: Home
lastModified: Last modified
loading: Loading...
lonely: It feels lonely here...
metadata: Metadata
multipleSelectionEnabled: Multiple selection enabled
name: Name
size: Size
sortByName: Sort by name
sortBySize: Sort by size
sortByLastModified: Sort by last modified
help:
click: select file or directory
ctrl:
click: select multiple files or directories
f: opens search
s: save a file or download the directory where you are
del: delete selected items
doubleClick: open a file or directory
esc: clear selection and/or close the prompt
f1: this information
f2: rename file
help: Help
login:
password: Password
submit: Login
username: Username
wrongCredentials: Wrong credentials
prompts:
copy: Copy
copyMessage: 'Choose the place to copy your files:'
currentlyNavigating: 'Currently navigating on:'
deleteMessageMultiple: Are you sure you want to delete {count} file(s)?
deleteMessageSingle: Are you sure you want to delete this file/folder?
deleteTitle: Delete files
displayName: 'Display Name:'
download: Download files
downloadMessage: Choose the format you want to download.
error: Something went wrong
fileInfo: File information
filesSelected: "{count} files selected."
lastModified: Last Modified
move: Move
moveMessage: 'Choose new house for your file(s)/folder(s):'
newDir: New directory
newDirMessage: Write the name of the new directory.
newFile: New file
newFileMessage: Write the name of the new file.
numberDirs: Number of directories
numberFiles: Number of files
replace: Replace
replaceMessage: >
One of the files you're trying to upload is conflicting because of its name.
Do you wish to replace the existing one?
rename: Rename
renameMessage: Insert a new name for
show: Show
size: Size
schedule: Schedule
scheduleMessage: Pick a date and time to schedule the publication of this post.
newArchetype: Create a new post based on an archetype. Your file will be created on content folder.
settings:
admin: Admin
administrator: Administrator
allowCommands: Execute commands
allowEdit: Edit, rename and delete files or directories
allowNew: Create new files and directories
allowPublish: Publish new posts and pages
avoidChanges: "(leave blank to avoid changes)"
changePassword: Change Password
commands: Commands
commandsHelp: >
Here you can set commands that are executed in the named events. You
write one command per line. If the event is related to files, such as before and
after saving, the environment variable "FILE" will be available with the path
of the file.
commandsUpdated: Commands updated!
customStylesheet: Custom Stylesheet
examples: Examples
globalSettings: Global Settings
language: Language
lockPassword: Prevent the user from changing the password
newPassword: Your new password
newPasswordConfirm: Confirm your new password
newUser: New User
password: Password
passwordUpdated: Password updated!
permissions: Permissions
permissionsHelp: >
You can set the user to be an administrator or choose the permissions
individually. If you select "Administrator", all of the other options will be
automatically checked. The management of users remains a privilege of an administrator.
profileSettings: Profile Settings
ruleExample1: >
prevents the access to any dot file (such as .git, .gitignore) in
every folder.
ruleExample2: blocks the access to the file named Caddyfile on the root of the scope.
rules: Rules
rulesHelp1: >
Here you can define a set of allow and disallow rules for this specific
user. The blocked files won't show up in the listings and they wont be accessible
to the user. We support regex and paths relative to the users scope.
rulesHelp2: >
Each rule goes in one different line and must start with the keyword
{0} or {1}. Then you should write {2} if you are using a regular expression and
then the expression or the path.
scope: Scope
settingsUpdated: Settings updated!
user: User
userCommands: Commands
userCommandsHelp: >
A space separated list with the available commands for this user.
Example:
userCreated: User created!
userDeleted: User deleted!
userManagement: User Management
username: Username
users: Users
userUpdated: User updated!
sidebar:
help: Help
logout: Logout
myFiles: My files
newFile: New file
newFolder: New folder
settings: Settings
siteSettings: Site Settings
hugoNew: Hugo New
preview: Preview
search:
images: Images
music: Music
pdf: PDF
pressToExecute: Press enter to execute.
pressToSearch: Press enter to search.
search: Search...
searchOrCommand: Search or execute a command...
searchOrSupportedCommand: 'Search or use one of your supported commands:'
type: Type and press enter to search.
types: Types
video: Video
writeToSearch: Write here to search
languages:
en: English
fr: Français
pt: Português
ja: 日本語
zhCN: 中文 (简体)
zhTW: 中文 (繁體)
es: Español
time:
unit: Time Unit
seconds: Seconds
minutes: Minutes
hours: Hours
days: Days

View File

@@ -1,202 +0,0 @@
permanent: Permanente
buttons:
cancel: Cancelar
close: Cerrar
copy: Copiar
copyFile: Copiar archivo
copyToClipboard: Copiar al portapapeles
create: Crear
delete: Borrar
download: Descargar
info: Info
more: Más
move: Mover
moveFile: Mover archivo
new: Nuevo
next: Siguiente
ok: OK
replace: Reemplazar
previous: Anterior
rename: Renombrar
reportIssue: Reportar problema
save: Guardar
search: Buscar
select: Seleccionar
share: Compartir
publish: Publicar
selectMultiple: Selección múltiple
schedule: Programar
switchView: Cambiar vista
toggleSidebar: Mostrar/Ocultar menú
update: Actualizar
upload: Subir
permalink: Link permanente
success:
linkCopied: ¡Link copiado!
errors:
forbidden: No eres bienvenido aquí.
internal: La verdad es que algo ha ido mal.
notFound: No se puede acceder a este lugar.
files:
folders: Carpetas
files: Archivos
body: Cuerpo
clear: Limpiar
closePreview: Cerrar vista previa
home: Inicio
lastModified: Última modificación
loading: Cargando...
lonely: Uno se siente muy sólo aquí...
metadata: Metadatos
multipleSelectionEnabled: Selección múltiple activada
name: Nombre
size: Tamaño
sortByName: Ordenar por nombre
sortBySize: Ordenar por tamaño
sortByLastModified: Ordenar por última modificación
help:
click: seleccionar archivo o carpeta
ctrl:
click: seleccionar múltiples archivos o carpetas
f: abre la búsqueda
s: guarda un archivo o lo descarga a la carpeta en la que estás
del: elimina los items seleccionados
doubleClick: abre un archivo o carpeta
esc: limpia la selección y/o cierra la ventana
f1: esta información
f2: renombrar archivo
help: Ayuda
login:
password: Contraseña
submit: Iniciar sesión
username: Usuario
wrongCredentials: Usuario y/o contraseña incorrectos
prompts:
copy: Copiar
copyMessage: 'Elige el lugar donde quieres copiar tus archivos:'
currentlyNavigating: 'Actualmente estás en:'
deleteMessageMultiple: ¿Estás seguro que quieres eliminar {count} archivo(s)?
deleteMessageSingle: ¿Estás seguro que quieres eliminar este archivo/carpeta?
deleteTitle: Borrar archivos
displayName: 'Nombre:'
download: Descargar archivos
downloadMessage: Elige el formato de descarga.
error: Algo ha fallado
fileInfo: Información del archivo
filesSelected: "{count} archivos seleccionados."
lastModified: Última modificación
move: Mover
moveMessage: 'Elige una nueva casa para tus archivo(s)/carpeta(s):'
newDir: Nueva carpeta
newDirMessage: Escribe el nombre de la nueva carpeta.
newFile: Nuevo archivo
newFileMessage: Escribe el nombre del nuevo archivo.
numberDirs: Número de carpetas
numberFiles: Número de archivos
replace: Reemplazar
replaceMessage: >
Uno de los archivos ue intentas subir está creando conflicto por su nombre.
¿Quieres cambiar el nombre del ya existente?
rename: Renombrar
renameMessage: Escribe el nuevo nombre para
show: Mostrar
size: Tamaño
schedule: Programar
scheduleMessage: Elige una hora y fecha para programar la publicación de este post.
newArchetype: Crea un nuevo post basado en un arquetipo. Tu archivo será creado en la carpeta de contenido.
settings:
admin: Admin
administrator: Administrador
allowCommands: Ejecutar comandos
allowEdit: Editar, renombrar y borrar archivos o carpetas
allowNew: Crear nuevos archivos y carpetas
allowPublish: Publicar nuevos posts y páginas
avoidChanges: "(dejar en blanco para evitar cambios)"
changePassword: Cambiar contraseña
commands: Comandos
commandsHelp: >
Aquí puedes crear comandos que serán ejecutados en los eventos. Debes
escribir un comando por linea. Si el evento está relacionado con archivos, como
por ejemplo, antes y después de guardar, la variable de entorno "FILE" estará
disponible en la ruta del archivo.
commandsUpdated: ¡Comandos actualizados!
customStylesheet: Modificar hoja de estilos
examples: Ejemplos
globalSettings: Ajustes globales
language: Idioma
lockPassword: Evitar que el usuario cambie la contraseña
newPassword: Tu nueva contraseña
newPasswordConfirm: Confirma tu contraseña
newUser: Nuevo usuario
password: Contraseña
passwordUpdated: ¡Contraseña actualizada!
permissions: Permisos
permissionsHelp: >
Puedes nombrar al usuario como administrador o elegir los permisos
individualmente. Si seleccionas "Administrador", todas las otras opciones
serán activadas automáticamente. La administración de usuarios es un privilegio de administrador.
profileSettings: Ajustes del perfil
ruleExample1: >
previene el acceso a una extensión de archivo (Como .git) en
cada carpeta.
ruleExample2: bloquea el acceso al archivo llamado Caddyfile en la carpeta raíz.
rules: Reglas
rulesHelp1: >
Aquí puedes definir un conjunto de reglas de permisos para este usuario
específico. Los archivos bloqueados no se mostrarán en las listas y no serán accesibles
por el usuario. Puedes utilizar regex y rutas relativas a la raíz del usuario.
rulesHelp2: >
Cada regla va en una línea diferente, y debe comenzar con la palabra clave
{0} or {1}. Entonces, debes escribir {2} si estás usando una expresión regular (REGEX) y
luego la expresión o la ruta.
scope: Raíz
settingsUpdated: ¡Ajustes actualizados!
user: Usuario
userCommands: Comandos
userCommandsHelp: >
Una lista separada por espacios con los comandos permitidos para este usuario.
Ejemplo:
userCreated: ¡Usuario creado!
userDeleted: ¡Usuario eliminado!
userManagement: Administración de usuarios
username: Usuario
users: Usuarios
userUpdated: ¡Usuario actualizado!
sidebar:
help: Ayuda
logout: Cerrar sesión
myFiles: Mis archivos
newFile: Nuevo archivo
newFolder: Nueva carpeta
settings: Ajustes
siteSettings: Ajustes del sitio
hugoNew: Nuevo Hugo
preview: Vista previa
search:
images: Images
music: Música
pdf: PDF
pressToExecute: Presiona enter para ejecutar.
pressToSearch: Presiona enter para buscar.
search: Buscar...
searchOrCommand: Buscar o ejecutar un comando...
searchOrSupportedCommand: 'Buscar o ejecutar uno de los comandos soportados:'
type: Escribe y presiona enter para buscar.
types: Tipos
video: Vídeo
writeToSearch: Escribe aquí para buscar
languages:
en: English
fr: Français
pt: Português
es: Español
ja: 日本語
zhCN: 中文 (简体)
zhTW: 中文 (繁體)
time:
unit: Unidad
seconds: Segundos
minutes: Minutos
hours: Horas
days: Días

View File

@@ -1,194 +0,0 @@
permanent: Permanent
buttons:
cancel: Annuler
close: Fermer
copy: Copier
copyFile: Copier le fichier
copyToClipboard: Copier dans le presse-papier
create: Créer
delete: Supprimer
download: Télécharger
info: Info
more: Plus
move: Déplacer
moveFile: Déplacer le fichier
new: Nouveau
next: Suivant
ok: OK
replace: Remplacer
previous: Précédent
rename: Renommer
reportIssue: Rapport d'erreur
save: Enregistrer
search: Chercher
select: Sélectionner
share: Partager
publish: Publier
selectMultiple: Sélection multiple
schedule: Fixer la date
switchView: Changer le mode d'affichage
toggleSidebar: Afficher/Masquer la barre latérale
update: Mettre à jour
upload: Importer
permalink: Obtenir un lien permanent
errors:
forbidden: Vous n'êtes pas autorisé à être ici.
internal: Aïe ! Quelque chose s'est mal passé.
notFound: Impossible d'accéder à cet emplacement.
files:
folders: Dossiers
files: Fichiers
body: Corps
clear: Fermer
closePreview: Fermer la prévisualisation
home: Accueil
lastModified: Dernière modification
loading: Chargement...
lonely: Il semble qu'il n'y ai rien par ici...
metadata: Metadonnées
multipleSelectionEnabled: Sélection multiple activée
name: Nom
size: Taille
sortByName: Trier par nom
sortBySize: Trier par taille
sortByLastModified: Trier par date de dernière modification
help:
click: Sélectionner un élément
ctrl:
click: Sélectionner plusieurs éléments
f: Ouvrir l'invité de recherche
s: Télécharger l'élément actuel
del: Supprimer les éléments sélectionnés
doubleClick: Ouvrir un élément
esc: Désélectionner et/ou fermer la boîte de dialogue
f1: Ouvrir l'aide
f2: Renommer le fichier
help: Aide
login:
password: Mot de passe
submit: Se connecter
username: Utilisateur
wrongCredentials: Identifiants incorrects !
prompts:
copy: Copier
copyMessage: 'Choisissez l''emplacement où copier la sélection :'
currentlyNavigating: 'Dossier courant :'
deleteMessageMultiple: Etes-vous sûr de vouloir supprimer ces {count} élément(s) ?
deleteMessageSingle: Etes-vous sûr de vouloir supprimer cet élément ?
deleteTitle: Supprimer
displayName: 'Nom :'
download: Télécharger
downloadMessage: 'Choisissez le format de téléchargement :'
error: Quelque chose s'est mal passé
fileInfo: Informations
filesSelected: "{count} éléments sélectionnés"
lastModified: Dernière modification
move: Déplacer
moveMessage: 'Choisissez l''emplacement où déplacer la sélection :'
newDir: Nouveau dossier
newDirMessage: 'Nom du nouveau dossier :'
newFile: Nouveau fichier
newFileMessage: 'Nom du nouveau fichier :'
numberDirs: Nombre de dossiers
numberFiles: Nombre de fichiers
replace: Remplacer
replaceMessage: >
Un des fichiers que vous êtes en train d'importer a le même nom qu'un autre déjà présent.
Voulez-vous remplacer le fichier actuel par le nouveau ?
rename: Renommer
renameMessage: Nouveau nom pour
show: Montrer
size: Taille
schedule: Fixer la date
scheduleMessage: Choisissez une date pour planifier la publication de ce post
newArchetype: Créer un nouveau post basé sur un archétype. Votre fichier sera créé dans le dossier de contenu.
settings:
admin: Admin
administrator: Administrateur
allowCommands: Exécuter des commandes
allowEdit: Editer, renommer et supprimer des fichiers ou des dossiers
allowNew: Créer de nouveaux fichiers et dossiers
allowPublish: Publier de nouveaux posts et pages
avoidChanges: "(Laisser vide pour conserver l'actuel)"
changePassword: Modifier le mot de passe
commands: Commandes
commandsHelp: >
Ici vous pouvez définir des commandes qui seront exécutées lors de l'évènement correspondant.
Vous devez indiquer une commande par ligne. Si l'évènement est en rapport avec des fichiers,
par exemple avant et après enregistrement, la variable d'environement "FILE" sera disponible
et contiendra le chemin d'accès vers le fichier.
commandsUpdated: Commandes mises à jour !
customStylesheet: Feuille de style personnalisée
examples: Exemples
globalSettings: Paramètres généraux
language: Langue
newPassword: Votre nouveau mot de passe
newPasswordConfirm: Confirmation du nouveau mot de passe
newUser: Nouvel Utilisateur
password: Mot de passe
passwordUpdated: Mot de passe mis à jour !
permissions: Permissions
permissionsHelp: >
Vous pouvez définir l'utilisateur comme étant un administrateur ou encore choisir les
permissions individuellement. Si vous sélectionnez "Administrateur", toutes les autres
options seront automatiquement activées. La gestion des utilisateurs est un privilège que
seul l'administrateur possède.
profileSettings: Paramètres du profil
ruleExample1: Bloque l'accès à tous les fichiers commençant par un point (comme par exemple .git, .gitignore) dans tous les dossiers
ruleExample2: Bloque l'accès au fichier nommé "Caddyfile" à la racine du dossier utilisateur
rules: Règles
rulesHelp1: >
Vous pouvez définir ici un ensemble de règles pour cet utilisateur.
Les fichiers bloqués ne seront pas affichés et ne seront pas accessibles par l'utilisateur.
Les expressions régulières sont supportées et les chemins d'accès sont relatifs par rapport au dossier de l'utilisateur.
rulesHelp2: >
Chaque règle est définie sur une ligne différente et doit commencer par le mot clé {0} ou {1}.
Vous devez ensuite ajouter {2} si vous utilisez une expression régulière puis l'expression en question ou bien seulement le chemin d'accès.
scope: Portée du dossier utilisateur
settingsUpdated: Les paramètres ont été mis à jour !
user: Utilisateur
userCommands: Commandes
userCommandsHelp: 'Une liste séparée par des espaces des commandes permises pour l''utilisateur. Exemple :'
userCreated: Utilisateur créé !
userDeleted: Utilisateur supprimé !
userManagement: Gestion des utilisateurs
username: Nom d'utilisateur
users: Utilisateurs
userUpdated: Utilisateur mis à jour !
sidebar:
help: Aide
logout: Se déconnecter
myFiles: Mes fichiers
newFile: Nouveau fichier
newFolder: Nouveau dossier
settings: Paramètres
siteSettings: Paramètres du site
hugoNew: Nouveau Hugo
preview: Prévisualiser
search:
images: Images
music: Musique
pdf: PDF
pressToExecute: Appuyez sur Entrée pour exécuter
pressToSearch: Appuyez sur Entrée pour lancer la recherche
search: Recherche en cours...
searchOrCommand: Rechercher ou exécuter une commande...
searchOrSupportedCommand: 'Lancez une recherche ou exécutez une commande parmis les suivantes :'
type: Tapez votre recherche et appuyez sur Entrée
types: Types
video: Video
writeToSearch: Ecrivez ici pour lancer une recherche
languages:
en: English
fr: Français
pt: Português
ja: 日本語
zhCN: 中文 (简体)
zhTW: 中文 (繁體)
es: Español
time:
unit: Unité de temps
seconds: Secondes
minutes: Minutes
hours: Heures
days: Jours

View File

@@ -1,61 +0,0 @@
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import en from './en.yaml'
import fr from './fr.yaml'
import pt from './pt.yaml'
import ja from './ja.yaml'
import zhCN from './zh-cn.yaml'
import zhTW from './zh-tw.yaml'
import es from './es.yaml'
Vue.use(VueI18n)
export function detectLocale () {
let locale = (navigator.language || navigator.browserLangugae).toLowerCase()
switch (true) {
case /^en.*/i.test(locale):
locale = 'en'
break
case /^fr.*/i.test(locale):
locale = 'fr'
break
case /^pt.*/i.test(locale):
locale = 'pt'
break
case /^ja.*/i.test(locale):
locale = 'ja'
break
case /^zh-CN/i.test(locale):
locale = 'zh-cn'
break
case /^zh-TW/i.test(locale):
locale = 'zh-tw'
break
case /^zh.*/i.test(locale):
locale = 'zh-cn'
break
case /^es.*/i.test(locale):
locale = 'es'
break
default:
locale = 'en'
}
return locale
}
const i18n = new VueI18n({
locale: detectLocale(),
fallbackLocale: 'en',
messages: {
'en': en,
'fr': fr,
'pt': pt,
'ja': ja,
'zh-cn': zhCN,
'zh-tw': zhTW,
'es': es
}
})
export default i18n

View File

@@ -1,201 +0,0 @@
permanent: 永久
buttons:
cancel: キャンセル
close: 閉じる
copy: コピー
copyFile: ファイルをコピー
copyToClipboard: クリップボードにコピー
create: 作成
delete: 削除
download: ダウンロード
info: 情報
more: More
move: 移動
moveFile: ファイルを移動
new: 新規
next:
ok: OK
replace: 置き換える
previous:
rename: 名前を変更
reportIssue: 問題を報告
save: 保存
search: 検索
select: 選択
share: シェア
publish: 発表
selectMultiple: 複数選択
schedule: スケジュール
switchView: 表示を切り替わる
toggleSidebar: サイドバーを表示する
update: 更新
upload: アップロード
permalink: 固定リンク
success:
linkCopied: リンクがコピーされました!
errors:
forbidden: アクセスが拒否されました。
internal: 内部エラーが発生しました。
notFound: リソースが見つからなりませんでした。
files:
folders: フォルダ
files: ファイル
body: 本文
clear: クリアー
closePreview: プレビューを閉じる
home: ホーム
lastModified: 最終変更
loading: ローディング...
lonely: ここには何もない...
metadata: メタデータ
multipleSelectionEnabled: 複数選択有効
name: 名前
size: サイズ
sortByName: 名前によるソート
sortBySize: サイズによるソート
sortByLastModified: 最終変更日付によるソート
help:
click: ファイルやディレクトリを選択
ctrl:
click: 複数のファイルやディレクトリを選択
f: 検索を有効にする
s: ファイルを保存またはカレントディレクトリをダウンロード
del: 選択した項目を削除
doubleClick: ファイルやディレクトリをオープン
esc: 選択をクリアーまたはプロンプトを閉じる
f1: このヘルプを表示
f2: ファイルの名前を変更
help: ヘルプ
login:
password: パスワード
submit: ログイン
username: ユーザ名
wrongCredentials: ユーザ名またはパスワードが間違っています。
prompts:
copy: コピー
copyMessage: コピーの目標ディレクトリを選択してください:
currentlyNavigating: 現在閲覧しているディレクトリ:
deleteMessageMultiple: '{count} つのファイルを本当に削除してよろしいですか。'
deleteMessageSingle: このファイル/フォルダを本当に削除してよろしいですか。
deleteTitle: ファイルを削除
displayName: 名前:
download: ファイルをダウンロード
downloadMessage: 圧縮形式を選択してください。
error: あるエラーが発生しました。
fileInfo: ファイル情報
filesSelected: '{count} つのファイルは選択されました。'
lastModified: 最終変更
move: 移動
moveMessage: 移動の目標ディレクトリを選択してください:
newDir: 新しいディレクトリを作成
newDirMessage: 新しいディレクトリの名前を入力してください。
newFile: 新しいファイルを作成
newFileMessage: 新しいファイルの名前を入力してください。
numberDirs: ディレクトリ個数
numberFiles: ファイル個数
replace: 置き換える
replaceMessage: >
アップロードするファイルの中でかち合う名前が一つあります。
既存のファイルを置き換えりませんか。
rename: 名前を変更
renameMessage: 名前を変更しようファイルは:
show: 表示
size: サイズ
schedule: スケジュール
scheduleMessage: このポストの発表日付をスケジュールしてください。
newArchetype: ある元型に基づいて新しいポストを作成します。ファイルは コンテンツフォルダに作成されます。
settings:
admin: 管理者
administrator: 管理者
allowCommands: コマンドの実行
allowEdit: ファイルやディレクトリの編集、名前変更と削除
allowNew: ファイルとディレクトリの作成
allowPublish: ポストとぺーじの発表
avoidChanges: "(変更を避けるために空白にしてください)"
changePassword: パスワードを変更
commands: コマンド
commandsHelp: "\
ここで、名前付きイベントに実行するコマンドを設定することができます。\
一行にコマンド一つを入力してください。\
イベントはファイルに関連する場合、例えばファイル保存の前にまたは後で、\
環境変数 FILE はファイルのパスに割り当てられます。"
commandsUpdated: コマンドは更新されました!
customStylesheet: カスタムスタイルシ ート
examples:
globalSettings: グローバル設定
language: 言語
lockPassword: 新しいパスワードを変更に禁止
newPassword: 新しいパスワード
newPasswordConfirm: 新しいパスワードを確認します
newUser: 新しいユーザー
password: パスワード
passwordUpdated: パスワードは更新されました!
permissions: 権限
permissionsHelp: "\
あなたはユーザーを管理者に設定し、または権限を個々に設定しできます。\
\"管理者\"を選択する場合、その他のすべての選択肢は自動的に設定されます。\
ユーザーの管理は管理者の権限として保留されました。"
profileSettings: プロファイル設定
ruleExample1: "\
各フォルダに名前はドットで始まるファイル(例えば、.git、.gitignore\
へのアクセスを制限します。"
ruleExample2: 範囲のルートパスに名前は Caddyfile のファイルへのアクセスを制限します。
rules: 規則
rulesHelp1: "\
ここに、あなたはこのユーザーの許可または拒否規則を設定できます。\
ブロックされたファイルはリストに表示されません、それではアクセスも制限されます。\
正規表現(regex)のサポートと範囲に相対のパスが提供されています。"
rulesHelp2: "\
一行に規則一つを入力してください、\
その間に規則はキーワード {0} や {1} で始める必要があります。\
そして正規表現を使う場合、{2} と入力し、表現やパスを入力してください。"
scope: 範囲
settingsUpdated: 設定は更新されました!
user: ユーザー
userCommands: ユーザーのコマンド
userCommandsHelp: "\
空白区切りの有効のコマンドのリストを指定してください。\
例:"
userCreated: ユーザーは作成されました!
userDeleted: ユーザーは削除されました!
userManagement: ユーザー管理
username: ユーザー名
users: ユーザー
userUpdated: ユーザーは更新されました!
sidebar:
help: ヘルプ
logout: ログアウト
myFiles: 私のファイル
newFile: 新しいファイルを作成
newFolder: 新しいフォルダを作成
settings: 設定
siteSettings: サイト設定
hugoNew: Hugo New
preview: プレビュー
search:
images: 画像
music: 音楽
pdf: PDF
pressToExecute: Enter を押して実行します。
pressToSearch: Enter を押して検索します。
search: 検索...
searchOrCommand: コマンドを検索または実行します。
searchOrSupportedCommand: サポートしているコマンドを検索または実行します:
type: キーワードを入力し、Enter を押して検索します。
types: 種類
video: ビデオ
writeToSearch: ここにキーワードを入力してください
languages:
en: English
fr: Français
pt: Português
ja: 日本語
zhCN: 中文 (简体)
zhTW: 中文 (繁體)
es: Español
time:
unit: 時間単位
seconds:
minutes:
hours: 時間
days:

View File

@@ -1,204 +0,0 @@
permanent: Permanente
buttons:
cancel: Cancelar
close: Fechar
copy: Copiar
copyFile: Copiar ficheiro
copyToClipboard: Copiar
create: Criar
delete: Eliminar
download: Descarregar
info: Info
more: Mais
move: Mover
moveFile: Mover ficheiro
new: Novo
next: Próximo
ok: OK
previous: Anterior
publish: Publicar
rename: Renomear
replace: Substituir
reportIssue: Reportar Erro
save: Guardar
share: Partilhar
schedule: Agendar
search: Pesquisar
select: Selecionar
selectMultiple: Selecionar múltiplos
switchView: Alterar modo de visão
toggleSidebar: Alternar barra lateral
update: Atualizar
upload: Enviar
permalink: Obter link permanente
success:
linkCopied: Link copiado!
errors:
forbidden: Tu não és bem-vindo aqui.
internal: Algo correu bastante mal.
notFound: Não conseguimos chegar a esta localização.
files:
body: Corpo
clear: Limpar
closePreview: Fechar pré-visualização
files: Ficheiros
folders: Pastas
home: Início
lastModified: Última modificação
loading: A carregar...
lonely: Sinto-me sozinho...
metadata: Metadados
multipleSelectionEnabled: Seleção múltipla ativada
name: Nome
size: Tamanho
sortByLastModified: Ordenar pela última modificação
sortByName: Ordenar pelo nome
sortBySize: Ordenar pelo tamanho
help:
click: selecionar pasta ou ficheiro
ctrl:
click: selecionar várias pastas e ficheiros
f: pesquisar
s: guardar um ficheiro ou descarregar a pasta em que estás a navegar
del: eliminar os ficheiros selecionados
doubleClick: abrir pasta ou ficheiro
esc: limpar seleção e/ou fechar menu
f1: esta informação
f2: renomear ficheiro
help: Ajuda
languages:
en: English
fr: Français
pt: Português
ja: 日本語
zhCN: 中文 (简体)
zhTW: 中文 (繁體)
es: Español
login:
password: Palavra-passe
submit: Login
username: Nome de utilizador
wrongCredentials: Dados errados
prompts:
copy: Copiar
copyMessage: 'Escolhe um lugar para copiar os ficheiros:'
currentlyNavigating: 'A navegar em:'
deleteMessageMultiple: Deseja eliminar {count} ficheiro(s)?
deleteMessageSingle: Deseja eliminar esta pasta/ficheiro?
deleteTitle: Eliminar ficheiros
displayName: 'Nome:'
download: Descarregar ficheiros
downloadMessage: Escolha o formato do ficheiro.
error: Algo correu mal
fileInfo: Informação do ficheiro
filesSelected: "{count} ficheiros selecionados."
lastModified: Última Modificação
move: Mover
moveMessage: 'Escolha uma nova casa para os seus ficheiros:'
newArchetype: Criar um novo post baseado num "archetype". O seu ficheiro será criado
na pasta "content".
newDir: Nova pasta
newDirMessage: Escreva o nome da nova pasta.
newFile: Novo ficheiro
newFileMessage: Escreva o nome do novo ficheiro.
numberDirs: Número de pastas
numberFiles: Número de ficheiros
rename: Renomear
renameMessage: Insira um novo nome para
replace: Substituir
replaceMessage: >
Já existe um ficheiro com nome igual a um dos que está a tentar
enviar. Deseja substituir?
schedule: Agendar
scheduleMessage: Escolha uma data para publicar este post.
show: Mostrar
size: Tamanho
search:
images: Imagens
music: Música
pdf: PDF
pressToExecute: Prima enter para executar.
pressToSearch: Prima enter para pesquisar.
search: Pesquise...
searchOrCommand: Pesquise ou execute um comando...
searchOrSupportedCommand: 'Pesquise ou utilize um dos seus comandos:'
type: Escreva e prima enter para pesquisar.
types: Tipos
video: Vídeos
writeToSearch: Escreva aqui para pesquisar
settings:
admin: Admin
administrator: Administrador
allowCommands: Executar comandos
allowEdit: Editar, renomear e eliminar ficheiros ou pastas
allowNew: Criar novos ficheiros e pastas
allowPublish: Publicar novas páginas e conteúdos
avoidChanges: "(deixe em branco para manter)"
changePassword: Alterar Password
commands: Comandos
commandsHelp: >
Pode definir um conjunto de comandos a executar em determiandos eventos.
Deve escrever um comando por linha. Se o evento estiver relacionado com ficheiros,
como antes e depois de guardar, irá existir uma variável de ambiente denominada
"FILE" com o caminho do ficheiro.
commandsUpdated: Comandos atualizados!
customStylesheet: Estilos Personalizados
examples: Exemplos
globalSettings: Configurações Globais
language: Linguagem
lockPassword: Não permitir que o utilizador altere a palavra-passe
newPassword: Nova palavra-passe
newPasswordConfirm: Confirme a nova palavra-passe
newUser: Novo Utilizador
password: Palavra-passe
passwordUpdated: Palavra-passe atualizada!
permissions: Permissões
permissionsHelp: >
Pode definir o utilizador como administrador ou escolher as permissões
manualmente. Se selecionar a opção "Administrador", todas as outras opções serão
automaticamente selecionadas. A gestão dos utilizadores é um privilégio restringido
aos administradores.
profileSettings: Configurações do Utilizador
ruleExample1: >
previne o acesso a qualquer "dotfile" (como .git, .gitignore) em
qualquer pasta
ruleExample2: bloqueia o acesso ao ficheiro chamado Caddyfile.
rules: Regras
rulesHelp1: >
Aqui pode definir um conjunto de regras para permitir ou bloquear o
acesso do utilizador a determinados ficheiros ou pastas. Os ficheiros bloqueados
não irão aparecer durante a navegação. Suportamos expressões regulares e os caminhos
dos ficheiros devem ser relativos à base do utilizador.
rulesHelp2: >
Cada regra deve ser colocada numa linha diferente e deve começar com
as palavras {0} (permite) ou {1} (bloqueia). Deve escrever, logo de seguida, {2},
caso queira utilizar uma expressão regular. Depois, escreva o caminho do ficheiro/pasta
ou a expressão regular.
scope: Base
settingsUpdated: Configurações atualizadas!
user: Utilizador
userCommands: Comandos
userCommandsHelp: 'Uma lista, separada com espaços, de comandos disponíveis para
este utilizados. Exemplo:'
userCreated: Utilizador criado!
userDeleted: Utilizador eliminado!
userManagement: Gestão de Utilizadores
username: Nome de utilizador
users: Utilizadores
userUpdated: Utilizador atualizado!
sidebar:
help: Ajuda
hugoNew: Hugo New
logout: Sair
myFiles: Ficheiros
newFile: Novo ficheiro
newFolder: Nova pasta
preview: Pré-visualizar
settings: Configurações
siteSettings: Configurações do Site
time:
unit: Unidades de Tempo
seconds: Segundos
minutes: Minutos
hours: Horas
days: Dias

View File

@@ -1,199 +0,0 @@
permanent: 永久
buttons:
cancel: 取消
close: 关闭
copy: 复制
copyFile: 复制文件
copyToClipboard: 复制到剪贴板
create: 创建
delete: 删除
download: 下载
info: 信息
more: 更多
move: 移动
moveFile: 移动文件
new:
next: 下一个
ok: 确定
replace: 替换
previous: 上一个
rename: 重命名
reportIssue: 报告问题
save: 保存
search: 搜索
select: 选择
share: 分享
publish: 发布
selectMultiple: 选择多个
schedule: 计划
switchView: 切换显示方式
toggleSidebar: 切换侧边栏
update: 更新
upload: 上传
permalink: 获取永久链接
success:
linkCopied: 链接已复制!
errors:
forbidden: 你被禁止访问。
internal: 内部出现麻烦了。
notFound: 找不到文件。
files:
folders: 文件夹
files: 文件
body: Body
clear: 清空
closePreview: 关闭预览
home: 主页
lastModified: 最后修改
loading: 加载中...
lonely: 这里没有任何文件...
metadata: 元数据
multipleSelectionEnabled: 多选模式已开启
name: 名称
size: 大小
sortByName: 按名称排序
sortBySize: 按大小排序
sortByLastModified: 按最后修改时间排序
help:
click: 选择文件或目录
ctrl:
click: 选择多个文件或目录
f: 打开搜索框
s: 保存文件或下载当前文件夹
del: 删除所选的文件/文件夹
doubleClick: 打开文件/文件夹
esc: 清除已选项或关闭提示信息
f1: 显示该帮助信息
f2: 重命名文件/文件夹
help: 帮助
login:
password: 密码
submit: 登录
username: 用户名
wrongCredentials: 用户名或密码错误
prompts:
copy: 复制
copyMessage: 请选择欲复制至的目录:
currentlyNavigating: 当前目录:
deleteMessageMultiple: 你确定要删除这 {count} 个文件吗?
deleteMessageSingle: 你确定要删除这个文件/文件夹吗?
deleteTitle: 删除文件
displayName: 名称:
download: 下载文件
downloadMessage: 请选择要下载的压缩格式。
error: 出了一点问题...
fileInfo: 文件信息
filesSelected: 已选择 {count} 个文件。
lastModified: 最后修改
move: 移动
moveMessage: 请选择欲移动至的目录:
newDir: 新建目录
newDirMessage: 请输入新目录的名称。
newFile: 新建文件
newFileMessage: 请输入新文件的名称。
numberDirs: 目录数
numberFiles: 文件数
replace: 替换
replaceMessage: "\
您尝试上传的文件中有一个与现有文件的名称存在冲突。\
是否替换现有的同名文件?"
rename: 重命名
renameMessage: 请输入新名称,旧名称为:
show: 揭示
size: 大小
schedule: 计划
scheduleMessage: 请选择发布这篇帖子的日期。
newArchetype: 创建一个基于原型的新帖子。您的文件将会创建在内容文件夹中。
settings:
admin: 管理员
administrator: 管理员
allowCommands: 执行命令(Linux 代码)
allowEdit: 编辑、重命名或删除文件/目录
allowNew: 创建新文件和目录
allowPublish: 发布新的帖子与页面
avoidChanges: '(留空以避免更改)'
changePassword: 更改密码
commands: 命令(linux 代码)
commandsHelp: "\
在这里,您可以设置在指定事件下执行的命令,一行一条。\
若事件与文件相关,如“在保存文件前”,\
则文件的路径会被赋值给环境变量 \"FILE\"。"
commandsUpdated: 命令已更新!
customStylesheet: 自定义样式表
examples: 例子
globalSettings: 全局设置
language: 语言
lockPassword: 禁止用户修改密码
newPassword: 您的新密码
newPasswordConfirm: 重输一遍新密码
newUser: 新建用户
password: 密码
passwordUpdated: 密码已更新!
permissions: 权限
permissionsHelp: "\
您可以将该用户设置为管理员,也可以单独选择各项权限。\
如果选择了“管理员”,则其他的选项会被自动勾上,\
同时该用户可以管理其他用户。"
profileSettings: 配置文件设置
ruleExample1: "\
阻止用户访问所有文件夹下任何以 . 开头的文件\
(隐藏文件, 例如: .git, .gitignore)。"
ruleExample2: 阻止用户访问其目录范围的根目录下名为 Caddyfile 的文件。
rules: 规则
rulesHelp1: "\
您可以为该用户制定一组黑名单或白名单式的规则,\
被屏蔽的文件将不会显示在列表中,用户也无权限访问,\
支持相对于目录范围的路径。"
rulesHelp2: "\
每行一条规则,且必须以关键词 {0} 或 {1} 开头。\
如要使用正则表达式,请在加上 {2} 之后再附上表达式或路径。"
scope: 目录范围
settingsUpdated: 设置已更新!
user: 用户
userCommands: 用户命令(Linux 代码)
userCommandsHelp: "\
指定该用户可以执行的命令(Linux 代码),用空格分隔。\
例如:"
userCreated: 用户已创建!
userDeleted: 用户已删除!
userManagement: 用户管理
username: 用户名
users: 用户
userUpdated: 用户已更新!
sidebar:
help: 帮助
logout: 登出
myFiles: 我的文件
newFile: 新建文件
newFolder: 新建文件夹
settings: 设置
siteSettings: 网站设置
hugoNew: Hugo New
preview: 预览
search:
images: 图像
music: 音乐
pdf: PDF
pressToExecute: 按回车键执行。
pressToSearch: 按回车键搜索。
search: 搜索...
searchOrCommand: 搜索或者执行命令(Linux 代码)...
searchOrSupportedCommand: 搜索或使用您可以使用的命令(一次只能执行一个命令)
type: 键入并按回车键进行搜索。
types: 类型
video: 视频
writeToSearch: 请输入要搜索的内容
languages:
en: English
fr: Français
pt: Português
ja: 日本語
zhCN: 中文 (简体)
zhTW: 中文 (繁體)
es: Español
time:
unit: 时间单位
seconds:
minutes: 分钟
hours: 小时
days:

View File

@@ -1,199 +0,0 @@
permanent: 永久
buttons:
cancel: 取消
close: 關閉
copy: 複製
copyFile: 複製檔案
copyToClipboard: 複製到剪貼簿
create: 建立
delete: 刪除
download: 下載
info: 資訊
more: 更多
move: 移動
moveFile: 移動檔案
new:
next: 下一個
ok: 確認
replace: 更換
previous: 上一個
rename: 重新命名
reportIssue: 報告問題
save: 儲存
search: 搜尋
select: 選擇
share: 分享
publish: 發佈
selectMultiple: 選擇多個
schedule: 計畫
switchView: 切換顯示方式
toggleSidebar: 切換側邊欄
update: 更新
upload: 上傳
permalink: 獲取永久連結
success:
linkCopied: 連結已複製!
errors:
forbidden: 你被禁止存取。
internal: 內部出現麻煩了。
notFound: 找不到檔案。
files:
folders: 資料夾
files: 檔案
body: Body
clear: 清空
closePreview: 關閉預覽
home: 主頁
lastModified: 最後修改
loading: 讀取中...
lonely: 這裡沒有任何檔案...
metadata: 詮釋資料
multipleSelectionEnabled: 多選模式已開啟
name: 名稱
size: 大小
sortByName: 按名稱排序
sortBySize: 按大小排序
sortByLastModified: 按最後修改時間排序
help:
click: 選擇檔案或目錄
ctrl:
click: 選擇多個檔案或目錄
f: 打開搜尋列
s: 儲存檔案或下載目前資料夾
del: 刪除所選的檔案/資料夾
doubleClick: 打開檔案/資料夾
esc: 清除已選項或關閉提示資訊
f1: 顯示該幫助資訊
f2: 重新命名檔案/資料夾
help: 幫助
login:
password: 密碼
submit: 登入
username: 帳號
wrongCredentials: 帳號或密碼錯誤
prompts:
copy: 複製
copyMessage: 請選擇欲複製至的目錄:
currentlyNavigating: 目前目錄:
deleteMessageMultiple: 你確定要刪除這 {count} 個檔案嗎?
deleteMessageSingle: 你確定要刪除這個檔案/資料夾嗎?
deleteTitle: 刪除檔案
displayName: 名稱:
download: 下載檔案
downloadMessage: 請選擇要下載的壓縮格式。
error: 發出了一點錯誤...
fileInfo: 檔案資訊
filesSelected: 已選擇 {count} 個檔案。
lastModified: 最後修改
move: 移動
moveMessage: 請選擇欲移動至的目錄:
newDir: 建立目錄
newDirMessage: 請輸入新目錄的名稱。
newFile: 建立檔案
newFileMessage: 請輸入新檔案的名稱。
numberDirs: 目錄數
numberFiles: 檔案數
replace: 替換
replaceMessage: "\
您嘗試上傳的檔案中有一個與現有檔案的名稱存在衝突。\
是否取代現有的同名檔案?"
rename: 重新命名
renameMessage: 請輸入新名稱,舊名稱為:
show: 顯示
size: 大小
schedule: 計畫
scheduleMessage: 請選擇發佈這篇貼文的日期。
newArchetype: 建立一個基於原型的新貼文。您的檔案將會建立在內容資料夾中。
settings:
admin: 管理員
administrator: 管理員
allowCommands: 執行命令
allowEdit: 編輯、重命名或刪除檔案/目錄
allowNew: 創建新檔案和目錄
allowPublish: 發佈新的貼文與頁面
avoidChanges: '(留空以避免更改)'
changePassword: 更改密碼
commands: 命令
commandsHelp: "\
在這裡,您可以設定在指定事件下執行的命令,一行一條。\
若事件與檔案相關,如“在保存檔案前”,\
則檔案的路徑會被賦值給環境變數 \"FILE\"。"
commandsUpdated: 命令已更新!
customStylesheet: 自定義樣式表
examples: 範例
globalSettings: 全域設定
language: 語言
lockPassword: 禁止使用者修改密碼
newPassword: 您的新密碼
newPasswordConfirm: 重輸一遍新密碼
newUser: 建立使用者
password: 密碼
passwordUpdated: 密碼已更新!
permissions: 權限
permissionsHelp: "\
您可以將該使用者設置為管理員,也可以單獨選擇各項權限。\
如果選擇了“管理員”,則其他的選項會被自動勾上,\
同時該使用者可以管理其他使用者。"
profileSettings: 設定檔設定
ruleExample1: "\
封鎖使用者存取所有資料夾下任何以 . 開頭的檔案\
(隱藏文件, 例如: .git, .gitignore)。"
ruleExample2: 封鎖使用者存取其目錄範圍的根目錄下名為 Caddyfile 的檔案。
rules: 規則
rulesHelp1: "\
您可以為該使用者製定一組黑名單或白名單式的規則,\
被屏蔽的檔案將不會顯示在清單中,使用者也無權限存取,\
支持相對於目錄範圍的路徑。"
rulesHelp2: "\
每行一條規則,且必須以關鍵字 {0} 或 {1} 開頭。\
如要使用規則運算式,請在加上 {2} 之後再附上運算式或路徑。"
scope: 目錄範圍
settingsUpdated: 設定已更新!
user: 使用者
userCommands: 使用者命令
userCommandsHelp: "\
指定該使用者可以執行的命令,用空格分隔。\
例如:"
userCreated: 使用者已建立!
userDeleted: 使用者已刪除!
userManagement: 使用者管理
username: 使用者名稱
users: 使用者
userUpdated: 使用者已更新!
sidebar:
help: 幫助
logout: 登出
myFiles: 我的檔案
newFile: 建立檔案
newFolder: 建立資料夾
settings: 設定
siteSettings: 網站設定
hugoNew: Hugo New
preview: 預覽
search:
images: 影像
music: 音樂
pdf: PDF
pressToExecute: 按確定鍵執行。
pressToSearch: 按確定鍵搜尋。
search: 搜尋...
searchOrCommand: 搜尋或者執行命令...
searchOrSupportedCommand: 搜尋或使用您可以使用的命令(一次只能執行一個命令)
type: 輸入並按確定鍵進行搜尋。
types: 類型
video: 影片
writeToSearch: 請輸入要搜尋的內容
languages:
en: English
fr: Français
pt: Português
ja: 日本語
zhCN: 中文 (简体)
zhTW: 中文 (繁體)
es: Español
time:
unit: 時間單位
seconds:
minutes: 分鐘
hours: 小時
days:

View File

@@ -1,54 +0,0 @@
import Vue from 'vue'
import App from './App'
import store from './store'
import router from './router'
import i18n from './i18n'
import Noty from 'noty'
Vue.config.productionTip = true
const notyDefault = {
type: 'info',
layout: 'bottomRight',
timeout: 1000,
progressBar: true
}
Vue.prototype.$noty = function (opts) {
new Noty(Object.assign({}, notyDefault, opts)).show()
}
Vue.prototype.$showSuccess = function (message) {
new Noty(Object.assign({}, notyDefault, {
text: message,
type: 'success'
})).show()
}
Vue.prototype.$showError = function (error) {
let n = new Noty(Object.assign({}, notyDefault, {
text: error,
type: 'error',
timeout: null,
buttons: [
Noty.button(i18n.t('buttons.reportIssue'), '', function () {
window.open('https://github.com/hacdias/filemanager/issues/new')
}),
Noty.button(i18n.t('buttons.close'), '', function () {
n.close()
})
]
}))
n.show()
}
/* eslint-disable no-new */
new Vue({
el: '#app',
store,
router,
i18n,
template: '<App/>',
components: { App }
})

View File

@@ -1,161 +0,0 @@
import Vue from 'vue'
import Router from 'vue-router'
import Login from '@/views/Login'
import Layout from '@/views/Layout'
import Files from '@/views/Files'
import Users from '@/views/settings/Users'
import User from '@/views/settings/User'
import Settings from '@/views/Settings'
import GlobalSettings from '@/views/settings/Global'
import ProfileSettings from '@/views/settings/Profile'
import Error403 from '@/views/errors/403'
import Error404 from '@/views/errors/404'
import Error500 from '@/views/errors/500'
import auth from '@/utils/auth'
import store from '@/store'
Vue.use(Router)
const router = new Router({
base: document.querySelector('meta[name="base"]').getAttribute('content'),
mode: 'history',
routes: [
{
path: '/login',
name: 'Login',
component: Login,
beforeEnter: function (to, from, next) {
auth.loggedIn()
.then(() => {
next({ path: '/files' })
})
.catch(() => {
document.title = 'Login'
next()
})
}
},
{
path: '/*',
component: Layout,
meta: {
requiresAuth: true
},
children: [
{
path: '/files/*',
name: 'Files',
component: Files
},
{
path: '/settings',
name: 'Settings',
component: Settings,
redirect: {
path: '/settings/profile'
},
meta: {
disableOnNoAuth: true
},
children: [
{
path: '/settings/profile',
name: 'Profile Settings',
component: ProfileSettings
},
{
path: '/settings/global',
name: 'Global Settings',
component: GlobalSettings,
meta: {
requiresAdmin: true
}
},
{
path: '/settings/users',
name: 'Users',
component: Users,
meta: {
requiresAdmin: true
}
},
{
path: '/settings/users/*',
name: 'User',
component: User,
meta: {
requiresAdmin: true
}
}
]
},
{
path: '/403',
name: 'Forbidden',
component: Error403
},
{
path: '/404',
name: 'Not Found',
component: Error404
},
{
path: '/500',
name: 'Internal Server Error',
component: Error500
},
{
path: '/files',
redirect: {
path: '/files/'
}
},
{
path: '/*',
redirect: {
name: 'Files'
}
}
]
}
]
})
router.beforeEach((to, from, next) => {
document.title = to.name
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
auth.loggedIn()
.then(() => {
if (to.matched.some(record => record.meta.requiresAdmin)) {
if (!store.state.user.admin) {
next({ path: '/403' })
return
}
}
if (to.matched.some(record => record.meta.disableOnNoAuth)) {
if (store.state.noAuth) {
next({ path: '/403' })
return
}
}
next()
})
.catch(e => {
next({
path: '/login',
query: { redirect: to.fullPath }
})
})
return
}
next()
})
export default router

View File

@@ -1,5 +0,0 @@
const getters = {
selectedCount: state => state.selected.length
}
export default getters

View File

@@ -1,42 +0,0 @@
import Vue from 'vue'
import Vuex from 'vuex'
import mutations from './mutations'
import getters from './getters'
Vue.use(Vuex)
const state = {
user: {},
req: {},
clipboard: {
key: '',
items: []
},
css: (() => {
let css = window.CSS
window.CSS = null
return css
})(),
recaptcha: document.querySelector('meta[name="recaptcha"]').getAttribute('content'),
staticGen: document.querySelector('meta[name="staticgen"]').getAttribute('content'),
baseURL: document.querySelector('meta[name="base"]').getAttribute('content'),
noAuth: (document.querySelector('meta[name="noauth"]').getAttribute('content') === 'true'),
version: document.querySelector('meta[name="version"]').getAttribute('content'),
jwt: '',
progress: 0,
schedule: '',
loading: false,
reload: false,
selected: [],
multiple: false,
show: null,
showMessage: null,
showConfirm: null
}
export default new Vuex.Store({
strict: process.env.NODE_ENV !== 'production',
state,
getters,
mutations
})

Some files were not shown because too many files have changed in this diff Show More