🎉 Initial commit
674
LICENSE
Normal file
@ -0,0 +1,674 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
2
archetypes/default.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
+++
|
||||||
|
+++
|
8
assets/icons/archive.svg
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-archive" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<rect x="3" y="4" width="18" height="4" rx="2" />
|
||||||
|
<path d="M5 8v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-10" />
|
||||||
|
<line x1="10" y1="12" x2="14" y2="12" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 432 B |
6
assets/icons/arrow-back.svg
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-arrow-back" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<path d="M9 11l-4 4l4 4m-4 -4h11a4 4 0 0 0 0 -8h-1" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 338 B |
6
assets/icons/back.svg
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-left" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<polyline points="15 6 9 12 15 18" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 323 B |
7
assets/icons/chevrons-left.svg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevrons-left" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<polyline points="11 7 6 12 11 17" />
|
||||||
|
<polyline points="17 7 12 12 17 17" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 365 B |
7
assets/icons/chevrons-right.svg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevrons-right" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<polyline points="7 7 12 12 7 17" />
|
||||||
|
<polyline points="13 7 18 12 13 17" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 365 B |
7
assets/icons/clock.svg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-clock" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<circle cx="12" cy="12" r="9" />
|
||||||
|
<polyline points="12 7 12 12 15 15" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 352 B |
7
assets/icons/copyright.svg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-copyright" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<circle cx="12" cy="12" r="9" />
|
||||||
|
<path d="M14.5 9a3.5 4 0 1 0 0 6" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 354 B |
9
assets/icons/hash.svg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-hash" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<line x1="5" y1="9" x2="19" y2="9" />
|
||||||
|
<line x1="5" y1="15" x2="19" y2="15" />
|
||||||
|
<line x1="11" y1="4" x2="7" y2="20" />
|
||||||
|
<line x1="17" y1="4" x2="13" y2="20" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 440 B |
8
assets/icons/home.svg
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-home" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<polyline points="5 12 3 12 12 3 21 12 19 12" />
|
||||||
|
<path d="M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-7" />
|
||||||
|
<path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 441 B |
6
assets/icons/infinity.svg
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-infinity" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<path d="M9.828 9.172a4 4 0 1 0 0 5.656 a10 10 0 0 0 2.172 -2.828a10 10 0 0 1 2.172 -2.828 a4 4 0 1 1 0 5.656a10 10 0 0 1 -2.172 -2.828a10 10 0 0 0 -2.172 -2.828" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 447 B |
7
assets/icons/link.svg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-link" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<path d="M10 14a3.5 3.5 0 0 0 5 0l4 -4a3.5 3.5 0 0 0 -5 -5l-.5 .5" />
|
||||||
|
<path d="M14 10a3.5 3.5 0 0 0 -5 0l-4 4a3.5 3.5 0 0 0 5 5l.5 -.5" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 418 B |
7
assets/icons/messages.svg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-messages" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<path d="M21 14l-3 -3h-7a1 1 0 0 1 -1 -1v-6a1 1 0 0 1 1 -1h9a1 1 0 0 1 1 1v10" />
|
||||||
|
<path d="M14 15v2a1 1 0 0 1 -1 1h-7l-3 3v-10a1 1 0 0 1 1 -1h2" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 431 B |
8
assets/icons/rss.svg
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-rss" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<circle cx="5" cy="19" r="1" />
|
||||||
|
<path d="M4 4a16 16 0 0 1 16 16" />
|
||||||
|
<path d="M4 11a9 9 0 0 1 9 9" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 381 B |
7
assets/icons/tag.svg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-tag" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<path d="M11 3L20 12a1.5 1.5 0 0 1 0 2L14 20a1.5 1.5 0 0 1 -2 0L3 11v-4a4 4 0 0 1 4 -4h4" />
|
||||||
|
<circle cx="9" cy="9" r="2" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 402 B |
7
assets/icons/user.svg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-user" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<circle cx="12" cy="7" r="4" />
|
||||||
|
<path d="M6 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 366 B |
349
assets/scss/external/normalize.scss
vendored
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
|
||||||
|
|
||||||
|
/* Document
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the line height in all browsers.
|
||||||
|
* 2. Prevent adjustments of font size after orientation changes in iOS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
html {
|
||||||
|
line-height: 1.15; /* 1 */
|
||||||
|
-webkit-text-size-adjust: 100%; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sections
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the margin in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the `main` element consistently in IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
main {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the font size and margin on `h1` elements within `section` and
|
||||||
|
* `article` contexts in Chrome, Firefox, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin: 0.67em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grouping content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in Firefox.
|
||||||
|
* 2. Show the overflow in Edge and IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
hr {
|
||||||
|
box-sizing: content-box; /* 1 */
|
||||||
|
height: 0; /* 1 */
|
||||||
|
overflow: visible; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pre {
|
||||||
|
font-family: monospace, monospace; /* 1 */
|
||||||
|
font-size: 1em; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text-level semantics
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the gray background on active links in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
a {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Remove the bottom border in Chrome 57-
|
||||||
|
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
abbr[title] {
|
||||||
|
border-bottom: none; /* 1 */
|
||||||
|
text-decoration: underline; /* 2 */
|
||||||
|
text-decoration: underline dotted; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
samp {
|
||||||
|
font-family: monospace, monospace; /* 1 */
|
||||||
|
font-size: 1em; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font size in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||||
|
* all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Embedded content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the border on images inside links in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forms
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Change the font styles in all browsers.
|
||||||
|
* 2. Remove the margin in Firefox and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
optgroup,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font-family: inherit; /* 1 */
|
||||||
|
font-size: 100%; /* 1 */
|
||||||
|
line-height: 1.15; /* 1 */
|
||||||
|
margin: 0; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the overflow in IE.
|
||||||
|
* 1. Show the overflow in Edge.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input { /* 1 */
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||||
|
* 1. Remove the inheritance of text transform in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
select { /* 1 */
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
[type="button"],
|
||||||
|
[type="reset"],
|
||||||
|
[type="submit"] {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner border and padding in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
[type="button"]::-moz-focus-inner,
|
||||||
|
[type="reset"]::-moz-focus-inner,
|
||||||
|
[type="submit"]::-moz-focus-inner {
|
||||||
|
border-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the focus styles unset by the previous rule.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button:-moz-focusring,
|
||||||
|
[type="button"]:-moz-focusring,
|
||||||
|
[type="reset"]:-moz-focusring,
|
||||||
|
[type="submit"]:-moz-focusring {
|
||||||
|
outline: 1px dotted ButtonText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the padding in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
padding: 0.35em 0.75em 0.625em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the text wrapping in Edge and IE.
|
||||||
|
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||||
|
* 3. Remove the padding so developers are not caught out when they zero out
|
||||||
|
* `fieldset` elements in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
legend {
|
||||||
|
box-sizing: border-box; /* 1 */
|
||||||
|
color: inherit; /* 2 */
|
||||||
|
display: table; /* 1 */
|
||||||
|
max-width: 100%; /* 1 */
|
||||||
|
padding: 0; /* 3 */
|
||||||
|
white-space: normal; /* 1 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||||
|
*/
|
||||||
|
|
||||||
|
progress {
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the default vertical scrollbar in IE 10+.
|
||||||
|
*/
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in IE 10.
|
||||||
|
* 2. Remove the padding in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="checkbox"],
|
||||||
|
[type="radio"] {
|
||||||
|
box-sizing: border-box; /* 1 */
|
||||||
|
padding: 0; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="number"]::-webkit-inner-spin-button,
|
||||||
|
[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the odd appearance in Chrome and Safari.
|
||||||
|
* 2. Correct the outline style in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="search"] {
|
||||||
|
-webkit-appearance: textfield; /* 1 */
|
||||||
|
outline-offset: -2px; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner padding in Chrome and Safari on macOS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
* 2. Change font properties to `inherit` in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
-webkit-appearance: button; /* 1 */
|
||||||
|
font: inherit; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interactive
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in Edge, IE 10+, and Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
details {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Misc
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 10+.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
12
assets/scss/helper/shadow.scss
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
@mixin box_shadow($level) {
|
||||||
|
@if $level == 1 {
|
||||||
|
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 0px 2px rgba(0, 0, 0, 0.06), 0px 0px 1px rgba(0, 0, 0, 0.04);
|
||||||
|
} @else if $level == 2 {
|
||||||
|
box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.04), 0px 2px 6px rgba(0, 0, 0, 0.04), 0px 0px 1px rgba(0, 0, 0, 0.04);
|
||||||
|
} @else if $level == 3 {
|
||||||
|
box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.04), 0px 2px 6px rgba(0, 0, 0, 0.04), 0px 0px 1px rgba(0, 0, 0, 0.04);
|
||||||
|
} @else if $level == 4 {
|
||||||
|
box-shadow: 0px 24px 32px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04),
|
||||||
|
0px 4px 8px rgba(0, 0, 0, 0.04), 0px 0px 1px rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
}
|
254
assets/scss/partials/article.scss
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
/* Default article style */
|
||||||
|
.article-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
article {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
margin-bottom: 40px;
|
||||||
|
background-color: var(--card-background);
|
||||||
|
@include box_shadow(1);
|
||||||
|
border-radius: var(--card-border-radius);
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.article-image {
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 250px;
|
||||||
|
object-fit: cover;
|
||||||
|
|
||||||
|
@media (max-width: $on-tablet) {
|
||||||
|
height: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: $on-desktop) {
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@for $i from 1 through length($defaultTagBackgrounds) {
|
||||||
|
&:nth-child(#{length($defaultTagBackgrounds)}n + #{$i}) {
|
||||||
|
.article-category a {
|
||||||
|
background: nth($defaultTagBackgrounds, $i);
|
||||||
|
color: nth($defaultTagColors, $i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-details {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
padding: 25px 20px;
|
||||||
|
|
||||||
|
@media (max-width: $on-desktop) {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-category {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
a {
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 8px 16px;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
background: nth($defaultTagBackgrounds, 1);
|
||||||
|
color: nth($defaultTagColors, 1);
|
||||||
|
border-radius: var(--tag-border-radius);
|
||||||
|
|
||||||
|
@media (max-width: $on-phone) {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
padding: 8px 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-title {
|
||||||
|
font-size: 2.4rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 10px 0;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--card-text-color-main);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--card-text-color-main);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: $on-desktop) {
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-subtitle {
|
||||||
|
font-weight: lighter;
|
||||||
|
font-size: 2rem;
|
||||||
|
color: var(--card-text-color-secondary);
|
||||||
|
margin: 5px 0;
|
||||||
|
line-height: 1.5;
|
||||||
|
@media (max-width: $on-desktop) {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-time {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--card-text-color-tertiary);
|
||||||
|
margin-top: 10px;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
time {
|
||||||
|
font-size: 16px;
|
||||||
|
@media (max-width: $on-desktop) {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-tags {
|
||||||
|
& + .article-copyright {
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--accent-color-text);
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
padding: 8px 18px;
|
||||||
|
border-radius: var(--tag-border-radius);
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
transition: background-color 0.5s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--accent-color-text);
|
||||||
|
background-color: var(--accent-color-darker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compact style article list */
|
||||||
|
.article-list--compact {
|
||||||
|
border-radius: var(--card-border-radius);
|
||||||
|
@include box_shadow(1);
|
||||||
|
background-color: var(--card-background);
|
||||||
|
padding: 0 15px;
|
||||||
|
|
||||||
|
& + .pagination {
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
article {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 25px 10px;
|
||||||
|
|
||||||
|
&:not(:last-of-type) {
|
||||||
|
border-bottom: 2px solid var(--card-separator-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-details {
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: 0;
|
||||||
|
padding-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 2rem;
|
||||||
|
|
||||||
|
@media (max-width: $on-phone) {
|
||||||
|
font-size: 1.6rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-image {
|
||||||
|
img {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tile style article list */
|
||||||
|
.article-list--tile {
|
||||||
|
article {
|
||||||
|
border-radius: var(--card-border-radius);
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
height: 350px;
|
||||||
|
width: 250px;
|
||||||
|
@include box_shadow(1);
|
||||||
|
transition: box-shadow 0.3s ease;
|
||||||
|
background-color: var(--card-background);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
@include box_shadow(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.has-image {
|
||||||
|
.article-details {
|
||||||
|
background-color: rgba(#000, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-title {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-image {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-details {
|
||||||
|
border-radius: var(--card-border-radius);
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
|
z-index: 2;
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
|
@media (max-width: $on-phone) {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-title {
|
||||||
|
font-size: 2.2rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--card-text-color-main);
|
||||||
|
|
||||||
|
@media (max-width: $on-phone) {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
assets/scss/partials/base.scss
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
html {
|
||||||
|
font-size: 62.5%;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: var(--body-background);
|
||||||
|
margin: 0;
|
||||||
|
font-family: $base-font-family;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
30
assets/scss/partials/footer.scss
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
footer.site-footer {
|
||||||
|
padding: 20px 0 40px 0;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
line-height: 1.75;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
height: 3px;
|
||||||
|
width: 50px;
|
||||||
|
background: var(--body-text-color);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyright {
|
||||||
|
color: var(--accent-color);
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.powerby {
|
||||||
|
color: var(--body-text-color);
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--body-text-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
assets/scss/partials/layout/404.scss
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.not-found-card {
|
||||||
|
background-color: var(--card-background);
|
||||||
|
@include box_shadow(1);
|
||||||
|
border-radius: var(--card-border-radius);
|
||||||
|
padding: 30px;
|
||||||
|
}
|
32
assets/scss/partials/layout/archive.scss
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
.archive-group {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
.archive-date {
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--body-text-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-archive {
|
||||||
|
.category-list {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
overflow-x: auto;
|
||||||
|
|
||||||
|
.article-list--tile {
|
||||||
|
display: flex;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
|
||||||
|
article {
|
||||||
|
width: 250px;
|
||||||
|
height: 150px;
|
||||||
|
margin-right: 20px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
303
assets/scss/partials/layout/article.scss
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
@import "variables.scss";
|
||||||
|
|
||||||
|
.article-page {
|
||||||
|
.left-sidebar {
|
||||||
|
@media (max-width: $on-tablet) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-sidebar {
|
||||||
|
position: sticky;
|
||||||
|
top: 50px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
@media (max-width: $on-tablet) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-tablet) {
|
||||||
|
padding-left: 15px;
|
||||||
|
margin-left: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-tablet) {
|
||||||
|
width: 25%;
|
||||||
|
margin-right: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-desktop) {
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
article {
|
||||||
|
background: var(--card-background);
|
||||||
|
border-radius: var(--card-border-radius);
|
||||||
|
@include box_shadow(1);
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&.main-article {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-header {
|
||||||
|
.article-image {
|
||||||
|
img {
|
||||||
|
height: auto;
|
||||||
|
width: 100%;
|
||||||
|
max-height: 500px;
|
||||||
|
width: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-details {
|
||||||
|
padding: 30px 30px 0 30px;
|
||||||
|
@media (max-width: $on-tablet) {
|
||||||
|
padding: 20px 20px 0 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content {
|
||||||
|
margin: 30px 0;
|
||||||
|
padding: 0 30px;
|
||||||
|
line-height: 1.75;
|
||||||
|
color: var(--card-text-color-main);
|
||||||
|
|
||||||
|
@media (max-width: $on-tablet) {
|
||||||
|
padding: 0 20px;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-footer {
|
||||||
|
padding: 30px;
|
||||||
|
|
||||||
|
@media (max-width: $on-phone) {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-copyright {
|
||||||
|
color: var(--card-text-color-tertiary);
|
||||||
|
text-transform: uppercase;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
|
||||||
|
svg {
|
||||||
|
margin-right: 15px;
|
||||||
|
stroke-width: 1.33;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#TableOfContents {
|
||||||
|
background: var(--card-background);
|
||||||
|
border-radius: var(--card-border-radius);
|
||||||
|
@include box_shadow(1);
|
||||||
|
ul {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
list-style: none;
|
||||||
|
|
||||||
|
li {
|
||||||
|
padding: 15px 30px;
|
||||||
|
padding-right: 50px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:not(:last-of-type) {
|
||||||
|
border-bottom: 1px solid var(--card-separator-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
border-top: 1px solid var(--card-separator-color);
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#article-toolbar {
|
||||||
|
background: var(--card-background);
|
||||||
|
@include box_shadow(1);
|
||||||
|
border-radius: var(--card-border-radius);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 15px 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
@media (max-width: $on-phone) {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-tablet) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-home {
|
||||||
|
color: var(--card-text-color-secondary);
|
||||||
|
margin-right: 30px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-contents--wrapper {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
.widget-title {
|
||||||
|
//padding-left: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-contents {
|
||||||
|
overflow-x: auto;
|
||||||
|
//padding: 0 15px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
|
||||||
|
& > .flex {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
article {
|
||||||
|
margin-right: 15px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
@media (max-width: $on-phone) {
|
||||||
|
height: 250px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-phone) {
|
||||||
|
height: 200px;
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-title {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-details {
|
||||||
|
transition: background-color 0.5s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "noto-sans", "Segoe UI", "Droid Sans", "Helvetica Neue",
|
||||||
|
"PingFang SC", "Hiragino Sans GB", "Droid Sans Fallback", "Microsoft YaHei", sans-serif;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 1.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 0 auto;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
figcaption {
|
||||||
|
font-size: 1.6rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
position: relative;
|
||||||
|
margin: 10px 0;
|
||||||
|
border-left: 4px solid var(--card-separator-color);
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
width: 100px;
|
||||||
|
margin: 40px 0;
|
||||||
|
background: var(--card-text-color-tertiary);
|
||||||
|
height: 4px;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
color: #808080;
|
||||||
|
font-size: 0.96em;
|
||||||
|
background-color: #f9f9f7;
|
||||||
|
padding: 1px 2px;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 20px 0;
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 0 5px;
|
||||||
|
|
||||||
|
a:after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
//width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
overflow-x: auto;
|
||||||
|
display: block;
|
||||||
|
background-color: #fafafa;
|
||||||
|
color: #999;
|
||||||
|
font-family: Consolas, monospace;
|
||||||
|
line-height: 1.428571429;
|
||||||
|
word-break: break-all;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: var(--card-border-radius);
|
||||||
|
|
||||||
|
code {
|
||||||
|
color: unset;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
position: relative;
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
bottom: -3px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
opacity: 0.2;
|
||||||
|
height: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
56
assets/scss/partials/layout/taxonomy.scss
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
.taxonomy-type {
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--body-text-color);
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taxonomy-card {
|
||||||
|
border-radius: var(--card-border-radius);
|
||||||
|
background-color: var(--card-background);
|
||||||
|
padding: 20px 20px;
|
||||||
|
@include box_shadow(1);
|
||||||
|
margin-bottom: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.taxonomy-term {
|
||||||
|
font-size: 2.2rem;
|
||||||
|
margin: 0;
|
||||||
|
margin-top: 15px;
|
||||||
|
color: var(--card-text-color-main);
|
||||||
|
|
||||||
|
& + .taxonomy-description {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.taxonomy-description {
|
||||||
|
font-weight: normal;
|
||||||
|
color: var(--card-text-color-secondary);
|
||||||
|
font-size: 1.8rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taxonomy-details {
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: 10px 0;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taxonomy-image {
|
||||||
|
img {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.taxonomy-count {
|
||||||
|
color: var(--card-text-color-tertiary);
|
||||||
|
font-size: 1.4rem;
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
}
|
214
assets/scss/partials/menu.scss
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
/*!
|
||||||
|
* Hamburgers
|
||||||
|
* @description Tasty CSS-animated hamburgers
|
||||||
|
* @author Jonathan Suh @jonsuh
|
||||||
|
* @site https://jonsuh.com/hamburgers
|
||||||
|
* @link https://github.com/jonsuh/hamburgers
|
||||||
|
*/
|
||||||
|
|
||||||
|
.hamburger {
|
||||||
|
padding-top: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
transition-property: opacity, filter;
|
||||||
|
transition-duration: 0.15s;
|
||||||
|
transition-timing-function: linear;
|
||||||
|
font: inherit;
|
||||||
|
color: inherit;
|
||||||
|
text-transform: none;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
.hamburger:hover {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
.hamburger.is-active:hover {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
.hamburger.is-active .hamburger-inner,
|
||||||
|
.hamburger.is-active .hamburger-inner::before,
|
||||||
|
.hamburger.is-active .hamburger-inner::after {
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-box {
|
||||||
|
width: 30px;
|
||||||
|
height: 24px;
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-inner {
|
||||||
|
display: block;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-inner,
|
||||||
|
.hamburger-inner::before,
|
||||||
|
.hamburger-inner::after {
|
||||||
|
width: 30px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: var(--card-text-color-main);
|
||||||
|
border-radius: 4px;
|
||||||
|
position: absolute;
|
||||||
|
transition-property: transform;
|
||||||
|
transition-duration: 0.15s;
|
||||||
|
transition-timing-function: ease;
|
||||||
|
}
|
||||||
|
.hamburger-inner::before,
|
||||||
|
.hamburger-inner::after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.hamburger-inner::before {
|
||||||
|
top: -10px;
|
||||||
|
}
|
||||||
|
.hamburger-inner::after {
|
||||||
|
bottom: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--spin .hamburger-inner {
|
||||||
|
transition-duration: 0.22s;
|
||||||
|
transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
.hamburger--spin .hamburger-inner::before {
|
||||||
|
transition: top 0.1s 0.25s ease-in, opacity 0.1s ease-in;
|
||||||
|
}
|
||||||
|
.hamburger--spin .hamburger-inner::after {
|
||||||
|
transition: bottom 0.1s 0.25s ease-in, transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--spin.is-active .hamburger-inner {
|
||||||
|
transform: rotate(225deg);
|
||||||
|
transition-delay: 0.12s;
|
||||||
|
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
.hamburger--spin.is-active .hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transition: top 0.1s ease-out, opacity 0.1s 0.12s ease-out;
|
||||||
|
}
|
||||||
|
.hamburger--spin.is-active .hamburger-inner::after {
|
||||||
|
bottom: 0;
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
transition: bottom 0.1s ease-out, transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#toggle-menu {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 30px;
|
||||||
|
top: 30px;
|
||||||
|
z-index: 2;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
@media (min-width: $on-phone + 1) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
.hamburger-inner,
|
||||||
|
.hamburger-inner::before,
|
||||||
|
.hamburger-inner::after {
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Menu style */
|
||||||
|
.menu {
|
||||||
|
list-style: none;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 30px 0;
|
||||||
|
|
||||||
|
@media (max-width: $on-phone) {
|
||||||
|
background-color: var(--card-background);
|
||||||
|
margin-top: 0;
|
||||||
|
padding: 15px 0;
|
||||||
|
@include box_shadow(1);
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
&.show {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-phone + 1) {
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
position: relative;
|
||||||
|
vertical-align: middle;
|
||||||
|
padding: 10px 0;
|
||||||
|
|
||||||
|
&:not(:last-of-type) {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
@media (max-width: $on-desktop) {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: $on-phone) {
|
||||||
|
padding: 10px 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-phone + 1) and (max-width: ($on-desktop - 1)) {
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-phone + 1) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
stroke-width: 1.33;
|
||||||
|
|
||||||
|
margin-right: 40px;
|
||||||
|
|
||||||
|
@media (max-width: $on-desktop) {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
height: 100%;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--body-text-color);
|
||||||
|
|
||||||
|
@media (max-width: $on-desktop) {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.current {
|
||||||
|
a {
|
||||||
|
color: var(--accent-color);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: $on-phone) {
|
||||||
|
.show-menu {
|
||||||
|
.site-info {
|
||||||
|
//@include box_shadow(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
assets/scss/partials/pagination.scss
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
.pagination {
|
||||||
|
display: flex;
|
||||||
|
background-color: var(--card-background);
|
||||||
|
@include box_shadow(1);
|
||||||
|
border-radius: var(--card-border-radius);
|
||||||
|
overflow: hidden;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
.page-link {
|
||||||
|
padding: 16px 32px;
|
||||||
|
display: inline-flex;
|
||||||
|
|
||||||
|
&.current {
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: var(--card-background-selected);
|
||||||
|
color: var(--card-text-color-main);
|
||||||
|
}
|
||||||
|
|
||||||
|
color: var(--card-text-color-secondary);
|
||||||
|
}
|
||||||
|
}
|
150
assets/scss/partials/sidebar.scss
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
.sidebar {
|
||||||
|
padding: 0 15px;
|
||||||
|
&.sticky {
|
||||||
|
@media (min-width: ($on-phone + 1)) {
|
||||||
|
position: sticky;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-sidebar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
@media (max-width: $on-phone) {
|
||||||
|
width: 100%;
|
||||||
|
padding: 30px 0;
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.sticky {
|
||||||
|
top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-phone + 1) {
|
||||||
|
//justify-content: right;
|
||||||
|
//text-align: right;
|
||||||
|
width: 25%;
|
||||||
|
margin-right: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-tablet) {
|
||||||
|
width: 25%;
|
||||||
|
margin-right: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-desktop) {
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-desktop-large) {
|
||||||
|
width: 15%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-sidebar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&.sticky {
|
||||||
|
top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: $on-desktop - 1) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-tablet) {
|
||||||
|
width: 25%;
|
||||||
|
margin-left: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-desktop + 1) {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-info {
|
||||||
|
z-index: 1;
|
||||||
|
transition: box-shadow 0.5s ease;
|
||||||
|
@media (max-width: $on-phone) {
|
||||||
|
padding: 15px 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-avatar {
|
||||||
|
position: relative;
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
|
||||||
|
@media (min-width: $on-phone + 1) {
|
||||||
|
//margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: $on-desktop) {
|
||||||
|
height: 120px;
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-logo {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 100%;
|
||||||
|
@include box_shadow(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji {
|
||||||
|
position: absolute;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
border-radius: 100%;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 20px;
|
||||||
|
background-color: var(--card-background);
|
||||||
|
@include box_shadow(2);
|
||||||
|
|
||||||
|
@media (max-width: $on-desktop) {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-name {
|
||||||
|
color: var(--accent-color);
|
||||||
|
font-size: 2.4rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-description {
|
||||||
|
color: var(--body-text-color);
|
||||||
|
font-weight: lighter;
|
||||||
|
margin: 10px 0;
|
||||||
|
font-size: 2rem;
|
||||||
|
|
||||||
|
@media (max-width: $on-desktop) {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
.widget {
|
||||||
|
&:not(:last-of-type) {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
width: 100px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: var(--body-text-color);
|
||||||
|
display: block;
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
assets/scss/partials/widgets.scss
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
.widget {
|
||||||
|
.widget-title {
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--body-text-color);
|
||||||
|
font-weight: normal;
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-icon {
|
||||||
|
svg {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
stroke-width: 1.33px;
|
||||||
|
color: var(--body-text-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tag cloud widget */
|
||||||
|
.tagCloud {
|
||||||
|
.tagCloud-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
a {
|
||||||
|
background: var(--card-background);
|
||||||
|
@include box_shadow(1);
|
||||||
|
border-radius: var(--tag-border-radius);
|
||||||
|
padding: 8px 20px;
|
||||||
|
|
||||||
|
color: var(--card-text-color-main);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-right: 5px;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tweet widget */
|
||||||
|
.tweet-container {
|
||||||
|
.tweet--item {
|
||||||
|
.tweet--text {
|
||||||
|
font-size: 1.6rem;
|
||||||
|
color: var(--accent-color);
|
||||||
|
line-height: 1.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tweet--time {
|
||||||
|
text-transform: uppercase;
|
||||||
|
a {
|
||||||
|
color: var(--body-text-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget.archive {
|
||||||
|
.archive-year {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
a {
|
||||||
|
background-color: var(--card-background);
|
||||||
|
padding: 15px 25px;
|
||||||
|
border-radius: var(--card-border-radius);
|
||||||
|
@include box_shadow(1);
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
span.year {
|
||||||
|
flex: 1;
|
||||||
|
color: var(--card-text-color-main);
|
||||||
|
}
|
||||||
|
|
||||||
|
span.count {
|
||||||
|
color: var(--card-text-color-tertiary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
131
assets/scss/style.scss
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
@import "variables.scss";
|
||||||
|
@import "helper/shadow.scss";
|
||||||
|
|
||||||
|
@import "external/normalize.scss";
|
||||||
|
|
||||||
|
@import "partials/menu.scss";
|
||||||
|
@import "partials/article.scss";
|
||||||
|
@import "partials/widgets.scss";
|
||||||
|
@import "partials/footer.scss";
|
||||||
|
@import "partials/pagination.scss";
|
||||||
|
@import "partials/sidebar.scss";
|
||||||
|
@import "partials/base.scss";
|
||||||
|
@import "partials/layout/archive.scss";
|
||||||
|
@import "partials/layout/article.scss";
|
||||||
|
@import "partials/layout/taxonomy.scss";
|
||||||
|
@import "partials/layout/404.scss";
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--accent-color);
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
&:hover {
|
||||||
|
color: var(--accent-color-darker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
|
||||||
|
&.extended {
|
||||||
|
@media (min-width: $on-phone) {
|
||||||
|
max-width: 720px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-tablet) {
|
||||||
|
max-width: 972px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-desktop) {
|
||||||
|
max-width: 1200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-desktop-large) {
|
||||||
|
max-width: 1536px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#content {
|
||||||
|
@media (min-width: $on-phone) {
|
||||||
|
padding-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $on-tablet) {
|
||||||
|
padding-top: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main.main {
|
||||||
|
min-width: 0;
|
||||||
|
padding: 0 15px;
|
||||||
|
max-width: 100%;
|
||||||
|
@media (min-width: $on-phone + 1) {
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-grid {
|
||||||
|
@media (max-width: $on-phone) {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
&.column {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.on-phone--column {
|
||||||
|
@media (max-width: $on-phone) {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.align-items--flex-start {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grow {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.do-not-shrink {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.do-not-overflow {
|
||||||
|
min-width: 0;
|
||||||
|
flex-shrink: 1;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
position: fixed;
|
||||||
|
right: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
z-index: 5;
|
||||||
|
background: var(--card-background);
|
||||||
|
max-width: 400px;
|
||||||
|
padding: 15px 20px;
|
||||||
|
border-radius: var(--card-border-radius);
|
||||||
|
line-height: 1.75;
|
||||||
|
@include box_shadow(2);
|
||||||
|
color: var(--card-text-color-secondary);
|
||||||
|
|
||||||
|
@media (max-width: $on-phone) {
|
||||||
|
max-width: 100vw;
|
||||||
|
width: calc(100% - 30px);
|
||||||
|
left: 15px;
|
||||||
|
}
|
||||||
|
}
|
92
assets/scss/variables.scss
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
$fallback-font-family: -apple-system, "Noto Sans", "Helvetica Neue", Helvetica, "Nimbus Sans L", Arial,
|
||||||
|
"Liberation Sans", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Source Han Sans SC", "Source Han Sans CN",
|
||||||
|
"Microsoft YaHei", "Wenquanyi Micro Hei", "WenQuanYi Zen Hei", "ST Heiti", SimHei, "WenQuanYi Zen Hei Sharp",
|
||||||
|
sans-serif;
|
||||||
|
$base-font-family: "Lato", $fallback-font-family;
|
||||||
|
$container-width: 1200px;
|
||||||
|
$container-padding: 15px;
|
||||||
|
|
||||||
|
$defaultTagBackgrounds: #8ea885, #df7988, #0177b8, #ffb900, #6b69d6;
|
||||||
|
$defaultTagColors: #fff, #fff, #fff, #fff, #fff;
|
||||||
|
|
||||||
|
$on-phone: 740px;
|
||||||
|
$on-tablet: 1024px;
|
||||||
|
$on-desktop: 1519px;
|
||||||
|
$on-desktop-large: 1920px;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CSS Variables
|
||||||
|
*/
|
||||||
|
$body-background: #f5f5fa;
|
||||||
|
$accent-color: #34495e;
|
||||||
|
$accent-color-darker: #2c3e50;
|
||||||
|
$accent-color-text: #fff;
|
||||||
|
|
||||||
|
$card-background: #fff;
|
||||||
|
$card-background-selected: #eaeaea;
|
||||||
|
|
||||||
|
$card-text-color-main: #000;
|
||||||
|
$card-text-color-secondary: #747474;
|
||||||
|
$card-text-color-tertiary: #bababa;
|
||||||
|
$card-separator-color: rgba(218, 218, 218, 0.5);
|
||||||
|
|
||||||
|
$card-border-radius: 10px;
|
||||||
|
|
||||||
|
$body-text-color: #bababa;
|
||||||
|
|
||||||
|
$tag-border-radius: 4px;
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--body-background: #{$body-background};
|
||||||
|
--accent-color: #{$accent-color};
|
||||||
|
--accent-color-darker: #{$accent-color-darker};
|
||||||
|
--accent-color-text: #{$accent-color-text};
|
||||||
|
|
||||||
|
--card-background: #{$card-background};
|
||||||
|
--card-background-selected: #{$card-background-selected};
|
||||||
|
|
||||||
|
--card-text-color-main: #{$card-text-color-main};
|
||||||
|
--card-text-color-secondary: #{$card-text-color-secondary};
|
||||||
|
--card-text-color-tertiary: #{$card-text-color-tertiary};
|
||||||
|
--card-separator-color: #{$card-separator-color};
|
||||||
|
|
||||||
|
--card-border-radius: #{$card-border-radius};
|
||||||
|
|
||||||
|
--body-text-color: #{$body-text-color};
|
||||||
|
|
||||||
|
--tag-border-radius: #{$tag-border-radius};
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
$body-background: #303030;
|
||||||
|
$accent-color: #ecf0f1;
|
||||||
|
$accent-color-darker: #bdc3c7;
|
||||||
|
|
||||||
|
$accent-color-text: #000;
|
||||||
|
|
||||||
|
$card-background: #424242;
|
||||||
|
$card-background-selected: rgba(255, 255, 255, 0.16);
|
||||||
|
|
||||||
|
$card-text-color-main: rgba(255, 255, 255, 0.9);
|
||||||
|
$card-text-color-secondary: rgba(255, 255, 255, 0.7);
|
||||||
|
$card-text-color-tertiary: rgba(255, 255, 255, 0.5);
|
||||||
|
$card-separator-color: rgba(255, 255, 255, 0.12);
|
||||||
|
|
||||||
|
$body-text-color: rgba(255, 255, 255, 0.7);
|
||||||
|
|
||||||
|
--body-background: #{$body-background};
|
||||||
|
--accent-color: #{$accent-color};
|
||||||
|
--accent-color-darker: #{$accent-color-darker};
|
||||||
|
--accent-color-text: #{$accent-color-text};
|
||||||
|
|
||||||
|
--card-background: #{$card-background};
|
||||||
|
--card-background-selected: #{$card-background-selected};
|
||||||
|
--card-text-color-main: #{$card-text-color-main};
|
||||||
|
--card-text-color-secondary: #{$card-text-color-secondary};
|
||||||
|
--card-text-color-tertiary: #{$card-text-color-tertiary};
|
||||||
|
--card-separator-color: #{$card-separator-color};
|
||||||
|
|
||||||
|
--body-text-color: #{$body-text-color};
|
||||||
|
}
|
||||||
|
}
|
49
assets/ts/color.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
interface colorScheme {
|
||||||
|
DarkMuted: {
|
||||||
|
hex: string,
|
||||||
|
rgb: Number[],
|
||||||
|
bodyTextColor: string
|
||||||
|
},
|
||||||
|
Vibrant: {
|
||||||
|
hex: string,
|
||||||
|
rgb: Number[],
|
||||||
|
bodyTextColor: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let colorsCache: { [key: string]: colorScheme } = {};
|
||||||
|
|
||||||
|
if (localStorage.hasOwnProperty('colorsCache')) {
|
||||||
|
try {
|
||||||
|
colorsCache = JSON.parse(localStorage.getItem('colorsCache'));
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
colorsCache = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getColor(imageURL: string) {
|
||||||
|
if (!colorsCache.hasOwnProperty(imageURL)) {
|
||||||
|
const palette = await Vibrant.from(imageURL).getPalette();
|
||||||
|
|
||||||
|
colorsCache[imageURL] = {
|
||||||
|
Vibrant: {
|
||||||
|
hex: palette.Vibrant.hex,
|
||||||
|
rgb: palette.Vibrant.rgb,
|
||||||
|
bodyTextColor: palette.Vibrant.bodyTextColor
|
||||||
|
},
|
||||||
|
DarkMuted: {
|
||||||
|
hex: palette.DarkMuted.hex,
|
||||||
|
rgb: palette.DarkMuted.rgb,
|
||||||
|
bodyTextColor: palette.DarkMuted.bodyTextColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
localStorage.setItem('colorsCache', JSON.stringify(colorsCache));
|
||||||
|
}
|
||||||
|
return colorsCache[imageURL];
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getColor
|
||||||
|
}
|
287
assets/ts/gallery.ts
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
import { loadScript, loadStyle } from './utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init PhotoSwipe
|
||||||
|
* From: https://photoswipe.com/documentation/getting-started.html
|
||||||
|
* @param gallerySelector
|
||||||
|
*/
|
||||||
|
var initPhotoSwipeFromDOM = function (gallerySelector) {
|
||||||
|
|
||||||
|
// parse slide data (url, title, size ...) from DOM elements
|
||||||
|
// (children of gallerySelector)
|
||||||
|
var parseThumbnailElements = function (el) {
|
||||||
|
var thumbElements = el.childNodes,
|
||||||
|
numNodes = thumbElements.length,
|
||||||
|
items = [],
|
||||||
|
figureEl,
|
||||||
|
linkEl,
|
||||||
|
size,
|
||||||
|
item;
|
||||||
|
|
||||||
|
for (var i = 0; i < numNodes; i++) {
|
||||||
|
|
||||||
|
figureEl = thumbElements[i]; // <figure> element
|
||||||
|
|
||||||
|
// include only element nodes
|
||||||
|
if (figureEl.nodeType !== 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
linkEl = figureEl.children[0]; // <a> element
|
||||||
|
|
||||||
|
size = linkEl.getAttribute('data-size').split('x');
|
||||||
|
|
||||||
|
// create slide object
|
||||||
|
item = {
|
||||||
|
src: linkEl.getAttribute('href'),
|
||||||
|
w: parseInt(size[0], 10),
|
||||||
|
h: parseInt(size[1], 10)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (figureEl.children.length > 1) {
|
||||||
|
// <figcaption> content
|
||||||
|
item.title = figureEl.children[1].innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (linkEl.children.length > 0) {
|
||||||
|
// <img> thumbnail element, retrieving thumbnail url
|
||||||
|
item.msrc = linkEl.children[0].getAttribute('src');
|
||||||
|
}
|
||||||
|
|
||||||
|
item.el = figureEl; // save link to element for getThumbBoundsFn
|
||||||
|
items.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
};
|
||||||
|
|
||||||
|
// find nearest parent element
|
||||||
|
var closest = function closest(el, fn) {
|
||||||
|
return el && (fn(el) ? el : closest(el.parentNode, fn));
|
||||||
|
};
|
||||||
|
|
||||||
|
// triggers when user clicks on thumbnail
|
||||||
|
var onThumbnailsClick = function (e) {
|
||||||
|
e = e || window.event;
|
||||||
|
e.preventDefault ? e.preventDefault() : e.returnValue = false;
|
||||||
|
|
||||||
|
var eTarget = e.target || e.srcElement;
|
||||||
|
|
||||||
|
// find root element of slide
|
||||||
|
var clickedListItem = closest(eTarget, function (el) {
|
||||||
|
return (el.tagName && el.tagName.toUpperCase() === 'FIGURE');
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!clickedListItem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find index of clicked item by looping through all child nodes
|
||||||
|
// alternatively, you may define index via data- attribute
|
||||||
|
var clickedGallery = clickedListItem.parentNode,
|
||||||
|
childNodes = clickedListItem.parentNode.childNodes,
|
||||||
|
numChildNodes = childNodes.length,
|
||||||
|
nodeIndex = 0,
|
||||||
|
index;
|
||||||
|
|
||||||
|
for (var i = 0; i < numChildNodes; i++) {
|
||||||
|
if (childNodes[i].nodeType !== 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (childNodes[i] === clickedListItem) {
|
||||||
|
index = nodeIndex;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nodeIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= 0) {
|
||||||
|
// open PhotoSwipe if valid index found
|
||||||
|
openPhotoSwipe(index, clickedGallery);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// parse picture index and gallery index from URL (#&pid=1&gid=2)
|
||||||
|
var photoswipeParseHash = function () {
|
||||||
|
var hash = window.location.hash.substring(1),
|
||||||
|
params = {};
|
||||||
|
|
||||||
|
if (hash.length < 5) {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vars = hash.split('&');
|
||||||
|
for (var i = 0; i < vars.length; i++) {
|
||||||
|
if (!vars[i]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var pair = vars[i].split('=');
|
||||||
|
if (pair.length < 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
params[pair[0]] = pair[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.gid) {
|
||||||
|
params.gid = parseInt(params.gid, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
return params;
|
||||||
|
};
|
||||||
|
|
||||||
|
var openPhotoSwipe = function (index, galleryElement, disableAnimation, fromURL) {
|
||||||
|
var pswpElement = document.querySelectorAll('.pswp')[0],
|
||||||
|
gallery,
|
||||||
|
options,
|
||||||
|
items;
|
||||||
|
|
||||||
|
items = parseThumbnailElements(galleryElement);
|
||||||
|
|
||||||
|
// define options (if needed)
|
||||||
|
options = {
|
||||||
|
|
||||||
|
// define gallery index (for URL)
|
||||||
|
galleryUID: galleryElement.getAttribute('data-pswp-uid'),
|
||||||
|
|
||||||
|
getThumbBoundsFn: function (index) {
|
||||||
|
// See Options -> getThumbBoundsFn section of documentation for more info
|
||||||
|
var thumbnail = items[index].el.getElementsByTagName('img')[0], // find thumbnail
|
||||||
|
pageYScroll = window.pageYOffset || document.documentElement.scrollTop,
|
||||||
|
rect = thumbnail.getBoundingClientRect();
|
||||||
|
|
||||||
|
return { x: rect.left, y: rect.top + pageYScroll, w: rect.width };
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// PhotoSwipe opened from URL
|
||||||
|
if (fromURL) {
|
||||||
|
if (options.galleryPIDs) {
|
||||||
|
// parse real index when custom PIDs are used
|
||||||
|
// http://photoswipe.com/documentation/faq.html#custom-pid-in-url
|
||||||
|
for (var j = 0; j < items.length; j++) {
|
||||||
|
if (items[j].pid == index) {
|
||||||
|
options.index = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// in URL indexes start from 1
|
||||||
|
options.index = parseInt(index, 10) - 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
options.index = parseInt(index, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// exit if index not found
|
||||||
|
if (isNaN(options.index)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disableAnimation) {
|
||||||
|
options.showAnimationDuration = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass data to PhotoSwipe and initialize it
|
||||||
|
gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, options);
|
||||||
|
gallery.init();
|
||||||
|
};
|
||||||
|
|
||||||
|
// loop through all gallery elements and bind events
|
||||||
|
var galleryElements = document.querySelectorAll(gallerySelector);
|
||||||
|
|
||||||
|
for (var i = 0, l = galleryElements.length; i < l; i++) {
|
||||||
|
galleryElements[i].setAttribute('data-pswp-uid', i + 1);
|
||||||
|
galleryElements[i].onclick = onThumbnailsClick;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse URL and open gallery if it contains #&pid=3&gid=1
|
||||||
|
var hashData = photoswipeParseHash();
|
||||||
|
if (hashData.pid && hashData.gid) {
|
||||||
|
openPhotoSwipe(hashData.pid, galleryElements[hashData.gid - 1], true, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap adjacent figure tags with div.gallery, and append style
|
||||||
|
* Reference: https://github.com/xieranmaya/blog/issues/6
|
||||||
|
* @param gallery
|
||||||
|
*/
|
||||||
|
function wrap(gallery: HTMLElement[]) {
|
||||||
|
let galleryContainer = document.createElement('div');
|
||||||
|
galleryContainer.className = 'gallery';
|
||||||
|
|
||||||
|
let parentNode = gallery[0].parentNode,
|
||||||
|
first = gallery[0];
|
||||||
|
|
||||||
|
parentNode.insertBefore(galleryContainer, first)
|
||||||
|
|
||||||
|
for (let j = 0; j < gallery.length; ++j) {
|
||||||
|
const width = gallery[j].querySelector('img').width,
|
||||||
|
height = gallery[j].querySelector('img').height;
|
||||||
|
|
||||||
|
gallery[j].style.flexGrow = `${width * 100 / height}`;
|
||||||
|
gallery[j].style.flexBasis = `${width * 240 / height}px`;
|
||||||
|
|
||||||
|
galleryContainer.appendChild(gallery[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load PhotoSwipe library dynamically
|
||||||
|
*/
|
||||||
|
function loadPhotoSwipe() {
|
||||||
|
const tasks = [
|
||||||
|
loadScript("https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe.min.js"),
|
||||||
|
loadScript("https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe-ui-default.min.js"),
|
||||||
|
loadStyle("https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe.min.css"),
|
||||||
|
loadStyle("https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/default-skin/default-skin.min.css")
|
||||||
|
];
|
||||||
|
|
||||||
|
return Promise.all(tasks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create gallery
|
||||||
|
* @param selector
|
||||||
|
*/
|
||||||
|
function createGallery(selector: string) {
|
||||||
|
const figures = document.querySelector(selector).querySelectorAll('figure');
|
||||||
|
|
||||||
|
if (figures.length) {
|
||||||
|
let currentGallery = [figures[0]];
|
||||||
|
for (let i = 1; i < figures.length; ++i) {
|
||||||
|
if (figures[i].previousElementSibling === currentGallery[currentGallery.length - 1]) {
|
||||||
|
/* Adjacent */
|
||||||
|
currentGallery.push(figures[i]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* End gallery */
|
||||||
|
wrap(currentGallery);
|
||||||
|
currentGallery = [figures[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentGallery.length > 0) {
|
||||||
|
wrap(currentGallery);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load PhotoSwipe library, and then initialize
|
||||||
|
*/
|
||||||
|
loadPhotoSwipe().then(() => {
|
||||||
|
const pswp = document.querySelector('.pswp') as HTMLDivElement;
|
||||||
|
pswp.style.removeProperty('display');
|
||||||
|
|
||||||
|
initPhotoSwipeFromDOM(`${selector} .gallery`);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
createGallery
|
||||||
|
}
|
96
assets/ts/main.ts
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import { createGallery } from "./gallery"
|
||||||
|
import { getColor } from './color';
|
||||||
|
import menu from './menu';
|
||||||
|
|
||||||
|
let Stack = {
|
||||||
|
init: () => {
|
||||||
|
/**
|
||||||
|
* Bind menu event
|
||||||
|
*/
|
||||||
|
menu();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add timeago
|
||||||
|
*/
|
||||||
|
const timeagoElements = document.querySelectorAll('article time[data-timeago=true]');
|
||||||
|
if (timeagoElements.length) {
|
||||||
|
timeago.render(timeagoElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.querySelector('.article-content')) {
|
||||||
|
createGallery('.article-content');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add color to tags
|
||||||
|
*/
|
||||||
|
document.querySelectorAll('.color-tag').forEach(async (tag: HTMLLinkElement) => {
|
||||||
|
const imageURL = tag.getAttribute('data-image');
|
||||||
|
|
||||||
|
const colors = await getColor(imageURL);
|
||||||
|
|
||||||
|
tag.style.color = colors.Vibrant.bodyTextColor;
|
||||||
|
tag.style.background = colors.Vibrant.hex;
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add linear gradient background to tile style article
|
||||||
|
*/
|
||||||
|
const articleTile = document.querySelector('.article-list--tile');
|
||||||
|
if (articleTile) {
|
||||||
|
let observer = new IntersectionObserver(async (entries, observer) => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
if (!entry.isIntersecting) return;
|
||||||
|
observer.unobserve(entry.target);
|
||||||
|
|
||||||
|
const articles = entry.target.querySelectorAll('article.has-image');
|
||||||
|
articles.forEach(async articles => {
|
||||||
|
const image = articles.querySelector('img'),
|
||||||
|
imageURL = image.src,
|
||||||
|
articleDetails: HTMLDivElement = articles.querySelector('.article-details');
|
||||||
|
|
||||||
|
const colors = await getColor(imageURL);
|
||||||
|
|
||||||
|
articleDetails.style.background = `
|
||||||
|
linear-gradient(0deg,
|
||||||
|
rgba(${colors.DarkMuted.rgb[0]}, ${colors.DarkMuted.rgb[1]}, ${colors.DarkMuted.rgb[2]}, 0.5) 0%,
|
||||||
|
rgba(${colors.Vibrant.rgb[0]}, ${colors.Vibrant.rgb[1]}, ${colors.Vibrant.rgb[2]}, 0.75) 100%)`;
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
observer.observe(articleTile)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
alert: (content, time = 5000, animationSpeed = 500) => {
|
||||||
|
const alert = document.createElement('div');
|
||||||
|
alert.innerHTML = content;
|
||||||
|
alert.className = 'alert';
|
||||||
|
alert.style.visibility = 'hidden';
|
||||||
|
document.body.appendChild(alert);
|
||||||
|
|
||||||
|
alert.style.transform = `translateY(${alert.clientHeight + 50}px)`;
|
||||||
|
alert.style.transition = `transform ${animationSpeed / 1000}s ease`;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
alert.style.removeProperty('visibility');
|
||||||
|
alert.style.transform = `translateY(0)`;
|
||||||
|
}, animationSpeed);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
alert.style.transform = `translateY(${alert.clientHeight + 50}px)`;
|
||||||
|
}, animationSpeed + time);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
alert.remove();
|
||||||
|
}, 2 * animationSpeed + time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
setTimeout(function () {
|
||||||
|
Stack.init();
|
||||||
|
}, 0);
|
||||||
|
})
|
||||||
|
|
||||||
|
window.Stack = Stack;
|
83
assets/ts/menu.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* Slide up/down
|
||||||
|
* Code from https://dev.to/bmsvieira/vanilla-js-slidedown-up-4dkn
|
||||||
|
* @param target
|
||||||
|
* @param duration
|
||||||
|
*/
|
||||||
|
let slideUp = (target: HTMLElement, duration = 500) => {
|
||||||
|
target.classList.add('transiting');
|
||||||
|
target.style.transitionProperty = 'height, margin, padding';
|
||||||
|
target.style.transitionDuration = duration + 'ms';
|
||||||
|
///target.style.boxSizing = 'border-box';
|
||||||
|
target.style.height = target.offsetHeight + 'px';
|
||||||
|
target.offsetHeight;
|
||||||
|
target.style.overflow = 'hidden';
|
||||||
|
target.style.height = "0";
|
||||||
|
target.style.paddingTop = "0";
|
||||||
|
target.style.paddingBottom = "0";
|
||||||
|
target.style.marginTop = "0";
|
||||||
|
target.style.marginBottom = "0";
|
||||||
|
window.setTimeout(() => {
|
||||||
|
target.classList.remove('show')
|
||||||
|
target.style.removeProperty('height');
|
||||||
|
target.style.removeProperty('padding-top');
|
||||||
|
target.style.removeProperty('padding-bottom');
|
||||||
|
target.style.removeProperty('margin-top');
|
||||||
|
target.style.removeProperty('margin-bottom');
|
||||||
|
target.style.removeProperty('overflow');
|
||||||
|
target.style.removeProperty('transition-duration');
|
||||||
|
target.style.removeProperty('transition-property');
|
||||||
|
target.classList.remove('transiting');
|
||||||
|
}, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
let slideDown = (target: HTMLElement, duration = 500) => {
|
||||||
|
target.classList.add('transiting');
|
||||||
|
target.style.removeProperty('display');
|
||||||
|
|
||||||
|
target.classList.add('show');
|
||||||
|
|
||||||
|
let height = target.offsetHeight;
|
||||||
|
target.style.overflow = 'hidden';
|
||||||
|
target.style.height = "0";
|
||||||
|
target.style.paddingTop = "0";
|
||||||
|
target.style.paddingBottom = "0";
|
||||||
|
target.style.marginTop = "0";
|
||||||
|
target.style.marginBottom = "0";
|
||||||
|
target.offsetHeight;
|
||||||
|
///target.style.boxSizing = 'border-box';
|
||||||
|
target.style.transitionProperty = "height, margin, padding";
|
||||||
|
target.style.transitionDuration = duration + 'ms';
|
||||||
|
target.style.height = height + 'px';
|
||||||
|
target.style.removeProperty('padding-top');
|
||||||
|
target.style.removeProperty('padding-bottom');
|
||||||
|
target.style.removeProperty('margin-top');
|
||||||
|
target.style.removeProperty('margin-bottom');
|
||||||
|
window.setTimeout(() => {
|
||||||
|
target.style.removeProperty('height');
|
||||||
|
target.style.removeProperty('overflow');
|
||||||
|
target.style.removeProperty('transition-duration');
|
||||||
|
target.style.removeProperty('transition-property');
|
||||||
|
target.classList.remove('transiting');
|
||||||
|
}, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
let slideToggle = (target, duration = 500) => {
|
||||||
|
if (window.getComputedStyle(target).display === 'none') {
|
||||||
|
return slideDown(target, duration);
|
||||||
|
} else {
|
||||||
|
return slideUp(target, duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function () {
|
||||||
|
const toggleMenu = document.getElementById('toggle-menu');
|
||||||
|
if (toggleMenu) {
|
||||||
|
toggleMenu.addEventListener('click', () => {
|
||||||
|
if (document.getElementById('main-menu').classList.contains('transiting')) return;
|
||||||
|
document.body.classList.toggle('show-menu');
|
||||||
|
slideToggle(document.getElementById('main-menu'), 300);
|
||||||
|
toggleMenu.classList.toggle('is-active');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
43
assets/ts/utils.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* Load script asynchronous
|
||||||
|
* @return {Promise}
|
||||||
|
* @param url
|
||||||
|
*/
|
||||||
|
const loadScript = function (url) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
var scriptTag = document.createElement('script');
|
||||||
|
scriptTag.src = url;
|
||||||
|
|
||||||
|
scriptTag.onload = () => {
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
document.head.appendChild(scriptTag);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load style asynchronous
|
||||||
|
* @return {Promise}
|
||||||
|
* @param url
|
||||||
|
*/
|
||||||
|
const loadStyle = function (url) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
var link = document.createElement('link');
|
||||||
|
link.href = url;
|
||||||
|
|
||||||
|
link.type = "text/css";
|
||||||
|
link.rel = "stylesheet";
|
||||||
|
|
||||||
|
link.onload = () => {
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
document.head.appendChild(link);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
loadScript,
|
||||||
|
loadStyle
|
||||||
|
}
|
13
layouts/404.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{{ define "body_class" }}2-column{{ end }}
|
||||||
|
{{ define "main" }}
|
||||||
|
<div class="container extended flex on-phone--column align-items--flex-start">
|
||||||
|
{{ partial "sidebar/left.html" . }}
|
||||||
|
|
||||||
|
<main class="main full-width">
|
||||||
|
<div class="not-found-card">
|
||||||
|
<h1 class="article-title">Not Found</h1>
|
||||||
|
<h2 class="article-subtitle">This page does not exist.</h2>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
18
layouts/_default/_markup/render-image.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{{- $image := .Page.Resources.GetMatch (printf "%s" (.Destination | safeURL)) -}}
|
||||||
|
{{- $small := $image.Resize "480x" -}}
|
||||||
|
{{- $big := $image.Resize "1024x" -}}
|
||||||
|
{{- $alt := .PlainText | safeHTML -}}
|
||||||
|
{{- $caption := "" -}}
|
||||||
|
{{- with $alt -}}
|
||||||
|
{{- $caption = . | safeHTML -}}
|
||||||
|
{{- end -}}
|
||||||
|
<figure>
|
||||||
|
<a href="{{ $image.RelPermalink }}" data-size="{{ $image.Width }}x{{ $image.Height }}">
|
||||||
|
<img srcset="{{ $small.RelPermalink }} 480w, {{ $big.RelPermalink }} 1024w"
|
||||||
|
src="{{ $image.RelPermalink }}" width="{{ $image.Width }}" height="{{ $image.Height }}" loading="lazy"
|
||||||
|
alt="{{ if $alt }}{{ $alt }}{{ else if $caption }}{{ $caption | markdownify | plainify }}{{ else }} {{ end }}">
|
||||||
|
</a>
|
||||||
|
{{ with $caption }}
|
||||||
|
<figcaption>{{ . | markdownify }}</figcaption>
|
||||||
|
{{ end }}
|
||||||
|
</figure>
|
11
layouts/_default/baseof.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="{{ .Site.LanguageCode }}">
|
||||||
|
{{- partial "head.html" . -}}
|
||||||
|
<body>
|
||||||
|
<div id="content">
|
||||||
|
{{- block "main" . }}{{- end }}
|
||||||
|
</div>
|
||||||
|
{{ partial "footer/script.html" . }}
|
||||||
|
{{ partial "footer/style.html" . }}
|
||||||
|
</body>
|
||||||
|
</html>
|
30
layouts/_default/single.html
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{{ define "body_class" }}2-column{{ end }}
|
||||||
|
{{ define "main" }}
|
||||||
|
<div class="container extended flex on-phone--column align-items--flex-start article-page">
|
||||||
|
{{ partial "sidebar/left.html" . }}
|
||||||
|
|
||||||
|
<div class="flex column do-not-overflow">
|
||||||
|
<main class="main">
|
||||||
|
<div id="article-toolbar">
|
||||||
|
<a href="{{ .Site.BaseURL }}" class="back-home">
|
||||||
|
{{ (resources.Get "icons/back.svg").Content | safeHTML }}
|
||||||
|
<span>Back</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ partial "article/article.html" . }}
|
||||||
|
|
||||||
|
{{ partial "article/components/related-contents" . }}
|
||||||
|
|
||||||
|
{{ if or (not (isset .Params "comments")) (eq .Params.comments "true")}}
|
||||||
|
{{ partial "article/components/comment" . }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ partialCached "footer" . }}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{- partial "article/components/photoswipe.html" . -}}
|
||||||
|
|
||||||
|
{{ end }}
|
41
layouts/_default/term.html
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{{ define "body_class" }}2-column{{ end }}
|
||||||
|
{{ define "main" }}
|
||||||
|
<div class="container extended flex on-phone--column">
|
||||||
|
{{ partial "sidebar/left.html" . }}
|
||||||
|
|
||||||
|
<main class="main">
|
||||||
|
|
||||||
|
<h3 class="taxonomy-type">{{ .Type | singularize | humanize }}</h3>
|
||||||
|
<div class="taxonomy-card">
|
||||||
|
<div class="taxonomy-details">
|
||||||
|
<h3 class="taxonomy-count">{{ len .Pages }} post{{ if gt (len .Pages) 1 }}s{{ end }}</h3>
|
||||||
|
<h1 class="taxonomy-term">{{ .Title }}</h1>
|
||||||
|
{{ with .Params.description }}
|
||||||
|
<h2 class="taxonomy-description">{{ . }}</h2>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ if .Params.image }}
|
||||||
|
{{- $image := partial "helper/image" . -}}
|
||||||
|
{{- $thumbnail := $image.Fill "120x120" -}}
|
||||||
|
<div class="taxonomy-image">
|
||||||
|
<img src="{{ $thumbnail.RelPermalink }}" width="{{ $thumbnail.Width }}"
|
||||||
|
height="{{ $thumbnail.Height }}" loading="lazy">
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="article-list--compact">
|
||||||
|
{{ $v2 := where .Pages "Params.hidden" "!=" true }}
|
||||||
|
{{ $pag := .Paginate (.Pages) }}
|
||||||
|
{{ range $pag.Pages }}
|
||||||
|
{{ partial "article-list/compact" . }}
|
||||||
|
{{ end }}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{{- partial "pagination.html" . -}}
|
||||||
|
|
||||||
|
{{ partial "footer" . }}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
25
layouts/index.html
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{{ define "body_class" }}3-column{{ end }}
|
||||||
|
{{ define "main" }}
|
||||||
|
<div class="container extended flex on-phone--column align-items--flex-start">
|
||||||
|
{{ partialCached "sidebar/left.html" . }}
|
||||||
|
|
||||||
|
<main class="main full-width">
|
||||||
|
{{ $postSection := $.Site.Params.postSection }}
|
||||||
|
{{ $v1 := where .Site.RegularPages "Section" $postSection }}
|
||||||
|
{{ $v2 := where .Site.RegularPages "Params.hidden" "!=" true }}
|
||||||
|
{{ $.Scratch.Set "filtered" ($v1 | intersect $v2) }}
|
||||||
|
{{ $pag := .Paginate ($.Scratch.Get "filtered") }}
|
||||||
|
|
||||||
|
<section class="article-list">
|
||||||
|
{{ range $index, $element := $pag.Pages }}
|
||||||
|
{{ partial "article-list/default" . }}
|
||||||
|
{{ end }}
|
||||||
|
{{- partial "pagination.html" . -}}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{{ partialCached "footer" . }}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
{{ partialCached "sidebar/right.html" . }}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
39
layouts/page/archive.html
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{{ define "body_class" }}2-column{{ end }}
|
||||||
|
{{ define "main" }}
|
||||||
|
<div class="container extended flex on-phone--column align-items--flex-start">
|
||||||
|
|
||||||
|
{{ partial "sidebar/left.html" . }}
|
||||||
|
|
||||||
|
<main class="main template-archive">
|
||||||
|
<div class="widget">
|
||||||
|
<h1 class="widget-title">Categories</h1>
|
||||||
|
<div class="category-list">
|
||||||
|
<div class="article-list--tile">
|
||||||
|
{{ range ($.Site.GetPage "taxonomyTerm" "categories").Pages }}
|
||||||
|
{{ partial "article-list/tile" (dict "context" . "size" "250x150") }}
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ $postSection := $.Site.Params.postSection }}
|
||||||
|
{{ $v1 := where .Site.RegularPages "Section" $postSection }}
|
||||||
|
{{ $v2 := where .Site.RegularPages "Params.hidden" "!=" true }}
|
||||||
|
{{ $filtered := $v1 | intersect $v2 }}
|
||||||
|
{{ range $filtered.GroupByDate "2006" }}
|
||||||
|
{{ $id := lower (replace .Key " " "-") }}
|
||||||
|
<div class="archive-group" id="{{ $id }}">
|
||||||
|
<h3 class="archive-date"><a href="{{ $.Permalink }}#{{ $id }}">{{ .Key }}</a></h3>
|
||||||
|
<div class="article-list--compact">
|
||||||
|
{{ range .Pages }}
|
||||||
|
{{ partial "article-list/compact" . }}
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ partial "footer.html" . }}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ end }}
|
18
layouts/page/single.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{{ define "body_class" }}2-column{{ end }}
|
||||||
|
{{ define "main" }}
|
||||||
|
<div class="container extended flex on-phone--column align-items--flex-start article-and-sidebar">
|
||||||
|
|
||||||
|
{{ partial "sidebar/left.html" . }}
|
||||||
|
|
||||||
|
<main class="main article-page do-not-overflow full-width">
|
||||||
|
{{ partial "article/article.html" . }}
|
||||||
|
|
||||||
|
{{ if or (not (isset .Params "comments")) (eq .Params.comments "true")}}
|
||||||
|
{{ partial "article/components/comment" . }}
|
||||||
|
{{ end }}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ partial "article/components/photoswipe" . }}
|
||||||
|
|
||||||
|
{{ end }}
|
24
layouts/partials/article-list/compact.html
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<article>
|
||||||
|
<div class="article-details">
|
||||||
|
<h2 class="article-title">
|
||||||
|
<a href="{{ .Permalink }}">
|
||||||
|
{{- .Title -}}
|
||||||
|
</a>
|
||||||
|
</h2>
|
||||||
|
<footer class="article-time">
|
||||||
|
<time datetime='{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}'>
|
||||||
|
{{- .Date.Format ( or .Site.Params.dateFormat "Jan 02, 2006" ) -}}
|
||||||
|
</time>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ if .Params.image }}
|
||||||
|
{{- $image := partial "helper/image" . -}}
|
||||||
|
{{- $thumbnail := $image.Fill "120x120" -}}
|
||||||
|
|
||||||
|
<div class="article-image">
|
||||||
|
<img src="{{ $thumbnail.RelPermalink }}" width="{{ $thumbnail.Width }}"
|
||||||
|
height="{{ $thumbnail.Height }}" loading="lazy">
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</article>
|
51
layouts/partials/article-list/default.html
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<article class="{{ if .Params.image }}has-image{{ end }}">
|
||||||
|
{{ if .Params.image }}
|
||||||
|
{{- $image := partial "helper/image" . -}}
|
||||||
|
{{- $thumbnailNotDesktop := $image.Resize "x500 smart" -}}
|
||||||
|
|
||||||
|
<div class="article-image">
|
||||||
|
<img src="{{ $thumbnailNotDesktop.RelPermalink }}"
|
||||||
|
width="{{ $thumbnailNotDesktop.Width }}" height="{{ $thumbnailNotDesktop.Height }}" loading="lazy"
|
||||||
|
alt="Featured image of post {{ .Title }}" />
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ $i := .Params.image }}
|
||||||
|
{{ $context := . }}
|
||||||
|
|
||||||
|
<div class="article-details">
|
||||||
|
{{ with $categories := .Params.categories }}
|
||||||
|
<header class="article-category">
|
||||||
|
{{ range first 1 $categories }}
|
||||||
|
{{ if $i }}
|
||||||
|
{{- $image := partial "helper/image" $context -}}
|
||||||
|
{{- $20x := $image.Fill "20x20 smart" -}}
|
||||||
|
<a href="/categories/{{ . | urlize }}" class="color-tag"
|
||||||
|
data-image="{{ $20x.RelPermalink }}">{{ . | humanize }}</a>
|
||||||
|
{{ else }}
|
||||||
|
<a href="/categories/{{ . | urlize }}">{{ . | humanize }}</a>
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
</header>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<h2 class="article-title">
|
||||||
|
<a href="{{ .Permalink }}">
|
||||||
|
{{- .Title -}}
|
||||||
|
</a>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
{{ with .Params.description }}
|
||||||
|
<h3 class="article-subtitle">
|
||||||
|
{{ . }}
|
||||||
|
</h3>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<footer class="article-time">
|
||||||
|
{{ (resources.Get "icons/clock.svg").Content | safeHTML }}
|
||||||
|
<time data-timeago="true" datetime='{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}'>
|
||||||
|
{{- .Date.Format ( or .Site.Params.dateFormat "Jan 02, 2006" ) -}}
|
||||||
|
</time>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</article>
|
17
layouts/partials/article-list/tile.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<article class="{{ if .context.Params.image }}has-image{{ end }}">
|
||||||
|
<a href="{{ .context.Permalink }}">
|
||||||
|
{{ if .context.Params.image }}
|
||||||
|
{{- $thumbnail := (partial "helper/image" (.context) ).Fill .size -}}
|
||||||
|
<div class="article-image">
|
||||||
|
<img src="{{ $thumbnail.RelPermalink }}" width="{{ $thumbnail.Width }}" height="{{ $thumbnail.Height }}"
|
||||||
|
loading="lazy">
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<div class="article-details">
|
||||||
|
<h2 class="article-title">
|
||||||
|
{{- .context.Title -}}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</article>
|
75
layouts/partials/article/article.html
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<article class="{{ if .Params.image }}has-image{{ end }} main-article">
|
||||||
|
<header class="article-header">
|
||||||
|
{{ if .Params.image }}
|
||||||
|
{{- $image := partial "helper/image" . -}}
|
||||||
|
|
||||||
|
{{- $tablet := $image.Resize "1024x" -}}
|
||||||
|
{{- $desktop := $image.Resize "2000x" -}}
|
||||||
|
|
||||||
|
{{- $20x := $image.Fill "20x20 smart" -}}
|
||||||
|
{{- .Scratch.Set "20x" $20x -}}
|
||||||
|
|
||||||
|
<div class="article-image">
|
||||||
|
<img srcset="{{ $tablet.RelPermalink }} 1024w, {{ $desktop.RelPermalink }} 2000w"
|
||||||
|
src="{{ $desktop.RelPermalink }}" width="{{ $image.Width }}" height="{{ $image.Height }}"
|
||||||
|
loading="lazy"
|
||||||
|
alt="Featured image of post {{ .Title }}" />
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<div class="article-details">
|
||||||
|
{{ with $category := .Params.categories }}
|
||||||
|
<header class="article-category">
|
||||||
|
{{ range first 1 $category }}
|
||||||
|
{{ if $.Params.image }}
|
||||||
|
<a href="/categories/{{ . | urlize }}" class="color-tag"
|
||||||
|
data-image="{{ ($.Scratch.Get "20x").RelPermalink }}">{{ . | humanize }}</a>
|
||||||
|
{{ else }}
|
||||||
|
<a href="/categories/{{ . | urlize }}">{{ . | humanize }}</a>
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
</header>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<h2 class="article-title">
|
||||||
|
<a href="{{ .Permalink }}">
|
||||||
|
{{- .Title -}}
|
||||||
|
</a>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
{{ with .Params.description }}
|
||||||
|
<h3 class="article-subtitle">
|
||||||
|
{{ . }}
|
||||||
|
</h3>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<footer class="article-time">
|
||||||
|
{{ (resources.Get "icons/clock.svg").Content | safeHTML }}
|
||||||
|
<time datetime='{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}'>
|
||||||
|
{{- .Date.Format ( or .Site.Params.dateFormat "Jan 02, 2006" ) -}}
|
||||||
|
</time>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="article-content">
|
||||||
|
{{ .Content }}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer class="article-footer">
|
||||||
|
{{ with $tags := .Params.Tags }}
|
||||||
|
<section class="article-tags">
|
||||||
|
{{ range $tags }}
|
||||||
|
<a href="/tags/{{ . | urlize }}">{{ . | humanize }}</a>
|
||||||
|
{{ end }}
|
||||||
|
</section>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if .Site.Params.postLicense }}
|
||||||
|
<section class="article-copyright">
|
||||||
|
{{ (resources.Get "icons/copyright.svg").Content | safeHTML }}
|
||||||
|
<span>{{ .Site.Params.postLicense }}</span>
|
||||||
|
</section>
|
||||||
|
{{ end }}
|
||||||
|
</footer>
|
||||||
|
</article>
|
1
layouts/partials/article/components/comment.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
{{ template "_internal/disqus.html" . }}
|
66
layouts/partials/article/components/photoswipe.html
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<!-- Root element of PhotoSwipe. Must have class pswp. -->
|
||||||
|
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true" style="display:none">
|
||||||
|
|
||||||
|
<!-- Background of PhotoSwipe.
|
||||||
|
It's a separate element as animating opacity is faster than rgba(). -->
|
||||||
|
<div class="pswp__bg"></div>
|
||||||
|
|
||||||
|
<!-- Slides wrapper with overflow:hidden. -->
|
||||||
|
<div class="pswp__scroll-wrap">
|
||||||
|
|
||||||
|
<!-- Container that holds slides.
|
||||||
|
PhotoSwipe keeps only 3 of them in the DOM to save memory.
|
||||||
|
Don't modify these 3 pswp__item elements, data is added later on. -->
|
||||||
|
<div class="pswp__container">
|
||||||
|
<div class="pswp__item"></div>
|
||||||
|
<div class="pswp__item"></div>
|
||||||
|
<div class="pswp__item"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
|
||||||
|
<div class="pswp__ui pswp__ui--hidden">
|
||||||
|
|
||||||
|
<div class="pswp__top-bar">
|
||||||
|
|
||||||
|
<!-- Controls are self-explanatory. Order can be changed. -->
|
||||||
|
|
||||||
|
<div class="pswp__counter"></div>
|
||||||
|
|
||||||
|
<button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
|
||||||
|
|
||||||
|
<button class="pswp__button pswp__button--share" title="Share"></button>
|
||||||
|
|
||||||
|
<button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
|
||||||
|
|
||||||
|
<button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
|
||||||
|
|
||||||
|
<!-- Preloader demo https://codepen.io/dimsemenov/pen/yyBWoR -->
|
||||||
|
<!-- element will get class pswp__preloader--active when preloader is running -->
|
||||||
|
<div class="pswp__preloader">
|
||||||
|
<div class="pswp__preloader__icn">
|
||||||
|
<div class="pswp__preloader__cut">
|
||||||
|
<div class="pswp__preloader__donut"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
|
||||||
|
<div class="pswp__share-tooltip"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="pswp__caption">
|
||||||
|
<div class="pswp__caption__center"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
13
layouts/partials/article/components/related-contents.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<aside class="widget related-contents--wrapper">
|
||||||
|
{{ $related := .Site.RegularPages.Related . | first 5 }}
|
||||||
|
{{ with $related }}
|
||||||
|
<h1 class="widget-title">Related contents</h1>
|
||||||
|
<div class="related-contents">
|
||||||
|
<div class="flex article-list--tile">
|
||||||
|
{{ range . }}
|
||||||
|
{{ partial "article-list/tile" (dict "context" . "size" "250x350") }}
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</aside>
|
11
layouts/partials/data/description.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{{- with .Description -}}
|
||||||
|
{{- . -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- if .IsPage -}}
|
||||||
|
{{- .Summary -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- with .Site.Params.subtitle -}}
|
||||||
|
{{- . -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
16
layouts/partials/data/title.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{{- $title := .Title -}}
|
||||||
|
{{- $siteTitle := .Site.Title -}}
|
||||||
|
{{- $authorName := .Site.Author.name -}}
|
||||||
|
|
||||||
|
{{- if .IsHome -}}
|
||||||
|
{{- $v1 := where .Site.RegularPages "Type" "post" -}}
|
||||||
|
{{- $v2 := where .Site.RegularPages "Params.hidden" "!=" true -}}
|
||||||
|
{{- $filtered := $v1 | intersect $v2 -}}
|
||||||
|
{{- $pag := .Paginate ($filtered) -}}
|
||||||
|
{{ if .Paginator.HasPrev }}{{ .Paginator }} - {{ end }}{{ $siteTitle }}
|
||||||
|
{{- else if eq .Kind "term" -}}
|
||||||
|
{{- $pag := .Paginate (where .Data.Pages "Type" "post") -}}
|
||||||
|
{{ title .Data.Singular }}: {{ $title }}{{ if .Paginator.HasPrev }} - {{ .Paginator }}{{ end }} - {{ $siteTitle }}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $title -}}
|
||||||
|
{{- end -}}
|
7
layouts/partials/footer.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<footer class="site-footer">
|
||||||
|
<section class="copyright">© {{ now.Format "2006" }} {{ .Site.Title }}</section>
|
||||||
|
<section class="powerby">
|
||||||
|
Built with <a href="https://gohugo.io/" target="_blank">Hugo</a> <br />
|
||||||
|
Theme <b>Stack</b> designed by <a href="https://jimmycai.com" target="_blank">Jimmy</a>
|
||||||
|
</section>
|
||||||
|
</footer>
|
15
layouts/partials/footer/script.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/timeago.js/4.0.2/timeago.min.js"
|
||||||
|
integrity="sha512-SVDh1zH5N9ChofSlNAK43lcNS7lWze6DTVx1JCXH1Tmno+0/1jMpdbR8YDgDUfcUrPp1xyE53G42GFrcM0CMVg=="
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-JavaScript-Templates/3.18.0/js/tmpl.min.js"
|
||||||
|
integrity="sha512-62X328c9VQQkWxrLMccNyRISbwvqQDjvF/HFuvHBMGtZJbNvTG30k1M2O+PYLyWUrcHFKIPvr2OkgmUmcaiccw=="
|
||||||
|
crossorigin="anonymous"></script>-->
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/node-vibrant@3.1.5/dist/vibrant.min.js"
|
||||||
|
integrity="sha256-5NovOZc4iwiAWTYIFiIM7DxKUXKWvpVEuMEPLzcm5/g=" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
{{ $opts := dict "minify" hugo.IsProduction }}
|
||||||
|
{{ $script := resources.Get "ts/main.ts" | js.Build $opts }}
|
||||||
|
|
||||||
|
<script type="text/javascript" src="{{ $script.RelPermalink }}" defer></script>
|
0
layouts/partials/footer/style.html
Normal file
18
layouts/partials/head.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<head>
|
||||||
|
<meta charset='utf-8'>
|
||||||
|
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||||
|
<meta name='description' content='{{ chomp (partial "data/description" . | plainify ) }}'>
|
||||||
|
<base href='{{ .Site.BaseURL }}'>
|
||||||
|
|
||||||
|
<title>{{ (trim (partial "data/title" .) "\n" ) | safeHTML }}</title>
|
||||||
|
<link rel='canonical' href='{{ .Permalink }}'>
|
||||||
|
|
||||||
|
{{ partial "head/style.html" . }}
|
||||||
|
{{ partial "head/script.html" . }}
|
||||||
|
|
||||||
|
{{ partial "head/opengraph.html" . }}
|
||||||
|
|
||||||
|
{{ range .AlternativeOutputFormats -}}
|
||||||
|
<link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink | safeURL }}">
|
||||||
|
{{ end -}}
|
||||||
|
</head>
|
51
layouts/partials/head/opengraph.html
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<meta property='og:title' content='{{ partial "data/title" . }}'>
|
||||||
|
<meta property='og:description' content='{{ chomp (partial "data/description" . | plainify ) }}'>
|
||||||
|
<meta property='og:url' content='{{ .Permalink }}'>
|
||||||
|
<meta property='og:site_name' content='{{ .Site.Title }}'>
|
||||||
|
<meta property='og:type' content='
|
||||||
|
{{- if .IsPage -}}
|
||||||
|
article
|
||||||
|
{{- else -}}
|
||||||
|
website
|
||||||
|
{{- end -}}
|
||||||
|
'>
|
||||||
|
|
||||||
|
{{ with .Site.Params.twitter }}
|
||||||
|
<meta name="twitter:site" content="{{ . }}">
|
||||||
|
{{ end }}
|
||||||
|
<meta name="twitter:title" content="{{ partial "data/title" . }}">
|
||||||
|
<meta name="twitter:description" content="{{ chomp (partial "data/description" . | plainify ) }}">
|
||||||
|
|
||||||
|
{{- with .Params.locale -}}
|
||||||
|
<meta property='og:locale' content='{{ . }}'>
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- if .IsPage -}}
|
||||||
|
<meta property='article:section' content='{{ .Section | title }}' />
|
||||||
|
{{- range .Params.tags -}}
|
||||||
|
<meta property='article:tag' content='{{ . }}' />
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- if .IsPage -}}
|
||||||
|
{{- if not .Date.IsZero -}}
|
||||||
|
<meta property='article:published_time' content='{{ .Date.Format "2006-01-02T15:04:05-07:00" | safeHTML }}'/>
|
||||||
|
{{- end -}}
|
||||||
|
{{- if not .Lastmod.IsZero -}}
|
||||||
|
<meta property='article:modified_time' content='{{ .Lastmod.Format "2006-01-02T15:04:05-07:00" | safeHTML }}'/>
|
||||||
|
{{- end -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- if not .Site.LastChange.IsZero -}}
|
||||||
|
<meta property='og:updated_time' content='{{ .Site.LastChange.Format " 2006-01-02T15:04:05-07:00 " | safeHTML }}'/>
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
|
||||||
|
{{- if .Params.image -}}
|
||||||
|
{{ $image := partial "helper/image" . }}
|
||||||
|
<meta property='og:image' content='{{ absURL $image.RelPermalink }}' />
|
||||||
|
<meta name="twitter:image" content='{{ absURL $image.RelPermalink }}' />
|
||||||
|
{{- else -}}
|
||||||
|
<meta property='og:image' content='{{ absURL .Site.Params.logo }}' />
|
||||||
|
{{- end -}}
|
0
layouts/partials/head/script.html
Normal file
5
layouts/partials/head/style.html
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<link href="https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700&display=swap" rel="stylesheet">
|
||||||
|
|
||||||
|
{{ $sass := resources.Get "scss/style.scss" }}
|
||||||
|
{{ $style := $sass | resources.ToCSS | minify }}
|
||||||
|
<link rel="stylesheet" href="{{ $style.Permalink }}">
|
2
layouts/partials/helper/image.html
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
{{- $image := .Resources.GetMatch (printf "%s" (.Params.image | safeURL)) -}}
|
||||||
|
{{ return $image }}
|
26
layouts/partials/pagination.html
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{{ if gt .Paginator.TotalPages 1 }}
|
||||||
|
<nav class='pagination'>
|
||||||
|
{{ $.Scratch.Set "hasPrevDots" false }}
|
||||||
|
{{ $.Scratch.Set "hasNextDots" false }}
|
||||||
|
|
||||||
|
{{ range .Paginator.Pagers }}
|
||||||
|
{{ if eq . $.Paginator }}
|
||||||
|
<span class='page-link current'>
|
||||||
|
{{- .PageNumber -}}
|
||||||
|
</span>
|
||||||
|
{{ else if or (or (eq . $.Paginator.First) (eq . $.Paginator.Prev)) (or (eq . $.Paginator.Next) (eq . $.Paginator.Last )) }}
|
||||||
|
<a class='page-link' href='{{ .URL }}'>
|
||||||
|
{{- .PageNumber -}}
|
||||||
|
</a>
|
||||||
|
{{ else }}
|
||||||
|
{{ if and (not ($.Scratch.Get "hasPrevDots")) (lt .PageNumber $.Paginator.PageNumber) }}
|
||||||
|
{{ $.Scratch.Set "hasPrevDots" true }}
|
||||||
|
<span class='page-link dots'>…</span>
|
||||||
|
{{ else if and (not ($.Scratch.Get "hasNextDots")) (gt .PageNumber $.Paginator.PageNumber) }}
|
||||||
|
{{ $.Scratch.Set "hasNextDots" true }}
|
||||||
|
<span class='page-link dots'>…</span>
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
</nav>
|
||||||
|
{{ end }}
|
33
layouts/partials/sidebar/left.html
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<aside class="sidebar left-sidebar sticky">
|
||||||
|
<button class="hamburger hamburger--spin" type="button" id="toggle-menu" aria-label="Toggle Menu">
|
||||||
|
<span class="hamburger-box">
|
||||||
|
<span class="hamburger-inner"></span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<header class="site-info">
|
||||||
|
<figure class="site-avatar">
|
||||||
|
{{ $avatar := resources.Get (.Site.Params.avatar) }}
|
||||||
|
{{ $avatarResized := $avatar.Resize "300x300" }}
|
||||||
|
<img src="{{ $avatarResized.RelPermalink }}" width="{{ $avatarResized.Width }}"
|
||||||
|
height="{{ $avatarResized.Height }}" class="site-logo" loading="lazy" alt="Avatar">
|
||||||
|
<span class="emoji">{{ .Site.Params.emoji }}</span>
|
||||||
|
</figure>
|
||||||
|
<h1 class="site-name"><a href="{{ .Site.BaseURL }}">{{ .Site.Title }}</a></h1>
|
||||||
|
<h2 class="site-description">{{ .Site.Params.subtitle }}</h2>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<nav class="menu" id="main-menu">
|
||||||
|
{{ $currentPage := . }}
|
||||||
|
{{ range .Site.Menus.main }}
|
||||||
|
{{ $active := or (eq $currentPage.Title .Name) (or ($currentPage.HasMenuCurrent "main" .) ($currentPage.IsMenuCurrent "main" .)) }}
|
||||||
|
|
||||||
|
<li {{ if $active }} class='current' {{ end }}>
|
||||||
|
<a href='{{ .URL }}'>
|
||||||
|
{{ (resources.Get (delimit (slice "icons/" .Pre ".svg") "")).Content | safeHTML }}
|
||||||
|
<span>{{- .Name -}}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{ end }}
|
||||||
|
</nav>
|
||||||
|
</aside>
|
8
layouts/partials/sidebar/right.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{{ if .Site.Params.widgets.enabled }}
|
||||||
|
{{ $context := . }}
|
||||||
|
<aside class="sidebar right-sidebar sticky">
|
||||||
|
{{ range $widget := .Site.Params.widgets.enabled }}
|
||||||
|
{{ partial (printf "widget/%s" $widget) $context }}
|
||||||
|
{{ end }}
|
||||||
|
</aside>
|
||||||
|
{{ end }}
|
19
layouts/partials/widget/archive.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<section class="widget archive">
|
||||||
|
<div class="widget-icon">
|
||||||
|
{{ (resources.Get "icons/infinity.svg").Content | safeHTML }}
|
||||||
|
</div>
|
||||||
|
<h1 class="widget-title">Archive</h1>
|
||||||
|
|
||||||
|
{{ $v1 := where .Site.RegularPages "Section" "post" }}
|
||||||
|
{{ $v2 := where .Site.RegularPages "Params.hidden" "!=" true }}
|
||||||
|
{{ $filtered := $v1 | intersect $v2 }}
|
||||||
|
{{ range $filtered.GroupByDate "2006" }}
|
||||||
|
{{ $id := lower (replace .Key " " "-") }}
|
||||||
|
<div class="archive-year">
|
||||||
|
<a href="{{ $.Site.BaseURL }}/archive#{{ $id }}">
|
||||||
|
<span class="year">{{ .Key }}</span>
|
||||||
|
<span class="count">{{ len .Pages }}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</section>
|
17
layouts/partials/widget/tag-cloud.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{{ $tags := .Site.Taxonomies.tags.ByCount }}
|
||||||
|
{{ $v2 := where $tags "Term" "not in" (slice "hugo" "tag" "rss") }}
|
||||||
|
|
||||||
|
<section class="widget tagCloud">
|
||||||
|
<div class="widget-icon">
|
||||||
|
{{ (resources.Get "icons/tag.svg").Content | safeHTML }}
|
||||||
|
</div>
|
||||||
|
<h1 class="widget-title">Tags</h1>
|
||||||
|
|
||||||
|
<div class="tagCloud-tags">
|
||||||
|
{{ range first .Site.Params.widgets.tagCloud.limit $v2 }}
|
||||||
|
<a href="{{ $.Site.BaseURL }}tags/{{ .Term | urlize }}/" class="font_size_{{ .Count }}">
|
||||||
|
{{ .Term | humanize }}
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</section>
|
9
layouts/shortcodes/youtube.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{{- $pc := .Page.Site.Config.Privacy.YouTube -}}
|
||||||
|
{{- if not $pc.Disable -}}
|
||||||
|
{{- $ytHost := cond $pc.PrivacyEnhanced "www.youtube-nocookie.com" "www.youtube.com" -}}
|
||||||
|
{{- $id := .Get "id" | default (.Get 0) -}}
|
||||||
|
{{- $class := .Get "class" | default (.Get 1) }}
|
||||||
|
<div {{ with $class }}class="{{ . }}"{{ else }}style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"{{ end }}>
|
||||||
|
<iframe loading="lazy" src="https://{{ $ytHost }}/embed/{{ $id }}{{ with .Get "autoplay" }}{{ if eq . "true" }}?autoplay=1{{ end }}{{ end }}" {{ if not $class }}style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" {{ end }}allowfullscreen title="YouTube Video"></iframe>
|
||||||
|
</div>
|
||||||
|
{{ end -}}
|
15
theme.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# theme.toml template for a Hugo theme
|
||||||
|
# See https://github.com/gohugoio/hugoThemes#themetoml for an example
|
||||||
|
|
||||||
|
name = "Stack"
|
||||||
|
license = "GPL-3.0-only"
|
||||||
|
licenselink = "https://github.com/CaiJimmy/hugo-theme-stack/blob/master/LICENSE"
|
||||||
|
description = ""
|
||||||
|
homepage = "https://blog.jimmycai.com/p/hugo-theme-stack"
|
||||||
|
tags = []
|
||||||
|
features = []
|
||||||
|
min_version = "0.74.0"
|
||||||
|
|
||||||
|
[author]
|
||||||
|
name = "Jimmy Cai"
|
||||||
|
homepage = "https://jimmycai.com"
|