Add code from previous version
This commit is contained in:
parent
7b532690ad
commit
4cf445df4d
7
.gitignore
vendored
7
.gitignore
vendored
@ -8,3 +8,10 @@
|
||||
/var/
|
||||
/vendor/
|
||||
###< symfony/framework-bundle ###
|
||||
|
||||
###> symfony/webpack-encore-bundle ###
|
||||
/node_modules/
|
||||
/public/build/
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
###< symfony/webpack-encore-bundle ###
|
||||
|
9
assets/fonts/JetBrainsMono.scss
Normal file
9
assets/fonts/JetBrainsMono.scss
Normal file
@ -0,0 +1,9 @@
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono Medium';
|
||||
src: url('JetBrainsMono/web/eot/JetBrainsMono-Medium.eot');
|
||||
src: url('JetBrainsMono/web/eot/JetBrainsMono-Medium.eot?#iefix') format('embedded-opentype'),
|
||||
url('JetBrainsMono/web/woff/JetBrainsMono-Medium.woff') format('woff')
|
||||
;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
201
assets/fonts/JetBrainsMono/LICENSE
Normal file
201
assets/fonts/JetBrainsMono/LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
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.
|
BIN
assets/fonts/JetBrainsMono/web/eot/JetBrainsMono-Bold-Italic.eot
Normal file
BIN
assets/fonts/JetBrainsMono/web/eot/JetBrainsMono-Bold-Italic.eot
Normal file
Binary file not shown.
BIN
assets/fonts/JetBrainsMono/web/eot/JetBrainsMono-Bold.eot
Normal file
BIN
assets/fonts/JetBrainsMono/web/eot/JetBrainsMono-Bold.eot
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/fonts/JetBrainsMono/web/eot/JetBrainsMono-ExtraBold.eot
Normal file
BIN
assets/fonts/JetBrainsMono/web/eot/JetBrainsMono-ExtraBold.eot
Normal file
Binary file not shown.
BIN
assets/fonts/JetBrainsMono/web/eot/JetBrainsMono-Italic.eot
Normal file
BIN
assets/fonts/JetBrainsMono/web/eot/JetBrainsMono-Italic.eot
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/fonts/JetBrainsMono/web/eot/JetBrainsMono-Medium.eot
Normal file
BIN
assets/fonts/JetBrainsMono/web/eot/JetBrainsMono-Medium.eot
Normal file
Binary file not shown.
BIN
assets/fonts/JetBrainsMono/web/eot/JetBrainsMono-Regular.eot
Normal file
BIN
assets/fonts/JetBrainsMono/web/eot/JetBrainsMono-Regular.eot
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/fonts/JetBrainsMono/web/woff/JetBrainsMono-Bold.woff
Normal file
BIN
assets/fonts/JetBrainsMono/web/woff/JetBrainsMono-Bold.woff
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/fonts/JetBrainsMono/web/woff/JetBrainsMono-ExtraBold.woff
Normal file
BIN
assets/fonts/JetBrainsMono/web/woff/JetBrainsMono-ExtraBold.woff
Normal file
Binary file not shown.
BIN
assets/fonts/JetBrainsMono/web/woff/JetBrainsMono-Italic.woff
Normal file
BIN
assets/fonts/JetBrainsMono/web/woff/JetBrainsMono-Italic.woff
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/fonts/JetBrainsMono/web/woff/JetBrainsMono-Medium.woff
Normal file
BIN
assets/fonts/JetBrainsMono/web/woff/JetBrainsMono-Medium.woff
Normal file
Binary file not shown.
BIN
assets/fonts/JetBrainsMono/web/woff/JetBrainsMono-Regular.woff
Normal file
BIN
assets/fonts/JetBrainsMono/web/woff/JetBrainsMono-Regular.woff
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/fonts/JetBrainsMono/web/woff2/JetBrainsMono-Bold.woff2
Normal file
BIN
assets/fonts/JetBrainsMono/web/woff2/JetBrainsMono-Bold.woff2
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
assets/fonts/JetBrainsMono/web/woff2/JetBrainsMono-Italic.woff2
Normal file
BIN
assets/fonts/JetBrainsMono/web/woff2/JetBrainsMono-Italic.woff2
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/fonts/JetBrainsMono/web/woff2/JetBrainsMono-Medium.woff2
Normal file
BIN
assets/fonts/JetBrainsMono/web/woff2/JetBrainsMono-Medium.woff2
Normal file
Binary file not shown.
BIN
assets/fonts/JetBrainsMono/web/woff2/JetBrainsMono-Regular.woff2
Normal file
BIN
assets/fonts/JetBrainsMono/web/woff2/JetBrainsMono-Regular.woff2
Normal file
Binary file not shown.
BIN
assets/img/favicon.png
Executable file
BIN
assets/img/favicon.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 383 B |
BIN
assets/img/kadet.png
Executable file
BIN
assets/img/kadet.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
BIN
assets/img/logo.png
Executable file
BIN
assets/img/logo.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
BIN
assets/img/overlay.png
Executable file
BIN
assets/img/overlay.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
35
assets/sass/_bootstrap.scss
Executable file
35
assets/sass/_bootstrap.scss
Executable file
@ -0,0 +1,35 @@
|
||||
@import "../../node_modules/bootstrap/scss/functions";
|
||||
@import "../../node_modules/bootstrap/scss/variables";
|
||||
|
||||
$theme-colors: map_merge($theme-colors, (
|
||||
primary: $color-accent,
|
||||
dark: $color-dark
|
||||
));
|
||||
$navbar-dark-color: $color-accent;
|
||||
$link-color: darken(map_get($theme-colors, 'primary'), 10%);
|
||||
|
||||
@import "../../node_modules/bootstrap/scss/bootstrap";
|
||||
|
||||
.navbar-nav {
|
||||
> .nav-item {
|
||||
font-family: $font-family-monospace;
|
||||
> a {
|
||||
padding-left: 1rem !important;
|
||||
padding-right: 1rem !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a.navbar-brand {
|
||||
padding-bottom: 0.25rem;
|
||||
padding-top: 0.25rem;
|
||||
> img {
|
||||
height: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-primary, .btn-primary:hover, .btn-primary:active { color: white; }
|
||||
|
||||
a, button {
|
||||
cursor: pointer;
|
||||
}
|
8
assets/sass/_docs.scss
Executable file
8
assets/sass/_docs.scss
Executable file
@ -0,0 +1,8 @@
|
||||
.chapter--navigation {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
.nav--prev {
|
||||
margin-right: auto;
|
||||
}
|
||||
}
|
59
assets/sass/_keylighter.scss
Executable file
59
assets/sass/_keylighter.scss
Executable file
@ -0,0 +1,59 @@
|
||||
$kl-prefix: "kl-";
|
||||
|
||||
@import "../../vendor/kadet/keylighter/Styles/Html/keylighter";
|
||||
|
||||
pre.keylighter {
|
||||
background-color: #181818;
|
||||
color: $foreground;
|
||||
font-weight: 100;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
pre.keylighter:not(.inline), .try-it textarea {
|
||||
background: #181818 url("../img/overlay.png") no-repeat right 30px bottom 0;
|
||||
padding: 25px !important;
|
||||
}
|
||||
|
||||
pre.keylighter.inline {
|
||||
display: inline-block;
|
||||
padding: .25rem .5rem;
|
||||
vertical-align: baseline;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
code.keylighter {
|
||||
background-color: #181818;
|
||||
color: $foreground;
|
||||
}
|
||||
|
||||
.keylighter.inline {
|
||||
padding: .25rem .5rem;
|
||||
}
|
||||
|
||||
code {
|
||||
color: $background;
|
||||
background: $gray-100;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.close {
|
||||
float: none;
|
||||
font-size: inherit;
|
||||
font-weight: inherit;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
text-shadow: none;
|
||||
opacity: inherit;
|
||||
}
|
||||
|
||||
.close:focus, .close:hover {
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
opacity: inherit;
|
||||
}
|
||||
|
||||
$kl-prefix: "";
|
||||
@import "../../vendor/kadet/keylighter/Styles/Html/keylighter";
|
||||
|
17
assets/sass/_sidebar.scss
Executable file
17
assets/sass/_sidebar.scss
Executable file
@ -0,0 +1,17 @@
|
||||
#sidebar {
|
||||
margin-top: -2rem;
|
||||
padding-top: 2rem;
|
||||
|
||||
.category-title {
|
||||
margin-top: 2rem;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.nav-item.active {
|
||||
border-left: map_get($theme-colors, 'primary') 3px solid;
|
||||
|
||||
a {
|
||||
margin-left: -3px;
|
||||
}
|
||||
}
|
||||
}
|
5
assets/sass/_variables.scss
Executable file
5
assets/sass/_variables.scss
Executable file
@ -0,0 +1,5 @@
|
||||
$color-dark: #131313;
|
||||
$color-accent: #FF9700;
|
||||
$color-light: #DDDDDD;
|
||||
|
||||
$font-family-monospace: "JetBrains Mono Medium", "Fira Mono", monospace;
|
137
assets/sass/style.scss
Executable file
137
assets/sass/style.scss
Executable file
@ -0,0 +1,137 @@
|
||||
@import "variables";
|
||||
@import "bootstrap";
|
||||
|
||||
@import "../fonts/JetBrainsMono";
|
||||
|
||||
@import "keylighter";
|
||||
@import "sidebar";
|
||||
@import "docs";
|
||||
|
||||
$footer-height: 60px;
|
||||
|
||||
html {
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin-bottom: $footer-height;
|
||||
}
|
||||
|
||||
#content {
|
||||
padding: 5rem 0;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
#footer {
|
||||
padding: 1rem;
|
||||
line-height: 2rem;
|
||||
background: $gray-100;
|
||||
border-top: 1px solid $gray-300;
|
||||
vertical-align: middle;
|
||||
height: $footer-height;
|
||||
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0; right: 0;
|
||||
|
||||
span, a {
|
||||
display: inline-block;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
img {
|
||||
display: inline-block;
|
||||
margin-left: .3rem;
|
||||
height: 2rem;
|
||||
vertical-align: middle;
|
||||
margin-top: -4px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.timing {
|
||||
height: 1.5rem;
|
||||
|
||||
.progress-bar {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.snippet {
|
||||
> nav, > aside, > pre, > section {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
aside {
|
||||
font-weight: bolder;
|
||||
}
|
||||
}
|
||||
|
||||
#try-form {
|
||||
padding: 1rem 0;
|
||||
color: $foreground;
|
||||
background: $color-dark;
|
||||
|
||||
textarea, label, input {
|
||||
font-family: $font-family-monospace;
|
||||
}
|
||||
|
||||
textarea, input {
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
background: $background;
|
||||
color: $foreground;
|
||||
}
|
||||
|
||||
textarea {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
&.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.visible {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.d-flex.dual {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.nav-item > a.slim {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
|
||||
#form-toggle {
|
||||
&.visible svg {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
svg {
|
||||
transition: transform 300ms ease, color 100ms ease;
|
||||
}
|
||||
}
|
||||
|
||||
#language-selector {
|
||||
> a.language {
|
||||
margin-bottom: .5rem;
|
||||
margin-right: .5rem;
|
||||
|
||||
display: none;
|
||||
}
|
||||
|
||||
margin-bottom: -.5rem;
|
||||
|
||||
&.standalone > a.standalone { display: inline-block }
|
||||
&.embeddable > a.embeddable { display: inline-block }
|
||||
|
||||
a.hidden { display: none !important; }
|
||||
}
|
26
assets/ts/app.ts
Normal file
26
assets/ts/app.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import 'bootstrap'
|
||||
import TryItForm from "./form"
|
||||
import '@fortawesome/fontawesome-pro/css/all.min.css'
|
||||
|
||||
import '../sass/style.scss'
|
||||
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
|
||||
let $form = $('#try-form');
|
||||
let $toggle = $('#form-toggle');
|
||||
|
||||
let form = new TryItForm($form, $toggle);
|
||||
|
||||
$toggle.click(() => {
|
||||
form.toggle();
|
||||
return false;
|
||||
});
|
||||
|
||||
let $edit = $('#snippet-edit').click(() => {
|
||||
let $snippet = $('#snippet');
|
||||
|
||||
form.source = $snippet.data('source');
|
||||
form.language = $snippet.data('language');
|
||||
|
||||
form.show();
|
||||
});
|
115
assets/ts/form.ts
Executable file
115
assets/ts/form.ts
Executable file
@ -0,0 +1,115 @@
|
||||
export default class TryItForm {
|
||||
private $form: JQuery;
|
||||
private $toggle: JQuery;
|
||||
private $picker: JQuery;
|
||||
|
||||
constructor($form: JQuery, $toggle: JQuery) {
|
||||
this.$form = $form;
|
||||
this.$picker = $form.find('.languages');
|
||||
this.$picker.find('.language').click(e => this.pick(e));
|
||||
this.$form.find('[name="language"]').on('input', e => this.update(e));
|
||||
this.$toggle = $toggle;
|
||||
}
|
||||
|
||||
public toggle() {
|
||||
if (this.$form.hasClass('visible')) {
|
||||
this.hide();
|
||||
} else {
|
||||
this.show();
|
||||
}
|
||||
}
|
||||
|
||||
public show() {
|
||||
this.$form.slideDown({
|
||||
complete: () => this.$form.addClass('visible')
|
||||
});
|
||||
this.$toggle
|
||||
.addClass('visible')
|
||||
.addClass('active');
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public hide() {
|
||||
this.$form.slideUp({
|
||||
complete: () => this.$form.removeClass('visible')
|
||||
});
|
||||
|
||||
this.$toggle
|
||||
.removeClass('visible')
|
||||
.removeClass('active');
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
get source() {
|
||||
return this.$form.find('[name="source"]').val();
|
||||
}
|
||||
|
||||
set source(value: string) {
|
||||
this.$form.find('[name="source"]').val(value);
|
||||
}
|
||||
|
||||
get language() {
|
||||
return this.$form.find('[name="language"]').val();
|
||||
}
|
||||
|
||||
set language(value: string) {
|
||||
this.$form.find('[name="language"]').val(value);
|
||||
}
|
||||
|
||||
public set(source: string, language: string) {
|
||||
this.source = source;
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
public submit() {
|
||||
this.$form.find('form').submit();
|
||||
}
|
||||
|
||||
private update(e: JQueryKeyEventObject) {
|
||||
let $this = $(e.currentTarget);
|
||||
let tokens = $this.val()
|
||||
.split(/\b/)
|
||||
.map(x => x.trim())
|
||||
.filter(x => !!x);
|
||||
|
||||
let last: string|boolean = false;
|
||||
|
||||
if (tokens.length) {
|
||||
last = tokens[tokens.length - 1];
|
||||
if (last == '>') {
|
||||
last = false;
|
||||
}
|
||||
}
|
||||
|
||||
let standalone = tokens.indexOf('>') == -1;
|
||||
this.$picker
|
||||
.toggleClass('embeddable', !standalone)
|
||||
.toggleClass('standalone', standalone);
|
||||
|
||||
this.$picker.find('.language').each((index, elem) => {
|
||||
let $elem = $(elem);
|
||||
let show = !last || (typeof last == 'string' && $elem.text().indexOf(last) !== -1);
|
||||
|
||||
$elem.toggleClass('hidden', !show);
|
||||
})
|
||||
}
|
||||
|
||||
private pick(e: JQueryEventObject) {
|
||||
let $this = $(e.currentTarget);
|
||||
let $selector = this.$form.find('[name="language"]');
|
||||
let input = <HTMLInputElement>$selector[0];
|
||||
let value = input.value;
|
||||
|
||||
let start = input.selectionStart;
|
||||
let end = input.selectionEnd;
|
||||
|
||||
while(start > 0 && value[start-1] != ' ' && start--) {}
|
||||
while(end < value.length && value[end] != ' ' && end++) {}
|
||||
|
||||
input.value = value.substring(0, start) + $this.text().trim() + value.substring(end);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
128
composer.json
128
composer.json
@ -1,64 +1,72 @@
|
||||
{
|
||||
"type": "project",
|
||||
"license": "proprietary",
|
||||
"require": {
|
||||
"php": "^7.2.5",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"symfony/console": "5.0.*",
|
||||
"symfony/dotenv": "5.0.*",
|
||||
"symfony/flex": "^1.3.1",
|
||||
"symfony/framework-bundle": "5.0.*",
|
||||
"symfony/orm-pack": "^1.0",
|
||||
"symfony/twig-pack": "^1.0",
|
||||
"symfony/yaml": "5.0.*"
|
||||
"type": "project",
|
||||
"license": "proprietary",
|
||||
"require": {
|
||||
"php": "^7.2.5",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-json": "*",
|
||||
"kadet/keylighter": "dev-master",
|
||||
"league/commonmark": "^1.3",
|
||||
"sensio/framework-extra-bundle": "^5.5",
|
||||
"symfony/asset": "5.0.*",
|
||||
"symfony/console": "5.0.*",
|
||||
"symfony/dotenv": "5.0.*",
|
||||
"symfony/flex": "^1.3.1",
|
||||
"symfony/framework-bundle": "5.0.*",
|
||||
"symfony/orm-pack": "^1.0",
|
||||
"symfony/profiler-pack": "^1.0",
|
||||
"symfony/twig-pack": "^1.0",
|
||||
"symfony/webpack-encore-bundle": "^1.7",
|
||||
"symfony/yaml": "5.0.*",
|
||||
"tightenco/collect": "^7.5"
|
||||
},
|
||||
"require-dev": {
|
||||
},
|
||||
"config": {
|
||||
"preferred-install": {
|
||||
"*": "dist"
|
||||
},
|
||||
"require-dev": {
|
||||
},
|
||||
"config": {
|
||||
"preferred-install": {
|
||||
"*": "dist"
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"App\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"replace": {
|
||||
"paragonie/random_compat": "2.*",
|
||||
"symfony/polyfill-ctype": "*",
|
||||
"symfony/polyfill-iconv": "*",
|
||||
"symfony/polyfill-php72": "*",
|
||||
"symfony/polyfill-php71": "*",
|
||||
"symfony/polyfill-php70": "*",
|
||||
"symfony/polyfill-php56": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"auto-scripts": {
|
||||
"cache:clear": "symfony-cmd",
|
||||
"assets:install %PUBLIC_DIR%": "symfony-cmd"
|
||||
},
|
||||
"post-install-cmd": [
|
||||
"@auto-scripts"
|
||||
],
|
||||
"post-update-cmd": [
|
||||
"@auto-scripts"
|
||||
]
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/symfony": "*"
|
||||
},
|
||||
"extra": {
|
||||
"symfony": {
|
||||
"allow-contrib": false,
|
||||
"require": "5.0.*"
|
||||
}
|
||||
"sort-packages": true
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"App\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"replace": {
|
||||
"paragonie/random_compat": "2.*",
|
||||
"symfony/polyfill-ctype": "*",
|
||||
"symfony/polyfill-iconv": "*",
|
||||
"symfony/polyfill-php72": "*",
|
||||
"symfony/polyfill-php71": "*",
|
||||
"symfony/polyfill-php70": "*",
|
||||
"symfony/polyfill-php56": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"auto-scripts": {
|
||||
"cache:clear": "symfony-cmd",
|
||||
"assets:install %PUBLIC_DIR%": "symfony-cmd"
|
||||
},
|
||||
"post-install-cmd": [
|
||||
"@auto-scripts"
|
||||
],
|
||||
"post-update-cmd": [
|
||||
"@auto-scripts"
|
||||
]
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/symfony": "*"
|
||||
},
|
||||
"extra": {
|
||||
"symfony": {
|
||||
"allow-contrib": false,
|
||||
"require": "5.0.*"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
490
composer.lock
generated
490
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "f5f287a8a8950e4398c1b309fe77101d",
|
||||
"content-hash": "e2304bcfe75a51f30dd11d1699bab82a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
@ -1228,6 +1228,133 @@
|
||||
],
|
||||
"time": "2014-01-12T16:20:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "kadet/keylighter",
|
||||
"version": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/kadet1090/KeyLighter.git",
|
||||
"reference": "f3f2804ba69766681f8df1887f8e7d58a5504642"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/kadet1090/KeyLighter/zipball/f3f2804ba69766681f8df1887f8e7d58a5504642",
|
||||
"reference": "f3f2804ba69766681f8df1887f8e7d58a5504642",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"easybook/geshi": "v1.0.8.19",
|
||||
"ext-json": "*",
|
||||
"phpunit/phpunit": "^7.0",
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"symfony/console": "^4.4",
|
||||
"symfony/var-exporter": "^4.4"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/console": "Allows usage of keylighters CLI utility."
|
||||
},
|
||||
"bin": [
|
||||
"bin/keylighter"
|
||||
],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Kadet\\Highlighter\\": "."
|
||||
},
|
||||
"files": [
|
||||
"./functions.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Kacper Donat",
|
||||
"email": "contact@kadet.net"
|
||||
}
|
||||
],
|
||||
"description": "Yet another syntax highlighter for PHP",
|
||||
"time": "2020-04-09T07:40:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/commonmark",
|
||||
"version": "1.3.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/commonmark.git",
|
||||
"reference": "5a67afc2572ec6d430526cdc9c637ef124812389"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/5a67afc2572ec6d430526cdc9c637ef124812389",
|
||||
"reference": "5a67afc2572ec6d430526cdc9c637ef124812389",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"php": "^7.1"
|
||||
},
|
||||
"conflict": {
|
||||
"scrutinizer/ocular": "1.7.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"cebe/markdown": "~1.0",
|
||||
"commonmark/commonmark.js": "0.29.1",
|
||||
"erusev/parsedown": "~1.0",
|
||||
"ext-json": "*",
|
||||
"github/gfm": "0.29.0",
|
||||
"michelf/php-markdown": "~1.4",
|
||||
"mikehaertl/php-shellcommand": "^1.4",
|
||||
"phpstan/phpstan-shim": "^0.11.5",
|
||||
"phpunit/phpunit": "^7.5",
|
||||
"scrutinizer/ocular": "^1.5",
|
||||
"symfony/finder": "^4.2"
|
||||
},
|
||||
"bin": [
|
||||
"bin/commonmark"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\CommonMark\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Colin O'Dell",
|
||||
"email": "colinodell@gmail.com",
|
||||
"homepage": "https://www.colinodell.com",
|
||||
"role": "Lead Developer"
|
||||
}
|
||||
],
|
||||
"description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and Github-Flavored Markdown (GFM)",
|
||||
"homepage": "https://commonmark.thephpleague.com",
|
||||
"keywords": [
|
||||
"commonmark",
|
||||
"flavored",
|
||||
"gfm",
|
||||
"github",
|
||||
"github-flavored",
|
||||
"markdown",
|
||||
"md",
|
||||
"parser"
|
||||
],
|
||||
"time": "2020-04-05T16:01:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ocramius/package-versions",
|
||||
"version": "1.5.1",
|
||||
@ -1537,6 +1664,149 @@
|
||||
],
|
||||
"time": "2020-03-23T09:12:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sensio/framework-extra-bundle",
|
||||
"version": "v5.5.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sensiolabs/SensioFrameworkExtraBundle.git",
|
||||
"reference": "d0585d4825a87a5030ca8cd34adb4a17e1066c17"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sensiolabs/SensioFrameworkExtraBundle/zipball/d0585d4825a87a5030ca8cd34adb4a17e1066c17",
|
||||
"reference": "d0585d4825a87a5030ca8cd34adb4a17e1066c17",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/annotations": "^1.0",
|
||||
"php": ">=7.1.3",
|
||||
"symfony/config": "^4.4|^5.0",
|
||||
"symfony/dependency-injection": "^4.4|^5.0",
|
||||
"symfony/framework-bundle": "^4.4|^5.0",
|
||||
"symfony/http-kernel": "^4.4|^5.0"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/doctrine-cache-bundle": "<1.3.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/doctrine-bundle": "^1.11|^2.0",
|
||||
"doctrine/orm": "^2.5",
|
||||
"nyholm/psr7": "^1.1",
|
||||
"symfony/browser-kit": "^4.4|^5.0",
|
||||
"symfony/dom-crawler": "^4.4|^5.0",
|
||||
"symfony/expression-language": "^4.4|^5.0",
|
||||
"symfony/finder": "^4.4|^5.0",
|
||||
"symfony/monolog-bridge": "^4.0|^5.0",
|
||||
"symfony/monolog-bundle": "^3.2",
|
||||
"symfony/phpunit-bridge": "^4.3.5|^5.0",
|
||||
"symfony/psr-http-message-bridge": "^1.1",
|
||||
"symfony/security-bundle": "^4.4|^5.0",
|
||||
"symfony/twig-bundle": "^4.4|^5.0",
|
||||
"symfony/yaml": "^4.4|^5.0",
|
||||
"twig/twig": "^1.34|^2.4|^3.0"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.5.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Sensio\\Bundle\\FrameworkExtraBundle\\": "src/"
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
}
|
||||
],
|
||||
"description": "This bundle provides a way to configure your controllers with annotations",
|
||||
"keywords": [
|
||||
"annotations",
|
||||
"controllers"
|
||||
],
|
||||
"time": "2020-04-06T12:20:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/asset",
|
||||
"version": "v5.0.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/asset.git",
|
||||
"reference": "8872144d5d9f28eec62857400bb437693ef4d082"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/asset/zipball/8872144d5d9f28eec62857400bb437693ef4d082",
|
||||
"reference": "8872144d5d9f28eec62857400bb437693ef4d082",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/http-foundation": "^4.4|^5.0",
|
||||
"symfony/http-kernel": "^4.4|^5.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/http-foundation": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Asset\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Asset Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-03-27T16:56:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/cache",
|
||||
"version": "v5.0.7",
|
||||
@ -3158,6 +3428,34 @@
|
||||
],
|
||||
"time": "2020-02-27T09:26:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/profiler-pack",
|
||||
"version": "v1.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/profiler-pack.git",
|
||||
"reference": "99c4370632c2a59bb0444852f92140074ef02209"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/profiler-pack/zipball/99c4370632c2a59bb0444852f92140074ef02209",
|
||||
"reference": "99c4370632c2a59bb0444852f92140074ef02209",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.0",
|
||||
"symfony/stopwatch": "*",
|
||||
"symfony/twig-bundle": "*",
|
||||
"symfony/web-profiler-bundle": "*"
|
||||
},
|
||||
"type": "symfony-pack",
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "A pack for the Symfony web profiler",
|
||||
"time": "2018-12-10T12:11:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/routing",
|
||||
"version": "v5.0.7",
|
||||
@ -3822,6 +4120,139 @@
|
||||
],
|
||||
"time": "2020-03-27T16:56:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/web-profiler-bundle",
|
||||
"version": "v5.0.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/web-profiler-bundle.git",
|
||||
"reference": "635bf7fe86b67b0d3903a3013709fe028ac43b59"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/635bf7fe86b67b0d3903a3013709fe028ac43b59",
|
||||
"reference": "635bf7fe86b67b0d3903a3013709fe028ac43b59",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2.5",
|
||||
"symfony/config": "^4.4|^5.0",
|
||||
"symfony/framework-bundle": "^4.4|^5.0",
|
||||
"symfony/http-kernel": "^4.4|^5.0",
|
||||
"symfony/routing": "^4.4|^5.0",
|
||||
"symfony/twig-bundle": "^4.4|^5.0",
|
||||
"twig/twig": "^2.10|^3.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/form": "<4.4",
|
||||
"symfony/messenger": "<4.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/browser-kit": "^4.4|^5.0",
|
||||
"symfony/console": "^4.4|^5.0",
|
||||
"symfony/css-selector": "^4.4|^5.0",
|
||||
"symfony/dependency-injection": "^4.4|^5.0",
|
||||
"symfony/stopwatch": "^4.4|^5.0"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Bundle\\WebProfilerBundle\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony WebProfilerBundle",
|
||||
"homepage": "https://symfony.com",
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-03-27T16:56:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/webpack-encore-bundle",
|
||||
"version": "v1.7.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/webpack-encore-bundle.git",
|
||||
"reference": "5c0f659eceae87271cce54bbdfb05ed8ec9007bd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/webpack-encore-bundle/zipball/5c0f659eceae87271cce54bbdfb05ed8ec9007bd",
|
||||
"reference": "5c0f659eceae87271cce54bbdfb05ed8ec9007bd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"symfony/asset": "^3.4 || ^4.0 || ^5.0",
|
||||
"symfony/config": "^3.4 || ^4.0 || ^5.0",
|
||||
"symfony/dependency-injection": "^3.4 || ^4.0 || ^5.0",
|
||||
"symfony/http-kernel": "^3.4 || ^4.0 || ^5.0",
|
||||
"symfony/service-contracts": "^1.0 || ^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/framework-bundle": "^3.4 || ^4.0 || ^5.0",
|
||||
"symfony/phpunit-bridge": "^4.3.5 || ^5.0",
|
||||
"symfony/twig-bundle": "^3.4 || ^4.0 || ^5.0",
|
||||
"symfony/web-link": "^3.4 || ^4.0 || ^5.0"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"name": "symfony/webpack-encore",
|
||||
"url": "https://github.com/symfony/webpack-encore"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\WebpackEncoreBundle\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Integration with your Symfony app & Webpack Encore!",
|
||||
"time": "2020-01-31T15:31:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v5.0.7",
|
||||
@ -3895,6 +4326,56 @@
|
||||
],
|
||||
"time": "2020-03-30T11:42:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "tightenco/collect",
|
||||
"version": "v7.5.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/tightenco/collect.git",
|
||||
"reference": "1f5f7a36657a126fa035c7cfaafd738391690967"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/tightenco/collect/zipball/1f5f7a36657a126fa035c7cfaafd738391690967",
|
||||
"reference": "1f5f7a36657a126fa035c7cfaafd738391690967",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"symfony/var-dumper": "^3.4 || ^4.0 || ^5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.0",
|
||||
"nesbot/carbon": "^2.23.0",
|
||||
"phpunit/phpunit": "^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/Collect/Support/helpers.php",
|
||||
"src/Collect/Support/alias.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Tightenco\\Collect\\": "src/Collect"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylorotwell@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Collect - Illuminate Collections as a separate package.",
|
||||
"keywords": [
|
||||
"collection",
|
||||
"laravel"
|
||||
],
|
||||
"time": "2020-04-08T17:29:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/extra-bundle",
|
||||
"version": "v3.0.3",
|
||||
@ -4133,13 +4614,16 @@
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"stability-flags": {
|
||||
"kadet/keylighter": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": "^7.2.5",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*"
|
||||
"ext-iconv": "*",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "1.1.0"
|
||||
|
@ -6,4 +6,7 @@ return [
|
||||
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
|
||||
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
|
||||
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
|
||||
Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true],
|
||||
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
|
||||
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
|
||||
];
|
||||
|
3
config/packages/assets.yaml
Normal file
3
config/packages/assets.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
framework:
|
||||
assets:
|
||||
json_manifest_path: '%kernel.project_dir%/public/build/manifest.json'
|
6
config/packages/dev/web_profiler.yaml
Normal file
6
config/packages/dev/web_profiler.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
web_profiler:
|
||||
toolbar: true
|
||||
intercept_redirects: false
|
||||
|
||||
framework:
|
||||
profiler: { only_exceptions: false }
|
@ -10,7 +10,7 @@ framework:
|
||||
cookie_secure: auto
|
||||
cookie_samesite: lax
|
||||
|
||||
#esi: true
|
||||
#fragments: true
|
||||
esi: true
|
||||
fragments: true
|
||||
php_errors:
|
||||
log: true
|
||||
|
4
config/packages/prod/webpack_encore.yaml
Normal file
4
config/packages/prod/webpack_encore.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
#webpack_encore:
|
||||
# Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes)
|
||||
# Available in version 1.2
|
||||
#cache: true
|
3
config/packages/sensio_framework_extra.yaml
Normal file
3
config/packages/sensio_framework_extra.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
sensio_framework_extra:
|
||||
router:
|
||||
annotations: false
|
6
config/packages/test/web_profiler.yaml
Normal file
6
config/packages/test/web_profiler.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
web_profiler:
|
||||
toolbar: false
|
||||
intercept_redirects: false
|
||||
|
||||
framework:
|
||||
profiler: { collect: false }
|
2
config/packages/test/webpack_encore.yaml
Normal file
2
config/packages/test/webpack_encore.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
#webpack_encore:
|
||||
# strict_mode: false
|
@ -1,2 +1,5 @@
|
||||
twig:
|
||||
default_path: '%kernel.project_dir%/templates'
|
||||
default_path: '%kernel.project_dir%/templates'
|
||||
globals:
|
||||
versioner: '@twig.versioner'
|
||||
keylighter: '@twig.keylighter'
|
||||
|
25
config/packages/webpack_encore.yaml
Normal file
25
config/packages/webpack_encore.yaml
Normal file
@ -0,0 +1,25 @@
|
||||
webpack_encore:
|
||||
# The path where Encore is building the assets - i.e. Encore.setOutputPath()
|
||||
output_path: '%kernel.project_dir%/public/build'
|
||||
# If multiple builds are defined (as shown below), you can disable the default build:
|
||||
# output_path: false
|
||||
|
||||
# if using Encore.enableIntegrityHashes() and need the crossorigin attribute (default: false, or use 'anonymous' or 'use-credentials')
|
||||
# crossorigin: 'anonymous'
|
||||
|
||||
# preload all rendered script and link tags automatically via the http2 Link header
|
||||
# preload: true
|
||||
|
||||
# Throw an exception if the entrypoints.json file is missing or an entry is missing from the data
|
||||
# strict_mode: false
|
||||
|
||||
# if you have multiple builds:
|
||||
# builds:
|
||||
# pass "frontend" as the 3rg arg to the Twig functions
|
||||
# {{ encore_entry_script_tags('entry1', null, 'frontend') }}
|
||||
|
||||
# frontend: '%kernel.project_dir%/public/frontend/build'
|
||||
|
||||
# Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes)
|
||||
# Put in config/packages/prod/webpack_encore.yaml
|
||||
# cache: true
|
7
config/routes/dev/web_profiler.yaml
Normal file
7
config/routes/dev/web_profiler.yaml
Normal file
@ -0,0 +1,7 @@
|
||||
web_profiler_wdt:
|
||||
resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml'
|
||||
prefix: /_wdt
|
||||
|
||||
web_profiler_profiler:
|
||||
resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml'
|
||||
prefix: /_profiler
|
@ -1,27 +1,64 @@
|
||||
# This file is the entry point to configure your own services.
|
||||
# Files in the packages/ subdirectory configure your dependencies.
|
||||
|
||||
# Put parameters here that don't need to change on each machine where the app is deployed
|
||||
# put parameters here that don't need to change on each machine where the app is deployed
|
||||
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
|
||||
parameters:
|
||||
keylighter_dir: '%kernel.project_dir%/var/keylighter/'
|
||||
keylighter_temp_dir: '%kernel.cache_dir%/keylighter/'
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
_defaults:
|
||||
autowire: true # Automatically injects dependencies in your services.
|
||||
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
|
||||
|
||||
# automatically injects dependencies in your services
|
||||
autowire: true
|
||||
# automatically registers your services as commands, event subscribers, etc.
|
||||
autoconfigure: true
|
||||
# this means you cannot fetch services directly from the container via $container->get()
|
||||
# if you need to do this, you can override this setting on individual services
|
||||
public: false
|
||||
# makes classes in src/ available to be used as services
|
||||
# this creates a service per class whose id is the fully-qualified class name
|
||||
App\:
|
||||
resource: '../src/*'
|
||||
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
|
||||
# you can exclude directories or files
|
||||
# but if a service is unused, it's removed anyway
|
||||
exclude: '../src/{Entity,Repository,Tests,Listener,Migrations}'
|
||||
lazy: true
|
||||
|
||||
# controllers are imported separately to make sure services can be injected
|
||||
# as action arguments even if you don't extend any base controller class
|
||||
App\Service\:
|
||||
resource: '../src/Service/*'
|
||||
public: true
|
||||
|
||||
# controllers are imported separately to make sure they're public
|
||||
# and have a tag that allows actions to type-hint services
|
||||
App\Controller\:
|
||||
resource: '../src/Controller'
|
||||
public: true
|
||||
tags: ['controller.service_arguments']
|
||||
|
||||
# add more service definitions when explicit configuration is needed
|
||||
# please note that last definitions always *replace* previous ones
|
||||
# controllers are imported separately to make sure they're public
|
||||
# and have a tag that allows actions to type-hint services
|
||||
App\Command\:
|
||||
resource: '../src/Command'
|
||||
public: true
|
||||
tags: ['console.command']
|
||||
|
||||
App\Listener\KeyLighterVersionListener:
|
||||
tags:
|
||||
- { name: kernel.event_listener, event: kernel.request }
|
||||
- { name: kernel.event_listener, event: kernel.response }
|
||||
|
||||
Kadet\Highlighter\KeyLighter:
|
||||
class: Kadet\Highlighter\KeyLighter
|
||||
factory: 'Kadet\Highlighter\KeyLighter::get'
|
||||
|
||||
League\CommonMark\Environment:
|
||||
factory: ['League\CommonMark\Environment', 'createGFMEnvironment']
|
||||
calls:
|
||||
- ['addExtension', ['@App\CommonMark\KeylighterExtension']]
|
||||
|
||||
League\CommonMark\EnvironmentInterface: '@League\CommonMark\Environment'
|
||||
League\CommonMark\DocParser: ~
|
||||
League\CommonMark\DocParserInterface: '@League\CommonMark\DocParser'
|
||||
League\CommonMark\HtmlRenderer: ~
|
||||
|
||||
twig.versioner: '@App\Service\KeyLighterVersioner'
|
||||
twig.keylighter: '@App\Twig\KeyLighterTwigAccess'
|
||||
|
27
package.json
Normal file
27
package.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"@symfony/webpack-encore": "^0.28.2",
|
||||
"@types/bootstrap": "^3.3.32",
|
||||
"@types/jquery": "^2.0.41",
|
||||
"bootstrap": "4.0.0-beta",
|
||||
"core-js": "^3.0.0",
|
||||
"firacode": "^1.205.0",
|
||||
"jquery": "^3.2.1",
|
||||
"node-sass": "^4.13.1",
|
||||
"popper.js": "^1.12.5",
|
||||
"regenerator-runtime": "^0.13.2",
|
||||
"sass-loader": "7.0.3",
|
||||
"ts-loader": "^5.3.0",
|
||||
"typescript": "^3.8.3",
|
||||
"webpack-notifier": "^1.6.0",
|
||||
"@fortawesome/fontawesome-pro": "^5.13.0"
|
||||
},
|
||||
"license": "UNLICENSED",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev-server": "encore dev-server",
|
||||
"dev": "encore dev",
|
||||
"watch": "encore dev --watch",
|
||||
"build": "encore production --progress"
|
||||
}
|
||||
}
|
40
src/Command/KeyLighterBenchmark.php
Executable file
40
src/Command/KeyLighterBenchmark.php
Executable file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
|
||||
use App\Service\KeyLighterVersioner;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class KeyLighterBenchmark extends Command
|
||||
{
|
||||
/** @var \App\Service\KeyLighterVersioner */
|
||||
private $versioner;
|
||||
|
||||
/**
|
||||
* KeyLighterUpdate constructor.
|
||||
*
|
||||
* @param \App\Service\KeyLighterVersioner $versioner
|
||||
*/
|
||||
public function __construct(KeyLighterVersioner $versioner)
|
||||
{
|
||||
$this->versioner = $versioner;
|
||||
|
||||
parent::__construct('keylighter:benchmark');
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->addArgument('version', InputArgument::REQUIRED, 'keylighter version to benchmark');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$directory = $this->versioner->getDirectory($input->getArgument('version'));
|
||||
|
||||
}
|
||||
}
|
37
src/Command/KeyLighterUpdate.php
Executable file
37
src/Command/KeyLighterUpdate.php
Executable file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
|
||||
use App\Service\KeyLighterVersioner;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class KeyLighterUpdate extends Command
|
||||
{
|
||||
/** @var \App\Service\KeyLighterVersioner */
|
||||
private $versioner;
|
||||
|
||||
/**
|
||||
* KeyLighterUpdate constructor.
|
||||
*
|
||||
* @param \App\Service\KeyLighterVersioner $versioner
|
||||
*/
|
||||
public function __construct(KeyLighterVersioner $versioner)
|
||||
{
|
||||
$this->versioner = $versioner;
|
||||
|
||||
parent::__construct('keylighter:update');
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->versioner->updateAll();
|
||||
}
|
||||
}
|
32
src/CommonMark/KeylighterCodeRenderer.php
Normal file
32
src/CommonMark/KeylighterCodeRenderer.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\CommonMark;
|
||||
|
||||
use Kadet\Highlighter\KeyLighter;
|
||||
use League\CommonMark\Block\Element\AbstractBlock;
|
||||
use League\CommonMark\Block\Renderer\BlockRendererInterface;
|
||||
use League\CommonMark\ElementRendererInterface;
|
||||
use League\CommonMark\HtmlElement;
|
||||
|
||||
class KeylighterCodeRenderer implements BlockRendererInterface
|
||||
{
|
||||
private $keylighter;
|
||||
private $formatter;
|
||||
|
||||
public function __construct(KeyLighter $keylighter)
|
||||
{
|
||||
$this->keylighter = $keylighter;
|
||||
$this->formatter = $keylighter->getFormatter('html');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function render(AbstractBlock $block, ElementRendererInterface $htmlRenderer, bool $inTightList = false)
|
||||
{
|
||||
$language = $this->keylighter->getLanguage($block->getInfo());
|
||||
$text = $block->getStringContent();
|
||||
|
||||
return new HtmlElement('pre', ['class' => 'keylighter'], @$this->keylighter->highlight($text, $language, $this->formatter));
|
||||
}
|
||||
}
|
58
src/CommonMark/KeylighterExtension.php
Normal file
58
src/CommonMark/KeylighterExtension.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\CommonMark;
|
||||
|
||||
use League\CommonMark\Block\Element\AbstractBlock;
|
||||
use League\CommonMark\Block\Element\FencedCode;
|
||||
use League\CommonMark\Block\Element\IndentedCode;
|
||||
use League\CommonMark\Block\Renderer\BlockRendererInterface;
|
||||
use League\CommonMark\ConfigurableEnvironmentInterface;
|
||||
use League\CommonMark\ElementRendererInterface;
|
||||
use League\CommonMark\Extension\ExtensionInterface;
|
||||
use League\CommonMark\Extension\Table\Table;
|
||||
use League\CommonMark\Extension\Table\TableRenderer;
|
||||
use Symfony\Contracts\Service\ServiceProviderInterface;
|
||||
use Symfony\Contracts\Service\ServiceSubscriberInterface;
|
||||
|
||||
class KeylighterExtension implements ExtensionInterface, ServiceSubscriberInterface
|
||||
{
|
||||
private $provider;
|
||||
|
||||
public function __construct(ServiceProviderInterface $provider)
|
||||
{
|
||||
$this->provider = $provider;
|
||||
}
|
||||
|
||||
public function register(ConfigurableEnvironmentInterface $environment)
|
||||
{
|
||||
$environment->addBlockRenderer(FencedCode::class, $this->provider->get(KeylighterCodeRenderer::class), 150);
|
||||
$environment->addBlockRenderer(IndentedCode::class, $this->provider->get(KeylighterCodeRenderer::class), 150);
|
||||
|
||||
$environment->addBlockRenderer(Table::class, new class implements BlockRendererInterface {
|
||||
private $decorated;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->decorated = new TableRenderer();
|
||||
}
|
||||
|
||||
public function render(AbstractBlock $block, ElementRendererInterface $htmlRenderer, bool $inTightList = false)
|
||||
{
|
||||
$element = $this->decorated->render($block, $htmlRenderer, $inTightList);
|
||||
$element->setAttribute('class', 'table');
|
||||
|
||||
return $element;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function getSubscribedServices()
|
||||
{
|
||||
return [
|
||||
KeylighterCodeRenderer::class
|
||||
];
|
||||
}
|
||||
}
|
0
src/Migrations/.gitignore → src/Consumer/.gitignore
vendored
Normal file → Executable file
0
src/Migrations/.gitignore → src/Consumer/.gitignore
vendored
Normal file → Executable file
205
src/Consumer/UpdateKeylighterConsumer.php
Executable file
205
src/Consumer/UpdateKeylighterConsumer.php
Executable file
@ -0,0 +1,205 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Consumer;
|
||||
|
||||
|
||||
use App\Exception\CommandExecuteException;
|
||||
use FilesystemIterator;
|
||||
use OldSound\RabbitMqBundle\RabbitMq\ConsumerInterface;
|
||||
use PhpAmqpLib\Message\AMQPMessage;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Filesystem\Exception\IOException;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
class UpdateKeylighterConsumer implements ConsumerInterface
|
||||
{
|
||||
/** @var \App\Service\KeyLighterVersioner */
|
||||
private $versioner;
|
||||
|
||||
/**
|
||||
* @var \Psr\Log\LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
private $composer;
|
||||
private $filesystem;
|
||||
|
||||
private $temp;
|
||||
private $installed;
|
||||
private $box;
|
||||
|
||||
/**
|
||||
* UpdateKeylighterConsumer constructor.
|
||||
*
|
||||
* @param \Psr\Log\LoggerInterface $logger
|
||||
* @param \Symfony\Component\Filesystem\Filesystem $filesystem
|
||||
* @param $composer
|
||||
* @param $box
|
||||
*/
|
||||
public function __construct(LoggerInterface $logger, Filesystem $filesystem, $composer, $box)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->composer = $composer;
|
||||
$this->box = $box;
|
||||
$this->filesystem = $filesystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTempFile()
|
||||
{
|
||||
return $this->filesystem->tempnam($this->temp, 'keylighter');
|
||||
}
|
||||
|
||||
public function getTempDir()
|
||||
{
|
||||
$path = $this->temp.DIRECTORY_SEPARATOR.uniqid('keylighter');
|
||||
|
||||
$this->filesystem->mkdir($path, 0755);
|
||||
|
||||
return realpath($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $temp
|
||||
*/
|
||||
public function setTemp($temp)
|
||||
{
|
||||
$this->temp = $temp;
|
||||
$this->filesystem->mkdir($this->temp, 0755);
|
||||
}
|
||||
|
||||
public function setInstalledFile(string $path)
|
||||
{
|
||||
$this->installed = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AMQPMessage $msg The message
|
||||
*
|
||||
* @return mixed false to reject and requeue, any other value to acknowledge
|
||||
*/
|
||||
public function execute(AMQPMessage $msg)
|
||||
{
|
||||
list($destination, $revision) = unserialize($msg->getBody());
|
||||
|
||||
$this->logger->info(sprintf('Downloading KeyLighter revision %s to %s', $revision['version'], $destination));
|
||||
|
||||
return $this->download($revision, $destination);
|
||||
}
|
||||
|
||||
private function download($revision, $destination)
|
||||
{
|
||||
$temp = $this->getTempDir();
|
||||
|
||||
$archive = new \ZipArchive();
|
||||
$archive->open($this->downloadArchive($revision));
|
||||
$archive->extractTo($temp);
|
||||
$archive->close();
|
||||
|
||||
$this->move($temp, $destination);
|
||||
|
||||
$cwd = getcwd();
|
||||
chdir($destination);
|
||||
try {
|
||||
$this->runCommands([ $this->composer.' install -n --no-ansi --quiet' ]);
|
||||
|
||||
if (file_exists('./box.json.dist')) {
|
||||
$this->runCommands([ $this->box.' build -n --no-ansi']);
|
||||
$this->logger->info(sprintf('keylighter.phar build OK'));
|
||||
}
|
||||
} catch (CommandExecuteException $exception) {
|
||||
$this->logger->error($exception->getMessage(), [
|
||||
'code' => $exception->getCode(),
|
||||
'output' => $exception->getOutput()
|
||||
]);
|
||||
|
||||
return false;
|
||||
} finally {
|
||||
chdir($cwd);
|
||||
}
|
||||
|
||||
$this->logger->info(sprintf('Download OK'));
|
||||
$this->addInstalledEntry($revision['version'], $revision['dist']['reference']);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function runCommands(array $commands)
|
||||
{
|
||||
$commands = array_map(function($command) {
|
||||
return str_replace('@php', PHP_BINARY, $command);
|
||||
}, $commands);
|
||||
$commands = implode('; ', $commands);
|
||||
|
||||
$this->logger->debug('Executing: '.$commands);
|
||||
|
||||
exec($commands, $output, $code);
|
||||
if ($code !== 0) {
|
||||
throw new CommandExecuteException("Command `$commands` returned non-zero exit code.", implode("\n", $output), $code);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function move($temp, $final)
|
||||
{
|
||||
try {
|
||||
/** @var \SplFileInfo[] $files */
|
||||
$files = array_values(iterator_to_array(new FilesystemIterator($temp, FilesystemIterator::SKIP_DOTS)));
|
||||
|
||||
// really nasty hack
|
||||
if (count($files) === 1 && $files[0]->isDir()) {
|
||||
$dir = $files[0]->getPathName();
|
||||
} else {
|
||||
$dir = $temp;
|
||||
}
|
||||
|
||||
if ($this->filesystem->exists($final)) {
|
||||
$this->filesystem->remove($final);
|
||||
}
|
||||
$this->filesystem->rename($dir, $final, true);
|
||||
|
||||
return true;
|
||||
} catch (IOException $exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function downloadArchive($revision)
|
||||
{
|
||||
try {
|
||||
$temp = $this->getTempFile();
|
||||
$result = fopen($temp, 'w');
|
||||
$curl = curl_init();
|
||||
|
||||
curl_setopt($curl, CURLOPT_URL, $revision['dist']['url']);
|
||||
curl_setopt($curl, CURLOPT_FILE, $result);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($curl, CURLOPT_USERAGENT, "keylighter.kadet.net/1.0");
|
||||
|
||||
if (!curl_exec($curl)) {
|
||||
throw new \RuntimeException(curl_error($curl), curl_errno($curl));
|
||||
}
|
||||
|
||||
if (($code = curl_getinfo($curl, CURLINFO_HTTP_CODE)) !== 200) {
|
||||
throw new \RuntimeException("Response code was $code.");
|
||||
}
|
||||
|
||||
return $temp;
|
||||
} finally {
|
||||
curl_close($curl);
|
||||
fclose($result);
|
||||
}
|
||||
}
|
||||
|
||||
private function addInstalledEntry($version, $checksum)
|
||||
{
|
||||
$entries = file_exists($this->installed) ? json_decode(file_get_contents($this->installed), true) : [];
|
||||
$entries[$version] = $checksum;
|
||||
|
||||
file_put_contents($this->installed, json_encode($entries, true), LOCK_EX);
|
||||
}
|
||||
}
|
0
src/Controller/.gitignore
vendored
Normal file → Executable file
0
src/Controller/.gitignore
vendored
Normal file → Executable file
25
src/Controller/DemoController.php
Executable file
25
src/Controller/DemoController.php
Executable file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
|
||||
use App\Entity\Snippet;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class DemoController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @Route("/highlight", name="demo_highlight", methods={"POST"})
|
||||
*/
|
||||
public function highlightAction(Request $request)
|
||||
{
|
||||
$snippet = new Snippet();
|
||||
$snippet->setLanguage($request->get('language'));
|
||||
$snippet->setCode($request->get('source'));
|
||||
|
||||
return $this->forward(sprintf('%s::showAction', SnippetController::class), ['snippet' => $snippet]);
|
||||
}
|
||||
|
||||
}
|
104
src/Controller/DocumentationController.php
Executable file
104
src/Controller/DocumentationController.php
Executable file
@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Document;
|
||||
use App\Service\DocumentResolver;
|
||||
use Kadet\Highlighter\KeyLighter;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
/**
|
||||
* Class DocumentationController
|
||||
*
|
||||
* @package App\Controller
|
||||
* @Route("/docs")
|
||||
*/
|
||||
class DocumentationController extends AbstractController
|
||||
{
|
||||
private const DEFAULT_FILE = null;
|
||||
private $resolver;
|
||||
|
||||
/**
|
||||
* HomeController constructor.
|
||||
*
|
||||
* @param DocumentResolver $resolver
|
||||
*/
|
||||
public function __construct(DocumentResolver $resolver)
|
||||
{
|
||||
$this->resolver = $resolver;
|
||||
}
|
||||
|
||||
public function sidebarAction($path = null)
|
||||
{
|
||||
$category = function (Document $document) {
|
||||
return $document->getMetadata()['category'];
|
||||
};
|
||||
|
||||
$title = function (Document $document) {
|
||||
return $document->getMetadata()['title'];
|
||||
};
|
||||
|
||||
/** @var \App\Entity\Document[][] $result */
|
||||
$result = collect($this->resolver->fetch('/Docs/'))
|
||||
->sortBy($title)->sortBy($category)
|
||||
->groupBy($category);
|
||||
|
||||
return $this->render('docs/sidebar.html.twig', [
|
||||
'categories' => $result,
|
||||
'path' => $path
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/{path}", name="documentation_show", requirements={"path": ".+"})
|
||||
*/
|
||||
public function showAction($path = self::DEFAULT_FILE)
|
||||
{
|
||||
try {
|
||||
if ($path == self::DEFAULT_FILE) {
|
||||
$path = $this->getDefaultFile();
|
||||
}
|
||||
|
||||
$document = $this->resolver->getDocument('/Docs/'.$path);
|
||||
|
||||
$meta = $document->getMetadata();
|
||||
|
||||
$prev = false;
|
||||
$next = false;
|
||||
|
||||
if (isset($meta['next'])) {
|
||||
$next = $this->resolver->getDocument('/Docs/'.$meta['next']);
|
||||
}
|
||||
|
||||
if (isset($meta['previous'])) {
|
||||
$prev = $this->resolver->getDocument('/Docs/'.$meta['previous']);
|
||||
}
|
||||
|
||||
return $this->render("docs/document.html.twig", compact('document', 'path', 'prev', 'next'));
|
||||
} catch (FileNotFoundException $exception) {
|
||||
if ($path == $this->getDefaultFile()) {
|
||||
throw new NotFoundHttpException("Documentation starting point for that version is invalid.");
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('documentation_show');
|
||||
}
|
||||
}
|
||||
|
||||
private function getDefaultFile()
|
||||
{
|
||||
$version = KeyLighter::VERSION;
|
||||
$version = str_replace('-', '.0-', $version); // keylighter uses major.minor-
|
||||
|
||||
if (version_compare($version, '0.9.0-dev', '>=')) {
|
||||
return '1-installation';
|
||||
} elseif (version_compare($version, '0.8.0', '>=')) {
|
||||
return 'usage';
|
||||
}
|
||||
|
||||
throw new NotFoundHttpException("No documentation was found for that version :(");
|
||||
}
|
||||
}
|
68
src/Controller/HomeController.php
Executable file
68
src/Controller/HomeController.php
Executable file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
|
||||
use App\Service\DocumentResolver;
|
||||
use App\Service\KeyLighterVersioner;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class HomeController extends AbstractController
|
||||
{
|
||||
/** @var DocumentResolver */
|
||||
private $resolver;
|
||||
|
||||
/** @var \App\Service\KeyLighterVersioner */
|
||||
private $versioner;
|
||||
|
||||
/**
|
||||
* HomeController constructor.
|
||||
*
|
||||
* @param DocumentResolver $resolver
|
||||
*/
|
||||
public function __construct(DocumentResolver $resolver, KeyLighterVersioner $versioner)
|
||||
{
|
||||
$this->resolver = $resolver;
|
||||
$this->versioner = $versioner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/", name="homepage")
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$document = $this->resolver->getDocument('README');
|
||||
|
||||
return $this->render('homepage.html.twig', compact('document'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/download/keylighter.phar")
|
||||
* @Route("/download/{version}/keylighter.phar")
|
||||
*/
|
||||
public function downloadPharAction($version = null)
|
||||
{
|
||||
$directory = $this->versioner->getCurrentDir();
|
||||
if ($version) {
|
||||
$directory = $this->versioner->getDirectory($version);
|
||||
}
|
||||
$directory .= DIRECTORY_SEPARATOR;
|
||||
|
||||
return $this->file($directory."keylighter.phar");
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/changelog", name="changelog")
|
||||
*/
|
||||
public function changelogAction()
|
||||
{
|
||||
$document = $this->resolver->getDocument('changelog');
|
||||
|
||||
return $this->render('document.html.twig', [
|
||||
'document' => $document,
|
||||
'current' => 'changelog'
|
||||
]);
|
||||
}
|
||||
}
|
47
src/Controller/WebHookController.php
Executable file
47
src/Controller/WebHookController.php
Executable file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
|
||||
use App\Service\KeyLighterVersioner;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
/**
|
||||
* Class WebHookController
|
||||
*
|
||||
* @package App\Controller
|
||||
* @Route("/_webhook")
|
||||
*/
|
||||
class WebHookController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @var \App\Service\KeyLighterVersioner
|
||||
*/
|
||||
private $versioner;
|
||||
|
||||
/**
|
||||
* WebHookController constructor.
|
||||
*
|
||||
* @param \App\Service\KeyLighterVersioner $versioner
|
||||
*/
|
||||
public function __construct(KeyLighterVersioner $versioner)
|
||||
{
|
||||
$this->versioner = $versioner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/travis")
|
||||
*/
|
||||
public function travisTestsPassedAction(Request $request)
|
||||
{
|
||||
$this->versioner->updateAll();
|
||||
|
||||
return new JsonResponse([
|
||||
"status" => "OK"
|
||||
], 200);
|
||||
}
|
||||
}
|
0
src/Entity/.gitignore
vendored
Normal file → Executable file
0
src/Entity/.gitignore
vendored
Normal file → Executable file
63
src/Entity/Document.php
Executable file
63
src/Entity/Document.php
Executable file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
|
||||
class Document
|
||||
{
|
||||
private $content;
|
||||
private $metadata = [];
|
||||
|
||||
/**
|
||||
* Document constructor.
|
||||
*
|
||||
* @param string $content
|
||||
* @param array $metadata
|
||||
*/
|
||||
public function __construct(string $content, array $metadata)
|
||||
{
|
||||
$this->setContent($content);
|
||||
$this->setMetadata($metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getContent()
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $content
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setContent($content)
|
||||
{
|
||||
$this->content = $content;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMetadata(): array
|
||||
{
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $metadata
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setMetadata(array $metadata)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
24
src/Exception/CommandExecuteException.php
Executable file
24
src/Exception/CommandExecuteException.php
Executable file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Exception;
|
||||
|
||||
|
||||
class CommandExecuteException extends \RuntimeException
|
||||
{
|
||||
private $output = "";
|
||||
|
||||
public function __construct(string $message = "", string $output = "", int $code = 0, \Throwable $previous = null)
|
||||
{
|
||||
$this->output = $output;
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOutput(): string
|
||||
{
|
||||
return $this->output;
|
||||
}
|
||||
}
|
49
src/Listener/KeyLighterVersionListener.php
Executable file
49
src/Listener/KeyLighterVersionListener.php
Executable file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Listener;
|
||||
|
||||
|
||||
use App\Service\KeyLighterVersioner;
|
||||
use Symfony\Component\HttpFoundation\Cookie;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
||||
|
||||
class KeyLighterVersionListener
|
||||
{
|
||||
private $versioner;
|
||||
|
||||
/**
|
||||
* KeyLighterVersionListener constructor.
|
||||
*
|
||||
* @param $versioner
|
||||
*/
|
||||
public function __construct(KeyLighterVersioner $versioner)
|
||||
{
|
||||
$this->versioner = $versioner;
|
||||
}
|
||||
|
||||
public function onKernelRequest(RequestEvent $event)
|
||||
{
|
||||
if (!$event->isMasterRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cookie = $event->getRequest()->cookies->get('keylighter_version', 'dev-master');
|
||||
$version = $event->getRequest()->query->get('keylighter', $cookie);
|
||||
|
||||
$this->versioner->load($version);
|
||||
}
|
||||
|
||||
public function onKernelResponse(ResponseEvent $event)
|
||||
{
|
||||
if (!$event->isMasterRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($event->getRequest()->query->has('keylighter')) {
|
||||
$cookie = new Cookie('keylighter_version', $this->versioner->getCurrent());
|
||||
$event->getResponse()->headers->setCookie($cookie);
|
||||
}
|
||||
}
|
||||
}
|
0
src/Repository/.gitignore
vendored
0
src/Repository/.gitignore
vendored
73
src/Service/DocumentResolver.php
Executable file
73
src/Service/DocumentResolver.php
Executable file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
|
||||
use App\Entity\Document;
|
||||
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class DocumentResolver
|
||||
{
|
||||
private $base;
|
||||
|
||||
/**
|
||||
* DocumentResolver constructor.
|
||||
*
|
||||
* @param \App\Service\KeyLighterVersioner $versioner
|
||||
*/
|
||||
public function __construct(KeyLighterVersioner $versioner)
|
||||
{
|
||||
$this->base = $versioner->getCurrentDir();
|
||||
}
|
||||
|
||||
public function fetch($path)
|
||||
{
|
||||
$path = $this->buildPath($path);
|
||||
|
||||
$finder = new Finder();
|
||||
$finder->name("*.md");
|
||||
|
||||
foreach ($finder->files()->in($path)->getIterator() as $file) {
|
||||
$document = $this->getDocument($file->getPathname(), true);
|
||||
|
||||
$metadata = array_merge([
|
||||
"title" => str_replace('-', ' ', $file->getBasename('.md')),
|
||||
"category" => basename($file->getPath()),
|
||||
"path" => str_replace(['.md', DIRECTORY_SEPARATOR], [null, '/'], substr($file->getPathname(), strlen($path)+1))
|
||||
], $document->getMetadata());
|
||||
$document->setMetadata($metadata);
|
||||
|
||||
yield $file->getFilename() => $document;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDocument($path, $absolute = false)
|
||||
{
|
||||
$path = $absolute ? $path : $this->buildPath(trim($path, '/').'.md');
|
||||
|
||||
if (!file_exists($path)) {
|
||||
throw new FileNotFoundException("File '$path' was not found.");
|
||||
}
|
||||
|
||||
list($content, $meta) = $this->split(file_get_contents($path));
|
||||
return new Document($content, $meta);
|
||||
}
|
||||
|
||||
private function split(string $content): array
|
||||
{
|
||||
if(!preg_match('/^-{3,}\h*\R(?P<metadata>.*?)\R-{3,}\h*\R/sm', $content, $matches)) {
|
||||
return [ $content, [] ];
|
||||
}
|
||||
|
||||
$metadata = $matches['metadata'];
|
||||
return [ trim(substr($content, strlen($matches[0]))), Yaml::parse($metadata) ];
|
||||
}
|
||||
|
||||
private function buildPath($path)
|
||||
{
|
||||
return realpath($this->base.DIRECTORY_SEPARATOR.$path);
|
||||
}
|
||||
}
|
98
src/Service/KeyLighterVersioner.php
Executable file
98
src/Service/KeyLighterVersioner.php
Executable file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
class KeyLighterVersioner
|
||||
{
|
||||
const URL = 'https://packagist.org/p/kadet/keylighter.json';
|
||||
|
||||
private $dir = '';
|
||||
private $current;
|
||||
|
||||
private $filesystem;
|
||||
private $parameters;
|
||||
|
||||
public function __construct(Filesystem $filesystem, ParameterBagInterface $parameters)
|
||||
{
|
||||
$this->filesystem = $filesystem;
|
||||
$this->parameters = $parameters;
|
||||
}
|
||||
|
||||
public function getAvailableVersions()
|
||||
{
|
||||
$info = $this->getInstalledInfo();
|
||||
|
||||
return array_keys($info);
|
||||
}
|
||||
|
||||
public function getInstalledInfo()
|
||||
{
|
||||
$file = $this->getDirectory().'/installed.json';
|
||||
if (!file_exists($file)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return json_decode(file_get_contents($file), true);
|
||||
}
|
||||
|
||||
public function updateAll()
|
||||
{
|
||||
$info = $this->getPackageInfo();
|
||||
$installed = $this->getInstalledInfo();
|
||||
|
||||
foreach ($info as $version => $revision) {
|
||||
if (array_key_exists($version, $installed) && $installed[$version] == $revision['dist']['reference']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// fixme: add package to download queue
|
||||
}
|
||||
}
|
||||
|
||||
private function getPackageInfo()
|
||||
{
|
||||
return json_decode(file_get_contents(self::URL), true)['packages']['kadet/keylighter'];
|
||||
}
|
||||
|
||||
public function getDirectory($version = null): string
|
||||
{
|
||||
return $this->ensureDirectoryExists($this->parameters->get('keylighter_dir').DIRECTORY_SEPARATOR.$version);
|
||||
}
|
||||
|
||||
private function ensureDirectoryExists($directory)
|
||||
{
|
||||
$this->filesystem->mkdir($directory, 0755);
|
||||
|
||||
return realpath($directory);
|
||||
}
|
||||
|
||||
public function load($version)
|
||||
{
|
||||
if(!in_array($version, $this->getAvailableVersions())) {
|
||||
throw new \RuntimeException("'$version' is not an valid KeyLighter version, available are: ".implode(', ', $this->getAvailableVersions()));
|
||||
}
|
||||
|
||||
if (!file_exists($this->getDirectory($version).'/vendor/autoload.php')) {
|
||||
throw new \RuntimeException("'$version' has no autoload file generated, maybe it is not installed correctly?");
|
||||
}
|
||||
|
||||
require $this->getDirectory($version).'/vendor/autoload.php';
|
||||
$this->current = $version;
|
||||
}
|
||||
|
||||
public function getCurrent()
|
||||
{
|
||||
return $this->current;
|
||||
}
|
||||
|
||||
public function getCurrentDir()
|
||||
{
|
||||
return $this->getDirectory($this->current);
|
||||
}
|
||||
}
|
27
src/Twig/HelpersExtension.php
Executable file
27
src/Twig/HelpersExtension.php
Executable file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Twig;
|
||||
|
||||
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
class HelpersExtension extends AbstractExtension
|
||||
{
|
||||
public function getFunctions()
|
||||
{
|
||||
return [
|
||||
new TwigFunction('fa', function($icon, $pack = 'regular') {
|
||||
$pack = [
|
||||
'regular' => 'far',
|
||||
'solid' => 'fas',
|
||||
'brand' => 'fab',
|
||||
'light' => 'fal'
|
||||
][$pack] ?? 'fa';
|
||||
|
||||
return "$pack fa-$icon";
|
||||
})
|
||||
];
|
||||
}
|
||||
}
|
30
src/Twig/KeyLighterExtension.php
Executable file
30
src/Twig/KeyLighterExtension.php
Executable file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Twig;
|
||||
|
||||
|
||||
use Kadet\Highlighter\Formatter\HtmlFormatter;
|
||||
use Kadet\Highlighter\KeyLighter;
|
||||
use Kadet\Highlighter\Language\Language;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFilter;
|
||||
use function Kadet\Highlighter\highlight;
|
||||
|
||||
class KeyLighterExtension extends AbstractExtension
|
||||
{
|
||||
public function getFilters()
|
||||
{
|
||||
$formatter = new HtmlFormatter(['prefix' => 'kl-']);
|
||||
|
||||
return [
|
||||
new TwigFilter('highlight', function($source, $language) use ($formatter) {
|
||||
if (!$language instanceof Language) {
|
||||
$language = KeyLighter::get()->getLanguage($language);
|
||||
}
|
||||
|
||||
return highlight($source, $language, $formatter);
|
||||
}, ['pre_escape' => 'html', 'is_safe' => ['html']])
|
||||
];
|
||||
}
|
||||
}
|
37
src/Twig/KeyLighterTwigAccess.php
Executable file
37
src/Twig/KeyLighterTwigAccess.php
Executable file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Twig;
|
||||
|
||||
|
||||
use App\Service\KeyLighterVersioner;
|
||||
use Kadet\Highlighter\KeyLighter;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
|
||||
class KeyLighterTwigAccess
|
||||
{
|
||||
private $keylighter;
|
||||
private $versioner;
|
||||
|
||||
public function __construct(KeyLighter $keylighter, KeyLighterVersioner $versioner)
|
||||
{
|
||||
$this->keylighter = $keylighter;
|
||||
$this->versioner = $versioner;
|
||||
}
|
||||
|
||||
public function getLanguages()
|
||||
{
|
||||
$languages = require $this->versioner->getCurrentDir().'/Config/metadata.php';
|
||||
$languages = collect($languages);
|
||||
|
||||
$languages = $languages->reduce(function (Collection $collection, $language) {
|
||||
return $collection->merge(array_fill_keys($language['name'], [
|
||||
'class' => $language[0],
|
||||
'standalone' => $language['standalone'],
|
||||
'embeddable' => $language['injectable']
|
||||
]));
|
||||
}, collect());
|
||||
|
||||
return $languages;
|
||||
}
|
||||
}
|
33
src/Twig/MarkdownTwigExtension.php
Executable file
33
src/Twig/MarkdownTwigExtension.php
Executable file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Twig;
|
||||
|
||||
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
use League\CommonMark\DocParserInterface;
|
||||
use League\CommonMark\HtmlRenderer;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFilter;
|
||||
|
||||
class MarkdownTwigExtension extends AbstractExtension
|
||||
{
|
||||
private $parser;
|
||||
private $renderer;
|
||||
|
||||
public function __construct(DocParserInterface $parser, HtmlRenderer $renderer)
|
||||
{
|
||||
$this->parser = $parser;
|
||||
$this->renderer = $renderer;
|
||||
}
|
||||
|
||||
public function getFilters()
|
||||
{
|
||||
return [
|
||||
new TwigFilter('markdown', function ($text) {
|
||||
$block = $this->parser->parse($text);
|
||||
return $this->renderer->renderBlock($block);
|
||||
}, ['is_safe' => ['html']])
|
||||
];
|
||||
}
|
||||
}
|
60
symfony.lock
60
symfony.lock
@ -78,6 +78,12 @@
|
||||
"jdorn/sql-formatter": {
|
||||
"version": "v1.2.17"
|
||||
},
|
||||
"kadet/keylighter": {
|
||||
"version": "dev-master"
|
||||
},
|
||||
"league/commonmark": {
|
||||
"version": "1.3.3"
|
||||
},
|
||||
"ocramius/package-versions": {
|
||||
"version": "1.5.1"
|
||||
},
|
||||
@ -99,6 +105,21 @@
|
||||
"psr/log": {
|
||||
"version": "1.1.3"
|
||||
},
|
||||
"sensio/framework-extra-bundle": {
|
||||
"version": "5.2",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "master",
|
||||
"version": "5.2",
|
||||
"ref": "fb7e19da7f013d0d422fa9bce16f5c510e27609b"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/sensio_framework_extra.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/asset": {
|
||||
"version": "v5.0.7"
|
||||
},
|
||||
"symfony/cache": {
|
||||
"version": "v5.0.7"
|
||||
},
|
||||
@ -198,6 +219,9 @@
|
||||
"symfony/polyfill-php73": {
|
||||
"version": "v1.15.0"
|
||||
},
|
||||
"symfony/profiler-pack": {
|
||||
"version": "v1.0.4"
|
||||
},
|
||||
"symfony/routing": {
|
||||
"version": "4.2",
|
||||
"recipe": {
|
||||
@ -247,9 +271,45 @@
|
||||
"symfony/var-exporter": {
|
||||
"version": "v5.0.7"
|
||||
},
|
||||
"symfony/web-profiler-bundle": {
|
||||
"version": "3.3",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "master",
|
||||
"version": "3.3",
|
||||
"ref": "6bdfa1a95f6b2e677ab985cd1af2eae35d62e0f6"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/dev/web_profiler.yaml",
|
||||
"config/packages/test/web_profiler.yaml",
|
||||
"config/routes/dev/web_profiler.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/webpack-encore-bundle": {
|
||||
"version": "1.6",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "master",
|
||||
"version": "1.6",
|
||||
"ref": "69e1d805ad95964088bd510c05995e87dc391564"
|
||||
},
|
||||
"files": [
|
||||
"assets/css/app.css",
|
||||
"assets/js/app.js",
|
||||
"config/packages/assets.yaml",
|
||||
"config/packages/prod/webpack_encore.yaml",
|
||||
"config/packages/test/webpack_encore.yaml",
|
||||
"config/packages/webpack_encore.yaml",
|
||||
"package.json",
|
||||
"webpack.config.js"
|
||||
]
|
||||
},
|
||||
"symfony/yaml": {
|
||||
"version": "v5.0.7"
|
||||
},
|
||||
"tightenco/collect": {
|
||||
"version": "v7.5.2"
|
||||
},
|
||||
"twig/extra-bundle": {
|
||||
"version": "v3.0.3"
|
||||
},
|
||||
|
@ -1,12 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}Welcome!{% endblock %}</title>
|
||||
{% block stylesheets %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
{% block body %}{% endblock %}
|
||||
{% block javascripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
33
templates/demo/_form.html.twig
Executable file
33
templates/demo/_form.html.twig
Executable file
@ -0,0 +1,33 @@
|
||||
<form action="{{ url('demo_highlight') }}" method="post" class="try-form">
|
||||
<div class="form-group">
|
||||
<label for="form_source"><i class="{{ fa('file-code') }}"></i> try it</label>
|
||||
<textarea name="source" class="form-control" id="form_source" rows="15" required></textarea>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="form_language" class="col-md-2 col-form-label"><i class="{{ fa('lightbulb') }}"></i> language</label>
|
||||
<div class="col-md-10">
|
||||
<input type="text" name="language" id="form_language" class="form-control" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div id="language-selector" class="standalone languages">
|
||||
{% apply spaceless %}
|
||||
{% for alias, language in keylighter.languages %}
|
||||
<a href="#" class="btn btn-sm btn-outline-primary language {{ language.embeddable ? 'embeddable' }} {{ language.standalone ? 'standalone' }}">
|
||||
{{ alias }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% endapply %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex flex-row-reverse">
|
||||
<div class="form-group">
|
||||
<button type="reset" class="btn btn-outline-danger">
|
||||
<i class="{{ fa('trash') }}"></i> reset
|
||||
</button>
|
||||
<button type="submit" class="btn btn-outline-primary">
|
||||
<i class="{{ fa('code') }}"></i> highlight
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
110
templates/demo/highlight.html.twig
Executable file
110
templates/demo/highlight.html.twig
Executable file
@ -0,0 +1,110 @@
|
||||
{% extends 'keylighter.html.twig' %}
|
||||
{% set current = 'about' %}
|
||||
|
||||
{% import _self as macros %}
|
||||
|
||||
{% block content %}
|
||||
<div class="snippet">
|
||||
<div class="d-flex dual">
|
||||
<div class="form-group">
|
||||
<a href="#" class="btn btn-outline-primary" id="snippet-edit">
|
||||
<i class="{{ fa('pen') }}"></i> edit
|
||||
</a>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{% if snippet.id is empty %}
|
||||
<a href="#" class="btn btn-primary" id="snippet-save" data-toggle="modal"
|
||||
data-target="#save-modal">
|
||||
<i class="{{ fa('share') }}"></i> share
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="#" class="btn btn-outline-danger">
|
||||
<i class="{{ fa('github', 'brand') }}"></i> open issue
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<pre class="keylighter" id="snippet" data-language="{{ snippet.language }}"
|
||||
data-source="{{ snippet.code }}">{{ source|raw }}</pre>
|
||||
<aside>
|
||||
<span class="entry">
|
||||
<span class="label"><i class="{{ fa('code') }}"></i></span>
|
||||
{{ snippet.language }}
|
||||
</span>
|
||||
<span class="entry">
|
||||
<span class="label"><i class="{{ fa('clock') }}"></i></span>
|
||||
{{ (all*1000)|number_format(3) }}ms
|
||||
</span>
|
||||
<span class="entry">
|
||||
<span class="label"><i class="{{ fa('cubes', 'solid') }}"></i></span>
|
||||
{{ snippet.size|number_format }} bytes
|
||||
</span>
|
||||
<span class="entry float-right">
|
||||
{% if snippet.showcase %}
|
||||
<strong class="text-success"><i class="{{ fa('lightbulb') }}"></i> showcase</strong>
|
||||
{% else %}
|
||||
<strong class="text-muted"><i class="{{ fa('lock-alt') }}"></i> hidden</strong>
|
||||
{% endif %}
|
||||
</span>
|
||||
</aside>
|
||||
<section id="timing">
|
||||
<div class="progress timing">
|
||||
{{ macros.time(timing.parsing, all, 'info') }}
|
||||
{{ macros.time(timing.tokenization, all, 'primary') }}
|
||||
{{ macros.time(timing.formatting, all, 'secondary') }}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block modals %}
|
||||
<div class="fade modal" tabindex="-1" role="dialog" id="save-modal">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<form action="{{ url('snippet_save') }}" method="post">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Save your snippet</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label for="save-title">Title:</label>
|
||||
<input type="text" class="form-control" id="save-title" name="title"/>
|
||||
<small class="form-text text-muted">Title is required only if you want to share snippet in showcase.</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="hidden" value="{{ snippet.code }}" name="code"/>
|
||||
<input type="hidden" value="{{ snippet.language }}" name="language"/>
|
||||
|
||||
<pre class="keylighter">{{ source|raw }}</pre>
|
||||
<aside>
|
||||
<span class="entry">
|
||||
<span class="label"><i class="{{ fa('code') }}"></i></span>
|
||||
{{ snippet.language }}
|
||||
</span>
|
||||
</aside>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="showcase"> show that snippet in showcase gallery</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">cancel</button>
|
||||
<button type="submit" class="btn btn-outline-primary"><i class="{{ fa('save') }}"></i> save</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% macro time(time, all, class) %}
|
||||
{% set milliseconds = time * 1000 %}
|
||||
<div class="progress-bar bg-{{ class }} has-tooltip" role="progressbar" style="width: {{ (time / all) * 100 }}%"
|
||||
aria-valuenow="{{ milliseconds|number_format(2) }}" aria-valuemin="0"
|
||||
aria-valuemax="{{ (all * 1000)|number_format(2) }}"
|
||||
title="{{ milliseconds|number_format(2) }}ms" data-placement="bottom" data-toggle="tooltip"
|
||||
>
|
||||
</div>
|
||||
{% endmacro %}
|
27
templates/demo/showcase.html.twig
Executable file
27
templates/demo/showcase.html.twig
Executable file
@ -0,0 +1,27 @@
|
||||
{% extends 'keylighter.html.twig' %}
|
||||
{% set showForm = true %}
|
||||
{% set current = 'showcase' %}
|
||||
|
||||
{% import _self as macros %}
|
||||
|
||||
{% block content %}
|
||||
{% for snippet in snippets %}
|
||||
<div class="snippet">
|
||||
<h1>
|
||||
<a href="{{ url('snippet_show', { snippet: snippet.id }) }}">{{ snippet.title|default('untitled') }}</a>
|
||||
</h1>
|
||||
<pre class="keylighter">{{ snippet.code|highlight(snippet.language) }}</pre>
|
||||
<aside>
|
||||
<span class="entry">
|
||||
<span class="label"><i class="{{ fa('code') }}"></i></span>
|
||||
{{ snippet.language }}
|
||||
</span>
|
||||
|
||||
<span class="float-right entry">
|
||||
<span class="label"><i class="{{ fa('hashtag') }}"></i></span>
|
||||
<a href="{{ url('snippet_show', { snippet: snippet.id }) }}">{{ snippet.id }}</a>
|
||||
</span>
|
||||
</aside>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
36
templates/docs/document.html.twig
Executable file
36
templates/docs/document.html.twig
Executable file
@ -0,0 +1,36 @@
|
||||
{% extends 'keylighter.html.twig' %}
|
||||
{% set current = 'docs' %}
|
||||
|
||||
{% import 'macros.twig' as helpers %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div id="sidebar" class="sticky-top">
|
||||
<h2>Documentation</h2>
|
||||
{{ render_esi(controller("App\\Controller\\DocumentationController:sidebarAction", { path: path })) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<nav class="d-flex justify-content-end">
|
||||
<a href="https://github.com/kadet1090/KeyLighter/edit/master/Docs/{{ path }}.md" class="btn btn-outline-primary">
|
||||
<i class="{{ fa('github', 'brand') }}"></i> edit on github
|
||||
</a>
|
||||
</nav>
|
||||
{{ document.content|markdown }}
|
||||
<nav class="d-flex chapter--navigation">
|
||||
{% if prev %}
|
||||
<a href="{{ document.metadata['previous'] }}" class="btn btn-outline-primary nav--prev">
|
||||
<i class="far fa-chevron-left"></i> {{ helpers.document_link(prev) }}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if next %}
|
||||
<a href="{{ document.metadata['next'] }}" class="btn btn-outline-primary nav--next">
|
||||
{{ helpers.document_link(next) }} <i class="far fa-chevron-right"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
17
templates/docs/sidebar.html.twig
Executable file
17
templates/docs/sidebar.html.twig
Executable file
@ -0,0 +1,17 @@
|
||||
{% import "macros.twig" as helpers %}
|
||||
|
||||
{% for name, documents in categories %}
|
||||
{% if name|lower != 'docs' %}
|
||||
<h3 class="category-title">{{ name|title }}</h3>
|
||||
{% endif %}
|
||||
<ul class="nav flex-column">
|
||||
{% for document in documents %}
|
||||
{{ helpers.menu_entry(
|
||||
url('documentation_show', { path: document.metadata.path }),
|
||||
document.metadata.title,
|
||||
fa(document.metadata.icon ?? 'document', document.metadata.iconType ?? 'regular'),
|
||||
path == document.metadata.path
|
||||
) }}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
6
templates/document.html.twig
Executable file
6
templates/document.html.twig
Executable file
@ -0,0 +1,6 @@
|
||||
{% extends 'keylighter.html.twig' %}
|
||||
|
||||
{% block content %}
|
||||
{{ document.content|markdown }}
|
||||
{% endblock %}
|
||||
|
7
templates/homepage.html.twig
Executable file
7
templates/homepage.html.twig
Executable file
@ -0,0 +1,7 @@
|
||||
{% extends "keylighter.html.twig" %}
|
||||
{% set showForm = true %}
|
||||
{% set current = 'about' %}
|
||||
|
||||
{% block content %}
|
||||
{{ document.content | markdown }}
|
||||
{% endblock %}
|
81
templates/keylighter.html.twig
Executable file
81
templates/keylighter.html.twig
Executable file
@ -0,0 +1,81 @@
|
||||
{% import "macros.twig" as helper %}
|
||||
{% set current = current is defined ? current : 'demo' %}
|
||||
{% set showForm = showForm|default(false) %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
<title>KeyLighter</title>
|
||||
|
||||
{{ encore_entry_link_tags('app') }}
|
||||
<link rel="icon" href="{{ asset('img/favicon.png') }}"/>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{{ url('homepage') }}">
|
||||
<img src="{{ asset('img/logo.png') }}" alt="KeyLighter" class="d-inline-block align-top"/>
|
||||
</a>
|
||||
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse right" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<li class="nav-item {% if showForm %}visible active{% endif %}" data-toggle="form" data-id="try-form" id="form-toggle">
|
||||
<a href="#try-form" class="nav-link slim"><i class="{{ fa('chevron-down', 'solid') }}"></i></a>
|
||||
</li>
|
||||
{{ helper.menu_entry('https://github.com/kadet1090/keylighter', 'GitHub', fa('github', 'brand'), current == 'github') }}
|
||||
{{ helper.menu_entry(url('changelog'), 'Changelog', fa('history'), current == 'changelog') }}
|
||||
{{ helper.menu_entry(url('documentation_show'), 'Docs', fa('book'), current == 'docs') }}
|
||||
{{ helper.menu_entry(url('homepage'), 'About', fa('info'), current == 'about') }}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="try-form" class="{{ showForm ? 'visible' : 'hidden' }}">
|
||||
<div class="container">
|
||||
{% include 'demo/_form.html.twig' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container" id="content">
|
||||
{% block content '' %}
|
||||
</div>
|
||||
|
||||
<footer id="footer">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-auto d-flex align-items-center">
|
||||
<span style="margin-right: .5rem">KeyLighter</span>
|
||||
<div class="dropup">
|
||||
<button class="btn btn-primary dropdown-toggle btn-sm" type="button" title="Change KeyLighter version" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
{{ versioner.current }}
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
|
||||
{% for version, hash in versioner.installedInfo %}
|
||||
<a class="dropdown-item" href="?keylighter={{ version }}" title="{{ hash }}">{{ version }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto align-content-center ml-auto">
|
||||
<span>brought to you by</span>
|
||||
<a href="#">
|
||||
<img src="{{ asset('img/kadet.png') }}" alt="kadet.net" />
|
||||
</a>
|
||||
<span>© 2017</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{% block modals '' %}
|
||||
|
||||
{{ encore_entry_script_tags('app') }}
|
||||
{% block scripts '' %}
|
||||
</body>
|
||||
</html>
|
10
templates/macros.twig
Executable file
10
templates/macros.twig
Executable file
@ -0,0 +1,10 @@
|
||||
{% macro menu_entry(url, title, icon, current) %}
|
||||
<li class="nav-item {% if current %}active{% endif %}">
|
||||
<a class="nav-link" href="{{ url }}"><i class="fa-fw {{ icon }}"></i> {{ title }}</a>
|
||||
</li>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro document_link(document) %}
|
||||
<i class="fa-fw {{ fa(document.metadata.icon ?? 'document', document.metadata.iconType ?? 'regular') }}"></i>
|
||||
{{ document.metadata.title }}
|
||||
{% endmacro %}
|
13
tsconfig.json
Normal file
13
tsconfig.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["dom", "es2015", "es2016.array.include", "es2017.object"],
|
||||
"target": "es5",
|
||||
"module": "esnext",
|
||||
"sourceMap": true,
|
||||
"noImplicitThis": true,
|
||||
"moduleResolution": "node",
|
||||
"downlevelIteration": true
|
||||
},
|
||||
"files": ["assets/ts/app.ts"],
|
||||
"include": ["assets/ts/**/*.ts"]
|
||||
}
|
27
webpack.config.js
Normal file
27
webpack.config.js
Normal file
@ -0,0 +1,27 @@
|
||||
const Encore = require('@symfony/webpack-encore');
|
||||
|
||||
if (!Encore.isRuntimeEnvironmentConfigured()) {
|
||||
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
|
||||
}
|
||||
|
||||
Encore
|
||||
.setOutputPath('public/build/')
|
||||
.setPublicPath('/build')
|
||||
.addEntry('app', './assets/ts/app.ts')
|
||||
.splitEntryChunks()
|
||||
.enableSingleRuntimeChunk()
|
||||
.cleanupOutputBeforeBuild()
|
||||
.enableBuildNotifications()
|
||||
.enableSourceMaps(!Encore.isProduction())
|
||||
.enableVersioning(Encore.isProduction())
|
||||
.configureBabelPresetEnv((config) => {
|
||||
config.useBuiltIns = 'usage';
|
||||
config.corejs = 3;
|
||||
})
|
||||
.autoProvidejQuery()
|
||||
.autoProvideVariables({ Popper: ['popper.js', 'default'] })
|
||||
.enableSassLoader()
|
||||
.enableTypeScriptLoader()
|
||||
;
|
||||
|
||||
module.exports = Encore.getWebpackConfig();
|
Loading…
Reference in New Issue
Block a user