├── .github └── workflows │ └── cd.yaml ├── .gitignore ├── LICENSE ├── README.md ├── package.json ├── pnpm-lock.yaml ├── settings.yaml ├── templates ├── archives.html ├── assets │ ├── css │ │ └── style.css │ ├── images │ │ ├── gongan_beian.webp │ │ ├── halo.jpg │ │ └── logo.svg │ └── js │ │ └── script.js ├── categories.html ├── category.html ├── index.html ├── layout.html ├── links.html ├── modules │ ├── navbar.html │ ├── pagination.html │ └── sidebar.html ├── moments.html ├── page.html ├── photos.html ├── post.html ├── resume.html ├── tag.html └── tags.html ├── theme.yaml └── website-demo-image ├── Thumbs.db ├── desktop.png └── mobile.png /.github/workflows/cd.yaml: -------------------------------------------------------------------------------- 1 | name: CD 2 | 3 | on: 4 | release: 5 | types: 6 | - published 7 | 8 | jobs: 9 | cd: 10 | uses: halo-sigs/reusable-workflows/.github/workflows/theme-cd.yaml@v3 11 | secrets: 12 | halo-pat: ${{ secrets.HALO_PAT }} 13 | permissions: 14 | contents: write 15 | with: 16 | app-id: app-EFeTP 17 | pnpm-version: 10 18 | node-version: 20 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | *.local 13 | 14 | # Editor directories and files 15 | .vscode/* 16 | !.vscode/extensions.json 17 | .idea 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | 24 | .gradle 25 | build 26 | dist -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vCard4 响应式个人作品集主题 2 | 3 | vCard4 是一个响应式的个人作品集主题,可适配所有设备,移植于 [codewithsadee/vcard-personal-portfolio](https://github.com/codewithsadee/vcard-personal-portfolio/) 4 | 5 | --- 6 | 7 |
8 | 9 | ### [主题演示](https://www.anye.xyz/?preview-theme=theme-vcard4) 10 | 11 | |桌面端|移动端| 12 | |:---:|:---:| 13 | |![](website-demo-image/desktop.png)|![](website-demo-image/mobile.png)| 14 | 15 | ![](https://img.shields.io/badge/dynamic/yaml?label=Halo&query=%24.spec.requires&url=https://raw.githubusercontent.com/Anyexyz/theme-vcard4/main/theme.yaml&color=113,195,71) 16 | ![](https://img.shields.io/github/v/release/Anyexyz/theme-vcard4) 17 | ![](https://img.shields.io/badge/License-GPL%20v3.0-green.svg) 18 | 19 |
20 | 21 | --- 22 | 23 | ## 插件支持 24 | - [x] [链接管理](https://www.halo.run/store/apps/app-hfbQg) 25 | - [x] [图库管理](https://github.com/halo-sigs/plugin-photos) 26 | - [x] [评论组件](https://www.halo.run/store/apps/app-YXyaD) 27 | - [x] [瞬间](https://www.halo.run/store/apps/app-SnwWD) 28 | - [x] [RSS](https://www.halo.run/store/apps/app-KhIVw) 29 | 30 | ## 已知 Bug 待修复 31 | 32 | - 瞬间无法点赞 33 | 34 | ## 🏭 贡献 35 | 36 | > 如果你想帮助完善 `vCard4` 主题,请: 37 | 38 | - 点 `star` 39 | - 提 `issue` 40 | - 修 `bugs` 41 | - 推 `pr` 42 | 43 | ## 🙆‍♂️ 感谢 44 | 45 | **特别致谢**: 46 | 47 | - [無.Flac](https://github.com/wflac/) 48 | - [Ryan Wang](https://github.com/ruibaby) 49 | - [困困鱼](https://github.com/chengzhongxue) 50 | 51 | 52 | 在此感谢以下项目提供的支持: 53 | 54 | - [vcard-personal-portfolio](https://github.com/codewithsadee/vcard-personal-portfolio/) 55 | - [theme-vcard](https://github.com/wflac/theme-vcard) 56 | - [Halo](https://halo.run) 57 | - [theme-starter](https://github.com/halo-dev/theme-starter) 58 | - [Cursor](https://github.com/getcursor/cursor) 59 | - ... -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "build": "npx @halo-dev/theme-package-cli" 4 | }, 5 | "packageManager": "pnpm@10.6.5+sha512.cdf928fca20832cd59ec53826492b7dc25dc524d4370b6b4adbf65803d32efaa6c1c88147c0ae4e8d579a6c9eec715757b50d4fa35eea179d868eada4ed043af" 6 | } 7 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: {} 10 | -------------------------------------------------------------------------------- /settings.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1alpha1 2 | kind: Setting 3 | metadata: 4 | name: theme-vcard4-setting 5 | annotations: 6 | "store.halo.run/app-id": "app-EFeTP" 7 | spec: 8 | forms: 9 | - group: index 10 | label: 个人资料 11 | formSchema: 12 | - $formkit: group 13 | name: header_info 14 | label: 站点资料 15 | children: 16 | - $formkit: attachment 17 | name: header_info_img 18 | label: 头像 19 | help: 自定义头像, 未填写时与站点设置 `Logo` 同步 20 | - $formkit: text 21 | name: header_info_title 22 | label: 标题 23 | help: 自定义标题, 未填写时与站点设置 `站点标题` 同步 24 | - $formkit: text 25 | name: header_info_subtitle 26 | label: 职业 27 | help: 自定义职业, 未填写时与站点设置 `站点副标题` 同步 28 | 29 | - $formkit: group 30 | name: header_contact 31 | label: 联系方式 32 | help: 注意!为空时则不显示 33 | children: 34 | - $formkit: text 35 | name: email 36 | label: 📮邮箱 37 | - $formkit: text 38 | name: phone 39 | label: 📱电话 40 | - $formkit: text 41 | name: birthday 42 | label: 🎂生日 43 | - $formkit: text 44 | name: Location 45 | label: 🌏地区 46 | 47 | - $formkit: repeater 48 | name: social 49 | label: 社交媒体 50 | max: 6 51 | help: 为保证页面美观, 限制最多显示 6 个社交媒体 52 | value: 53 | - icon: logo-rss 54 | name: RSS 55 | url: /rss.xml 56 | children: 57 | - $formkit: select 58 | name: icon 59 | label: 图标 60 | options: 61 | - label: 微信 62 | value: logo-wechat 63 | - label: 抖音 64 | value: logo-tiktok 65 | - label: Steam 66 | value: logo-steam 67 | - label: Skype 68 | value: logo-skype 69 | - label: Linkedin 70 | value: logo-linkedin 71 | - label: Youtube 72 | value: logo-youtube 73 | - label: X 74 | value: logo-twitter 75 | - label: twitch 76 | value: logo-twitch 77 | - label: Facebook 78 | value: logo-facebook 79 | - label: Instagram 80 | value: logo-instagram 81 | - label: Telegram 82 | value: paper-plane 83 | - label: Github 84 | value: logo-github 85 | - label: RSS 86 | value: logo-rss 87 | - $formkit: text 88 | name: name 89 | label: 名称 90 | - $formkit: text 91 | name: url 92 | label: 链接 93 | validation: "required" 94 | 95 | - group: about 96 | label: 个人简历页 97 | formSchema: 98 | - $formkit: text 99 | name: title 100 | label: 标题(需新建页面并选择个人简历模板生效) 101 | value: "关于我" 102 | - $formkit: group 103 | name: about_me 104 | label: 个人介绍 105 | children: 106 | - $formkit: checkbox 107 | name: switch 108 | label: 是否显示此模块 109 | value: true 110 | - $formkit: repeater 111 | name: content 112 | label: 内容 113 | value: [{"text":""}] 114 | help: 个人介绍内容, 每个内容块为一个段落, 支持 HTML 语法 115 | children: 116 | - $formkit: code 117 | name: text 118 | value: "" 119 | height: 100px 120 | language: html 121 | label: 新增内容 122 | - $formkit: group 123 | name: about_what 124 | label: 开发项目 125 | children: 126 | - $formkit: checkbox 127 | name: switch 128 | label: 是否显示此模块 129 | value: false 130 | - $formkit: text 131 | name: title 132 | label: 标题 133 | value: "项目" 134 | - $formkit: repeater 135 | name: content 136 | label: 内容 137 | value: [ ] 138 | children: 139 | - $formkit: text 140 | name: title 141 | label: 项目名称 142 | - $formkit: attachment 143 | name: images 144 | label: 图标 145 | - $formkit: text 146 | name: url 147 | label: 链接 148 | - $formkit: code 149 | name: text 150 | value: "" 151 | height: 60px 152 | language: html 153 | label: 描述 154 | - $formkit: repeater 155 | name: timeline 156 | label: 时间线 157 | value: [{"title":"教育经历","icon":"book-outline","content":[]},{"title":"工作经历","icon":"briefcase-outline","content":[]}] 158 | children: 159 | - $formkit: checkbox 160 | name: switch 161 | label: 是否显示此模块 162 | value: false 163 | - $formkit: text 164 | name: title 165 | label: 标题 166 | - $formkit: text 167 | name: icon 168 | label: 图标 169 | help: 请填写图标名称, 可参考 https://ionic.io/ionicons 170 | - $formkit: repeater 171 | name: content 172 | label: 节点 173 | value: [ ] 174 | children: 175 | - $formkit: text 176 | name: name 177 | label: 名称 178 | - $formkit: text 179 | name: time 180 | label: 时间 181 | - $formkit: code 182 | name: text 183 | value: "" 184 | height: 50px 185 | language: html 186 | label: 简介 187 | - $formkit: group 188 | name: skills 189 | label: 技能 190 | children: 191 | - $formkit: checkbox 192 | name: switch 193 | label: 是否显示此模块 194 | value: true 195 | - $formkit: text 196 | name: title 197 | label: 标题 198 | value: "技能" 199 | - $formkit: repeater 200 | name: content 201 | label: 新增内容 202 | value: [ ] 203 | children: 204 | - $formkit: text 205 | name: name 206 | label: 名称 207 | - $formkit: text 208 | name: num 209 | label: 百分比 210 | - $formkit: group 211 | name: about_evaluate 212 | label: 评价 213 | children: 214 | - $formkit: checkbox 215 | name: switch 216 | label: 是否显示此模块 217 | value: false 218 | - $formkit: text 219 | name: title 220 | label: 标题 221 | value: "评价" 222 | - $formkit: repeater 223 | name: content 224 | label: 内容 225 | value: [ ] 226 | children: 227 | - $formkit: text 228 | name: name 229 | label: 用户名 230 | - $formkit: attachment 231 | name: images 232 | label: 头像 233 | - $formkit: code 234 | name: text 235 | value: "" 236 | height: 60px 237 | language: html 238 | label: 评价内容 239 | - $formkit: group 240 | name: about_clients 241 | label: 合作客户 242 | children: 243 | - $formkit: checkbox 244 | name: switch 245 | label: 是否显示此模块 246 | value: false 247 | - $formkit: text 248 | name: title 249 | label: 标题 250 | value: "合作客户" 251 | - $formkit: repeater 252 | name: content 253 | label: 内容 254 | value: [ ] 255 | children: 256 | - $formkit: text 257 | name: name 258 | label: 名称 259 | - $formkit: text 260 | name: url 261 | label: 链接 262 | - $formkit: attachment 263 | name: images 264 | label: Logo 265 | 266 | - group: beian 267 | label: 备案设置 268 | formSchema: 269 | - $formkit: text 270 | name: icp_text 271 | label: ICP备案号 272 | - $formkit: text 273 | name: icp_link 274 | label: ICP备案跳转链接 275 | value: https://beian.miit.gov.cn/ 276 | 277 | - $formkit: text 278 | name: gongan_text 279 | label: 公安联网备案号 280 | - $formkit: text 281 | name: gongan_link 282 | label: 公安联网备案跳转链接 283 | value: https://beian.mps.gov.cn/#/query/webSearch -------------------------------------------------------------------------------- /templates/archives.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 |
21 | 22 | 23 | 24 |
25 |
26 |

时间线

27 |
28 | 29 |
30 |
31 |
32 | 33 |
34 |

35 |
36 |
    37 | 38 | 39 |
  1. 40 | 41 |

    42 |

    43 |
    44 |
  2. 45 |
    46 |
    47 |
48 | 49 |
50 | 51 | 52 |
53 |
54 | 55 |
56 | 57 |
58 | 59 | 60 | 62 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /templates/assets/css/style.css: -------------------------------------------------------------------------------- 1 | /*-----------------------------------*\ 2 | #style.css 3 | \*-----------------------------------*/ 4 | 5 | 6 | /** 7 | * copyright 2022 @codewithsadee 8 | */ 9 | 10 | 11 | 12 | 13 | 14 | /*-----------------------------------*\ 15 | #CUSTOM PROPERTY 16 | \*-----------------------------------*/ 17 | 18 | :root { 19 | 20 | /** 21 | * colors 22 | */ 23 | 24 | /* gradient */ 25 | 26 | --bg-gradient-onyx: linear-gradient(to bottom right, 27 | hsl(240, 1%, 25%) 3%, 28 | hsl(0, 0%, 19%) 97%); 29 | --bg-gradient-jet: linear-gradient(to bottom right, 30 | hsla(240, 1%, 18%, 0.251) 0%, 31 | hsla(240, 2%, 11%, 0) 100%), hsl(240, 2%, 13%); 32 | --bg-gradient-yellow-1: linear-gradient(to bottom right, 33 | hsl(45, 100%, 71%) 0%, 34 | hsla(36, 100%, 69%, 0) 50%); 35 | --bg-gradient-yellow-2: linear-gradient(135deg, 36 | hsla(45, 100%, 71%, 0.251) 0%, 37 | hsla(35, 100%, 68%, 0) 59.86%), hsl(240, 2%, 13%); 38 | --border-gradient-onyx: linear-gradient(to bottom right, 39 | hsl(0, 0%, 25%) 0%, 40 | hsla(0, 0%, 25%, 0) 50%); 41 | --text-gradient-yellow: linear-gradient(to right, 42 | hsl(45, 100%, 72%), 43 | hsl(35, 100%, 68%)); 44 | 45 | /* solid */ 46 | 47 | --jet: hsl(0, 0%, 22%); 48 | --onyx: hsl(240, 1%, 17%); 49 | --eerie-black-1: hsl(240, 2%, 13%); 50 | --eerie-black-2: hsl(240, 2%, 12%); 51 | --smoky-black: hsl(0, 0%, 7%); 52 | --white-1: hsl(0, 0%, 100%); 53 | --white-2: hsl(0, 0%, 98%); 54 | --orange-yellow-crayola: hsl(45, 100%, 72%); 55 | --vegas-gold: hsl(45, 54%, 58%); 56 | --light-gray: hsl(0, 0%, 84%); 57 | --light-gray-70: hsla(0, 0%, 84%, 0.7); 58 | --bittersweet-shimmer: hsl(0, 43%, 51%); 59 | 60 | /** 61 | * typography 62 | */ 63 | 64 | /* font-family */ 65 | --ff-poppins: 'Poppins', sans-serif; 66 | 67 | /* font-size */ 68 | --fs-1: 24px; 69 | --fs-2: 18px; 70 | --fs-3: 17px; 71 | --fs-4: 16px; 72 | --fs-5: 15px; 73 | --fs-6: 14px; 74 | --fs-7: 13px; 75 | --fs-8: 11px; 76 | 77 | /* font-weight */ 78 | --fw-300: 300; 79 | --fw-400: 400; 80 | --fw-500: 500; 81 | --fw-600: 600; 82 | 83 | /** 84 | * shadow 85 | */ 86 | 87 | --shadow-1: -4px 8px 24px hsla(0, 0%, 0%, 0.25); 88 | --shadow-2: 0 16px 30px hsla(0, 0%, 0%, 0.25); 89 | --shadow-3: 0 16px 40px hsla(0, 0%, 0%, 0.25); 90 | --shadow-4: 0 25px 50px hsla(0, 0%, 0%, 0.15); 91 | --shadow-5: 0 24px 80px hsla(0, 0%, 0%, 0.25); 92 | 93 | /** 94 | * transition 95 | */ 96 | 97 | --transition-1: 0.25s ease; 98 | --transition-2: 0.5s ease-in-out; 99 | 100 | } 101 | 102 | 103 | 104 | 105 | 106 | /*-----------------------------------*\ 107 | #RESET 108 | \*-----------------------------------*/ 109 | 110 | *, 111 | *::before, 112 | *::after { 113 | margin: 0; 114 | padding: 0; 115 | box-sizing: border-box; 116 | } 117 | 118 | a { 119 | text-decoration: none; 120 | color: var(--orange-yellow-crayola); 121 | } 122 | 123 | li { 124 | list-style: none; 125 | } 126 | 127 | img, 128 | ion-icon, 129 | a, 130 | button, 131 | time, 132 | span { 133 | display: block; 134 | } 135 | 136 | button { 137 | font: inherit; 138 | background: none; 139 | border: none; 140 | text-align: left; 141 | cursor: pointer; 142 | } 143 | 144 | input, 145 | textarea { 146 | display: block; 147 | width: 100%; 148 | background: none; 149 | font: inherit; 150 | } 151 | 152 | ::selection { 153 | background: var(--orange-yellow-crayola); 154 | color: var(--smoky-black); 155 | } 156 | 157 | :focus { 158 | outline-color: var(--orange-yellow-crayola); 159 | } 160 | 161 | html { 162 | font-family: var(--ff-poppins); 163 | } 164 | 165 | body { 166 | background: var(--smoky-black); 167 | } 168 | 169 | 170 | 171 | 172 | 173 | /*-----------------------------------*\ 174 | #REUSED STYLE 175 | \*-----------------------------------*/ 176 | 177 | .sidebar, 178 | article { 179 | background: var(--eerie-black-2); 180 | border: 1px solid var(--jet); 181 | border-radius: 20px; 182 | padding: 15px; 183 | box-shadow: var(--shadow-1); 184 | z-index: 1; 185 | } 186 | 187 | .separator { 188 | width: 100%; 189 | height: 1px; 190 | background: var(--jet); 191 | margin: 16px 0; 192 | } 193 | 194 | .icon-box { 195 | position: relative; 196 | background: var(--border-gradient-onyx); 197 | width: 30px; 198 | height: 30px; 199 | border-radius: 8px; 200 | display: flex; 201 | justify-content: center; 202 | align-items: center; 203 | font-size: 16px; 204 | color: var(--orange-yellow-crayola); 205 | box-shadow: var(--shadow-1); 206 | z-index: 1; 207 | } 208 | 209 | .icon-box::before { 210 | content: ""; 211 | position: absolute; 212 | inset: 1px; 213 | background: var(--eerie-black-1); 214 | border-radius: inherit; 215 | z-index: -1; 216 | } 217 | 218 | .icon-box ion-icon { 219 | --ionicon-stroke-width: 35px; 220 | } 221 | 222 | article { 223 | display: none; 224 | } 225 | 226 | article.active { 227 | display: block; 228 | animation: fade 0.5s ease backwards; 229 | } 230 | 231 | @keyframes fade { 232 | 0% { 233 | opacity: 0; 234 | } 235 | 236 | 100% { 237 | opacity: 1; 238 | } 239 | } 240 | 241 | .h2, 242 | .h3, 243 | .h4, 244 | .h5 { 245 | color: var(--white-2); 246 | text-transform: capitalize; 247 | } 248 | 249 | .h2 { 250 | font-size: var(--fs-1); 251 | } 252 | 253 | .h3 { 254 | font-size: var(--fs-2); 255 | } 256 | 257 | .h4 { 258 | font-size: var(--fs-4); 259 | } 260 | 261 | .h5 { 262 | font-size: var(--fs-7); 263 | font-weight: var(--fw-500); 264 | } 265 | 266 | .article-title { 267 | position: relative; 268 | padding-bottom: 7px; 269 | } 270 | 271 | /* 在中等屏幕和大屏幕下添加上边距 */ 272 | @media (min-width: 1024px) { 273 | .article-title { 274 | margin-top: 45px; /* 中等屏幕下的上边距 */ 275 | } 276 | } 277 | 278 | @media (min-width: 1250px) { 279 | .article-title { 280 | margin-top: 60px; /* 大屏幕下的上边距 */ 281 | } 282 | } 283 | 284 | .article-title::after { 285 | content: ""; 286 | position: absolute; 287 | bottom: 0; 288 | left: 0; 289 | width: 30px; 290 | height: 3px; 291 | background: var(--text-gradient-yellow); 292 | border-radius: 3px; 293 | } 294 | 295 | .has-scrollbar::-webkit-scrollbar { 296 | width: 5px; 297 | /* for vertical scrollbar */ 298 | height: 5px; 299 | /* for horizontal scrollbar */ 300 | } 301 | 302 | .has-scrollbar::-webkit-scrollbar-track { 303 | background: var(--onyx); 304 | border-radius: 5px; 305 | } 306 | 307 | .has-scrollbar::-webkit-scrollbar-thumb { 308 | background: var(--orange-yellow-crayola); 309 | border-radius: 5px; 310 | } 311 | 312 | .has-scrollbar::-webkit-scrollbar-button { 313 | width: 20px; 314 | } 315 | 316 | .content-card { 317 | position: relative; 318 | background: var(--border-gradient-onyx); 319 | padding: 15px; 320 | padding-top: 45px; 321 | border-radius: 14px; 322 | box-shadow: var(--shadow-2); 323 | cursor: pointer; 324 | z-index: 1; 325 | } 326 | 327 | .content-card::before { 328 | content: ""; 329 | position: absolute; 330 | inset: 1px; 331 | background: var(--bg-gradient-jet); 332 | border-radius: inherit; 333 | z-index: -1; 334 | } 335 | 336 | 337 | 338 | 339 | 340 | /*-----------------------------------*\ 341 | #MAIN 342 | \*-----------------------------------*/ 343 | 344 | main { 345 | margin: 15px 12px; 346 | margin-bottom: 75px; 347 | min-width: 259px; 348 | } 349 | 350 | 351 | 352 | 353 | 354 | /*-----------------------------------*\ 355 | #SIDEBAR 356 | \*-----------------------------------*/ 357 | 358 | .sidebar { 359 | margin-bottom: 15px; 360 | max-height: 112px; 361 | overflow: hidden; 362 | transition: var(--transition-2); 363 | } 364 | 365 | .sidebar.active { 366 | max-height: max-content; 367 | } 368 | 369 | .sidebar-info { 370 | position: relative; 371 | display: flex; 372 | justify-content: flex-start; 373 | align-items: center; 374 | gap: 15px; 375 | } 376 | 377 | .avatar-box { 378 | background: var(--bg-gradient-onyx); 379 | border-radius: 20px; 380 | } 381 | 382 | .info-content .name { 383 | color: var(--white-2); 384 | font-size: var(--fs-3); 385 | font-weight: var(--fw-500); 386 | letter-spacing: -0.25px; 387 | margin-bottom: 10px; 388 | } 389 | 390 | .info-content .title { 391 | color: var(--white-1); 392 | background: var(--onyx); 393 | font-size: var(--fs-8); 394 | font-weight: var(--fw-300); 395 | width: max-content; 396 | padding: 3px 12px; 397 | border-radius: 8px; 398 | } 399 | 400 | .info_more-btn { 401 | position: absolute; 402 | top: -15px; 403 | right: -15px; 404 | border-radius: 0 15px; 405 | font-size: 13px; 406 | color: var(--orange-yellow-crayola); 407 | background: var(--border-gradient-onyx); 408 | padding: 10px; 409 | box-shadow: var(--shadow-2); 410 | transition: var(--transition-1); 411 | z-index: 1; 412 | } 413 | 414 | .info_more-btn::before { 415 | content: ""; 416 | position: absolute; 417 | inset: 1px; 418 | border-radius: inherit; 419 | background: var(--bg-gradient-jet); 420 | transition: var(--transition-1); 421 | z-index: -1; 422 | } 423 | 424 | .info_more-btn:hover, 425 | .info_more-btn:focus { 426 | background: var(--bg-gradient-yellow-1); 427 | } 428 | 429 | .info_more-btn:hover::before, 430 | .info_more-btn:focus::before { 431 | background: var(--bg-gradient-yellow-2); 432 | } 433 | 434 | .info_more-btn span { 435 | display: none; 436 | } 437 | 438 | .sidebar-info_more { 439 | opacity: 0; 440 | visibility: hidden; 441 | transition: var(--transition-2); 442 | } 443 | 444 | .sidebar.active .sidebar-info_more { 445 | opacity: 1; 446 | visibility: visible; 447 | } 448 | 449 | .contacts-list { 450 | display: grid; 451 | grid-template-columns: 1fr; 452 | gap: 16px; 453 | } 454 | 455 | .contact-item { 456 | min-width: 100%; 457 | display: flex; 458 | align-items: center; 459 | gap: 16px; 460 | } 461 | 462 | .contact-info { 463 | max-width: calc(100% - 46px); 464 | width: calc(100% - 46px); 465 | } 466 | 467 | .contact-title { 468 | color: var(--light-gray-70); 469 | font-size: var(--fs-8); 470 | text-transform: uppercase; 471 | margin-bottom: 2px; 472 | } 473 | 474 | .contact-info :is(.contact-link, time, address) { 475 | color: var(--white-2); 476 | font-size: var(--fs-7); 477 | } 478 | 479 | .contact-info address { 480 | font-style: normal; 481 | } 482 | 483 | .social-list { 484 | display: flex; 485 | justify-content: flex-start; 486 | align-items: center; 487 | gap: 15px; 488 | padding-bottom: 4px; 489 | padding-left: 7px; 490 | } 491 | 492 | .social-item .social-link { 493 | color: var(--light-gray-70); 494 | font-size: 18px; 495 | } 496 | 497 | 498 | .social-item .social-link:hover { 499 | color: var(--light-gray); 500 | } 501 | 502 | 503 | 504 | 505 | 506 | /*-----------------------------------*\ 507 | #NAVBAR 508 | \*-----------------------------------*/ 509 | 510 | .navbar { 511 | position: fixed; 512 | bottom: 0; 513 | left: 0; 514 | width: 100%; 515 | background: hsla(240, 1%, 17%, 0.75); 516 | backdrop-filter: blur(10px); 517 | border: 1px solid var(--jet); 518 | border-radius: 12px 12px 0 0; 519 | box-shadow: var(--shadow-2); 520 | z-index: 5; 521 | } 522 | 523 | .navbar-list { 524 | display: flex; 525 | flex-wrap: wrap; 526 | justify-content: center; 527 | align-items: center; 528 | padding: 0 10px; 529 | } 530 | 531 | .navbar-link { 532 | color: var(--light-gray); 533 | font-size: var(--fs-8); 534 | padding: 20px 7px; 535 | transition: color var(--transition-1); 536 | } 537 | 538 | .navbar-link:hover, 539 | .navbar-link:focus { 540 | color: var(--light-gray-70); 541 | } 542 | 543 | .navbar-link.active { 544 | color: var(--orange-yellow-crayola); 545 | } 546 | 547 | 548 | 549 | 550 | 551 | /*-----------------------------------*\ 552 | #ABOUT 553 | \*-----------------------------------*/ 554 | 555 | .about .article-title { 556 | margin-bottom: 15px; 557 | } 558 | 559 | .about-text { 560 | color: var(--light-gray); 561 | font-size: var(--fs-6); 562 | font-weight: var(--fw-300); 563 | line-height: 1.6; 564 | } 565 | 566 | .about-text p { 567 | margin-bottom: 15px; 568 | } 569 | 570 | 571 | 572 | /** 573 | * #service 574 | */ 575 | 576 | .service { 577 | margin-bottom: 35px; 578 | } 579 | 580 | .service-title { 581 | margin-bottom: 20px; 582 | } 583 | 584 | .service-list { 585 | display: grid; 586 | grid-template-columns: 1fr; 587 | gap: 20px; 588 | } 589 | 590 | .service-item { 591 | position: relative; 592 | background: var(--border-gradient-onyx); 593 | padding: 20px; 594 | border-radius: 14px; 595 | box-shadow: var(--shadow-2); 596 | z-index: 1; 597 | } 598 | 599 | .service-item::before { 600 | content: ""; 601 | position: absolute; 602 | inset: 1px; 603 | background: var(--bg-gradient-jet); 604 | border-radius: inherit; 605 | z-index: -1; 606 | } 607 | 608 | .service-icon-box { 609 | margin-bottom: 0; 610 | margin-right: 1.25rem; 611 | flex-shrink: 0; 612 | } 613 | 614 | .service-icon-box img { 615 | margin: auto; 616 | width: 50px; 617 | height: 50px; 618 | border-radius: 0.875rem; 619 | object-fit: cover; 620 | } 621 | 622 | .service-content-box { 623 | text-align: left; 624 | width: 100%; 625 | min-width: 0; 626 | } 627 | 628 | .service-item-title { 629 | margin-bottom: 7px; 630 | } 631 | 632 | .service-item-text { 633 | color: var(--light-gray); 634 | font-size: var(--fs-6); 635 | font-weight: var(--fw-3); 636 | line-height: 1.6; 637 | overflow: hidden; 638 | text-overflow: ellipsis; 639 | display: -webkit-box; 640 | -webkit-line-clamp: 1; 641 | -webkit-box-orient: vertical; 642 | word-break: break-all; 643 | } 644 | 645 | 646 | /** 647 | * #testimonials 648 | */ 649 | 650 | .testimonials { 651 | margin-bottom: 30px; 652 | } 653 | 654 | .testimonials-title { 655 | margin-bottom: 20px; 656 | } 657 | 658 | .testimonials-list { 659 | display: flex; 660 | justify-content: flex-start; 661 | align-items: flex-start; 662 | gap: 15px; 663 | margin: 0 -15px; 664 | padding: 25px 15px; 665 | padding-bottom: 35px; 666 | overflow-x: auto; 667 | scroll-behavior: smooth; 668 | overscroll-behavior-inline: contain; 669 | scroll-snap-type: inline mandatory; 670 | } 671 | 672 | .testimonials-item { 673 | min-width: 100%; 674 | scroll-snap-align: center; 675 | } 676 | 677 | .testimonials-avatar-box { 678 | position: absolute; 679 | top: 0; 680 | left: 0; 681 | transform: translate(15px, -25px); 682 | background: var(--bg-gradient-onyx); 683 | border-radius: 14px; 684 | box-shadow: var(--shadow-1); 685 | } 686 | 687 | .testimonials-item-title { 688 | margin-bottom: 7px; 689 | } 690 | 691 | .testimonials-text { 692 | color: var(--light-gray); 693 | font-size: var(--fs-6); 694 | font-weight: var(--fw-300); 695 | line-height: 1.6; 696 | display: -webkit-box; 697 | line-clamp: 4; 698 | -webkit-line-clamp: 4; 699 | -webkit-box-orient: vertical; 700 | overflow: hidden; 701 | } 702 | 703 | 704 | /** 705 | * #testimonials-modal 706 | */ 707 | 708 | .modal-container { 709 | position: fixed; 710 | top: 0; 711 | left: 0; 712 | width: 100%; 713 | height: 100%; 714 | display: flex; 715 | justify-content: center; 716 | align-items: center; 717 | overflow-y: auto; 718 | overscroll-behavior: contain; 719 | z-index: 20; 720 | pointer-events: none; 721 | visibility: hidden; 722 | } 723 | 724 | .modal-container::-webkit-scrollbar { 725 | display: none; 726 | } 727 | 728 | .modal-container.active { 729 | pointer-events: all; 730 | visibility: visible; 731 | } 732 | 733 | .overlay { 734 | position: fixed; 735 | top: 0; 736 | left: 0; 737 | width: 100%; 738 | height: 100vh; 739 | background: hsl(0, 0%, 5%); 740 | opacity: 0; 741 | visibility: hidden; 742 | pointer-events: none; 743 | z-index: 1; 744 | transition: var(--transition-1); 745 | } 746 | 747 | .overlay.active { 748 | opacity: 0.8; 749 | visibility: visible; 750 | pointer-events: all; 751 | } 752 | 753 | .testimonials-modal { 754 | background: var(--eerie-black-2); 755 | position: relative; 756 | padding: 15px; 757 | margin: 15px 12px; 758 | border: 1px solid var(--jet); 759 | border-radius: 14px; 760 | box-shadow: var(--shadow-5); 761 | transform: scale(1.2); 762 | opacity: 0; 763 | transition: var(--transition-1); 764 | z-index: 2; 765 | } 766 | 767 | .modal-container.active .testimonials-modal { 768 | transform: scale(1); 769 | opacity: 1; 770 | } 771 | 772 | .modal-close-btn { 773 | position: absolute; 774 | top: 15px; 775 | right: 15px; 776 | background: var(--onyx); 777 | border-radius: 8px; 778 | width: 32px; 779 | height: 32px; 780 | display: flex; 781 | justify-content: center; 782 | align-items: center; 783 | color: var(--white-2); 784 | font-size: 18px; 785 | opacity: 0.7; 786 | } 787 | 788 | .modal-close-btn:hover, 789 | .modal-close-btn:focus { 790 | opacity: 1; 791 | } 792 | 793 | .modal-close-btn ion-icon { 794 | --ionicon-stroke-width: 50px; 795 | } 796 | 797 | .modal-avatar-box { 798 | background: var(--bg-gradient-onyx); 799 | width: max-content; 800 | border-radius: 14px; 801 | margin-bottom: 15px; 802 | box-shadow: var(--shadow-2); 803 | } 804 | 805 | .modal-img-wrapper>img { 806 | display: none; 807 | } 808 | 809 | .modal-title { 810 | margin-bottom: 4px; 811 | } 812 | 813 | .modal-content time { 814 | font-size: var(--fs-6); 815 | color: var(--light-gray-70); 816 | font-weight: var(--fw-300); 817 | margin-bottom: 10px; 818 | } 819 | 820 | .modal-content p { 821 | color: var(--light-gray); 822 | font-size: var(--fs-6); 823 | font-weight: var(--fw-300); 824 | line-height: 1.6; 825 | } 826 | 827 | 828 | /** 829 | * #clients 830 | */ 831 | 832 | .clients { 833 | margin-bottom: 15px; 834 | } 835 | 836 | .clients-list { 837 | display: flex; 838 | justify-content: flex-start; 839 | align-items: flex-start; 840 | gap: 15px; 841 | margin: 0 -15px; 842 | padding: 25px; 843 | padding-bottom: 25px; 844 | overflow-x: auto; 845 | scroll-behavior: smooth; 846 | overscroll-behavior-inline: contain; 847 | scroll-snap-type: inline mandatory; 848 | scroll-padding-inline: 25px; 849 | } 850 | 851 | .clients-item { 852 | min-width: 50%; 853 | scroll-snap-align: start; 854 | } 855 | 856 | .clients-item img { 857 | width: 100%; 858 | filter: grayscale(1); 859 | transition: var(--transition-1); 860 | } 861 | 862 | .clients-item img:hover { 863 | filter: grayscale(0); 864 | } 865 | 866 | 867 | 868 | 869 | 870 | /*-----------------------------------*\ 871 | #RESUME 872 | \*-----------------------------------*/ 873 | 874 | .article-title { 875 | margin-bottom: 30px; 876 | } 877 | 878 | 879 | /** 880 | * education and experience 881 | */ 882 | 883 | .timeline { 884 | margin-bottom: 30px; 885 | } 886 | 887 | .timeline .title-wrapper { 888 | display: flex; 889 | align-items: center; 890 | gap: 15px; 891 | margin-bottom: 25px; 892 | } 893 | 894 | .timeline-list { 895 | font-size: var(--fs-6); 896 | margin-left: 45px; 897 | } 898 | 899 | .timeline-item { 900 | position: relative; 901 | } 902 | 903 | .timeline-item:not(:last-child) { 904 | margin-bottom: 20px; 905 | } 906 | 907 | .timeline-item-title { 908 | font-size: var(--fs-6); 909 | line-height: 1.3; 910 | margin-bottom: 7px; 911 | } 912 | 913 | .timeline-list span { 914 | color: var(--vegas-gold); 915 | font-weight: var(--fw-400); 916 | line-height: 1.6; 917 | } 918 | 919 | .timeline-item:not(:last-child)::before { 920 | content: ""; 921 | position: absolute; 922 | top: -25px; 923 | left: -30px; 924 | width: 1px; 925 | height: calc(100% + 50px); 926 | background: var(--jet); 927 | } 928 | 929 | .timeline-item::after { 930 | content: ""; 931 | position: absolute; 932 | top: 5px; 933 | left: -33px; 934 | height: 6px; 935 | width: 6px; 936 | background: var(--text-gradient-yellow); 937 | border-radius: 50%; 938 | box-shadow: 0 0 0 4px var(--jet); 939 | } 940 | 941 | .timeline-text { 942 | color: var(--light-gray); 943 | font-weight: var(--fw-300); 944 | line-height: 1.6; 945 | } 946 | 947 | 948 | /** 949 | * skills 950 | */ 951 | 952 | .skills-title { 953 | margin-bottom: 20px; 954 | } 955 | 956 | .skills-list { 957 | padding: 20px; 958 | } 959 | 960 | 961 | .skills-item:not(:last-child) { 962 | margin-bottom: 15px; 963 | } 964 | 965 | .skill .title-wrapper { 966 | display: flex; 967 | align-items: center; 968 | gap: 5px; 969 | margin-bottom: 8px; 970 | } 971 | 972 | .skill .title-wrapper data { 973 | color: var(--light-gray); 974 | font-size: var(--fs-7); 975 | font-weight: var(--fw-300); 976 | } 977 | 978 | .skill-progress-bg { 979 | background: var(--jet); 980 | width: 100%; 981 | height: 8px; 982 | border-radius: 10px; 983 | } 984 | 985 | .skill-progress-fill { 986 | background: var(--text-gradient-yellow); 987 | height: 100%; 988 | border-radius: inherit; 989 | } 990 | 991 | 992 | 993 | 994 | 995 | /*-----------------------------------*\ 996 | #PORTFOLIO 997 | \*-----------------------------------*/ 998 | 999 | .filter-list { 1000 | display: none; 1001 | } 1002 | 1003 | .filter-select-box { 1004 | position: relative; 1005 | margin-bottom: 25px; 1006 | z-index: 2; 1007 | } 1008 | 1009 | .filter-select { 1010 | background: var(--eerie-black-2); 1011 | color: var(--light-gray); 1012 | display: flex; 1013 | justify-content: space-between; 1014 | align-items: center; 1015 | width: 100%; 1016 | padding: 12px 16px; 1017 | border: 1px solid var(--jet); 1018 | border-radius: 14px; 1019 | font-size: var(--fs-6); 1020 | font-weight: var(--fw-300); 1021 | cursor: pointer; 1022 | } 1023 | 1024 | .filter-select.active .select-icon { 1025 | transform: rotate(0.5turn); 1026 | } 1027 | 1028 | .select-list { 1029 | background: var(--eerie-black-2); 1030 | position: absolute; 1031 | top: calc(100% + 6px); 1032 | width: 100%; 1033 | padding: 6px; 1034 | border: 1px solid var(--jet); 1035 | border-radius: 14px; 1036 | z-index: 2; 1037 | opacity: 0; 1038 | visibility: hidden; 1039 | pointer-events: none; 1040 | transition: 0.15s ease-in-out; 1041 | } 1042 | 1043 | .filter-select.active + .select-list { 1044 | opacity: 1; 1045 | visibility: visible; 1046 | pointer-events: all; 1047 | } 1048 | 1049 | .select-item { 1050 | padding: 5px 0; 1051 | } 1052 | 1053 | .select-item a { 1054 | background: var(--eerie-black-2); 1055 | color: var(--light-gray); 1056 | font-size: var(--fs-6); 1057 | font-weight: var(--fw-300); 1058 | text-transform: capitalize; 1059 | width: 100%; 1060 | padding: 8px 10px; 1061 | border-radius: 8px; 1062 | display: block; 1063 | transition: var(--transition-1); 1064 | } 1065 | 1066 | .select-item a:hover, 1067 | .select-item a.active { 1068 | background: hsl(240, 2%, 20%); 1069 | color: var(--white-2); 1070 | } 1071 | 1072 | .project-list { 1073 | display: grid; 1074 | grid-template-columns: 1fr; 1075 | gap: 30px; 1076 | margin-bottom: 10px; 1077 | } 1078 | 1079 | .project-item { 1080 | display: none; 1081 | } 1082 | 1083 | .project-item.active { 1084 | display: block; 1085 | animation: scaleUp 0.25s ease forwards; 1086 | } 1087 | 1088 | @keyframes scaleUp { 1089 | 0% { 1090 | transform: scale(0.5); 1091 | } 1092 | 1093 | 100% { 1094 | transform: scale(1); 1095 | } 1096 | } 1097 | 1098 | .project-item>a { 1099 | width: 100%; 1100 | } 1101 | 1102 | .project-img { 1103 | position: relative; 1104 | width: 100%; 1105 | height: 200px; 1106 | border-radius: 16px; 1107 | overflow: hidden; 1108 | margin-bottom: 15px; 1109 | } 1110 | 1111 | .project-img::before { 1112 | content: ""; 1113 | position: absolute; 1114 | top: 0; 1115 | left: 0; 1116 | width: 100%; 1117 | height: 100%; 1118 | background: transparent; 1119 | z-index: 1; 1120 | transition: var(--transition-1); 1121 | } 1122 | 1123 | .project-item>a:hover .project-img::before { 1124 | background: hsla(0, 0%, 0%, 0.5); 1125 | } 1126 | 1127 | .project-item-icon-box { 1128 | --scale: 0.8; 1129 | 1130 | background: var(--jet); 1131 | color: var(--orange-yellow-crayola); 1132 | position: absolute; 1133 | top: 50%; 1134 | left: 50%; 1135 | transform: translate(-50%, -50%) scale(var(--scale)); 1136 | font-size: 20px; 1137 | padding: 18px; 1138 | border-radius: 12px; 1139 | opacity: 0; 1140 | z-index: 1; 1141 | transition: var(--transition-1); 1142 | } 1143 | 1144 | .project-item>a:hover .project-item-icon-box { 1145 | --scale: 1; 1146 | opacity: 1; 1147 | } 1148 | 1149 | .project-item-icon-box ion-icon { 1150 | --ionicon-stroke-width: 50px; 1151 | } 1152 | 1153 | .project-img img { 1154 | width: 100%; 1155 | height: 200px; 1156 | object-fit: cover; 1157 | transition: var(--transition-1); 1158 | } 1159 | 1160 | .project-item>a:hover img { 1161 | transform: scale(1.1); 1162 | } 1163 | 1164 | .project-title, 1165 | .project-category { 1166 | margin-left: 10px; 1167 | } 1168 | 1169 | .project-title { 1170 | color: var(--white-2); 1171 | font-size: var(--fs-5); 1172 | font-weight: var(--fw-400); 1173 | text-transform: capitalize; 1174 | line-height: 1.3; 1175 | } 1176 | 1177 | .project-category { 1178 | color: var(--light-gray-70); 1179 | font-size: var(--fs-6); 1180 | font-weight: var(--fw-300); 1181 | } 1182 | 1183 | 1184 | 1185 | 1186 | 1187 | /*-----------------------------------*\ 1188 | #BLOG 1189 | \*-----------------------------------*/ 1190 | 1191 | .blog-posts { 1192 | margin-bottom: 10px; 1193 | } 1194 | 1195 | .blog-posts-list { 1196 | display: grid; 1197 | grid-template-columns: 1fr; 1198 | gap: 20px; 1199 | } 1200 | 1201 | .blog-post-item>a { 1202 | position: relative; 1203 | background: var(--border-gradient-onyx); 1204 | height: 100%; 1205 | box-shadow: var(--shadow-4); 1206 | border-radius: 16px; 1207 | z-index: 1; 1208 | } 1209 | 1210 | .blog-post-item>a::before { 1211 | content: ""; 1212 | position: absolute; 1213 | inset: 1px; 1214 | border-radius: inherit; 1215 | background: var(--eerie-black-1); 1216 | z-index: -1; 1217 | } 1218 | 1219 | .blog-banner-box { 1220 | width: 100%; 1221 | height: 200px; 1222 | border-radius: 12px; 1223 | overflow: hidden; 1224 | } 1225 | 1226 | .blog-banner-box img { 1227 | width: 100%; 1228 | height: 100%; 1229 | object-fit: cover; 1230 | transition: var(--transition-1); 1231 | } 1232 | 1233 | .blog-post-item>a:hover .blog-banner-box img { 1234 | transform: scale(1.1); 1235 | } 1236 | 1237 | .blog-content { 1238 | padding: 15px; 1239 | } 1240 | 1241 | .blog-meta { 1242 | display: flex; 1243 | justify-content: flex-start; 1244 | align-items: center; 1245 | gap: 7px; 1246 | margin-bottom: 10px; 1247 | } 1248 | 1249 | .blog-meta :is(.blog-category, time) { 1250 | color: var(--light-gray-70); 1251 | font-size: var(--fs-6); 1252 | font-weight: var(--fw-300); 1253 | } 1254 | 1255 | .blog-meta .dot { 1256 | background: var(--light-gray-70); 1257 | width: 4px; 1258 | height: 4px; 1259 | border-radius: 4px; 1260 | } 1261 | 1262 | .blog-item-title { 1263 | margin-bottom: 10px; 1264 | line-height: 1.3; 1265 | transition: var(--transition-1); 1266 | } 1267 | 1268 | .blog-post-item>a:hover .blog-item-title { 1269 | color: var(--orange-yellow-crayola); 1270 | } 1271 | 1272 | .blog-text { 1273 | color: var(--light-gray); 1274 | font-size: var(--fs-6); 1275 | font-weight: var(--fw-300); 1276 | line-height: 1.6; 1277 | } 1278 | 1279 | 1280 | 1281 | 1282 | 1283 | /*-----------------------------------*\ 1284 | #CONTACT 1285 | \*-----------------------------------*/ 1286 | 1287 | .mapbox { 1288 | position: relative; 1289 | height: 250px; 1290 | width: 100%; 1291 | border-radius: 16px; 1292 | margin-bottom: 30px; 1293 | border: 1px solid var(--jet); 1294 | overflow: hidden; 1295 | } 1296 | 1297 | .mapbox figure { 1298 | height: 100%; 1299 | } 1300 | 1301 | .mapbox iframe { 1302 | width: 100%; 1303 | height: 100%; 1304 | border: none; 1305 | filter: grayscale(1) invert(1); 1306 | } 1307 | 1308 | .contact-form { 1309 | margin-bottom: 10px; 1310 | } 1311 | 1312 | .form-title { 1313 | margin-bottom: 20px; 1314 | } 1315 | 1316 | .input-wrapper { 1317 | display: grid; 1318 | grid-template-columns: 1fr; 1319 | gap: 25px; 1320 | margin-bottom: 25px; 1321 | } 1322 | 1323 | .form-input { 1324 | color: var(--white-2); 1325 | font-size: var(--fs-6); 1326 | font-weight: var(--fw-400); 1327 | padding: 13px 20px; 1328 | border: 1px solid var(--jet); 1329 | border-radius: 14px; 1330 | outline: none; 1331 | } 1332 | 1333 | .form-input::placeholder { 1334 | font-weight: var(--fw-500); 1335 | } 1336 | 1337 | .form-input:focus { 1338 | border-color: var(--orange-yellow-crayola); 1339 | } 1340 | 1341 | textarea.form-input { 1342 | min-height: 100px; 1343 | height: 120px; 1344 | max-height: 200px; 1345 | resize: vertical; 1346 | margin-bottom: 25px; 1347 | } 1348 | 1349 | textarea.form-input::-webkit-resizer { 1350 | display: none; 1351 | } 1352 | 1353 | .form-input:focus:invalid { 1354 | border-color: var(--bittersweet-shimmer); 1355 | } 1356 | 1357 | .form-btn { 1358 | position: relative; 1359 | width: 100%; 1360 | background: var(--border-gradient-onyx); 1361 | color: var(--orange-yellow-crayola); 1362 | display: flex; 1363 | justify-content: center; 1364 | align-items: center; 1365 | gap: 10px; 1366 | padding: 13px 20px; 1367 | border-radius: 14px; 1368 | font-size: var(--fs-6); 1369 | text-transform: capitalize; 1370 | box-shadow: var(--shadow-3); 1371 | z-index: 1; 1372 | transition: var(--transition-1); 1373 | } 1374 | 1375 | .form-btn::before { 1376 | content: ""; 1377 | position: absolute; 1378 | inset: 1px; 1379 | background: var(--bg-gradient-jet); 1380 | border-radius: inherit; 1381 | z-index: -1; 1382 | transition: var(--transition-1); 1383 | } 1384 | 1385 | .form-btn ion-icon { 1386 | font-size: 16px; 1387 | } 1388 | 1389 | .form-btn:hover { 1390 | background: var(--bg-gradient-yellow-1); 1391 | } 1392 | 1393 | .form-btn:hover::before { 1394 | background: var(--bg-gradient-yellow-2); 1395 | } 1396 | 1397 | .form-btn:disabled { 1398 | opacity: 0.7; 1399 | cursor: not-allowed; 1400 | } 1401 | 1402 | .form-btn:disabled:hover { 1403 | background: var(--border-gradient-onyx); 1404 | } 1405 | 1406 | .form-btn:disabled:hover::before { 1407 | background: var(--bg-gradient-jet); 1408 | } 1409 | 1410 | 1411 | 1412 | 1413 | 1414 | /*-----------------------------------*\ 1415 | #RESPONSIVE 1416 | \*-----------------------------------*/ 1417 | 1418 | /** 1419 | * responsive larger than 450px screen 1420 | */ 1421 | 1422 | @media (min-width: 450px) { 1423 | 1424 | /** 1425 | * client 1426 | */ 1427 | 1428 | .clients-item { 1429 | min-width: calc(33.33% - 10px); 1430 | } 1431 | 1432 | 1433 | 1434 | /** 1435 | * #PORTFOLIO, BLOG 1436 | */ 1437 | 1438 | .project-img, 1439 | .blog-banner-box { 1440 | height: auto; 1441 | } 1442 | 1443 | } 1444 | 1445 | 1446 | 1447 | 1448 | 1449 | /** 1450 | * responsive larger than 580px screen 1451 | */ 1452 | 1453 | @media (min-width: 580px) { 1454 | 1455 | /** 1456 | * CUSTOM PROPERTY 1457 | */ 1458 | 1459 | :root { 1460 | 1461 | /** 1462 | * typography 1463 | */ 1464 | 1465 | --fs-1: 32px; 1466 | --fs-2: 24px; 1467 | --fs-3: 26px; 1468 | --fs-4: 18px; 1469 | --fs-6: 15px; 1470 | --fs-7: 15px; 1471 | --fs-8: 12px; 1472 | 1473 | } 1474 | 1475 | 1476 | 1477 | /** 1478 | * #REUSED STYLE 1479 | */ 1480 | 1481 | .sidebar, 1482 | article { 1483 | width: 520px; 1484 | margin-inline: auto; 1485 | padding: 30px; 1486 | } 1487 | 1488 | .article-title { 1489 | font-weight: var(--fw-600); 1490 | padding-bottom: 15px; 1491 | } 1492 | 1493 | .article-title::after { 1494 | width: 40px; 1495 | height: 5px; 1496 | } 1497 | 1498 | .icon-box { 1499 | width: 48px; 1500 | height: 48px; 1501 | border-radius: 12px; 1502 | font-size: 18px; 1503 | } 1504 | 1505 | 1506 | 1507 | /** 1508 | * #MAIN 1509 | */ 1510 | 1511 | main { 1512 | margin-top: 60px; 1513 | margin-bottom: 100px; 1514 | } 1515 | 1516 | 1517 | 1518 | /** 1519 | * #SIDEBAR 1520 | */ 1521 | 1522 | .sidebar { 1523 | max-height: 180px; 1524 | margin-bottom: 30px; 1525 | } 1526 | 1527 | .sidebar.active { 1528 | max-height: max-content; 1529 | } 1530 | 1531 | .sidebar-info { 1532 | gap: 25px; 1533 | } 1534 | 1535 | .avatar-box { 1536 | border-radius: 30px; 1537 | } 1538 | 1539 | .avatar-box img { 1540 | width: 120px; 1541 | } 1542 | 1543 | .info-content .name { 1544 | margin-bottom: 15px; 1545 | } 1546 | 1547 | .info-content .title { 1548 | padding: 5px 18px; 1549 | } 1550 | 1551 | .info_more-btn { 1552 | top: -30px; 1553 | right: -30px; 1554 | padding: 10px 15px; 1555 | } 1556 | 1557 | .info_more-btn span { 1558 | display: block; 1559 | font-size: var(--fs-8); 1560 | } 1561 | 1562 | .info_more-btn ion-icon { 1563 | display: none; 1564 | } 1565 | 1566 | .separator { 1567 | margin: 32px 0; 1568 | } 1569 | 1570 | .contacts-list { 1571 | gap: 20px; 1572 | } 1573 | 1574 | .contact-info { 1575 | max-width: calc(100% - 64px); 1576 | width: calc(100% - 64px); 1577 | } 1578 | 1579 | 1580 | 1581 | /** 1582 | * #NAVBAR 1583 | */ 1584 | 1585 | .navbar { 1586 | border-radius: 20px 20px 0 0; 1587 | } 1588 | 1589 | .navbar-list { 1590 | gap: 20px; 1591 | } 1592 | 1593 | .navbar-link { 1594 | --fs-8: 14px; 1595 | } 1596 | 1597 | 1598 | 1599 | /** 1600 | * #ABOUT 1601 | */ 1602 | 1603 | .about .article-title { 1604 | margin-bottom: 20px; 1605 | } 1606 | 1607 | .about-text { 1608 | margin-bottom: 40px; 1609 | } 1610 | 1611 | /* service */ 1612 | 1613 | .service-item { 1614 | display: flex; 1615 | justify-content: flex-start; 1616 | align-items: flex-start; 1617 | gap: 18px; 1618 | padding: 30px; 1619 | } 1620 | 1621 | .service-icon-box { 1622 | margin-bottom: 0; 1623 | margin-top: 5px; 1624 | } 1625 | 1626 | .service-content-box { 1627 | text-align: left; 1628 | } 1629 | 1630 | /* testimonials */ 1631 | 1632 | .testimonials-title { 1633 | margin-bottom: 25px; 1634 | } 1635 | 1636 | .testimonials-list { 1637 | gap: 30px; 1638 | margin: 0 -30px; 1639 | padding: 30px; 1640 | padding-bottom: 35px; 1641 | } 1642 | 1643 | .content-card { 1644 | padding: 30px; 1645 | padding-top: 25px; 1646 | } 1647 | 1648 | .testimonials-avatar-box { 1649 | transform: translate(30px, -30px); 1650 | border-radius: 20px; 1651 | } 1652 | 1653 | .testimonials-avatar-box img { 1654 | width: 80px; 1655 | } 1656 | 1657 | .testimonials-item-title { 1658 | margin-bottom: 10px; 1659 | margin-left: 95px; 1660 | } 1661 | 1662 | .testimonials-text { 1663 | line-clamp: 2; 1664 | -webkit-line-clamp: 2; 1665 | } 1666 | 1667 | /* testimonials modal */ 1668 | 1669 | .modal-container { 1670 | padding: 20px; 1671 | } 1672 | 1673 | .testimonials-modal { 1674 | display: flex; 1675 | justify-content: flex-start; 1676 | align-items: stretch; 1677 | gap: 25px; 1678 | padding: 30px; 1679 | border-radius: 20px; 1680 | } 1681 | 1682 | .modal-img-wrapper { 1683 | display: flex; 1684 | flex-direction: column; 1685 | align-items: center; 1686 | } 1687 | 1688 | .modal-avatar-box { 1689 | border-radius: 18px; 1690 | margin-bottom: 0; 1691 | } 1692 | 1693 | .modal-avatar-box img { 1694 | width: 65px; 1695 | } 1696 | 1697 | .modal-img-wrapper>img { 1698 | display: block; 1699 | flex-grow: 1; 1700 | width: 35px; 1701 | } 1702 | 1703 | /* clients */ 1704 | 1705 | .clients-list { 1706 | gap: 50px; 1707 | margin: 0 -30px; 1708 | padding: 45px; 1709 | scroll-padding-inline: 45px; 1710 | } 1711 | 1712 | .clients-item { 1713 | min-width: calc(33.33% - 35px); 1714 | } 1715 | 1716 | 1717 | 1718 | /** 1719 | * #RESUME 1720 | */ 1721 | 1722 | .timeline-list { 1723 | margin-left: 65px; 1724 | } 1725 | 1726 | .timeline-item:not(:last-child)::before { 1727 | left: -40px; 1728 | } 1729 | 1730 | .timeline-item::after { 1731 | height: 8px; 1732 | width: 8px; 1733 | left: -43px; 1734 | } 1735 | 1736 | .skills-item:not(:last-child) { 1737 | margin-bottom: 25px; 1738 | } 1739 | 1740 | 1741 | 1742 | /** 1743 | * #PORTFOLIO, BLOG 1744 | */ 1745 | 1746 | .project-img, 1747 | .blog-banner-box { 1748 | border-radius: 16px; 1749 | } 1750 | 1751 | .blog-posts-list { 1752 | gap: 30px; 1753 | } 1754 | 1755 | .blog-content { 1756 | padding: 25px; 1757 | } 1758 | 1759 | 1760 | 1761 | /** 1762 | * #CONTACT 1763 | */ 1764 | 1765 | .mapbox { 1766 | height: 380px; 1767 | border-radius: 18px; 1768 | } 1769 | 1770 | .input-wrapper { 1771 | gap: 30px; 1772 | margin-bottom: 30px; 1773 | } 1774 | 1775 | .form-input { 1776 | padding: 15px 20px; 1777 | } 1778 | 1779 | textarea.form-input { 1780 | margin-bottom: 30px; 1781 | } 1782 | 1783 | .form-btn { 1784 | --fs-6: 16px; 1785 | padding: 16px 20px; 1786 | } 1787 | 1788 | .form-btn ion-icon { 1789 | font-size: 18px; 1790 | } 1791 | 1792 | } 1793 | 1794 | 1795 | 1796 | 1797 | 1798 | /** 1799 | * responsive larger than 768px screen 1800 | */ 1801 | 1802 | @media (min-width: 768px) { 1803 | 1804 | /** 1805 | * REUSED STYLE 1806 | */ 1807 | 1808 | .sidebar, 1809 | article { 1810 | width: 700px; 1811 | } 1812 | 1813 | .has-scrollbar::-webkit-scrollbar-button { 1814 | width: 100px; 1815 | } 1816 | 1817 | 1818 | 1819 | /** 1820 | * SIDEBAR 1821 | */ 1822 | 1823 | .contacts-list { 1824 | grid-template-columns: 1fr 1fr; 1825 | gap: 30px 15px; 1826 | } 1827 | 1828 | 1829 | 1830 | /** 1831 | * NAVBAR 1832 | */ 1833 | 1834 | .navbar-link { 1835 | --fs-8: 15px; 1836 | } 1837 | 1838 | 1839 | 1840 | /** 1841 | * ABOUT 1842 | */ 1843 | 1844 | /* testimonials modal */ 1845 | 1846 | .testimonials-modal { 1847 | gap: 35px; 1848 | max-width: 680px; 1849 | } 1850 | 1851 | .modal-avatar-box img { 1852 | width: 80px; 1853 | } 1854 | 1855 | 1856 | 1857 | /** 1858 | * PORTFOLIO 1859 | */ 1860 | 1861 | .article-title { 1862 | padding-bottom: 20px; 1863 | } 1864 | 1865 | .filter-select-box { 1866 | display: none; 1867 | } 1868 | 1869 | .filter-list { 1870 | display: flex; 1871 | justify-content: flex-start; 1872 | align-items: center; 1873 | gap: 25px; 1874 | padding-left: 5px; 1875 | margin-bottom: 30px; 1876 | } 1877 | 1878 | .filter-item a { 1879 | color: var(--light-gray); 1880 | font-size: var(--fs-5); 1881 | transition: var(--transition-1); 1882 | } 1883 | 1884 | .filter-item a:hover { 1885 | color: var(--light-gray-70); 1886 | } 1887 | 1888 | .filter-item a.active { 1889 | color: var(--orange-yellow-crayola); 1890 | } 1891 | 1892 | /* portfolio and blog grid */ 1893 | 1894 | .project-list, 1895 | .blog-posts-list { 1896 | grid-template-columns: 1fr 1fr; 1897 | } 1898 | 1899 | 1900 | 1901 | /** 1902 | * CONTACT 1903 | */ 1904 | 1905 | .input-wrapper { 1906 | grid-template-columns: 1fr 1fr; 1907 | } 1908 | 1909 | .form-btn { 1910 | width: max-content; 1911 | margin-left: auto; 1912 | } 1913 | 1914 | } 1915 | 1916 | 1917 | 1918 | 1919 | 1920 | /** 1921 | * responsive larger than 1024px screen 1922 | */ 1923 | 1924 | @media (min-width: 1024px) { 1925 | 1926 | /** 1927 | * CUSTOM PROPERTY 1928 | */ 1929 | 1930 | :root { 1931 | 1932 | /** 1933 | * shadow 1934 | */ 1935 | 1936 | --shadow-1: -4px 8px 24px hsla(0, 0%, 0%, 0.125); 1937 | --shadow-2: 0 16px 30px hsla(0, 0%, 0%, 0.125); 1938 | --shadow-3: 0 16px 40px hsla(0, 0%, 0%, 0.125); 1939 | 1940 | } 1941 | 1942 | 1943 | 1944 | /** 1945 | * REUSED STYLE 1946 | */ 1947 | 1948 | .sidebar, 1949 | article { 1950 | width: 950px; 1951 | box-shadow: var(--shadow-5); 1952 | } 1953 | 1954 | 1955 | 1956 | /** 1957 | * MAIN 1958 | */ 1959 | 1960 | main { 1961 | margin-bottom: 60px; 1962 | } 1963 | 1964 | .main-content { 1965 | position: relative; 1966 | width: max-content; 1967 | margin: auto; 1968 | } 1969 | 1970 | 1971 | 1972 | /** 1973 | * NAVBAR 1974 | */ 1975 | 1976 | .navbar { 1977 | position: absolute; 1978 | bottom: auto; 1979 | top: 0; 1980 | left: auto; 1981 | right: 0; 1982 | width: max-content; 1983 | border-radius: 0 20px; 1984 | padding: 0 20px; 1985 | box-shadow: none; 1986 | } 1987 | 1988 | .navbar-list { 1989 | gap: 30px; 1990 | padding: 0 20px; 1991 | } 1992 | 1993 | .navbar-link { 1994 | font-weight: var(--fw-500); 1995 | } 1996 | 1997 | 1998 | 1999 | /** 2000 | * ABOUT 2001 | */ 2002 | 2003 | /* service */ 2004 | 2005 | .service-list { 2006 | grid-template-columns: 1fr 1fr; 2007 | gap: 20px 25px; 2008 | } 2009 | 2010 | /* testimonials */ 2011 | 2012 | .testimonials-item { 2013 | min-width: calc(50% - 15px); 2014 | } 2015 | 2016 | /* clients */ 2017 | 2018 | .clients-item { 2019 | min-width: calc(25% - 38px); 2020 | } 2021 | 2022 | 2023 | 2024 | /** 2025 | * PORTFOLIO 2026 | */ 2027 | 2028 | .project-list { 2029 | grid-template-columns: repeat(3, 1fr); 2030 | } 2031 | 2032 | 2033 | 2034 | /** 2035 | * BLOG 2036 | */ 2037 | 2038 | .blog-banner-box { 2039 | height: 230px; 2040 | } 2041 | 2042 | } 2043 | 2044 | 2045 | 2046 | 2047 | 2048 | /** 2049 | * responsive larger than 1250px screen 2050 | */ 2051 | 2052 | @media (min-width: 1250px) { 2053 | 2054 | /** 2055 | * RESET 2056 | */ 2057 | 2058 | body::-webkit-scrollbar { 2059 | width: 20px; 2060 | } 2061 | 2062 | body::-webkit-scrollbar-track { 2063 | background: var(--smoky-black); 2064 | } 2065 | 2066 | body::-webkit-scrollbar-thumb { 2067 | border: 5px solid var(--smoky-black); 2068 | background: hsla(0, 0%, 100%, 0.1); 2069 | border-radius: 20px; 2070 | box-shadow: inset 1px 1px 0 hsla(0, 0%, 100%, 0.11), 2071 | inset -1px -1px 0 hsla(0, 0%, 100%, 0.11); 2072 | } 2073 | 2074 | body::-webkit-scrollbar-thumb:hover { 2075 | background: hsla(0, 0%, 100%, 0.15); 2076 | } 2077 | 2078 | body::-webkit-scrollbar-button { 2079 | height: 60px; 2080 | } 2081 | 2082 | 2083 | 2084 | /** 2085 | * REUSED STYLE 2086 | */ 2087 | 2088 | .sidebar, 2089 | article { 2090 | width: auto; 2091 | } 2092 | 2093 | article { 2094 | min-height: inherit; 2095 | } 2096 | 2097 | 2098 | 2099 | /** 2100 | * MAIN 2101 | */ 2102 | 2103 | main { 2104 | max-width: 1200px; 2105 | margin-inline: auto; 2106 | display: flex; 2107 | justify-content: center; 2108 | align-items: stretch; 2109 | gap: 25px; 2110 | } 2111 | 2112 | .main-content { 2113 | min-width: 75%; 2114 | width: 75%; 2115 | margin: 0; 2116 | } 2117 | 2118 | 2119 | 2120 | /** 2121 | * SIDEBAR 2122 | */ 2123 | 2124 | .sidebar { 2125 | position: sticky; 2126 | top: 60px; 2127 | max-height: max-content; 2128 | height: 100%; 2129 | margin-bottom: 0; 2130 | padding-top: 60px; 2131 | z-index: 1; 2132 | } 2133 | 2134 | .sidebar-info { 2135 | flex-direction: column; 2136 | } 2137 | 2138 | .avatar-box img { 2139 | width: 150px; 2140 | } 2141 | 2142 | .info-content .name { 2143 | white-space: nowrap; 2144 | text-align: center; 2145 | } 2146 | 2147 | .info-content .title { 2148 | margin: auto; 2149 | } 2150 | 2151 | .info_more-btn { 2152 | display: none; 2153 | } 2154 | 2155 | .sidebar-info_more { 2156 | opacity: 1; 2157 | visibility: visible; 2158 | } 2159 | 2160 | .contacts-list { 2161 | grid-template-columns: 1fr; 2162 | } 2163 | 2164 | .contact-info :is(.contact-link) { 2165 | white-space: nowrap; 2166 | overflow: unset; 2167 | text-overflow: ellipsis; 2168 | } 2169 | 2170 | .contact-info :is(.contact-link, time, address) { 2171 | --fs-7: 14px; 2172 | font-weight: var(--fw-300); 2173 | } 2174 | 2175 | .separator:last-of-type { 2176 | margin: 15px 0; 2177 | opacity: 0; 2178 | } 2179 | 2180 | .social-list { 2181 | justify-content: center; 2182 | } 2183 | 2184 | 2185 | 2186 | /** 2187 | * RESUME 2188 | */ 2189 | 2190 | .timeline-text { 2191 | max-width: 700px; 2192 | } 2193 | 2194 | } 2195 | 2196 | .pagination { 2197 | display: flex; 2198 | flex-wrap: wrap; 2199 | justify-content: center; 2200 | width: 100%; 2201 | } 2202 | 2203 | .pagination a { 2204 | margin-left: 10px; 2205 | } 2206 | 2207 | .pagination>span { 2208 | margin-left: 10px; 2209 | } 2210 | 2211 | .justify-content-center { 2212 | -ms-flex-pack: center !important; 2213 | justify-content: center !important; 2214 | } 2215 | 2216 | .index-paination { 2217 | margin-top: 1.875rem; 2218 | } 2219 | 2220 | .flex { 2221 | display: flex; 2222 | } 2223 | 2224 | .post-content h1, 2225 | .post-content h2, 2226 | .post-content h3, 2227 | .post-content h4, 2228 | .post-content h5, 2229 | .post-content h6 { 2230 | line-height: 1.5; 2231 | margin-bottom: 0.5rem; 2232 | } 2233 | 2234 | .post-content a { 2235 | display: inline; 2236 | } 2237 | 2238 | .post-content ul { 2239 | padding-inline-start: 30px; 2240 | } 2241 | 2242 | .post-content li { 2243 | list-style-type: disc; 2244 | } 2245 | 2246 | .post-content p { 2247 | margin-bottom: 1rem; 2248 | } 2249 | 2250 | .post-content img { 2251 | max-width: 100%; 2252 | } 2253 | 2254 | .post-content blockquote { 2255 | border-left: 0.25em solid #d0d7de; 2256 | padding: 0 1em; 2257 | margin-bottom: 1rem; 2258 | } 2259 | 2260 | .post-content blockquote span { 2261 | display: inline; 2262 | } 2263 | 2264 | .post-comment { 2265 | margin-top: 50px; 2266 | } 2267 | 2268 | .post-content code { 2269 | border-radius: .5em; 2270 | } 2271 | 2272 | .post-content code span { 2273 | display: inline; 2274 | } 2275 | 2276 | code, 2277 | hr { 2278 | margin-bottom: 10px; 2279 | } 2280 | 2281 | /* 添加侧边栏信息样式 */ 2282 | .sidebar-info { 2283 | padding: 0; 2284 | text-align: left; 2285 | font-size: var(--fs-8); 2286 | color: var(--light-gray); 2287 | } 2288 | 2289 | .sidebar-info .beian, 2290 | .sidebar-info .gongan, 2291 | .sidebar-info .copyright { 2292 | margin: 3px 0; /* 减小行间距 */ 2293 | display: flex; 2294 | align-items: center; 2295 | gap: 3px; /* 减小内部元素间距 */ 2296 | } 2297 | 2298 | .sidebar-info .copyright { 2299 | margin-top: 6px; /* 调整版权信息上方间距 */ 2300 | font-size: var(--fs-8); 2301 | opacity: 0.9; 2302 | flex-direction: column; 2303 | align-items: flex-start; 2304 | gap: 2px; /* 减小版权信息两行之间的间距 */ 2305 | } 2306 | 2307 | .sidebar-info .copyright > div { 2308 | display: flex; 2309 | align-items: center; 2310 | gap: 3px; /* 控制年份和网站名称之间的间距 */ 2311 | white-space: nowrap; /* 防止换行 */ 2312 | } 2313 | 2314 | /* 在大屏幕下的样式调整 */ 2315 | @media (min-width: 1250px) { 2316 | .sidebar-info { 2317 | padding: 0 15px; 2318 | } 2319 | 2320 | .sidebar-info .beian, 2321 | .sidebar-info .gongan, 2322 | .sidebar-info .copyright { 2323 | justify-content: center; 2324 | } 2325 | 2326 | .sidebar-info .copyright { 2327 | align-items: center; 2328 | } 2329 | 2330 | .sidebar-info .copyright > div { 2331 | justify-content: center; /* 大屏幕下居中对齐 */ 2332 | } 2333 | } 2334 | 2335 | /* 添加新的页脚信息样式 */ 2336 | .footer-info { 2337 | margin-top: 15px; 2338 | padding: 0; 2339 | text-align: center; 2340 | font-size: var(--fs-8); 2341 | color: var(--light-gray); 2342 | width: 100%; 2343 | } 2344 | 2345 | .footer-info .beian, 2346 | .footer-info .gongan, 2347 | .footer-info .copyright { 2348 | margin: 2px 0; 2349 | display: flex; 2350 | align-items: center; 2351 | justify-content: center; 2352 | gap: 3px; 2353 | } 2354 | 2355 | .footer-info .copyright { 2356 | margin-top: 4px; 2357 | font-size: var(--fs-8); 2358 | opacity: 0.9; 2359 | flex-direction: column; 2360 | align-items: center; 2361 | gap: 2px; 2362 | } 2363 | 2364 | .footer-info .copyright > div { 2365 | display: flex; 2366 | align-items: center; 2367 | justify-content: center; 2368 | gap: 3px; 2369 | white-space: nowrap; 2370 | } 2371 | 2372 | /* 备案图标垂直对齐优化 */ 2373 | .footer-info .gongan img { 2374 | height: 12px; 2375 | margin-right: 3px; 2376 | vertical-align: middle; 2377 | display: inline-block; 2378 | } 2379 | 2380 | /* 链接样式优化 */ 2381 | .footer-info a { 2382 | color: var(--light-gray-70); 2383 | text-decoration: none; 2384 | transition: var(--transition-1); 2385 | display: inline-block; 2386 | } 2387 | 2388 | .footer-info a:hover { 2389 | color: var(--light-gray); 2390 | } 2391 | 2392 | /* 大屏幕下的样式保持不变 */ 2393 | @media (min-width: 1250px) { 2394 | .footer-info { 2395 | padding: 0 15px; 2396 | } 2397 | } 2398 | 2399 | /* 修改内联元素的显示方式 */ 2400 | .post-content span, 2401 | .post-content strong, 2402 | .post-content em, 2403 | .post-content code:not(pre code), 2404 | .post-content a { 2405 | display: inline; 2406 | } 2407 | 2408 | /* 修改列表项内容的样式 */ 2409 | .post-content li p { 2410 | display: block; 2411 | margin-bottom: 0.5rem; 2412 | } 2413 | 2414 | /* 确保列表项内的内联元素正确显示 */ 2415 | .post-content li * { 2416 | display: inline; 2417 | } 2418 | 2419 | /* 特殊处理列表项内的块级元素 */ 2420 | .post-content li > pre, 2421 | .post-content li > blockquote, 2422 | .post-content li > div { 2423 | display: block; 2424 | margin: 0.5rem 0; 2425 | } 2426 | 2427 | /* 在大屏幕下隐藏下拉框 */ 2428 | @media (min-width: 768px) { 2429 | .filter-select-box { 2430 | display: none; 2431 | } 2432 | } 2433 | 2434 | .link-info a.flex { 2435 | width: 100%; 2436 | display: flex; 2437 | align-items: center; 2438 | } 2439 | 2440 | /* 瞬间相关样式 */ 2441 | .moment-tags { 2442 | margin-bottom: 30px; 2443 | } 2444 | 2445 | .moments-list .blog-post-item { 2446 | padding: 30px; 2447 | border-radius: 16px; 2448 | box-shadow: var(--shadow-2); 2449 | margin-bottom: 25px; 2450 | background: var(--eerie-black-2); 2451 | border: 1px solid var(--jet); 2452 | width: 100%; 2453 | } 2454 | 2455 | .moment-text { 2456 | color: var(--light-gray); 2457 | font-size: var(--fs-6); 2458 | line-height: 1.6; 2459 | margin-bottom: 15px; 2460 | word-wrap: break-word; 2461 | overflow-wrap: break-word; 2462 | white-space: pre-wrap; 2463 | } 2464 | 2465 | .moment-text a { 2466 | color: var(--orange-yellow-crayola); 2467 | word-wrap: break-word; 2468 | overflow-wrap: break-word; 2469 | display: inline-block; 2470 | max-width: 100%; 2471 | } 2472 | 2473 | .moment-text a:hover { 2474 | text-decoration: underline; 2475 | } 2476 | 2477 | .moment-media { 2478 | margin: 15px 0; 2479 | display: grid; 2480 | grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); 2481 | gap: 15px; 2482 | } 2483 | 2484 | .moment-img { 2485 | position: relative; 2486 | border-radius: 12px; 2487 | overflow: hidden; 2488 | aspect-ratio: 1; 2489 | } 2490 | 2491 | .moment-img img { 2492 | width: 100%; 2493 | height: 100%; 2494 | object-fit: cover; 2495 | border-radius: 12px; 2496 | transition: transform 0.3s ease; 2497 | } 2498 | 2499 | .moment-img:hover img { 2500 | transform: scale(1.05); 2501 | } 2502 | 2503 | .moment-video, 2504 | .moment-audio { 2505 | width: 100%; 2506 | border-radius: 12px; 2507 | overflow: hidden; 2508 | } 2509 | 2510 | .moment-video video, 2511 | .moment-audio audio { 2512 | width: 100%; 2513 | border-radius: 12px; 2514 | background: var(--onyx); 2515 | } 2516 | 2517 | /* 移动端适配 */ 2518 | @media (max-width: 580px) { 2519 | .moments-list .blog-post-item { 2520 | padding: 20px; 2521 | width: 100%; 2522 | } 2523 | 2524 | .moment-text, 2525 | .moment-text a { 2526 | font-size: var(--fs-7); 2527 | } 2528 | } 2529 | 2530 | /* 标签样式优化 */ 2531 | .moment-tags { 2532 | margin-bottom: 30px; 2533 | } 2534 | 2535 | .moment-tags .filter-list { 2536 | display: flex; 2537 | flex-wrap: wrap; 2538 | gap: 10px; 2539 | padding: 0 5px; 2540 | } 2541 | 2542 | .moment-tags .filter-item a { 2543 | color: var(--light-gray); 2544 | background: var(--onyx); 2545 | font-size: var(--fs-7); 2546 | font-weight: var(--fw-300); 2547 | padding: 5px 15px; 2548 | border-radius: 8px; 2549 | transition: var(--transition-1); 2550 | } 2551 | 2552 | .moment-tags .filter-item a:hover, 2553 | .moment-tags .filter-item a.active { 2554 | color: var(--orange-yellow-crayola); 2555 | background: var(--jet); 2556 | } 2557 | 2558 | /* 瞬间作者信息样式 */ 2559 | .moment-author { 2560 | display: flex; 2561 | align-items: center; 2562 | gap: 12px; 2563 | margin-bottom: 15px; 2564 | } 2565 | 2566 | .author-avatar { 2567 | width: 48px; 2568 | height: 48px; 2569 | border-radius: 50%; 2570 | object-fit: cover; 2571 | } 2572 | 2573 | .author-name { 2574 | color: var(--white-2); 2575 | font-size: var(--fs-6); 2576 | font-weight: var(--fw-500); 2577 | } 2578 | 2579 | /* 视频播放按钮样式 */ 2580 | .video-wrapper { 2581 | position: relative; 2582 | border-radius: 12px; 2583 | overflow: hidden; 2584 | } 2585 | 2586 | .video-play-btn { 2587 | position: absolute; 2588 | top: 50%; 2589 | left: 50%; 2590 | transform: translate(-50%, -50%); 2591 | background: rgba(0, 0, 0, 0.5); 2592 | border-radius: 50%; 2593 | width: 48px; 2594 | height: 48px; 2595 | display: flex; 2596 | align-items: center; 2597 | justify-content: center; 2598 | cursor: pointer; 2599 | transition: var(--transition-1); 2600 | } 2601 | 2602 | .video-play-btn:hover { 2603 | background: rgba(0, 0, 0, 0.7); 2604 | } 2605 | 2606 | .video-play-btn ion-icon { 2607 | color: var(--white-1); 2608 | font-size: 24px; 2609 | } 2610 | 2611 | /* 瞬间元信息样式 */ 2612 | .moment-meta { 2613 | display: flex; 2614 | align-items: center; 2615 | gap: 20px; 2616 | margin-top: 15px; 2617 | } 2618 | 2619 | .meta-item { 2620 | display: flex; 2621 | align-items: center; 2622 | gap: 5px; 2623 | color: var(--light-gray); 2624 | font-size: var(--fs-7); 2625 | cursor: pointer; 2626 | transition: var(--transition-1); 2627 | } 2628 | 2629 | .meta-item:hover { 2630 | color: var(--orange-yellow-crayola); 2631 | } 2632 | 2633 | .meta-item ion-icon { 2634 | font-size: 18px; 2635 | } 2636 | 2637 | .like-btn { 2638 | cursor: pointer; 2639 | } 2640 | 2641 | .like-btn.active { 2642 | color: var(--orange-yellow-crayola); 2643 | } 2644 | 2645 | /* 评论区样式 */ 2646 | .moment-comments { 2647 | margin-top: 20px; 2648 | padding-top: 20px; 2649 | } 2650 | 2651 | .moment-comments .separator { 2652 | margin: 0 0 20px; 2653 | } 2654 | 2655 | /* 点赞按钮样式 */ 2656 | .like-btn:not(.can-like) { 2657 | cursor: not-allowed; 2658 | opacity: 0.7; 2659 | } 2660 | 2661 | .like-btn.active ion-icon { 2662 | color: var(--orange-yellow-crayola); 2663 | animation: likeAnimation 0.3s ease; 2664 | } 2665 | 2666 | @keyframes likeAnimation { 2667 | 0% { transform: scale(1); } 2668 | 50% { transform: scale(1.2); } 2669 | 100% { transform: scale(1); } 2670 | } 2671 | 2672 | /* 评论按钮激活状态 */ 2673 | .comment-btn.active { 2674 | color: var(--orange-yellow-crayola); 2675 | } -------------------------------------------------------------------------------- /templates/assets/images/gongan_beian.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Anyexyz/theme-vcard4/6e8ea75de116e785aa6eca660bd1d4bbb65e5987/templates/assets/images/gongan_beian.webp -------------------------------------------------------------------------------- /templates/assets/images/halo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Anyexyz/theme-vcard4/6e8ea75de116e785aa6eca660bd1d4bbb65e5987/templates/assets/images/halo.jpg -------------------------------------------------------------------------------- /templates/assets/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /templates/assets/js/script.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // 元素切换功能 4 | const elementToggleFunc = function (elem) { elem.classList.toggle("active"); } 5 | 6 | // 侧边栏变量 7 | const sidebar = document.querySelector("[data-sidebar]"); 8 | const sidebarBtn = document.querySelector("[data-sidebar-btn]"); 9 | 10 | // 侧边栏移动端切换功能 11 | sidebarBtn.addEventListener("click", function () { elementToggleFunc(sidebar); }); 12 | 13 | 14 | // testimonials variables 15 | const testimonialsItem = document.querySelectorAll("[data-testimonials-item]"); 16 | const modalContainer = document.querySelector("[data-modal-container]"); 17 | const modalCloseBtn = document.querySelector("[data-modal-close-btn]"); 18 | const overlay = document.querySelector("[data-overlay]"); 19 | 20 | // modal variable 21 | const modalImg = document.querySelector("[data-modal-img]"); 22 | const modalTitle = document.querySelector("[data-modal-title]"); 23 | const modalText = document.querySelector("[data-modal-text]"); 24 | 25 | // modal toggle function 26 | const testimonialsModalFunc = function () { 27 | modalContainer.classList.toggle("active"); 28 | overlay.classList.toggle("active"); 29 | } 30 | 31 | // add click event to all modal items 32 | for (let i = 0; i < testimonialsItem.length; i++) { 33 | 34 | testimonialsItem[i].addEventListener("click", function () { 35 | 36 | modalImg.src = this.querySelector("[data-testimonials-avatar]").src; 37 | modalImg.alt = this.querySelector("[data-testimonials-avatar]").alt; 38 | modalTitle.innerHTML = this.querySelector("[data-testimonials-title]").innerHTML; 39 | modalText.innerHTML = this.querySelector("[data-testimonials-text]").innerHTML; 40 | 41 | testimonialsModalFunc(); 42 | 43 | }); 44 | 45 | } 46 | 47 | // add click event to modal close button 48 | // modalCloseBtn.addEventListener("click", testimonialsModalFunc); 49 | // overlay.addEventListener("click", testimonialsModalFunc); 50 | 51 | 52 | 53 | // custom select variables 54 | const select = document.querySelector("[data-select]"); 55 | const selectItems = document.querySelectorAll("[data-select-item]"); 56 | const selectValue = document.querySelector("[data-selecct-value]"); 57 | const filterBtn = document.querySelectorAll("[data-filter-btn]"); 58 | 59 | // select.addEventListener("click", function () { elementToggleFunc(this); }); 60 | 61 | // add event in all select items 62 | for (let i = 0; i < selectItems.length; i++) { 63 | selectItems[i].addEventListener("click", function () { 64 | 65 | let selectedValue = this.innerText.toLowerCase(); 66 | selectValue.innerText = this.innerText; 67 | elementToggleFunc(select); 68 | filterFunc(selectedValue); 69 | 70 | }); 71 | } 72 | 73 | // filter variables 74 | const filterItems = document.querySelectorAll("[data-filter-item]"); 75 | 76 | const filterFunc = function (selectedValue) { 77 | 78 | for (let i = 0; i < filterItems.length; i++) { 79 | 80 | if (selectedValue === "all") { 81 | filterItems[i].classList.add("active"); 82 | } else if (selectedValue === filterItems[i].dataset.category) { 83 | filterItems[i].classList.add("active"); 84 | } else { 85 | filterItems[i].classList.remove("active"); 86 | } 87 | 88 | } 89 | 90 | } 91 | 92 | // add event in all filter button items for large screen 93 | let lastClickedBtn = filterBtn[0]; 94 | 95 | for (let i = 0; i < filterBtn.length; i++) { 96 | 97 | filterBtn[i].addEventListener("click", function () { 98 | 99 | let selectedValue = this.innerText.toLowerCase(); 100 | selectValue.innerText = this.innerText; 101 | filterFunc(selectedValue); 102 | 103 | lastClickedBtn.classList.remove("active"); 104 | this.classList.add("active"); 105 | lastClickedBtn = this; 106 | 107 | }); 108 | 109 | } 110 | 111 | 112 | 113 | // contact form variables 114 | const form = document.querySelector("[data-form]"); 115 | const formInputs = document.querySelectorAll("[data-form-input]"); 116 | const formBtn = document.querySelector("[data-form-btn]"); 117 | 118 | // add event to all form input field 119 | for (let i = 0; i < formInputs.length; i++) { 120 | formInputs[i].addEventListener("input", function () { 121 | 122 | // check form validation 123 | if (form.checkValidity()) { 124 | formBtn.removeAttribute("disabled"); 125 | } else { 126 | formBtn.setAttribute("disabled", ""); 127 | } 128 | 129 | }); 130 | } 131 | 132 | 133 | 134 | // page navigation variables 135 | const navigationLinks = document.querySelectorAll("[data-nav-link]"); 136 | const pages = document.querySelectorAll("[data-page]"); 137 | 138 | // add event to all nav link 139 | for (let i = 0; i < navigationLinks.length; i++) { 140 | navigationLinks[i].addEventListener("click", function () { 141 | 142 | for (let i = 0; i < pages.length; i++) { 143 | if (this.innerHTML.toLowerCase() === pages[i].dataset.page) { 144 | pages[i].classList.add("active"); 145 | navigationLinks[i].classList.add("active"); 146 | window.scrollTo(0, 0); 147 | } else { 148 | pages[i].classList.remove("active"); 149 | navigationLinks[i].classList.remove("active"); 150 | } 151 | } 152 | 153 | }); 154 | } 155 | 156 | // 点赞功能 157 | // 处理点赞按钮点击事件 158 | const UpvoteManager = (group, plural) => { 159 | const STORAGE_KEY = `anatole.upvoted.${group}.names`; 160 | 161 | return { 162 | upvotedNames: [], 163 | init() { 164 | // 从 localStorage 中加载已点赞的名称 165 | this.upvotedNames = JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]"); 166 | }, 167 | upvoted(name) { 168 | // 检查是否已经点赞 169 | return this.upvotedNames.includes(name); 170 | }, 171 | async handleUpvote(name) { 172 | if (this.upvoted(name)) return; // 如果已经点赞,直接返回 173 | 174 | try { 175 | const response = await fetch("/apis/api.halo.run/v1alpha1/trackers/upvote", { 176 | method: "POST", 177 | headers: { 178 | "Content-Type": "application/json", 179 | }, 180 | body: JSON.stringify({ 181 | group, 182 | plural, 183 | name, 184 | }), 185 | }); 186 | 187 | if (!response.ok) { 188 | throw new Error("网络请求失败"); 189 | } 190 | 191 | // 更新本地存储和 UI 192 | this.upvotedNames = [...this.upvotedNames, name]; 193 | localStorage.setItem(STORAGE_KEY, JSON.stringify(this.upvotedNames)); 194 | 195 | const upvoteElement = document.querySelector(`[data="${name}"] span`); 196 | if (upvoteElement) { 197 | const currentCount = parseInt(upvoteElement.textContent || "0"); 198 | upvoteElement.textContent = currentCount + 1; 199 | } 200 | } catch (error) { 201 | console.error("点赞失败:", error); 202 | alert("网络请求失败,请稍后再试"); 203 | } 204 | }, 205 | }; 206 | }; 207 | 208 | // 初始化点赞管理器 209 | const momentUpvoteManager = UpvoteManager("moment.halo.run", "moments"); 210 | const postUpvoteManager = UpvoteManager("content.halo.run", "posts"); 211 | const pageUpvoteManager = UpvoteManager("content.halo.run", "singlepages"); 212 | 213 | momentUpvoteManager.init(); 214 | postUpvoteManager.init(); 215 | pageUpvoteManager.init(); 216 | 217 | // 绑定点赞按钮点击事件 218 | document.addEventListener("DOMContentLoaded", () => { 219 | const likeButtons = document.querySelectorAll(".like-btn"); 220 | 221 | likeButtons.forEach((button) => { 222 | button.addEventListener("click", (event) => { 223 | const name = button.getAttribute("data"); 224 | const type = button.getAttribute("data-type"); // 获取点赞类型 225 | 226 | // 根据类型调用对应的点赞管理器 227 | if (type === "moment") { 228 | momentUpvoteManager.handleUpvote(name); 229 | } else if (type === "content") { 230 | postUpvoteManager.handleUpvote(name); 231 | } else if (type === "singlepages") { 232 | pageUpvoteManager.handleUpvote(name); 233 | } 234 | }); 235 | }); 236 | 237 | 238 | // 评论功能 239 | const commentButtons = document.querySelectorAll('.comment-btn'); 240 | 241 | commentButtons.forEach(btn => { 242 | btn.addEventListener('click', function() { 243 | const momentName = this.dataset.moment; 244 | const commentsSection = document.getElementById(`comments-${momentName}`); 245 | 246 | // 切换评论区显示状态 247 | if (commentsSection.style.display === 'none') { 248 | commentsSection.style.display = 'block'; 249 | this.classList.add('active'); 250 | } else { 251 | commentsSection.style.display = 'none'; 252 | this.classList.remove('active'); 253 | } 254 | }); 255 | }); 256 | }); -------------------------------------------------------------------------------- /templates/categories.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 |
21 | 22 | 23 | 24 | 55 | 56 |
57 | 58 |
59 | 60 | 61 | 63 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /templates/category.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 |
21 | 22 | 23 | 24 | 57 | 58 |
59 | 60 |
61 | 62 | 63 | 65 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 60 |
61 | 62 |
63 | 64 | 65 | 67 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /templates/links.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 49 | 50 |
51 | 52 |
53 | 54 | 55 | 57 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /templates/modules/navbar.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /templates/modules/pagination.html: -------------------------------------------------------------------------------- 1 | 29 | -------------------------------------------------------------------------------- /templates/modules/sidebar.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /templates/moments.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 |
20 | 21 | 22 |
23 |
24 |

瞬间

25 |
26 | 27 | 28 |
29 | 40 |
41 | 42 | 43 |
44 |
    45 |
  • 47 | 48 |
    49 | 51 | 52 |
    53 | 54 |
    55 | 56 |
    58 |
    59 | 60 | 61 |
    62 | 63 | 64 |
    65 | 69 |
    70 | 71 |
    72 |
    73 | 74 |
    75 | 76 |
    77 |
    78 |
    79 | 80 |
    81 | 82 |
    83 |
    84 |
    85 | 86 | 87 |
    88 | 89 | 94 | 95 |
    96 | 97 | 98 |
    99 | 100 | 103 |
    104 | 105 | 106 | 112 |
    113 |
  • 114 |
115 |
116 | 117 | 118 |
119 |
120 |
121 |
122 |
123 |
124 | 125 | 126 | 128 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /templates/page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 |
20 | 21 | 22 | 23 |
24 |
25 |

26 |
27 |
28 |
29 |
30 | 31 |
32 |

评论

33 | 34 |
35 |
36 |
37 |
38 | 39 | 41 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /templates/photos.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 |
26 |
27 |

28 |
29 | 30 |
31 | 42 | 43 |
44 | 50 | 62 |
63 |
    64 |
  • 65 |
    66 | 71 |
    72 |
  • 73 |
74 | 75 |
76 |
77 |
78 | 79 |
80 | 81 |
82 | 83 |
84 | 85 |
86 | 87 | 88 | 90 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /templates/post.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 |
20 | 21 | 22 | 23 |
24 |
25 |

26 |
27 |
28 |
29 |
30 | 31 |
32 |

评论

33 | 34 |
35 |
36 |
37 |
38 | 39 | 41 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /templates/resume.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 |
21 | 22 | 23 |
24 |
25 |

26 |
27 | 28 |
29 | 30 |

31 |
32 |
33 | 34 |
35 |

36 |
    37 |
  • 39 |
    40 | 41 |
    42 |
    43 |

    44 |

    45 |
    46 |
  • 47 |
48 |
49 | 50 |
52 |
53 |
54 | 55 |
56 |

57 |
58 |
    59 |
  1. 60 |

    61 | 62 |

    63 |
  2. 64 |
65 |
66 | 67 |
68 |

69 |
    70 |
  • 71 |
    72 |
    73 | 74 |
    75 |
    76 |
    77 |
    78 |
  • 79 |
80 | 81 |
82 |

83 |
    84 |
  • 85 |
    86 |
    87 | ${evaluate_list.name} 88 |
    89 |

    90 |
    91 |

    92 |
    93 |
    94 |
  • 95 |
96 |
97 | 98 |
99 |

100 | 107 |
108 | 109 |
110 | 111 |
112 |
113 | 114 | 116 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /templates/tag.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

5 |
    6 |
  • 7 | 8 |
  • 9 |
10 | 上一页 11 | 下一页 12 |
13 | 14 | -------------------------------------------------------------------------------- /templates/tags.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

标签

5 |
    6 |
  • 7 | 8 |
  • 9 |
10 |
11 | 12 | -------------------------------------------------------------------------------- /theme.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: theme.halo.run/v1alpha1 2 | kind: Theme 3 | metadata: 4 | name: theme-vcard4 5 | annotations: 6 | "store.halo.run/app-id": "app-EFeTP" 7 | spec: 8 | displayName: Theme vCard4 9 | author: 10 | name: Anye 11 | website: https://www.anye.xyz 12 | description: vCard4 是一个响应式的个人作品集主题,可适配所有设备。 13 | logo: https://cdn.jsdelivr.net/gh/Anyexyz/theme-vcard4@main/templates/assets/images/logo.svg 14 | homepage: https://www.halo.run/store/apps/app-EFeTP 15 | repo: https://github.com/Anyexyz/theme-vcard4 16 | issues: https://github.com/Anyexyz/theme-vcard4/issues 17 | settingName: theme-vcard4-setting 18 | configMapName: theme-vcard4-configMap 19 | version: "1.1.1" 20 | requires: ">=2.19.0" 21 | license: 22 | - name: "GPL-3.0" 23 | url: https://github.com/Anyexyz/theme-vcard4/blob/main/LICENSE 24 | customTemplates: 25 | page: 26 | - name: 个人简历 27 | description: 个人简历页面模板 28 | screenshot: 29 | file: resume.html -------------------------------------------------------------------------------- /website-demo-image/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Anyexyz/theme-vcard4/6e8ea75de116e785aa6eca660bd1d4bbb65e5987/website-demo-image/Thumbs.db -------------------------------------------------------------------------------- /website-demo-image/desktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Anyexyz/theme-vcard4/6e8ea75de116e785aa6eca660bd1d4bbb65e5987/website-demo-image/desktop.png -------------------------------------------------------------------------------- /website-demo-image/mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Anyexyz/theme-vcard4/6e8ea75de116e785aa6eca660bd1d4bbb65e5987/website-demo-image/mobile.png --------------------------------------------------------------------------------