Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb8b5b5d32
|
||
|
|
ed4cb4fc5c
|
||
|
|
b90ab68c74
|
||
|
|
91d5929260
|
||
|
|
6c435b8748
|
||
|
|
860a89db9f
|
||
|
|
3280dbfffe
|
||
|
|
e5b2020bda
|
||
|
|
4e848a0b68
|
||
|
|
8e191c8864
|
||
|
|
43400ef31c
|
||
|
|
199d3b2f8a
|
||
|
|
4882060a62
|
||
|
|
a9fd31fa97
|
||
|
|
92e83cd888
|
||
|
|
31174ea9a9
|
||
|
|
df5e2a26cb
|
||
|
|
e7332da3f1 | ||
|
|
85ea7ddbd0
|
||
|
|
eee1503855
|
||
|
|
a2426b8f87
|
||
|
|
3edf844494
|
||
|
|
2aa705489b
|
||
|
|
3b1399390e
|
||
|
|
3f37c60e75
|
||
|
|
b89909ec81
|
||
|
|
2a1c79ffdc
|
||
|
|
7244e5503d
|
||
|
|
c76cbd4682
|
||
|
|
36b0206010
|
||
|
|
1fbf81292f
|
||
|
|
149bfe3e25
|
||
|
|
d97ff65332
|
||
|
|
35a4047a6c
|
||
|
|
4207f349b9
|
||
|
|
d0293622b2
|
||
|
|
1b191dbb2e
|
||
|
|
8f4a98c9e3
|
||
|
|
54ba4969cd
|
||
|
|
5b6501e8c9
|
||
|
|
7a02a56a63
|
||
|
|
ed59610650
|
||
|
|
e623d7d012
|
||
|
|
f2954f09d2
|
||
|
|
0aadd4b383
|
||
|
|
8fd46e2543
|
||
|
|
8ed0ca9918
|
||
|
|
2965d6e7a6
|
||
|
|
3b497e231b
|
||
|
|
8c58acd9f8
|
||
|
|
be54eea7a9
|
||
|
|
6258431a9d
|
||
|
|
65d96abb40
|
||
|
|
5da5e79f41
|
||
|
|
e40f2de9e2
|
||
|
|
2de62be083
|
||
|
|
baac9b8642
|
||
|
|
a2a86d7f32
|
||
|
|
7f431aed5b
|
||
|
|
9043cba830
|
||
|
|
8df2030bd8
|
||
|
|
c45b74bd53
|
||
|
|
8c1375fe9a
|
||
|
|
529230d926
|
||
|
|
dc4d0ec5e0
|
||
|
|
84ef620259
|
||
|
|
db7ed4cea6
|
||
|
|
92cda1f189
|
||
|
|
cc53639ca8
|
||
|
|
73a38e9083
|
2
.github/workflows/deploy-pr-preview.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
run: |
|
||||
pnpm install
|
||||
go install github.com/a-h/templ/cmd/templ@latest
|
||||
make build-vercel
|
||||
make build/static
|
||||
- name: Deploy
|
||||
uses: BetaHuhn/deploy-to-vercel-action@v1
|
||||
with:
|
||||
|
||||
2
.github/workflows/deploy-preview.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
run: |
|
||||
pnpm install
|
||||
go install github.com/a-h/templ/cmd/templ@latest
|
||||
make build-vercel
|
||||
make build/static
|
||||
- name: Deploy
|
||||
uses: BetaHuhn/deploy-to-vercel-action@v1
|
||||
with:
|
||||
|
||||
2
.github/workflows/deploy.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
run: |
|
||||
pnpm install
|
||||
go install github.com/a-h/templ/cmd/templ@latest
|
||||
make build-vercel
|
||||
make build/static
|
||||
- name: Deploy
|
||||
uses: BetaHuhn/deploy-to-vercel-action@v1
|
||||
with:
|
||||
|
||||
1
.gitignore
vendored
@@ -3,6 +3,7 @@ Session.vim
|
||||
.direnv
|
||||
.vercel
|
||||
*_templ.go
|
||||
*_templ.txt
|
||||
dist
|
||||
tmp
|
||||
bin
|
||||
|
||||
373
LICENSE
Normal file
@@ -0,0 +1,373 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
428
LICENSE-CC-BY-SA
Normal file
@@ -0,0 +1,428 @@
|
||||
Attribution-ShareAlike 4.0 International
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||
does not provide legal services or legal advice. Distribution of
|
||||
Creative Commons public licenses does not create a lawyer-client or
|
||||
other relationship. Creative Commons makes its licenses and related
|
||||
information available on an "as-is" basis. Creative Commons gives no
|
||||
warranties regarding its licenses, any material licensed under their
|
||||
terms and conditions, or any related information. Creative Commons
|
||||
disclaims all liability for damages resulting from their use to the
|
||||
fullest extent possible.
|
||||
|
||||
Using Creative Commons Public Licenses
|
||||
|
||||
Creative Commons public licenses provide a standard set of terms and
|
||||
conditions that creators and other rights holders may use to share
|
||||
original works of authorship and other material subject to copyright
|
||||
and certain other rights specified in the public license below. The
|
||||
following considerations are for informational purposes only, are not
|
||||
exhaustive, and do not form part of our licenses.
|
||||
|
||||
Considerations for licensors: Our public licenses are
|
||||
intended for use by those authorized to give the public
|
||||
permission to use material in ways otherwise restricted by
|
||||
copyright and certain other rights. Our licenses are
|
||||
irrevocable. Licensors should read and understand the terms
|
||||
and conditions of the license they choose before applying it.
|
||||
Licensors should also secure all rights necessary before
|
||||
applying our licenses so that the public can reuse the
|
||||
material as expected. Licensors should clearly mark any
|
||||
material not subject to the license. This includes other CC-
|
||||
licensed material, or material used under an exception or
|
||||
limitation to copyright. More considerations for licensors:
|
||||
wiki.creativecommons.org/Considerations_for_licensors
|
||||
|
||||
Considerations for the public: By using one of our public
|
||||
licenses, a licensor grants the public permission to use the
|
||||
licensed material under specified terms and conditions. If
|
||||
the licensor's permission is not necessary for any reason--for
|
||||
example, because of any applicable exception or limitation to
|
||||
copyright--then that use is not regulated by the license. Our
|
||||
licenses grant only permissions under copyright and certain
|
||||
other rights that a licensor has authority to grant. Use of
|
||||
the licensed material may still be restricted for other
|
||||
reasons, including because others have copyright or other
|
||||
rights in the material. A licensor may make special requests,
|
||||
such as asking that all changes be marked or described.
|
||||
Although not required by our licenses, you are encouraged to
|
||||
respect those requests where reasonable. More considerations
|
||||
for the public:
|
||||
wiki.creativecommons.org/Considerations_for_licensees
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Attribution-ShareAlike 4.0 International Public
|
||||
License
|
||||
|
||||
By exercising the Licensed Rights (defined below), You accept and agree
|
||||
to be bound by the terms and conditions of this Creative Commons
|
||||
Attribution-ShareAlike 4.0 International Public License ("Public
|
||||
License"). To the extent this Public License may be interpreted as a
|
||||
contract, You are granted the Licensed Rights in consideration of Your
|
||||
acceptance of these terms and conditions, and the Licensor grants You
|
||||
such rights in consideration of benefits the Licensor receives from
|
||||
making the Licensed Material available under these terms and
|
||||
conditions.
|
||||
|
||||
|
||||
Section 1 -- Definitions.
|
||||
|
||||
a. Adapted Material means material subject to Copyright and Similar
|
||||
Rights that is derived from or based upon the Licensed Material
|
||||
and in which the Licensed Material is translated, altered,
|
||||
arranged, transformed, or otherwise modified in a manner requiring
|
||||
permission under the Copyright and Similar Rights held by the
|
||||
Licensor. For purposes of this Public License, where the Licensed
|
||||
Material is a musical work, performance, or sound recording,
|
||||
Adapted Material is always produced where the Licensed Material is
|
||||
synched in timed relation with a moving image.
|
||||
|
||||
b. Adapter's License means the license You apply to Your Copyright
|
||||
and Similar Rights in Your contributions to Adapted Material in
|
||||
accordance with the terms and conditions of this Public License.
|
||||
|
||||
c. BY-SA Compatible License means a license listed at
|
||||
creativecommons.org/compatiblelicenses, approved by Creative
|
||||
Commons as essentially the equivalent of this Public License.
|
||||
|
||||
d. Copyright and Similar Rights means copyright and/or similar rights
|
||||
closely related to copyright including, without limitation,
|
||||
performance, broadcast, sound recording, and Sui Generis Database
|
||||
Rights, without regard to how the rights are labeled or
|
||||
categorized. For purposes of this Public License, the rights
|
||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||
Rights.
|
||||
|
||||
e. Effective Technological Measures means those measures that, in the
|
||||
absence of proper authority, may not be circumvented under laws
|
||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||
Treaty adopted on December 20, 1996, and/or similar international
|
||||
agreements.
|
||||
|
||||
f. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||
any other exception or limitation to Copyright and Similar Rights
|
||||
that applies to Your use of the Licensed Material.
|
||||
|
||||
g. License Elements means the license attributes listed in the name
|
||||
of a Creative Commons Public License. The License Elements of this
|
||||
Public License are Attribution and ShareAlike.
|
||||
|
||||
h. Licensed Material means the artistic or literary work, database,
|
||||
or other material to which the Licensor applied this Public
|
||||
License.
|
||||
|
||||
i. Licensed Rights means the rights granted to You subject to the
|
||||
terms and conditions of this Public License, which are limited to
|
||||
all Copyright and Similar Rights that apply to Your use of the
|
||||
Licensed Material and that the Licensor has authority to license.
|
||||
|
||||
j. Licensor means the individual(s) or entity(ies) granting rights
|
||||
under this Public License.
|
||||
|
||||
k. Share means to provide material to the public by any means or
|
||||
process that requires permission under the Licensed Rights, such
|
||||
as reproduction, public display, public performance, distribution,
|
||||
dissemination, communication, or importation, and to make material
|
||||
available to the public including in ways that members of the
|
||||
public may access the material from a place and at a time
|
||||
individually chosen by them.
|
||||
|
||||
l. Sui Generis Database Rights means rights other than copyright
|
||||
resulting from Directive 96/9/EC of the European Parliament and of
|
||||
the Council of 11 March 1996 on the legal protection of databases,
|
||||
as amended and/or succeeded, as well as other essentially
|
||||
equivalent rights anywhere in the world.
|
||||
|
||||
m. You means the individual or entity exercising the Licensed Rights
|
||||
under this Public License. Your has a corresponding meaning.
|
||||
|
||||
|
||||
Section 2 -- Scope.
|
||||
|
||||
a. License grant.
|
||||
|
||||
1. Subject to the terms and conditions of this Public License,
|
||||
the Licensor hereby grants You a worldwide, royalty-free,
|
||||
non-sublicensable, non-exclusive, irrevocable license to
|
||||
exercise the Licensed Rights in the Licensed Material to:
|
||||
|
||||
a. reproduce and Share the Licensed Material, in whole or
|
||||
in part; and
|
||||
|
||||
b. produce, reproduce, and Share Adapted Material.
|
||||
|
||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||
Exceptions and Limitations apply to Your use, this Public
|
||||
License does not apply, and You do not need to comply with
|
||||
its terms and conditions.
|
||||
|
||||
3. Term. The term of this Public License is specified in Section
|
||||
6(a).
|
||||
|
||||
4. Media and formats; technical modifications allowed. The
|
||||
Licensor authorizes You to exercise the Licensed Rights in
|
||||
all media and formats whether now known or hereafter created,
|
||||
and to make technical modifications necessary to do so. The
|
||||
Licensor waives and/or agrees not to assert any right or
|
||||
authority to forbid You from making technical modifications
|
||||
necessary to exercise the Licensed Rights, including
|
||||
technical modifications necessary to circumvent Effective
|
||||
Technological Measures. For purposes of this Public License,
|
||||
simply making modifications authorized by this Section 2(a)
|
||||
(4) never produces Adapted Material.
|
||||
|
||||
5. Downstream recipients.
|
||||
|
||||
a. Offer from the Licensor -- Licensed Material. Every
|
||||
recipient of the Licensed Material automatically
|
||||
receives an offer from the Licensor to exercise the
|
||||
Licensed Rights under the terms and conditions of this
|
||||
Public License.
|
||||
|
||||
b. Additional offer from the Licensor -- Adapted Material.
|
||||
Every recipient of Adapted Material from You
|
||||
automatically receives an offer from the Licensor to
|
||||
exercise the Licensed Rights in the Adapted Material
|
||||
under the conditions of the Adapter's License You apply.
|
||||
|
||||
c. No downstream restrictions. You may not offer or impose
|
||||
any additional or different terms or conditions on, or
|
||||
apply any Effective Technological Measures to, the
|
||||
Licensed Material if doing so restricts exercise of the
|
||||
Licensed Rights by any recipient of the Licensed
|
||||
Material.
|
||||
|
||||
6. No endorsement. Nothing in this Public License constitutes or
|
||||
may be construed as permission to assert or imply that You
|
||||
are, or that Your use of the Licensed Material is, connected
|
||||
with, or sponsored, endorsed, or granted official status by,
|
||||
the Licensor or others designated to receive attribution as
|
||||
provided in Section 3(a)(1)(A)(i).
|
||||
|
||||
b. Other rights.
|
||||
|
||||
1. Moral rights, such as the right of integrity, are not
|
||||
licensed under this Public License, nor are publicity,
|
||||
privacy, and/or other similar personality rights; however, to
|
||||
the extent possible, the Licensor waives and/or agrees not to
|
||||
assert any such rights held by the Licensor to the limited
|
||||
extent necessary to allow You to exercise the Licensed
|
||||
Rights, but not otherwise.
|
||||
|
||||
2. Patent and trademark rights are not licensed under this
|
||||
Public License.
|
||||
|
||||
3. To the extent possible, the Licensor waives any right to
|
||||
collect royalties from You for the exercise of the Licensed
|
||||
Rights, whether directly or through a collecting society
|
||||
under any voluntary or waivable statutory or compulsory
|
||||
licensing scheme. In all other cases the Licensor expressly
|
||||
reserves any right to collect such royalties.
|
||||
|
||||
|
||||
Section 3 -- License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the
|
||||
following conditions.
|
||||
|
||||
a. Attribution.
|
||||
|
||||
1. If You Share the Licensed Material (including in modified
|
||||
form), You must:
|
||||
|
||||
a. retain the following if it is supplied by the Licensor
|
||||
with the Licensed Material:
|
||||
|
||||
i. identification of the creator(s) of the Licensed
|
||||
Material and any others designated to receive
|
||||
attribution, in any reasonable manner requested by
|
||||
the Licensor (including by pseudonym if
|
||||
designated);
|
||||
|
||||
ii. a copyright notice;
|
||||
|
||||
iii. a notice that refers to this Public License;
|
||||
|
||||
iv. a notice that refers to the disclaimer of
|
||||
warranties;
|
||||
|
||||
v. a URI or hyperlink to the Licensed Material to the
|
||||
extent reasonably practicable;
|
||||
|
||||
b. indicate if You modified the Licensed Material and
|
||||
retain an indication of any previous modifications; and
|
||||
|
||||
c. indicate the Licensed Material is licensed under this
|
||||
Public License, and include the text of, or the URI or
|
||||
hyperlink to, this Public License.
|
||||
|
||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||
reasonable manner based on the medium, means, and context in
|
||||
which You Share the Licensed Material. For example, it may be
|
||||
reasonable to satisfy the conditions by providing a URI or
|
||||
hyperlink to a resource that includes the required
|
||||
information.
|
||||
|
||||
3. If requested by the Licensor, You must remove any of the
|
||||
information required by Section 3(a)(1)(A) to the extent
|
||||
reasonably practicable.
|
||||
|
||||
b. ShareAlike.
|
||||
|
||||
In addition to the conditions in Section 3(a), if You Share
|
||||
Adapted Material You produce, the following conditions also apply.
|
||||
|
||||
1. The Adapter's License You apply must be a Creative Commons
|
||||
license with the same License Elements, this version or
|
||||
later, or a BY-SA Compatible License.
|
||||
|
||||
2. You must include the text of, or the URI or hyperlink to, the
|
||||
Adapter's License You apply. You may satisfy this condition
|
||||
in any reasonable manner based on the medium, means, and
|
||||
context in which You Share Adapted Material.
|
||||
|
||||
3. You may not offer or impose any additional or different terms
|
||||
or conditions on, or apply any Effective Technological
|
||||
Measures to, Adapted Material that restrict exercise of the
|
||||
rights granted under the Adapter's License You apply.
|
||||
|
||||
|
||||
Section 4 -- Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that
|
||||
apply to Your use of the Licensed Material:
|
||||
|
||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||
to extract, reuse, reproduce, and Share all or a substantial
|
||||
portion of the contents of the database;
|
||||
|
||||
b. if You include all or a substantial portion of the database
|
||||
contents in a database in which You have Sui Generis Database
|
||||
Rights, then the database in which You have Sui Generis Database
|
||||
Rights (but not its individual contents) is Adapted Material,
|
||||
including for purposes of Section 3(b); and
|
||||
|
||||
c. You must comply with the conditions in Section 3(a) if You Share
|
||||
all or a substantial portion of the contents of the database.
|
||||
|
||||
For the avoidance of doubt, this Section 4 supplements and does not
|
||||
replace Your obligations under this Public License where the Licensed
|
||||
Rights include other Copyright and Similar Rights.
|
||||
|
||||
|
||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||
|
||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
c. The disclaimer of warranties and limitation of liability provided
|
||||
above shall be interpreted in a manner that, to the extent
|
||||
possible, most closely approximates an absolute disclaimer and
|
||||
waiver of all liability.
|
||||
|
||||
|
||||
Section 6 -- Term and Termination.
|
||||
|
||||
a. This Public License applies for the term of the Copyright and
|
||||
Similar Rights licensed here. However, if You fail to comply with
|
||||
this Public License, then Your rights under this Public License
|
||||
terminate automatically.
|
||||
|
||||
b. Where Your right to use the Licensed Material has terminated under
|
||||
Section 6(a), it reinstates:
|
||||
|
||||
1. automatically as of the date the violation is cured, provided
|
||||
it is cured within 30 days of Your discovery of the
|
||||
violation; or
|
||||
|
||||
2. upon express reinstatement by the Licensor.
|
||||
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||
right the Licensor may have to seek remedies for Your violations
|
||||
of this Public License.
|
||||
|
||||
c. For the avoidance of doubt, the Licensor may also offer the
|
||||
Licensed Material under separate terms or conditions or stop
|
||||
distributing the Licensed Material at any time; however, doing so
|
||||
will not terminate this Public License.
|
||||
|
||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||
License.
|
||||
|
||||
|
||||
Section 7 -- Other Terms and Conditions.
|
||||
|
||||
a. The Licensor shall not be bound by any additional or different
|
||||
terms or conditions communicated by You unless expressly agreed.
|
||||
|
||||
b. Any arrangements, understandings, or agreements regarding the
|
||||
Licensed Material not stated herein are separate from and
|
||||
independent of the terms and conditions of this Public License.
|
||||
|
||||
|
||||
Section 8 -- Interpretation.
|
||||
|
||||
a. For the avoidance of doubt, this Public License does not, and
|
||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||
conditions on any use of the Licensed Material that could lawfully
|
||||
be made without permission under this Public License.
|
||||
|
||||
b. To the extent possible, if any provision of this Public License is
|
||||
deemed unenforceable, it shall be automatically reformed to the
|
||||
minimum extent necessary to make it enforceable. If the provision
|
||||
cannot be reformed, it shall be severed from this Public License
|
||||
without affecting the enforceability of the remaining terms and
|
||||
conditions.
|
||||
|
||||
c. No term or condition of this Public License will be waived and no
|
||||
failure to comply consented to unless expressly agreed to by the
|
||||
Licensor.
|
||||
|
||||
d. Nothing in this Public License constitutes or may be interpreted
|
||||
as a limitation upon, or waiver of, any privileges and immunities
|
||||
that apply to the Licensor or You, including from the legal
|
||||
processes of any jurisdiction or authority.
|
||||
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons is not a party to its public
|
||||
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
||||
its public licenses to material it publishes and in those instances
|
||||
will be considered the “Licensor.” The text of the Creative Commons
|
||||
public licenses is dedicated to the public domain under the CC0 Public
|
||||
Domain Dedication. Except for the limited purpose of indicating that
|
||||
material is shared under a Creative Commons public license or as
|
||||
otherwise permitted by the Creative Commons policies published at
|
||||
creativecommons.org/policies, Creative Commons does not authorize the
|
||||
use of the trademark "Creative Commons" or any other trademark or logo
|
||||
of Creative Commons without its prior written consent including,
|
||||
without limitation, in connection with any unauthorized modifications
|
||||
to any of its public licenses or any other arrangements,
|
||||
understandings, or agreements concerning use of licensed material. For
|
||||
the avoidance of doubt, this paragraph does not form part of the
|
||||
public licenses.
|
||||
|
||||
Creative Commons may be contacted at creativecommons.org.
|
||||
|
||||
11
README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
---
|
||||
|
||||
Copyright © 2024 Gustavo "Guz" L. de Mello.
|
||||
|
||||
Unless otherwise noticed, contents of this website itself are licensed under
|
||||
the [Creative Commons Attribution-Share Alike 4.0 International ("CC BY-SA 4.0")](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
[(Local copy)](./LICENSE-CC-BY-SA). Guz013, the 013 Logo, are trademarks of
|
||||
Gustavo L. de Mello. The underlyng source code used to format and display that
|
||||
content is, unless otherwise noticed, licensed under the [Mozilla Public License 2.0](https://www.mozilla.org/en-US/MPL/2.0/)
|
||||
[(Local copy)](./LICENSE).
|
||||
27
api/ai.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"www/internals"
|
||||
)
|
||||
|
||||
func AiTxt(w http.ResponseWriter, r *http.Request) {
|
||||
error := internals.HttpErrorHelper(w)
|
||||
|
||||
aiList, err := http.Get("https://raw.githubusercontent.com/ai-robots-txt/ai.robots.txt/main/ai.txt")
|
||||
if error("Error trying to fetch ai block list", err, http.StatusInternalServerError) {
|
||||
return
|
||||
}
|
||||
|
||||
bytes, err := io.ReadAll(aiList.Body)
|
||||
if error("Error trying to read ai block list", err, http.StatusInternalServerError) {
|
||||
return
|
||||
}
|
||||
w.Write(bytes)
|
||||
|
||||
w.Header().Add("Cache-Control", "max-age=604800, stale-while-revalidate=86400, stale-if-error=86400")
|
||||
w.Header().Add("CDN-Cache-Control", "max-age=604800")
|
||||
w.Header().Add("Content-Type", "text/plain")
|
||||
}
|
||||
45
api/hello.go
@@ -1,45 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand/v2"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type helloObj struct {
|
||||
Language string
|
||||
Hello string
|
||||
}
|
||||
|
||||
func getHelloList() ([]helloObj, error) {
|
||||
res, err := http.Get("https://raw.githubusercontent.com/novellac/multilanguage-hello-json/master/hello.json")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bytes, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var hellos []helloObj
|
||||
err = json.Unmarshal(bytes, &hellos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return hellos, nil
|
||||
}
|
||||
|
||||
func Hello(w http.ResponseWriter, r *http.Request) {
|
||||
hellos, err := getHelloList()
|
||||
var hello string
|
||||
if err != nil {
|
||||
hello = "Welcome!"
|
||||
} else {
|
||||
hello = hellos[rand.IntN(len(hellos)-1)].Hello
|
||||
}
|
||||
|
||||
fmt.Fprint(w, hello)
|
||||
}
|
||||
96
api/image.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"image"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"www/internals"
|
||||
|
||||
"github.com/chai2010/webp"
|
||||
"github.com/sunshineplan/imgconv"
|
||||
)
|
||||
|
||||
func ImgOptimize(i image.Image, threshold int) image.Image {
|
||||
w := i.Bounds().Max.X
|
||||
|
||||
if threshold >= w {
|
||||
return i
|
||||
}
|
||||
|
||||
d := w / threshold
|
||||
return imgconv.Resize(i, &imgconv.ResizeOption{Width: w / d})
|
||||
}
|
||||
|
||||
func Image(w http.ResponseWriter, r *http.Request) {
|
||||
error := internals.HttpErrorHelper(w)
|
||||
|
||||
params, err := url.ParseQuery(r.URL.RawQuery)
|
||||
if error("Error trying to parse query parameters", err, http.StatusInternalServerError) {
|
||||
return
|
||||
}
|
||||
|
||||
if _, some := params["url"]; !some {
|
||||
error("\"url\" parameter missing", errors.New("Missing argument"), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
u, err := url.Parse(params.Get("url"))
|
||||
if error("\"url\" is not a valid URL string", err, http.StatusBadRequest) {
|
||||
return
|
||||
}
|
||||
|
||||
if u.Hostname() == "" {
|
||||
if r.URL.Scheme == "" {
|
||||
u.Scheme = "https"
|
||||
} else {
|
||||
u.Scheme = r.URL.Scheme
|
||||
}
|
||||
u.Host = r.Host
|
||||
}
|
||||
|
||||
if _, some := params["threshold"]; !some {
|
||||
error("\"threshold\" parameter missing", errors.New("Missing argument"), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
threshold, err := strconv.Atoi(params.Get("threshold"))
|
||||
if error("\"threshold\" parameter is not a valid integer", err, http.StatusBadRequest) {
|
||||
return
|
||||
}
|
||||
|
||||
res, err := http.Get(u.String())
|
||||
if error("Error trying to fetch the image", err, http.StatusInternalServerError) {
|
||||
return
|
||||
}
|
||||
if res.StatusCode < 200 || res.StatusCode >= 300 {
|
||||
error(
|
||||
"Error trying to fetch the image, response is a non 2XX code",
|
||||
errors.New("Status code: "+res.Status),
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(res.Body)
|
||||
if error("Error trying to read the image data", err, http.StatusInternalServerError) {
|
||||
return
|
||||
}
|
||||
|
||||
img, err := imgconv.Decode(bytes.NewReader(data))
|
||||
if error("Error trying to decode the image", err, http.StatusInternalServerError) {
|
||||
return
|
||||
}
|
||||
|
||||
img = ImgOptimize(img, threshold)
|
||||
|
||||
err = webp.Encode(w, img, &webp.Options{Lossless: true})
|
||||
if error("Error trying to encode the image", err, http.StatusInternalServerError) {
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Add("Cache-Control", "max-age=604800, stale-while-revalidate=86400, stale-if-error=86400")
|
||||
w.Header().Add("CDN-Cache-Control", "max-age=604800")
|
||||
w.Header().Add("Content-Type", "image/webp")
|
||||
}
|
||||
27
api/robots.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"www/internals"
|
||||
)
|
||||
|
||||
func RobotsTxt(w http.ResponseWriter, r *http.Request) {
|
||||
error := internals.HttpErrorHelper(w)
|
||||
|
||||
aiList, err := http.Get("https://raw.githubusercontent.com/ai-robots-txt/ai.robots.txt/main/robots.txt")
|
||||
if error("Error trying to fetch ai block list", err, http.StatusInternalServerError) {
|
||||
return
|
||||
}
|
||||
|
||||
bytes, err := io.ReadAll(aiList.Body)
|
||||
if error("Error trying to read ai block list", err, http.StatusInternalServerError) {
|
||||
return
|
||||
}
|
||||
w.Write(bytes)
|
||||
|
||||
w.Header().Add("Cache-Control", "max-age=604800, stale-while-revalidate=86400, stale-if-error=86400")
|
||||
w.Header().Add("CDN-Cache-Control", "max-age=604800")
|
||||
w.Header().Add("Content-Type", "text/plain")
|
||||
}
|
||||
@@ -13,6 +13,8 @@ func main() {
|
||||
dir := flag.String("d", "./dist", "the directory to write the files")
|
||||
staticDir := flag.String("s", "./static", "the directory to copy static files from")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
w := internals.StaticWriter{
|
||||
DistDir: dir,
|
||||
StaticDir: staticDir,
|
||||
|
||||
@@ -24,6 +24,8 @@ func main() {
|
||||
staticDir := flag.String("s", "./static", "the directory to copy static files from")
|
||||
port := flag.Int("p", 8080, "the port to run the server")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
configFile, err := os.ReadFile(*configPath)
|
||||
if err != nil {
|
||||
logger.Fatalf("Unable to read vercel.json file due to:\n%s", err)
|
||||
|
||||
49
components/blog.templ
Normal file
@@ -0,0 +1,49 @@
|
||||
package components
|
||||
|
||||
import "strings"
|
||||
|
||||
type Blog struct {
|
||||
Title string
|
||||
Summary string
|
||||
Link templ.SafeURL
|
||||
}
|
||||
|
||||
templ BlogSummary(entry Blog) {
|
||||
<article
|
||||
aria-labelledby={ "blog-entry-" + strings.ReplaceAll(entry.Title, " ", "-") }
|
||||
>
|
||||
<h3
|
||||
id={ "blog-entry-" + strings.ReplaceAll(entry.Title, " ", "-") }
|
||||
class="font-cal text-xl"
|
||||
>
|
||||
{ entry.Title }
|
||||
</h3>
|
||||
<div class="relative w-fit h-fit">
|
||||
<p class="line-clamp-3 text-justify text-light-gray">
|
||||
{ entry.Summary }
|
||||
</p>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="h-0 w-0 pointer-events-none bg-transparent! contrast-more:hidden"
|
||||
>
|
||||
<div
|
||||
class={ "absolute left-0 top-0 h-100% w-100% " +
|
||||
"bg-transparent bg-gradient-to-t from-black/50" }
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
class={ "transition-2s transition-all text-gray hover:text-light-gray no-underline " +
|
||||
"hover:underline transform-gpu hover:-translate-y-0.2 " +
|
||||
"contrast-more:text-light-gray contrast-more:hover:text-white" }
|
||||
href={ entry.Link }
|
||||
>
|
||||
Read all
|
||||
<span
|
||||
class="w-3 h-3 i-solar:arrow-right-up-line-duotone inline-block"
|
||||
></span>
|
||||
</a>
|
||||
</div>
|
||||
</article>
|
||||
}
|
||||
29
components/image.templ
Normal file
@@ -0,0 +1,29 @@
|
||||
package components
|
||||
|
||||
import "net/url"
|
||||
|
||||
templ Image(src templ.SafeURL, alt string, class string) {
|
||||
<picture class={ class }>
|
||||
<source
|
||||
media="(min-width: 1536px)"
|
||||
srcset={ "/api/image?threshold=1536&url=" + url.PathEscape(string(src)) }
|
||||
/>
|
||||
<source
|
||||
media="(min-width: 1280px)"
|
||||
srcset={ "/api/image?threshold=1280&url=" + url.PathEscape(string(src)) }
|
||||
/>
|
||||
<source
|
||||
media="(min-width: 1024px)"
|
||||
srcset={ "/api/image?threshold=1024&url=" + url.PathEscape(string(src)) }
|
||||
/>
|
||||
<source
|
||||
media="(min-width: 768px)"
|
||||
srcset={ "/api/image?threshold=768&url=" + url.PathEscape(string(src)) }
|
||||
/>
|
||||
<source
|
||||
media="(min-width: 640px)"
|
||||
srcset={ "/api/image?threshold=640&url=" + url.PathEscape(string(src)) }
|
||||
/>
|
||||
<img src={ string(src) } alt={ alt } class="w-100% h-100%"/>
|
||||
</picture>
|
||||
}
|
||||
89
components/nav.templ
Normal file
@@ -0,0 +1,89 @@
|
||||
package components
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Link struct {
|
||||
Text string
|
||||
Link templ.SafeURL
|
||||
}
|
||||
|
||||
templ Nav(links []Link) {
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="h-0 w-0 pointer-events-none bg-transparent!"
|
||||
>
|
||||
<div
|
||||
class="fixed left-0 top-0 w-screen z-100"
|
||||
>
|
||||
<div class="h-4rem bg-black z-100"></div>
|
||||
<div class="h-10vh bg-transparent bg-gradient-to-b from-black z-100"></div>
|
||||
</div>
|
||||
</div>
|
||||
<section
|
||||
class="flex flex-row justify-between fixed top-0 font-cal w-90% lg:w-80% xl:w-90% z-110"
|
||||
>
|
||||
<p
|
||||
class="text-gray contrast-more:text-light-gray cannot-hover md:block!"
|
||||
>
|
||||
Gustavo "Guz" L. de Mello
|
||||
</p>
|
||||
<p
|
||||
class="text-gray contrast-more:text-light-gray can-hover md:hidden"
|
||||
>
|
||||
Guz
|
||||
</p>
|
||||
<nav class="can-hover">
|
||||
<ul class="flex flex-row gap-3 list-none">
|
||||
for _, i := range links {
|
||||
<li class="transform-gpu hover:-translate-y-0.2 transition-transform">
|
||||
<a
|
||||
class={ "text-gray contrast-more:text-light-gray hover:text-white " +
|
||||
"no-underline hover:underline transition-color transition-1s" }
|
||||
id={ fmt.Sprintf("nav-anchor-%s", i.Link) }
|
||||
href={ i.Link }
|
||||
>
|
||||
{ i.Text }
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</nav>
|
||||
</section>
|
||||
<button
|
||||
class={ "block p-0.3 bg-black/97 b-0 m-0 outline-0 shadow-2xl " +
|
||||
"fixed bottom-5 right-5 text-gray z-100 cannot-hover" }
|
||||
popovertarget="nav-popover"
|
||||
>
|
||||
<span class="i-solar:hamburger-menu-broken w-2rem h-2rem block">Menu</span>
|
||||
</button>
|
||||
<nav
|
||||
class={ "fixed pb-10 p-5 m-0 b-0 h-100vh bg-black/97 shadow-black shadow-2xl z-10 " +
|
||||
"animate slide-from-r fade-in overflow-hidden cannot-hover" }
|
||||
style="inset: unset; bottom: 0; right: 0; --anim-duration: 300ms; --anim-slide-from-x: 50%;"
|
||||
id="nav-popover"
|
||||
popover
|
||||
>
|
||||
<div class="text-right h-100% w-100% flex flex-col-reverse">
|
||||
<ul class="flex flex-col h-fit gap-3 font-cal text-xl pl-0 text-gray list-none">
|
||||
for _, i := range links {
|
||||
<li
|
||||
class={ "hover:text-white transform-gpu hover:-translate-y-0.2 " +
|
||||
"transition-transform after:content-['@'] " +
|
||||
"after:pl-4 after:i-solar:posts-carousel-vertical-line-duotone" }
|
||||
>
|
||||
<a
|
||||
class={ "text-gray hover:text-white no-underline " +
|
||||
"hover:underline transition-color transition-1s" }
|
||||
id={ fmt.Sprintf("nav-anchor-touch-%s", i.Link) }
|
||||
href={ i.Link }
|
||||
>
|
||||
{ i.Text }
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
}
|
||||
77
components/project_card.templ
Normal file
@@ -0,0 +1,77 @@
|
||||
package components
|
||||
|
||||
import "strings"
|
||||
import "slices"
|
||||
import "cmp"
|
||||
|
||||
type Project struct {
|
||||
Name string
|
||||
Summary string
|
||||
Image templ.SafeURL
|
||||
Link templ.SafeURL
|
||||
Icon string
|
||||
WIP bool
|
||||
Current bool
|
||||
Language string
|
||||
}
|
||||
|
||||
func SortProjects(projects []Project) []Project {
|
||||
slices.SortFunc(projects, func(a, b Project) int {
|
||||
if (a.Current && !b.Current) || (a.WIP && !b.WIP) {
|
||||
return -1
|
||||
}
|
||||
return cmp.Compare(a.Name, b.Name)
|
||||
})
|
||||
return projects
|
||||
}
|
||||
|
||||
templ ProjectCard(project Project) {
|
||||
<article
|
||||
class={ "bg-dark-gray relative h-100% test:m-1 @container/projectcard-size " +
|
||||
"border-white forced-colors:border-3 forced-colors:border-solid" }
|
||||
aria-labelledby={ "project-" + strings.ReplaceAll(project.Name, " ", "-") }
|
||||
>
|
||||
<div class="hidden @[h:12rem]/projectcard:block max-h-50% overflow-hidden relative">
|
||||
<picture class="h-100% flex items-center -translate-y-25%">
|
||||
<img class="h-auto w-100% self-center" src={ string(project.Image) } alt=""/>
|
||||
</picture>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="w-100% h-100% absolute top-0 bg-gradient-to-t from-dark-gray translate-y-1%"
|
||||
></div>
|
||||
</div>
|
||||
<div class="px-10 py-5 flex gap-5">
|
||||
<div class="hidden @[w:24rem]/projectcard:flex items-center justify-center forced-colors:hidden">
|
||||
<div class={ "w-12 h-12 bg-light-gray text-0 " + project.Icon }>Icon</div>
|
||||
</div>
|
||||
<div>
|
||||
<hgroup class="flex items-center justify-between">
|
||||
<h3
|
||||
id={ "project-" + project.Name }
|
||||
class="font-cal text-xl m-0"
|
||||
>
|
||||
{ project.Name }
|
||||
</h3>
|
||||
<p
|
||||
aria-label="Status"
|
||||
class="top-0 right-0 m-0 text-xs"
|
||||
>
|
||||
if project.Current {
|
||||
<span class="bg-mauve text-dark-gray rounded-xl px-2">Current</span>
|
||||
}
|
||||
if project.WIP {
|
||||
<span class="bg-yellow text-dark-gray rounded-xl px-2">
|
||||
<abbr class="decoration-none" title="Work In Progress">WIP</abbr>
|
||||
</span>
|
||||
}
|
||||
</p>
|
||||
</hgroup>
|
||||
<p
|
||||
class="m-0 text-sm text-gray contrast-more:text-light-gray text-justify line-clamp-2"
|
||||
>
|
||||
{ project.Summary }
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
}
|
||||
120
config/routes.go
@@ -1,17 +1,133 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/a-h/templ"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
|
||||
"www/api"
|
||||
"www/components"
|
||||
"www/internals"
|
||||
"www/pages"
|
||||
)
|
||||
|
||||
var mockProjects = []components.Project{
|
||||
{
|
||||
Name: "rec-sh",
|
||||
Summary: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.",
|
||||
Link: templ.SafeURL("https://github.com/dot013/rec-sh"),
|
||||
Image: templ.SafeURL("https://images.unsplash.com/photo-1461749280684-dccba630e2f6?q=80&w=2669&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"),
|
||||
Icon: "i-solar:programming-bold",
|
||||
WIP: false,
|
||||
Current: false,
|
||||
Language: "bash",
|
||||
},
|
||||
{
|
||||
Name: ".mdparser",
|
||||
Summary: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.",
|
||||
Link: templ.SafeURL("https://github.com/dot013/rec-sh"),
|
||||
Image: templ.SafeURL("https://images.unsplash.com/photo-1560697024-fd4affa63094?q=80&w=2630&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"),
|
||||
Icon: "i-simple-icons:rust",
|
||||
WIP: true,
|
||||
Current: false,
|
||||
Language: "rust",
|
||||
},
|
||||
{
|
||||
Name: ".www",
|
||||
Summary: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.",
|
||||
Link: templ.SafeURL("https://github.com/dot013/.www"),
|
||||
Image: templ.SafeURL("https://images.unsplash.com/photo-1461749280684-dccba630e2f6?q=80&w=2669&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"),
|
||||
Icon: "i-simple-icons:go",
|
||||
WIP: true,
|
||||
Current: true,
|
||||
Language: "golang",
|
||||
},
|
||||
{
|
||||
Name: "Project",
|
||||
Summary: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.",
|
||||
Link: templ.SafeURL("https://github.com/dot013/.www"),
|
||||
Image: templ.SafeURL("https://images.unsplash.com/photo-1461749280684-dccba630e2f6?q=80&w=2669&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"),
|
||||
Icon: "i-solar:box-bold-duotone",
|
||||
WIP: false,
|
||||
Current: false,
|
||||
Language: "nix",
|
||||
},
|
||||
{
|
||||
Name: "Project",
|
||||
Summary: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.",
|
||||
Link: templ.SafeURL("https://github.com/dot013/.www"),
|
||||
Image: templ.SafeURL("https://images.unsplash.com/photo-1461749280684-dccba630e2f6?q=80&w=2669&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"),
|
||||
Icon: "i-solar:box-bold-duotone",
|
||||
WIP: false,
|
||||
Current: false,
|
||||
Language: "nix",
|
||||
},
|
||||
}
|
||||
|
||||
var mockBlog = []components.Blog{
|
||||
{
|
||||
Title: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim.",
|
||||
Summary: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint " +
|
||||
"cillum sint consectetur cupidatat Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.",
|
||||
Link: templ.URL("/001"),
|
||||
},
|
||||
{
|
||||
Title: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim.",
|
||||
Summary: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint " +
|
||||
"cillum sint consectetur cupidatat Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.",
|
||||
Link: templ.URL("/001"),
|
||||
},
|
||||
{
|
||||
Title: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim.",
|
||||
Summary: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint " +
|
||||
"cillum sint consectetur cupidatat Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.",
|
||||
Link: templ.URL("/001"),
|
||||
},
|
||||
{
|
||||
Title: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim.",
|
||||
Summary: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint " +
|
||||
"cillum sint consectetur cupidatat Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.",
|
||||
Link: templ.URL("/001"),
|
||||
},
|
||||
{
|
||||
Title: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim.",
|
||||
Summary: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint " +
|
||||
"cillum sint consectetur cupidatat Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.",
|
||||
Link: templ.URL("/001"),
|
||||
},
|
||||
{
|
||||
Title: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim.",
|
||||
Summary: "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint " +
|
||||
"cillum sint consectetur cupidatat Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.",
|
||||
Link: templ.URL("/001"),
|
||||
},
|
||||
}
|
||||
|
||||
var images = []string{
|
||||
"/images/image-1.png",
|
||||
"/images/image-2.png",
|
||||
"/images/image-3.png",
|
||||
"/images/image-4.png",
|
||||
"/images/image-5.png",
|
||||
"/images/image-6.png",
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Shuffle(len(images), func(i, j int) {
|
||||
images[i], images[j] = images[j], images[i]
|
||||
})
|
||||
}
|
||||
|
||||
var ROUTES = []internals.Page{
|
||||
{Path: "index.html", Component: pages.Homepage()},
|
||||
{Path: "index.html", Component: pages.Homepage(pages.HomepageProps{
|
||||
Projects: mockProjects,
|
||||
Images: []string{},
|
||||
Blogs: mockBlog,
|
||||
})},
|
||||
}
|
||||
|
||||
func APIROUTES(mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/hello", api.Hello)
|
||||
mux.HandleFunc("/api/image", api.Image)
|
||||
mux.HandleFunc("/robots.txt", api.RobotsTxt)
|
||||
mux.HandleFunc("/ai.txt", api.AiTxt)
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
{
|
||||
devShells.default = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
air
|
||||
go
|
||||
golangci-lint
|
||||
templ
|
||||
|
||||
19
go.mod
@@ -2,4 +2,21 @@ module www
|
||||
|
||||
go 1.22.2
|
||||
|
||||
require github.com/a-h/templ v0.2.697
|
||||
require (
|
||||
github.com/a-h/templ v0.2.697
|
||||
github.com/chai2010/webp v1.1.1
|
||||
github.com/sunshineplan/imgconv v1.1.10
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/hhrutter/lzw v1.0.0 // indirect
|
||||
github.com/hhrutter/tiff v1.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/pdfcpu/pdfcpu v0.8.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/sunshineplan/pdf v1.0.7 // indirect
|
||||
golang.org/x/image v0.17.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
27
go.sum
@@ -1,4 +1,31 @@
|
||||
github.com/a-h/templ v0.2.697 h1:OILxtWvD0NRJaoCOiZCopRDPW8paroKlGsrAiHLykNE=
|
||||
github.com/a-h/templ v0.2.697/go.mod h1:5cqsugkq9IerRNucNsI4DEamdHPsoGMQy99DzydLhM8=
|
||||
github.com/chai2010/webp v1.1.1 h1:jTRmEccAJ4MGrhFOrPMpNGIJ/eybIgwKpcACsrTEapk=
|
||||
github.com/chai2010/webp v1.1.1/go.mod h1:0XVwvZWdjjdxpUEIf7b9g9VkHFnInUSYujwqTLEuldU=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/hhrutter/lzw v1.0.0 h1:laL89Llp86W3rRs83LvKbwYRx6INE8gDn0XNb1oXtm0=
|
||||
github.com/hhrutter/lzw v1.0.0/go.mod h1:2HC6DJSn/n6iAZfgM3Pg+cP1KxeWc3ezG8bBqW5+WEo=
|
||||
github.com/hhrutter/tiff v1.0.1 h1:MIus8caHU5U6823gx7C6jrfoEvfSTGtEFRiM8/LOzC0=
|
||||
github.com/hhrutter/tiff v1.0.1/go.mod h1:zU/dNgDm0cMIa8y8YwcYBeuEEveI4B0owqHyiPpJPHc=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/pdfcpu/pdfcpu v0.8.0 h1:SuEB4uVsPFz1nb802r38YpFpj9TtZh/oB0bGG34IRZw=
|
||||
github.com/pdfcpu/pdfcpu v0.8.0/go.mod h1:jj03y/KKrwigt5xCi8t7px2mATcKuOzkIOoCX62yMho=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/sunshineplan/imgconv v1.1.10 h1:EJZVXLwmvmKgEA1KIJpNSzSssjGaZMdtOLycGFyzxQA=
|
||||
github.com/sunshineplan/imgconv v1.1.10/go.mod h1:de9NsLFCMW2JVom3mjRZu3GceLFwkEIEkf1EGS5rDX4=
|
||||
github.com/sunshineplan/pdf v1.0.7 h1:62xlc079jh4tGLDjiihyyhwVFkn0IsxLyDpHplbG9Ew=
|
||||
github.com/sunshineplan/pdf v1.0.7/go.mod h1:QsEmZCWBE3uFK8PCrM0pua1WDWLNU77YusiDEcY56OQ=
|
||||
golang.org/x/image v0.17.0 h1:nTRVVdajgB8zCMZVsViyzhnMKPwYeroEERRC64JuLco=
|
||||
golang.org/x/image v0.17.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
|
||||
20
internals/helpers.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package internals
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func HttpErrorHelper(w http.ResponseWriter) func(msg string, err error, status int) bool {
|
||||
return func(msg string, err error, status int) bool {
|
||||
if err != nil {
|
||||
w.WriteHeader(status)
|
||||
_, err = w.Write([]byte(msg + "\n Error: " + err.Error()))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
_, _ = w.Write([]byte("Error trying to return error code (somehow):\n" + err.Error()))
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
34
internals/middleware.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package internals
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Middleware struct {
|
||||
handler http.Handler
|
||||
dev bool
|
||||
noCache bool
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func (m *Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
m.logger.Printf("Handling request. path=%s", r.URL.Path)
|
||||
|
||||
if m.dev {
|
||||
r.URL.Scheme = "http"
|
||||
} else {
|
||||
r.URL.Scheme = "https"
|
||||
}
|
||||
|
||||
m.handler.ServeHTTP(w, r)
|
||||
|
||||
if m.noCache {
|
||||
w.Header().Del("Cache-Control")
|
||||
w.Header().Add("Cache-Control", "max-age=0")
|
||||
}
|
||||
}
|
||||
|
||||
func NewMiddleware(handler http.Handler, dev bool, noCache bool, logger *log.Logger) *Middleware {
|
||||
return &Middleware{handler, dev, noCache, logger}
|
||||
}
|
||||
@@ -1,26 +1,26 @@
|
||||
package layouts
|
||||
|
||||
templ Page(title string) {
|
||||
<html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US" class="scroll-smooth motion-reduce:scroll-auto">
|
||||
<head>
|
||||
<!-- TODO: improve a11y for zoomed states -->
|
||||
<meta
|
||||
name="viewport"
|
||||
content={ "width=device-width, " +
|
||||
"initial-scale=1.0, " +
|
||||
"maximum-scale=1.0, " +
|
||||
"user-scalable=no" }
|
||||
/>
|
||||
<link rel="stylesheet" href="/uno.css"/>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: Inter;
|
||||
src: url(inter.woff2);
|
||||
}
|
||||
@font-face {
|
||||
font-family: Cal Sans;
|
||||
src: url(cal-sans.woff2);
|
||||
}
|
||||
@font-face {
|
||||
font-family: Fira Code;
|
||||
src: url(fira-code.woff2);
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/global.css"/>
|
||||
<title>{ title }</title>
|
||||
</head>
|
||||
<body class="bg-black flex flex-col justify-center items-center w-screen h-screen overflow-hidden text-white font-sans">
|
||||
<body
|
||||
class={ "flex flex-col justify-center items-center " +
|
||||
"w-screen overflow-x-hidden text-white bg-black font-sans m-0" }
|
||||
style="--anim-slide-from-y: 10px; --anim-delay: 120ms; --anim-duration: 0.6s;"
|
||||
>
|
||||
{ children... }
|
||||
</body>
|
||||
</html>
|
||||
|
||||
16
main.go
@@ -17,6 +17,14 @@ var logger = log.Default()
|
||||
func main() {
|
||||
staticDir := flag.String("s", "./static", "the directory to copy static files from")
|
||||
port := flag.Int("p", 8080, "the port to run the server")
|
||||
dev := flag.Bool("d", false, "if the server is in development mode")
|
||||
cache := flag.Bool("c", true, "if the static files are cached")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if *dev {
|
||||
log.Printf("Running server in DEVELOPMENT MODE")
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
|
||||
@@ -29,8 +37,6 @@ func main() {
|
||||
logger.Printf("Registering page route. page=%s route=%s", route.Path, path)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
logger.Printf("Handling request. path=%s", r.URL.Path)
|
||||
|
||||
w.Header().Add("Content-Type", "text/html")
|
||||
|
||||
err := route.Component.Render(r.Context(), w)
|
||||
@@ -46,8 +52,6 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
logger.Printf("Handling request. path=%s", r.URL.Path)
|
||||
|
||||
w.Header().Add("Content-Type", "text/html")
|
||||
|
||||
index := slices.IndexFunc(config.ROUTES, func(route internals.Page) bool {
|
||||
@@ -62,7 +66,9 @@ func main() {
|
||||
})
|
||||
|
||||
logger.Printf("Running server at port: %v", *port)
|
||||
err := http.ListenAndServe(fmt.Sprintf(":%v", *port), mux)
|
||||
|
||||
middleware := internals.NewMiddleware(mux, *dev, !*cache, log.Default())
|
||||
err := http.ListenAndServe(fmt.Sprintf(":%v", *port), middleware)
|
||||
if err != nil {
|
||||
logger.Fatalf("Server crashed due to:\n%s", err)
|
||||
}
|
||||
|
||||
87
makefile
@@ -1,52 +1,47 @@
|
||||
PORT?=8080
|
||||
|
||||
all: run
|
||||
build: templ
|
||||
pnpm unocss
|
||||
go build -o bin/www
|
||||
|
||||
build/static: templ
|
||||
pnpm unocss
|
||||
go run ./cmd/build
|
||||
|
||||
dev/templ:
|
||||
templ generate --watch \
|
||||
--proxy=http://localhost:$(PORT) \
|
||||
--open-browser=false
|
||||
|
||||
dev/server:
|
||||
go run github.com/air-verse/air@v1.52.2 \
|
||||
--build.cmd "go build -o tmp/bin/main" \
|
||||
--build.bin "tmp/bin/main" \
|
||||
--build.exclude_dir "node_modules" \
|
||||
--build.include_ext "go" \
|
||||
--build.stop_on_error "false" \
|
||||
--misc.clean_on_exit true \
|
||||
-- -p $(PORT) -d
|
||||
|
||||
dev/unocss:
|
||||
pnpm unocss -w
|
||||
|
||||
dev/sync_assets:
|
||||
go run github.com/air-verse/air@v1.52.2 \
|
||||
--build.cmd "templ generate --notify-proxy" \
|
||||
--build.bin "true" \
|
||||
--build.delay "100" \
|
||||
--build.exclude_dir "" \
|
||||
--build.include_dir "static" \
|
||||
--build.include_ext "js,css"
|
||||
|
||||
dev:
|
||||
pnpm unocss -w &
|
||||
air -build.pre_cmd 'make templ' \
|
||||
-build.include_ext 'templ' \
|
||||
-build.include_ext 'css' \
|
||||
-proxy.enabled true \
|
||||
-proxy.app_port $(PORT) \
|
||||
-proxy.proxy_port $$(($(PORT) + 1)) \
|
||||
-- -p $(PORT)
|
||||
make -j4 dev/templ dev/server dev/unocss dev/sync_assets
|
||||
|
||||
dev-vercel:
|
||||
air -build.pre_cmd 'make build-vercel' \
|
||||
-build.include_ext 'templ' \
|
||||
-build.cmd 'make build-vercel' \
|
||||
-build.bin './bin/vercel' \
|
||||
-proxy.enabled true \
|
||||
-proxy.app_port $(PORT) \
|
||||
-proxy.proxy_port $$(($(PORT) + 1)) \
|
||||
-- -p $(PORT)
|
||||
|
||||
run: bin/www
|
||||
run: build
|
||||
./bin/www
|
||||
|
||||
run-vercel: bin/vercel
|
||||
./bin/vercel
|
||||
|
||||
build-static: templ
|
||||
pnpm unocss
|
||||
go run ./cmd/build/main.go
|
||||
|
||||
build-vercel: bin/vercel build-static
|
||||
|
||||
bin/www: main.go templ
|
||||
go build -o ./bin/www ./main.go
|
||||
|
||||
bin/vercel: cmd/vercel/main.go templ
|
||||
go build -o ./bin/vercel ./cmd/vercel/main.go
|
||||
|
||||
# For some reason "templ generate" does not detect the files, so this is a
|
||||
# workaround.
|
||||
TEMPL_FILES=$(patsubst %.templ, %_templ.go, $(wildcard **/*.templ))
|
||||
templ: $(TEMPL_FILES)
|
||||
@echo Generating templ files
|
||||
%_templ.go: %.templ
|
||||
templ generate -f $^ > /dev/null
|
||||
all: build
|
||||
|
||||
clean:
|
||||
if [[ -d "dist" ]]; then rm -r ./dist; fi
|
||||
@@ -54,3 +49,11 @@ clean:
|
||||
if [[ -d "bin" ]]; then rm -r ./bin; fi
|
||||
rm ./static/uno.css
|
||||
rm $(TEMPL_FILES)
|
||||
|
||||
# For some reason "templ generate" does not detect the files in CI,
|
||||
# so this is a workaround.
|
||||
TEMPL_FILES=$(patsubst %.templ, %_templ.go, $(wildcard **/*.templ))
|
||||
templ: $(TEMPL_FILES)
|
||||
@echo Generating templ files
|
||||
%_templ.go: %.templ
|
||||
templ generate -f $^ > /dev/null
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
"name": "www",
|
||||
"version": "0.0.1",
|
||||
"devDependencies": {
|
||||
"@iconify-json/simple-icons": "^1.1.102",
|
||||
"@iconify-json/simple-icons": "^1.1.103",
|
||||
"@iconify-json/solar": "^1.1.9",
|
||||
"@types/node": "^20.12.12",
|
||||
"@unocss/cli": "^0.60.3",
|
||||
"@unocss/core": "^0.60.4",
|
||||
"@unocss/preset-mini": "^0.60.4",
|
||||
"unocss": "^0.60.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,88 +1,378 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"www/layouts"
|
||||
"www/components"
|
||||
)
|
||||
|
||||
templ Homepage() {
|
||||
type HomepageProps struct {
|
||||
Projects []components.Project
|
||||
Blogs []components.Blog
|
||||
Images []string
|
||||
}
|
||||
|
||||
templ Homepage(props HomepageProps) {
|
||||
@layouts.Page("013") {
|
||||
<main>
|
||||
<img src="/logo-013.svg" alt="" width="100" height="100"/>
|
||||
<h1 class="font-cal">Someone who's trying to improve</h1>
|
||||
<div class="text-#181818 flex flex-row justify-between items-center">
|
||||
<nav>
|
||||
<ul class="list-none flex flex-row gap-3 p-0">
|
||||
<li class="i-simple-icons:github w-4 hover:text-#ababab transition-colors">
|
||||
@components.Nav([]components.Link{
|
||||
{Text: "about", Link: templ.SafeURL("#about")},
|
||||
{Text: "projects", Link: templ.SafeURL("#projects")},
|
||||
// {Text: "gallery", Link: templ.SafeURL("#gallery")},
|
||||
{Text: "blog", Link: templ.SafeURL("#blog")},
|
||||
{Text: "contact", Link: templ.SafeURL("#contact")},
|
||||
})
|
||||
<section
|
||||
id="homepage"
|
||||
class={ "w-screen h-screen overflow-x-hidden overflow-y-scroll scroll-smooth motion-reduce:scroll-auto " +
|
||||
"snap-y scrollbar thumb-gray contrast-more:thumb-light-gray track-black" }
|
||||
>
|
||||
<header
|
||||
class="h-screen w-screen flex justify-center items-center snap-start"
|
||||
id="about"
|
||||
>
|
||||
<div class="flex flex-col lg:flex-row lg:justify-between lg:gap-5rem w-90% lg:w-80% xl:w-60%">
|
||||
<div class="w-50% xl:w-25%">
|
||||
<img
|
||||
src="/logo-013.svg"
|
||||
class="animate slide-from-b fade-in"
|
||||
style="--anim-stagger: 1; opacity: 0;"
|
||||
alt="013 Logo"
|
||||
/>
|
||||
</div>
|
||||
<h1
|
||||
class={ "w-full lg:max-w-45rem mb-0 lg:mt-0 prose text-2.9rem lg:text-6xl xl:text-4.3rem " +
|
||||
"animate slide-from-b fade-in" }
|
||||
style="--anim-stagger: 2; opacity: 0;"
|
||||
>
|
||||
Someone who's trying to improve
|
||||
</h1>
|
||||
</div>
|
||||
</header>
|
||||
<main
|
||||
aria-labelledby="about-header"
|
||||
class="w-screen h-50vh lg:h-60vh xl:h-50vh flex justify-center items-center"
|
||||
>
|
||||
<div class="w-90% xl:w-50% lg:text-xl -translate-y-20% xl:-translate-y-45% text-justify snap-center">
|
||||
<h2 id="about-header" class="opacity-0">About</h2>
|
||||
<p class="animate slide-from-b fade-in" style="--anim-stagger: 4; opacity: 0;">
|
||||
Lorem ipsum dolor sit amet, officia excepteur ex fugiat
|
||||
reprehenderit enim labore culpa sint ad nisi Lorem pariatur mollit ex
|
||||
esse exercitation amet. Nisi anim cupidatat excepteur officia.
|
||||
Reprehenderit nostrud nostrud ipsum Lorem est aliquip amet voluptate
|
||||
voluptate dolor minim nulla est proident. Nostrud officia pariatur ut
|
||||
officia. Sit irure elit esse ea nulla sunt ex occaecat reprehenderit
|
||||
commodo officia dolor Lorem duis laboris cupidatat officia voluptate.
|
||||
Culpa proident adipisicing id nulla nisi laboris ex in Lorem sunt duis
|
||||
officia eiusmod. Aliqua reprehenderit commodo ex non excepteur duis
|
||||
sunt velit enim. Voluptate laboris sint cupidatat ullamco ut ea
|
||||
consectetur et est culpa et culpa duis.
|
||||
</p>
|
||||
<p class="animate slide-from-b fade-in" style="--anim-stagger: 5; opacity: 0;">
|
||||
Lorem ipsum dolor sit amet, officia excepteur ex fugiat
|
||||
reprehenderit enim labore culpa sint ad nisi Lorem pariatur mollit ex
|
||||
esse exercitation amet. Nisi anim cupidatat excepteur officia.
|
||||
Reprehenderit nostrud nostrud ipsum Lorem est aliquip amet voluptate
|
||||
voluptate dolor minim nulla est proident. Nostrud officia pariatur ut
|
||||
officia. Sit irure elit esse ea nulla sunt ex occaecat reprehenderit
|
||||
commodo officia dolor Lorem duis laboris cupidatat officia voluptate.
|
||||
Culpa proident adipisicing id nulla nisi laboris ex in Lorem sunt duis
|
||||
officia eiusmod. Aliqua reprehenderit commodo ex non excepteur duis
|
||||
sunt velit enim. Voluptate laboris sint cupidatat ullamco ut ea
|
||||
consectetur et est culpa et culpa duis.
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
<section
|
||||
aria-labelledby="projects-header"
|
||||
id="projects"
|
||||
class="w-screen h-screen flex justify-center items-center"
|
||||
>
|
||||
<div class="w-90% xl:w-50% snap-center">
|
||||
<hgroup class="flex justify-between my-5">
|
||||
<h2 id="projects-header" class="font-cal text-5xl m-0">Projects.</h2>
|
||||
<p class="m-0">
|
||||
<a
|
||||
href="https://github.com/guz013"
|
||||
target="_blank"
|
||||
class="opacity-0"
|
||||
rel="noreferrer noopener"
|
||||
href="/projects"
|
||||
class="decoration-none text-light-gray flex items-center"
|
||||
>
|
||||
GitHub
|
||||
See more
|
||||
<span
|
||||
class="w-5 h-5 bg-light-gray i-solar:arrow-right-up-line-duotone inline-block"
|
||||
></span>
|
||||
</a>
|
||||
</p>
|
||||
</hgroup>
|
||||
<div class="grid grid-flow-row auto-rows-[minmax(6.7rem,_2fr)] md:grid-cols-2 gap-5">
|
||||
for i, project := range components.SortProjects(props.Projects) {
|
||||
if i == 0 {
|
||||
<div class="row-span-2">
|
||||
@components.ProjectCard(project)
|
||||
</div>
|
||||
} else if i < 3 {
|
||||
<div>
|
||||
@components.ProjectCard(project)
|
||||
</div>
|
||||
} else {
|
||||
<div class="hidden md:block">
|
||||
@components.ProjectCard(project)
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- <section
|
||||
aria-labelledby="gallery-header"
|
||||
id="gallery"
|
||||
class="w-screen min-h-screen flex justify-center items-center"
|
||||
>
|
||||
<div class="w-90% xl:w-50% max-h-60% snap-start">
|
||||
<hgroup class="flex justify-between my-5">
|
||||
<h2 id="gallery-header" class="font-cal text-5xl m-0">Gallery.</h2>
|
||||
<p class="m-0">
|
||||
<a
|
||||
href="/gallery"
|
||||
class="decoration-none text-light-gray flex items-center"
|
||||
>
|
||||
See more
|
||||
<span
|
||||
class="w-5 h-5 bg-light-gray i-solar:arrow-right-up-line-duotone inline-block"
|
||||
></span>
|
||||
</a>
|
||||
</p>
|
||||
</hgroup>
|
||||
<div class="flex flex-wrap flex-col w-100% max-h-65vh md:max-h-70vh overflow-hidden">
|
||||
for _, img := range props.Images {
|
||||
<div class="w-50% md:w-33.3%">
|
||||
@components.Image(templ.SafeURL(img), "", "block max-w-100%")
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</section> -->
|
||||
<section
|
||||
aria-labelledby="blog-header"
|
||||
id="blog"
|
||||
class="w-screen min-h-screen flex justify-center items-center"
|
||||
>
|
||||
<div class="w-90% xl:w-50% max-h-60% snap-center">
|
||||
<hgroup class="flex justify-between my-5">
|
||||
<h2 id="blog-header" class="font-cal text-5xl m-0">Blog.</h2>
|
||||
<p class="m-0">
|
||||
<a
|
||||
href="/blog"
|
||||
class="decoration-none text-light-gray flex items-center"
|
||||
>
|
||||
See more
|
||||
<span
|
||||
class="w-5 h-5 bg-light-gray i-solar:arrow-right-up-line-duotone inline-block"
|
||||
></span>
|
||||
</a>
|
||||
</p>
|
||||
</hgroup>
|
||||
<div
|
||||
class={ "w-100% max-h-65vh md:max-h-70vh overflow-hidden " +
|
||||
"md:grid grid-cols-2 gap-4" }
|
||||
>
|
||||
for i, blog := range props.Blogs {
|
||||
if i < 2 {
|
||||
<div class="">
|
||||
@components.BlogSummary(blog)
|
||||
</div>
|
||||
} else if i < 4 {
|
||||
<div class="hidden md:block">
|
||||
@components.BlogSummary(blog)
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
aria-labelledby="contact-header"
|
||||
id="contact"
|
||||
class="w-screen min-h-screen flex justify-center items-center"
|
||||
>
|
||||
<div class="w-90% xl:w-50% max-h-60% snap-start">
|
||||
<hgroup class="flex justify-between my-5">
|
||||
<h2 id="contact-header" class="font-cal text-5xl m-0">Contact.</h2>
|
||||
</hgroup>
|
||||
<ul class="text-xl pl-0 grid grid-cols-2 md:grid-cols-4 list-none w-100%">
|
||||
<li>
|
||||
@contactList("Software") {
|
||||
@contactItem("i-simple-icons:github", "GitHub", "http://github.com/guz013")
|
||||
@contactItem("i-simple-icons:codeberg", "Codeberg", "http://codeberg.org/guz013")
|
||||
}
|
||||
</li>
|
||||
<li class="i-simple-icons:codeberg w-4 hover:text-#ababab transition-colors">
|
||||
<a
|
||||
href="https://codeberg.org/guz013"
|
||||
target="_blank"
|
||||
class="opacity-0"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
Codeberg
|
||||
</a>
|
||||
<li>
|
||||
@contactList("Social") {
|
||||
@contactItem("i-simple-icons:twitter", "Twitter", "http://twitter.com/guz013_")
|
||||
@contactItem("i-simple-icons:mastodon", "Mastodon", "http://mastodon.social/@guz013")
|
||||
}
|
||||
</li>
|
||||
<li class="i-simple-icons:twitter w-4 hover:text-#ababab transition-colors">
|
||||
<a
|
||||
href="https://twitter.com/guz013_"
|
||||
target="_blank"
|
||||
class="opacity-0"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
Twitter
|
||||
</a>
|
||||
<li>
|
||||
@contactList("Photography") {
|
||||
@contactItem("i-simple-icons:instagram", "Instagram", "http://instagram.com/guz013_")
|
||||
@contactItem("i-simple-icons:pixelfed", "Pixelfed", "http://pixelfed.social/guz013")
|
||||
}
|
||||
</li>
|
||||
<li class="i-simple-icons:mastodon w-4 hover:text-#ababab transition-colors">
|
||||
<a
|
||||
href="https://mastodon.social/@guz013"
|
||||
target="_blank"
|
||||
class="opacity-0"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
Mastodon
|
||||
</a>
|
||||
</li>
|
||||
<li class="i-simple-icons:instagram w-4 hover:text-#ababab transition-colors">
|
||||
<a
|
||||
href="https://instagram.com/guz013_"
|
||||
target="_blank"
|
||||
class="opacity-0"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
Instagram
|
||||
</a>
|
||||
</li>
|
||||
<li class="i-simple-icons:pixelfed w-4 hover:text-#ababab transition-colors">
|
||||
<a
|
||||
href="https://pixelfed.social/@guz013"
|
||||
target="_blank"
|
||||
class="opacity-0"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
Pixelfed
|
||||
</a>
|
||||
<li>
|
||||
@contactList("Art") {
|
||||
@contactItem("i-simple-icons:instagram", "Instagram", "http://instagram.com/guzsart")
|
||||
@contactItem("i-simple-icons:pixelfed", "Pixelfed", "http://pixelfed.social/guzsart")
|
||||
}
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<p class="m-0">
|
||||
<a class="text-#181818 hover:text-#ababab transition-colors" href="mailto:contact.guz013@gmail.com">
|
||||
2024 © Gustavo L. de Mello
|
||||
</a>
|
||||
</p>
|
||||
<div
|
||||
class="mt-3 md:mt-10"
|
||||
aria-labelledby="business-contact"
|
||||
>
|
||||
<h3
|
||||
class="text-gray contrast-more:text-white text-xl font-normal mb-0 inline-flex items-center gap-2"
|
||||
id="business-contact"
|
||||
>
|
||||
Business
|
||||
<a
|
||||
class={ "inline-flex items-center text-black text-sm p-0.5 px-2 rounded-lg no-underline " +
|
||||
"transition-all transition-2s bg-gray hover:bg-light-gray bg-gradient-to-t from-black/50 " +
|
||||
"contrast-more:bg-light-gray contrast-more:hover:bg-white contrast-more:from-black/0" }
|
||||
rel="noopener nofollow noreferrer"
|
||||
href="mailto:contact.guz013@gmail.com"
|
||||
>
|
||||
<span
|
||||
class="inline-block i-solar:hand-shake-bold-duotone w-4.5 h-4.5"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<span class="opacity-0">(</span>Open to hire!<span class="opacity-0">)</span>
|
||||
</a>
|
||||
</h3>
|
||||
<ul class="list-none pl-0 flex gap-2 md:gap-5 relative">
|
||||
<li>
|
||||
<a
|
||||
class={ "transition-all transition-2s text-light-gray hover:text-white " +
|
||||
"flex items-center gap-1 no-underline hover:underline" }
|
||||
target="_blank"
|
||||
rel="noopener nofollow noreferrer"
|
||||
href="mailto:contact.guz013@gmail.com"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="inline-block w-4.5 h-4.5 i-solar:mailbox-bold-duotone"
|
||||
></span>
|
||||
<span
|
||||
class="transform-gpu pl-4.5 -translate-x-4.5 hover:-translate-y-0.2 transition-transform"
|
||||
>
|
||||
contact.guz013@gmail.com
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
@contactItem("i-simple-icons:linkedin", "LinkedIn", "http://linkedin.com/in/guz013")
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="h-0 w-0 pointer-events-none bg-transparent! contrast-more:hidden"
|
||||
>
|
||||
<div
|
||||
class={ "absolute left-0 top-0 h-100% w-100% " +
|
||||
"bg-transparent bg-gradient-to-t from-black/50" }
|
||||
></div>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<footer
|
||||
aria-labelledby="footer-header"
|
||||
class="w-screen min-h-screen flex justify-center items-center"
|
||||
>
|
||||
<div
|
||||
class="w-90% xl:w-50% max-h-60% snap-start text-center"
|
||||
id="footer"
|
||||
>
|
||||
<h3 id="footer-header" class="opacity-0">Footer</h3>
|
||||
<p>Copyright © 2024 Gustavo "Guz" L. de Mello</p>
|
||||
<p class="text-sm text-gray contrast-more:text-light-gray" id="license">
|
||||
Unless otherwise noticed, contents of this website itself are licensed under
|
||||
the
|
||||
<a
|
||||
class={ "transition-all transition-2s text-gray hover:text-light-gray "+
|
||||
"contrast-more:text-light-gray contrart-more:hover:text-white "+
|
||||
"underline" }
|
||||
href="https://creativecommons.org/licenses/by-sa/4.0/"
|
||||
rel="noopener nofollow noreferrer"
|
||||
>
|
||||
Creative Commons Attribution-Share Alike 4.0 International ("CC BY-SA 4.0")
|
||||
</a>.
|
||||
Guz013, the 013 Logo, are trademarks of Gustavo L. de Mello. The underlyng
|
||||
source code used to format and display that content is, unless otherwise noticed,
|
||||
licensed under the
|
||||
<a
|
||||
class={ "transition-all transition-2s text-gray hover:text-light-gray "+
|
||||
"contrast-more:text-light-gray contrart-more:hover:text-white "+
|
||||
"underline" }
|
||||
href="https://www.mozilla.org/en-US/MPL/2.0/"
|
||||
rel="noopener nofollow noreferrer"
|
||||
>
|
||||
Mozilla Public License 2.0
|
||||
</a>.
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="h-0 w-0 pointer-events-none bg-transparent!"
|
||||
>
|
||||
<div
|
||||
class={ "fixed bottom-0 left-0 w-screen h-40vh md:h-20vh " +
|
||||
"bg-transparent bg-gradient-to-t from-black from-10%" }
|
||||
></div>
|
||||
</div>
|
||||
</main>
|
||||
<footer class="fixed bottom-0 text-xs font-mono ">
|
||||
<p><a class="text-#181818 hover:text-#ababab" href="https://dot013-www-guz013-guzsprojects.vercel.app">new website in development</a></p>
|
||||
</footer>
|
||||
</section>
|
||||
}
|
||||
}
|
||||
|
||||
templ contactList(label string) {
|
||||
<h3
|
||||
class="mb-2 text-gray contrast-more:text-white font-normal text-xl"
|
||||
id={ "contact-list-" + strings.ReplaceAll(label, " ", "-") }
|
||||
>{ label }</h3>
|
||||
<ul
|
||||
class="list-none pl-0 relative"
|
||||
aria-labelledby={ "contact-list-" + strings.ReplaceAll(label, " ", "-") }
|
||||
>
|
||||
{ children... }
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="h-0 w-0 pointer-events-none bg-transparent! contrast-more:hidden"
|
||||
>
|
||||
<div
|
||||
class={ "absolute left-0 top-0 h-100% w-100% " +
|
||||
"bg-transparent bg-gradient-to-t from-black/50" }
|
||||
></div>
|
||||
</div>
|
||||
</ul>
|
||||
}
|
||||
|
||||
templ contactItem(icon string, label string, url string) {
|
||||
<li>
|
||||
<a
|
||||
class={ "transition-all transition-2s text-light-gray hover:text-white " +
|
||||
"flex items-center gap-1 no-underline hover:underline" }
|
||||
target="_blank"
|
||||
rel="noopener nofollow noreferrer"
|
||||
href={ templ.URL(url) }
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class={ "inline-block w-4.5 h-4.5 " + icon }
|
||||
></span>
|
||||
<span
|
||||
class="transform-gpu pl-4.5 -translate-x-4.5 hover:-translate-y-0.2 transition-transform"
|
||||
>{ label }</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="inline-block i-solar:arrow-right-up-line-duotone w-4.5 h-4.5 -translate-x-4.5"
|
||||
></span>
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
|
||||
351
pnpm-lock.yaml
generated
@@ -6,8 +6,8 @@ settings:
|
||||
|
||||
devDependencies:
|
||||
'@iconify-json/simple-icons':
|
||||
specifier: ^1.1.102
|
||||
version: 1.1.102
|
||||
specifier: ^1.1.103
|
||||
version: 1.1.103
|
||||
'@iconify-json/solar':
|
||||
specifier: ^1.1.9
|
||||
version: 1.1.9
|
||||
@@ -17,6 +17,12 @@ devDependencies:
|
||||
'@unocss/cli':
|
||||
specifier: ^0.60.3
|
||||
version: 0.60.3
|
||||
'@unocss/core':
|
||||
specifier: ^0.60.4
|
||||
version: 0.60.4
|
||||
'@unocss/preset-mini':
|
||||
specifier: ^0.60.4
|
||||
version: 0.60.4
|
||||
unocss:
|
||||
specifier: ^0.60.3
|
||||
version: 0.60.3(postcss@8.4.38)(vite@5.2.11)
|
||||
@@ -42,33 +48,33 @@ packages:
|
||||
resolution: {integrity: sha512-rWQkqXRESdjXtc+7NRfK9lASQjpXJu1ayp7qi1d23zZorY+wBHVLHHoVcMsEnkqEBWTFqbztO7/QdJFzyEcLTg==}
|
||||
dev: true
|
||||
|
||||
/@babel/code-frame@7.24.2:
|
||||
resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==}
|
||||
/@babel/code-frame@7.24.6:
|
||||
resolution: {integrity: sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/highlight': 7.24.5
|
||||
'@babel/highlight': 7.24.6
|
||||
picocolors: 1.0.1
|
||||
dev: true
|
||||
|
||||
/@babel/compat-data@7.24.4:
|
||||
resolution: {integrity: sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==}
|
||||
/@babel/compat-data@7.24.6:
|
||||
resolution: {integrity: sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dev: true
|
||||
|
||||
/@babel/core@7.24.5:
|
||||
resolution: {integrity: sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==}
|
||||
/@babel/core@7.24.6:
|
||||
resolution: {integrity: sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@ampproject/remapping': 2.3.0
|
||||
'@babel/code-frame': 7.24.2
|
||||
'@babel/generator': 7.24.5
|
||||
'@babel/helper-compilation-targets': 7.23.6
|
||||
'@babel/helper-module-transforms': 7.24.5(@babel/core@7.24.5)
|
||||
'@babel/helpers': 7.24.5
|
||||
'@babel/parser': 7.24.5
|
||||
'@babel/template': 7.24.0
|
||||
'@babel/traverse': 7.24.5
|
||||
'@babel/types': 7.24.5
|
||||
'@babel/code-frame': 7.24.6
|
||||
'@babel/generator': 7.24.6
|
||||
'@babel/helper-compilation-targets': 7.24.6
|
||||
'@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6)
|
||||
'@babel/helpers': 7.24.6
|
||||
'@babel/parser': 7.24.6
|
||||
'@babel/template': 7.24.6
|
||||
'@babel/traverse': 7.24.6
|
||||
'@babel/types': 7.24.6
|
||||
convert-source-map: 2.0.0
|
||||
debug: 4.3.4
|
||||
gensync: 1.0.0-beta.2
|
||||
@@ -78,281 +84,278 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@babel/generator@7.24.5:
|
||||
resolution: {integrity: sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==}
|
||||
/@babel/generator@7.24.6:
|
||||
resolution: {integrity: sha512-S7m4eNa6YAPJRHmKsLHIDJhNAGNKoWNiWefz1MBbpnt8g9lvMDl1hir4P9bo/57bQEmuwEhnRU/AMWsD0G/Fbg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/types': 7.24.5
|
||||
'@babel/types': 7.24.6
|
||||
'@jridgewell/gen-mapping': 0.3.5
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
jsesc: 2.5.2
|
||||
dev: true
|
||||
|
||||
/@babel/helper-annotate-as-pure@7.22.5:
|
||||
resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==}
|
||||
/@babel/helper-annotate-as-pure@7.24.6:
|
||||
resolution: {integrity: sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/types': 7.24.5
|
||||
'@babel/types': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/helper-compilation-targets@7.23.6:
|
||||
resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==}
|
||||
/@babel/helper-compilation-targets@7.24.6:
|
||||
resolution: {integrity: sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/compat-data': 7.24.4
|
||||
'@babel/helper-validator-option': 7.23.5
|
||||
'@babel/compat-data': 7.24.6
|
||||
'@babel/helper-validator-option': 7.24.6
|
||||
browserslist: 4.23.0
|
||||
lru-cache: 5.1.1
|
||||
semver: 6.3.1
|
||||
dev: true
|
||||
|
||||
/@babel/helper-create-class-features-plugin@7.24.5(@babel/core@7.24.5):
|
||||
resolution: {integrity: sha512-uRc4Cv8UQWnE4NXlYTIIdM7wfFkOqlFztcC/gVXDKohKoVB3OyonfelUBaJzSwpBntZ2KYGF/9S7asCHsXwW6g==}
|
||||
/@babel/helper-create-class-features-plugin@7.24.6(@babel/core@7.24.6):
|
||||
resolution: {integrity: sha512-djsosdPJVZE6Vsw3kk7IPRWethP94WHGOhQTc67SNXE0ZzMhHgALw8iGmYS0TD1bbMM0VDROy43od7/hN6WYcA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
dependencies:
|
||||
'@babel/core': 7.24.5
|
||||
'@babel/helper-annotate-as-pure': 7.22.5
|
||||
'@babel/helper-environment-visitor': 7.22.20
|
||||
'@babel/helper-function-name': 7.23.0
|
||||
'@babel/helper-member-expression-to-functions': 7.24.5
|
||||
'@babel/helper-optimise-call-expression': 7.22.5
|
||||
'@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.5)
|
||||
'@babel/helper-skip-transparent-expression-wrappers': 7.22.5
|
||||
'@babel/helper-split-export-declaration': 7.24.5
|
||||
'@babel/core': 7.24.6
|
||||
'@babel/helper-annotate-as-pure': 7.24.6
|
||||
'@babel/helper-environment-visitor': 7.24.6
|
||||
'@babel/helper-function-name': 7.24.6
|
||||
'@babel/helper-member-expression-to-functions': 7.24.6
|
||||
'@babel/helper-optimise-call-expression': 7.24.6
|
||||
'@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.6)
|
||||
'@babel/helper-skip-transparent-expression-wrappers': 7.24.6
|
||||
'@babel/helper-split-export-declaration': 7.24.6
|
||||
semver: 6.3.1
|
||||
dev: true
|
||||
|
||||
/@babel/helper-environment-visitor@7.22.20:
|
||||
resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==}
|
||||
/@babel/helper-environment-visitor@7.24.6:
|
||||
resolution: {integrity: sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dev: true
|
||||
|
||||
/@babel/helper-function-name@7.23.0:
|
||||
resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==}
|
||||
/@babel/helper-function-name@7.24.6:
|
||||
resolution: {integrity: sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/template': 7.24.0
|
||||
'@babel/types': 7.24.5
|
||||
'@babel/template': 7.24.6
|
||||
'@babel/types': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/helper-hoist-variables@7.22.5:
|
||||
resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
|
||||
/@babel/helper-hoist-variables@7.24.6:
|
||||
resolution: {integrity: sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/types': 7.24.5
|
||||
'@babel/types': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/helper-member-expression-to-functions@7.24.5:
|
||||
resolution: {integrity: sha512-4owRteeihKWKamtqg4JmWSsEZU445xpFRXPEwp44HbgbxdWlUV1b4Agg4lkA806Lil5XM/e+FJyS0vj5T6vmcA==}
|
||||
/@babel/helper-member-expression-to-functions@7.24.6:
|
||||
resolution: {integrity: sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/types': 7.24.5
|
||||
'@babel/types': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/helper-module-imports@7.24.3:
|
||||
resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==}
|
||||
/@babel/helper-module-imports@7.24.6:
|
||||
resolution: {integrity: sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/types': 7.24.5
|
||||
'@babel/types': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/helper-module-transforms@7.24.5(@babel/core@7.24.5):
|
||||
resolution: {integrity: sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==}
|
||||
/@babel/helper-module-transforms@7.24.6(@babel/core@7.24.6):
|
||||
resolution: {integrity: sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
dependencies:
|
||||
'@babel/core': 7.24.5
|
||||
'@babel/helper-environment-visitor': 7.22.20
|
||||
'@babel/helper-module-imports': 7.24.3
|
||||
'@babel/helper-simple-access': 7.24.5
|
||||
'@babel/helper-split-export-declaration': 7.24.5
|
||||
'@babel/helper-validator-identifier': 7.24.5
|
||||
'@babel/core': 7.24.6
|
||||
'@babel/helper-environment-visitor': 7.24.6
|
||||
'@babel/helper-module-imports': 7.24.6
|
||||
'@babel/helper-simple-access': 7.24.6
|
||||
'@babel/helper-split-export-declaration': 7.24.6
|
||||
'@babel/helper-validator-identifier': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/helper-optimise-call-expression@7.22.5:
|
||||
resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==}
|
||||
/@babel/helper-optimise-call-expression@7.24.6:
|
||||
resolution: {integrity: sha512-3SFDJRbx7KuPRl8XDUr8O7GAEB8iGyWPjLKJh/ywP/Iy9WOmEfMrsWbaZpvBu2HSYn4KQygIsz0O7m8y10ncMA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/types': 7.24.5
|
||||
'@babel/types': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/helper-plugin-utils@7.24.5:
|
||||
resolution: {integrity: sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==}
|
||||
/@babel/helper-plugin-utils@7.24.6:
|
||||
resolution: {integrity: sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dev: true
|
||||
|
||||
/@babel/helper-replace-supers@7.24.1(@babel/core@7.24.5):
|
||||
resolution: {integrity: sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==}
|
||||
/@babel/helper-replace-supers@7.24.6(@babel/core@7.24.6):
|
||||
resolution: {integrity: sha512-mRhfPwDqDpba8o1F8ESxsEkJMQkUF8ZIWrAc0FtWhxnjfextxMWxr22RtFizxxSYLjVHDeMgVsRq8BBZR2ikJQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
dependencies:
|
||||
'@babel/core': 7.24.5
|
||||
'@babel/helper-environment-visitor': 7.22.20
|
||||
'@babel/helper-member-expression-to-functions': 7.24.5
|
||||
'@babel/helper-optimise-call-expression': 7.22.5
|
||||
'@babel/core': 7.24.6
|
||||
'@babel/helper-environment-visitor': 7.24.6
|
||||
'@babel/helper-member-expression-to-functions': 7.24.6
|
||||
'@babel/helper-optimise-call-expression': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/helper-simple-access@7.24.5:
|
||||
resolution: {integrity: sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==}
|
||||
/@babel/helper-simple-access@7.24.6:
|
||||
resolution: {integrity: sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/types': 7.24.5
|
||||
'@babel/types': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/helper-skip-transparent-expression-wrappers@7.22.5:
|
||||
resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==}
|
||||
/@babel/helper-skip-transparent-expression-wrappers@7.24.6:
|
||||
resolution: {integrity: sha512-jhbbkK3IUKc4T43WadP96a27oYti9gEf1LdyGSP2rHGH77kwLwfhO7TgwnWvxxQVmke0ImmCSS47vcuxEMGD3Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/types': 7.24.5
|
||||
'@babel/types': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/helper-split-export-declaration@7.24.5:
|
||||
resolution: {integrity: sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==}
|
||||
/@babel/helper-split-export-declaration@7.24.6:
|
||||
resolution: {integrity: sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/types': 7.24.5
|
||||
'@babel/types': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/helper-string-parser@7.24.1:
|
||||
resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==}
|
||||
/@babel/helper-string-parser@7.24.6:
|
||||
resolution: {integrity: sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dev: true
|
||||
|
||||
/@babel/helper-validator-identifier@7.24.5:
|
||||
resolution: {integrity: sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==}
|
||||
/@babel/helper-validator-identifier@7.24.6:
|
||||
resolution: {integrity: sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dev: true
|
||||
|
||||
/@babel/helper-validator-option@7.23.5:
|
||||
resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==}
|
||||
/@babel/helper-validator-option@7.24.6:
|
||||
resolution: {integrity: sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dev: true
|
||||
|
||||
/@babel/helpers@7.24.5:
|
||||
resolution: {integrity: sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==}
|
||||
/@babel/helpers@7.24.6:
|
||||
resolution: {integrity: sha512-V2PI+NqnyFu1i0GyTd/O/cTpxzQCYioSkUIRmgo7gFEHKKCg5w46+r/A6WeUR1+P3TeQ49dspGPNd/E3n9AnnA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/template': 7.24.0
|
||||
'@babel/traverse': 7.24.5
|
||||
'@babel/types': 7.24.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
'@babel/template': 7.24.6
|
||||
'@babel/types': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/highlight@7.24.5:
|
||||
resolution: {integrity: sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==}
|
||||
/@babel/highlight@7.24.6:
|
||||
resolution: {integrity: sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/helper-validator-identifier': 7.24.5
|
||||
'@babel/helper-validator-identifier': 7.24.6
|
||||
chalk: 2.4.2
|
||||
js-tokens: 4.0.0
|
||||
picocolors: 1.0.1
|
||||
dev: true
|
||||
|
||||
/@babel/parser@7.24.5:
|
||||
resolution: {integrity: sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==}
|
||||
/@babel/parser@7.24.6:
|
||||
resolution: {integrity: sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@babel/types': 7.24.5
|
||||
'@babel/types': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/plugin-syntax-jsx@7.24.1(@babel/core@7.24.5):
|
||||
resolution: {integrity: sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==}
|
||||
/@babel/plugin-syntax-jsx@7.24.6(@babel/core@7.24.6):
|
||||
resolution: {integrity: sha512-lWfvAIFNWMlCsU0DRUun2GpFwZdGTukLaHJqRh1JRb80NdAP5Sb1HDHB5X9P9OtgZHQl089UzQkpYlBq2VTPRw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
dependencies:
|
||||
'@babel/core': 7.24.5
|
||||
'@babel/helper-plugin-utils': 7.24.5
|
||||
'@babel/core': 7.24.6
|
||||
'@babel/helper-plugin-utils': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/plugin-syntax-typescript@7.24.1(@babel/core@7.24.5):
|
||||
resolution: {integrity: sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==}
|
||||
/@babel/plugin-syntax-typescript@7.24.6(@babel/core@7.24.6):
|
||||
resolution: {integrity: sha512-TzCtxGgVTEJWWwcYwQhCIQ6WaKlo80/B+Onsk4RRCcYqpYGFcG9etPW94VToGte5AAcxRrhjPUFvUS3Y2qKi4A==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
dependencies:
|
||||
'@babel/core': 7.24.5
|
||||
'@babel/helper-plugin-utils': 7.24.5
|
||||
'@babel/core': 7.24.6
|
||||
'@babel/helper-plugin-utils': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/plugin-transform-modules-commonjs@7.24.1(@babel/core@7.24.5):
|
||||
resolution: {integrity: sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==}
|
||||
/@babel/plugin-transform-modules-commonjs@7.24.6(@babel/core@7.24.6):
|
||||
resolution: {integrity: sha512-JEV8l3MHdmmdb7S7Cmx6rbNEjRCgTQMZxllveHO0mx6uiclB0NflCawlQQ6+o5ZrwjUBYPzHm2XoK4wqGVUFuw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
dependencies:
|
||||
'@babel/core': 7.24.5
|
||||
'@babel/helper-module-transforms': 7.24.5(@babel/core@7.24.5)
|
||||
'@babel/helper-plugin-utils': 7.24.5
|
||||
'@babel/helper-simple-access': 7.24.5
|
||||
'@babel/core': 7.24.6
|
||||
'@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6)
|
||||
'@babel/helper-plugin-utils': 7.24.6
|
||||
'@babel/helper-simple-access': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/plugin-transform-typescript@7.24.5(@babel/core@7.24.5):
|
||||
resolution: {integrity: sha512-E0VWu/hk83BIFUWnsKZ4D81KXjN5L3MobvevOHErASk9IPwKHOkTgvqzvNo1yP/ePJWqqK2SpUR5z+KQbl6NVw==}
|
||||
/@babel/plugin-transform-typescript@7.24.6(@babel/core@7.24.6):
|
||||
resolution: {integrity: sha512-H0i+hDLmaYYSt6KU9cZE0gb3Cbssa/oxWis7PX4ofQzbvsfix9Lbh8SRk7LCPDlLWJHUiFeHU0qRRpF/4Zv7mQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
dependencies:
|
||||
'@babel/core': 7.24.5
|
||||
'@babel/helper-annotate-as-pure': 7.22.5
|
||||
'@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.5)
|
||||
'@babel/helper-plugin-utils': 7.24.5
|
||||
'@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.5)
|
||||
'@babel/core': 7.24.6
|
||||
'@babel/helper-annotate-as-pure': 7.24.6
|
||||
'@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6)
|
||||
'@babel/helper-plugin-utils': 7.24.6
|
||||
'@babel/plugin-syntax-typescript': 7.24.6(@babel/core@7.24.6)
|
||||
dev: true
|
||||
|
||||
/@babel/preset-typescript@7.24.1(@babel/core@7.24.5):
|
||||
resolution: {integrity: sha512-1DBaMmRDpuYQBPWD8Pf/WEwCrtgRHxsZnP4mIy9G/X+hFfbI47Q2G4t1Paakld84+qsk2fSsUPMKg71jkoOOaQ==}
|
||||
/@babel/preset-typescript@7.24.6(@babel/core@7.24.6):
|
||||
resolution: {integrity: sha512-U10aHPDnokCFRXgyT/MaIRTivUu2K/mu0vJlwRS9LxJmJet+PFQNKpggPyFCUtC6zWSBPjvxjnpNkAn3Uw2m5w==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
dependencies:
|
||||
'@babel/core': 7.24.5
|
||||
'@babel/helper-plugin-utils': 7.24.5
|
||||
'@babel/helper-validator-option': 7.23.5
|
||||
'@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.5)
|
||||
'@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.24.5)
|
||||
'@babel/plugin-transform-typescript': 7.24.5(@babel/core@7.24.5)
|
||||
'@babel/core': 7.24.6
|
||||
'@babel/helper-plugin-utils': 7.24.6
|
||||
'@babel/helper-validator-option': 7.24.6
|
||||
'@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6)
|
||||
'@babel/plugin-transform-modules-commonjs': 7.24.6(@babel/core@7.24.6)
|
||||
'@babel/plugin-transform-typescript': 7.24.6(@babel/core@7.24.6)
|
||||
dev: true
|
||||
|
||||
/@babel/template@7.24.0:
|
||||
resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==}
|
||||
/@babel/template@7.24.6:
|
||||
resolution: {integrity: sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.24.2
|
||||
'@babel/parser': 7.24.5
|
||||
'@babel/types': 7.24.5
|
||||
'@babel/code-frame': 7.24.6
|
||||
'@babel/parser': 7.24.6
|
||||
'@babel/types': 7.24.6
|
||||
dev: true
|
||||
|
||||
/@babel/traverse@7.24.5:
|
||||
resolution: {integrity: sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==}
|
||||
/@babel/traverse@7.24.6:
|
||||
resolution: {integrity: sha512-OsNjaJwT9Zn8ozxcfoBc+RaHdj3gFmCmYoQLUII1o6ZrUwku0BMg80FoOTPx+Gi6XhcQxAYE4xyjPTo4SxEQqw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.24.2
|
||||
'@babel/generator': 7.24.5
|
||||
'@babel/helper-environment-visitor': 7.22.20
|
||||
'@babel/helper-function-name': 7.23.0
|
||||
'@babel/helper-hoist-variables': 7.22.5
|
||||
'@babel/helper-split-export-declaration': 7.24.5
|
||||
'@babel/parser': 7.24.5
|
||||
'@babel/types': 7.24.5
|
||||
'@babel/code-frame': 7.24.6
|
||||
'@babel/generator': 7.24.6
|
||||
'@babel/helper-environment-visitor': 7.24.6
|
||||
'@babel/helper-function-name': 7.24.6
|
||||
'@babel/helper-hoist-variables': 7.24.6
|
||||
'@babel/helper-split-export-declaration': 7.24.6
|
||||
'@babel/parser': 7.24.6
|
||||
'@babel/types': 7.24.6
|
||||
debug: 4.3.4
|
||||
globals: 11.12.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@babel/types@7.24.5:
|
||||
resolution: {integrity: sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==}
|
||||
/@babel/types@7.24.6:
|
||||
resolution: {integrity: sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/helper-string-parser': 7.24.1
|
||||
'@babel/helper-validator-identifier': 7.24.5
|
||||
'@babel/helper-string-parser': 7.24.6
|
||||
'@babel/helper-validator-identifier': 7.24.6
|
||||
to-fast-properties: 2.0.0
|
||||
dev: true
|
||||
|
||||
@@ -563,8 +566,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@iconify-json/simple-icons@1.1.102:
|
||||
resolution: {integrity: sha512-ErRQGs7tjGsq4sj5SSeYwBOQ766yd9LtWblWakyL+ugg1k48ImabkI3mptDN5o+XSUb9SC+b7YNSStlrrecqNQ==}
|
||||
/@iconify-json/simple-icons@1.1.103:
|
||||
resolution: {integrity: sha512-u5r+Sirr0CME+Q0qUr6OgjErFpTSsGyttJbkfL5BUcRwELgN9FpCj8zYXySKTqCP1ttWIgAAiTC4ZKGoN5Gehw==}
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
dev: true
|
||||
@@ -850,12 +853,22 @@ packages:
|
||||
resolution: {integrity: sha512-4bBX1pavDl2DSCozEII7bxYGT0IkyO7kKlUuCtooTePWyLjf2F7essdzHkJ00EpNR64kkebR9V0lqBMBo07VPw==}
|
||||
dev: true
|
||||
|
||||
/@unocss/core@0.60.4:
|
||||
resolution: {integrity: sha512-6tz8KTzC30oB0YikwRQoIpJ6Y6Dg+ZiK3NfCIsH+UX11bh2J2M53as2EL/5VQCqtiUn3YP0ZEzR2d1AWX78RCA==}
|
||||
dev: true
|
||||
|
||||
/@unocss/extractor-arbitrary-variants@0.60.3:
|
||||
resolution: {integrity: sha512-PnwNwkeAHmbJbrf5XN0xQG1KT1VQEye8neYn5yz1MHnT8Cj2nqjrqoCRGLCLhpOUg3/MNj+bpiA7hGnFbXWaCQ==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.60.3
|
||||
dev: true
|
||||
|
||||
/@unocss/extractor-arbitrary-variants@0.60.4:
|
||||
resolution: {integrity: sha512-USuFGs5CLft9q7IGNdAEp1oliuUns+W7OO0Tx5qtx/oBh6pU/L93lcNNsuuGNrMU8BCmF3atx1/PEmGymgJ7VA==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.60.4
|
||||
dev: true
|
||||
|
||||
/@unocss/inspector@0.60.3:
|
||||
resolution: {integrity: sha512-2cXAPA1yddB79mmpMXxPpSpizn4TskAsB7aSocbprOTYIU2Ff53gfkkijnLixrBvbG8xw91d9oPuI5Hm9GCyMQ==}
|
||||
dependencies:
|
||||
@@ -904,6 +917,14 @@ packages:
|
||||
'@unocss/rule-utils': 0.60.3
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-mini@0.60.4:
|
||||
resolution: {integrity: sha512-ZiHbP69vkyz0xmhqzC4B4PegwV+LPlZOBT7cRhsh0P8oPOQKYOyDRy4rAl+sJBJeIrggn1r1LgN+Z0Xvd8Ytcw==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.60.4
|
||||
'@unocss/extractor-arbitrary-variants': 0.60.4
|
||||
'@unocss/rule-utils': 0.60.4
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-tagify@0.60.3:
|
||||
resolution: {integrity: sha512-pzD6bgtGuIk7M1n/JQiR6EpwnVvafSTHoM70Jhf+T8MSuatDb+KFJCn3VELV2v38aikcUY5cTf95jqHQdzOAhQ==}
|
||||
dependencies:
|
||||
@@ -949,7 +970,15 @@ packages:
|
||||
resolution: {integrity: sha512-I47/DcKQ2z12W80+Ffth0K6LzNvqcQPYRWk7KwVemVoEiGYamMV8/s+SbB26Fk9KUFjh+Ns/pGAo4iJZo0ueUQ==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
'@unocss/core': 0.60.3
|
||||
'@unocss/core': 0.60.4
|
||||
magic-string: 0.30.10
|
||||
dev: true
|
||||
|
||||
/@unocss/rule-utils@0.60.4:
|
||||
resolution: {integrity: sha512-7qUN33NM4T/IwWavm9VIOCZ2+4hLBc0YUGxcMNTDZSFQRQLkWe3N5dOlgwKXtMyMKatZfbIRUKVDUgvEefoCTA==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
'@unocss/core': 0.60.4
|
||||
magic-string: 0.30.10
|
||||
dev: true
|
||||
|
||||
@@ -960,9 +989,9 @@ packages:
|
||||
/@unocss/transformer-attributify-jsx-babel@0.60.3:
|
||||
resolution: {integrity: sha512-6WcEFPSaxscGR22dRUcNqY0ippC3/Q/LBVFVSCJh++hoIPVCZbxF505cPq/bOdF2bpNzj9yXW0OJt03nB505Hg==}
|
||||
dependencies:
|
||||
'@babel/core': 7.24.5
|
||||
'@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.5)
|
||||
'@babel/preset-typescript': 7.24.1(@babel/core@7.24.5)
|
||||
'@babel/core': 7.24.6
|
||||
'@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6)
|
||||
'@babel/preset-typescript': 7.24.6(@babel/core@7.24.6)
|
||||
'@unocss/core': 0.60.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -1052,8 +1081,8 @@ packages:
|
||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001621
|
||||
electron-to-chromium: 1.4.780
|
||||
caniuse-lite: 1.0.30001623
|
||||
electron-to-chromium: 1.4.783
|
||||
node-releases: 2.0.14
|
||||
update-browserslist-db: 1.0.16(browserslist@4.23.0)
|
||||
dev: true
|
||||
@@ -1063,8 +1092,8 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/caniuse-lite@1.0.30001621:
|
||||
resolution: {integrity: sha512-+NLXZiviFFKX0fk8Piwv3PfLPGtRqJeq2TiNoUff/qB5KJgwecJTvCXDpmlyP/eCI/GUEmp/h/y5j0yckiiZrA==}
|
||||
/caniuse-lite@1.0.30001623:
|
||||
resolution: {integrity: sha512-X/XhAVKlpIxWPpgRTnlgZssJrF0m6YtRA0QDWgsBNT12uZM6LPRydR7ip405Y3t1LamD8cP2TZFEDZFBf5ApcA==}
|
||||
dev: true
|
||||
|
||||
/chalk@2.4.2:
|
||||
@@ -1159,8 +1188,8 @@ packages:
|
||||
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
|
||||
dev: true
|
||||
|
||||
/electron-to-chromium@1.4.780:
|
||||
resolution: {integrity: sha512-NPtACGFe7vunRYzvYqVRhQvsDrTevxpgDKxG/Vcbe0BTNOY+5+/2mOXSw2ls7ToNbE5Bf/+uQbjTxcmwMozpCw==}
|
||||
/electron-to-chromium@1.4.783:
|
||||
resolution: {integrity: sha512-bT0jEz/Xz1fahQpbZ1D7LgmPYZ3iHVY39NcWWro1+hA2IvjiPeaXtfSqrQ+nXjApMvQRE2ASt1itSLRrebHMRQ==}
|
||||
dev: true
|
||||
|
||||
/esbuild@0.20.2:
|
||||
|
||||
61
static/global.css
Normal file
@@ -0,0 +1,61 @@
|
||||
@font-face {
|
||||
font-family: Inter;
|
||||
src: url(inter.woff2);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Cal Sans;
|
||||
src: url(cal-sans.woff2);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Fira Code;
|
||||
src: url(fira-code.woff2);
|
||||
}
|
||||
|
||||
@keyframes anim-in {
|
||||
from {
|
||||
opacity: var(--anim-fade-from, 1);
|
||||
transform:
|
||||
translateY(var(--anim-slide-from-y, 0)) translateX(var(--anim-slide-from-x, 0));
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: var(--anim-fade-to, 1);
|
||||
transform:
|
||||
translateY(var(--anim-slide-to-y, 0)) translateX(var(--anim-slide-to-x, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.cannot-hover {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media not all and (hover: hover) {
|
||||
.can-hover {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.animate {
|
||||
animation-name: anim-in;
|
||||
animation-delay: calc(var(--anim-delay, 0) * var(--anim-stagger, 1) * var(--start, 1));
|
||||
animation-duration: var(--anim-duration, 1s);
|
||||
animation-fill-mode: var(--anim--fill-mode, forwards);
|
||||
animation-iteration-count: var(--anim-iter-count, 1);
|
||||
animation-timing-function: var(--anim-timing, ease-in-out);
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
--anim-fade-from: 0;
|
||||
}
|
||||
|
||||
.slide-from-b {
|
||||
--anim-slide-from-y: 1.7rem;
|
||||
}
|
||||
|
||||
.slide-from-r {
|
||||
--anim-slide-from-x: 1.7rem;
|
||||
}
|
||||
BIN
static/images/image-1.png
Normal file
|
After Width: | Height: | Size: 5.2 MiB |
BIN
static/images/image-2.png
Normal file
|
After Width: | Height: | Size: 5.8 MiB |
BIN
static/images/image-3.png
Normal file
|
After Width: | Height: | Size: 433 KiB |
BIN
static/images/image-4.png
Normal file
|
After Width: | Height: | Size: 2.7 MiB |
BIN
static/images/image-5.png
Normal file
|
After Width: | Height: | Size: 363 KiB |
BIN
static/images/image-6.png
Normal file
|
After Width: | Height: | Size: 526 KiB |
BIN
static/images/image-7.png
Normal file
|
After Width: | Height: | Size: 242 KiB |
@@ -1 +0,0 @@
|
||||
test
|
||||
143
uno-utils.js
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
This file is licensed under the MIT license provided down below:
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024-PRESENT Gustavo L. de Mello
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
This file has source code modified from the UnoCSS repository, licensed under the MIT
|
||||
license. A copy of the original licensed is provided here https://github.com/unocss/unocss/blob/main/LICENSE
|
||||
and down below:
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-PRESENT Anthony Fu <https://github.com/antfu>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @param {string} [requiredType]
|
||||
*
|
||||
* @license MIT
|
||||
* @author Anthony Fu <https://github.com/antfu>
|
||||
*/
|
||||
function bracketWithType(str, requiredType) {
|
||||
if (str && str.startsWith('[') && str.endsWith(']')) {
|
||||
/** @type {string | undefined } */
|
||||
let base
|
||||
/** @type {string | undefined } */
|
||||
let hintedType
|
||||
|
||||
const bracketTypeRe = /^\[(color|length|size|position|quoted|string):/i
|
||||
const match = str.match(bracketTypeRe)
|
||||
if (!match) {
|
||||
base = str.slice(1, -1)
|
||||
}
|
||||
else {
|
||||
if (!requiredType)
|
||||
hintedType = match[1]
|
||||
base = str.slice(match[0].length, -1)
|
||||
}
|
||||
|
||||
if (!base)
|
||||
return
|
||||
|
||||
// test/preset-attributify.test.ts > fixture5
|
||||
if (base === '=""')
|
||||
return
|
||||
|
||||
if (base.startsWith('--'))
|
||||
base = `var(${base})`
|
||||
|
||||
let curly = 0
|
||||
for (const i of base) {
|
||||
if (i === '[') {
|
||||
curly += 1
|
||||
}
|
||||
else if (i === ']') {
|
||||
curly -= 1
|
||||
if (curly < 0)
|
||||
return
|
||||
}
|
||||
}
|
||||
if (curly)
|
||||
return
|
||||
|
||||
switch (hintedType) {
|
||||
case 'string': return base
|
||||
.replace(/(^|[^\\])_/g, '$1 ')
|
||||
.replace(/\\_/g, '_')
|
||||
|
||||
case 'quoted': return base
|
||||
.replace(/(^|[^\\])_/g, '$1 ')
|
||||
.replace(/\\_/g, '_')
|
||||
.replace(/(["\\])/g, '\\$1')
|
||||
.replace(/^(.+)$/, '"$1"')
|
||||
}
|
||||
|
||||
return base
|
||||
.replace(/(url\(.*?\))/g, v => v.replace(/_/g, '\\_'))
|
||||
.replace(/(^|[^\\])_/g, '$1 ')
|
||||
.replace(/\\_/g, '_')
|
||||
.replace(/(?:calc|clamp|max|min)\((.*)/g, (match) => {
|
||||
/** @type {string[]} */
|
||||
const vars = []
|
||||
return match
|
||||
.replace(/var\((--.+?)[,)]/g, (match, g1) => {
|
||||
vars.push(g1)
|
||||
return match.replace(g1, '--un-calc')
|
||||
})
|
||||
.replace(/(-?\d*\.?\d(?!-\d.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, '$1 $2 ')
|
||||
.replace(/--un-calc/g, () => /** @type {string} */(vars.shift()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
*
|
||||
* @license MIT
|
||||
* @author Anthony Fu <https://github.com/antfu>
|
||||
*/
|
||||
export function bracket(str) {
|
||||
return bracketWithType(str)
|
||||
}
|
||||
162
uno.config.js
@@ -7,19 +7,175 @@ import {
|
||||
transformerDirectives,
|
||||
transformerVariantGroup,
|
||||
} from 'unocss';
|
||||
import { definePreset } from 'unocss';
|
||||
import { colorResolver, variantGetParameter } from '@unocss/preset-mini/utils';
|
||||
|
||||
import * as utils from './uno-utils.js';
|
||||
|
||||
const presetForcedColors = definePreset(
|
||||
/** @returns {import('unocss').Preset} */
|
||||
() => {
|
||||
return {
|
||||
name: 'preset-forced-colors',
|
||||
variants: [
|
||||
{
|
||||
name: 'forced-colors',
|
||||
match(matcher, ctx) {
|
||||
if (!matcher.startsWith('forced-colors:')) {
|
||||
return matcher
|
||||
}
|
||||
return {
|
||||
matcher: matcher.slice('forced-colors:'.length),
|
||||
handle: (input, next) => next({
|
||||
...input,
|
||||
parent: `${input.parent ? `${input.parent} $$` : ''}@media(forced-colors: active)`,
|
||||
parentOrder: 1000,
|
||||
}),
|
||||
}
|
||||
/* handle: (input, next) => next({
|
||||
...input,
|
||||
parent: `${input.parent ? `${input.parent} $$` : ''}@container${label ? ` ${label} ` : ''}${container}`,
|
||||
parentOrder: order,
|
||||
}), */
|
||||
},
|
||||
multiPass: true,
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Preset based on https://github.com/tailwindlabs/tailwindcss-container-queries
|
||||
*/
|
||||
const presetContainers = definePreset(
|
||||
/**
|
||||
* @param {{ containers?: Record<string, string | number>}} [options={}]
|
||||
*/
|
||||
(options = {}) => {
|
||||
const defaultContainers = {
|
||||
'xs': '20rem' /* 320px */,
|
||||
'sm': '24rem' /* 384px */,
|
||||
'md': '28rem' /* 448px */,
|
||||
'lg': '32rem' /* 512px */,
|
||||
'xl': '36rem' /* 576px */,
|
||||
'2xl': '42rem' /* 672px */,
|
||||
'3xl': '48rem' /* 768px */,
|
||||
'4xl': '56rem' /* 896px */,
|
||||
'5xl': '64rem' /* 1024px */,
|
||||
'6xl': '72rem' /* 1152px */,
|
||||
'7xl': '80rem' /* 1280px */,
|
||||
};
|
||||
options.containers = {
|
||||
...defaultContainers,
|
||||
...Object.fromEntries(Object.entries(defaultContainers).map(e => [`h-${e[0]}`, e[1]])),
|
||||
...Object.fromEntries(Object.entries(defaultContainers).map(e => [`w-${e[0]}`, e[1]])),
|
||||
...options.containers,
|
||||
};
|
||||
/** @type {import('unocss').Preset} */
|
||||
const preset = {
|
||||
name: 'preset-containers',
|
||||
rules: [
|
||||
[/^@container(?:\/(\w+))?(?:-(normal|size))?$/, ([, l, v]) => {
|
||||
return {
|
||||
'container-type': v ?? 'inline-size',
|
||||
'container-name': l,
|
||||
}
|
||||
}],
|
||||
],
|
||||
variants: [
|
||||
{
|
||||
name: '@',
|
||||
match(matcher, ctx) {
|
||||
if (matcher.startsWith('@container')) {
|
||||
return matcher
|
||||
}
|
||||
const variant = variantGetParameter('@', matcher, ctx.generator.config.separators)
|
||||
if (variant) {
|
||||
const [match, rest, label] = variant;
|
||||
const unit = utils.bracket(match);
|
||||
|
||||
/** @type {string | undefined } */
|
||||
let container;
|
||||
if (unit?.startsWith("h:")) {
|
||||
container = `(min-height: ${unit.replace('h:', '')})`
|
||||
} else if (unit?.startsWith("w:") || unit) {
|
||||
container = `(min-width: ${unit.replace('w:', '')})`
|
||||
} else {
|
||||
/** @type {string | number} */
|
||||
const size = options.containers?.[match] ?? '';
|
||||
container =
|
||||
`(${match.startsWith('h-') ? 'min-height' : 'min-width'}: ` +
|
||||
`${typeof size === 'number' ? `${size}px` : size})`
|
||||
}
|
||||
|
||||
if (!container) {
|
||||
return
|
||||
}
|
||||
|
||||
let order = (label ? 1000 : 2000) + Object.keys(options.containers ?? {}).indexOf(match);
|
||||
|
||||
return {
|
||||
matcher: rest,
|
||||
handle: (input, next) => next({
|
||||
...input,
|
||||
parent: `${input.parent ? `${input.parent} $$` : ''}@container${label ? ` ${label} ` : ''}${container}`,
|
||||
parentOrder: order,
|
||||
}),
|
||||
}
|
||||
}
|
||||
},
|
||||
multiPass: true,
|
||||
}
|
||||
],
|
||||
}
|
||||
return preset;
|
||||
})
|
||||
|
||||
export default defineConfig({
|
||||
theme: {
|
||||
colors: {
|
||||
'black': '#000000',
|
||||
'white': '#ffffff',
|
||||
'light-gray': '#9c9c9c',
|
||||
'gray': '#383838',
|
||||
'dark-gray': '#0c0c0c',
|
||||
'mauve': '#cba6f7',
|
||||
'yellow': '#f9e2af',
|
||||
},
|
||||
},
|
||||
rules: [
|
||||
[
|
||||
'scrollbar',
|
||||
{
|
||||
'scrollbar-color': 'var(--un-scrollbar-thumb, #ddd) var(--un-scrollbar-track, #f5f5f5)',
|
||||
},
|
||||
],
|
||||
[
|
||||
/^(?:scrollbar-)?thumb-(?:color-)?(.+)$/,
|
||||
// @ts-expect-error
|
||||
colorResolver('--un-scrollbar-thumb', 'scrollbar-thumb'),
|
||||
{ autocomplete: 'scrollbar-thumb-$colors' },
|
||||
],
|
||||
[
|
||||
/^(?:scrollbar-)?track-(?:color-)?(.+)$/,
|
||||
// @ts-expect-error
|
||||
colorResolver('--un-scrollbar-track', 'scrollbar-thumb'),
|
||||
{ autocomplete: 'scrollbar-track-$colors' },
|
||||
],
|
||||
],
|
||||
cli: {
|
||||
entry: {
|
||||
patterns: [
|
||||
'./{pages,layouts}/**/*.templ',
|
||||
'./static/**/*.{js,css,html}',
|
||||
'!./static/uno.css',
|
||||
'./{components,layouts,pages}/*.templ',
|
||||
'./static/*.{js,html}',
|
||||
],
|
||||
outFile: './static/uno.css',
|
||||
},
|
||||
},
|
||||
presets: [
|
||||
presetForcedColors(),
|
||||
presetContainers(),
|
||||
presetIcons(),
|
||||
presetTypography(),
|
||||
presetUno(),
|
||||
|
||||
15
vercel.json
@@ -1,5 +1,16 @@
|
||||
{
|
||||
"$schema": "https://openapi.vercel.sh/vercel.json",
|
||||
"outputDirectory": "dist"
|
||||
"outputDirectory": "dist",
|
||||
"redirects": [
|
||||
{
|
||||
"source": "/robots.txt",
|
||||
"destination": "/api/robots",
|
||||
"statusCode": 301
|
||||
},
|
||||
{
|
||||
"source": "/ai.txt",
|
||||
"destination": "/api/ai",
|
||||
"statusCode": 301
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||