feat: 添加多个字体图标、样式文件和配置文件
新增了多个字体图标文件(SVG格式),包括品牌图标和常规图标。添加了相关的样式文件(LESS和SCSS)用于管理图标样式。更新了配置文件如.gitignore、composer.json和.htaccess等。新增了开发者相关的PHP文件如logout.php。添加了项目规则文档和字体相关的样式文件。
This commit is contained in:
2133
.VSCodeCounter/2025-07-08_12-45-16/details.md
Normal file
2133
.VSCodeCounter/2025-07-08_12-45-16/details.md
Normal file
File diff suppressed because it is too large
Load Diff
15
.VSCodeCounter/2025-07-08_12-45-16/diff-details.md
Normal file
15
.VSCodeCounter/2025-07-08_12-45-16/diff-details.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Diff Details
|
||||
|
||||
Date : 2025-07-08 12:45:16
|
||||
|
||||
Directory c:\\web\\app2
|
||||
|
||||
Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||
|
||||
## Files
|
||||
| filename | language | code | comment | blank | total |
|
||||
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||
2
.VSCodeCounter/2025-07-08_12-45-16/diff.csv
Normal file
2
.VSCodeCounter/2025-07-08_12-45-16/diff.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
"filename", "language", "", "comment", "blank", "total"
|
||||
"Total", "-", , 0, 0, 0
|
||||
|
19
.VSCodeCounter/2025-07-08_12-45-16/diff.md
Normal file
19
.VSCodeCounter/2025-07-08_12-45-16/diff.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Diff Summary
|
||||
|
||||
Date : 2025-07-08 12:45:16
|
||||
|
||||
Directory c:\\web\\app2
|
||||
|
||||
Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||
|
||||
## Languages
|
||||
| language | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
|
||||
## Directories
|
||||
| path | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||
22
.VSCodeCounter/2025-07-08_12-45-16/diff.txt
Normal file
22
.VSCodeCounter/2025-07-08_12-45-16/diff.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
Date : 2025-07-08 12:45:16
|
||||
Directory : c:\web\app2
|
||||
Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines
|
||||
|
||||
Languages
|
||||
+----------+------------+------------+------------+------------+------------+
|
||||
| language | files | code | comment | blank | total |
|
||||
+----------+------------+------------+------------+------------+------------+
|
||||
+----------+------------+------------+------------+------------+------------+
|
||||
|
||||
Directories
|
||||
+------+------------+------------+------------+------------+------------+
|
||||
| path | files | code | comment | blank | total |
|
||||
+------+------------+------------+------------+------------+------------+
|
||||
+------+------------+------------+------------+------------+------------+
|
||||
|
||||
Files
|
||||
+----------+----------+------------+------------+------------+------------+
|
||||
| filename | language | code | comment | blank | total |
|
||||
+----------+----------+------------+------------+------------+------------+
|
||||
| Total | | 0 | 0 | 0 | 0 |
|
||||
+----------+----------+------------+------------+------------+------------+
|
||||
2120
.VSCodeCounter/2025-07-08_12-45-16/results.csv
Normal file
2120
.VSCodeCounter/2025-07-08_12-45-16/results.csv
Normal file
File diff suppressed because it is too large
Load Diff
1
.VSCodeCounter/2025-07-08_12-45-16/results.json
Normal file
1
.VSCodeCounter/2025-07-08_12-45-16/results.json
Normal file
File diff suppressed because one or more lines are too long
46
.VSCodeCounter/2025-07-08_12-45-16/results.md
Normal file
46
.VSCodeCounter/2025-07-08_12-45-16/results.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Summary
|
||||
|
||||
Date : 2025-07-08 12:45:16
|
||||
|
||||
Directory c:\\web\\app2
|
||||
|
||||
Total : 2118 files, 346723 codes, 1364 comments, 3318 blanks, all 351405 lines
|
||||
|
||||
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
|
||||
## Languages
|
||||
| language | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| JSON | 3 | 207,518 | 0 | 0 | 207,518 |
|
||||
| YAML | 5 | 97,374 | 0 | 5 | 97,379 |
|
||||
| JavaScript | 15 | 14,387 | 794 | 1,677 | 16,858 |
|
||||
| XML | 2,023 | 8,089 | 15 | 0 | 8,104 |
|
||||
| SCSS | 19 | 6,938 | 99 | 575 | 7,612 |
|
||||
| Less | 18 | 6,907 | 72 | 570 | 7,549 |
|
||||
| PHP | 27 | 4,887 | 323 | 384 | 5,594 |
|
||||
| Python | 2 | 253 | 17 | 47 | 317 |
|
||||
| MS SQL | 2 | 191 | 31 | 31 | 253 |
|
||||
| CSS | 3 | 138 | 13 | 22 | 173 |
|
||||
| Markdown | 1 | 41 | 0 | 7 | 48 |
|
||||
|
||||
## Directories
|
||||
| path | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| . | 2,118 | 346,723 | 1,364 | 3,318 | 351,405 |
|
||||
| . (Files) | 13 | 1,816 | 173 | 204 | 2,193 |
|
||||
| admin | 10 | 1,981 | 102 | 156 | 2,239 |
|
||||
| css | 2 | 5 | 9 | 1 | 15 |
|
||||
| developer | 7 | 1,417 | 80 | 83 | 1,580 |
|
||||
| docs | 1 | 38 | 3 | 0 | 41 |
|
||||
| js | 15 | 14,387 | 794 | 1,677 | 16,858 |
|
||||
| less | 18 | 6,907 | 72 | 570 | 7,549 |
|
||||
| metadata | 8 | 304,892 | 0 | 5 | 304,897 |
|
||||
| scss | 19 | 6,938 | 99 | 575 | 7,612 |
|
||||
| sprites | 3 | 6,069 | 15 | 0 | 6,084 |
|
||||
| svgs | 2,020 | 2,020 | 0 | 0 | 2,020 |
|
||||
| svgs\\brands | 467 | 467 | 0 | 0 | 467 |
|
||||
| svgs\\regular | 163 | 163 | 0 | 0 | 163 |
|
||||
| svgs\\solid | 1,390 | 1,390 | 0 | 0 | 1,390 |
|
||||
| windows | 2 | 253 | 17 | 47 | 317 |
|
||||
|
||||
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
2167
.VSCodeCounter/2025-07-08_12-45-16/results.txt
Normal file
2167
.VSCodeCounter/2025-07-08_12-45-16/results.txt
Normal file
File diff suppressed because it is too large
Load Diff
2221
.VSCodeCounter/2025-07-09_15-40-50/details.md
Normal file
2221
.VSCodeCounter/2025-07-09_15-40-50/details.md
Normal file
File diff suppressed because it is too large
Load Diff
120
.VSCodeCounter/2025-07-09_15-40-50/diff-details.md
Normal file
120
.VSCodeCounter/2025-07-09_15-40-50/diff-details.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# Diff Details
|
||||
|
||||
Date : 2025-07-09 15:40:50
|
||||
|
||||
Directory c:\\web\\app2
|
||||
|
||||
Total : 105 files, 12779 codes, 4573 comments, 1852 blanks, all 19204 lines
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||
|
||||
## Files
|
||||
| filename | language | code | comment | blank | total |
|
||||
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||
| [.trae/rules/project_rules.md](/.trae/rules/project_rules.md) | Markdown | 4 | 0 | 3 | 7 |
|
||||
| [README.md](/README.md) | Markdown | 248 | 0 | 47 | 295 |
|
||||
| [admin/manage_developers.php](/admin/manage_developers.php) | PHP | 16 | 1 | 0 | 17 |
|
||||
| [admin/review_apps.php](/admin/review_apps.php) | PHP | 61 | 4 | 4 | 69 |
|
||||
| [api.php](/api.php) | PHP | 19 | 2 | 2 | 23 |
|
||||
| [app.php](/app.php) | PHP | 95 | 7 | 9 | 111 |
|
||||
| [app_store.sql](/app_store.sql) | MS SQL | 21 | 3 | 4 | 28 |
|
||||
| [app_store_update.sql](/app_store_update.sql) | MS SQL | -2 | -1 | 0 | -3 |
|
||||
| [composer.json](/composer.json) | JSON | 5 | 0 | 1 | 6 |
|
||||
| [composer.lock](/composer.lock) | JSON | 100 | 0 | 1 | 101 |
|
||||
| [config.php](/config.php) | PHP | -4 | 1 | 2 | -1 |
|
||||
| [developer/dashboard.php](/developer/dashboard.php) | PHP | 1 | 0 | 0 | 1 |
|
||||
| [developer/edit_app.php](/developer/edit_app.php) | PHP | -68 | 0 | 0 | -68 |
|
||||
| [developer/profile.php](/developer/profile.php) | PHP | -3 | 0 | 1 | -2 |
|
||||
| [developer/register.php](/developer/register.php) | PHP | 69 | 15 | 16 | 100 |
|
||||
| [developer/upload_app.php](/developer/upload_app.php) | PHP | 55 | 2 | 6 | 63 |
|
||||
| [developer/verify_email.php](/developer/verify_email.php) | PHP | 77 | 5 | 8 | 90 |
|
||||
| [developer/version_control.php](/developer/version_control.php) | PHP | 209 | 10 | 13 | 232 |
|
||||
| [developer_apps.php](/developer_apps.php) | PHP | 34 | 3 | 5 | 42 |
|
||||
| [docs/app_review_standards.php](/docs/app_review_standards.php) | PHP | 196 | 0 | 18 | 214 |
|
||||
| [docs/privacy_policy.php](/docs/privacy_policy.php) | PHP | 37 | 0 | 9 | 46 |
|
||||
| [includes/logger.php](/includes/logger.php) | PHP | 30 | 18 | 8 | 56 |
|
||||
| [index.php](/index.php) | PHP | -1 | 1 | 0 | 0 |
|
||||
| [js/bootstrap.bundle.js](/js/bootstrap.bundle.js) | JavaScript | 5,053 | 655 | 598 | 6,306 |
|
||||
| [mail/verification_template.php](/mail/verification_template.php) | PHP | 33 | 6 | 0 | 39 |
|
||||
| [vendor/autoload.php](/vendor/autoload.php) | PHP | 20 | 1 | 5 | 26 |
|
||||
| [vendor/composer/ClassLoader.php](/vendor/composer/ClassLoader.php) | PHP | 286 | 235 | 59 | 580 |
|
||||
| [vendor/composer/InstalledVersions.php](/vendor/composer/InstalledVersions.php) | PHP | 178 | 133 | 49 | 360 |
|
||||
| [vendor/composer/autoload_classmap.php](/vendor/composer/autoload_classmap.php) | PHP | 6 | 1 | 4 | 11 |
|
||||
| [vendor/composer/autoload_namespaces.php](/vendor/composer/autoload_namespaces.php) | PHP | 5 | 1 | 4 | 10 |
|
||||
| [vendor/composer/autoload_psr4.php](/vendor/composer/autoload_psr4.php) | PHP | 6 | 1 | 4 | 11 |
|
||||
| [vendor/composer/autoload_real.php](/vendor/composer/autoload_real.php) | PHP | 25 | 4 | 10 | 39 |
|
||||
| [vendor/composer/autoload_static.php](/vendor/composer/autoload_static.php) | PHP | 28 | 1 | 8 | 37 |
|
||||
| [vendor/composer/installed.json](/vendor/composer/installed.json) | JSON | 90 | 0 | 1 | 91 |
|
||||
| [vendor/composer/installed.php](/vendor/composer/installed.php) | PHP | 32 | 0 | 1 | 33 |
|
||||
| [vendor/composer/platform_check.php](/vendor/composer/platform_check.php) | PHP | 21 | 1 | 5 | 27 |
|
||||
| [vendor/phpmailer/phpmailer/README.md](/vendor/phpmailer/phpmailer/README.md) | Markdown | 169 | 0 | 64 | 233 |
|
||||
| [vendor/phpmailer/phpmailer/SECURITY.md](/vendor/phpmailer/phpmailer/SECURITY.md) | Markdown | 19 | 0 | 19 | 38 |
|
||||
| [vendor/phpmailer/phpmailer/SMTPUTF8.md](/vendor/phpmailer/phpmailer/SMTPUTF8.md) | Markdown | 27 | 0 | 22 | 49 |
|
||||
| [vendor/phpmailer/phpmailer/composer.json](/vendor/phpmailer/phpmailer/composer.json) | JSON | 80 | 0 | 1 | 81 |
|
||||
| [vendor/phpmailer/phpmailer/get_oauth_token.php](/vendor/phpmailer/phpmailer/get_oauth_token.php) | PHP | 117 | 48 | 18 | 183 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-af.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-af.php) | PHP | 20 | 4 | 3 | 27 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-ar.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-ar.php) | PHP | 20 | 5 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-as.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-as.php) | PHP | 28 | 5 | 3 | 36 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-az.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-az.php) | PHP | 19 | 6 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-ba.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-ba.php) | PHP | 20 | 5 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-be.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-be.php) | PHP | 19 | 6 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-bg.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-bg.php) | PHP | 20 | 5 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-bn.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-bn.php) | PHP | 28 | 5 | 3 | 36 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-ca.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-ca.php) | PHP | 19 | 6 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-cs.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-cs.php) | PHP | 22 | 4 | 3 | 29 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-da.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-da.php) | PHP | 27 | 7 | 3 | 37 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-de.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-de.php) | PHP | 22 | 4 | 3 | 29 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-el.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-el.php) | PHP | 27 | 4 | 3 | 34 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-eo.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-eo.php) | PHP | 20 | 4 | 3 | 27 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-es.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-es.php) | PHP | 27 | 7 | 3 | 37 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-et.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-et.php) | PHP | 20 | 6 | 3 | 29 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-fa.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-fa.php) | PHP | 20 | 6 | 3 | 29 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-fi.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-fi.php) | PHP | 13 | 12 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-fo.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-fo.php) | PHP | 13 | 12 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-fr.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-fr.php) | PHP | 27 | 7 | 3 | 37 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-gl.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-gl.php) | PHP | 19 | 6 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-he.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-he.php) | PHP | 19 | 6 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-hi.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-hi.php) | PHP | 27 | 6 | 3 | 36 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-hr.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-hr.php) | PHP | 20 | 5 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-hu.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-hu.php) | PHP | 20 | 5 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-hy.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-hy.php) | PHP | 20 | 5 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-id.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-id.php) | PHP | 22 | 7 | 3 | 32 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-it.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-it.php) | PHP | 20 | 6 | 3 | 29 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-ja.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-ja.php) | PHP | 27 | 8 | 3 | 38 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-ka.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-ka.php) | PHP | 20 | 5 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-ko.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-ko.php) | PHP | 20 | 5 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-ku.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-ku.php) | PHP | 20 | 5 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-lt.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-lt.php) | PHP | 19 | 6 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-lv.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-lv.php) | PHP | 19 | 6 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-mg.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-mg.php) | PHP | 20 | 5 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-mn.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-mn.php) | PHP | 20 | 5 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-ms.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-ms.php) | PHP | 20 | 5 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-nb.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-nb.php) | PHP | 27 | 4 | 3 | 34 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-nl.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-nl.php) | PHP | 27 | 5 | 3 | 35 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-pl.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-pl.php) | PHP | 27 | 4 | 3 | 34 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-pt.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-pt.php) | PHP | 27 | 5 | 3 | 35 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-pt_br.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-pt_br.php) | PHP | 27 | 9 | 3 | 39 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-ro.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-ro.php) | PHP | 27 | 4 | 3 | 34 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-ru.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-ru.php) | PHP | 27 | 7 | 3 | 37 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-si.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-si.php) | PHP | 27 | 5 | 3 | 35 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-sk.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-sk.php) | PHP | 22 | 6 | 3 | 31 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-sl.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-sl.php) | PHP | 27 | 7 | 3 | 37 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-sr.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-sr.php) | PHP | 20 | 6 | 3 | 29 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-sr_latn.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-sr_latn.php) | PHP | 20 | 6 | 3 | 29 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-sv.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-sv.php) | PHP | 19 | 6 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-tl.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-tl.php) | PHP | 20 | 6 | 3 | 29 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-tr.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-tr.php) | PHP | 27 | 9 | 3 | 39 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-uk.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-uk.php) | PHP | 20 | 6 | 3 | 29 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-ur.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-ur.php) | PHP | 23 | 5 | 3 | 31 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-vi.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-vi.php) | PHP | 19 | 6 | 3 | 28 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-zh.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-zh.php) | PHP | 20 | 7 | 3 | 30 |
|
||||
| [vendor/phpmailer/phpmailer/language/phpmailer.lang-zh_cn.php](/vendor/phpmailer/phpmailer/language/phpmailer.lang-zh_cn.php) | PHP | 27 | 7 | 3 | 37 |
|
||||
| [vendor/phpmailer/phpmailer/src/DSNConfigurator.php](/vendor/phpmailer/phpmailer/src/DSNConfigurator.php) | PHP | 136 | 80 | 30 | 246 |
|
||||
| [vendor/phpmailer/phpmailer/src/Exception.php](/vendor/phpmailer/phpmailer/src/Exception.php) | PHP | 9 | 28 | 4 | 41 |
|
||||
| [vendor/phpmailer/phpmailer/src/OAuth.php](/vendor/phpmailer/phpmailer/src/OAuth.php) | PHP | 46 | 79 | 15 | 140 |
|
||||
| [vendor/phpmailer/phpmailer/src/OAuthTokenProvider.php](/vendor/phpmailer/phpmailer/src/OAuthTokenProvider.php) | PHP | 6 | 35 | 4 | 45 |
|
||||
| [vendor/phpmailer/phpmailer/src/PHPMailer.php](/vendor/phpmailer/phpmailer/src/PHPMailer.php) | PHP | 2,985 | 1,979 | 399 | 5,363 |
|
||||
| [vendor/phpmailer/phpmailer/src/POP3.php](/vendor/phpmailer/phpmailer/src/POP3.php) | PHP | 183 | 234 | 53 | 470 |
|
||||
| [vendor/phpmailer/phpmailer/src/SMTP.php](/vendor/phpmailer/phpmailer/src/SMTP.php) | PHP | 757 | 644 | 147 | 1,548 |
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||
107
.VSCodeCounter/2025-07-09_15-40-50/diff.csv
Normal file
107
.VSCodeCounter/2025-07-09_15-40-50/diff.csv
Normal file
@@ -0,0 +1,107 @@
|
||||
"filename", "language", "PHP", "Markdown", "JSON", "JavaScript", "MS SQL", "comment", "blank", "total"
|
||||
"c:\web\app2\.trae\rules\project_rules.md", "Markdown", 0, 4, 0, 0, 0, 0, 3, 7
|
||||
"c:\web\app2\README.md", "Markdown", 0, 248, 0, 0, 0, 0, 47, 295
|
||||
"c:\web\app2\admin\manage_developers.php", "PHP", 16, 0, 0, 0, 0, 1, 0, 17
|
||||
"c:\web\app2\admin\review_apps.php", "PHP", 61, 0, 0, 0, 0, 4, 4, 69
|
||||
"c:\web\app2\api.php", "PHP", 19, 0, 0, 0, 0, 2, 2, 23
|
||||
"c:\web\app2\app.php", "PHP", 95, 0, 0, 0, 0, 7, 9, 111
|
||||
"c:\web\app2\app_store.sql", "MS SQL", 0, 0, 0, 0, 21, 3, 4, 28
|
||||
"c:\web\app2\app_store_update.sql", "MS SQL", 0, 0, 0, 0, -2, -1, 0, -3
|
||||
"c:\web\app2\composer.json", "JSON", 0, 0, 5, 0, 0, 0, 1, 6
|
||||
"c:\web\app2\composer.lock", "JSON", 0, 0, 100, 0, 0, 0, 1, 101
|
||||
"c:\web\app2\config.php", "PHP", -4, 0, 0, 0, 0, 1, 2, -1
|
||||
"c:\web\app2\developer\dashboard.php", "PHP", 1, 0, 0, 0, 0, 0, 0, 1
|
||||
"c:\web\app2\developer\edit_app.php", "PHP", -68, 0, 0, 0, 0, 0, 0, -68
|
||||
"c:\web\app2\developer\profile.php", "PHP", -3, 0, 0, 0, 0, 0, 1, -2
|
||||
"c:\web\app2\developer\register.php", "PHP", 69, 0, 0, 0, 0, 15, 16, 100
|
||||
"c:\web\app2\developer\upload_app.php", "PHP", 55, 0, 0, 0, 0, 2, 6, 63
|
||||
"c:\web\app2\developer\verify_email.php", "PHP", 77, 0, 0, 0, 0, 5, 8, 90
|
||||
"c:\web\app2\developer\version_control.php", "PHP", 209, 0, 0, 0, 0, 10, 13, 232
|
||||
"c:\web\app2\developer_apps.php", "PHP", 34, 0, 0, 0, 0, 3, 5, 42
|
||||
"c:\web\app2\docs\app_review_standards.php", "PHP", 196, 0, 0, 0, 0, 0, 18, 214
|
||||
"c:\web\app2\docs\privacy_policy.php", "PHP", 37, 0, 0, 0, 0, 0, 9, 46
|
||||
"c:\web\app2\includes\logger.php", "PHP", 30, 0, 0, 0, 0, 18, 8, 56
|
||||
"c:\web\app2\index.php", "PHP", -1, 0, 0, 0, 0, 1, 0, 0
|
||||
"c:\web\app2\js\bootstrap.bundle.js", "JavaScript", 0, 0, 0, 5053, 0, 655, 598, 6306
|
||||
"c:\web\app2\mail\verification_template.php", "PHP", 33, 0, 0, 0, 0, 6, 0, 39
|
||||
"c:\web\app2\vendor\autoload.php", "PHP", 20, 0, 0, 0, 0, 1, 5, 26
|
||||
"c:\web\app2\vendor\composer\ClassLoader.php", "PHP", 286, 0, 0, 0, 0, 235, 59, 580
|
||||
"c:\web\app2\vendor\composer\InstalledVersions.php", "PHP", 178, 0, 0, 0, 0, 133, 49, 360
|
||||
"c:\web\app2\vendor\composer\autoload_classmap.php", "PHP", 6, 0, 0, 0, 0, 1, 4, 11
|
||||
"c:\web\app2\vendor\composer\autoload_namespaces.php", "PHP", 5, 0, 0, 0, 0, 1, 4, 10
|
||||
"c:\web\app2\vendor\composer\autoload_psr4.php", "PHP", 6, 0, 0, 0, 0, 1, 4, 11
|
||||
"c:\web\app2\vendor\composer\autoload_real.php", "PHP", 25, 0, 0, 0, 0, 4, 10, 39
|
||||
"c:\web\app2\vendor\composer\autoload_static.php", "PHP", 28, 0, 0, 0, 0, 1, 8, 37
|
||||
"c:\web\app2\vendor\composer\installed.json", "JSON", 0, 0, 90, 0, 0, 0, 1, 91
|
||||
"c:\web\app2\vendor\composer\installed.php", "PHP", 32, 0, 0, 0, 0, 0, 1, 33
|
||||
"c:\web\app2\vendor\composer\platform_check.php", "PHP", 21, 0, 0, 0, 0, 1, 5, 27
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\README.md", "Markdown", 0, 169, 0, 0, 0, 0, 64, 233
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\SECURITY.md", "Markdown", 0, 19, 0, 0, 0, 0, 19, 38
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\SMTPUTF8.md", "Markdown", 0, 27, 0, 0, 0, 0, 22, 49
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\composer.json", "JSON", 0, 0, 80, 0, 0, 0, 1, 81
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\get_oauth_token.php", "PHP", 117, 0, 0, 0, 0, 48, 18, 183
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-af.php", "PHP", 20, 0, 0, 0, 0, 4, 3, 27
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ar.php", "PHP", 20, 0, 0, 0, 0, 5, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-as.php", "PHP", 28, 0, 0, 0, 0, 5, 3, 36
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-az.php", "PHP", 19, 0, 0, 0, 0, 6, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ba.php", "PHP", 20, 0, 0, 0, 0, 5, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-be.php", "PHP", 19, 0, 0, 0, 0, 6, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-bg.php", "PHP", 20, 0, 0, 0, 0, 5, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-bn.php", "PHP", 28, 0, 0, 0, 0, 5, 3, 36
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ca.php", "PHP", 19, 0, 0, 0, 0, 6, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-cs.php", "PHP", 22, 0, 0, 0, 0, 4, 3, 29
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-da.php", "PHP", 27, 0, 0, 0, 0, 7, 3, 37
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-de.php", "PHP", 22, 0, 0, 0, 0, 4, 3, 29
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-el.php", "PHP", 27, 0, 0, 0, 0, 4, 3, 34
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-eo.php", "PHP", 20, 0, 0, 0, 0, 4, 3, 27
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-es.php", "PHP", 27, 0, 0, 0, 0, 7, 3, 37
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-et.php", "PHP", 20, 0, 0, 0, 0, 6, 3, 29
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-fa.php", "PHP", 20, 0, 0, 0, 0, 6, 3, 29
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-fi.php", "PHP", 13, 0, 0, 0, 0, 12, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-fo.php", "PHP", 13, 0, 0, 0, 0, 12, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-fr.php", "PHP", 27, 0, 0, 0, 0, 7, 3, 37
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-gl.php", "PHP", 19, 0, 0, 0, 0, 6, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-he.php", "PHP", 19, 0, 0, 0, 0, 6, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-hi.php", "PHP", 27, 0, 0, 0, 0, 6, 3, 36
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-hr.php", "PHP", 20, 0, 0, 0, 0, 5, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-hu.php", "PHP", 20, 0, 0, 0, 0, 5, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-hy.php", "PHP", 20, 0, 0, 0, 0, 5, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-id.php", "PHP", 22, 0, 0, 0, 0, 7, 3, 32
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-it.php", "PHP", 20, 0, 0, 0, 0, 6, 3, 29
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ja.php", "PHP", 27, 0, 0, 0, 0, 8, 3, 38
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ka.php", "PHP", 20, 0, 0, 0, 0, 5, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ko.php", "PHP", 20, 0, 0, 0, 0, 5, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ku.php", "PHP", 20, 0, 0, 0, 0, 5, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-lt.php", "PHP", 19, 0, 0, 0, 0, 6, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-lv.php", "PHP", 19, 0, 0, 0, 0, 6, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-mg.php", "PHP", 20, 0, 0, 0, 0, 5, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-mn.php", "PHP", 20, 0, 0, 0, 0, 5, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ms.php", "PHP", 20, 0, 0, 0, 0, 5, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-nb.php", "PHP", 27, 0, 0, 0, 0, 4, 3, 34
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-nl.php", "PHP", 27, 0, 0, 0, 0, 5, 3, 35
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-pl.php", "PHP", 27, 0, 0, 0, 0, 4, 3, 34
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-pt.php", "PHP", 27, 0, 0, 0, 0, 5, 3, 35
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-pt_br.php", "PHP", 27, 0, 0, 0, 0, 9, 3, 39
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ro.php", "PHP", 27, 0, 0, 0, 0, 4, 3, 34
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ru.php", "PHP", 27, 0, 0, 0, 0, 7, 3, 37
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-si.php", "PHP", 27, 0, 0, 0, 0, 5, 3, 35
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-sk.php", "PHP", 22, 0, 0, 0, 0, 6, 3, 31
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-sl.php", "PHP", 27, 0, 0, 0, 0, 7, 3, 37
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-sr.php", "PHP", 20, 0, 0, 0, 0, 6, 3, 29
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-sr_latn.php", "PHP", 20, 0, 0, 0, 0, 6, 3, 29
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-sv.php", "PHP", 19, 0, 0, 0, 0, 6, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-tl.php", "PHP", 20, 0, 0, 0, 0, 6, 3, 29
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-tr.php", "PHP", 27, 0, 0, 0, 0, 9, 3, 39
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-uk.php", "PHP", 20, 0, 0, 0, 0, 6, 3, 29
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ur.php", "PHP", 23, 0, 0, 0, 0, 5, 3, 31
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-vi.php", "PHP", 19, 0, 0, 0, 0, 6, 3, 28
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-zh.php", "PHP", 20, 0, 0, 0, 0, 7, 3, 30
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-zh_cn.php", "PHP", 27, 0, 0, 0, 0, 7, 3, 37
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\src\DSNConfigurator.php", "PHP", 136, 0, 0, 0, 0, 80, 30, 246
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\src\Exception.php", "PHP", 9, 0, 0, 0, 0, 28, 4, 41
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\src\OAuth.php", "PHP", 46, 0, 0, 0, 0, 79, 15, 140
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\src\OAuthTokenProvider.php", "PHP", 6, 0, 0, 0, 0, 35, 4, 45
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\src\PHPMailer.php", "PHP", 2985, 0, 0, 0, 0, 1979, 399, 5363
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\src\POP3.php", "PHP", 183, 0, 0, 0, 0, 234, 53, 470
|
||||
"c:\web\app2\vendor\phpmailer\phpmailer\src\SMTP.php", "PHP", 757, 0, 0, 0, 0, 644, 147, 1548
|
||||
"Total", "-", 6965, 467, 275, 5053, 19, 4573, 1852, 19204
|
||||
|
42
.VSCodeCounter/2025-07-09_15-40-50/diff.md
Normal file
42
.VSCodeCounter/2025-07-09_15-40-50/diff.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Diff Summary
|
||||
|
||||
Date : 2025-07-09 15:40:50
|
||||
|
||||
Directory c:\\web\\app2
|
||||
|
||||
Total : 105 files, 12779 codes, 4573 comments, 1852 blanks, all 19204 lines
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||
|
||||
## Languages
|
||||
| language | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| PHP | 93 | 6,965 | 3,916 | 1,091 | 11,972 |
|
||||
| JavaScript | 1 | 5,053 | 655 | 598 | 6,306 |
|
||||
| Markdown | 5 | 467 | 0 | 155 | 622 |
|
||||
| JSON | 4 | 275 | 0 | 4 | 279 |
|
||||
| MS SQL | 2 | 19 | 2 | 4 | 25 |
|
||||
|
||||
## Directories
|
||||
| path | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| . | 105 | 12,779 | 4,573 | 1,852 | 19,204 |
|
||||
| . (Files) | 10 | 515 | 16 | 71 | 602 |
|
||||
| .trae | 1 | 4 | 0 | 3 | 7 |
|
||||
| .trae\\rules | 1 | 4 | 0 | 3 | 7 |
|
||||
| admin | 2 | 77 | 5 | 4 | 86 |
|
||||
| developer | 7 | 340 | 32 | 44 | 416 |
|
||||
| docs | 2 | 233 | 0 | 27 | 260 |
|
||||
| includes | 1 | 30 | 18 | 8 | 56 |
|
||||
| js | 1 | 5,053 | 655 | 598 | 6,306 |
|
||||
| mail | 1 | 33 | 6 | 0 | 39 |
|
||||
| vendor | 80 | 6,494 | 3,841 | 1,097 | 11,432 |
|
||||
| vendor (Files) | 1 | 20 | 1 | 5 | 26 |
|
||||
| vendor\\composer | 10 | 677 | 377 | 145 | 1,199 |
|
||||
| vendor\\phpmailer | 69 | 5,797 | 3,463 | 947 | 10,207 |
|
||||
| vendor\\phpmailer\\phpmailer | 69 | 5,797 | 3,463 | 947 | 10,207 |
|
||||
| vendor\\phpmailer\\phpmailer (Files) | 5 | 412 | 48 | 124 | 584 |
|
||||
| vendor\\phpmailer\\phpmailer\\language | 57 | 1,263 | 336 | 171 | 1,770 |
|
||||
| vendor\\phpmailer\\phpmailer\\src | 7 | 4,122 | 3,079 | 652 | 7,853 |
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||
150
.VSCodeCounter/2025-07-09_15-40-50/diff.txt
Normal file
150
.VSCodeCounter/2025-07-09_15-40-50/diff.txt
Normal file
@@ -0,0 +1,150 @@
|
||||
Date : 2025-07-09 15:40:50
|
||||
Directory : c:\web\app2
|
||||
Total : 105 files, 12779 codes, 4573 comments, 1852 blanks, all 19204 lines
|
||||
|
||||
Languages
|
||||
+------------+------------+------------+------------+------------+------------+
|
||||
| language | files | code | comment | blank | total |
|
||||
+------------+------------+------------+------------+------------+------------+
|
||||
| PHP | 93 | 6,965 | 3,916 | 1,091 | 11,972 |
|
||||
| JavaScript | 1 | 5,053 | 655 | 598 | 6,306 |
|
||||
| Markdown | 5 | 467 | 0 | 155 | 622 |
|
||||
| JSON | 4 | 275 | 0 | 4 | 279 |
|
||||
| MS SQL | 2 | 19 | 2 | 4 | 25 |
|
||||
+------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Directories
|
||||
+------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| path | files | code | comment | blank | total |
|
||||
+------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| . | 105 | 12,779 | 4,573 | 1,852 | 19,204 |
|
||||
| . (Files) | 10 | 515 | 16 | 71 | 602 |
|
||||
| .trae | 1 | 4 | 0 | 3 | 7 |
|
||||
| .trae\rules | 1 | 4 | 0 | 3 | 7 |
|
||||
| admin | 2 | 77 | 5 | 4 | 86 |
|
||||
| developer | 7 | 340 | 32 | 44 | 416 |
|
||||
| docs | 2 | 233 | 0 | 27 | 260 |
|
||||
| includes | 1 | 30 | 18 | 8 | 56 |
|
||||
| js | 1 | 5,053 | 655 | 598 | 6,306 |
|
||||
| mail | 1 | 33 | 6 | 0 | 39 |
|
||||
| vendor | 80 | 6,494 | 3,841 | 1,097 | 11,432 |
|
||||
| vendor (Files) | 1 | 20 | 1 | 5 | 26 |
|
||||
| vendor\composer | 10 | 677 | 377 | 145 | 1,199 |
|
||||
| vendor\phpmailer | 69 | 5,797 | 3,463 | 947 | 10,207 |
|
||||
| vendor\phpmailer\phpmailer | 69 | 5,797 | 3,463 | 947 | 10,207 |
|
||||
| vendor\phpmailer\phpmailer (Files) | 5 | 412 | 48 | 124 | 584 |
|
||||
| vendor\phpmailer\phpmailer\language | 57 | 1,263 | 336 | 171 | 1,770 |
|
||||
| vendor\phpmailer\phpmailer\src | 7 | 4,122 | 3,079 | 652 | 7,853 |
|
||||
+------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Files
|
||||
+------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| filename | language | code | comment | blank | total |
|
||||
+------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| c:\web\app2\.trae\rules\project_rules.md | Markdown | 4 | 0 | 3 | 7 |
|
||||
| c:\web\app2\README.md | Markdown | 248 | 0 | 47 | 295 |
|
||||
| c:\web\app2\admin\manage_developers.php | PHP | 16 | 1 | 0 | 17 |
|
||||
| c:\web\app2\admin\review_apps.php | PHP | 61 | 4 | 4 | 69 |
|
||||
| c:\web\app2\api.php | PHP | 19 | 2 | 2 | 23 |
|
||||
| c:\web\app2\app.php | PHP | 95 | 7 | 9 | 111 |
|
||||
| c:\web\app2\app_store.sql | MS SQL | 21 | 3 | 4 | 28 |
|
||||
| c:\web\app2\app_store_update.sql | MS SQL | -2 | -1 | 0 | -3 |
|
||||
| c:\web\app2\composer.json | JSON | 5 | 0 | 1 | 6 |
|
||||
| c:\web\app2\composer.lock | JSON | 100 | 0 | 1 | 101 |
|
||||
| c:\web\app2\config.php | PHP | -4 | 1 | 2 | -1 |
|
||||
| c:\web\app2\developer\dashboard.php | PHP | 1 | 0 | 0 | 1 |
|
||||
| c:\web\app2\developer\edit_app.php | PHP | -68 | 0 | 0 | -68 |
|
||||
| c:\web\app2\developer\profile.php | PHP | -3 | 0 | 1 | -2 |
|
||||
| c:\web\app2\developer\register.php | PHP | 69 | 15 | 16 | 100 |
|
||||
| c:\web\app2\developer\upload_app.php | PHP | 55 | 2 | 6 | 63 |
|
||||
| c:\web\app2\developer\verify_email.php | PHP | 77 | 5 | 8 | 90 |
|
||||
| c:\web\app2\developer\version_control.php | PHP | 209 | 10 | 13 | 232 |
|
||||
| c:\web\app2\developer_apps.php | PHP | 34 | 3 | 5 | 42 |
|
||||
| c:\web\app2\docs\app_review_standards.php | PHP | 196 | 0 | 18 | 214 |
|
||||
| c:\web\app2\docs\privacy_policy.php | PHP | 37 | 0 | 9 | 46 |
|
||||
| c:\web\app2\includes\logger.php | PHP | 30 | 18 | 8 | 56 |
|
||||
| c:\web\app2\index.php | PHP | -1 | 1 | 0 | 0 |
|
||||
| c:\web\app2\js\bootstrap.bundle.js | JavaScript | 5,053 | 655 | 598 | 6,306 |
|
||||
| c:\web\app2\mail\verification_template.php | PHP | 33 | 6 | 0 | 39 |
|
||||
| c:\web\app2\vendor\autoload.php | PHP | 20 | 1 | 5 | 26 |
|
||||
| c:\web\app2\vendor\composer\ClassLoader.php | PHP | 286 | 235 | 59 | 580 |
|
||||
| c:\web\app2\vendor\composer\InstalledVersions.php | PHP | 178 | 133 | 49 | 360 |
|
||||
| c:\web\app2\vendor\composer\autoload_classmap.php | PHP | 6 | 1 | 4 | 11 |
|
||||
| c:\web\app2\vendor\composer\autoload_namespaces.php | PHP | 5 | 1 | 4 | 10 |
|
||||
| c:\web\app2\vendor\composer\autoload_psr4.php | PHP | 6 | 1 | 4 | 11 |
|
||||
| c:\web\app2\vendor\composer\autoload_real.php | PHP | 25 | 4 | 10 | 39 |
|
||||
| c:\web\app2\vendor\composer\autoload_static.php | PHP | 28 | 1 | 8 | 37 |
|
||||
| c:\web\app2\vendor\composer\installed.json | JSON | 90 | 0 | 1 | 91 |
|
||||
| c:\web\app2\vendor\composer\installed.php | PHP | 32 | 0 | 1 | 33 |
|
||||
| c:\web\app2\vendor\composer\platform_check.php | PHP | 21 | 1 | 5 | 27 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\README.md | Markdown | 169 | 0 | 64 | 233 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\SECURITY.md | Markdown | 19 | 0 | 19 | 38 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\SMTPUTF8.md | Markdown | 27 | 0 | 22 | 49 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\composer.json | JSON | 80 | 0 | 1 | 81 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\get_oauth_token.php | PHP | 117 | 48 | 18 | 183 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-af.php | PHP | 20 | 4 | 3 | 27 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ar.php | PHP | 20 | 5 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-as.php | PHP | 28 | 5 | 3 | 36 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-az.php | PHP | 19 | 6 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ba.php | PHP | 20 | 5 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-be.php | PHP | 19 | 6 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-bg.php | PHP | 20 | 5 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-bn.php | PHP | 28 | 5 | 3 | 36 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ca.php | PHP | 19 | 6 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-cs.php | PHP | 22 | 4 | 3 | 29 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-da.php | PHP | 27 | 7 | 3 | 37 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-de.php | PHP | 22 | 4 | 3 | 29 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-el.php | PHP | 27 | 4 | 3 | 34 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-eo.php | PHP | 20 | 4 | 3 | 27 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-es.php | PHP | 27 | 7 | 3 | 37 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-et.php | PHP | 20 | 6 | 3 | 29 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-fa.php | PHP | 20 | 6 | 3 | 29 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-fi.php | PHP | 13 | 12 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-fo.php | PHP | 13 | 12 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-fr.php | PHP | 27 | 7 | 3 | 37 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-gl.php | PHP | 19 | 6 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-he.php | PHP | 19 | 6 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-hi.php | PHP | 27 | 6 | 3 | 36 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-hr.php | PHP | 20 | 5 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-hu.php | PHP | 20 | 5 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-hy.php | PHP | 20 | 5 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-id.php | PHP | 22 | 7 | 3 | 32 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-it.php | PHP | 20 | 6 | 3 | 29 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ja.php | PHP | 27 | 8 | 3 | 38 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ka.php | PHP | 20 | 5 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ko.php | PHP | 20 | 5 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ku.php | PHP | 20 | 5 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-lt.php | PHP | 19 | 6 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-lv.php | PHP | 19 | 6 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-mg.php | PHP | 20 | 5 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-mn.php | PHP | 20 | 5 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ms.php | PHP | 20 | 5 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-nb.php | PHP | 27 | 4 | 3 | 34 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-nl.php | PHP | 27 | 5 | 3 | 35 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-pl.php | PHP | 27 | 4 | 3 | 34 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-pt.php | PHP | 27 | 5 | 3 | 35 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-pt_br.php | PHP | 27 | 9 | 3 | 39 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ro.php | PHP | 27 | 4 | 3 | 34 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ru.php | PHP | 27 | 7 | 3 | 37 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-si.php | PHP | 27 | 5 | 3 | 35 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-sk.php | PHP | 22 | 6 | 3 | 31 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-sl.php | PHP | 27 | 7 | 3 | 37 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-sr.php | PHP | 20 | 6 | 3 | 29 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-sr_latn.php | PHP | 20 | 6 | 3 | 29 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-sv.php | PHP | 19 | 6 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-tl.php | PHP | 20 | 6 | 3 | 29 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-tr.php | PHP | 27 | 9 | 3 | 39 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-uk.php | PHP | 20 | 6 | 3 | 29 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-ur.php | PHP | 23 | 5 | 3 | 31 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-vi.php | PHP | 19 | 6 | 3 | 28 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-zh.php | PHP | 20 | 7 | 3 | 30 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\language\phpmailer.lang-zh_cn.php | PHP | 27 | 7 | 3 | 37 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\src\DSNConfigurator.php | PHP | 136 | 80 | 30 | 246 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\src\Exception.php | PHP | 9 | 28 | 4 | 41 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\src\OAuth.php | PHP | 46 | 79 | 15 | 140 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\src\OAuthTokenProvider.php | PHP | 6 | 35 | 4 | 45 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\src\PHPMailer.php | PHP | 2,985 | 1,979 | 399 | 5,363 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\src\POP3.php | PHP | 183 | 234 | 53 | 470 |
|
||||
| c:\web\app2\vendor\phpmailer\phpmailer\src\SMTP.php | PHP | 757 | 644 | 147 | 1,548 |
|
||||
| Total | | 12,779 | 4,573 | 1,852 | 19,204 |
|
||||
+------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
2208
.VSCodeCounter/2025-07-09_15-40-50/results.csv
Normal file
2208
.VSCodeCounter/2025-07-09_15-40-50/results.csv
Normal file
File diff suppressed because it is too large
Load Diff
1
.VSCodeCounter/2025-07-09_15-40-50/results.json
Normal file
1
.VSCodeCounter/2025-07-09_15-40-50/results.json
Normal file
File diff suppressed because one or more lines are too long
58
.VSCodeCounter/2025-07-09_15-40-50/results.md
Normal file
58
.VSCodeCounter/2025-07-09_15-40-50/results.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Summary
|
||||
|
||||
Date : 2025-07-09 15:40:50
|
||||
|
||||
Directory c:\\web\\app2
|
||||
|
||||
Total : 2206 files, 359502 codes, 5937 comments, 5170 blanks, all 370609 lines
|
||||
|
||||
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
|
||||
## Languages
|
||||
| language | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| JSON | 7 | 207,793 | 0 | 4 | 207,797 |
|
||||
| YAML | 5 | 97,374 | 0 | 5 | 97,379 |
|
||||
| JavaScript | 16 | 19,440 | 1,449 | 2,275 | 23,164 |
|
||||
| PHP | 107 | 11,852 | 4,239 | 1,475 | 17,566 |
|
||||
| XML | 2,023 | 8,089 | 15 | 0 | 8,104 |
|
||||
| SCSS | 19 | 6,938 | 99 | 575 | 7,612 |
|
||||
| Less | 18 | 6,907 | 72 | 570 | 7,549 |
|
||||
| Markdown | 5 | 508 | 0 | 162 | 670 |
|
||||
| Python | 2 | 253 | 17 | 47 | 317 |
|
||||
| MS SQL | 1 | 210 | 33 | 35 | 278 |
|
||||
| CSS | 3 | 138 | 13 | 22 | 173 |
|
||||
|
||||
## Directories
|
||||
| path | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| . | 2,206 | 359,502 | 5,937 | 5,170 | 370,609 |
|
||||
| . (Files) | 14 | 2,331 | 189 | 275 | 2,795 |
|
||||
| .trae | 1 | 4 | 0 | 3 | 7 |
|
||||
| .trae\\rules | 1 | 4 | 0 | 3 | 7 |
|
||||
| admin | 10 | 2,058 | 107 | 160 | 2,325 |
|
||||
| css | 2 | 5 | 9 | 1 | 15 |
|
||||
| developer | 9 | 1,757 | 112 | 127 | 1,996 |
|
||||
| docs | 2 | 271 | 3 | 27 | 301 |
|
||||
| includes | 1 | 30 | 18 | 8 | 56 |
|
||||
| js | 16 | 19,440 | 1,449 | 2,275 | 23,164 |
|
||||
| less | 18 | 6,907 | 72 | 570 | 7,549 |
|
||||
| mail | 1 | 33 | 6 | 0 | 39 |
|
||||
| metadata | 8 | 304,892 | 0 | 5 | 304,897 |
|
||||
| scss | 19 | 6,938 | 99 | 575 | 7,612 |
|
||||
| sprites | 3 | 6,069 | 15 | 0 | 6,084 |
|
||||
| svgs | 2,020 | 2,020 | 0 | 0 | 2,020 |
|
||||
| svgs\\brands | 467 | 467 | 0 | 0 | 467 |
|
||||
| svgs\\regular | 163 | 163 | 0 | 0 | 163 |
|
||||
| svgs\\solid | 1,390 | 1,390 | 0 | 0 | 1,390 |
|
||||
| vendor | 80 | 6,494 | 3,841 | 1,097 | 11,432 |
|
||||
| vendor (Files) | 1 | 20 | 1 | 5 | 26 |
|
||||
| vendor\\composer | 10 | 677 | 377 | 145 | 1,199 |
|
||||
| vendor\\phpmailer | 69 | 5,797 | 3,463 | 947 | 10,207 |
|
||||
| vendor\\phpmailer\\phpmailer | 69 | 5,797 | 3,463 | 947 | 10,207 |
|
||||
| vendor\\phpmailer\\phpmailer (Files) | 5 | 412 | 48 | 124 | 584 |
|
||||
| vendor\\phpmailer\\phpmailer\\language | 57 | 1,263 | 336 | 171 | 1,770 |
|
||||
| vendor\\phpmailer\\phpmailer\\src | 7 | 4,122 | 3,079 | 652 | 7,853 |
|
||||
| windows | 2 | 253 | 17 | 47 | 317 |
|
||||
|
||||
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
2267
.VSCodeCounter/2025-07-09_15-40-50/results.txt
Normal file
2267
.VSCodeCounter/2025-07-09_15-40-50/results.txt
Normal file
File diff suppressed because it is too large
Load Diff
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# 忽略上传的应用文件
|
||||
uploads/
|
||||
|
||||
# 忽略文件目录
|
||||
files/
|
||||
|
||||
# 忽略图片目录
|
||||
images/
|
||||
|
||||
# 忽略日志文件
|
||||
logs/
|
||||
|
||||
# 忽略Windows系统文件
|
||||
Thumbs.db
|
||||
.DS_Store
|
||||
7
.trae/rules/project_rules.md
Normal file
7
.trae/rules/project_rules.md
Normal file
@@ -0,0 +1,7 @@
|
||||
弹窗都用Sweet Alert弹窗
|
||||
|
||||
说中文!!!
|
||||
|
||||
不要用通用顶栏方式搞顶栏
|
||||
|
||||
不要出现EndOfFile错误!
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 LeonMMcoset
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
343
README.md
Normal file
343
README.md
Normal file
@@ -0,0 +1,343 @@
|
||||
# App Store 项目
|
||||
|
||||
这是一个基于 PHP 7.4 的 App Store 项目,使用 Bootstrap 实现 Fluent Design 风格界面,数据存储采用 MySQL 数据库。
|
||||
|
||||
## 项目结构
|
||||
```
|
||||
app2/
|
||||
├── config.php # 配置文件,包含数据库和管理员信息
|
||||
├── app_store.sql # 数据库初始化 SQL 文件
|
||||
├── index.php # 首页
|
||||
├── app.php # App 信息页
|
||||
├── admin/ # 管理员后台目录
|
||||
│ ├── addapp.php
|
||||
│ ├── deleteapp.php
|
||||
│ ├── editapp.php
|
||||
│ ├── index.php
|
||||
│ ├── login.php
|
||||
│ ├── manage_tags.php
|
||||
│ ├── review_apps.php
|
||||
│ └── system_info.php
|
||||
├── developer/ # 开发者后台目录
|
||||
│ ├── dashboard.php
|
||||
│ ├── edit_app.php
|
||||
│ ├── login.php
|
||||
│ ├── logout.php
|
||||
│ ├── profile.php
|
||||
│ ├── register.php
|
||||
│ └── upload_app.php
|
||||
├── vendor/ # Composer 依赖
|
||||
├── includes/ # 通用包含文件
|
||||
├── api.php # API 接口文件
|
||||
├── styles.css # 自定义 CSS 文件
|
||||
├── images/ # 存储 App 预览图片和年龄分级 SVG
|
||||
│ ├── age_3plus.svg
|
||||
│ ├── age_7plus.svg
|
||||
│ ├── age_12plus.svg
|
||||
│ ├── age_17plus.svg
|
||||
├── files/ # 存储 App 文件
|
||||
```
|
||||
|
||||
## 环境要求
|
||||
- PHP 7.4+
|
||||
- MySQL 5.7+
|
||||
- Composer
|
||||
- Node.js (可选,用于前端资源构建)
|
||||
- Web 服务器(如 Apache 或 Nginx)
|
||||
|
||||
## 快速启动指南
|
||||
对于有经验的开发者,可按照以下步骤快速部署:
|
||||
```cmd
|
||||
# 1. 克隆项目并进入目录
|
||||
git clone <repository-url> app2
|
||||
cd app2
|
||||
|
||||
# 2. 创建并配置环境文件
|
||||
copy config.example.php config.php
|
||||
# 编辑config.php设置数据库和邮件信息
|
||||
|
||||
# 3. 创建数据库并导入结构
|
||||
mysql -u root -p -e "CREATE DATABASE your_db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
||||
mysql -u root -p your_db_name < app_store.sql
|
||||
|
||||
# 4. 安装依赖并设置权限
|
||||
composer install
|
||||
icacls files /grant Users:(OI)(CI)W
|
||||
icacls images /grant Users:(OI)(CI)W
|
||||
|
||||
# 5. 启动开发服务器
|
||||
php -S localhost:8000
|
||||
```
|
||||
访问 http://localhost:8000 开始使用,管理员后台地址:http://localhost:8000/admin
|
||||
|
||||
## 详细安装教程
|
||||
|
||||
### 1. 环境准备
|
||||
确保您的系统满足以下要求:
|
||||
- PHP 7.4+(推荐PHP 8.0+)
|
||||
- MySQL 5.7+ 或 MariaDB 10.2+
|
||||
- Composer(PHP依赖管理工具)
|
||||
- Web服务器(Apache/Nginx/IIS)或PHP内置服务器
|
||||
- Git(可选,用于版本控制)
|
||||
|
||||
#### 检查PHP环境
|
||||
打开命令提示符,输入以下命令验证PHP版本:
|
||||
```cmd
|
||||
php -v
|
||||
# 应显示PHP 7.4.0或更高版本
|
||||
|
||||
# 检查必要扩展
|
||||
php -m | findstr /i "mysqli pdo_mysql json curl fileinfo"
|
||||
# 确保以上扩展均已安装
|
||||
```
|
||||
|
||||
### 2. 获取项目代码
|
||||
选择以下任一方式获取代码:
|
||||
|
||||
#### 方式一:使用Git克隆(推荐)
|
||||
```cmd
|
||||
git clone <repository-url> app2
|
||||
cd app2
|
||||
```
|
||||
|
||||
#### 方式二:手动下载
|
||||
1. 从项目仓库下载ZIP压缩包
|
||||
2. 解压到本地目录(如 `c:\web\app2`)
|
||||
3. 打开命令提示符,进入项目目录:
|
||||
```cmd
|
||||
cd c:\web\app2
|
||||
```
|
||||
|
||||
### 3. 数据库配置
|
||||
|
||||
#### 创建数据库
|
||||
1. 登录MySQL控制台:
|
||||
```cmd
|
||||
mysql -u root -p
|
||||
```
|
||||
2. 创建数据库(将`your_db_name`替换为您喜欢的数据库名称):
|
||||
```sql
|
||||
CREATE DATABASE your_db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
exit
|
||||
```
|
||||
|
||||
#### 导入数据库结构
|
||||
```cmd
|
||||
mysql -u root -p your_db_name < app_store.sql
|
||||
```
|
||||
> **注意**:请确保在导入前替换命令中的`your_db_name`为您实际创建的数据库名称
|
||||
|
||||
### 4. 应用配置
|
||||
|
||||
#### 创建配置文件
|
||||
如果项目中存在`config.example.php`:
|
||||
```cmd
|
||||
copy config.example.php config.php
|
||||
```
|
||||
如果不存在,请手动创建`config.php`文件并添加以下内容:
|
||||
```php
|
||||
<?php
|
||||
// 数据库配置
|
||||
define('DB_HOST', 'localhost');
|
||||
define('DB_USER', 'root');
|
||||
define('DB_PASS', 'your_database_password');
|
||||
define('DB_NAME', 'your_db_name');
|
||||
|
||||
define('APP_URL', 'http://localhost'); // 应用基础URL
|
||||
define('ADMIN_EMAIL', 'admin@example.com'); // 默认管理员邮箱
|
||||
define('ADMIN_PASSWORD', 'admin123'); // 默认管理员密码(首次登录后必须修改)
|
||||
|
||||
// 邮件服务配置(用于开发者注册验证)
|
||||
define('SMTP_HOST', 'smtp.example.com');
|
||||
define('SMTP_PORT', 465);
|
||||
define('SMTP_USER', 'your_email@example.com');
|
||||
define('SMTP_PASS', 'your_email_password');
|
||||
define('SMTP_ENCRYPTION', 'ssl'); // 通常为ssl或tls
|
||||
|
||||
define('DEBUG_MODE', true); // 开发环境设为true,生产环境设为false
|
||||
?>
|
||||
```
|
||||
|
||||
#### 配置参数说明
|
||||
| 参数 | 说明 | 示例值 |
|
||||
|------|------|--------|
|
||||
| DB_HOST | 数据库主机地址 | localhost |
|
||||
| DB_USER | 数据库用户名 | root |
|
||||
| DB_PASS | 数据库密码 | your_actual_password |
|
||||
| DB_NAME | 数据库名称 | app_store |
|
||||
| APP_URL | 应用访问URL | http://localhost/app2 |
|
||||
| DEBUG_MODE | 调试模式开关 | true/false |
|
||||
|
||||
### 5. 安装依赖
|
||||
使用Composer安装项目依赖:
|
||||
```cmd
|
||||
composer install
|
||||
```
|
||||
> 如果没有安装Composer,请先从 https://getcomposer.org/ 下载并安装
|
||||
|
||||
### 6. 设置目录权限
|
||||
项目需要对以下目录有写入权限:
|
||||
- `files/`:存储上传的应用文件
|
||||
- `images/`:存储应用截图和图标
|
||||
|
||||
#### 图形界面方式(推荐)
|
||||
1. 在文件资源管理器中找到项目目录
|
||||
2. 右键点击`files`文件夹,选择**属性**
|
||||
3. 切换到**安全**选项卡,点击**编辑**
|
||||
4. 选择当前用户,勾选**写入**权限,点击**确定**
|
||||
5. 对`images`文件夹执行相同操作
|
||||
|
||||
#### 命令行方式
|
||||
```cmd
|
||||
icacls files /grant Users:(OI)(CI)W
|
||||
icacls images /grant Users:(OI)(CI)W
|
||||
```
|
||||
|
||||
### 7. 配置Web服务器
|
||||
|
||||
#### 选项A:使用PHP内置开发服务器(推荐用于开发)
|
||||
```cmd
|
||||
php -S localhost:8000
|
||||
```
|
||||
然后在浏览器中访问:http://localhost:8000
|
||||
|
||||
#### 选项B:配置Apache服务器
|
||||
1. 确保`mod_rewrite`模块已启用
|
||||
2. 创建虚拟主机配置:
|
||||
```apache
|
||||
<VirtualHost *:80>
|
||||
ServerName appstore.local
|
||||
DocumentRoot "d:/app2"
|
||||
<Directory "d:/app2">
|
||||
Options Indexes FollowSymLinks
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
</Directory>
|
||||
</VirtualHost>
|
||||
```
|
||||
3. 修改`hosts`文件添加:`127.0.0.1 appstore.local`
|
||||
4. 重启Apache,访问 http://appstore.local
|
||||
|
||||
#### 选项C:配置Nginx服务器
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name appstore.local;
|
||||
root d:/app2;
|
||||
index index.php;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8. 首次使用与安全设置
|
||||
|
||||
#### 管理员账号初始化
|
||||
1. 访问管理员登录页面:http://localhost:8000/admin/login.php
|
||||
2. 使用默认账号登录:
|
||||
- 用户名:`admin@example.com`(来自config.php中的ADMIN_EMAIL)
|
||||
- 密码:`admin123`(来自config.php中的ADMIN_PASSWORD)
|
||||
3. **重要**:登录后立即点击右上角头像,选择**修改密码**,设置强密码
|
||||
|
||||
#### 安全建议
|
||||
- 生产环境中设置`define('DEBUG_MODE', false);`
|
||||
- 定期备份数据库
|
||||
- 不要将`config.php`提交到版本控制系统
|
||||
- 保持PHP和所有依赖包为最新安全版本
|
||||
|
||||
## 使用教程
|
||||
|
||||
### 开发者功能
|
||||
|
||||
#### 注册开发者账号
|
||||
1. 访问开发者注册页面:http://localhost:8000/developer/register.php
|
||||
2. 填写注册信息,提交后系统会发送验证邮件
|
||||
3. 点击邮件中的验证链接激活账号
|
||||
|
||||
#### 上传新应用
|
||||
1. 登录开发者后台:http://localhost:8000/developer/login.php
|
||||
2. 点击**上传新应用**按钮
|
||||
3. 填写应用信息:
|
||||
- 应用名称、描述、版本号
|
||||
- 选择应用类别和年龄分级
|
||||
- 上传应用图标(推荐尺寸:512x512px)
|
||||
- 上传应用截图(最多5张)
|
||||
- 上传应用安装包(支持.zip格式)
|
||||
4. 点击**提交审核**,等待管理员审核
|
||||
|
||||
#### 管理应用版本
|
||||
1. 在开发者后台点击应用名称进入管理页面
|
||||
2. 点击**发布新版本**添加应用更新
|
||||
3. 填写版本变更说明和更新内容
|
||||
4. 上传新版本安装包
|
||||
|
||||
### 管理员功能
|
||||
|
||||
#### 应用审核
|
||||
1. 登录管理员后台:http://localhost:8000/admin/login.php
|
||||
2. 点击**应用审核**菜单
|
||||
3. 查看待审核应用列表,点击**查看详情**
|
||||
4. 审核应用信息和安装包,点击**通过**或**拒绝**并填写反馈
|
||||
|
||||
#### 管理应用分类
|
||||
1. 在管理员后台点击**分类管理**
|
||||
2. 可以添加、编辑或删除应用分类
|
||||
3. 设置分类排序和显示状态
|
||||
|
||||
#### 系统信息查看
|
||||
1. 在管理员后台点击**系统信息**
|
||||
2. 查看服务器环境、PHP配置和数据库状态
|
||||
3. 监控应用总数、开发者数量和文件存储使用情况
|
||||
|
||||
### API使用指南
|
||||
|
||||
#### 获取应用列表
|
||||
```http
|
||||
GET /api.php?action=list&page=1&limit=10
|
||||
```
|
||||
返回JSON格式的应用列表数据
|
||||
|
||||
#### 获取应用详情
|
||||
```http
|
||||
GET /api.php?action=app&id=1
|
||||
```
|
||||
返回指定ID的应用详细信息
|
||||
|
||||
#### API响应格式
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {},
|
||||
"message": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
## 功能说明
|
||||
- **首页**:展示最新 App 列表,包含基本信息和评分。
|
||||
- **App 信息页**:显示 App 详细信息、版本历史、预览图片和用户评价,支持用户评分。
|
||||
- **管理页**:管理员可以添加、删除 App,审核应用,管理标签和查看系统信息。
|
||||
- **开发者后台**:开发者可以注册账号、管理应用、上传新版本和查看应用统计。
|
||||
- **API 接口**:提供 `/api` 获取 App 列表,`/api/app/<编号>` 获取单个 App 详细信息。
|
||||
|
||||
## 管理员登录
|
||||
默认管理员账号信息在 `config.php` 中配置,登录后可访问管理页面。
|
||||
|
||||
## 故障排除
|
||||
- **数据库导入错误**:确保数据库名称为'awa'且已创建,检查SQL文件路径是否正确
|
||||
- **权限问题**:确认 `files` 和 `images` 目录权限设置为755
|
||||
- **邮件发送失败**:检查 `config.php` 中的SMTP配置,确保端口(通常465或587)和加密方式正确
|
||||
- **类找不到错误**:运行 `composer install` 确保所有依赖已正确安装
|
||||
|
||||
## 注意事项
|
||||
- 请确保 `files`、`images` 目录以及其子目录有足够的写入权限(推荐设置权限为755)。
|
||||
- 生产环境中必须修改默认管理员密码和数据库连接信息,确保系统安全。
|
||||
- 邮件服务配置:请在 `config.php` 中正确设置 SMTP 服务器地址、端口、用户名和密码,以确保开发者邮箱验证功能正常工作。
|
||||
346
admin/addapp.php
Normal file
346
admin/addapp.php
Normal file
@@ -0,0 +1,346 @@
|
||||
<?php
|
||||
require_once '../config.php';
|
||||
|
||||
session_start();
|
||||
// 检查管理员登录状态
|
||||
if (!isset($_SESSION['admin'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$success = '';
|
||||
$error = '';
|
||||
// 处理添加App请求
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_app'])) {
|
||||
$name = $_POST['name'];
|
||||
$description = $_POST['description'];
|
||||
$ageRating = $_POST['age_rating'];
|
||||
$platforms = isset($_POST['platforms']) ? json_encode($_POST['platforms']) : json_encode([]);
|
||||
|
||||
// 处理表单提交
|
||||
// 验证必填字段
|
||||
$required = ['name', 'description', 'age_rating', 'platforms'];
|
||||
$errors = [];
|
||||
foreach ($required as $field) {
|
||||
if (empty($_POST[$field])) {
|
||||
$errors[] = ucfirst($field) . ' 不能为空';
|
||||
}
|
||||
}
|
||||
|
||||
// 年龄分级说明验证
|
||||
if (($_POST['age_rating'] === '12+' || $_POST['age_rating'] === '17+') && empty($_POST['age_rating_description'])) {
|
||||
$errors[] = '年龄分级为12+或以上时,年龄分级说明不能为空';
|
||||
}
|
||||
|
||||
|
||||
// 处理应用图标上传
|
||||
|
||||
// 处理平台数据
|
||||
$platforms = json_encode($_POST['platforms']);
|
||||
// 插入应用数据
|
||||
$stmt = $conn->prepare("INSERT INTO apps (name, description, age_rating, age_rating_description, platforms) VALUES (?, ?, ?, ?, ?)");
|
||||
if (!$stmt) {
|
||||
$error = "Database error: " . $conn->error;
|
||||
}
|
||||
if ($stmt) {
|
||||
$stmt->bind_param("sssss", $name, $description, $ageRating, $_POST['age_rating_description'], $platforms);
|
||||
if ($stmt->execute() === TRUE) {
|
||||
$appId = $stmt->insert_id;
|
||||
|
||||
// 保存标签关联
|
||||
if (!empty($_POST['tags'])) {
|
||||
$stmt = $conn->prepare("INSERT INTO app_tags (app_id, tag_id) VALUES (?, ?)");
|
||||
foreach ($_POST['tags'] as $tagId) {
|
||||
$stmt->bind_param("ii", $appId, $tagId);
|
||||
$stmt->execute();
|
||||
}
|
||||
$stmt->close();
|
||||
}
|
||||
|
||||
// 处理上传的预览图片
|
||||
if (!empty($_FILES['images']['name'][0])) {
|
||||
$uploadDir = '../images/';
|
||||
foreach ($_FILES['images']['tmp_name'] as $key => $tmpName) {
|
||||
$fileName = basename($_FILES['images']['name'][$key]);
|
||||
$targetPath = $uploadDir . $fileName;
|
||||
if (move_uploaded_file($tmpName, $targetPath)) {
|
||||
$insertImageSql = "INSERT INTO app_images (app_id, image_path) VALUES (?, ?)";
|
||||
$imgStmt = $conn->prepare($insertImageSql);
|
||||
$imgStmt->bind_param("is", $appId, $targetPath);
|
||||
$imgStmt->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理上传的App文件
|
||||
if (!empty($_FILES['app_file']['name'])) {
|
||||
$uploadDir = '../files/';
|
||||
$fileName = basename($_FILES['app_file']['name']);
|
||||
$targetPath = $uploadDir . $fileName;
|
||||
if (move_uploaded_file($_FILES['app_file']['tmp_name'], $targetPath)) {
|
||||
$version = $_POST['version'];
|
||||
$changelog = $_POST['changelog'];
|
||||
$insertVersionSql = "INSERT INTO app_versions (app_id, version, changelog, file_path) VALUES (?, ?, ?, ?)";
|
||||
$verStmt = $conn->prepare($insertVersionSql);
|
||||
$verStmt->bind_param("isss", $appId, $version, $changelog, $targetPath);
|
||||
$verStmt->execute();
|
||||
}
|
||||
}
|
||||
|
||||
header('Location: index.php?success=App 添加成功');
|
||||
exit;
|
||||
} else {
|
||||
$error = 'App 添加失败: '. $conn->error;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>添加App - <?php echo APP_STORE_NAME; ?></title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- 自定义CSS -->
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<!-- Fluent Design 模糊效果 -->
|
||||
<style>
|
||||
.blur-bg {
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php if (isset($error)): ?>
|
||||
<div style='color: red; padding: 10px; background-color: #ffeeee; border-radius: 5px; margin-bottom: 20px;'>
|
||||
<?php echo htmlspecialchars($error); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light blur-bg">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="../index.php"><?php echo APP_STORE_NAME; ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">App列表</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="addapp.php">添加App</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="?logout=true">退出登录</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<?php if (!empty($success)): ?>
|
||||
<div class="alert alert-success"><?php echo $success; ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($error)): ?>
|
||||
<div class="alert alert-danger"><?php echo $error; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h2>添加App</h2>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" class="form-control" id="name" name="name" required>
|
||||
<label for="name">App名称</label>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="tags" class="form-label">标签</label>
|
||||
<select id="tags" name="tags[]" multiple class="form-control">
|
||||
<?php
|
||||
$tagResult = $conn->query("SELECT id, name FROM tags");
|
||||
while ($tag = $tagResult->fetch_assoc()):
|
||||
?>
|
||||
<option value="<?php echo $tag['id']; ?>"><?php echo htmlspecialchars($tag['name']); ?></option>
|
||||
<?php endwhile; ?>
|
||||
</select>
|
||||
<small class="form-text text-muted">按住Ctrl键可选择多个标签</small>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<textarea class="form-control" id="description" name="description" rows="3" required></textarea>
|
||||
<label for="description">描述</label>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="age_rating" class="form-label">年龄分级</label>
|
||||
<select class="form-select" id="age_rating" name="age_rating" required>
|
||||
<option value="3+">3+</option>
|
||||
<option value="7+">7+</option>
|
||||
<option value="12+">12+</option>
|
||||
<option value="17+">17+</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-floating mb-3" id="ageRatingDescriptionGroup" style="display: none;">
|
||||
<textarea class="form-control" id="age_rating_description" name="age_rating_description" rows="3" placeholder="请说明为何需要此年龄分级"></textarea>
|
||||
<label for="age_rating_description">年龄分级说明</label>
|
||||
<div class="form-text">当年龄分级为12+或以上时,此项为必填</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">适用平台</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="android" id="android" name="platforms[]">
|
||||
<label class="form-check-label" for="android">Android</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="ios" id="ios" name="platforms[]">
|
||||
<label class="form-check-label" for="ios">iOS</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="windows" id="windows" name="platforms[]">
|
||||
<label class="form-check-label" for="windows">Windows</label>
|
||||
</div>
|
||||
<div id="windows_suboptions" class="ms-4 mt-2" style="display: none;">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="windows_version" id="windows_xp" value="windows_xp">
|
||||
<label class="form-check-label" for="windows_xp">XP以前</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="windows_version" id="windows_win7" value="windows_win7">
|
||||
<label class="form-check-label" for="windows_win7">Win7以后</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="macos" id="macos" name="platforms[]">
|
||||
<label class="form-check-label" for="macos">macOS</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="linux" id="linux" name="platforms[]">
|
||||
<label class="form-check-label" for="linux">Linux</label>
|
||||
</div>
|
||||
<div id="linux_suboptions" class="ms-4 mt-2" style="display: none;">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="linux_distribution" id="linux_ubuntu" value="linux_ubuntu">
|
||||
<label class="form-check-label" for="linux_ubuntu">Ubuntu</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="linux_distribution" id="linux_arch" value="linux_arch">
|
||||
<label class="form-check-label" for="linux_arch">Arch Linux</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="linux_distribution" id="linux_centos" value="linux_centos">
|
||||
<label class="form-check-label" for="linux_centos">CentOS</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" class="form-control" id="version" name="version" required>
|
||||
<label for="version">版本号</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<textarea class="form-control" id="changelog" name="changelog" rows="3" required></textarea>
|
||||
<label for="changelog">更新日志</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input class="form-control" type="file" id="app_file" name="app_file" required>
|
||||
<label for="app_file">App文件</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input class="form-control" type="file" id="images" name="images[]" multiple>
|
||||
<label for="images">预览图片 (可多选)</label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary" name="add_app">添加App</button>
|
||||
<a href="index.php" class="btn btn-secondary ms-2">取消</a>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS Bundle with Popper -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
// 年龄分级说明显示控制
|
||||
const ageRatingSelect = document.getElementById('age_rating');
|
||||
const descriptionGroup = document.getElementById('ageRatingDescriptionGroup');
|
||||
const descriptionInput = document.getElementById('age_rating_description');
|
||||
|
||||
function toggleAgeDescription() {
|
||||
const selectedRating = ageRatingSelect.value;
|
||||
if (selectedRating === '12+' || selectedRating === '17+') {
|
||||
descriptionGroup.style.display = 'block';
|
||||
descriptionInput.required = true;
|
||||
} else {
|
||||
descriptionGroup.style.display = 'none';
|
||||
descriptionInput.required = false;
|
||||
}
|
||||
}
|
||||
|
||||
ageRatingSelect.addEventListener('change', toggleAgeDescription);
|
||||
// 初始加载时检查
|
||||
toggleAgeDescription();
|
||||
|
||||
|
||||
// 导航栏滚动效果
|
||||
window.addEventListener('scroll', function() {
|
||||
const navbar = document.querySelector('.navbar');
|
||||
if (window.scrollY > 10) {
|
||||
navbar.classList.add('scrolled');
|
||||
} else {
|
||||
navbar.classList.remove('scrolled');
|
||||
}
|
||||
});
|
||||
|
||||
// 平台子选项显示控制
|
||||
document.getElementById('windows').addEventListener('change', function() {
|
||||
const suboptions = document.getElementById('windows_suboptions');
|
||||
suboptions.style.display = this.checked ? 'block' : 'none';
|
||||
if (!this.checked) {
|
||||
document.querySelectorAll('input[name="windows_version"]').forEach(radio => radio.checked = false);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('linux').addEventListener('change', function() {
|
||||
const suboptions = document.getElementById('linux_suboptions');
|
||||
suboptions.style.display = this.checked ? 'block' : 'none';
|
||||
if (!this.checked) {
|
||||
document.querySelectorAll('input[name="linux_distribution"]').forEach(radio => radio.checked = false);
|
||||
}
|
||||
});
|
||||
|
||||
// 表单提交验证
|
||||
document.querySelector('form').addEventListener('submit', function(e) {
|
||||
// 验证Windows子选项
|
||||
if (document.getElementById('windows').checked && !document.querySelector('input[name="windows_version"]:checked')) {
|
||||
e.preventDefault();
|
||||
Swal.fire({
|
||||
title: '提示',
|
||||
text: '请选择Windows版本(XP以前或Win7以后)',
|
||||
icon: 'warning',
|
||||
confirmButtonText: '确定'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证Linux子选项
|
||||
if (document.getElementById('linux').checked && !document.querySelector('input[name="linux_distribution"]:checked')) {
|
||||
e.preventDefault();
|
||||
Swal.fire({
|
||||
title: '提示',
|
||||
text: '请选择Linux发行版(Ubuntu、Arch Linux或CentOS)',
|
||||
icon: 'warning',
|
||||
confirmButtonText: '确定'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新平台值包含子选项信息
|
||||
if (document.getElementById('windows').checked) {
|
||||
document.getElementById('windows').value = document.querySelector('input[name="windows_version"]:checked').value;
|
||||
}
|
||||
if (document.getElementById('linux').checked) {
|
||||
document.getElementById('linux').value = document.querySelector('input[name="linux_distribution"]:checked').value;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
179
admin/announcements.php
Normal file
179
admin/announcements.php
Normal file
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
require_once '../config.php';
|
||||
session_start();
|
||||
// 检查管理员登录状态
|
||||
if (!isset($_SESSION['admin']) || !isset($_SESSION['admin']['id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// 处理公告发布
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$title = $_POST['title'] ?? '';
|
||||
$content = $_POST['content'] ?? '';
|
||||
$admin_id = $_SESSION['admin']['id'];
|
||||
|
||||
if (!empty($title) && !empty($content)) {
|
||||
$stmt = $conn->prepare('INSERT INTO announcements (title, content, admin_id) VALUES (?, ?, ?)');
|
||||
$stmt->bind_param('ssi', $title, $content, $admin_id);
|
||||
if ($stmt->execute()) {
|
||||
header('Location: announcements.php?success=公告发布成功');
|
||||
exit;
|
||||
} else {
|
||||
$error = '公告发布失败: ' . $conn->error;
|
||||
}
|
||||
$stmt->close();
|
||||
} else {
|
||||
$error = '标题和内容不能为空';
|
||||
}
|
||||
}
|
||||
|
||||
// 获取公告列表
|
||||
$sql = 'SELECT a.*, ad.username FROM announcements a JOIN admins ad ON a.admin_id = ad.id ORDER BY a.created_at DESC';
|
||||
$result = $conn->query($sql);
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<style>
|
||||
.page-transition {
|
||||
animation: fadeIn 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>公告管理 - <?php echo APP_STORE_NAME; ?></title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- 自定义CSS -->
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
<!-- Fluent Design 模糊效果 -->
|
||||
<style>
|
||||
.blur-bg {
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="page-transition">
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light blur-bg">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="../index.php"><?php echo APP_STORE_NAME; ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">App列表</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="addapp.php">添加App</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="review_apps.php">审核APP</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="manage_developers.php">管理开发者</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="system_info.php">系统信息</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="announcements.php">公告管理</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="?logout=true">退出登录</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script>
|
||||
<?php if (isset($_GET['success'])): ?>
|
||||
Swal.fire({
|
||||
icon: "success",
|
||||
title: "成功",
|
||||
text: "<?php echo addslashes($_GET['success']); ?>",
|
||||
});
|
||||
<?php endif; ?>
|
||||
<?php if (isset($error)): ?>
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
title: "错误",
|
||||
text: "<?php echo addslashes($error); ?>",
|
||||
});
|
||||
<?php endif; ?>
|
||||
</script>
|
||||
|
||||
<h2>发布公告</h2>
|
||||
<form method="post">
|
||||
<div class="mb-3">
|
||||
<label for="title" class="form-label">标题</label>
|
||||
<input type="text" class="form-control" id="title" name="title" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="content" class="form-label">内容</label>
|
||||
<textarea class="form-control" id="content" name="content" rows="4" required></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">发布</button>
|
||||
</form>
|
||||
|
||||
<h2 class="mt-4">公告列表</h2>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>标题</th>
|
||||
<th>发布者</th>
|
||||
<th>发布时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php while ($row = $result->fetch_assoc()): ?>
|
||||
<tr>
|
||||
<td><?php echo $row['id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($row['title']); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['username']); ?></td>
|
||||
<td><?php echo $row['created_at']; ?></td>
|
||||
</tr>
|
||||
<?php endwhile; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS Bundle with Popper -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
// 导航栏滚动效果
|
||||
window.addEventListener('scroll', function() {
|
||||
const navbar = document.querySelector('.navbar');
|
||||
if (window.scrollY > 10) {
|
||||
navbar.classList.add('scrolled');
|
||||
} else {
|
||||
navbar.classList.remove('scrolled');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.body.classList.add('page-transition');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
41
admin/deleteapp.php
Normal file
41
admin/deleteapp.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
require_once '../config.php';
|
||||
|
||||
session_start();
|
||||
// 检查管理员登录状态
|
||||
if (!isset($_SESSION['admin'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// 验证App ID
|
||||
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
||||
header('Location: index.php?error=无效的App ID');
|
||||
exit;
|
||||
}
|
||||
$appId = $_GET['id'];
|
||||
|
||||
// 删除App
|
||||
$deleteAppSql = "DELETE FROM apps WHERE id = ?";
|
||||
$stmt = $conn->prepare($deleteAppSql);
|
||||
$stmt->bind_param("i", $appId);
|
||||
|
||||
if ($stmt->execute() === TRUE) {
|
||||
// 删除关联的图片
|
||||
$deleteImagesSql = "DELETE FROM app_images WHERE app_id = ?";
|
||||
$imgStmt = $conn->prepare($deleteImagesSql);
|
||||
$imgStmt->bind_param("i", $appId);
|
||||
$imgStmt->execute();
|
||||
|
||||
// 删除关联的版本
|
||||
$deleteVersionsSql = "DELETE FROM app_versions WHERE app_id = ?";
|
||||
$verStmt = $conn->prepare($deleteVersionsSql);
|
||||
$verStmt->bind_param("i", $appId);
|
||||
$verStmt->execute();
|
||||
|
||||
header('Location: index.php?success=App 删除成功');
|
||||
} else {
|
||||
header('Location: index.php?error=App 删除失败: '. $conn->error);
|
||||
}
|
||||
exit;
|
||||
?>
|
||||
395
admin/editapp.php
Normal file
395
admin/editapp.php
Normal file
@@ -0,0 +1,395 @@
|
||||
<?php
|
||||
require_once '../config.php';
|
||||
|
||||
session_start();
|
||||
// 检查管理员登录状态
|
||||
if (!isset($_SESSION['admin'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// 验证App ID
|
||||
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
||||
header('Location: index.php?error=无效的App ID');
|
||||
exit;
|
||||
}
|
||||
$appId = $_GET['id'];
|
||||
|
||||
// 获取App信息
|
||||
$app = null;
|
||||
$getAppSql = "SELECT * FROM apps WHERE id = ?";
|
||||
$stmt = $conn->prepare($getAppSql);
|
||||
$stmt->bind_param("i", $appId);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
if ($result->num_rows === 0) {
|
||||
header('Location: index.php?error=App不存在');
|
||||
exit;
|
||||
}
|
||||
$app = $result->fetch_assoc();
|
||||
$platforms = json_decode($app['platforms'], true);
|
||||
|
||||
$success = '';
|
||||
$error = '';
|
||||
// 处理编辑App请求
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['edit_app'])) {
|
||||
$name = $_POST['name'];
|
||||
$description = $_POST['description'];
|
||||
$ageRating = $_POST['age_rating'];
|
||||
$newPlatforms = json_encode($_POST['platforms'] ?? []);
|
||||
|
||||
// 处理表单提交
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// 验证必填字段
|
||||
$required = ['name', 'description', 'age_rating', 'platforms'];
|
||||
$errors = [];
|
||||
foreach ($required as $field) {
|
||||
if (empty($_POST[$field])) {
|
||||
$errors[] = ucfirst($field) . ' 不能为空';
|
||||
}
|
||||
}
|
||||
|
||||
// 年龄分级验证
|
||||
if (($_POST['age_rating'] === '12+' || $_POST['age_rating'] === '17+') && empty($_POST['age_rating_description'])) {
|
||||
$errors[] = '年龄分级为12+或以上时,年龄分级说明不能为空';
|
||||
}
|
||||
|
||||
// 处理应用图标上传(如果有新上传)
|
||||
if (!empty($_FILES['images']['name'][0])) {
|
||||
$uploadDir = '../images/';
|
||||
foreach ($_FILES['images']['tmp_name'] as $key => $tmpName) {
|
||||
$fileName = basename($_FILES['images']['name'][$key]);
|
||||
$targetPath = $uploadDir . $fileName;
|
||||
if (move_uploaded_file($tmpName, $targetPath)) {
|
||||
$insertImageSql = "INSERT INTO app_images (app_id, image_path) VALUES (?, ?)";
|
||||
$imgStmt = $conn->prepare($insertImageSql);
|
||||
$imgStmt->bind_param("is", $appId, $targetPath);
|
||||
$imgStmt->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理新上传的App文件
|
||||
if (!empty($_FILES['app_file']['name'])) {
|
||||
$uploadDir = '../files/';
|
||||
$fileName = basename($_FILES['app_file']['name']);
|
||||
$targetPath = $uploadDir . $fileName;
|
||||
if (move_uploaded_file($_FILES['app_file']['tmp_name'], $targetPath)) {
|
||||
$version = $_POST['version'];
|
||||
$changelog = $_POST['changelog'];
|
||||
$insertVersionSql = "INSERT INTO app_versions (app_id, version, changelog, file_path) VALUES (?, ?, ?, ?)";
|
||||
$verStmt = $conn->prepare($insertVersionSql);
|
||||
$verStmt->bind_param("isss", $appId, $version, $changelog, $targetPath);
|
||||
$verStmt->execute();
|
||||
}
|
||||
}
|
||||
|
||||
// 更新标签关联
|
||||
$stmt = $conn->prepare("DELETE FROM app_tags WHERE app_id = ?");
|
||||
$stmt->bind_param("i", $appId);
|
||||
$stmt->execute();
|
||||
$stmt->close();
|
||||
|
||||
if (!empty($_POST['tags'])) {
|
||||
$stmt = $conn->prepare("INSERT INTO app_tags (app_id, tag_id) VALUES (?, ?)");
|
||||
foreach ($_POST['tags'] as $tagId) {
|
||||
$stmt->bind_param("ii", $appId, $tagId);
|
||||
$stmt->execute();
|
||||
}
|
||||
$stmt->close();
|
||||
}
|
||||
|
||||
header('Location: index.php?success=App 更新成功');
|
||||
exit;
|
||||
} else {
|
||||
$error = 'App 更新失败: '. $conn->error;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>编辑App - <?php echo APP_STORE_NAME; ?></title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- 自定义CSS -->
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<!-- Fluent Design 模糊效果 -->
|
||||
<style>
|
||||
.blur-bg {
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light blur-bg">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="../index.php"><?php echo APP_STORE_NAME; ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">App列表</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="addapp.php">添加App</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="editapp.php?id=<?php echo $appId; ?>">编辑App</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="?logout=true">退出登录</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<?php if (!empty($success)): ?>
|
||||
<div class="alert alert-success"><?php echo $success; ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($error)): ?>
|
||||
<div class="alert alert-danger"><?php echo $error; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h2>编辑App: <?php echo htmlspecialchars($app['name']); ?></h2>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" class="form-control" id="name" name="name" value="<?php echo htmlspecialchars($app['name']); ?>" required>
|
||||
<label for="name">App名称</label>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="tags" class="form-label">标签</label>
|
||||
<select id="tags" name="tags[]" multiple class="form-control">
|
||||
<?php
|
||||
$selectedTags = [];
|
||||
$tagQuery = $conn->prepare("SELECT tag_id FROM app_tags WHERE app_id = ?");
|
||||
$tagQuery->bind_param("i", $appId);
|
||||
$tagQuery->execute();
|
||||
$tagResult = $tagQuery->get_result();
|
||||
while ($tag = $tagResult->fetch_assoc()) {
|
||||
$selectedTags[] = $tag['tag_id'];
|
||||
}
|
||||
|
||||
$allTags = $conn->query("SELECT id, name FROM tags");
|
||||
while ($tag = $allTags->fetch_assoc()):
|
||||
$selected = in_array($tag['id'], $selectedTags) ? 'selected' : '';
|
||||
?>
|
||||
<option value="<?php echo $tag['id']; ?>" <?php echo $selected; ?>><?php echo htmlspecialchars($tag['name']); ?></option>
|
||||
<?php endwhile; ?>
|
||||
</select>
|
||||
<div class="form-text">按住Ctrl键可选择多个标签</div>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<textarea class="form-control" id="description" name="description" rows="3" required><?php echo htmlspecialchars($app['description']); ?></textarea>
|
||||
<label for="description">描述</label>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="age_rating" class="form-label">年龄分级</label>
|
||||
<select class="form-select" id="age_rating" name="age_rating" required>
|
||||
<option value="3+" <?php echo $app['age_rating'] === '3+' ? 'selected' : ''; ?>>3+</option>
|
||||
<option value="7+" <?php echo $app['age_rating'] === '7+' ? 'selected' : ''; ?>>7+</option>
|
||||
<option value="12+" <?php echo $app['age_rating'] === '12+' ? 'selected' : ''; ?>>12+</option>
|
||||
<option value="17+" <?php echo $app['age_rating'] === '17+' ? 'selected' : ''; ?>>17+</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3" id="ageRatingDescriptionGroup" style="display: none;">
|
||||
<label for="age_rating_description" class="form-label">年龄分级说明</label>
|
||||
<textarea class="form-control" id="age_rating_description" name="age_rating_description" rows="3" placeholder="请说明为何需要此年龄分级"><?php echo htmlspecialchars($app['age_rating_description'] ?? ''); ?></textarea>
|
||||
<div class="form-text">当年龄分级为12+或以上时,此项为必填</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">适用平台</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="android" id="android" name="platforms[]" <?php echo in_array('android', $platforms) ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="android">Android</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="ios" id="ios" name="platforms[]" <?php echo in_array('ios', $platforms) ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="ios">iOS</label>
|
||||
</div>
|
||||
<?php
|
||||
$windowsChecked = false;
|
||||
$windowsVersion = '';
|
||||
foreach ($platforms as $p) {
|
||||
if (strpos($p, 'windows_') === 0) {
|
||||
$windowsChecked = true;
|
||||
$windowsVersion = $p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="windows" id="windows" name="platforms[]" <?php echo $windowsChecked ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="windows">Windows</label>
|
||||
</div>
|
||||
<div id="windows_suboptions" class="ms-4 mt-2" style="display: <?php echo $windowsChecked ? 'block' : 'none'; ?>">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="windows_version" id="windows_xp" value="windows_xp" <?php echo $windowsVersion === 'windows_xp' ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="windows_xp">XP以前</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="windows_version" id="windows_win7" value="windows_win7" <?php echo $windowsVersion === 'windows_win7' ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="windows_win7">Win7以后</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="macos" id="macos" name="platforms[]" <?php echo in_array('macos', $platforms) ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="macos">macOS</label>
|
||||
</div>
|
||||
<?php
|
||||
$linuxChecked = false;
|
||||
$linuxVersion = '';
|
||||
foreach ($platforms as $p) {
|
||||
if (strpos($p, 'linux_') === 0) {
|
||||
$linuxChecked = true;
|
||||
$linuxVersion = $p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="linux" id="linux" name="platforms[]" <?php echo $linuxChecked ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="linux">Linux</label>
|
||||
</div>
|
||||
<div id="linux_suboptions" class="ms-4 mt-2" style="display: <?php echo $linuxChecked ? 'block' : 'none'; ?>">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="linux_distribution" id="linux_ubuntu" value="linux_ubuntu" <?php echo $linuxVersion === 'linux_ubuntu' ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="linux_ubuntu">Ubuntu</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="linux_distribution" id="linux_arch" value="linux_arch" <?php echo $linuxVersion === 'linux_arch' ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="linux_arch">Arch Linux</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="linux_distribution" id="linux_centos" value="linux_centos" <?php echo $linuxVersion === 'linux_centos' ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="linux_centos">CentOS</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" class="form-control" id="version" name="version" placeholder="如: 1.0.1">
|
||||
<label for="version">新版本号</label>
|
||||
<div class="form-text">仅在上传新安装包时填写</div>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<textarea class="form-control" id="changelog" name="changelog" rows="3" placeholder="描述本次更新内容"></textarea>
|
||||
<label for="changelog">更新日志</label>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="app_file" class="form-label">新App文件 (可选)</label>
|
||||
<input class="form-control" type="file" id="app_file" name="app_file">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="images" class="form-label">新增预览图片 (可选, 可多选)</label>
|
||||
<input class="form-control" type="file" id="images" name="images[]" multiple>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary" name="edit_app">更新App</button>
|
||||
<a href="index.php" class="btn btn-secondary ms-2">取消</a>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS Bundle with Popper -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
// 年龄分级说明显示控制
|
||||
// 年龄分级说明显示控制
|
||||
const ageRatingSelect = document.getElementById('age_rating');
|
||||
const descriptionGroup = document.getElementById('ageRatingDescriptionGroup');
|
||||
const descriptionInput = document.getElementById('age_rating_description');
|
||||
|
||||
function toggleAgeDescription() {
|
||||
const selectedRating = ageRatingSelect.value;
|
||||
if (selectedRating === '12+' || selectedRating === '17+') {
|
||||
descriptionGroup.style.display = 'block';
|
||||
descriptionInput.required = true;
|
||||
} else {
|
||||
descriptionGroup.style.display = 'none';
|
||||
descriptionInput.required = false;
|
||||
}
|
||||
}
|
||||
|
||||
ageRatingSelect.addEventListener('change', toggleAgeDescription);
|
||||
// 初始加载时检查
|
||||
toggleAgeDescription();
|
||||
|
||||
// 导航栏滚动效果
|
||||
window.addEventListener('scroll', function() {
|
||||
const navbar = document.querySelector('.navbar');
|
||||
if (window.scrollY > 10) {
|
||||
navbar.classList.add('scrolled');
|
||||
} else {
|
||||
navbar.classList.remove('scrolled');
|
||||
}
|
||||
});
|
||||
|
||||
// 平台子选项显示控制
|
||||
document.getElementById('windows').addEventListener('change', function() {
|
||||
const suboptions = document.getElementById('windows_suboptions');
|
||||
suboptions.style.display = this.checked ? 'block' : 'none';
|
||||
if (!this.checked) {
|
||||
document.querySelectorAll('input[name="windows_version"]').forEach(radio => radio.checked = false);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('linux').addEventListener('change', function() {
|
||||
const suboptions = document.getElementById('linux_suboptions');
|
||||
suboptions.style.display = this.checked ? 'block' : 'none';
|
||||
if (!this.checked) {
|
||||
document.querySelectorAll('input[name="linux_distribution"]').forEach(radio => radio.checked = false);
|
||||
}
|
||||
});
|
||||
|
||||
// 表单提交验证
|
||||
document.querySelector('form').addEventListener('submit', function(e) {
|
||||
// 验证Windows子选项
|
||||
if (document.getElementById('windows').checked && !document.querySelector('input[name="windows_version"]:checked')) {
|
||||
e.preventDefault();
|
||||
Swal.fire({
|
||||
title: '提示',
|
||||
text: '请选择Windows版本(XP以前或Win7以后)',
|
||||
icon: 'warning',
|
||||
confirmButtonText: '确定'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证Linux子选项
|
||||
if (document.getElementById('linux').checked && !document.querySelector('input[name="linux_distribution"]:checked')) {
|
||||
e.preventDefault();
|
||||
Swal.fire({
|
||||
title: '提示',
|
||||
text: '请选择Linux发行版(Ubuntu、Arch Linux或CentOS)',
|
||||
icon: 'warning',
|
||||
confirmButtonText: '确定'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新平台值包含子选项信息
|
||||
if (document.getElementById('windows').checked) {
|
||||
document.getElementById('windows').value = document.querySelector('input[name="windows_version"]:checked').value;
|
||||
}
|
||||
if (document.getElementById('linux').checked) {
|
||||
document.getElementById('linux').value = document.querySelector('input[name="linux_distribution"]:checked').value;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<?php
|
||||
// 更新应用数据
|
||||
$stmt = $conn->prepare("UPDATE apps SET name=?, description=?, age_rating=?, age_rating_description=?, platforms=?, updated_at=NOW() WHERE id=?");
|
||||
$stmt->bind_param("sssssi", $name, $description, $age_rating, $_POST['age_rating_description'], $platformsJson, $appId);
|
||||
|
||||
// ... existing code ...
|
||||
?>
|
||||
168
admin/index.php
Normal file
168
admin/index.php
Normal file
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
require_once '../config.php';
|
||||
|
||||
session_start();
|
||||
|
||||
if (!isset($conn) || !$conn instanceof mysqli) {
|
||||
die('数据库连接失败,请检查配置文件。');
|
||||
}
|
||||
|
||||
// 获取最新公告
|
||||
$sql = 'SELECT title, content FROM announcements ORDER BY created_at DESC LIMIT 1';
|
||||
$result = $conn->query($sql);
|
||||
$announcement = $result ? $result->fetch_assoc() : null;
|
||||
// 检查管理员登录状态
|
||||
if (!isset($_SESSION['admin'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// 处理退出登录
|
||||
if (isset($_GET['logout'])) {
|
||||
unset($_SESSION['admin']);
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取App列表
|
||||
$sqlApps = "SELECT * FROM apps WHERE status = 'approved' ORDER BY created_at DESC";
|
||||
$resultApps = $conn->query($sqlApps);
|
||||
|
||||
if (!$resultApps) {
|
||||
error_log("Database query failed: " . $conn->error);
|
||||
echo '<div class="alert alert-danger">获取App列表失败,请联系管理员。</div>';
|
||||
} else {
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<style>
|
||||
.page-transition {
|
||||
animation: fadeIn 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>App管理 - <?php echo APP_STORE_NAME; ?></title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- 自定义CSS -->
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
<!-- Fluent Design 模糊效果 -->
|
||||
<style>
|
||||
.blur-bg {
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="page-transition">
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light blur-bg">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="../index.php"><?php echo APP_STORE_NAME; ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="index.php">App列表</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="addapp.php">添加App</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="review_apps.php">审核APP</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="manage_developers.php">管理开发者</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="system_info.php">系统信息</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="announcements.php">公告管理</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="?logout=true">退出登录</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<?php if (isset($_GET['success'])): ?>
|
||||
<div class="alert alert-success"><?php echo $_GET['success']; ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (isset($_GET['error'])): ?>
|
||||
<div class="alert alert-danger"><?php echo $_GET['error']; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h2>App列表</h2>
|
||||
<div class="mb-3">
|
||||
<a href="manage_tags.php" class="btn btn-info">标签管理</a>
|
||||
</div>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>名称</th>
|
||||
<th>年龄分级</th>
|
||||
<th>创建时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php while ($app = $resultApps->fetch_assoc()): ?>
|
||||
<tr>
|
||||
<td><?php echo $app['id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($app['name']); ?></td>
|
||||
<td><?php echo $app['age_rating']; ?></td>
|
||||
<td><?php echo $app['created_at']; ?></td>
|
||||
<td>
|
||||
<a href="editapp.php?id=<?php echo $app['id']; ?>" class="btn btn-sm btn-outline-primary">编辑</a>
|
||||
<a href="manage_versions.php?app_id=<?php echo $app['id']; ?>" class="btn btn-sm btn-outline-secondary">版本管理</a>
|
||||
<a href="deleteapp.php?id=<?php echo $app['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('确定要删除吗?');">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endwhile; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS Bundle with Popper -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
// 导航栏滚动效果
|
||||
window.addEventListener('scroll', function() {
|
||||
const navbar = document.querySelector('.navbar');
|
||||
if (window.scrollY > 10) {
|
||||
navbar.classList.add('scrolled');
|
||||
} else {
|
||||
navbar.classList.remove('scrolled');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.body.classList.add('page-transition');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
111
admin/login.php
Normal file
111
admin/login.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
require_once '../config.php';
|
||||
|
||||
// 检查管理员登录状态
|
||||
session_start();
|
||||
|
||||
// 顶栏样式
|
||||
echo '<style>
|
||||
.navbar.scrolled {
|
||||
background-color: rgba(255, 255, 255, 0.95) !important;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
</style>';
|
||||
|
||||
// 导航栏
|
||||
echo '<nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="../index.php">'. APP_STORE_NAME . '</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="../index.php">首页</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">管理后台</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>';
|
||||
|
||||
// 为内容添加顶部内边距
|
||||
echo '<div style="padding-top: 70px;">';
|
||||
if (!isset($_SESSION['admin'])) {
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['username']) && isset($_POST['password'])) {
|
||||
$username = $_POST['username'];
|
||||
$password = $_POST['password'];
|
||||
|
||||
if ($username === ADMIN_USERNAME && $password === ADMIN_PASSWORD) {
|
||||
$_SESSION['admin'] = [
|
||||
'id' => 1, // 配置文件中未定义管理员ID,使用默认值1
|
||||
'username' => $username
|
||||
];
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
} else {
|
||||
$error = '用户名或密码错误';
|
||||
}
|
||||
}
|
||||
|
||||
// 显示登录表单
|
||||
echo '<!DOCTYPE html>';
|
||||
echo '<html lang="zh-CN">';
|
||||
echo '<head>';
|
||||
echo ' <meta charset="UTF-8">';
|
||||
echo ' <meta name="viewport" content="width=device-width, initial-scale=1.0">';
|
||||
echo ' <title>管理员登录 - '. APP_STORE_NAME . '</title>';
|
||||
echo ' <!-- Bootstrap CSS -->';
|
||||
echo ' <link href="../css/bootstrap.min.css" rel="stylesheet">';
|
||||
echo ' <!-- 自定义CSS -->';
|
||||
echo ' <link rel="stylesheet" href="../styles.css">';
|
||||
echo ' <!-- Fluent Design 模糊效果 -->';
|
||||
echo ' <style>';
|
||||
echo ' .blur-bg {';
|
||||
echo ' backdrop-filter: blur(10px);';
|
||||
echo ' background-color: rgba(255, 255, 255, 0.5);';
|
||||
echo ' }';
|
||||
echo ' </style>';
|
||||
echo '</head>';
|
||||
echo '<body>';
|
||||
echo ' <div class="container mt-5">';
|
||||
echo ' <div class="row justify-content-center">';
|
||||
echo ' <div class="col-md-6">';
|
||||
echo ' <div class="card blur-bg">';
|
||||
echo ' <div class="card-header">管理员登录</div>';
|
||||
echo ' <div class="card-body">';
|
||||
if (isset($error)) {
|
||||
echo '<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>';
|
||||
echo '<script>
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
title: "错误",
|
||||
text: "'. addslashes($error) . '",
|
||||
});
|
||||
</script>';
|
||||
}
|
||||
echo ' <form method="post">';
|
||||
echo ' <div class="mb-3">';
|
||||
echo ' <label for="username" class="form-label">用户名</label>';
|
||||
echo ' <input type="text" class="form-control" id="username" name="username" required>';
|
||||
echo ' </div>';
|
||||
echo ' <div class="mb-3">';
|
||||
echo ' <label for="password" class="form-label">密码</label>';
|
||||
echo ' <input type="password" class="form-control" id="password" name="password" required>';
|
||||
echo ' </div>';
|
||||
echo ' <button type="submit" class="btn btn-primary">登录</button>';
|
||||
echo ' </form>';
|
||||
echo ' </div>';
|
||||
echo ' </div>';
|
||||
echo ' </div>';
|
||||
echo ' </div>';
|
||||
echo ' </div>';
|
||||
echo ' <!-- Bootstrap JS Bundle with Popper -->';
|
||||
echo ' <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>';
|
||||
echo '</body>';
|
||||
echo '</html>';
|
||||
exit;
|
||||
}
|
||||
297
admin/manage_developers.php
Normal file
297
admin/manage_developers.php
Normal file
@@ -0,0 +1,297 @@
|
||||
<?php
|
||||
require_once '../config.php';
|
||||
|
||||
// 设置会话cookie路径为根目录以确保跨目录访问
|
||||
session_set_cookie_params(0, '/');
|
||||
session_start();
|
||||
// 检查管理员登录状态
|
||||
if (!isset($_SESSION['admin'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// 处理退出登录
|
||||
if (isset($_GET['logout'])) {
|
||||
unset($_SESSION['admin']);
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// 导航栏
|
||||
?>
|
||||
<nav class="navbar navbar-expand-lg navbar-light blur-bg">
|
||||
<div class="container mt-4">
|
||||
<a class="navbar-brand" href="../index.php"><?php echo APP_STORE_NAME; ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">App列表</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="addapp.php">添加App</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="review_apps.php">审核APP</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="manage_developers.php">管理开发者</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="?logout=true">退出登录</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<?php
|
||||
// 检查管理员权限
|
||||
// 设置会话cookie路径为根目录以确保跨目录访问
|
||||
session_set_cookie_params(0, '/');
|
||||
// 检查会话是否已启动,避免重复启动
|
||||
if (session_status() == PHP_SESSION_NONE) {
|
||||
if (!session_start()) {
|
||||
error_log('会话启动失败');
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
|
||||
error_log('会话启动失败');
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
// 从数据库验证用户角色,确保权限检查准确性
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
$userId = $_SESSION['user_id'];
|
||||
$stmt = $conn->prepare("SELECT role FROM users WHERE id = ?");
|
||||
if (!$stmt) {
|
||||
error_log('Database prepare failed: ' . $conn->error);
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
$stmt->bind_param("i", $userId);
|
||||
if (!$stmt->execute()) {
|
||||
error_log('Query execution failed: ' . $stmt->error);
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
$result = $stmt->get_result();
|
||||
if (!$result) {
|
||||
error_log('Failed to get result: ' . $stmt->error);
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
$user = $result->fetch_assoc();
|
||||
|
||||
if (!$user || $user['role'] !== 'admin') {
|
||||
error_log('用户 ' . $userId . ' 不是管理员,拒绝访问');
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
error_log('未找到用户会话,重定向到登录页');
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理删除用户请求
|
||||
if (isset($_POST['delete_user'])) {
|
||||
$userId = $_POST['user_id'];
|
||||
$stmt = $conn->prepare("DELETE FROM users WHERE id = ? AND role = 'developer'");
|
||||
if (!$stmt) {
|
||||
error_log('Database prepare failed: ' . $conn->error);
|
||||
header('Location: manage_developers.php?error=delete');
|
||||
exit;
|
||||
}
|
||||
$stmt->bind_param("i", $userId);
|
||||
if (!$stmt->execute()) {
|
||||
error_log('Delete query execution failed: ' . $stmt->error);
|
||||
header('Location: manage_developers.php?error=delete');
|
||||
exit;
|
||||
}
|
||||
$affected_rows = $stmt->affected_rows;
|
||||
$stmt->close();
|
||||
if ($affected_rows > 0) {
|
||||
header("Location: manage_developers.php?deleted=true");
|
||||
} else {
|
||||
error_log('No user deleted with ID: ' . $userId);
|
||||
header('Location: manage_developers.php?error=delete&user_id=' . $userId);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// 处理更新用户请求
|
||||
if (isset($_POST['update_user'])) {
|
||||
$userId = $_POST['user_id'];
|
||||
$username = $_POST['username'];
|
||||
$email = $_POST['email'];
|
||||
|
||||
// 使用mysqli语法更新用户信息
|
||||
$stmt = $conn->prepare("UPDATE developers SET username = ?, email = ? WHERE id = ?");
|
||||
if (!$stmt) {
|
||||
$error = $conn->error ?? 'Unknown error';
|
||||
error_log("Prepare failed: $error");
|
||||
die("更新用户信息失败: $error");
|
||||
}
|
||||
$stmt->bind_param("ssi", $username, $email, $userId);
|
||||
if (!$stmt->execute()) {
|
||||
$error = $stmt->error ?? 'Unknown error';
|
||||
error_log("Execute failed: $error");
|
||||
die("更新用户信息失败: $error");
|
||||
}
|
||||
$stmt->close();
|
||||
header("Location: manage_developers.php?updated=true");
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取所有开发者用户
|
||||
$developers = [];
|
||||
// 检查developers表是否存在
|
||||
$tableExists = $conn->query("SELECT 1 FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'developers'");
|
||||
if (!$tableExists || $tableExists->num_rows === 0) {
|
||||
error_log('Developers table does not exist');
|
||||
die('获取开发者列表失败: 开发者数据表不存在');
|
||||
}
|
||||
|
||||
$sql = "SELECT * FROM developers ORDER BY id DESC";
|
||||
$result = $conn->query($sql);
|
||||
if (!$result) {
|
||||
error_log('Failed to fetch developers. SQL: ' . $sql . ', Error: ' . $conn->error);
|
||||
die('获取开发者列表失败: ' . $conn->error . ' (SQL: ' . $sql . ')');
|
||||
}
|
||||
|
||||
// 检查是否有数据
|
||||
$rowCount = $result->num_rows;
|
||||
error_log('Developer query executed. Rows returned: ' . $rowCount);
|
||||
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$developers[] = $row;
|
||||
}
|
||||
|
||||
// 获取要编辑的用户信息
|
||||
$editUser = null;
|
||||
if (isset($_GET['edit'])) {
|
||||
$editId = (int)$_GET['edit'];
|
||||
$stmt = $conn->prepare("SELECT id, username, email FROM developers WHERE id = ?");
|
||||
if (!$stmt) {
|
||||
error_log('Prepare failed for edit user: ' . $conn->error);
|
||||
die('获取编辑用户信息失败: ' . $conn->error);
|
||||
}
|
||||
$stmt->bind_param("i", $editId);
|
||||
$stmt->execute();
|
||||
$editUser = $stmt->get_result()->fetch_assoc();
|
||||
$stmt->close();
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>管理开发者用户 - 应用商店管理</title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- 自定义CSS -->
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
<!-- Fluent Design 模糊效果 -->
|
||||
<style>
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Bootstrap JS Bundle with Popper -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
// 导航栏滚动效果
|
||||
window.addEventListener('scroll', function() {
|
||||
const navbar = document.querySelector('.navbar');
|
||||
if (window.scrollY > 10) {
|
||||
navbar.classList.add('scrolled');
|
||||
} else {
|
||||
navbar.classList.remove('scrolled');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<div class="container">
|
||||
<h1>管理开发者用户</h1>
|
||||
<pre>调试信息:
|
||||
查询SQL: <?php echo $sql; ?>
|
||||
查询结果行数: <?php echo $rowCount; ?>
|
||||
数据表存在: <?php echo $tableExists ? '是' : '否'; ?>
|
||||
开发者数据: <?php print_r($developers); ?></pre>
|
||||
|
||||
<?php if (isset($_GET['deleted'])): ?>
|
||||
<div class="alert alert-success">用户已成功删除</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (isset($_GET['updated'])): ?>
|
||||
<div class="alert alert-success">用户信息已成功更新</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($editUser): ?>
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h2>编辑开发者用户</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="manage_developers.php">
|
||||
<input type="hidden" name="user_id" value="<?php echo $editUser['id']; ?>">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" class="form-control" id="username" name="username" value="<?php echo htmlspecialchars($editUser['username']); ?>" required>
|
||||
<label for="username">用户名</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="email" class="form-control" id="email" name="email" value="<?php echo htmlspecialchars($editUser['email']); ?>" required>
|
||||
<label for="email">邮箱</label>
|
||||
</div>
|
||||
<button type="submit" name="update_user" class="btn btn-primary me-2">更新用户</button>
|
||||
<a href="manage_developers.php" class="btn btn-secondary">取消</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>用户名</th>
|
||||
<th>邮箱</th>
|
||||
<th>注册时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($developers as $developer): ?>
|
||||
<tr>
|
||||
<td><?php echo $developer['id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($developer['username']); ?></td>
|
||||
<td><?php echo htmlspecialchars($developer['email']); ?></td>
|
||||
<td><?php echo $developer['created_at']; ?></td>
|
||||
<td>
|
||||
<a href="manage_developers.php?edit=<?php echo $developer['id']; ?>" class="btn btn-sm btn-outline-primary">编辑</a>
|
||||
<form method="post" action="manage_developers.php" style="display: inline-block;" onsubmit="return confirm('确定要删除这个用户吗?');">
|
||||
<input type="hidden" name="user_id" value="<?php echo $developer['id']; ?>">
|
||||
<button type="submit" name="delete_user" class="btn btn-sm btn-outline-danger">删除</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if (empty($developers)): ?>
|
||||
<tr>
|
||||
<td colspan="5" class="text-center">暂无开发者数据</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
155
admin/manage_tags.php
Normal file
155
admin/manage_tags.php
Normal file
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
require_once '../config.php';
|
||||
require_once 'login.php'; // 确保管理员已登录
|
||||
|
||||
// 处理标签添加
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_tag'])) {
|
||||
$name = trim($_POST['tag_name']);
|
||||
if (!empty($name)) {
|
||||
$stmt = $conn->prepare("INSERT INTO tags (name) VALUES (?)");
|
||||
$stmt->bind_param("s", $name);
|
||||
if ($stmt->execute()) {
|
||||
header('Location: manage_tags.php?success=标签添加成功');
|
||||
exit;
|
||||
} else {
|
||||
$error = '添加失败: ' . $conn->error;
|
||||
}
|
||||
} else {
|
||||
$error = '标签名称不能为空';
|
||||
}
|
||||
}
|
||||
|
||||
// 处理标签删除
|
||||
if (isset($_GET['delete'])) {
|
||||
$tagId = intval($_GET['delete']);
|
||||
$stmt = $conn->prepare("DELETE FROM tags WHERE id = ?");
|
||||
$stmt->bind_param("i", $tagId);
|
||||
if ($stmt->execute()) {
|
||||
header('Location: manage_tags.php?success=标签删除成功');
|
||||
exit;
|
||||
} else {
|
||||
$error = '删除失败: ' . $conn->error;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理标签编辑
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['edit_tag'])) {
|
||||
$tagId = intval($_POST['tag_id']);
|
||||
$name = trim($_POST['tag_name']);
|
||||
if (!empty($name)) {
|
||||
$stmt = $conn->prepare("UPDATE tags SET name = ? WHERE id = ?");
|
||||
$stmt->bind_param("si", $name, $tagId);
|
||||
if ($stmt->execute()) {
|
||||
header('Location: manage_tags.php?success=标签更新成功');
|
||||
exit;
|
||||
} else {
|
||||
$error = '更新失败: ' . $conn->error;
|
||||
}
|
||||
} else {
|
||||
$error = '标签名称不能为空';
|
||||
}
|
||||
}
|
||||
|
||||
// 获取所有标签
|
||||
$tagsResult = $conn->query("SELECT * FROM tags ORDER BY created_at DESC");
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>标签管理 - 应用商店后台</title>
|
||||
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container mt-5">
|
||||
<h1 class="mb-4">标签管理</h1>
|
||||
<a href="index.php" class="btn btn-secondary mb-3">返回应用列表</a>
|
||||
|
||||
<?php if (isset($_GET['success'])): ?>
|
||||
<div class="alert alert-success"><?php echo $_GET['success']; ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (isset($error)): ?>
|
||||
<div class="alert alert-danger"><?php echo $error; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- 添加标签表单 -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">添加新标签</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" class="form-control" id="tag_name" name="tag_name" required>
|
||||
<label for="tag_name">标签名称</label>
|
||||
</div>
|
||||
<button type="submit" name="add_tag" class="btn btn-primary">添加标签</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 标签列表 -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">现有标签</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>标签名称</th>
|
||||
<th>创建时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php while ($tag = $tagsResult->fetch_assoc()): ?>
|
||||
<tr>
|
||||
<td><?php echo $tag['id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($tag['name']); ?></td>
|
||||
<td><?php echo $tag['created_at']; ?></td>
|
||||
<td>
|
||||
<!-- 编辑按钮触发模态框 -->
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#editModal<?php echo $tag['id']; ?>">
|
||||
编辑
|
||||
</button>
|
||||
<a href="manage_tags.php?delete=<?php echo $tag['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('确定要删除这个标签吗?关联的应用标签也会被删除。');">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- 编辑标签模态框 -->
|
||||
<div class="modal fade" id="editModal<?php echo $tag['id']; ?>" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">编辑标签</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="post">
|
||||
<input type="hidden" name="tag_id" value="<?php echo $tag['id']; ?>">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" class="form-control" id="edit_tag_name<?php echo $tag['id']; ?>" name="tag_name" value="<?php echo htmlspecialchars($tag['name']); ?>" required>
|
||||
<label for="edit_tag_name<?php echo $tag['id']; ?>">标签名称</label>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
||||
<button type="submit" name="edit_tag" class="btn btn-primary">保存修改</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endwhile; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
362
admin/manage_versions.php
Normal file
362
admin/manage_versions.php
Normal file
@@ -0,0 +1,362 @@
|
||||
<?php
|
||||
require_once '../config.php';
|
||||
|
||||
session_start();
|
||||
// 检查管理员登录状态
|
||||
if (!isset($_SESSION['admin'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// 验证App ID
|
||||
if (!isset($_GET['app_id']) || !is_numeric($_GET['app_id'])) {
|
||||
header('Location: index.php?error=无效的App ID');
|
||||
exit;
|
||||
}
|
||||
$appId = $_GET['app_id'];
|
||||
|
||||
// 获取App信息
|
||||
$app = null;
|
||||
$getAppSql = "SELECT * FROM apps WHERE id = ?";
|
||||
$stmt = $conn->prepare($getAppSql);
|
||||
$stmt->bind_param("i", $appId);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
if ($result->num_rows === 0) {
|
||||
header('Location: index.php?error=App不存在');
|
||||
exit;
|
||||
}
|
||||
$app = $result->fetch_assoc();
|
||||
|
||||
// 获取所有版本
|
||||
$versions = [];
|
||||
$getVersionsSql = "SELECT * FROM app_versions WHERE app_id = ? ORDER BY created_at DESC";
|
||||
$stmt = $conn->prepare($getVersionsSql);
|
||||
$stmt->bind_param("i", $appId);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$versions[] = $row;
|
||||
}
|
||||
|
||||
$success = '';
|
||||
$error = '';
|
||||
|
||||
// 处理添加版本
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_version'])) {
|
||||
$version = $_POST['version'];
|
||||
$changelog = $_POST['changelog'];
|
||||
|
||||
if (empty($version)) {
|
||||
$error = '版本号不能为空';
|
||||
} elseif (empty($_FILES['app_file']['name'])) {
|
||||
$error = '请上传App文件';
|
||||
} else {
|
||||
$uploadDir = '../files/';
|
||||
$fileName = basename($_FILES['app_file']['name']);
|
||||
$targetPath = $uploadDir . $fileName;
|
||||
|
||||
if (move_uploaded_file($_FILES['app_file']['tmp_name'], $targetPath)) {
|
||||
$insertVersionSql = "INSERT INTO app_versions (app_id, version, changelog, file_path, created_at) VALUES (?, ?, ?, ?, NOW())";
|
||||
$stmt = $conn->prepare($insertVersionSql);
|
||||
$stmt->bind_param("isss", $appId, $version, $changelog, $targetPath);
|
||||
|
||||
if ($stmt->execute() === TRUE) {
|
||||
header('Location: manage_versions.php?app_id=' . $appId . '&success=版本添加成功');
|
||||
exit;
|
||||
} else {
|
||||
$error = '版本添加失败: ' . $conn->error;
|
||||
unlink($targetPath); // 删除已上传的文件
|
||||
}
|
||||
} else {
|
||||
$error = '文件上传失败';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理删除版本
|
||||
if (isset($_GET['delete_id']) && is_numeric($_GET['delete_id'])) {
|
||||
$versionId = $_GET['delete_id'];
|
||||
|
||||
// 获取版本信息
|
||||
$getVersionSql = "SELECT file_path FROM app_versions WHERE id = ? AND app_id = ?";
|
||||
$stmt = $conn->prepare($getVersionSql);
|
||||
$stmt->bind_param("ii", $versionId, $appId);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($result->num_rows === 1) {
|
||||
$version = $result->fetch_assoc();
|
||||
|
||||
// 删除文件
|
||||
if (file_exists($version['file_path'])) {
|
||||
unlink($version['file_path']);
|
||||
}
|
||||
|
||||
// 删除数据库记录
|
||||
$deleteVersionSql = "DELETE FROM app_versions WHERE id = ? AND app_id = ?";
|
||||
$stmt = $conn->prepare($deleteVersionSql);
|
||||
$stmt->bind_param("ii", $versionId, $appId);
|
||||
|
||||
if ($stmt->execute() === TRUE) {
|
||||
header('Location: manage_versions.php?app_id=' . $appId . '&success=版本删除成功');
|
||||
exit;
|
||||
} else {
|
||||
$error = '版本删除失败: ' . $conn->error;
|
||||
}
|
||||
} else {
|
||||
$error = '版本不存在';
|
||||
}
|
||||
}
|
||||
|
||||
// 处理编辑版本
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['edit_version'])) {
|
||||
$versionId = $_POST['version_id'];
|
||||
$version = $_POST['version'];
|
||||
$changelog = $_POST['changelog'];
|
||||
|
||||
if (empty($version)) {
|
||||
$error = '版本号不能为空';
|
||||
} else {
|
||||
// 检查是否上传了新文件
|
||||
$fileUpdate = '';
|
||||
$params = ['ss', $version, $changelog, $versionId, $appId];
|
||||
|
||||
if (!empty($_FILES['new_app_file']['name'])) {
|
||||
$uploadDir = '../files/';
|
||||
$fileName = basename($_FILES['new_app_file']['name']);
|
||||
$targetPath = $uploadDir . $fileName;
|
||||
|
||||
if (move_uploaded_file($_FILES['new_app_file']['tmp_name'], $targetPath)) {
|
||||
// 获取旧文件路径
|
||||
$getOldFileSql = "SELECT file_path FROM app_versions WHERE id = ? AND app_id = ?";
|
||||
$stmt = $conn->prepare($getOldFileSql);
|
||||
$stmt->bind_param("ii", $versionId, $appId);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$oldVersion = $result->fetch_assoc();
|
||||
|
||||
// 删除旧文件
|
||||
if (file_exists($oldVersion['file_path'])) {
|
||||
unlink($oldVersion['file_path']);
|
||||
}
|
||||
|
||||
$fileUpdate = ", file_path = ?";
|
||||
$params[0] = 'sss';
|
||||
$params[] = $targetPath;
|
||||
} else {
|
||||
$error = '文件上传失败';
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($error)) {
|
||||
$updateVersionSql = "UPDATE app_versions SET version = ?, changelog = ?" . $fileUpdate . " WHERE id = ? AND app_id = ?";
|
||||
$stmt = $conn->prepare($updateVersionSql);
|
||||
|
||||
// 动态绑定参数
|
||||
$stmt->bind_param(...$params);
|
||||
|
||||
if ($stmt->execute() === TRUE) {
|
||||
header('Location: manage_versions.php?app_id=' . $appId . '&success=版本更新成功');
|
||||
exit;
|
||||
} else {
|
||||
$error = '版本更新失败: ' . $conn->error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取URL参数中的成功/错误消息
|
||||
if (isset($_GET['success'])) {
|
||||
$success = $_GET['success'];
|
||||
} elseif (isset($_GET['error'])) {
|
||||
$error = $_GET['error'];
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>管理版本 - <?php echo htmlspecialchars($app['name']); ?></title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- 自定义CSS -->
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
<style>
|
||||
.version-card {
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
.version-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
|
||||
}
|
||||
.action-btn {
|
||||
margin: 0 2px;
|
||||
}
|
||||
.modal-backdrop {
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="index.php"><?php echo APP_STORE_NAME; ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">App列表</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="editapp.php?id=<?php echo $appId; ?>">返回编辑App</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="manage_versions.php?app_id=<?php echo $appId; ?>">管理版本</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="?logout=true">退出登录</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<div class="row mb-4">
|
||||
<div class="col">
|
||||
<h1>管理版本: <?php echo htmlspecialchars($app['name']); ?></h1>
|
||||
<p class="text-muted">管理该应用的所有版本</p>
|
||||
</div>
|
||||
<div class="col text-end">
|
||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addVersionModal">
|
||||
添加新版本
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($success)): ?>
|
||||
<div class="alert alert-success"><?php echo $success; ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($error)): ?>
|
||||
<div class="alert alert-danger"><?php echo $error; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (empty($versions)): ?>
|
||||
<div class="alert alert-info">
|
||||
暂无版本记录
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="row">
|
||||
<?php foreach ($versions as $version): ?>
|
||||
<div class="col-md-6 col-lg-4 mb-4">
|
||||
<div class="card version-card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">版本 <?php echo htmlspecialchars($version['version']); ?></h5>
|
||||
<h6 class="card-subtitle mb-2 text-muted">发布日期: <?php echo date('Y-m-d H:i', strtotime($version['created_at'])); ?></h6>
|
||||
<p class="card-text"><?php echo nl2br(htmlspecialchars($version['changelog'])); ?></p>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent d-flex justify-content-between align-items-center">
|
||||
<small class="text-muted">文件大小: <?php
|
||||
$filePath = $version['file_path'];
|
||||
if (file_exists($filePath)) {
|
||||
echo filesize($filePath) > 0 ? number_format(filesize($filePath) / 1024 / 1024, 2) . ' MB' : '未知';
|
||||
} else {
|
||||
echo '文件不存在';
|
||||
}
|
||||
?></small>
|
||||
<div> <button type="button" class="btn btn-sm btn-outline-secondary action-btn" data-bs-toggle="modal" data-bs-target="#editVersionModal_<?php echo $version['id']; ?>"> 编辑 </button> <a href="../<?php echo htmlspecialchars($version['file_path']); ?>" class="btn btn-sm btn-primary action-btn" download>下载</a> <a href="?app_id=<?php echo $appId; ?>&delete_id=<?php echo $version['id']; ?>" class="btn btn-sm btn-outline-danger action-btn" onclick="return confirm('确定要删除此版本吗?');"> 删除 </a> </div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 编辑版本模态框 -->
|
||||
<div class="modal fade" id="editVersionModal_<?php echo $version['id']; ?>" tabindex="-1" aria-labelledby="editVersionModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="editVersionModalLabel">编辑版本 <?php echo htmlspecialchars($version['version']); ?></h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div class="modal-body">
|
||||
<input type="hidden" name="version_id" value="<?php echo $version['id']; ?>">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" class="form-control" id="version_<?php echo $version['id']; ?>" name="version" value="<?php echo htmlspecialchars($version['version']); ?>" required>
|
||||
<label for="version_<?php echo $version['id']; ?>">版本号</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<textarea class="form-control" id="changelog_<?php echo $version['id']; ?>" name="changelog" rows="3" required><?php echo htmlspecialchars($version['changelog']); ?></textarea>
|
||||
<label for="changelog_<?php echo $version['id']; ?>">更新日志</label>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="new_app_file_<?php echo $version['id']; ?>" class="form-label">更新App文件 (可选)</label>
|
||||
<input class="form-control" type="file" id="new_app_file_<?php echo $version['id']; ?>" name="new_app_file">
|
||||
<div class="form-text">当前文件: <?php echo basename($version['file_path']); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
||||
<button type="submit" class="btn btn-primary" name="edit_version">保存更改</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- 添加版本模态框 -->
|
||||
<div class="modal fade" id="addVersionModal" tabindex="-1" aria-labelledby="addVersionModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addVersionModalLabel">添加新版本</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div class="modal-body">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" class="form-control" id="version" name="version" placeholder="如: 1.0.0" required>
|
||||
<label for="version">版本号</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<textarea class="form-control" id="changelog" name="changelog" rows="3" placeholder="描述本次更新内容" required></textarea>
|
||||
<label for="changelog">更新日志</label>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="app_file" class="form-label">App文件</label>
|
||||
<input class="form-control" type="file" id="app_file" name="app_file" required>
|
||||
<a href="<?php echo htmlspecialchars($version['file_path']); ?>" class="btn btn-sm btn-primary" download>下载</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
||||
<button type="submit" class="btn btn-primary" name="add_version">添加版本</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS Bundle with Popper -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
// 导航栏滚动效果
|
||||
window.addEventListener('scroll', function() {
|
||||
const navbar = document.querySelector('.navbar');
|
||||
if (window.scrollY > 10) {
|
||||
navbar.classList.add('scrolled');
|
||||
} else {
|
||||
navbar.classList.remove('scrolled');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
277
admin/review_apps.php
Normal file
277
admin/review_apps.php
Normal file
@@ -0,0 +1,277 @@
|
||||
<?php
|
||||
require_once '../config.php';
|
||||
require_once '../vendor/autoload.php';
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
|
||||
session_start();
|
||||
// 检查管理员登录状态
|
||||
if (!isset($_SESSION['admin'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$success = '';
|
||||
$error = '';
|
||||
|
||||
// 处理审核操作
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['review_action'])) {
|
||||
$appId = $_POST['app_id'];
|
||||
$action = $_POST['review_action'];
|
||||
$rejectionReason = urldecode($_POST['rejection_reason'] ?? '');
|
||||
|
||||
// 验证应用ID
|
||||
if (!is_numeric($appId)) {
|
||||
$error = '无效的应用ID';
|
||||
} else {
|
||||
// 检查数据库连接
|
||||
if (!($conn instanceof mysqli)) {
|
||||
log_error('数据库连接错误: 连接不是MySQLi实例', __FILE__, __LINE__);
|
||||
$error = '数据库连接错误,请检查配置';
|
||||
} else {
|
||||
// 更新应用状态
|
||||
$status = $action === 'approve' ? 'approved' : 'rejected';
|
||||
$stmt = $conn->prepare("UPDATE apps SET status = ?, rejection_reason = ? WHERE id = ?");
|
||||
if (!$stmt) {
|
||||
$error = "数据库错误: " . $conn->error;
|
||||
} else {
|
||||
$stmt->bind_param("ssi", $status, $rejectionReason, $appId);
|
||||
if ($stmt->execute()) {
|
||||
// 获取应用信息和开发者邮箱
|
||||
$getAppStmt = $conn->prepare("SELECT name, developer_email FROM apps WHERE id = ?");
|
||||
$getAppStmt->bind_param("i", $appId);
|
||||
$getAppStmt->execute();
|
||||
$appResult = $getAppStmt->get_result();
|
||||
$appInfo = $appResult->fetch_assoc();
|
||||
$getAppStmt->close();
|
||||
|
||||
$success = '应用审核已更新';
|
||||
$appName = $appInfo['name'] ?? '未知应用';
|
||||
$devEmail = $appInfo['developer_email'] ?? '';
|
||||
|
||||
// 发送邮件通知
|
||||
if (!empty($devEmail)) {
|
||||
$mail = new PHPMailer(true);
|
||||
try {
|
||||
// 服务器配置
|
||||
$mail->isSMTP();
|
||||
$mail->Host = SMTP_HOST;
|
||||
$mail->Port = SMTP_PORT;
|
||||
$mail->SMTPSecure = SMTP_ENCRYPTION;
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = SMTP_USERNAME;
|
||||
$mail->Password = SMTP_PASSWORD;
|
||||
$mail->CharSet = 'UTF-8';
|
||||
$mail->isHTML(true);
|
||||
$mail->setFrom(SMTP_FROM_EMAIL, SMTP_FROM_NAME);
|
||||
$mail->addAddress($devEmail);
|
||||
|
||||
// 邮件内容
|
||||
if ($status === 'approved') {
|
||||
$mail->Subject = '应用审核通过通知';
|
||||
$mail->Body = "<div style='font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e0e0e0; border-radius: 8px;'>
|
||||
<h2 style='color: #2c3e50;'>应用审核通过通知</h2>
|
||||
<p>您好,</p>
|
||||
<p>您的应用 <strong>{$appName}</strong> 已成功通过审核!</p>
|
||||
<p>现在可以在应用商店中查看您的应用。</p>
|
||||
<p style='margin-top: 20px; color: #666;'>此致<br>应用商店团队</p>
|
||||
</div>";
|
||||
} else {
|
||||
$mail->Subject = '应用审核未通过通知';
|
||||
$mail->Body = "<div style='font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e0e0e0; border-radius: 8px;'>
|
||||
<h2 style='color: #e74c3c;'>应用审核未通过通知</h2>
|
||||
<p>您好,</p>
|
||||
<p>您的应用 <strong>{$appName}</strong> 未通过审核。</p>
|
||||
<p>原因:<br>{$rejectionReason}</p>
|
||||
<p style='margin-top: 20px; color: #666;'>此致<br>应用商店团队</p>
|
||||
</div>";
|
||||
}
|
||||
|
||||
$mail->send();
|
||||
$success .= ',邮件通知已发送';
|
||||
} catch (Exception $e) {
|
||||
log_error("邮件发送失败: {$mail->ErrorInfo}", __FILE__, __LINE__);
|
||||
$error = "审核状态已更新,但邮件发送失败: {$mail->ErrorInfo}";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$error = '更新审核状态失败: ' . $conn->error;
|
||||
}
|
||||
$stmt->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取待审核应用列表
|
||||
$pendingApps = [];
|
||||
if (!($conn instanceof mysqli)) {
|
||||
log_error('数据库连接错误: 连接不是MySQLi实例', __FILE__, __LINE__);
|
||||
$error = '数据库连接错误,请检查配置';
|
||||
} else {
|
||||
$stmt = $conn->prepare("SELECT a.id, a.name, a.description, a.status, a.created_at
|
||||
FROM apps a
|
||||
WHERE a.status = 'pending'
|
||||
ORDER BY a.created_at DESC");
|
||||
if (!$stmt) {
|
||||
$error = "数据库错误: " . $conn->error;
|
||||
} else {
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$pendingApps = $result->fetch_all(MYSQLI_ASSOC);
|
||||
$stmt->close();
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>应用审核 - <?php echo APP_STORE_NAME; ?></title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- SweetAlert2 CSS -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
|
||||
<!-- 自定义CSS -->
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
<!-- Fluent Design 模糊效果 -->
|
||||
<style>
|
||||
.blur-bg {
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.app-card {
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
.app-card:hover {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light blur-bg">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="../index.php"><?php echo APP_STORE_NAME; ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">App列表</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="addapp.php">添加App</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="review_apps.php">应用审核</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="?logout=true">退出登录</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<?php if (!empty($success)): ?>
|
||||
<div class="alert alert-success"><?php echo $success; ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($error)): ?>
|
||||
<div class="alert alert-danger"><?php echo $error; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h2>应用审核</h2>
|
||||
<p class="text-muted">待审核应用: <?php echo count($pendingApps); ?></p>
|
||||
|
||||
<?php if (empty($pendingApps)): ?>
|
||||
<div class="alert alert-info">没有待审核的应用</div>
|
||||
<?php else: ?>
|
||||
<div class="row">
|
||||
<?php foreach ($pendingApps as $app): ?>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card app-card shadow-sm">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="card-title mb-0"><?php echo htmlspecialchars($app['name']); ?></h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text"><strong>开发者:</strong> <?php echo htmlspecialchars($app['username']); ?></p>
|
||||
<p class="card-text"><strong>提交时间:</strong> <?php echo htmlspecialchars($app['created_at']); ?></p>
|
||||
<p class="card-text"><strong>描述:</strong> <?php echo nl2br(htmlspecialchars($app['description'])); ?></p>
|
||||
|
||||
<!-- 获取应用图片 -->
|
||||
<?php
|
||||
$images = [];
|
||||
$stmt = $conn->prepare("SELECT image_path FROM app_images WHERE app_id = ?");
|
||||
$stmt->bind_param("i", $app['id']);
|
||||
$stmt->execute();
|
||||
$imgResult = $stmt->get_result();
|
||||
while ($img = $imgResult->fetch_assoc()) {
|
||||
$images[] = $img['image_path'];
|
||||
}
|
||||
$stmt->close();
|
||||
?>
|
||||
|
||||
<?php if (!empty($images)): ?>
|
||||
<div class="mb-3">
|
||||
<strong>预览图片:</strong><br>
|
||||
<img src="<?php echo htmlspecialchars($images[0]); ?>" alt="应用截图" class="img-thumbnail" style="max-width: 200px;">
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="post" class="mt-3">
|
||||
<input type="hidden" name="app_id" value="<?php echo $app['id']; ?>">
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" name="review_action" value="approve" class="btn btn-success flex-grow-1">通过</button>
|
||||
<button type="button" class="btn btn-danger flex-grow-1" onclick="showRejectReason(<?php echo $app['id']; ?>, '<?php echo addslashes(htmlspecialchars($app['name'])); ?>')">拒绝</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function showRejectReason(appId, appName) {
|
||||
Swal.fire({
|
||||
title: '拒绝应用: ' + appName,
|
||||
html: '<textarea id="rejectionReason" class="swal2-textarea" rows="3" placeholder="请详细说明拒绝原因,帮助开发者改进应用"></textarea>',
|
||||
confirmButtonText: '确认拒绝',
|
||||
cancelButtonText: '取消',
|
||||
showCancelButton: true,
|
||||
validationMessage: '请输入拒绝原因',
|
||||
preConfirm: () => {
|
||||
const reason = document.getElementById('rejectionReason').value;
|
||||
if (!reason) {
|
||||
Swal.showValidationMessage('请输入拒绝原因');
|
||||
}
|
||||
return reason;
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
const form = document.createElement('form');
|
||||
form.method = 'post';
|
||||
form.innerHTML = `
|
||||
<input type="hidden" name="app_id" value="${appId}">
|
||||
<input type="hidden" name="review_action" value="reject">
|
||||
<input type="hidden" name="rejection_reason" value="${encodeURIComponent(result.value)}">
|
||||
`;
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS with Popper -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<!-- SweetAlert2 JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.all.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
194
admin/system_info.php
Normal file
194
admin/system_info.php
Normal file
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once '../config.php';
|
||||
|
||||
// 删除文件
|
||||
function delete_file($file_path) {
|
||||
if (file_exists($file_path)) {
|
||||
return unlink($file_path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 处理删除请求
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$upload_dirs = [
|
||||
'../uploads/apps',
|
||||
'../uploads/images'
|
||||
];
|
||||
|
||||
// 全量删除
|
||||
if (isset($_POST['delete_all'])) {
|
||||
foreach ($upload_dirs as $dir) {
|
||||
if (is_dir($dir)) {
|
||||
$files = scandir($dir);
|
||||
foreach ($files as $file) {
|
||||
if ($file !== '.' && $file !== '..') {
|
||||
$file_path = $dir . '/' . $file;
|
||||
if (is_file($file_path)) {
|
||||
delete_file($file_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
header('Location: ' . $_SERVER['PHP_SELF']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 单个删除
|
||||
if (isset($_POST['delete_files'])) {
|
||||
foreach ($_POST['delete_files'] as $file_info) {
|
||||
list($type, $filename) = explode('|', $file_info);
|
||||
$dir = $type === '图片' ? '../uploads/images' : '../uploads/apps';
|
||||
$file_path = $dir . '/' . $filename;
|
||||
delete_file($file_path);
|
||||
}
|
||||
header('Location: ' . $_SERVER['PHP_SELF']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// 验证管理员权限
|
||||
if (!isset($_SESSION['admin'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取上传文件和图片信息
|
||||
function get_uploaded_files_info() {
|
||||
$uploaded_files = [];
|
||||
|
||||
// 上传目录配置
|
||||
$upload_dirs = [
|
||||
'../uploads/apps',
|
||||
'../uploads/images'
|
||||
];
|
||||
|
||||
foreach ($upload_dirs as $dir) {
|
||||
if (is_dir($dir)) {
|
||||
$files = scandir($dir);
|
||||
foreach ($files as $file) {
|
||||
if ($file !== '.' && $file !== '..') {
|
||||
$file_path = $dir . '/' . $file;
|
||||
if (is_file($file_path)) {
|
||||
$file_size = filesize($file_path);
|
||||
$uploaded_files[] = [
|
||||
'name' => $file,
|
||||
'size' => $file_size,
|
||||
'type' => strpos($dir, 'images') !== false ? '图片' : '文件'
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $uploaded_files;
|
||||
}
|
||||
|
||||
$uploaded_files = get_uploaded_files_info();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>系统信息 - 上传文件列表</title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- 自定义CSS -->
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="index.php">管理员面板</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">首页</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="system_info.php">系统信息</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<form method="post">
|
||||
<h2>上传文件信息</h2>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><input type="checkbox" id="selectAll"></th>
|
||||
<th>文件名</th>
|
||||
<th>大小</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($uploaded_files as $file): ?>
|
||||
<?php if ($file['type'] === '文件'): ?>
|
||||
<tr>
|
||||
<td><input type="checkbox" name="delete_files[]" value="<?php echo $file['type'] . '|' . $file['name']; ?>"></td>
|
||||
<td><?php echo htmlspecialchars($file['name']); ?></td>
|
||||
<td><?php echo round($file['size'] / 1024, 2); ?> KB</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>上传图片信息</h2>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><input type="checkbox" id="selectAllImages"></th>
|
||||
<th>文件名</th>
|
||||
<th>大小</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($uploaded_files as $file): ?>
|
||||
<?php if ($file['type'] === '图片'): ?>
|
||||
<tr>
|
||||
<td><input type="checkbox" name="delete_files[]" value="<?php echo $file['type'] . '|' . $file['name']; ?>"></td>
|
||||
<td><?php echo htmlspecialchars($file['name']); ?></td>
|
||||
<td><?php echo round($file['size'] / 1024, 2); ?> KB</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<button type="submit" name="delete_all" class="btn btn-danger" onclick="return confirm('确定要删除所有文件吗?')">全量删除</button>
|
||||
<button type="submit" class="btn btn-danger ms-2" onclick="return confirm('确定要删除选中的文件吗?')">删除选中</button>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS Bundle with Popper -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
document.getElementById('selectAll').addEventListener('change', function() {
|
||||
const checkboxes = document.querySelectorAll('input[name="delete_files[]"]');
|
||||
checkboxes.forEach(checkbox => {
|
||||
checkbox.checked = this.checked;
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('selectAllImages').addEventListener('change', function() {
|
||||
const checkboxes = document.querySelectorAll('input[name="delete_files[]"]');
|
||||
checkboxes.forEach(checkbox => {
|
||||
checkbox.checked = this.checked;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
576
api.php
Normal file
576
api.php
Normal file
@@ -0,0 +1,576 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'config.php';
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$requestMethod = $_SERVER['REQUEST_METHOD'];
|
||||
|
||||
// API根路径处理 - 返回可用端点信息
|
||||
if (!isset($_GET['action'])) {
|
||||
http_response_code(200);
|
||||
echo json_encode([
|
||||
'status' => 'success',
|
||||
'message' => 'App Store API',
|
||||
'version' => '1.0',
|
||||
'endpoints' => [
|
||||
'/api?action=list' => '获取应用列表,支持search、platform、age_rating、tag、page、limit参数',
|
||||
'/api?action=app&id=1' => '获取指定ID的应用详情',
|
||||
'/api?action=favorite' => '收藏应用(POST方法,需app_id和user_id参数)'
|
||||
],
|
||||
'example' => 'GET /api?action=list&platform=windows&limit=20'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
// 支持查询参数路由模式(不依赖URL重写)
|
||||
if (isset($_GET['action'])) {
|
||||
$action = $_GET['action'];
|
||||
|
||||
// 处理应用列表请求
|
||||
if ($action === 'list' && $requestMethod === 'GET') {
|
||||
$sql = "SELECT apps.id, apps.name, apps.description, apps.age_rating, AVG(reviews.rating) as avg_rating
|
||||
FROM apps
|
||||
LEFT JOIN reviews ON apps.id = reviews.app_id";
|
||||
|
||||
$conditions = [];
|
||||
$stmtParams = [];
|
||||
$paramTypes = '';
|
||||
|
||||
// 搜索功能
|
||||
if (isset($_GET['search'])) {
|
||||
$search = '%' . $_GET['search'] . '%';
|
||||
$conditions[] = "(apps.name LIKE ? OR apps.description LIKE ?)";
|
||||
$stmtParams[] = &$search;
|
||||
$stmtParams[] = &$search;
|
||||
$paramTypes .= 'ss';
|
||||
}
|
||||
|
||||
// 平台过滤
|
||||
if (isset($_GET['platform'])) {
|
||||
$platform = $_GET['platform'];
|
||||
// Removed platform condition - column does not exist
|
||||
$stmtParams[] = &$platform;
|
||||
$paramTypes .= 's';
|
||||
}
|
||||
|
||||
// 年龄分级过滤
|
||||
if (isset($_GET['age_rating'])) {
|
||||
$ageRating = $_GET['age_rating'];
|
||||
$conditions[] = "apps.age_rating = ?";
|
||||
$stmtParams[] = &$ageRating;
|
||||
$paramTypes .= 's';
|
||||
}
|
||||
|
||||
// 标签过滤
|
||||
if (isset($_GET['tag'])) {
|
||||
$tag = $_GET['tag'];
|
||||
$conditions[] = "apps.id IN (SELECT app_id FROM app_tags JOIN tags ON app_tags.tag_id = tags.id WHERE tags.name = ?)";
|
||||
$stmtParams[] = &$tag;
|
||||
$paramTypes .= 's';
|
||||
}
|
||||
|
||||
// 分页参数处理
|
||||
$page = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;
|
||||
$limit = isset($_GET['limit']) ? min(100, max(1, intval($_GET['limit']))) : 10;
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
if (!empty($conditions)) {
|
||||
$sql .= " WHERE " . implode(" AND ", $conditions);
|
||||
}
|
||||
|
||||
// 添加分页
|
||||
$sql .= " GROUP BY apps.id, apps.name, apps.description, apps.age_rating ORDER BY apps.created_at DESC LIMIT ? OFFSET ?";
|
||||
$stmtParams[] = &$limit;
|
||||
$stmtParams[] = &$offset;
|
||||
$paramTypes .= 'ii';
|
||||
|
||||
// 获取总数用于分页元数据
|
||||
$countSql = "SELECT COUNT(DISTINCT apps.id) as total FROM apps LEFT JOIN reviews ON apps.id = reviews.app_id";
|
||||
if (!empty($conditions)) {
|
||||
$countSql .= " WHERE " . implode(" AND ", $conditions);
|
||||
}
|
||||
$countStmt = $conn->prepare($countSql);
|
||||
if ($paramTypes && count($stmtParams) > 2) {
|
||||
// 排除最后两个分页参数
|
||||
$countParams = array_slice($stmtParams, 0, -2);
|
||||
$countTypes = substr($paramTypes, 0, -2);
|
||||
call_user_func_array([$countStmt, 'bind_param'], array_merge([$countTypes], $countParams));
|
||||
}
|
||||
$countStmt->execute();
|
||||
$countResult = $countStmt->get_result();
|
||||
$total = $countResult->fetch_assoc()['total'] ?? 0;
|
||||
$totalPages = ceil($total / $limit);
|
||||
|
||||
// 执行主查询
|
||||
$stmt = $conn->prepare($sql);
|
||||
if (!$stmt) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Database error: ' . $conn->error]);
|
||||
exit;
|
||||
}
|
||||
call_user_func_array([$stmt, 'bind_param'], array_merge([$paramTypes], $stmtParams));
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
$apps = [];
|
||||
if ($result->num_rows > 0) {
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$apps[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
// 返回带分页元数据的响应
|
||||
echo json_encode([
|
||||
'data' => $apps,
|
||||
'pagination' => [
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'limit' => $limit,
|
||||
'totalPages' => $totalPages
|
||||
]
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 处理应用详情请求
|
||||
elseif ($action === 'app' && isset($_GET['id']) && is_numeric($_GET['id']) && $requestMethod === 'GET') {
|
||||
$appId = $_GET['id'];
|
||||
error_log("Requesting app details for ID: $appId");
|
||||
|
||||
$sqlApp = "SELECT apps.id, apps.name, apps.description, apps.age_rating, apps.created_at, AVG(reviews.rating) as avg_rating
|
||||
FROM apps
|
||||
LEFT JOIN reviews ON apps.id = reviews.app_id
|
||||
WHERE apps.id = ?
|
||||
GROUP BY apps.id, apps.name, apps.description, apps.age_rating, apps.created_at";
|
||||
$stmt = $conn->prepare($sqlApp);
|
||||
$stmt->bind_param("i", $appId);
|
||||
$stmt->execute();
|
||||
$resultApp = $stmt->get_result();
|
||||
error_log("Executing prepared statement for app details");
|
||||
|
||||
if (!$resultApp) {
|
||||
error_log("Database error: " . $conn->error);
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Database query failed']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$app = $resultApp->fetch_assoc();
|
||||
error_log("App found: " . ($app ? "Yes" : "No"));
|
||||
|
||||
if ($app) {
|
||||
// 获取版本信息
|
||||
$sqlVersions = "SELECT * FROM app_versions WHERE app_id = $appId ORDER BY created_at DESC";
|
||||
$resultVersions = $conn->query($sqlVersions);
|
||||
$versions = [];
|
||||
while ($version = $resultVersions->fetch_assoc()) {
|
||||
$versions[] = $version;
|
||||
}
|
||||
$app['versions'] = $versions;
|
||||
|
||||
// 获取图片信息
|
||||
$sqlImages = "SELECT * FROM app_images WHERE app_id = $appId";
|
||||
$resultImages = $conn->query($sqlImages);
|
||||
$images = [];
|
||||
while ($image = $resultImages->fetch_assoc()) {
|
||||
$images[] = $image;
|
||||
}
|
||||
$app['images'] = $images;
|
||||
|
||||
// 获取评价信息
|
||||
$sqlReviews = "SELECT * FROM reviews WHERE app_id = $appId ORDER BY created_at DESC";
|
||||
$resultReviews = $conn->query($sqlReviews);
|
||||
$reviews = [];
|
||||
while ($review = $resultReviews->fetch_assoc()) {
|
||||
$reviews[] = $review;
|
||||
}
|
||||
$app['reviews'] = $reviews;
|
||||
|
||||
// 获取应用标签
|
||||
$sqlTags = "SELECT tags.id, tags.name FROM app_tags JOIN tags ON app_tags.tag_id = tags.id WHERE app_tags.app_id = ?";
|
||||
$stmtTags = $conn->prepare($sqlTags);
|
||||
$stmtTags->bind_param("i", $appId);
|
||||
$stmtTags->execute();
|
||||
$resultTags = $stmtTags->get_result();
|
||||
$tags = [];
|
||||
while ($tag = $resultTags->fetch_assoc()) {
|
||||
$tags[] = $tag;
|
||||
}
|
||||
$app['tags'] = $tags;
|
||||
|
||||
echo json_encode($app);
|
||||
} else {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => "App with ID $appId not found", 'sql' => $sqlApp]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// 处理用户收藏应用
|
||||
elseif ($action === 'favorite' && isset($_GET['app_id']) && is_numeric($_GET['app_id']) && isset($_GET['user_id']) && is_numeric($_GET['user_id']) && $requestMethod === 'POST') {
|
||||
$appId = $_GET['app_id'];
|
||||
$userId = $_GET['user_id'];
|
||||
|
||||
$stmt = $conn->prepare("INSERT IGNORE INTO user_favorites (user_id, app_id) VALUES (?, ?)");
|
||||
$stmt->bind_param("ii", $userId, $appId);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
echo json_encode(['status' => 'success', 'message' => 'App added to favorites']);
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Failed to add to favorites']);
|
||||
}
|
||||
$stmt->close();
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取用户收藏列表
|
||||
elseif ($action === 'favorites' && isset($_GET['user_id']) && is_numeric($_GET['user_id']) && $requestMethod === 'GET') {
|
||||
$userId = $_GET['user_id'];
|
||||
|
||||
$sql = "SELECT apps.* FROM user_favorites JOIN apps ON user_favorites.app_id = apps.id WHERE user_favorites.user_id = $userId";
|
||||
$result = $conn->query($sql);
|
||||
|
||||
$favorites = [];
|
||||
if ($result->num_rows > 0) {
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$favorites[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($favorites);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取所有标签
|
||||
elseif ($action === 'tags' && $requestMethod === 'GET') {
|
||||
$sql = "SELECT id, name FROM tags ORDER BY name";
|
||||
$result = $conn->query($sql);
|
||||
$tags = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$tags[] = $row;
|
||||
}
|
||||
echo json_encode($tags);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取应用推荐列表
|
||||
elseif ($action === 'recommendations' && $requestMethod === 'GET') {
|
||||
$sql = "SELECT apps.*, app_recommendations.reason FROM app_recommendations JOIN apps ON app_recommendations.app_id = apps.id";
|
||||
$result = $conn->query($sql);
|
||||
|
||||
$recommendations = [];
|
||||
if ($result->num_rows > 0) {
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$recommendations[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($recommendations);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取热门应用排行榜
|
||||
elseif ($action === 'hot_apps' && $requestMethod === 'GET') {
|
||||
$sql = "SELECT apps.*, SUM(app_versions.download_count) as total_downloads FROM apps JOIN app_versions ON apps.id = app_versions.app_id GROUP BY apps.id ORDER BY total_downloads DESC LIMIT 10";
|
||||
$result = $conn->query($sql);
|
||||
|
||||
$hotApps = [];
|
||||
if ($result->num_rows > 0) {
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$hotApps[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($hotApps);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 提交用户反馈
|
||||
elseif ($action === 'feedback' && isset($_GET['user_id']) && is_numeric($_GET['user_id']) && $requestMethod === 'POST') {
|
||||
$userId = $_GET['user_id'];
|
||||
$appId = isset($_GET['app_id']) && is_numeric($_GET['app_id']) ? $_GET['app_id'] : null;
|
||||
$content = $_POST['content'] ?? '';
|
||||
|
||||
if (empty($content)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Feedback content is required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $conn->prepare("INSERT INTO user_feedback (user_id, app_id, content) VALUES (?, ?, ?)");
|
||||
$stmt->bind_param("iis", $userId, $appId, $content);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
echo json_encode(['status' => 'success', 'message' => 'Feedback submitted successfully']);
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Failed to submit feedback']);
|
||||
}
|
||||
$stmt->close();
|
||||
exit;
|
||||
}
|
||||
|
||||
// 处理下载请求
|
||||
elseif ($action === 'download' && isset($_GET['version_id']) && is_numeric($_GET['version_id']) && $requestMethod === 'GET') {
|
||||
$versionId = $_GET['version_id'];
|
||||
|
||||
$stmt = $conn->prepare("SELECT * FROM app_versions WHERE id = ?");
|
||||
$stmt->bind_param("i", $versionId);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($result->num_rows > 0) {
|
||||
$version = $result->fetch_assoc();
|
||||
// 更新下载计数
|
||||
$updateStmt = $conn->prepare("UPDATE app_versions SET download_count = download_count + 1 WHERE id = ?");
|
||||
$updateStmt->bind_param("i", $versionId);
|
||||
$updateStmt->execute();
|
||||
$updateStmt->close();
|
||||
$filePath = $version['file_path'];
|
||||
|
||||
if (file_exists($filePath)) {
|
||||
header('Content-Type: application/octet-stream');
|
||||
header('Content-Disposition: attachment; filename="' . basename($filePath) . '"');
|
||||
header('Content-Length: ' . filesize($filePath));
|
||||
readfile($filePath);
|
||||
exit;
|
||||
} else {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'File not found']);
|
||||
}
|
||||
} else {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Version not found']);
|
||||
}
|
||||
$stmt->close();
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取公告列表(支持分页)
|
||||
elseif ($action === 'announcements' && $requestMethod === 'GET') {
|
||||
$page = isset($_GET['page']) && is_numeric($_GET['page']) ? (int)$_GET['page'] : 1;
|
||||
$perPage = isset($_GET['per_page']) && is_numeric($_GET['per_page']) ? (int)$_GET['per_page'] : 10;
|
||||
$offset = ($page - 1) * $perPage;
|
||||
|
||||
// 获取总数
|
||||
$countSql = "SELECT COUNT(*) as total FROM announcements";
|
||||
$countResult = $conn->query($countSql);
|
||||
$total = $countResult->fetch_assoc()['total'];
|
||||
|
||||
// 获取分页数据
|
||||
$sql = "SELECT * FROM announcements ORDER BY created_at DESC LIMIT ?, ?";
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->bind_param("ii", $offset, $perPage);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
$announcements = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$announcements[] = $row;
|
||||
}
|
||||
|
||||
// 返回分页数据和元信息
|
||||
echo json_encode([
|
||||
'data' => $announcements,
|
||||
'pagination' => [
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'per_page' => $perPage,
|
||||
'total_pages' => ceil($total / $perPage)
|
||||
]
|
||||
]);
|
||||
$stmt->close();
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取最新公告
|
||||
elseif ($action === 'latest_announcement' && $requestMethod === 'GET') {
|
||||
$sql = "SELECT * FROM announcements ORDER BY created_at DESC LIMIT 1";
|
||||
$result = $conn->query($sql);
|
||||
|
||||
$announcement = $result->fetch_assoc();
|
||||
echo json_encode($announcement);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 添加公告
|
||||
elseif ($action === 'add_announcement' && $requestMethod === 'POST') {
|
||||
if (!isset($_SESSION['admin']['id'])) {
|
||||
http_response_code(403);
|
||||
echo json_encode(['error' => 'Unauthorized']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$title = $_POST['title'] ?? '';
|
||||
$content = $_POST['content'] ?? '';
|
||||
$adminId = $_SESSION['admin']['id'];
|
||||
|
||||
if (empty($title) || empty($content)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Title and content are required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $conn->prepare("INSERT INTO announcements (title, content, admin_id) VALUES (?, ?, ?)");
|
||||
$stmt->bind_param("ssi", $title, $content, $adminId);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
echo json_encode(['status' => 'success', 'message' => 'Announcement added successfully']);
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Failed to add announcement']);
|
||||
}
|
||||
$stmt->close();
|
||||
exit;
|
||||
}
|
||||
|
||||
// 删除公告
|
||||
elseif ($action === 'delete_announcement' && isset($_GET['id']) && is_numeric($_GET['id']) && $requestMethod === 'DELETE') {
|
||||
if (!isset($_SESSION['admin']['id'])) {
|
||||
http_response_code(403);
|
||||
echo json_encode(['error' => 'Unauthorized']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id = $_GET['id'];
|
||||
$stmt = $conn->prepare("DELETE FROM announcements WHERE id = ?");
|
||||
$stmt->bind_param("i", $id);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
echo json_encode(['status' => 'success', 'message' => 'Announcement deleted successfully']);
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Failed to delete announcement']);
|
||||
}
|
||||
$stmt->close();
|
||||
exit;
|
||||
}
|
||||
|
||||
// 更新公告
|
||||
elseif ($action === 'update_announcement' && isset($_GET['id']) && is_numeric($_GET['id']) && $requestMethod === 'PUT') {
|
||||
if (!isset($_SESSION['admin']['id'])) {
|
||||
http_response_code(403);
|
||||
echo json_encode(['error' => 'Unauthorized']);
|
||||
exit;
|
||||
}
|
||||
|
||||
parse_str(file_get_contents('php://input'), $putData);
|
||||
$id = $_GET['id'];
|
||||
$title = $putData['title'] ?? '';
|
||||
$content = $putData['content'] ?? '';
|
||||
|
||||
if (empty($title) || empty($content)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Title and content are required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $conn->prepare("UPDATE announcements SET title = ?, content = ? WHERE id = ?");
|
||||
$stmt->bind_param("ssi", $title, $content, $id);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
echo json_encode(['status' => 'success', 'message' => 'Announcement updated successfully']);
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Failed to update announcement']);
|
||||
}
|
||||
$stmt->close();
|
||||
exit;
|
||||
}
|
||||
|
||||
// 无效操作
|
||||
else {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Invalid action or parameters']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// 保留原路径路由逻辑作为兼容 fallback
|
||||
$requestUri = $_SERVER['REQUEST_URI'];
|
||||
$path = parse_url($requestUri, PHP_URL_PATH);
|
||||
$path = preg_replace('/\.php$/', '', $path);
|
||||
$pathParts = explode('/', trim($path, '/'));
|
||||
error_log("Path parts: " . print_r($pathParts, true));
|
||||
|
||||
if ($pathParts[0] === 'api') {
|
||||
error_log("Processing API path request: " . print_r($pathParts, true));
|
||||
// 处理应用详情请求 /api/app/<id>
|
||||
if (count($pathParts) >= 3 && $pathParts[1] === 'app' && is_numeric($pathParts[2])) {
|
||||
$appId = $pathParts[2];
|
||||
error_log("Path-based app details request for ID: $appId");
|
||||
|
||||
$sqlApp = "SELECT apps.id, apps.name, apps.description, apps.age_rating, apps.platform, apps.created_at, AVG(reviews.rating) as avg_rating
|
||||
FROM apps
|
||||
LEFT JOIN reviews ON apps.id = reviews.app_id
|
||||
WHERE apps.id = ?
|
||||
GROUP BY apps.id, apps.name, apps.description, apps.age_rating, apps.platform, apps.created_at";
|
||||
$stmt = $conn->prepare($sqlApp);
|
||||
$stmt->bind_param("i", $appId);
|
||||
$stmt->execute();
|
||||
$resultApp = $stmt->get_result();
|
||||
error_log("Executing prepared statement for path-based app details");
|
||||
|
||||
if (!$resultApp) {
|
||||
error_log("Database error: " . $conn->error);
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Database query failed']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$app = $resultApp->fetch_assoc();
|
||||
error_log("App found via path: " . ($app ? "Yes" : "No"));
|
||||
|
||||
if ($app) {
|
||||
// 获取版本信息
|
||||
$sqlVersions = "SELECT * FROM app_versions WHERE app_id = $appId ORDER BY created_at DESC";
|
||||
$resultVersions = $conn->query($sqlVersions);
|
||||
$versions = [];
|
||||
while ($version = $resultVersions->fetch_assoc()) {
|
||||
$versions[] = $version;
|
||||
}
|
||||
$app['versions'] = $versions;
|
||||
|
||||
// 获取图片信息
|
||||
$sqlImages = "SELECT * FROM app_images WHERE app_id = $appId";
|
||||
$resultImages = $conn->query($sqlImages);
|
||||
$images = [];
|
||||
while ($image = $resultImages->fetch_assoc()) {
|
||||
$images[] = $image;
|
||||
}
|
||||
$app['images'] = $images;
|
||||
|
||||
// 获取评价信息
|
||||
$sqlReviews = "SELECT * FROM reviews WHERE app_id = $appId ORDER BY created_at DESC";
|
||||
$resultReviews = $conn->query($sqlReviews);
|
||||
$reviews = [];
|
||||
while ($review = $resultReviews->fetch_assoc()) {
|
||||
$reviews[] = $review;
|
||||
}
|
||||
$app['reviews'] = $reviews;
|
||||
|
||||
echo json_encode($app);
|
||||
} else {
|
||||
http_response_code(404);
|
||||
echo json_encode([
|
||||
'error' => 'Not found',
|
||||
'path' => $path,
|
||||
'path_parts' => $pathParts,
|
||||
'action' => isset($_GET['action']) ? $_GET['action'] : null
|
||||
]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
// 处理其他API路径请求...
|
||||
}
|
||||
|
||||
http_response_code(404);
|
||||
echo json_encode([
|
||||
'error' => 'Not found',
|
||||
'path' => $path,
|
||||
'path_parts' => $pathParts,
|
||||
'action' => isset($_GET['action']) ? $_GET['action'] : null
|
||||
]);
|
||||
?>
|
||||
448
app.php
Normal file
448
app.php
Normal file
@@ -0,0 +1,448 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'config.php';
|
||||
|
||||
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$appId = $_GET['id'];
|
||||
|
||||
// 获取App信息
|
||||
$sqlApp = "SELECT apps.*, apps.developer_id, developers.username as developer_name, AVG(reviews.rating) as avg_rating
|
||||
FROM apps
|
||||
LEFT JOIN developers ON apps.developer_id = developers.id
|
||||
LEFT JOIN reviews ON apps.id = reviews.app_id
|
||||
WHERE apps.id = $appId
|
||||
GROUP BY apps.id, apps.developer_id, developers.username";
|
||||
$resultApp = $conn->query($sqlApp);
|
||||
if (!$resultApp) {
|
||||
die("<h1>数据库查询错误</h1><p>错误信息: " . htmlspecialchars($conn->error) . "</p><p>SQL语句: " . htmlspecialchars($sqlApp) . "</p>");
|
||||
}
|
||||
$app = $resultApp->fetch_assoc();
|
||||
$developerId = $app['developer_id'] ?? 0;
|
||||
$developerName = ($developerId == 0) ? '管理员' : ($app['developer_name'] ?? '未知开发者');
|
||||
|
||||
if (!$app) {
|
||||
die("<h1>错误:应用不存在</h1><p>找不到ID为 $appId 的应用。请检查ID是否正确。</p>");
|
||||
}
|
||||
|
||||
// 检查应用审核状态
|
||||
if ($app['status'] != 'approved') {
|
||||
echo '<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
Swal.fire({
|
||||
title: "应用审核中",
|
||||
text: "该应用正在审核中,暂时无法访问。",
|
||||
icon: "info",
|
||||
confirmButtonText: "确定"
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.history.back();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>';
|
||||
}
|
||||
|
||||
// 处理评价加载请求
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'load_reviews') {
|
||||
header('Content-Type: text/html; charset=UTF-8');
|
||||
// 获取评论数据
|
||||
$sqlReviews = "SELECT * FROM reviews WHERE app_id = ? ORDER BY created_at DESC, id DESC LIMIT 10 OFFSET ?";
|
||||
$stmt = $conn->prepare($sqlReviews);
|
||||
$offset = isset($_GET['offset']) ? intval($_GET['offset']) : 0;
|
||||
$stmt->bind_param("ii", $appId, $offset);
|
||||
$stmt->execute();
|
||||
$resultReviews = $stmt->get_result();
|
||||
|
||||
if (!$resultReviews) {
|
||||
die("Error fetching reviews: " . htmlspecialchars($conn->error));
|
||||
}
|
||||
|
||||
while ($review = $resultReviews->fetch_assoc()) {
|
||||
?>
|
||||
<div class="card mb-3 blur-bg">
|
||||
<div class="card-body">
|
||||
<?php
|
||||
$rating = $review['rating'] !== null ? $review['rating'] : 0;
|
||||
echo '<p class="card-text">评分: ';
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
if ($i <= floor($rating)) {
|
||||
echo '<span class="fas fa-star text-warning"></span>';
|
||||
} elseif ($i - $rating <= 0.5) {
|
||||
echo '<span class="fas fa-star-half-alt text-warning"></span>';
|
||||
} else {
|
||||
echo '<span class="far fa-star text-warning"></span>';
|
||||
}
|
||||
}
|
||||
echo '</p>';
|
||||
?>
|
||||
<p class="card-text"><small class="text-muted">评价时间: <?php echo $review['created_at']; ?></small></p>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取App版本信息
|
||||
$sqlVersions = "SELECT * FROM app_versions WHERE app_id = $appId ORDER BY created_at DESC";
|
||||
$resultVersions = $conn->query($sqlVersions);
|
||||
|
||||
// 获取App预览图片
|
||||
$sqlImages = "SELECT * FROM app_images WHERE app_id = $appId";
|
||||
$resultImages = $conn->query($sqlImages);
|
||||
|
||||
// 获取评价总数
|
||||
$sqlReviewCount = "SELECT COUNT(*) as total FROM reviews WHERE app_id = $appId";
|
||||
$resultReviewCount = $conn->query($sqlReviewCount);
|
||||
$reviewCount = $resultReviewCount->fetch_assoc()['total'];
|
||||
|
||||
// 分页参数
|
||||
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
|
||||
$limit = 10;
|
||||
$offset = ($page - 1) * $limit;
|
||||
$hasMore = ($page * $limit) < $reviewCount;
|
||||
|
||||
// 获取评价信息
|
||||
$sqlReviews = "SELECT * FROM reviews WHERE app_id = $appId ORDER BY created_at DESC, id DESC LIMIT 10 OFFSET $offset";
|
||||
$resultReviews = $conn->query($sqlReviews);
|
||||
|
||||
// 获取评分分布
|
||||
$sqlRatingDistribution = "SELECT rating, COUNT(*) as count FROM reviews WHERE app_id = $appId GROUP BY rating ORDER BY rating DESC";
|
||||
$resultRatingDistribution = $conn->query($sqlRatingDistribution);
|
||||
$ratingDistribution = [];
|
||||
while ($row = $resultRatingDistribution->fetch_assoc()) {
|
||||
$ratingDistribution[$row['rating']] = $row['count'];
|
||||
}
|
||||
|
||||
// 处理评价提交
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['rating'])) {
|
||||
$rating = $_POST['rating'];
|
||||
$ipAddress = $_SERVER['REMOTE_ADDR'];
|
||||
|
||||
$insertSql = "INSERT INTO reviews (app_id, rating) VALUES ($appId, $rating)"; if ($conn->query($insertSql) === TRUE) { header("Location: app.php?id=$appId"); exit; }
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php echo $app['name']; ?> - <?php echo APP_STORE_NAME; ?></title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Font Awesome -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<!-- SweetAlert2 -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.all.min.js"></script>
|
||||
<!-- 本地 Chart.js -->
|
||||
<script src="js/charts.js"></script>
|
||||
<!-- 自定义CSS -->
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<!-- Fluent Design 模糊效果 -->
|
||||
<style>
|
||||
.blur-bg {
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light blur-bg">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="index.php"><?php echo APP_STORE_NAME; ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">首页</a>
|
||||
</li>
|
||||
<?php if (isset($_SESSION['admin'])): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/admin/">管理</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h1><?php echo $app['name']; ?></h1>
|
||||
<p class="lead"><?php echo $app['description']; ?></p>
|
||||
<p>年龄分级: <?php echo $app['age_rating']; ?></p>
|
||||
<?php if (!empty($app['age_rating_description'])): ?>
|
||||
<div class="age-rating-description">
|
||||
<h4>年龄分级说明</h4>
|
||||
<p><?php echo nl2br(htmlspecialchars($app['age_rating_description'])); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<p>适用平台: <?php
|
||||
$platforms = json_decode($app['platforms'], true) ?? [];
|
||||
$platformIcons = [
|
||||
'windows' => '<i class="fab fa-windows"></i>',
|
||||
'macos' => '<i class="fab fa-apple"></i>',
|
||||
'linux' => '<i class="fab fa-linux"></i>',
|
||||
'android' => '<i class="fab fa-android"></i>',
|
||||
'ios' => '<i class="fab fa-app-store-ios"></i>'
|
||||
];
|
||||
$platformMap = [
|
||||
'android' => 'Android',
|
||||
'ios' => 'iOS',
|
||||
'windows_win7' => 'Windows(Windows 7以上)',
|
||||
'windows_xp' => 'Windows XP',
|
||||
'macos' => 'MacOS',
|
||||
'linux_arch' => 'Linux(适用于Arch Linux)',
|
||||
'linux_ubuntu' => 'Linux(适用于Ubuntu)',
|
||||
];
|
||||
|
||||
$platformTexts = [];
|
||||
foreach ($platforms as $platform) {
|
||||
$icon = $platformIcons[strtolower($platform)] ?? '';
|
||||
$readableName = $platformMap[strtolower($platform)] ?? ucfirst($platform);
|
||||
$platformTexts[] = $icon . ' ' . $readableName;
|
||||
}
|
||||
echo implode(', ', $platformTexts);
|
||||
?></p>
|
||||
<p>评分: <?php echo round($app['avg_rating'], 1); ?>/5</p>
|
||||
<p>开发者: <?php if ($developerId == 0 || empty($developerName)): ?>管理员<?php else: ?><a href="developer_apps.php?id=<?php echo $developerId; ?>"><?php echo htmlspecialchars($developerName); ?></a><?php endif; ?></p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div id="imageCarousel" class="carousel slide" data-bs-ride="carousel">
|
||||
<div class="carousel-inner">
|
||||
<?php
|
||||
$first = true;
|
||||
while ($image = $resultImages->fetch_assoc()) {
|
||||
$active = $first ? 'active' : '';
|
||||
echo '<div class="carousel-item '. $active . '">';
|
||||
echo '<img src="'. $image['image_path'] . '" class="d-block w-100" alt="App Image">';
|
||||
echo '</div>';
|
||||
$first = false;
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<button class="carousel-control-prev" type="button" data-bs-target="#imageCarousel" data-bs-slide="prev">
|
||||
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
|
||||
<span class="visually-hidden">Previous</span>
|
||||
</button>
|
||||
<button class="carousel-control-next" type="button" data-bs-target="#imageCarousel" data-bs-slide="next">
|
||||
<span class="carousel-control-next-icon" aria-hidden="true"></span>
|
||||
<span class="visually-hidden">Next</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-12">
|
||||
<h2>版本历史</h2>
|
||||
<?php while ($version = $resultVersions->fetch_assoc()): ?>
|
||||
<div class="card mb-3 blur-bg">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">版本 <?php echo $version['version']; ?></h5>
|
||||
<p class="card-text"><?php echo $version['changelog']; ?></p>
|
||||
<a href="<?php echo htmlspecialchars($version['file_path']); ?>" class="btn btn-primary btn-lg" download>立即下载</a>
|
||||
<a href="version_list.php?id=<?php echo $app['id']; ?>" class="btn btn-outline-secondary">查看版本历史</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-6">
|
||||
<h2>提交评价</h2>
|
||||
<form method="post" action="">
|
||||
<div class="mb-3">
|
||||
<label for="rating" class="form-label">评分</label>
|
||||
<select class="form-select" id="rating" name="rating" required>
|
||||
<option value="1">1星</option>
|
||||
<option value="2">2星</option>
|
||||
<option value="3">3星</option>
|
||||
<option value="4">4星</option>
|
||||
<option value="5">5星</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">提交评价</button>
|
||||
</form>
|
||||
<h2>评价</h2>
|
||||
<div id="reviews-container">
|
||||
<?php while ($review = $resultReviews->fetch_assoc()): ?>
|
||||
<div class="card mb-3 blur-bg">
|
||||
<div class="card-body">
|
||||
<?php
|
||||
$rating = $review['rating'] !== null ? $review['rating'] : 0;
|
||||
echo '<p class="card-text">评分: ';
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
if ($i <= floor($rating)) {
|
||||
echo '<span class="fas fa-star text-warning"></span>';
|
||||
} elseif ($i - $rating <= 0.5) {
|
||||
echo '<span class="fas fa-star-half-alt text-warning"></span>';
|
||||
} else {
|
||||
echo '<span class="far fa-star text-warning"></span>';
|
||||
}
|
||||
}
|
||||
echo '</p>';
|
||||
?>
|
||||
<p class="card-text"><small class="text-muted">评价时间: <?php echo $review['created_at']; ?></small></p>
|
||||
</div>
|
||||
</div>
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
<?php if ($hasMore): ?>
|
||||
<button id="load-more" class="btn btn-secondary" data-page="<?php echo $page + 1; ?>">加载更多</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h2>评分分布</h2>
|
||||
<div id="ratingChartSkeleton" class="skeleton-chart"></div>
|
||||
<canvas id="ratingChart" width="400" height="200"></canvas>
|
||||
<script>
|
||||
// 加载更多评价功能
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const loadMoreBtn = document.getElementById('load-more');
|
||||
if (loadMoreBtn) {
|
||||
loadMoreBtn.addEventListener('click', function() {
|
||||
const button = this;
|
||||
const page = parseInt(button.getAttribute('data-page'));
|
||||
const offset = (page - 1) * 10;
|
||||
const appId = <?php echo $appId; ?>;
|
||||
|
||||
button.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 加载中...';
|
||||
button.disabled = true;
|
||||
|
||||
fetch(`app.php?id=${appId}&offset=${offset}&action=load_reviews`)
|
||||
.then(response => response.text())
|
||||
.then(html => {
|
||||
if (html.trim() === '') {
|
||||
button.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
document.getElementById('reviews-container').insertAdjacentHTML('beforeend', html);
|
||||
button.innerHTML = '加载更多';
|
||||
button.disabled = false;
|
||||
button.setAttribute('data-page', parseInt(page) + 1);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('加载评价失败:', error);
|
||||
button.innerHTML = '加载更多';
|
||||
button.disabled = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 评分图表
|
||||
const ctx = document.getElementById('ratingChart').getContext('2d');
|
||||
new Chart(ctx).Bar({
|
||||
labels: ['5星', '4星', '3星', '2星', '1星'],
|
||||
datasets: [
|
||||
// {
|
||||
// label: '评分数量',
|
||||
// fillColor: 'rgba(75, 192, 192, 0.6)',
|
||||
// strokeColor: 'rgba(75, 192, 192, 1)',
|
||||
// highlightFill: 'rgba(75, 192, 192, 0.8)',
|
||||
// highlightStroke: 'rgba(75, 192, 192, 1)',
|
||||
// data: [
|
||||
// <?php echo $ratingDistribution[5] ?? 0; ?>,
|
||||
// <?php echo $ratingDistribution[4] ?? 0; ?>,
|
||||
// <?php echo $ratingDistribution[3] ?? 0; ?>,
|
||||
// <?php echo $ratingDistribution[2] ?? 0; ?>,
|
||||
// <?php echo $ratingDistribution[1] ?? 0; ?>
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// label: '评分数量',
|
||||
// fillColor: 'rgba(153, 102, 255, 0.6)',
|
||||
// strokeColor: 'rgba(153, 102, 255, 1)',
|
||||
// highlightFill: 'rgba(153, 102, 255, 0.8)',
|
||||
// highlightStroke: 'rgba(153, 102, 255, 1)',
|
||||
// data: [
|
||||
// <?php echo $ratingDistribution[5] ?? 0; ?>,
|
||||
// <?php echo $ratingDistribution[4] ?? 0; ?>,
|
||||
// <?php echo $ratingDistribution[3] ?? 0; ?>,
|
||||
// <?php echo $ratingDistribution[2] ?? 0; ?>,
|
||||
// <?php echo $ratingDistribution[1] ?? 0; ?>
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// label: '评分数量',
|
||||
// fillColor: 'rgba(255, 206, 86, 0.6)',
|
||||
// strokeColor: 'rgba(255, 206, 86, 1)',
|
||||
// highlightFill: 'rgba(255, 206, 86, 0.8)',
|
||||
// highlightStroke: 'rgba(255, 206, 86, 1)',
|
||||
// data: [
|
||||
// <?php echo $ratingDistribution[5] ?? 0; ?>,
|
||||
// <?php echo $ratingDistribution[4] ?? 0; ?>,
|
||||
// <?php echo $ratingDistribution[3] ?? 0; ?>,
|
||||
// <?php echo $ratingDistribution[2] ?? 0; ?>,
|
||||
// <?php echo $ratingDistribution[1] ?? 0; ?>
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// label: '评分数量',
|
||||
// fillColor: 'rgba(255, 99, 132, 0.6)',
|
||||
// strokeColor: 'rgba(255, 99, 132, 1)',
|
||||
// highlightFill: 'rgba(255, 99, 132, 0.8)',
|
||||
// highlightStroke: 'rgba(255, 99, 132, 1)',
|
||||
// data: [
|
||||
// <?php echo $ratingDistribution[5] ?? 0; ?>,
|
||||
// <?php echo $ratingDistribution[4] ?? 0; ?>,
|
||||
// <?php echo $ratingDistribution[3] ?? 0; ?>,
|
||||
// <?php echo $ratingDistribution[2] ?? 0; ?>,
|
||||
// <?php echo $ratingDistribution[1] ?? 0; ?>
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
label: '评分数量',
|
||||
fillColor: 'rgba(54, 162, 235, 0.6)',
|
||||
strokeColor: 'rgba(54, 162, 235, 1)',
|
||||
highlightFill: 'rgba(54, 162, 235, 0.8)',
|
||||
highlightStroke: 'rgba(54, 162, 235, 1)',
|
||||
data: [
|
||||
<?php echo $ratingDistribution[5] ?? 0; ?>,
|
||||
<?php echo $ratingDistribution[4] ?? 0; ?>,
|
||||
<?php echo $ratingDistribution[3] ?? 0; ?>,
|
||||
<?php echo $ratingDistribution[2] ?? 0; ?>,
|
||||
<?php echo $ratingDistribution[1] ?? 0; ?>
|
||||
]
|
||||
}
|
||||
]
|
||||
}, {
|
||||
scaleBeginAtZero: true,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
});
|
||||
document.getElementById('ratingChartSkeleton').style.display = 'none';
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS Bundle with Popper -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
// 导航栏滚动效果
|
||||
window.addEventListener('scroll', function() {
|
||||
const navbar = document.querySelector('.navbar');
|
||||
if (window.scrollY > 10) {
|
||||
navbar.classList.add('scrolled');
|
||||
} else {
|
||||
navbar.classList.remove('scrolled');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
287
app_store.sql
Normal file
287
app_store.sql
Normal file
@@ -0,0 +1,287 @@
|
||||
-- 创建数据库
|
||||
-- CREATE DATABASE IF NOT EXISTS app_store;
|
||||
-- 创建APP表
|
||||
CREATE TABLE IF NOT EXISTS apps (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
age_rating ENUM('3+', '7+', '12+', '17+') NOT NULL,
|
||||
age_rating_description TEXT,
|
||||
platforms JSON NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
version VARCHAR(20) NOT NULL,
|
||||
changelog TEXT NOT NULL,
|
||||
file_path VARCHAR(255) NOT NULL,
|
||||
status ENUM('pending', 'approved', 'rejected') DEFAULT 'pending',
|
||||
is_approved TINYINT(1) DEFAULT 0 COMMENT '应用是否已审核',
|
||||
developer_email VARCHAR(255) NOT NULL
|
||||
);
|
||||
|
||||
-- 确保状态列存在(用于现有数据库)
|
||||
|
||||
-- 创建APP版本表
|
||||
CREATE TABLE IF NOT EXISTS app_versions (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
app_id INT NOT NULL,
|
||||
version VARCHAR(50) NOT NULL,
|
||||
changelog TEXT NOT NULL,
|
||||
file_path VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (app_id) REFERENCES apps(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 创建APP预览图片表
|
||||
CREATE TABLE IF NOT EXISTS app_images (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
app_id INT NOT NULL,
|
||||
image_path VARCHAR(255) NOT NULL,
|
||||
FOREIGN KEY (app_id) REFERENCES apps(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 创建评价表
|
||||
CREATE TABLE IF NOT EXISTS reviews (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
app_id INT NOT NULL,
|
||||
ip_address VARCHAR(45) NOT NULL,
|
||||
rating TINYINT NOT NULL CHECK (rating BETWEEN 1 AND 5),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY unique_review (app_id, ip_address),
|
||||
FOREIGN KEY (app_id) REFERENCES apps(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 创建管理员表
|
||||
CREATE TABLE IF NOT EXISTS admins (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
username VARCHAR(50) NOT NULL UNIQUE,
|
||||
password VARCHAR(255) NOT NULL
|
||||
);
|
||||
|
||||
-- 插入默认管理员
|
||||
INSERT IGNORE INTO admins (username, password) VALUES ("admin", "your_admin_password_hash");
|
||||
|
||||
-- 创建用户表
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
username VARCHAR(50) NOT NULL UNIQUE,
|
||||
email VARCHAR(100) NOT NULL UNIQUE,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
last_login TIMESTAMP NULL
|
||||
);
|
||||
|
||||
-- 创建标签表
|
||||
CREATE TABLE IF NOT EXISTS tags (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(50) NOT NULL UNIQUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 创建应用标签关联表
|
||||
CREATE TABLE IF NOT EXISTS app_tags (
|
||||
app_id INT NOT NULL,
|
||||
tag_id INT NOT NULL,
|
||||
PRIMARY KEY (app_id, tag_id),
|
||||
FOREIGN KEY (app_id) REFERENCES apps(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 创建应用分类表
|
||||
CREATE TABLE IF NOT EXISTS categories (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL UNIQUE,
|
||||
description TEXT
|
||||
);
|
||||
|
||||
-- 应用与分类的多对多关系表
|
||||
CREATE TABLE IF NOT EXISTS app_categories (
|
||||
app_id INT NOT NULL,
|
||||
category_id INT NOT NULL,
|
||||
PRIMARY KEY (app_id, category_id),
|
||||
FOREIGN KEY (app_id) REFERENCES apps(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 修改评价表,支持文字评论并关联用户
|
||||
SET @exist_ip_address = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'reviews' AND COLUMN_NAME = 'ip_address');
|
||||
SET @sql = IF(@exist_ip_address > 0, 'ALTER TABLE reviews DROP COLUMN ip_address', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 检查并删除unique_review索引(如果存在)
|
||||
SET @exist_unique_review = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'reviews' AND INDEX_NAME = 'unique_review');
|
||||
SET @sql = IF(@exist_unique_review > 0, 'ALTER TABLE reviews DROP INDEX unique_review', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 检查并添加user_id列(如果不存在)
|
||||
SET @exist_user_id = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'reviews' AND COLUMN_NAME = 'user_id');
|
||||
SET @sql = IF(@exist_user_id = 0, 'ALTER TABLE reviews ADD COLUMN user_id INT', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 检查并添加comment列(如果不存在)
|
||||
SET @exist_comment = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'reviews' AND COLUMN_NAME = 'comment');
|
||||
SET @sql = IF(@exist_comment = 0, 'ALTER TABLE reviews ADD COLUMN comment TEXT', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 添加外键约束(如果不存在)
|
||||
SET @exist_fk = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'reviews' AND COLUMN_NAME = 'user_id' AND CONSTRAINT_NAME = 'fk_reviews_users');
|
||||
SET @sql = IF(@exist_fk = 0, 'ALTER TABLE reviews ADD CONSTRAINT fk_reviews_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
-- 检查并添加唯一索引(如果不存在)
|
||||
SET @exist_unique_index = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'reviews' AND INDEX_NAME = 'unique_user_app_review');
|
||||
SET @sql = IF(@exist_unique_index = 0, 'ALTER TABLE reviews ADD UNIQUE KEY unique_user_app_review (user_id, app_id)', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 添加应用下载统计
|
||||
SET @exist_download_count = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'awa' AND TABLE_NAME = 'app_versions' AND COLUMN_NAME = 'download_count');
|
||||
SET @sql = IF(@exist_download_count = 0, 'ALTER TABLE app_versions ADD COLUMN download_count INT DEFAULT 0', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 创建下载历史表
|
||||
CREATE TABLE IF NOT EXISTS download_history (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT,
|
||||
version_id INT NOT NULL,
|
||||
download_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL,
|
||||
FOREIGN KEY (version_id) REFERENCES app_versions(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 创建用户收藏表
|
||||
CREATE TABLE IF NOT EXISTS user_favorites (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
app_id INT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY unique_favorite (user_id, app_id),
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (app_id) REFERENCES apps(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 创建公告表
|
||||
CREATE TABLE IF NOT EXISTS announcements (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
admin_id INT NOT NULL,
|
||||
FOREIGN KEY (admin_id) REFERENCES admins(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 创建开发者表
|
||||
CREATE TABLE IF NOT EXISTS developers (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
username VARCHAR(50) NOT NULL UNIQUE,
|
||||
email VARCHAR(100) NOT NULL UNIQUE,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 添加开发者邮箱验证字段(条件性)
|
||||
SET @exist_verification_token = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'developers' AND COLUMN_NAME = 'verification_token');
|
||||
SET @sql = IF(@exist_verification_token = 0, 'ALTER TABLE developers ADD COLUMN verification_token VARCHAR(255) NULL', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @exist_is_verified = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'developers' AND COLUMN_NAME = 'is_verified');
|
||||
SET @sql = IF(@exist_is_verified = 0, 'ALTER TABLE developers ADD COLUMN is_verified BOOLEAN DEFAULT FALSE', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @exist_verified_at = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'developers' AND COLUMN_NAME = 'verified_at');
|
||||
SET @sql = IF(@exist_verified_at = 0, 'ALTER TABLE developers ADD COLUMN verified_at TIMESTAMP NULL', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 修改 apps 表,添加 developer_id 和 status 字段
|
||||
SET @exist_developer_id = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apps' AND COLUMN_NAME = 'developer_id');
|
||||
SET @sql = IF(@exist_developer_id = 0, 'ALTER TABLE apps ADD COLUMN developer_id INT', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @exist_status = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apps' AND COLUMN_NAME = 'status');
|
||||
SET @sql = IF(@exist_status = 0, 'ALTER TABLE apps ADD COLUMN status ENUM(''pending'', ''approved'', ''rejected'') DEFAULT ''pending''', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 添加应用拒绝原因字段
|
||||
SET @exist_rejection_reason = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apps' AND COLUMN_NAME = 'rejection_reason');
|
||||
SET @sql = IF(@exist_rejection_reason = 0, 'ALTER TABLE apps ADD COLUMN rejection_reason TEXT NULL', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @exist_fk = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apps' AND COLUMN_NAME = 'developer_id' AND CONSTRAINT_NAME = 'fk_apps_developers');
|
||||
|
||||
-- 添加 social_links 字段到 developers 表(条件性)
|
||||
SET @exist_social_links = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'developers' AND COLUMN_NAME = 'social_links');
|
||||
SET @sql = IF(@exist_social_links = 0, 'ALTER TABLE developers ADD social_links VARCHAR(255) DEFAULT '''' AFTER password', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
SET @sql = IF(@exist_fk = 0, 'ALTER TABLE apps ADD CONSTRAINT fk_apps_developers FOREIGN KEY (developer_id) REFERENCES developers(id) ON DELETE SET NULL', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 创建应用推荐表
|
||||
CREATE TABLE IF NOT EXISTS app_recommendations (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
app_id INT NOT NULL,
|
||||
reason TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (app_id) REFERENCES apps(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 创建应用更新通知表
|
||||
CREATE TABLE IF NOT EXISTS app_update_notifications (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
app_id INT NOT NULL,
|
||||
version_id INT NOT NULL,
|
||||
is_read BOOLEAN DEFAULT FALSE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (app_id) REFERENCES apps(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (version_id) REFERENCES app_versions(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 创建用户反馈表
|
||||
CREATE TABLE IF NOT EXISTS user_feedback (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
app_id INT,
|
||||
content TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (app_id) REFERENCES apps(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
-- 修改app_versions表,添加最后更新时间戳用于热门排行
|
||||
SET @exist_last_updated = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'app_versions' AND COLUMN_NAME = 'last_updated');
|
||||
SET @sql = IF(@exist_last_updated = 0, 'ALTER TABLE app_versions ADD COLUMN last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 创建验证令牌索引
|
||||
CREATE INDEX idx_verification_token ON developers(verification_token);
|
||||
|
||||
5
composer.json
Normal file
5
composer.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"require": {
|
||||
"phpmailer/phpmailer": "^6.10"
|
||||
}
|
||||
}
|
||||
100
composer.lock
generated
Normal file
100
composer.lock
generated
Normal file
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "cb5da62d73716ac8a1776f19367bc28f",
|
||||
"packages": [
|
||||
{
|
||||
"name": "phpmailer/phpmailer",
|
||||
"version": "v6.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPMailer/PHPMailer.git",
|
||||
"reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144",
|
||||
"reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-ctype": "*",
|
||||
"ext-filter": "*",
|
||||
"ext-hash": "*",
|
||||
"php": ">=5.5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
|
||||
"doctrine/annotations": "^1.2.6 || ^1.13.3",
|
||||
"php-parallel-lint/php-console-highlighter": "^1.0.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3.2",
|
||||
"phpcompatibility/php-compatibility": "^9.3.5",
|
||||
"roave/security-advisories": "dev-latest",
|
||||
"squizlabs/php_codesniffer": "^3.7.2",
|
||||
"yoast/phpunit-polyfills": "^1.0.4"
|
||||
},
|
||||
"suggest": {
|
||||
"decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication",
|
||||
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
|
||||
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
|
||||
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
|
||||
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
|
||||
"league/oauth2-google": "Needed for Google XOAUTH2 authentication",
|
||||
"psr/log": "For optional PSR-3 debug logging",
|
||||
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)",
|
||||
"thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PHPMailer\\PHPMailer\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-2.1-only"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marcus Bointon",
|
||||
"email": "phpmailer@synchromedia.co.uk"
|
||||
},
|
||||
{
|
||||
"name": "Jim Jagielski",
|
||||
"email": "jimjag@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Andy Prevost",
|
||||
"email": "codeworxtech@users.sourceforge.net"
|
||||
},
|
||||
{
|
||||
"name": "Brent R. Matzelle"
|
||||
}
|
||||
],
|
||||
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
|
||||
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.10.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/Synchro",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-04-24T15:19:31+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.3.0"
|
||||
}
|
||||
38
config.php
Normal file
38
config.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
// MySQL 配置
|
||||
define('DB_HOST', 'localhost:8000');
|
||||
define('DB_NAME', 'awa');
|
||||
define('DB_USER', 'aww');
|
||||
define('DB_PASSWORD', 'caocao123');
|
||||
|
||||
// App Store 名称
|
||||
define('APP_STORE_NAME', 'LeonAPP');
|
||||
|
||||
// SMTP邮件配置
|
||||
define('SMTP_HOST', 'smtp.163.com');
|
||||
define('SMTP_PORT', 25); // 163邮箱推荐使用587端口
|
||||
define('SMTP_ENCRYPTION', 'tls'); // 启用TLS加密
|
||||
define('SMTP_USERNAME', 'leonmm2@163.com'); // 使用完整邮箱地址作为用户名
|
||||
define('SMTP_PASSWORD', 'FHYNSqRhB6MqJQBw');
|
||||
define('SMTP_FROM_EMAIL', 'leonmm2@163.com');
|
||||
define('SMTP_FROM_NAME', 'leonmm2@163.com');
|
||||
|
||||
// 管理员账号
|
||||
define('ADMIN_USERNAME', 'Admin');
|
||||
define('ADMIN_PASSWORD', 'Caocao&123');
|
||||
|
||||
// 数据库连接
|
||||
$conn = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
|
||||
if ($conn->connect_error) {
|
||||
$error_msg = '数据库连接失败: ' . $conn->connect_error;
|
||||
log_error($error_msg, __FILE__, __LINE__);
|
||||
die($error_msg);
|
||||
}
|
||||
$conn->set_charset('utf8mb4');
|
||||
|
||||
// 设置时区
|
||||
date_default_timezone_set('Asia/Shanghai');
|
||||
|
||||
// 错误日志记录函数
|
||||
|
||||
?>
|
||||
9
css/all.min.css
vendored
Normal file
9
css/all.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
6
css/bootstrap.min.css
vendored
Normal file
6
css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
215
developer/dashboard.php
Normal file
215
developer/dashboard.php
Normal file
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
// 引入配置文件
|
||||
require_once '../config.php';
|
||||
|
||||
session_start();
|
||||
|
||||
// 检查开发者是否已登录
|
||||
if (!isset($_SESSION['developer_id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$developerId = $_SESSION['developer_id'];
|
||||
$developerUsername = $_SESSION['developer_username'];
|
||||
|
||||
// 检查数据库连接是否为 MySQLi 对象
|
||||
if (!($conn instanceof mysqli)) {
|
||||
log_error('数据库连接错误: 连接不是MySQLi实例', __FILE__, __LINE__);
|
||||
$error = '数据库连接错误,请检查配置';
|
||||
} else {
|
||||
// 获取开发者的应用列表
|
||||
$apps = [];
|
||||
$stmt = $conn->prepare('SELECT id, name, status, rejection_reason FROM apps WHERE developer_id = ?');
|
||||
if (!$stmt) {
|
||||
log_error('获取应用列表查询准备失败: ' . $conn->error, __FILE__, __LINE__);
|
||||
$error = '获取应用列表时发生错误,请稍后再试';
|
||||
} else {
|
||||
$stmt->bind_param('i', $developerId);
|
||||
if (!$stmt->execute()) {
|
||||
log_error('获取应用列表查询执行失败: ' . $stmt->error, __FILE__, __LINE__);
|
||||
$error = '获取应用列表时发生错误,请稍后再试';
|
||||
} else {
|
||||
$result = $stmt->get_result();
|
||||
$apps = $result->fetch_all(MYSQLI_ASSOC);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>开发者仪表盘 - <?php echo APP_STORE_NAME; ?></title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- 自定义CSS -->
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
<style>
|
||||
.blur-bg {
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.app-card {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
.dashboard-container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
.app-list {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.app-item {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.status-pending {
|
||||
color: orange;
|
||||
}
|
||||
.status-approved {
|
||||
color: green;
|
||||
}
|
||||
.status-rejected {
|
||||
color: red;
|
||||
}
|
||||
.action-buttons {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.action-buttons a {
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
background-color: #007BFF;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
border-radius: 3px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.action-buttons a:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
.add-app {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.add-app a {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
background-color: #28a745;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.add-app a:hover {
|
||||
background-color: #218838;
|
||||
}
|
||||
.logout {
|
||||
text-align: right;
|
||||
}
|
||||
.logout a {
|
||||
color: #dc3545;
|
||||
text-decoration: none;
|
||||
}
|
||||
.logout a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light blur-bg">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="../index.php"><?php echo APP_STORE_NAME; ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="dashboard.php">应用仪表盘</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="upload_app.php">上传应用</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="profile.php">更改信息</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="logout.php">退出登录</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="dashboard-container mt-4">
|
||||
<?php
|
||||
$rejectedApps = array_filter($apps, function($app) {
|
||||
return $app['status'] === 'rejected';
|
||||
});
|
||||
if (!empty($rejectedApps)):
|
||||
?>
|
||||
<div class="alert alert-danger">
|
||||
<strong>提醒:</strong> 您有 <?php echo count($rejectedApps); ?> 个应用未通过审核,请查看详情。
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h1>欢迎,<?php echo htmlspecialchars($developerUsername); ?>!</h1>
|
||||
<div class="add-app">
|
||||
<a href="upload_app.php">上传新应用</a>
|
||||
</div>
|
||||
<?php if (isset($error)): ?>
|
||||
<div style="color: red;"><?php echo $error; ?></div>
|
||||
<?php endif; ?>
|
||||
<div class="app-list">
|
||||
<h2>我的应用</h2>
|
||||
<?php if (empty($apps)): ?>
|
||||
<p>您还没有上传任何应用。</p>
|
||||
<?php else: ?>
|
||||
<?php foreach ($apps as $app): ?>
|
||||
<div class="card app-card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><?php echo htmlspecialchars($app['name']); ?></h5>
|
||||
<p class="card-text">
|
||||
状态:
|
||||
<?php if ($app['status'] === 'approved'): ?>
|
||||
<span class="badge bg-success">已通过</span>
|
||||
<?php elseif ($app['status'] === 'rejected'): ?>
|
||||
<span class="badge bg-danger">未通过</span>
|
||||
<div class="alert alert-warning mt-2">
|
||||
拒绝原因: <?php echo htmlspecialchars($app['rejection_reason']); ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-warning">待审核</span>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
<div class="action-buttons">
|
||||
<a href="edit_app.php?id=<?php echo $app['id']; ?>", class="btn btn-primary">编辑</a>
|
||||
<a href="version_control.php?id=<?php echo $app['id']; ?>", class="btn btn-secondary">版本控制</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Bootstrap JS and Popper -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
366
developer/edit_app.php
Normal file
366
developer/edit_app.php
Normal file
@@ -0,0 +1,366 @@
|
||||
<?php
|
||||
// 引入配置文件
|
||||
require_once '../config.php';
|
||||
|
||||
session_start();
|
||||
|
||||
// 检查开发者是否已登录
|
||||
if (!isset($_SESSION['developer_id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$developerId = $_SESSION['developer_id'];
|
||||
$error = '';
|
||||
$success = '';
|
||||
|
||||
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
||||
header('Location: dashboard.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$appId = $_GET['id'];
|
||||
$app = [];
|
||||
|
||||
// 检查数据库连接是否为 MySQLi 对象
|
||||
if (!($conn instanceof mysqli)) {
|
||||
log_error('数据库连接错误: 连接不是MySQLi实例', __FILE__, __LINE__);
|
||||
$error = '数据库连接错误,请检查配置';
|
||||
header('Location: dashboard.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取所有标签
|
||||
$tags = [];
|
||||
$tagStmt = $conn->query('SELECT id, name FROM tags');
|
||||
while ($tag = $tagStmt->fetch_assoc()) {
|
||||
$tags[] = $tag;
|
||||
}
|
||||
$tagStmt->close();
|
||||
|
||||
// 获取应用现有标签
|
||||
$appTags = [];
|
||||
$appTagStmt = $conn->prepare('SELECT tag_id FROM app_tags WHERE app_id = ?');
|
||||
$appTagStmt->bind_param('i', $appId);
|
||||
$appTagStmt->execute();
|
||||
$appTagResult = $appTagStmt->get_result();
|
||||
while ($tag = $appTagResult->fetch_assoc()) {
|
||||
$appTags[] = $tag['tag_id'];
|
||||
}
|
||||
$appTagStmt->close();
|
||||
|
||||
// 获取应用信息并验证开发者权限
|
||||
$stmt = $conn->prepare('SELECT id, name, description, version, changelog, age_rating, age_rating_description, platforms, file_path FROM apps WHERE id = ? AND developer_id = ?');
|
||||
if (!$stmt) {
|
||||
log_error('获取应用信息查询准备失败: ' . $conn->error, __FILE__, __LINE__);
|
||||
$error = '获取应用信息时发生错误,请稍后再试';
|
||||
header('Location: dashboard.php');
|
||||
exit;
|
||||
}
|
||||
$stmt->bind_param('ii', $appId, $developerId);
|
||||
if (!$stmt->execute()) {
|
||||
log_error('获取应用信息查询执行失败: ' . $stmt->error, __FILE__, __LINE__);
|
||||
$error = '获取应用信息时发生错误,请稍后再试';
|
||||
header('Location: dashboard.php');
|
||||
exit;
|
||||
}
|
||||
$result = $stmt->get_result();
|
||||
$app = $result->fetch_assoc();
|
||||
if (!$app) {
|
||||
header('Location: dashboard.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$appName = trim($_POST['name']);
|
||||
$appDescription = trim($_POST['description']);
|
||||
$version = trim($_POST['version']);
|
||||
$changelog = trim($_POST['changelog']);
|
||||
$ageRating = $_POST['age_rating'];
|
||||
$ageRatingDescription = trim($_POST['age_rating_description']);
|
||||
$platforms = $_POST['platforms'] ?? [];
|
||||
$platforms_json = json_encode($platforms);
|
||||
$appFilePath = $app['file_path']; // 默认使用现有文件路径
|
||||
|
||||
// 处理应用文件上传
|
||||
if (!empty($_FILES['app_file']['tmp_name'])) {
|
||||
$uploadDir = '../uploads/apps/';
|
||||
$fileExtension = pathinfo($_FILES['app_file']['name'], PATHINFO_EXTENSION);
|
||||
$newFileName = uniqid() . '.' . $fileExtension;
|
||||
$targetPath = $uploadDir . $newFileName;
|
||||
|
||||
// 验证文件类型和大小
|
||||
$allowedTypes = ['apk', 'exe', 'jar', 'crx', 'ini'];
|
||||
if (!in_array($fileExtension, $allowedTypes)) {
|
||||
$error = '不支持的文件类型,请上传 ' . implode(', ', $allowedTypes) . ' 格式的文件';
|
||||
} elseif ($_FILES['app_file']['size'] > 50 * 1024 * 1024) { // 50MB
|
||||
$error = '文件大小不能超过50MB';
|
||||
} elseif (!move_uploaded_file($_FILES['app_file']['tmp_name'], $targetPath)) {
|
||||
$error = '文件上传失败,请检查服务器权限';
|
||||
} else {
|
||||
// 删除旧文件
|
||||
if (file_exists($appFilePath)) {
|
||||
unlink($appFilePath);
|
||||
}
|
||||
$appFilePath = $targetPath;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理图片删除
|
||||
if (!empty($_POST['removed_images'])) {
|
||||
$removedImageIds = explode(',', $_POST['removed_images']);
|
||||
foreach ($removedImageIds as $imgId) {
|
||||
if (is_numeric($imgId)) {
|
||||
// 获取图片路径
|
||||
$stmt = $conn->prepare("SELECT image_path FROM app_images WHERE id = ?");
|
||||
$stmt->bind_param("i", $imgId);
|
||||
$stmt->execute();
|
||||
$imgResult = $stmt->get_result();
|
||||
if ($img = $imgResult->fetch_assoc()) {
|
||||
// 删除文件
|
||||
if (file_exists($img['image_path'])) {
|
||||
unlink($img['image_path']);
|
||||
}
|
||||
// 删除数据库记录
|
||||
$deleteStmt = $conn->prepare("DELETE FROM app_images WHERE id = ?");
|
||||
$deleteStmt->bind_param("i", $imgId);
|
||||
$deleteStmt->execute();
|
||||
$deleteStmt->close();
|
||||
}
|
||||
$stmt->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新应用标签
|
||||
// 删除现有标签关联
|
||||
$deleteTagStmt = $conn->prepare('DELETE FROM app_tags WHERE app_id = ?');
|
||||
$deleteTagStmt->bind_param('i', $appId);
|
||||
$deleteTagStmt->execute();
|
||||
$deleteTagStmt->close();
|
||||
|
||||
// 添加新标签关联
|
||||
foreach ($selectedTags as $tagId) {
|
||||
if (is_numeric($tagId)) {
|
||||
$tagStmt = $conn->prepare('INSERT INTO app_tags (app_id, tag_id) VALUES (?, ?)');
|
||||
$tagStmt->bind_param('ii', $appId, $tagId);
|
||||
$tagStmt->execute();
|
||||
$tagStmt->close();
|
||||
}
|
||||
}
|
||||
|
||||
// 处理新图片上传
|
||||
$imageUploadDir = '../uploads/images/';
|
||||
$allowedImageTypes = ['jpg', 'jpeg', 'png'];
|
||||
$maxImages = 5;
|
||||
$currentImageCount = count($existingImages) - count($removedImageIds ?? []);
|
||||
|
||||
if (!empty($_FILES['images']['name'][0]) && empty($error)) {
|
||||
$newImages = $_FILES['images'];
|
||||
for ($i = 0; $i < count($newImages['name']); $i++) {
|
||||
if ($newImages['error'][$i] !== UPLOAD_ERR_OK) continue;
|
||||
|
||||
$fileName = $newImages['name'][$i];
|
||||
$fileTmp = $newImages['tmp_name'][$i];
|
||||
$fileSize = $newImages['size'][$i];
|
||||
|
||||
$fileExt = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
if (!in_array($fileExt, $allowedImageTypes)) {
|
||||
$error = "图片 {$fileName} 格式不支持,仅允许jpg、png";
|
||||
break;
|
||||
}
|
||||
if ($fileSize > 2 * 1024 * 1024) { // 2MB
|
||||
$error = "图片 {$fileName} 大小超过2MB";
|
||||
break;
|
||||
}
|
||||
if ($currentImageCount >= $maxImages) {
|
||||
$error = "最多只能上传5张图片";
|
||||
break;
|
||||
}
|
||||
|
||||
$newFileName = uniqid() . '.' . $fileExt;
|
||||
$targetPath = $imageUploadDir . $newFileName;
|
||||
|
||||
if (move_uploaded_file($fileTmp, $targetPath)) {
|
||||
// 插入数据库
|
||||
$stmt = $conn->prepare("INSERT INTO app_images (app_id, image_path) VALUES (?, ?)");
|
||||
$stmt->bind_param("is", $appId, $targetPath);
|
||||
$stmt->execute();
|
||||
$stmt->close();
|
||||
$currentImageCount++;
|
||||
} else {
|
||||
$error = "图片 {$fileName} 上传失败";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 验证标签选择
|
||||
$selectedTags = $_POST['tags'] ?? [];
|
||||
if (empty($selectedTags)) {
|
||||
$error = '至少需要选择一个应用标签';
|
||||
}
|
||||
|
||||
if (empty($appName) || empty($appDescription) || empty($version) || empty($changelog) || empty($ageRating) || empty($ageRatingDescription)) {
|
||||
$error = '应用名称和描述不能为空';
|
||||
} else {
|
||||
// 检查数据库连接是否为 MySQLi 对象
|
||||
if (!($conn instanceof mysqli)) {
|
||||
log_error('数据库连接错误: 连接不是MySQLi实例', __FILE__, __LINE__);
|
||||
$error = '数据库连接错误,请检查配置';
|
||||
} else {
|
||||
$platforms = $_POST['platforms'] ?? [];
|
||||
$platforms_json = json_encode($platforms);
|
||||
$stmt = $conn->prepare('UPDATE apps SET name = ?, description = ?, version = ?, changelog = ?, age_rating = ?, age_rating_description = ?, platforms = ?, file_path = ?, status = \'pending\' WHERE id = ? AND developer_id = ?');
|
||||
if (!$stmt) {
|
||||
log_error('更新应用信息查询准备失败: ' . $conn->error, __FILE__, __LINE__);
|
||||
$error = '更新应用信息时发生错误,请稍后再试';
|
||||
} else {
|
||||
$stmt->bind_param('ssssssssii', $appName, $appDescription, $version, $changelog, $ageRating, $ageRatingDescription, $platforms_json, $appFilePath, $appId, $developerId);
|
||||
if (!$stmt->execute()) {
|
||||
log_error('更新应用信息查询执行失败: ' . $stmt->error, __FILE__, __LINE__);
|
||||
$error = '更新应用信息时发生错误,请稍后再试';
|
||||
} else {
|
||||
$success = '应用信息更新成功,请等待管理员重新审核';
|
||||
header('Location: dashboard.php?success=' . urlencode($success));
|
||||
exit;
|
||||
$app['name'] = $appName;
|
||||
$app['description'] = $appDescription;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>编辑应用</title>
|
||||
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container mt-4">
|
||||
<h2 class="text-center mb-4">编辑应用</h2>
|
||||
<?php if (!empty($error)): ?>
|
||||
<div class="alert alert-danger"><?php echo $error; ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($success)): ?>
|
||||
<div class="alert alert-success"><?php echo $success; ?></div>
|
||||
<?php endif; ?>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">应用名称</label>
|
||||
<input type="text" class="form-control" id="name" name="name" value="<?php echo htmlspecialchars($app['name']); ?>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="description" class="form-label">应用描述</label>
|
||||
<textarea class="form-control" id="description" name="description" rows="5" required><?php echo htmlspecialchars($app['description']); ?></textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="version" class="form-label">版本号</label>
|
||||
<input type="text" class="form-control" id="version" name="version" value="<?php echo htmlspecialchars($app['version']); ?>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="changelog" class="form-label">更新日志</label>
|
||||
<textarea class="form-control" id="changelog" name="changelog" rows="3" required><?php echo htmlspecialchars($app['changelog']); ?></textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="age_rating" class="form-label">年龄分级</label>
|
||||
<select class="form-select" id="age_rating" name="age_rating" required>
|
||||
<option value="3+" <?php echo $app['age_rating'] === '3+' ? 'selected' : ''; ?>>3+</option>
|
||||
<option value="7+" <?php echo $app['age_rating'] === '7+' ? 'selected' : ''; ?>>7+</option>
|
||||
<option value="12+" <?php echo $app['age_rating'] === '12+' ? 'selected' : ''; ?>>12+</option>
|
||||
<option value="17+" <?php echo $app['age_rating'] === '17+' ? 'selected' : ''; ?>>17+</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="age_rating_description" class="form-label">年龄分级说明</label>
|
||||
<input type="text" class="form-control" id="age_rating_description" name="age_rating_description" value="<?php echo htmlspecialchars($app['age_rating_description']); ?>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">适用平台</label>
|
||||
<?php $platforms = json_decode($app['platforms'], true) ?? []; ?>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="platform_android" name="platforms[]" value="Android" <?php echo in_array('Android', $platforms) ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="platform_android">Android</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="platform_ios" name="platforms[]" value="iOS" <?php echo in_array('iOS', $platforms) ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="platform_ios">iOS</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">应用标签 (至少选择1个)</label>
|
||||
<div class="row">
|
||||
<?php foreach ($tags as $tag): ?>
|
||||
<div class="col-6 col-md-4 col-lg-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="tag_<?php echo $tag['id']; ?>" name="tags[]" value="<?php echo $tag['id']; ?>" <?php echo in_array($tag['id'], $appTags) ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="tag_<?php echo $tag['id']; ?>"><?php echo htmlspecialchars($tag['name']); ?></label>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="app_file" class="form-label">更新应用文件</label>
|
||||
<input class="form-control" type="file" id="app_file" name="app_file">
|
||||
<div class="form-text">当前文件: <?php echo basename($app['file_path']); ?></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">应用图片 (最多5张)</label>
|
||||
<?php
|
||||
// 获取现有图片
|
||||
$existingImages = [];
|
||||
$stmt = $conn->prepare("SELECT id, image_path FROM app_images WHERE app_id = ?");
|
||||
$stmt->bind_param("i", $appId);
|
||||
$stmt->execute();
|
||||
$imgResult = $stmt->get_result();
|
||||
while ($img = $imgResult->fetch_assoc()) {
|
||||
$existingImages[] = $img;
|
||||
}
|
||||
$stmt->close();
|
||||
?>
|
||||
<!-- 现有图片 -->
|
||||
<?php if (!empty($existingImages)): ?>
|
||||
<div class="mb-3">
|
||||
<label>现有图片:</label>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<?php foreach ($existingImages as $img): ?>
|
||||
<div class="position-relative">
|
||||
<img src="<?php echo htmlspecialchars($img['image_path']); ?>" alt="应用图片" style="width: 100px; height: 100px; object-fit: cover; border-radius: 4px;">
|
||||
<button type="button" class="btn btn-danger btn-sm position-absolute top-0 end-0" onclick="removeImage(<?php echo $img['id']; ?>)">×</button>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<!-- 新图片上传 -->
|
||||
<input type="file" name="images[]" multiple accept="image/*" class="form-control">
|
||||
<small>支持jpg、png格式,最多上传5张图片</small>
|
||||
</div>
|
||||
<input type="hidden" name="removed_images" id="removed_images" value="">
|
||||
<button type="submit" class="btn btn-primary w-100">保存更改</button>
|
||||
</form>
|
||||
<div class="text-center mt-3">
|
||||
<a href="dashboard.php" class="btn btn-secondary">返回仪表盘</a>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function removeImage(imageId) {
|
||||
const removedInput = document.getElementById('removed_images');
|
||||
const currentValues = removedInput.value ? removedInput.value.split(',') : [];
|
||||
if (!currentValues.includes(imageId.toString())) {
|
||||
currentValues.push(imageId);
|
||||
removedInput.value = currentValues.join(',');
|
||||
}
|
||||
// 从DOM中移除图片元素
|
||||
event.target.closest('.position-relative').remove();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
122
developer/login.php
Normal file
122
developer/login.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
// 引入配置文件
|
||||
require_once '../config.php';
|
||||
|
||||
// 顶栏样式
|
||||
echo '<style>
|
||||
.navbar.scrolled {
|
||||
background-color: rgba(255, 255, 255, 0.95) !important;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
</style>';
|
||||
|
||||
// 导航栏
|
||||
echo '<nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="../index.php">'. APP_STORE_NAME . '</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="../index.php">首页</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="register.php">开发者注册</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>';
|
||||
|
||||
// 为内容添加顶部内边距
|
||||
echo '<div style="padding-top: 70px;">';
|
||||
|
||||
session_start();
|
||||
$error = '';
|
||||
|
||||
if (isset($_GET['register_success']) && $_GET['register_success'] == 1) {
|
||||
$success = '注册成功,请登录';
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$loginId = trim($_POST['login_id']);
|
||||
$password = $_POST['password'];
|
||||
|
||||
if (empty($loginId) || empty($password)) {
|
||||
$error = '邮箱/用户名和密码不能为空';
|
||||
} else {
|
||||
// 检查数据库连接是否为 MySQLi 对象
|
||||
if (!($conn instanceof mysqli)) {
|
||||
log_error('数据库连接错误: 连接不是MySQLi实例', __FILE__, __LINE__);
|
||||
$error = '数据库连接错误,请检查配置';
|
||||
} else {
|
||||
$stmt = $conn->prepare('SELECT id, username, password FROM developers WHERE email = ? OR username = ?');
|
||||
if (!$stmt) {
|
||||
log_error('登录查询准备失败: ' . $conn->error, __FILE__, __LINE__);
|
||||
$error = '登录时发生错误,请稍后再试';
|
||||
} else {
|
||||
$stmt->bind_param('ss', $loginId, $loginId);
|
||||
if (!$stmt->execute()) {
|
||||
log_error('登录查询执行失败: ' . $stmt->error, __FILE__, __LINE__);
|
||||
$error = '登录时发生错误,请稍后再试';
|
||||
} else {
|
||||
$result = $stmt->get_result();
|
||||
$developer = $result->fetch_assoc();
|
||||
if ($developer && password_verify($password, $developer['password'])) {
|
||||
$_SESSION['developer_id'] = $developer['id'];
|
||||
$_SESSION['developer_username'] = $developer['username'];
|
||||
header('Location: dashboard.php');
|
||||
exit;
|
||||
} else {
|
||||
$error = '邮箱/用户名或密码错误';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>开发者登录</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f4f4f4;
|
||||
padding: 20px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container mt-5 col-md-4">
|
||||
<h2>开发者登录</h2>
|
||||
<?php if (isset($success)): ?>
|
||||
<div class="alert alert-success" role="alert"><?php echo $success; ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($error)): ?>
|
||||
<div class="alert alert-danger" role="alert"><?php echo $error; ?></div>
|
||||
<?php endif; ?>
|
||||
<form method="post">
|
||||
<div class="mb-3">
|
||||
<label for="login_id" class="form-label">邮箱/用户名</label>
|
||||
<input type="text" id="login_id" name="login_id" class="form-control" placeholder="请输入邮箱或用户名" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password" class="form-label">密码</label>
|
||||
<input type="password" id="password" name="password" class="form-control" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100">登录</button>
|
||||
</form>
|
||||
<div class="text-center mt-3">
|
||||
还没有账号?<a href="register.php" class="text-decoration-none">注册</a>
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
10
developer/logout.php
Normal file
10
developer/logout.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
// 销毁会话数据
|
||||
session_unset();
|
||||
session_destroy();
|
||||
|
||||
// 重定向到登录页面
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
187
developer/profile.php
Normal file
187
developer/profile.php
Normal file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
// 引入配置文件
|
||||
require_once '../config.php';
|
||||
|
||||
session_start();
|
||||
|
||||
// 检查开发者是否已登录
|
||||
if (!isset($_SESSION['developer_id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$developerId = $_SESSION['developer_id'];
|
||||
$error = '';
|
||||
$success = '';
|
||||
|
||||
// 检查数据库连接是否为 MySQLi 对象
|
||||
if (!($conn instanceof mysqli)) {
|
||||
log_error('数据库连接错误: 连接不是MySQLi实例', __FILE__, __LINE__);
|
||||
$error = '数据库连接错误,请检查配置';
|
||||
} else {
|
||||
// 获取开发者信息
|
||||
$stmt = $conn->prepare('SELECT username, email, social_links FROM developers WHERE id = ?');
|
||||
if (!$stmt) {
|
||||
log_error('获取开发者信息查询准备失败: ' . $conn->error, __FILE__, __LINE__);
|
||||
$error = '获取开发者信息时发生错误,请稍后再试';
|
||||
} else {
|
||||
$stmt->bind_param('i', $developerId);
|
||||
if (!$stmt->execute()) {
|
||||
log_error('获取开发者信息查询执行失败: ' . $stmt->error, __FILE__, __LINE__);
|
||||
$error = '获取开发者信息时发生错误,请稍后再试';
|
||||
} else {
|
||||
$result = $stmt->get_result();
|
||||
$developer = $result->fetch_assoc();
|
||||
}
|
||||
}
|
||||
|
||||
// 处理表单提交
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$newUsername = trim($_POST['username']);
|
||||
$newEmail = trim($_POST['email']);
|
||||
$newPassword = $_POST['password'];
|
||||
$newSocialLinks = trim($_POST['social_links']);
|
||||
|
||||
// 更新用户名和邮箱
|
||||
$stmt = $conn->prepare('UPDATE developers SET username = ?, email = ?, social_links = ? WHERE id = ?');
|
||||
if (!$stmt) {
|
||||
log_error('更新开发者信息查询准备失败: ' . $conn->error, __FILE__, __LINE__);
|
||||
$error = '更新信息时发生错误,请稍后再试';
|
||||
} else {
|
||||
$stmt->bind_param('sssi', $newUsername, $newEmail, $newSocialLinks, $developerId);
|
||||
if (!$stmt->execute()) {
|
||||
log_error('更新开发者信息查询执行失败: ' . $stmt->error, __FILE__, __LINE__);
|
||||
$error = '更新信息时发生错误,请稍后再试';
|
||||
} else {
|
||||
// 更新密码
|
||||
if (!empty($newPassword)) {
|
||||
$hashedPassword = password_hash($newPassword, PASSWORD_DEFAULT);
|
||||
$stmt = $conn->prepare('UPDATE developers SET password = ? WHERE id = ?');
|
||||
if (!$stmt) {
|
||||
log_error('更新密码查询准备失败: ' . $conn->error, __FILE__, __LINE__);
|
||||
$error = '更新密码时发生错误,请稍后再试';
|
||||
} else {
|
||||
$stmt->bind_param('si', $hashedPassword, $developerId);
|
||||
if (!$stmt->execute()) {
|
||||
log_error('更新密码查询执行失败: ' . $stmt->error, __FILE__, __LINE__);
|
||||
$error = '更新密码时发生错误,请稍后再试';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (empty($error)) {
|
||||
$success = '信息更新成功';
|
||||
$_SESSION['developer_username'] = $newUsername;
|
||||
// 重新获取开发者信息
|
||||
$stmt = $conn->prepare('SELECT username, email, social_links FROM developers WHERE id = ?');
|
||||
if ($stmt) {
|
||||
$stmt->bind_param('i', $developerId);
|
||||
if ($stmt->execute()) {
|
||||
$result = $stmt->get_result();
|
||||
$developer = $result->fetch_assoc();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>开发者信息 - <?php echo APP_STORE_NAME; ?></title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- 自定义CSS -->
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
.profile-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
.success {
|
||||
color: green;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light blur-bg">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="../index.php"><?php echo APP_STORE_NAME; ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="dashboard.php">应用仪表盘</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="upload_app.php">上传应用</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="logout.php">退出登录</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="profile.php">开发者信息</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="profile-container mt-4">
|
||||
<?php if (!empty($error)): ?>
|
||||
<div class="error"><?php echo $error; ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($success)): ?>
|
||||
<div class="success"><?php echo $success; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h1>开发者信息</h1>
|
||||
<form method="post">
|
||||
<div class="form-group">
|
||||
<label for="username">用户名</label>
|
||||
<input type="text" class="form-control" id="username" name="username" value="<?php echo htmlspecialchars($developer['username']); ?>" placeholder="请输入用户名">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">邮箱</label>
|
||||
<input type="email" class="form-control" id="email" name="email" value="<?php echo htmlspecialchars($developer['email']); ?>" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">新密码 (留空则不修改)</label>
|
||||
<input type="password" class="form-control" id="password" name="password">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="social_links">社交媒体链接 (多个链接用逗号分隔)</label>
|
||||
<input type="text" class="form-control" id="social_links" name="social_links" value="<?php echo htmlspecialchars($developer['social_links']); ?>" placeholder="请输入社交媒体链接,多个链接用逗号分隔">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">保存更改</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
229
developer/register.php
Normal file
229
developer/register.php
Normal file
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
// 引入配置文件
|
||||
// 检查配置文件是否存在并加载
|
||||
$configFile = 'c:\web\app2\config.php';
|
||||
if (!file_exists($configFile)) {
|
||||
die('配置文件缺失: ' . $configFile . ',无法继续执行');
|
||||
}
|
||||
require_once $configFile;
|
||||
|
||||
// 引入日志工具
|
||||
require_once 'c:\web\app2\includes\logger.php';
|
||||
|
||||
// 配置文件加载后日志记录和常量检查
|
||||
log_error('配置文件已成功加载: ' . $configFile);
|
||||
// 验证关键常量是否定义
|
||||
log_error('配置加载后常量检查 - SMTP_HOST: ' . (defined('SMTP_HOST') ? SMTP_HOST : '未定义'));
|
||||
log_error('配置加载后常量检查 - SMTP_USERNAME: ' . (defined('SMTP_USERNAME') ? SMTP_USERNAME : '未定义'));
|
||||
log_error('配置加载后常量检查 - SMTP_PASSWORD: ' . (defined('SMTP_PASSWORD') ? '已设置' : '未定义'));
|
||||
log_error('配置加载后常量检查 - SMTP_PORT: ' . (defined('SMTP_PORT') ? SMTP_PORT : '未定义'));
|
||||
log_error('配置文件加载后 - SMTP_USERNAME: ' . (defined('SMTP_USERNAME') ? SMTP_USERNAME : '未定义') . ', SMTP_PORT: ' . (defined('SMTP_PORT') ? SMTP_PORT : '未定义'));
|
||||
|
||||
|
||||
|
||||
|
||||
// 引入PHPMailer命名空间
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\SMTP;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
|
||||
// 引入Composer自动加载器
|
||||
require_once '../vendor/autoload.php';
|
||||
|
||||
// 顶栏样式
|
||||
echo '<style>
|
||||
.navbar.scrolled {
|
||||
background-color: rgba(255, 255, 255, 0.95) !important;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
</style>';
|
||||
|
||||
// 导航栏
|
||||
echo '<nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="../index.php">'. APP_STORE_NAME . '</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="../index.php">首页</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="login.php">开发者登录</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>';
|
||||
|
||||
// 为内容添加顶部内边距
|
||||
echo '<div style="padding-top: 70px;">';
|
||||
|
||||
$error = '';
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$username = trim($_POST['username']);
|
||||
$email = trim($_POST['email']);
|
||||
$password = $_POST['password'];
|
||||
|
||||
if (empty($username) || empty($email) || empty($password)) {
|
||||
$error = '用户名、邮箱和密码不能为空';
|
||||
} elseif (empty($_POST['agree'])) {
|
||||
$error = '必须同意 APP 审核标准才能注册';
|
||||
} elseif (empty($_POST['agree_privacy'])) {
|
||||
$error = '必须同意隐私政策才能注册';
|
||||
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$error = '请输入有效的邮箱地址';
|
||||
} else {
|
||||
// 检查数据库连接是否为 PDO 对象
|
||||
if (!($conn instanceof mysqli)) {
|
||||
log_error('数据库连接错误: 连接不是MySQLi实例', __FILE__, __LINE__);
|
||||
$error = '数据库连接错误,请检查配置';
|
||||
} else {
|
||||
try {
|
||||
$stmt = $conn->prepare('SELECT id FROM developers WHERE username = ? OR email = ?');
|
||||
$stmt->bind_param('ss', $username, $email);
|
||||
$stmt->execute();
|
||||
$stmt->store_result();
|
||||
|
||||
if ($stmt->num_rows > 0) {
|
||||
$error = '用户名或邮箱已被注册';
|
||||
} else {
|
||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||
// 生成验证令牌
|
||||
$verificationToken = bin2hex(random_bytes(32));
|
||||
$insertStmt = $conn->prepare('INSERT INTO developers (username, email, password, verification_token) VALUES (?, ?, ?, ?)');
|
||||
$insertStmt->bind_param('ssss', $username, $email, $hashedPassword, $verificationToken);
|
||||
if (!$insertStmt->execute()) {
|
||||
log_error('插入执行失败: ' . $insertStmt->error, __FILE__, __LINE__);
|
||||
$error = '系统错误,请稍后再试';
|
||||
} else {
|
||||
// 生成验证链接
|
||||
$verificationLink = 'http://' . $_SERVER['HTTP_HOST'] . '/developer/verify_email.php?token=' . urlencode($verificationToken);
|
||||
|
||||
// 加载邮件模板
|
||||
$templatePath = __DIR__ . '/../mail/verification_template.php';
|
||||
if (file_exists($templatePath)) {
|
||||
$templateContent = file_get_contents($templatePath);
|
||||
$templateContent = str_replace('{username}', htmlspecialchars($username), $templateContent);
|
||||
$templateContent = str_replace('{verification_link}', $verificationLink, $templateContent);
|
||||
|
||||
// 调试日志测试
|
||||
$testLogDir = 'c:\\web\\app2\\logs';
|
||||
$testLogFile = $testLogDir . '\\test.log';
|
||||
if (!is_dir($testLogDir)) {
|
||||
mkdir($testLogDir, 0755, true);
|
||||
}
|
||||
file_put_contents($testLogFile, date('[Y-m-d H:i:s] ') . '邮件发送代码开始执行' . PHP_EOL, FILE_APPEND);
|
||||
|
||||
// 添加SMTP配置调试日志
|
||||
log_error('SMTP配置参数 - HOST: ' . (defined('SMTP_HOST') ? SMTP_HOST : '未定义') . ', PORT: ' . (defined('SMTP_PORT') ? SMTP_PORT : '未定义') . ', USERNAME: ' . (defined('SMTP_USERNAME') ? SMTP_USERNAME : '未定义') . ', ENCRYPTION: ' . (defined('SMTP_ENCRYPTION') ? SMTP_ENCRYPTION : '未定义'), __FILE__, __LINE__);
|
||||
log_error('开始执行邮件发送流程', __FILE__, __LINE__);
|
||||
|
||||
// 配置SMTP邮件发送
|
||||
require_once '../vendor/phpmailer/phpmailer/src/PHPMailer.php';
|
||||
require_once '../vendor/phpmailer/phpmailer/src/SMTP.php';
|
||||
|
||||
|
||||
/** @var \PHPMailer\PHPMailer\PHPMailer $mail */
|
||||
$mail = new \PHPMailer\PHPMailer\PHPMailer(true);
|
||||
try {
|
||||
$mail->isSMTP();
|
||||
$mail->SMTPDebug = 4;
|
||||
// 输出当前SMTP配置参数用于调试
|
||||
log_error('SMTP配置参数: HOST=' . SMTP_HOST . ', PORT=' . SMTP_PORT . ', USERNAME=' . SMTP_USERNAME . ', ENCRYPTION=' . SMTP_ENCRYPTION);
|
||||
// 检查openssl扩展是否启用
|
||||
log_error('OpenSSL扩展状态: ' . (extension_loaded('openssl') ? '已启用' : '未启用')); // 启用详细调试
|
||||
$mail->Debugoutput = function($str, $level) {
|
||||
$logDir = 'c:\\web\\app2\\logs';
|
||||
if (!is_dir($logDir)) {
|
||||
mkdir($logDir, 0755, true);
|
||||
}
|
||||
file_put_contents($logDir . '\\smtp_debug.log', date('[Y-m-d H:i:s] ') . $str . PHP_EOL, FILE_APPEND);
|
||||
};
|
||||
$mail->Host = defined('SMTP_HOST') ? SMTP_HOST : 'smtp.example.com';
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = defined('SMTP_USERNAME') ? SMTP_USERNAME : ''; // Ensure SMTP_USERNAME is defined in config.php
|
||||
$mail->Password = defined('SMTP_PASSWORD') ? SMTP_PASSWORD : '';
|
||||
$mail->SMTPSecure = defined('SMTP_ENCRYPTION') ? SMTP_ENCRYPTION : 'tls'; // Ensure SMTP_ENCRYPTION is defined in config.php
|
||||
$mail->AuthType = 'PLAIN'; // 尝试使用PLAIN认证方式
|
||||
$mail->Port = defined('SMTP_PORT') ? SMTP_PORT : 587;
|
||||
$mail->CharSet = 'UTF-8';
|
||||
|
||||
$mail->setFrom(defined('SMTP_FROM_EMAIL') ? SMTP_FROM_EMAIL : 'noreply@example.com', defined('SMTP_FROM_NAME') ? SMTP_FROM_NAME : 'App Store'); // Ensure SMTP_FROM_EMAIL is defined in config.php
|
||||
$mail->addAddress($email, $username);
|
||||
|
||||
$mail->isHTML(true);
|
||||
$mail->Subject = '邮箱验证 - ' . (defined('APP_STORE_NAME') ? APP_STORE_NAME : 'App Store');
|
||||
$mail->Body = $templateContent;
|
||||
|
||||
$mail->send();
|
||||
} catch (\PHPMailer\PHPMailer\Exception $e) {
|
||||
log_error('邮件发送失败: ' . $mail->ErrorInfo, __FILE__, __LINE__);
|
||||
}
|
||||
} else {
|
||||
log_error('验证邮件模板不存在: ' . $templatePath, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
header('Location: login.php?register_success=1&verify_email_sent=1');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error = '注册时发生错误,请稍后再试';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>开发者注册</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f4f4f4;
|
||||
padding: 20px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container mt-5 col-md-4">
|
||||
<h2>开发者注册</h2>
|
||||
<?php if (!empty($error)): ?>
|
||||
<div class="alert alert-danger" role="alert"><?php echo $error; ?></div>
|
||||
<?php endif; ?>
|
||||
<form method="post">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" class="form-control" id="username" name="username" required>
|
||||
<label for="username">用户名</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="email" class="form-control" id="email" name="email" required>
|
||||
<label for="email">邮箱</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
<label for="password">密码</label>
|
||||
</div>
|
||||
<div class="mb-3 form-check">
|
||||
<input type="checkbox" class="form-check-input" id="agree" name="agree" required>
|
||||
<label class="form-check-label" for="agree">我已阅读并同意 <a href="/docs/app_review_standards.php" target="_blank">APP 审核标准</a></label>
|
||||
</div>
|
||||
<div class="form-check mb-3">
|
||||
<input class="form-check-input" type="checkbox" id="privacy_policy" name="agree_privacy">
|
||||
<label class="form-check-label" for="privacy_policy">
|
||||
我已阅读并同意 <a href="../docs/privacy_policy.php" target="_blank">隐私政策</a>
|
||||
</label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100">注册</button>
|
||||
</form>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
543
developer/upload_app.php
Normal file
543
developer/upload_app.php
Normal file
@@ -0,0 +1,543 @@
|
||||
<?php
|
||||
require_once('../includes/logger.php');
|
||||
set_time_limit(0); // 添加此行取消脚本超时限制
|
||||
|
||||
// 引入配置文件
|
||||
require_once '../config.php';
|
||||
|
||||
session_start();
|
||||
|
||||
// 检查开发者是否已登录
|
||||
if (!isset($_SESSION['developer_id']) || !is_numeric($_SESSION['developer_id'])) {
|
||||
log_error('开发者会话ID不存在或无效', __FILE__, __LINE__);
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$developerId = (int)$_SESSION['developer_id'];
|
||||
log_info("上传应用的开发者ID: $developerId", __FILE__, __LINE__);
|
||||
log_info("上传应用的开发者ID: $developerId", __FILE__, __LINE__);
|
||||
$error = '';
|
||||
$success = '';
|
||||
|
||||
// 检查开发者邮箱是否已验证
|
||||
$stmt = $conn->prepare('SELECT is_verified FROM developers WHERE id = ?');
|
||||
if (!$stmt) {
|
||||
log_error('准备验证状态查询失败: ' . $conn->error, __FILE__, __LINE__);
|
||||
$error = '系统错误,请稍后再试';
|
||||
} else {
|
||||
$stmt->bind_param('i', $developerId);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$developer = $result->fetch_assoc();
|
||||
$stmt->close();
|
||||
|
||||
log_info("开发者验证状态: " . ($developer ? ($developer['is_verified'] ? "已验证" : "未验证") : "开发者不存在"), __FILE__, __LINE__);
|
||||
if (!$developer) {
|
||||
$error = '开发者账号不存在,请重新登录。';
|
||||
} elseif (!$developer['is_verified']) {
|
||||
$error = '您的邮箱尚未验证,请先验证邮箱后再上传应用。';
|
||||
}
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// 创建上传目录(如果不存在)
|
||||
$uploadDirs = ['../uploads/apps', '../uploads/images'];
|
||||
foreach ($uploadDirs as $dir) {
|
||||
if (!is_dir($dir)) {
|
||||
mkdir($dir, 0755, true);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取表单数据
|
||||
$appName = trim($_POST['name']);
|
||||
$appDescription = trim($_POST['description']);
|
||||
$tags = $_POST['tags'] ?? [];
|
||||
$ageRating = $_POST['age_rating'] ?? '';
|
||||
$ageRatingDescription = $_POST['age_rating_description'] ?? '';
|
||||
$platforms = isset($_POST['platforms']) ? $_POST['platforms'] : [];
|
||||
$version = trim($_POST['version']);
|
||||
$changelog = trim($_POST['changelog']);
|
||||
|
||||
// 验证表单数据
|
||||
if (empty($appName) || empty($appDescription)) {
|
||||
$error = '应用名称和描述不能为空';
|
||||
} elseif (empty($changelog)) {
|
||||
$error = '更新日志不能为空';
|
||||
} elseif (empty($platforms)) {
|
||||
$error = '请至少选择一个适用平台';
|
||||
} elseif (in_array($ageRating, ['12+', '17+']) && empty($ageRatingDescription)) {
|
||||
$error = '年龄分级为12+或以上时,必须提供年龄分级说明';
|
||||
} else {
|
||||
// 检查数据库连接是否为 MySQLi 对象
|
||||
if (!($conn instanceof mysqli)) {
|
||||
log_error('数据库连接错误: 连接不是MySQLi实例', __FILE__, __LINE__);
|
||||
$error = '数据库连接错误,请检查配置';
|
||||
} else {
|
||||
// 处理应用文件上传
|
||||
// 获取选中的平台
|
||||
$selectedPlatforms = $_POST['platforms'] ?? [];
|
||||
|
||||
// 处理应用文件上传
|
||||
$appFile = $_FILES['app_file'] ?? null;
|
||||
$appFilePath = '';
|
||||
if ($appFile && $appFile['error'] === UPLOAD_ERR_OK) {
|
||||
// 验证文件大小 (100MB)
|
||||
if ($appFile['size'] > 500 * 1024 * 1024) {
|
||||
log_error('应用文件过大: ' . number_format($appFile['size'] / 1024 / 1024, 2) . 'MB', __FILE__, __LINE__);
|
||||
$error = '应用文件大小不能超过500MB';
|
||||
}
|
||||
$appExtension = pathinfo($appFile['name'], PATHINFO_EXTENSION);
|
||||
$appFileName = uniqid() . '.' . $appExtension;
|
||||
$appRelativePath = 'uploads/apps/' . $appFileName;
|
||||
$appFilePath = __DIR__ . '/../' . $appRelativePath;
|
||||
if (!move_uploaded_file($appFile['tmp_name'], $appFilePath)) {
|
||||
log_error('应用文件移动失败', __FILE__, __LINE__);
|
||||
$error = '应用文件上传失败';
|
||||
}
|
||||
} else {
|
||||
// 验证标签ID是否存在
|
||||
if (!empty($tags)) {
|
||||
$tagIds = implode(',', array_map('intval', $tags));
|
||||
$tagCheckStmt = $conn->prepare("SELECT id FROM tags WHERE id IN ($tagIds)");
|
||||
if (!$tagCheckStmt) {
|
||||
log_error('标签验证查询准备失败: ' . $conn->error, __FILE__, __LINE__);
|
||||
$error = '系统错误,请稍后再试';
|
||||
} else {
|
||||
$tagCheckStmt->execute();
|
||||
$tagResult = $tagCheckStmt->get_result();
|
||||
$validTagIds = [];
|
||||
while ($tag = $tagResult->fetch_assoc()) {
|
||||
$validTagIds[] = $tag['id'];
|
||||
}
|
||||
$tagCheckStmt->close();
|
||||
|
||||
$invalidTags = array_diff($tags, $validTagIds);
|
||||
if (!empty($invalidTags)) {
|
||||
log_error('无效的标签ID: ' . implode(',', $invalidTags), __FILE__, __LINE__);
|
||||
$error = '选择了无效的标签,请刷新页面重试';
|
||||
}
|
||||
}
|
||||
}
|
||||
$error = '应用文件上传错误: ' . ($appFile ? $appFile['error'] : '未找到文件');
|
||||
}
|
||||
|
||||
// 处理图片上传
|
||||
$imagePaths = [];
|
||||
$images = $_FILES['images'] ?? null;
|
||||
if ($images && is_array($images['tmp_name'])) {
|
||||
foreach ($images['tmp_name'] as $key => $tmpName) {
|
||||
if ($images['error'][$key] === UPLOAD_ERR_OK) {
|
||||
// 验证图片大小 (10MB)
|
||||
if ($images['size'][$key] > 10 * 1024 * 1024) {
|
||||
log_error('图片过大: ' . $images['name'][$key] . ' (' . number_format($images['size'][$key] / 1024 / 1024, 2) . 'MB)', __FILE__, __LINE__);
|
||||
$error = '图片 ' . $images['name'][$key] . ' 大小不能超过10MB';
|
||||
}
|
||||
|
||||
$imageRelativePath = 'uploads/images/' . uniqid() . '.' . pathinfo($images['name'][$key], PATHINFO_EXTENSION);
|
||||
$imagePath = __DIR__ . '/../' . $imageRelativePath;
|
||||
$target_dir = dirname($imagePath);
|
||||
if (!is_dir($target_dir)) {
|
||||
mkdir($target_dir, 0755, true);
|
||||
}
|
||||
if (move_uploaded_file($tmpName, $imagePath)) {
|
||||
$imagePaths[] = $imageRelativePath;
|
||||
} else {
|
||||
log_error('图片文件移动失败: ' . $images['name'][$key], __FILE__, __LINE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($error)) {
|
||||
// 开始数据库事务
|
||||
$conn->begin_transaction();
|
||||
try {
|
||||
// 确保必要变量存在,防止空值导致 SQL 错误
|
||||
if (!isset($appName) || !isset($appDescription) || !isset($developerId) || !isset($version) || !isset($changelog) || !isset($ageRating) || !isset($ageRatingDescription)) {
|
||||
throw new Exception('缺少必要的上传参数');
|
||||
}
|
||||
|
||||
// 获取开发者邮箱
|
||||
$userStmt = $conn->prepare('SELECT email FROM developers WHERE id = ?');
|
||||
$userStmt->bind_param('i', $developerId);
|
||||
$userStmt->execute();
|
||||
$userResult = $userStmt->get_result();
|
||||
$user = $userResult->fetch_assoc();
|
||||
$developerEmail = $user['email'] ?? '';
|
||||
$userStmt->close();
|
||||
|
||||
if (empty($developerEmail)) {
|
||||
throw new Exception('无法获取开发者邮箱信息');
|
||||
}
|
||||
|
||||
// 插入应用基本信息
|
||||
$stmt = $conn->prepare('INSERT INTO apps (name, description, platforms, status, age_rating, age_rating_description, version, changelog, file_path, developer_id, developer_email, created_at) VALUES (?, ?, ?, \'pending\', ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)');
|
||||
if (!$stmt) {
|
||||
throw new Exception('应用基本信息查询准备失败: ' . $conn->error);
|
||||
}
|
||||
// 确保平台数据正确编码
|
||||
$platforms = $_POST['platforms'] ?? [];
|
||||
$platforms_json = json_encode($platforms);
|
||||
// 此处需确认预处理语句占位符数量,确保与 bind_param 参数数量一致,示例仅示意,实际需根据表结构调整
|
||||
// 修正参数绑定,添加file_path参数以匹配SQL占位符数量
|
||||
// 修正参数类型字符串长度,确保与10个参数匹配
|
||||
// 修正类型字符串长度,10个参数对应10个类型字符
|
||||
// 最终修正:10个参数对应10个类型字符
|
||||
// 根据参数实际类型修正类型字符串(整数用i,字符串用s)
|
||||
// 移除多余的$status参数,匹配SQL中9个占位符
|
||||
// 修正age_rating_description类型为字符串,并确保9个参数与占位符匹配
|
||||
// 修复变量名错误:使用已验证的$appFilePath替换未定义的$file_path
|
||||
$stmt->bind_param('ssssssssis', $appName, $appDescription, $platforms_json, $ageRating, $ageRatingDescription, $version, $changelog, $appRelativePath, $developerId, $developerEmail);
|
||||
if (!$stmt->execute()) {
|
||||
throw new Exception('应用基本信息查询执行失败: ' . $stmt->error);
|
||||
}
|
||||
$appId = $stmt->insert_id;
|
||||
log_info("应用已插入数据库: ID=$appId, 状态=pending", __FILE__, __LINE__);
|
||||
$stmt->close();
|
||||
|
||||
log_info("开始处理应用关联数据: ID=$appId", __FILE__, __LINE__);
|
||||
// 插入应用标签关联
|
||||
foreach ($tags as $tagId) {
|
||||
$tagStmt = $conn->prepare('INSERT INTO app_tags (app_id, tag_id) VALUES (?, ?)');
|
||||
if (!$tagStmt) {
|
||||
throw new Exception('标签关联查询准备失败: ' . $conn->error);
|
||||
}
|
||||
$tagStmt->bind_param('ii', $appId, $tagId);
|
||||
if (!$tagStmt->execute()) {
|
||||
throw new Exception('标签关联查询执行失败: ' . $tagStmt->error);
|
||||
}
|
||||
$tagStmt->close();
|
||||
}
|
||||
|
||||
// 插入应用图片
|
||||
foreach ($imagePaths as $imageRelativePath) {
|
||||
$imageStmt = $conn->prepare('INSERT INTO app_images (app_id, image_path) VALUES (?, ?)');
|
||||
if (!$imageStmt) {
|
||||
throw new Exception('图片关联查询准备失败: ' . $conn->error);
|
||||
}
|
||||
$imageStmt->bind_param('is', $appId, $imageRelativePath);
|
||||
if (!$imageStmt->execute()) {
|
||||
throw new Exception('图片关联查询执行失败: ' . $imageStmt->error);
|
||||
}
|
||||
$imageStmt->close();
|
||||
}
|
||||
|
||||
// 插入应用版本信息
|
||||
$versionStmt = $conn->prepare('INSERT INTO app_versions (app_id, version, changelog, file_path, created_at) VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP)');
|
||||
if (!$versionStmt) {
|
||||
throw new Exception('版本信息查询准备失败: ' . $conn->error);
|
||||
}
|
||||
$versionStmt->bind_param('isss', $appId, $version, $changelog, $appRelativePath);
|
||||
if (!$versionStmt->execute()) {
|
||||
throw new Exception('版本信息查询执行失败: ' . $versionStmt->error);
|
||||
}
|
||||
$versionStmt->close();
|
||||
|
||||
log_info("所有关联数据处理完成,准备提交事务: ID=$appId", __FILE__, __LINE__);
|
||||
// 提交事务
|
||||
$conn->commit();
|
||||
log_info("应用上传成功: ID=$appId, 状态=pending", __FILE__, __LINE__);
|
||||
$success = '应用上传成功,请等待管理员审核';
|
||||
} catch (Exception $e) {
|
||||
// 回滚事务
|
||||
$conn->rollback();
|
||||
log_error('应用上传事务失败(ID=$appId): ' . $e->getMessage(), __FILE__, __LINE__);
|
||||
$error = '上传应用时发生错误,请稍后再试';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>上传应用 - <?php echo APP_STORE_NAME; ?></title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- 自定义CSS -->
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<!-- Fluent Design 模糊效果 -->
|
||||
<style>
|
||||
.blur-bg {
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.btn-primary {
|
||||
background-color: #007BFF;
|
||||
border-color: #007BFF;
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background-color: #0056b3;
|
||||
border-color: #0056b3;
|
||||
}
|
||||
.back-link {
|
||||
text-align: center;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
#ageRatingDescriptionGroup {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<!-- Bootstrap JS with Popper -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</head>
|
||||
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light blur-bg">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="../index.php"><?php echo APP_STORE_NAME; ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="dashboard.php">应用仪表盘</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="upload_app.php">上传应用</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="logout.php">退出登录</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<style>
|
||||
.form-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.btn-primary {
|
||||
background-color: #007BFF;
|
||||
border-color: #007BFF;
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background-color: #0056b3;
|
||||
border-color: #0056b3;
|
||||
}
|
||||
.back-link {
|
||||
text-align: center;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
#ageRatingDescriptionGroup {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
// 年龄分级说明显示控制
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const ageRating = document.getElementById('age_rating');
|
||||
const ageDescGroup = document.getElementById('ageRatingDescriptionGroup');
|
||||
const ageDescInput = document.getElementById('age_rating_description');
|
||||
|
||||
function toggleAgeDescription() {
|
||||
if (['12+', '17+'].includes(ageRating.value)) {
|
||||
ageDescGroup.style.display = 'block';
|
||||
ageDescInput.required = true;
|
||||
} else {
|
||||
ageDescGroup.style.display = 'none';
|
||||
ageDescInput.required = false;
|
||||
}
|
||||
}
|
||||
|
||||
ageRating.addEventListener('change', toggleAgeDescription);
|
||||
toggleAgeDescription(); // 初始状态检查
|
||||
|
||||
// 文件类型验证
|
||||
const appFileInput = document.getElementById('app_file');
|
||||
const imageInput = document.getElementById('images');
|
||||
const allowedAppTypes = { 'android': ['apk'], 'ios': ['ipa'] };
|
||||
const allowedImageTypes = ['jpg', 'jpeg', 'png', 'gif'];
|
||||
|
||||
appFileInput.addEventListener('change', function(e) {
|
||||
if (this.files.length > 0) {
|
||||
const file = this.files[0];
|
||||
const ext = file.name.split('.').pop().toLowerCase();
|
||||
if (file.size > 500 * 1024 * 1024) { // 100MB限制
|
||||
Swal.fire({
|
||||
title: '提示',
|
||||
text: '文件大小不能超过500MB',
|
||||
icon: 'warning',
|
||||
confirmButtonText: '确定'
|
||||
});
|
||||
this.value = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
imageInput.addEventListener('change', function(e) {
|
||||
if (this.files.length > 0) {
|
||||
for (let i = 0; i < this.files.length; i++) {
|
||||
const file = this.files[i];
|
||||
if (file.size > 10 * 1024 * 1024) { // 10MB限制
|
||||
Swal.fire({
|
||||
title: '提示',
|
||||
text: `图片 ${file.name} 大小不能超过10MB`,
|
||||
icon: 'warning',
|
||||
confirmButtonText: '确定'
|
||||
});
|
||||
this.value = '';
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 平台子选项显示控制
|
||||
document.getElementById('windows').addEventListener('change', function() {
|
||||
const suboptions = document.getElementById('windows_suboptions');
|
||||
suboptions.style.display = this.checked ? 'block' : 'none';
|
||||
if (!this.checked) {
|
||||
document.querySelectorAll('input[name="windows_version"]').forEach(radio => radio.checked = false);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('linux').addEventListener('change', function() {
|
||||
const suboptions = document.getElementById('linux_suboptions');
|
||||
suboptions.style.display = this.checked ? 'block' : 'none';
|
||||
if (!this.checked) {
|
||||
document.querySelectorAll('input[name="linux_distribution"]').forEach(radio => radio.checked = false);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container mt-5 mb-5 col-md-8 col-lg-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h2 class="h4 mb-0">上传应用</h2>
|
||||
</div>
|
||||
<div class="card-body p-4">
|
||||
<?php if (!empty($error)): ?>
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<?php echo $error; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($success)): ?>
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
<?php echo $success; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div class="form-group mb-3">
|
||||
<label for="name" class="form-label">应用名称</label>
|
||||
<input type="text" id="name" name="name" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="tags" class="form-label">标签</label>
|
||||
<select id="tags" name="tags[]" multiple class="form-select" size="3">
|
||||
<?php
|
||||
$tagResult = $conn->query("SELECT id, name FROM tags");
|
||||
while ($tag = $tagResult->fetch_assoc()):
|
||||
?>
|
||||
<option value="<?php echo $tag['id']; ?>"><?php echo htmlspecialchars($tag['name']); ?></option>
|
||||
<?php endwhile; ?>
|
||||
</select>
|
||||
<small>按住Ctrl键可选择多个标签</small>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="description" class="form-label">应用描述</label>
|
||||
<textarea id="description" name="description" rows="5" class="form-control" required></textarea>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="age_rating" class="form-label">年龄分级</label>
|
||||
<select class="form-select" id="age_rating" name="age_rating" required>
|
||||
<option value="3+">3+</option>
|
||||
<option value="7+">7+</option>
|
||||
<option value="12+">12+</option>
|
||||
<option value="17+">17+</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group mb-3" id="ageRatingDescriptionGroup">
|
||||
<label for="age_rating_description" class="form-label">年龄分级说明</label>
|
||||
<textarea class="form-control" id="age_rating_description" name="age_rating_description" rows="3" placeholder="请说明为何需要此年龄分级"></textarea>
|
||||
<small>当年龄分级为12+或以上时,此项为必填</small>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label">适用平台</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="android" id="android" name="platforms[]">
|
||||
<label class="form-check-label" for="android">Android</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="ios" id="ios" name="platforms[]">
|
||||
<label class="form-check-label" for="ios">iOS</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="windows" id="windows" name="platforms[]">
|
||||
<label class="form-check-label" for="windows">Windows</label>
|
||||
</div>
|
||||
<div id="windows_suboptions" class="ms-4 mt-2" style="display: none;">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="windows_version" id="windows_xp" value="windows_xp">
|
||||
<label class="form-check-label" for="windows_xp">XP以前</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="windows_version" id="windows_win7" value="windows_win7">
|
||||
<label class="form-check-label" for="windows_win7">Win7以后</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="macos" id="macos" name="platforms[]">
|
||||
<label class="form-check-label" for="macos">macOS</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="linux" id="linux" name="platforms[]">
|
||||
<label class="form-check-label" for="linux">Linux</label>
|
||||
</div>
|
||||
<div id="linux_suboptions" class="ms-4 mt-2" style="display: none;">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="linux_distribution" id="linux_ubuntu" value="linux_ubuntu">
|
||||
<label class="form-check-label" for="linux_ubuntu">Ubuntu</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="linux_distribution" id="linux_arch" value="linux_arch">
|
||||
<label class="form-check-label" for="linux_arch">Arch Linux</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="linux_distribution" id="linux_centos" value="linux_centos">
|
||||
<label class="form-check-label" for="linux_centos">CentOS</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="app_file" class="form-label">应用文件</label>
|
||||
<input type="file" id="app_file" name="app_file" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="version" class="form-label">版本号</label>
|
||||
<input type="text" id="version" name="version" class="form-control" required placeholder="例如: 1.0.0">
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="changelog" class="form-label">更新日志</label>
|
||||
<textarea id="changelog" name="changelog" rows="3" class="form-control" required></textarea>
|
||||
</div>
|
||||
<div class="form-group mb-4">
|
||||
<label for="images" class="form-label">预览图片</label>
|
||||
<input type="file" id="images" name="images[]" multiple accept="image/*" class="form-control">
|
||||
<small>可选择多张图片</small>
|
||||
</div>
|
||||
<input type="submit" value="上传" class="btn btn-primary w-100 py-2">
|
||||
</form>
|
||||
<div class="back-link mt-4">
|
||||
<a href="dashboard.php" class="btn btn-outline-secondary w-100">返回仪表盘</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
90
developer/verify_email.php
Normal file
90
developer/verify_email.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
// 引入配置文件
|
||||
require_once '../config.php';
|
||||
|
||||
session_start();
|
||||
|
||||
$error = '';
|
||||
$success = '';
|
||||
|
||||
// 检查是否提供了验证令牌
|
||||
if (!isset($_GET['token']) || empty($_GET['token'])) {
|
||||
$error = '无效的验证链接';
|
||||
} else {
|
||||
$token = trim($_GET['token']);
|
||||
|
||||
// 验证数据库连接
|
||||
if (!($conn instanceof mysqli)) {
|
||||
log_error('数据库连接错误: 连接不是MySQLi实例', __FILE__, __LINE__);
|
||||
$error = '数据库连接错误,请稍后再试';
|
||||
} else {
|
||||
try {
|
||||
// 查询具有该令牌的未验证开发者
|
||||
$stmt = $conn->prepare('SELECT id FROM developers WHERE verification_token = ? AND is_verified = FALSE');
|
||||
$stmt->bind_param('s', $token);
|
||||
$stmt->execute();
|
||||
$stmt->store_result();
|
||||
|
||||
if ($stmt->num_rows === 1) {
|
||||
// 更新验证状态
|
||||
$updateStmt = $conn->prepare('UPDATE developers SET is_verified = TRUE, verified_at = NOW(), verification_token = NULL WHERE verification_token = ?');
|
||||
$updateStmt->bind_param('s', $token);
|
||||
$updateStmt->execute();
|
||||
$updateStmt->close();
|
||||
|
||||
$success = '邮箱验证成功!现在您可以登录并创建应用了。';
|
||||
} else {
|
||||
$error = '验证链接无效或已过期';
|
||||
}
|
||||
$stmt->close();
|
||||
} catch (Exception $e) {
|
||||
log_error('邮箱验证失败: ' . $e->getMessage(), __FILE__, __LINE__);
|
||||
$error = '验证过程中发生错误,请稍后再试';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>邮箱验证 - <?= APP_STORE_NAME ?></title>
|
||||
<link href="/css/bootstrap.min.css" rel="stylesheet">
|
||||
<style>
|
||||
body { background-color: #f4f4f4; padding: 70px 0; }
|
||||
.container { max-width: 500px; background: white; padding: 30px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
|
||||
.alert { margin-bottom: 20px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="../index.php"><?= APP_STORE_NAME ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item"><a class="nav-link" href="../index.php">首页</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="login.php">开发者登录</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
<h2 class="mb-4">邮箱验证</h2>
|
||||
<?php if (!empty($success)): ?>
|
||||
<div class="alert alert-success" role="alert"><?= $success ?></div>
|
||||
<a href="login.php" class="btn btn-primary">前往登录</a>
|
||||
<?php else: ?>
|
||||
<div class="alert alert-danger" role="alert"><?= $error ?></div>
|
||||
<a href="register.php" class="btn btn-secondary">重新注册</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<script src="/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
232
developer/version_control.php
Normal file
232
developer/version_control.php
Normal file
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
require_once '../config.php';
|
||||
require_once '../includes/logger.php';
|
||||
|
||||
session_start();
|
||||
// 检查开发者登录状态
|
||||
if (!isset($_SESSION['developer_id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
$developerId = $_SESSION['developer_id'];
|
||||
|
||||
// 验证App ID
|
||||
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
||||
header('Location: dashboard.php?error=无效的App ID');
|
||||
exit;
|
||||
}
|
||||
$appId = $_GET['id'];
|
||||
|
||||
// 获取App信息并验证所有权
|
||||
$app = null;
|
||||
$getAppSql = "SELECT * FROM apps WHERE id = ? AND developer_id = ?";
|
||||
$stmt = $conn->prepare($getAppSql);
|
||||
if (!$stmt) {
|
||||
log_error("应用所有权验证查询准备失败: " . $conn->error, __FILE__, __LINE__);
|
||||
header('Location: dashboard.php?error=验证应用所有权失败');
|
||||
exit;
|
||||
}
|
||||
$stmt->bind_param("ii", $appId, $developerId);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
if ($result->num_rows === 0) {
|
||||
header('Location: dashboard.php?error=App不存在或无权访问');
|
||||
exit;
|
||||
}
|
||||
$app = $result->fetch_assoc();
|
||||
$platforms = json_decode($app['platforms'], true);
|
||||
|
||||
$success = '';
|
||||
$error = '';
|
||||
// 处理版本上传请求
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['upload_version'])) {
|
||||
// 验证版本信息
|
||||
if (empty($_POST['version']) || empty($_FILES['app_file']['name'])) {
|
||||
$error = '版本号和安装包不能为空';
|
||||
} else {
|
||||
// 处理App文件上传
|
||||
$uploadDir = '../files/';
|
||||
if (!is_dir($uploadDir)) {
|
||||
mkdir($uploadDir, 0755, true);
|
||||
}
|
||||
$fileName = basename($_FILES['app_file']['name']);
|
||||
$targetPath = $uploadDir . $fileName;
|
||||
|
||||
if (move_uploaded_file($_FILES['app_file']['tmp_name'], $targetPath)) {
|
||||
$version = $_POST['version'];
|
||||
$changelog = $_POST['changelog'] ?? '';
|
||||
|
||||
// 插入新版本记录
|
||||
$insertVersionSql = "INSERT INTO app_versions (app_id, version, changelog, file_path) VALUES (?, ?, ?, ?)";
|
||||
$verStmt = $conn->prepare($insertVersionSql);
|
||||
if (!$verStmt) {
|
||||
log_error("版本插入准备失败: " . $conn->error, __FILE__, __LINE__);
|
||||
$error = '版本保存失败,请稍后再试';
|
||||
unlink($targetPath); // 清理已上传文件
|
||||
} else {
|
||||
$verStmt->bind_param("isss", $appId, $version, $changelog, $targetPath);
|
||||
|
||||
if ($verStmt->execute()) {
|
||||
// 更新应用表中的最新版本
|
||||
// 更新应用表中的最新版本
|
||||
$updateAppSql = "UPDATE apps SET version = ? WHERE id = ?";
|
||||
$updStmt = $conn->prepare($updateAppSql);
|
||||
if (!$updStmt) {
|
||||
log_error("应用版本更新准备失败: " . $conn->error, __FILE__, __LINE__);
|
||||
$error = '更新应用版本失败,请稍后再试';
|
||||
unlink($targetPath); // 数据库更新失败,删除文件
|
||||
} else {
|
||||
$updStmt->bind_param("si", $version, $appId);
|
||||
$updStmt->execute();
|
||||
$success = '版本上传成功';
|
||||
}
|
||||
} else {
|
||||
$error = '版本保存失败: '. $conn->error;
|
||||
unlink($targetPath); // 数据库更新失败,删除文件
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$error = '文件上传失败';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取现有版本列表
|
||||
$versions = [];
|
||||
$getVersionsSql = "SELECT * FROM app_versions WHERE app_id = ? ORDER BY id DESC";
|
||||
$verStmt = $conn->prepare($getVersionsSql);
|
||||
if (!$verStmt) {
|
||||
log_error("版本查询准备失败: " . $conn->error, __FILE__, __LINE__);
|
||||
$error = '获取版本列表失败,请稍后再试';
|
||||
} else {
|
||||
$verStmt->bind_param("i", $appId);
|
||||
$verStmt->execute();
|
||||
$versionsResult = $verStmt->get_result();
|
||||
while ($ver = $versionsResult->fetch_assoc()) {
|
||||
$versions[] = $ver;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>版本控制 - <?php echo htmlspecialchars($app['name']); ?></title>
|
||||
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<style>
|
||||
.blur-bg {
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-light blur-bg">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="../index.php"><?php echo APP_STORE_NAME; ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="dashboard.php">我的应用</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="upload_app.php">上传新应用</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="version_control.php?id=<?php echo $appId; ?>">版本控制</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="profile.php">个人资料</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="logout.php">退出登录</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<?php if (!empty($success)): ?>
|
||||
<script>Swal.fire('成功', '<?php echo addslashes($success); ?>', 'success');</script>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($error)): ?>
|
||||
<script>Swal.fire('错误', '<?php echo addslashes($error); ?>', 'error');</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card blur-bg mb-4">
|
||||
<div class="card-header">
|
||||
<h2>应用版本控制: <?php echo htmlspecialchars($app['name']); ?></h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h4>上传新版本</h4>
|
||||
<form method="post" enctype="multipart/form-data" class="mb-4">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<div class="form-floating">
|
||||
<input type="text" class="form-control" id="version" name="version" placeholder="版本号" required>
|
||||
<label for="version">版本号 (如: 1.0.0)</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="app_file" class="form-label">安装包文件</label>
|
||||
<input class="form-control" type="file" id="app_file" name="app_file" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<textarea class="form-control" id="changelog" name="changelog" rows="3" placeholder="更新日志"></textarea>
|
||||
<label for="changelog">更新日志</label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary" name="upload_version">上传新版本</button>
|
||||
<a href="dashboard.php" class="btn btn-secondary ms-2">返回</a>
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<h4>版本历史</h4>
|
||||
<?php if (empty($versions)): ?>
|
||||
<div class="alert alert-info">暂无版本记录</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>版本号</th>
|
||||
<th>上传时间</th>
|
||||
<th>更新日志</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($versions as $ver): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($ver['version']); ?></td>
|
||||
<td><?php echo htmlspecialchars($ver['upload_time']); ?></td>
|
||||
<td><?php echo nl2br(htmlspecialchars($ver['changelog'] ?: '无')); ?></td>
|
||||
<td>
|
||||
<a href="../download.php?id=<?php echo $ver['id']; ?>&type=version" class="btn btn-sm btn-outline-primary">下载</a>
|
||||
<?php if ($ver['is_current'] == 1): ?>
|
||||
<span class="badge bg-success">当前版本</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="../js/bootstrap.bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
205
developer_apps.php
Normal file
205
developer_apps.php
Normal file
@@ -0,0 +1,205 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'config.php';
|
||||
|
||||
// 验证开发者ID参数
|
||||
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$developerId = intval($_GET['id']);
|
||||
|
||||
// 获取开发者信息
|
||||
$sqlDeveloper = "SELECT username, social_links FROM developers WHERE id = $developerId";
|
||||
$resultDeveloper = $conn->query($sqlDeveloper);
|
||||
$developer = $resultDeveloper->fetch_assoc();
|
||||
|
||||
// 确定页面标题和开发者名称
|
||||
if ($developer) {
|
||||
$developerName = htmlspecialchars($developer['username']);
|
||||
$pageTitle = $developerName . ' 的应用 - ' . APP_STORE_NAME;
|
||||
} else {
|
||||
// 如果开发者ID为0或不存在,视为管理员
|
||||
$developerName = '管理员';
|
||||
$pageTitle = '管理员的应用 - ' . APP_STORE_NAME;
|
||||
}
|
||||
|
||||
// 获取该开发者的所有应用
|
||||
$sqlApps = "SELECT a.*, (SELECT AVG(rating) FROM reviews WHERE app_id = a.id) as avg_rating
|
||||
FROM apps a
|
||||
WHERE a.developer_id = $developerId";
|
||||
$resultApps = $conn->query($sqlApps);
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php echo $pageTitle; ?></title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Font Awesome -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<!-- 自定义CSS -->
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<!-- Fluent Design 模糊效果 -->
|
||||
<style>
|
||||
.blur-bg {
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.page-transition {
|
||||
animation: fadeIn 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="page-transition">
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light blur-bg">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="index.php"><?php echo APP_STORE_NAME; ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">首页</a>
|
||||
</li>
|
||||
<?php if (isset($_SESSION['admin'])): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/admin/">管理</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<form id="searchForm" class="mb-4">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-10">
|
||||
<div class="form-floating">
|
||||
<input type="text" class="form-control" id="searchApp" placeholder="搜索应用" value="">
|
||||
<label for="searchApp">搜索应用</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button class="btn btn-primary w-100" style="width: calc(3.5rem + calc(var(--bs-border-width) * 2)); height: calc(3.5rem + calc(var(--bs-border-width) * 2))" type="submit" id="searchButton">搜索</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<h1><?php echo $developerName; ?> 的应用</h1>
|
||||
<hr>
|
||||
<?php if (isset($developer['social_links']) && !empty($developer['social_links'])): ?>
|
||||
<div class="mb-4">
|
||||
<h5>开发者链接</h5>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<?php
|
||||
$socialLinks = explode(',', $developer['social_links']);
|
||||
foreach ($socialLinks as $link):
|
||||
$link = trim($link);
|
||||
if (!empty($link)):
|
||||
?>
|
||||
<a href="<?php echo htmlspecialchars($link); ?>" target="_blank" class="btn btn-outline-primary btn-sm">
|
||||
<i class="fas fa-link me-1"></i>
|
||||
<?php echo parse_url($link, PHP_URL_HOST) ?: $link; ?>
|
||||
</a>
|
||||
<?php
|
||||
endif;
|
||||
endforeach;
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($resultApps && $resultApps->num_rows > 0): ?>
|
||||
<div class="row">
|
||||
<?php while ($app = $resultApps->fetch_assoc()): ?>
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card h-100 blur-bg">
|
||||
<?php
|
||||
// 获取应用的第一张图片
|
||||
$sqlImage = "SELECT image_path FROM app_images WHERE app_id = ". $app['id'] ." LIMIT 1";
|
||||
$resultImage = $conn->query($sqlImage);
|
||||
$image = $resultImage ? $resultImage->fetch_assoc() : null;
|
||||
$imagePath = $image ? $image['image_path'] : 'default-app.png';
|
||||
?>
|
||||
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><?php echo htmlspecialchars($app['name']); ?></h5>
|
||||
<p class="card-text"><?php echo htmlspecialchars(substr($app['description'], 0, 100)); ?>...</p>
|
||||
<p class="card-text">
|
||||
<small class="text-muted">
|
||||
评分: <?php echo round($app['avg_rating'] ?? 0, 1); ?>/5
|
||||
</small>
|
||||
</p>
|
||||
<a href="app.php?id=<?php echo $app['id']; ?>" class="btn btn-primary">查看详情</a>
|
||||
<button class="btn btn-outline-secondary mt-2" onclick="toggleFavorite(<?php echo $app['id']; ?>, '<?php echo addslashes(htmlspecialchars($app['name'])); ?>')">收藏</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="alert alert-info" role="alert">
|
||||
<?php echo $developerName; ?> 暂无上传应用
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.body.classList.add('page-transition');
|
||||
|
||||
// 搜索功能实现
|
||||
function performSearch(event) {
|
||||
event.preventDefault();
|
||||
const searchTerm = document.getElementById('searchApp').value.toLowerCase();
|
||||
const appCards = document.querySelectorAll('.col-md-4.mb-4');
|
||||
let hasResults = false;
|
||||
|
||||
appCards.forEach(card => {
|
||||
const title = card.querySelector('.card-title').textContent.toLowerCase();
|
||||
const description = card.querySelector('.card-text').textContent.toLowerCase();
|
||||
|
||||
if (title.includes(searchTerm) || description.includes(searchTerm)) {
|
||||
card.style.display = '';
|
||||
hasResults = true;
|
||||
} else {
|
||||
card.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// 如果没有搜索结果,显示提示
|
||||
if (!hasResults) {
|
||||
Swal.fire({
|
||||
title: '未找到结果',
|
||||
text: '没有找到与 "' + searchTerm + '" 匹配的应用',
|
||||
icon: 'info',
|
||||
confirmButtonText: '确定'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 添加表单提交事件监听
|
||||
document.getElementById('searchForm').addEventListener('submit', performSearch);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
255
docs/app_review_standards.php
Normal file
255
docs/app_review_standards.php
Normal file
@@ -0,0 +1,255 @@
|
||||
<?php
|
||||
/**
|
||||
* APP 审核标准文档 - 完整版
|
||||
*/
|
||||
?>
|
||||
<?php require_once '../config.php'; ?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>APP 审核标准 - 完整版</title>
|
||||
<link href="/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Font Awesome -->
|
||||
<link rel="stylesheet" href="/css/all.min.css">
|
||||
<style>
|
||||
body { padding-top: 56px; }
|
||||
.blur-bg {
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.audit-section {
|
||||
margin-bottom: 2rem;
|
||||
padding: 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.audit-subsection {
|
||||
margin-bottom: 1.5rem;
|
||||
padding-left: 1rem;
|
||||
border-left: 3px solid #0d6efd;
|
||||
}
|
||||
.audit-point {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
.audit-note {
|
||||
color: #6c757d;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 0.25rem;
|
||||
margin-left: 1.5rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light blur-bg fixed-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="/index.php"><?php echo APP_STORE_NAME; ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">首页</a>
|
||||
</li>
|
||||
<?php if (isset($_SESSION['admin'])): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/admin/">管理</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container mt-5 mb-5">
|
||||
<div class="text-center mb-5">
|
||||
<h1 class="display-4">APP 审核标准文档</h1>
|
||||
<p class="lead">适用于所有平台的应用审核规范</p>
|
||||
<p class="text-muted">版本:2025.07 修订</p>
|
||||
</div>
|
||||
|
||||
<div class="audit-section">
|
||||
<h2 class="fw-bold mb-4">一、内容审核标准</h2>
|
||||
|
||||
<div class="audit-subsection">
|
||||
<h3 class="fw-semibold">1.1 法律法规合规性</h3>
|
||||
<ul class="list-unstyled">
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">1.1.1</span> 不得包含任何违反中国法律法规的内容,如赌博、色情、暴力、恐怖主义等相关信息
|
||||
<p class="audit-note">包括但不限于文字、图片、音频、视频等形式的违法内容</p>
|
||||
</li>
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">1.1.2</span> 不得含有侵犯他人隐私、名誉权、肖像权等个人权利的内容
|
||||
<p class="audit-note">需确保用户数据收集、使用和共享符合《个人信息保护法》</p>
|
||||
</li>
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">1.1.3</span> 不得传播谣言、虚假信息或误导性内容
|
||||
<p class="audit-note">特别是涉及金融、医疗、时政等敏感领域的信息</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="audit-subsection">
|
||||
<h3 class="fw-semibold">1.2 知识产权保护</h3>
|
||||
<ul class="list-unstyled">
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">1.2.1</span> 不得包含侵犯他人商标、专利、著作权等知识产权的内容
|
||||
<p class="audit-note">应用内所有内容需确保有合法授权或属于原创</p>
|
||||
</li>
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">1.2.2</span> 不得抄袭或模仿已有应用的界面设计、功能逻辑或商业模式
|
||||
<p class="audit-note">需具备显著的原创性和独特价值</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="audit-subsection">
|
||||
<h3 class="fw-semibold">1.3 广告与推广内容</h3>
|
||||
<ul class="list-unstyled">
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">1.3.1</span> 所有广告内容必须真实、合法,不得含有虚假或引人误解的宣传
|
||||
<p class="audit-note">广告需明确标识,与应用内容有清晰区分</p>
|
||||
</li>
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">1.3.2</span> 不得诱导用户点击广告或进行不必要的操作
|
||||
<p class="audit-note">禁止使用欺骗性标题、虚假下载按钮等手段</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="audit-section">
|
||||
<h2 class="fw-bold mb-4">二、功能审核标准</h2>
|
||||
|
||||
<div class="audit-subsection">
|
||||
<h3 class="fw-semibold">2.1 功能完整性</h3>
|
||||
<ul class="list-unstyled">
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">2.1.1</span> 应用必须实现所有宣称的核心功能,无缺失或未完成的功能模块
|
||||
<p class="audit-note">需与应用商店描述、宣传材料一致</p>
|
||||
</li>
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">2.1.2</span> 所有功能必须可正常使用,无崩溃、闪退或无法访问的情况
|
||||
<p class="audit-note">包括但不限于注册登录、数据提交、支付流程等</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="audit-subsection">
|
||||
<h3 class="fw-semibold">2.2 用户界面与交互</h3>
|
||||
<ul class="list-unstyled">
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">2.2.1</span> 界面设计需符合目标平台的设计规范(如iOS Human Interface Guidelines或Android Material Design)
|
||||
<p class="audit-note">包括布局、色彩、图标、字体等视觉元素的一致性</p>
|
||||
</li>
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">2.2.2</span> 交互逻辑清晰,操作流程合理,无歧义或容易引起用户误解的设计
|
||||
<p class="audit-note">例如按钮响应区域足够大,导航逻辑明确</p>
|
||||
</li>
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">2.2.3</span> 支持多种屏幕尺寸和分辨率,在不同设备上显示正常
|
||||
<p class="audit-note">需进行全面的兼容性测试</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="audit-subsection">
|
||||
<h3 class="fw-semibold">2.3 数据安全与隐私</h3>
|
||||
<ul class="list-unstyled">
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">2.3.1</span> 应用必须有明确的隐私政策,说明数据收集、使用和共享方式
|
||||
<p class="audit-note">隐私政策需符合相关法律法规要求</p>
|
||||
</li>
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">2.3.2</span> 敏感数据(如密码、支付信息等)必须进行加密处理
|
||||
<p class="audit-note">推荐使用HTTPS协议进行数据传输</p>
|
||||
</li>
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">2.3.3</span> 不得在用户未明确授权的情况下收集、使用或共享个人数据
|
||||
<p class="audit-note">特别是位置、联系人、摄像头等敏感权限</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="audit-section">
|
||||
<h2 class="fw-bold mb-4">三、性能审核标准</h2>
|
||||
|
||||
<div class="audit-subsection">
|
||||
<h3 class="fw-semibold">3.1 响应速度与稳定性</h3>
|
||||
<ul class="list-unstyled">
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">3.1.1</span> 应用启动时间不得超过3秒(冷启动)和1秒(热启动)
|
||||
<p class="audit-note">对于复杂应用,启动时间可适当放宽,但需提供合理说明</p>
|
||||
</li>
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">3.1.2</span> 界面切换和操作响应时间不得超过500毫秒
|
||||
<p class="audit-note">需避免长时间无响应或卡顿现象</p>
|
||||
</li>
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">3.1.3</span> 在正常使用场景下,应用不得出现崩溃、闪退或无响应的情况
|
||||
<p class="audit-note">需进行至少5000次操作的稳定性测试</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="audit-subsection">
|
||||
<h3 class="fw-semibold">3.2 资源占用</h3>
|
||||
<ul class="list-unstyled">
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">3.2.1</span> 应用在 idle 状态下内存占用不得超过100MB
|
||||
<p class="audit-note">复杂应用(如图形处理、游戏等)可适当放宽</p>
|
||||
</li>
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">3.2.2</span> 应用不得过度消耗设备CPU、电池等资源
|
||||
<p class="audit-note">禁止在后台执行不必要的操作或频繁唤醒设备</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="audit-subsection">
|
||||
<h3 class="fw-semibold">3.3 兼容性</h3>
|
||||
<ul class="list-unstyled">
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">3.3.1</span> 应用必须支持目标平台的主流版本(如iOS 14+,Android 8.0+)
|
||||
<p class="audit-note">需在审核时提供支持版本列表</p>
|
||||
</li>
|
||||
<li class="audit-point">
|
||||
<span class="fw-medium">3.3.2</span> 应用必须在主流设备型号上正常运行,无显示异常或功能缺失
|
||||
<p class="audit-note">至少覆盖市场占有率前80%的设备</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="audit-section">
|
||||
<h2 class="fw-bold mb-4">四、审核流程与结果</h2>
|
||||
|
||||
<div class="audit-subsection">
|
||||
<h3 class="fw-semibold">4.1 审核周期</h3>
|
||||
<p>标准审核周期为5个工作日,紧急审核可在24小时内完成(需额外支付加急费用支付到<a href="https://afdian.com/a/leonmmcoset">站长爱发电</a>(使用自定义金额并备注)5元)</p>
|
||||
</div>
|
||||
|
||||
<div class="audit-subsection">
|
||||
<h3 class="fw-semibold">4.2 审核结果通知</h3>
|
||||
<p>审核结果将通过邮件和平台内消息通知开发者,包含审核通过或拒绝上线两种结果</p>
|
||||
</div>
|
||||
|
||||
<div class="audit-subsection">
|
||||
<h3 class="fw-semibold">4.3 申诉机制</h3>
|
||||
<p>如对审核结果有异议,开发者可在收到通知后7个工作日内向<a href="mailto:leonmmcoset@outlook.com">站长邮件</a>提交申诉,我们将在3个工作日内进行复核</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-6">
|
||||
<p class="text-muted">© 2025 LeonAPP. 保留所有权利.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
46
docs/privacy_policy.php
Normal file
46
docs/privacy_policy.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once '../config.php';
|
||||
|
||||
if (!isset($conn) || !$conn instanceof mysqli) {
|
||||
die('数据库连接失败,请检查配置文件。');
|
||||
}?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>隐私政策</title>
|
||||
<style> .page-transition { animation: fadeIn 0.5s ease-in-out; } @keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } </style> <!-- Bootstrap CSS --> <link href="../css/bootstrap.min.css" rel="stylesheet"> <!-- 自定义CSS -->
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
<!-- Fluent Design 模糊效果 -->
|
||||
<!-- Bootstrap JS Bundle with Popper -->
|
||||
<script src="../js/bootstrap.bundle.js"></script> <style> .blur-bg { backdrop-filter: blur(10px); background-color: rgba(255, 255, 255, 0.5); } </style></head><body class="page-transition"> <!-- 导航栏 --> <nav class="navbar navbar-expand-lg navbar-light blur-bg"> <div class="container"> <a class="navbar-brand" href="#"><?php echo APP_STORE_NAME; ?></a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="../index.php">首页</a> </li> <?php if (isset($_SESSION['admin'])): ?> <li class="nav-item"> <a class="nav-link" href="../admin/">管理</a> </li> <?php endif; ?> <li class="nav-item"> <a class="nav-link" href="../tags.php">标签</a> </li> <?php if (isset($_SESSION['developer_id'])): ?> <li class="nav-item"> <a class="nav-link" href="../developer/dashboard.php">进入面板</a> </li> <?php else: ?> <li class="nav-item"> <a class="nav-link" href="../developer/register.php">开发者注册</a> </li> <li class="nav-item"> <a class="nav-link" href="../developer/login.php">开发者登录</a> </li> <?php endif; ?> </ul> </div> </div> </nav> <div class="container mt-4">
|
||||
<h1>隐私政策</h1>
|
||||
|
||||
<h2>引言</h2>
|
||||
<p>本隐私政策旨在说明我们如何收集、使用、披露和保护您的个人信息。在使用我们的服务前,请仔细阅读本隐私政策。</p>
|
||||
|
||||
<h2>信息收集</h2>
|
||||
<p>我们会收集您在使用服务时主动提供的信息,例如注册信息等。同时,我们也会自动收集一些信息,如设备信息、日志信息等。</p>
|
||||
|
||||
<h2>信息使用</h2>
|
||||
<p>我们会将收集到的信息用于提供、维护和改进服务,个性化用户体验,处理交易,以及遵守法律要求等。</p>
|
||||
|
||||
<h2>信息披露</h2>
|
||||
<p>除非获得您的同意,或者根据法律要求,否则我们不会向第三方披露您的个人信息。在某些情况下,我们可能会与合作伙伴共享信息,但会确保他们遵守严格的数据保护要求。</p>
|
||||
|
||||
<h2>信息保护</h2>
|
||||
<p>我们采用合理的安全措施来保护您的个人信息,防止信息被未经授权的访问、使用或披露。但请您理解,没有任何一种互联网传输方式或电子存储方式是 100% 安全的。</p>
|
||||
|
||||
<h2>您的权利</h2>
|
||||
<p>您有权访问、更正、删除您的个人信息,以及限制我们对您信息的处理。如果您有任何相关请求,请联系我们。</p>
|
||||
|
||||
<h2>政策变更</h2>
|
||||
<p>我们可能会定期更新本隐私政策。更新后,我们会在网站上发布新的隐私政策,并说明变更的生效日期。请您定期查看本政策,以了解我们的信息处理方式是否有变化。</p>
|
||||
|
||||
<h2>联系我们</h2>
|
||||
<p>如果您对本隐私政策有任何疑问或建议,请通过 [您的联系方式] 与我们联系。</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
54
download.php
Normal file
54
download.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
ob_start();
|
||||
require_once 'config.php';
|
||||
|
||||
// 验证版本ID
|
||||
if (!isset($_GET['version_id']) || !is_numeric($_GET['version_id'])) {
|
||||
http_response_code(400);
|
||||
exit('无效的版本ID');
|
||||
}
|
||||
$versionId = $_GET['version_id'];
|
||||
|
||||
// 获取版本信息
|
||||
$version = null;
|
||||
$getVersionSql = "SELECT * FROM app_versions WHERE id = ?";
|
||||
$stmt = $conn->prepare($getVersionSql);
|
||||
$stmt->bind_param("i", $versionId);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
if ($result->num_rows !== 1) {
|
||||
http_response_code(404);
|
||||
exit('版本不存在');
|
||||
}
|
||||
$version = $result->fetch_assoc();
|
||||
|
||||
// 获取绝对文件路径
|
||||
$filePath = realpath(__DIR__ . '/' . $version['file_path']);
|
||||
|
||||
// 验证文件存在性
|
||||
if (!$filePath || !file_exists($filePath)) {
|
||||
http_response_code(404);
|
||||
exit('文件不存在');
|
||||
}
|
||||
|
||||
// 设置下载响应头
|
||||
$fileName = basename($filePath);
|
||||
$fileSize = filesize($filePath);
|
||||
|
||||
// 清除输出缓冲区并发送 headers
|
||||
ob_end_clean();
|
||||
header('Content-Type: application/octet-stream');
|
||||
header('Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode($fileName));
|
||||
header('Content-Length: ' . $fileSize);
|
||||
header('Cache-Control: no-cache, must-revalidate');
|
||||
header('Expires: 0');
|
||||
header('Pragma: public');
|
||||
|
||||
// 输出文件内容
|
||||
if (!readfile($filePath)) {
|
||||
http_response_code(500);
|
||||
exit('无法读取文件');
|
||||
}
|
||||
|
||||
exit;
|
||||
?>
|
||||
56
includes/logger.php
Normal file
56
includes/logger.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/**
|
||||
* Logging utility for the application
|
||||
* Provides log_info() and log_error() functions
|
||||
*/
|
||||
|
||||
if (!function_exists('log_info')) {
|
||||
/**
|
||||
* Log informational message
|
||||
* @param string $message The message to log
|
||||
* @param string $file Optional file name where the log was called
|
||||
* @param int $line Optional line number where the log was called
|
||||
*/
|
||||
function log_info($message, $file = '', $line = 0) {
|
||||
$logFile = __DIR__ . '/../logs/app_' . date('Y-m-d') . '.log';
|
||||
|
||||
// Create logs directory if it doesn't exist
|
||||
if (!file_exists(dirname($logFile))) {
|
||||
mkdir(dirname($logFile), 0755, true);
|
||||
}
|
||||
|
||||
$prefix = '[' . date('Y-m-d H:i:s') . '] [INFO]';
|
||||
if (!empty($file) && $line > 0) {
|
||||
$prefix .= ' [' . basename($file) . ':' . $line . ']';
|
||||
}
|
||||
|
||||
$logMessage = $prefix . ' ' . $message . PHP_EOL;
|
||||
file_put_contents($logFile, $logMessage, FILE_APPEND);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('log_error')) {
|
||||
/**
|
||||
* Log error message
|
||||
* @param string $message The error message to log
|
||||
* @param string $file Optional file name where the error occurred
|
||||
* @param int $line Optional line number where the error occurred
|
||||
*/
|
||||
function log_error($message, $file = '', $line = 0) {
|
||||
$logFile = __DIR__ . '/../logs/error_' . date('Y-m-d') . '.log';
|
||||
|
||||
// Create logs directory if it doesn't exist
|
||||
if (!file_exists(dirname($logFile))) {
|
||||
mkdir(dirname($logFile), 0755, true);
|
||||
}
|
||||
|
||||
$prefix = '[' . date('Y-m-d H:i:s') . '] [ERROR]';
|
||||
if (!empty($file) && $line > 0) {
|
||||
$prefix .= ' [' . basename($file) . ':' . $line . ']';
|
||||
}
|
||||
|
||||
$logMessage = $prefix . ' ' . $message . PHP_EOL;
|
||||
file_put_contents($logFile, $logMessage, FILE_APPEND);
|
||||
}
|
||||
}
|
||||
?>
|
||||
355
index.php
Normal file
355
index.php
Normal file
@@ -0,0 +1,355 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'config.php';
|
||||
|
||||
if (!isset($conn) || !$conn instanceof mysqli) {
|
||||
die('数据库连接失败,请检查配置文件。');
|
||||
}?>
|
||||
<!DOCTYPE html>
|
||||
<style>
|
||||
.page-transition {
|
||||
animation: fadeIn 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php echo APP_STORE_NAME; ?></title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- 自定义CSS -->
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<!-- Fluent Design 模糊效果 -->
|
||||
<style>
|
||||
.blur-bg {
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="page-transition">
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light blur-bg">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="#"><?php echo APP_STORE_NAME; ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">首页</a>
|
||||
</li>
|
||||
<?php if (isset($_SESSION['admin'])): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/admin/">管理</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="tags.php">标签</a>
|
||||
</li>
|
||||
<?php if (isset($_SESSION['developer_id'])): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="developer/dashboard.php">进入面板</a>
|
||||
</li>
|
||||
<?php else: ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="developer/register.php">开发者注册</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="developer/login.php">开发者登录</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<?php
|
||||
// 获取最新公告
|
||||
$announcementQuery = "SELECT title, content FROM announcements ORDER BY created_at DESC LIMIT 1";
|
||||
$announcementResult = $conn->query($announcementQuery);
|
||||
$announcement = $announcementResult && $announcementResult->num_rows > 0 ? $announcementResult->fetch_assoc() : null;
|
||||
?>
|
||||
<?php if ($announcement): ?>
|
||||
<div class="container mt-3">
|
||||
<div class="alert alert-info blur-bg">
|
||||
<h4 class="alert-heading"><?php echo htmlspecialchars($announcement['title']); ?></h4>
|
||||
<p><?php echo nl2br(htmlspecialchars($announcement['content'])); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<form method="get" action="index.php" class="mb-4" onsubmit="return validateSearch();">
|
||||
<script>
|
||||
function validateSearch() {
|
||||
const searchInput = document.querySelector('input[name="search"]');
|
||||
if (searchInput.value.trim() === '') {
|
||||
Swal.fire({
|
||||
title: '提示',
|
||||
text: '请填写搜索名称后再进行搜索!',
|
||||
icon: 'warning',
|
||||
confirmButtonText: '确定'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
</script>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<div class="form-floating">
|
||||
<input type="text" name="search" class="form-control" id="searchInput" placeholder="搜索应用..." value="<?php echo isset($_GET['search']) ? htmlspecialchars($_GET['search']) : ''; ?>">
|
||||
<label for="searchInput">搜索应用</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-floating">
|
||||
<select name="tag" class="form-select" id="tagSelect">
|
||||
<option value="">所有标签</option>
|
||||
<?php
|
||||
$tagResult = $conn->query("SELECT id, name FROM tags ORDER BY name");
|
||||
$selectedTag = isset($_GET['tag']) ? $_GET['tag'] : '';
|
||||
while ($tag = $tagResult->fetch_assoc()):
|
||||
$selected = ($tag['id'] == $selectedTag) ? 'selected' : '';
|
||||
?>
|
||||
<option value="<?php echo $tag['id']; ?>" <?php echo $selected; ?>><?php echo htmlspecialchars($tag['name']); ?></option>
|
||||
<?php endwhile; ?>
|
||||
</select>
|
||||
<label for="tagSelect">选择标签</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button class="btn btn-primary w-100" style="width: calc(3.5rem + calc(var(--bs-border-width) * 2)); height: calc(3.5rem + calc(var(--bs-border-width) * 2))" type="submit">搜索</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php if (isset($_SESSION['user_id'])): ?>
|
||||
<h1>为你推荐</h1>
|
||||
<div class="row">
|
||||
<?php
|
||||
// 获取用户下载过的应用标签
|
||||
$userId = $_SESSION['user_id'];
|
||||
$tagSql = "SELECT DISTINCT t.id FROM tags t
|
||||
JOIN app_tags at ON t.id = at.tag_id
|
||||
JOIN app_versions av ON at.app_id = av.app_id
|
||||
JOIN download_history dh ON av.id = dh.version_id
|
||||
WHERE dh.user_id = ?";
|
||||
$tagStmt = $conn->prepare($tagSql);
|
||||
$tagStmt->bind_param('i', $userId);
|
||||
$tagStmt->execute();
|
||||
$tagResult = $tagStmt->get_result();
|
||||
$tagIds = [];
|
||||
while ($tag = $tagResult->fetch_assoc()) {
|
||||
$tagIds[] = $tag['id'];
|
||||
}
|
||||
$tagStmt->close();
|
||||
|
||||
// 获取用户已下载的应用
|
||||
$downloadedSql = "SELECT DISTINCT a.id FROM apps a
|
||||
JOIN app_versions av ON a.id = av.app_id
|
||||
JOIN download_history dh ON av.id = dh.version_id
|
||||
WHERE dh.user_id = ?";
|
||||
$downloadedStmt = $conn->prepare($downloadedSql);
|
||||
$downloadedStmt->bind_param('i', $userId);
|
||||
$downloadedStmt->execute();
|
||||
$downloadedResult = $downloadedStmt->get_result();
|
||||
$downloadedIds = [];
|
||||
while ($app = $downloadedResult->fetch_assoc()) {
|
||||
$downloadedIds[] = $app['id'];
|
||||
}
|
||||
$downloadedStmt->close();
|
||||
|
||||
// 基于标签推荐应用
|
||||
if (!empty($tagIds)) {
|
||||
$placeholders = implode(',', array_fill(0, count($tagIds), '?'));
|
||||
$recommendSql = "SELECT a.id, a.name, a.description, a.age_rating, AVG(r.rating) as avg_rating
|
||||
FROM apps a
|
||||
LEFT JOIN reviews r ON a.id = r.app_id
|
||||
JOIN app_tags at ON a.id = at.app_id
|
||||
WHERE at.tag_id IN ($placeholders)
|
||||
AND a.id NOT IN (" . (!empty($downloadedIds) ? implode(',', $downloadedIds) : '0') . ")
|
||||
AND a.status = 'approved'
|
||||
GROUP BY a.id
|
||||
ORDER BY COUNT(at.tag_id) DESC
|
||||
LIMIT 12";
|
||||
$recommendStmt = $conn->prepare($recommendSql);
|
||||
$types = str_repeat('i', count($tagIds));
|
||||
$recommendStmt->bind_param($types, ...$tagIds);
|
||||
$recommendStmt->execute();
|
||||
$recommendResult = $recommendStmt->get_result();
|
||||
} else {
|
||||
// 如果没有标签数据,显示热门应用
|
||||
$recommendSql = "SELECT a.id, a.name, a.description, a.age_rating, AVG(r.rating) as avg_rating, SUM(av.download_count) as total_downloads
|
||||
FROM apps a
|
||||
LEFT JOIN reviews r ON a.id = r.app_id
|
||||
LEFT JOIN app_versions av ON a.id = av.app_id
|
||||
WHERE a.status = 'approved'
|
||||
GROUP BY a.id
|
||||
ORDER BY total_downloads DESC
|
||||
LIMIT 12";
|
||||
$recommendResult = $conn->query($recommendSql);
|
||||
}
|
||||
|
||||
if ($recommendResult && $recommendResult->num_rows > 0) {
|
||||
while ($row = $recommendResult->fetch_assoc()) {
|
||||
echo '<div class="col-md-3 mb-4">';
|
||||
echo '<div class="card blur-bg">';
|
||||
|
||||
echo '<div class="card-body">';
|
||||
echo '<h5 class="card-title">'. htmlspecialchars($row['name']) . '</h5>';
|
||||
echo '<p class="card-text">'. substr(htmlspecialchars($row['description']), 0, 100) . '...</p>';
|
||||
echo '<p class="card-text">评分: '. round($row['avg_rating'] ?? 0, 1) . '/5</p>';
|
||||
echo '<a href="app.php?id='. $row['id'] . '" class="btn btn-primary">查看详情</a>';
|
||||
echo '<button class="btn btn-outline-secondary mt-2" onclick="toggleFavorite('. $row['id'] . ', \''. htmlspecialchars($row['name']) . '\')">收藏</button>';
|
||||
echo '</div></div></div>';
|
||||
}
|
||||
} else {
|
||||
echo '<div class="col-12"><p class="text-center">暂无推荐内容</p></div>';
|
||||
}
|
||||
if (isset($recommendStmt)) $recommendStmt->close();
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h1>最新应用</h1>
|
||||
<div class="row">
|
||||
<!-- 这里将通过PHP动态加载应用列表 -->
|
||||
<?php
|
||||
$search = isset($_GET['search']) ? $_GET['search'] : '';
|
||||
$limit = isset($_GET['limit']) ? intval($_GET['limit']) : 12;
|
||||
$offset = isset($_GET['page']) ? (intval($_GET['page']) - 1) * $limit : 0;
|
||||
$sql = "SELECT apps.id, apps.name, apps.description, apps.age_rating, AVG(reviews.rating) as avg_rating
|
||||
FROM apps
|
||||
LEFT JOIN reviews ON apps.id = reviews.app_id ";
|
||||
|
||||
$conditions = [];
|
||||
$params = [];
|
||||
$paramTypes = '';
|
||||
|
||||
// 标签筛选
|
||||
if (!empty($_GET['tag'])) {
|
||||
$sql .= "JOIN app_tags ON apps.id = app_tags.app_id
|
||||
JOIN tags ON app_tags.tag_id = tags.id ";
|
||||
$conditions[] = "app_tags.tag_id = ?";
|
||||
$tagId = $_GET['tag'];
|
||||
$params[] = &$tagId;
|
||||
$paramTypes .= 'i';
|
||||
}
|
||||
|
||||
// 平台筛选
|
||||
if (!empty($_GET['platform'])) {
|
||||
// Removed platform condition - column does not exist
|
||||
$platform = $_GET['platform'];
|
||||
$params[] = &$platform;
|
||||
$paramTypes .= 's';
|
||||
}
|
||||
|
||||
// 年龄分级筛选
|
||||
if (!empty($_GET['age_rating'])) {
|
||||
$conditions[] = "apps.age_rating = ?";
|
||||
$ageRating = $_GET['age_rating'];
|
||||
$params[] = &$ageRating;
|
||||
$paramTypes .= 's';
|
||||
}
|
||||
|
||||
// 搜索关键词筛选
|
||||
if (!empty($search)) {
|
||||
$conditions[] = "(apps.name LIKE ? OR apps.description LIKE ?)";
|
||||
$searchTerm1 = "%$search%";
|
||||
$searchTerm2 = "%$search%";
|
||||
$params[] = &$searchTerm1;
|
||||
$params[] = &$searchTerm2;
|
||||
$paramTypes .= 'ss';
|
||||
}
|
||||
|
||||
// 只显示已审核通过的应用
|
||||
$conditions[] = "apps.status = 'approved'";
|
||||
|
||||
// 添加条件
|
||||
if (!empty($conditions)) {
|
||||
$sql .= "WHERE " . implode(" AND ", $conditions);
|
||||
}
|
||||
|
||||
$sql .= "GROUP BY apps.id
|
||||
ORDER BY apps.created_at DESC
|
||||
LIMIT ? OFFSET ?";
|
||||
$limitVal = $limit;
|
||||
$offsetVal = $offset;
|
||||
$params[] = &$limitVal;
|
||||
$params[] = &$offsetVal;
|
||||
// 添加分页参数类型
|
||||
$paramTypes .= 'ii';
|
||||
|
||||
// 执行查询
|
||||
if (!empty($params)) {
|
||||
$stmt = $conn->prepare($sql);
|
||||
if (!$stmt) {
|
||||
die('预处理语句失败: ' . $conn->error);
|
||||
}
|
||||
call_user_func_array([$stmt, 'bind_param'], array_merge([$paramTypes], $params));
|
||||
if (!$stmt->execute()) {
|
||||
die('执行语句失败: ' . $stmt->error);
|
||||
}
|
||||
$result = $stmt->get_result();
|
||||
} else {
|
||||
$result = $conn->query($sql);
|
||||
if (!$result) {
|
||||
die('查询失败: ' . $conn->error);
|
||||
}
|
||||
}
|
||||
|
||||
if ($result->num_rows > 0) {
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
echo '<div class="col-md-3 mb-4">';
|
||||
echo '<div class="card blur-bg">';
|
||||
|
||||
echo '<div class="card-body">';
|
||||
echo '<h5 class="card-title">'. $row['name'] . '</h5>';
|
||||
echo '<p class="card-text">'. substr($row['description'], 0, 100) . '...</p>';
|
||||
echo '<p class="card-text">评分: '. round($row['avg_rating'], 1) . '/5</p>';
|
||||
echo '<a href="app.php?id='. $row['id'] . '" class="btn btn-primary">查看详情</a>';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS Bundle with Popper -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
// 导航栏滚动效果
|
||||
window.addEventListener('scroll', function() {
|
||||
const navbar = document.querySelector('.navbar');
|
||||
if (window.scrollY > 10) {
|
||||
navbar.classList.add('scrolled');
|
||||
} else {
|
||||
navbar.classList.remove('scrolled');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.body.classList.add('page-transition');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
6
js/all.min.js
vendored
Normal file
6
js/all.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6306
js/bootstrap.bundle.js
vendored
Normal file
6306
js/bootstrap.bundle.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
749
js/brands.js
Normal file
749
js/brands.js
Normal file
File diff suppressed because one or more lines are too long
6
js/brands.min.js
vendored
Normal file
6
js/brands.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
3477
js/charts.js
Normal file
3477
js/charts.js
Normal file
File diff suppressed because it is too large
Load Diff
1138
js/conflict-detection.js
Normal file
1138
js/conflict-detection.js
Normal file
File diff suppressed because it is too large
Load Diff
6
js/conflict-detection.min.js
vendored
Normal file
6
js/conflict-detection.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
3126
js/fontawesome.js
Normal file
3126
js/fontawesome.js
Normal file
File diff suppressed because one or more lines are too long
6
js/fontawesome.min.js
vendored
Normal file
6
js/fontawesome.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
445
js/regular.js
Normal file
445
js/regular.js
Normal file
@@ -0,0 +1,445 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var _WINDOW = {};
|
||||
var _DOCUMENT = {};
|
||||
|
||||
try {
|
||||
if (typeof window !== 'undefined') _WINDOW = window;
|
||||
if (typeof document !== 'undefined') _DOCUMENT = document;
|
||||
} catch (e) {}
|
||||
|
||||
var _ref = _WINDOW.navigator || {},
|
||||
_ref$userAgent = _ref.userAgent,
|
||||
userAgent = _ref$userAgent === void 0 ? '' : _ref$userAgent;
|
||||
var WINDOW = _WINDOW;
|
||||
var DOCUMENT = _DOCUMENT;
|
||||
var IS_BROWSER = !!WINDOW.document;
|
||||
var IS_DOM = !!DOCUMENT.documentElement && !!DOCUMENT.head && typeof DOCUMENT.addEventListener === 'function' && typeof DOCUMENT.createElement === 'function';
|
||||
var IS_IE = ~userAgent.indexOf('MSIE') || ~userAgent.indexOf('Trident/');
|
||||
|
||||
function ownKeys(object, enumerableOnly) {
|
||||
var keys = Object.keys(object);
|
||||
|
||||
if (Object.getOwnPropertySymbols) {
|
||||
var symbols = Object.getOwnPropertySymbols(object);
|
||||
enumerableOnly && (symbols = symbols.filter(function (sym) {
|
||||
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
||||
})), keys.push.apply(keys, symbols);
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
function _objectSpread2(target) {
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
var source = null != arguments[i] ? arguments[i] : {};
|
||||
i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
|
||||
_defineProperty(target, key, source[key]);
|
||||
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
|
||||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
||||
});
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
function _defineProperty(obj, key, value) {
|
||||
if (key in obj) {
|
||||
Object.defineProperty(obj, key, {
|
||||
value: value,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true
|
||||
});
|
||||
} else {
|
||||
obj[key] = value;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function _toConsumableArray(arr) {
|
||||
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
|
||||
}
|
||||
|
||||
function _arrayWithoutHoles(arr) {
|
||||
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
|
||||
}
|
||||
|
||||
function _iterableToArray(iter) {
|
||||
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
|
||||
}
|
||||
|
||||
function _unsupportedIterableToArray(o, minLen) {
|
||||
if (!o) return;
|
||||
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
|
||||
var n = Object.prototype.toString.call(o).slice(8, -1);
|
||||
if (n === "Object" && o.constructor) n = o.constructor.name;
|
||||
if (n === "Map" || n === "Set") return Array.from(o);
|
||||
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
|
||||
}
|
||||
|
||||
function _arrayLikeToArray(arr, len) {
|
||||
if (len == null || len > arr.length) len = arr.length;
|
||||
|
||||
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
|
||||
|
||||
return arr2;
|
||||
}
|
||||
|
||||
function _nonIterableSpread() {
|
||||
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
||||
}
|
||||
|
||||
var _familyProxy, _familyProxy2, _familyProxy3, _familyProxy4, _familyProxy5;
|
||||
|
||||
var NAMESPACE_IDENTIFIER = '___FONT_AWESOME___';
|
||||
var PRODUCTION = function () {
|
||||
try {
|
||||
return "production" === 'production';
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}();
|
||||
var FAMILY_CLASSIC = 'classic';
|
||||
var FAMILY_SHARP = 'sharp';
|
||||
var FAMILIES = [FAMILY_CLASSIC, FAMILY_SHARP];
|
||||
|
||||
function familyProxy(obj) {
|
||||
// Defaults to the classic family if family is not available
|
||||
return new Proxy(obj, {
|
||||
get: function get(target, prop) {
|
||||
return prop in target ? target[prop] : target[FAMILY_CLASSIC];
|
||||
}
|
||||
});
|
||||
}
|
||||
var PREFIX_TO_STYLE = familyProxy((_familyProxy = {}, _defineProperty(_familyProxy, FAMILY_CLASSIC, {
|
||||
'fa': 'solid',
|
||||
'fas': 'solid',
|
||||
'fa-solid': 'solid',
|
||||
'far': 'regular',
|
||||
'fa-regular': 'regular',
|
||||
'fal': 'light',
|
||||
'fa-light': 'light',
|
||||
'fat': 'thin',
|
||||
'fa-thin': 'thin',
|
||||
'fad': 'duotone',
|
||||
'fa-duotone': 'duotone',
|
||||
'fab': 'brands',
|
||||
'fa-brands': 'brands',
|
||||
'fak': 'kit',
|
||||
'fa-kit': 'kit'
|
||||
}), _defineProperty(_familyProxy, FAMILY_SHARP, {
|
||||
'fa': 'solid',
|
||||
'fass': 'solid',
|
||||
'fa-solid': 'solid',
|
||||
'fasr': 'regular',
|
||||
'fa-regular': 'regular',
|
||||
'fasl': 'light',
|
||||
'fa-light': 'light'
|
||||
}), _familyProxy));
|
||||
var STYLE_TO_PREFIX = familyProxy((_familyProxy2 = {}, _defineProperty(_familyProxy2, FAMILY_CLASSIC, {
|
||||
'solid': 'fas',
|
||||
'regular': 'far',
|
||||
'light': 'fal',
|
||||
'thin': 'fat',
|
||||
'duotone': 'fad',
|
||||
'brands': 'fab',
|
||||
'kit': 'fak'
|
||||
}), _defineProperty(_familyProxy2, FAMILY_SHARP, {
|
||||
'solid': 'fass',
|
||||
'regular': 'fasr',
|
||||
'light': 'fasl'
|
||||
}), _familyProxy2));
|
||||
var PREFIX_TO_LONG_STYLE = familyProxy((_familyProxy3 = {}, _defineProperty(_familyProxy3, FAMILY_CLASSIC, {
|
||||
'fab': 'fa-brands',
|
||||
'fad': 'fa-duotone',
|
||||
'fak': 'fa-kit',
|
||||
'fal': 'fa-light',
|
||||
'far': 'fa-regular',
|
||||
'fas': 'fa-solid',
|
||||
'fat': 'fa-thin'
|
||||
}), _defineProperty(_familyProxy3, FAMILY_SHARP, {
|
||||
'fass': 'fa-solid',
|
||||
'fasr': 'fa-regular',
|
||||
'fasl': 'fa-light'
|
||||
}), _familyProxy3));
|
||||
var LONG_STYLE_TO_PREFIX = familyProxy((_familyProxy4 = {}, _defineProperty(_familyProxy4, FAMILY_CLASSIC, {
|
||||
'fa-brands': 'fab',
|
||||
'fa-duotone': 'fad',
|
||||
'fa-kit': 'fak',
|
||||
'fa-light': 'fal',
|
||||
'fa-regular': 'far',
|
||||
'fa-solid': 'fas',
|
||||
'fa-thin': 'fat'
|
||||
}), _defineProperty(_familyProxy4, FAMILY_SHARP, {
|
||||
'fa-solid': 'fass',
|
||||
'fa-regular': 'fasr',
|
||||
'fa-light': 'fasl'
|
||||
}), _familyProxy4));
|
||||
var FONT_WEIGHT_TO_PREFIX = familyProxy((_familyProxy5 = {}, _defineProperty(_familyProxy5, FAMILY_CLASSIC, {
|
||||
'900': 'fas',
|
||||
'400': 'far',
|
||||
'normal': 'far',
|
||||
'300': 'fal',
|
||||
'100': 'fat'
|
||||
}), _defineProperty(_familyProxy5, FAMILY_SHARP, {
|
||||
'900': 'fass',
|
||||
'400': 'fasr',
|
||||
'300': 'fasl'
|
||||
}), _familyProxy5));
|
||||
var oneToTen = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
var oneToTwenty = oneToTen.concat([11, 12, 13, 14, 15, 16, 17, 18, 19, 20]);
|
||||
var DUOTONE_CLASSES = {
|
||||
GROUP: 'duotone-group',
|
||||
SWAP_OPACITY: 'swap-opacity',
|
||||
PRIMARY: 'primary',
|
||||
SECONDARY: 'secondary'
|
||||
};
|
||||
var prefixes = new Set();
|
||||
Object.keys(STYLE_TO_PREFIX[FAMILY_CLASSIC]).map(prefixes.add.bind(prefixes));
|
||||
Object.keys(STYLE_TO_PREFIX[FAMILY_SHARP]).map(prefixes.add.bind(prefixes));
|
||||
var RESERVED_CLASSES = [].concat(FAMILIES, _toConsumableArray(prefixes), ['2xs', 'xs', 'sm', 'lg', 'xl', '2xl', 'beat', 'border', 'fade', 'beat-fade', 'bounce', 'flip-both', 'flip-horizontal', 'flip-vertical', 'flip', 'fw', 'inverse', 'layers-counter', 'layers-text', 'layers', 'li', 'pull-left', 'pull-right', 'pulse', 'rotate-180', 'rotate-270', 'rotate-90', 'rotate-by', 'shake', 'spin-pulse', 'spin-reverse', 'spin', 'stack-1x', 'stack-2x', 'stack', 'ul', DUOTONE_CLASSES.GROUP, DUOTONE_CLASSES.SWAP_OPACITY, DUOTONE_CLASSES.PRIMARY, DUOTONE_CLASSES.SECONDARY]).concat(oneToTen.map(function (n) {
|
||||
return "".concat(n, "x");
|
||||
})).concat(oneToTwenty.map(function (n) {
|
||||
return "w-".concat(n);
|
||||
}));
|
||||
|
||||
function bunker(fn) {
|
||||
try {
|
||||
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
||||
args[_key - 1] = arguments[_key];
|
||||
}
|
||||
|
||||
fn.apply(void 0, args);
|
||||
} catch (e) {
|
||||
if (!PRODUCTION) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var w = WINDOW || {};
|
||||
if (!w[NAMESPACE_IDENTIFIER]) w[NAMESPACE_IDENTIFIER] = {};
|
||||
if (!w[NAMESPACE_IDENTIFIER].styles) w[NAMESPACE_IDENTIFIER].styles = {};
|
||||
if (!w[NAMESPACE_IDENTIFIER].hooks) w[NAMESPACE_IDENTIFIER].hooks = {};
|
||||
if (!w[NAMESPACE_IDENTIFIER].shims) w[NAMESPACE_IDENTIFIER].shims = [];
|
||||
var namespace = w[NAMESPACE_IDENTIFIER];
|
||||
|
||||
function normalizeIcons(icons) {
|
||||
return Object.keys(icons).reduce(function (acc, iconName) {
|
||||
var icon = icons[iconName];
|
||||
var expanded = !!icon.icon;
|
||||
|
||||
if (expanded) {
|
||||
acc[icon.iconName] = icon.icon;
|
||||
} else {
|
||||
acc[iconName] = icon;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
function defineIcons(prefix, icons) {
|
||||
var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
||||
var _params$skipHooks = params.skipHooks,
|
||||
skipHooks = _params$skipHooks === void 0 ? false : _params$skipHooks;
|
||||
var normalized = normalizeIcons(icons);
|
||||
|
||||
if (typeof namespace.hooks.addPack === 'function' && !skipHooks) {
|
||||
namespace.hooks.addPack(prefix, normalizeIcons(icons));
|
||||
} else {
|
||||
namespace.styles[prefix] = _objectSpread2(_objectSpread2({}, namespace.styles[prefix] || {}), normalized);
|
||||
}
|
||||
/**
|
||||
* Font Awesome 4 used the prefix of `fa` for all icons. With the introduction
|
||||
* of new styles we needed to differentiate between them. Prefix `fa` is now an alias
|
||||
* for `fas` so we'll ease the upgrade process for our users by automatically defining
|
||||
* this as well.
|
||||
*/
|
||||
|
||||
|
||||
if (prefix === 'fas') {
|
||||
defineIcons('fa', icons);
|
||||
}
|
||||
}
|
||||
|
||||
var icons = {
|
||||
"trash-can": [448, 512, [61460, "trash-alt"], "f2ed", "M170.5 51.6L151.5 80h145l-19-28.4c-1.5-2.2-4-3.6-6.7-3.6H177.1c-2.7 0-5.2 1.3-6.7 3.6zm147-26.6L354.2 80H368h48 8c13.3 0 24 10.7 24 24s-10.7 24-24 24h-8V432c0 44.2-35.8 80-80 80H112c-44.2 0-80-35.8-80-80V128H24c-13.3 0-24-10.7-24-24S10.7 80 24 80h8H80 93.8l36.7-55.1C140.9 9.4 158.4 0 177.1 0h93.7c18.7 0 36.2 9.4 46.6 24.9zM80 128V432c0 17.7 14.3 32 32 32H336c17.7 0 32-14.3 32-32V128H80zm80 64V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16zm80 0V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16zm80 0V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16z"],
|
||||
"message": [512, 512, ["comment-alt"], "f27a", "M160 368c26.5 0 48 21.5 48 48v16l72.5-54.4c8.3-6.2 18.4-9.6 28.8-9.6H448c8.8 0 16-7.2 16-16V64c0-8.8-7.2-16-16-16H64c-8.8 0-16 7.2-16 16V352c0 8.8 7.2 16 16 16h96zm48 124l-.2 .2-5.1 3.8-17.1 12.8c-4.8 3.6-11.3 4.2-16.8 1.5s-8.8-8.2-8.8-14.3V474.7v-6.4V468v-4V416H112 64c-35.3 0-64-28.7-64-64V64C0 28.7 28.7 0 64 0H448c35.3 0 64 28.7 64 64V352c0 35.3-28.7 64-64 64H309.3L208 492z"],
|
||||
"file-lines": [384, 512, [128441, 128462, 61686, "file-alt", "file-text"], "f15c", "M64 464c-8.8 0-16-7.2-16-16V64c0-8.8 7.2-16 16-16H224v80c0 17.7 14.3 32 32 32h80V448c0 8.8-7.2 16-16 16H64zM64 0C28.7 0 0 28.7 0 64V448c0 35.3 28.7 64 64 64H320c35.3 0 64-28.7 64-64V154.5c0-17-6.7-33.3-18.7-45.3L274.7 18.7C262.7 6.7 246.5 0 229.5 0H64zm56 256c-13.3 0-24 10.7-24 24s10.7 24 24 24H264c13.3 0 24-10.7 24-24s-10.7-24-24-24H120zm0 96c-13.3 0-24 10.7-24 24s10.7 24 24 24H264c13.3 0 24-10.7 24-24s-10.7-24-24-24H120z"],
|
||||
"calendar-days": [448, 512, ["calendar-alt"], "f073", "M152 24c0-13.3-10.7-24-24-24s-24 10.7-24 24V64H64C28.7 64 0 92.7 0 128v16 48V448c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V192 144 128c0-35.3-28.7-64-64-64H344V24c0-13.3-10.7-24-24-24s-24 10.7-24 24V64H152V24zM48 192h80v56H48V192zm0 104h80v64H48V296zm128 0h96v64H176V296zm144 0h80v64H320V296zm80-48H320V192h80v56zm0 160v40c0 8.8-7.2 16-16 16H320V408h80zm-128 0v56H176V408h96zm-144 0v56H64c-8.8 0-16-7.2-16-16V408h80zM272 248H176V192h96v56z"],
|
||||
"hand-point-right": [512, 512, [], "f0a4", "M448 128l-177.6 0c1 5.2 1.6 10.5 1.6 16l0 16 32 0 144 0c8.8 0 16-7.2 16-16s-7.2-16-16-16zM224 144c0-17.7-14.3-32-32-32c0 0 0 0 0 0l-24 0c-66.3 0-120 53.7-120 120l0 48c0 52.5 33.7 97.1 80.7 113.4c-.5-3.1-.7-6.2-.7-9.4c0-20 9.2-37.9 23.6-49.7c-4.9-9-7.6-19.4-7.6-30.3c0-15.1 5.3-29 14-40c-8.8-11-14-24.9-14-40l0-40c0-13.3 10.7-24 24-24s24 10.7 24 24l0 40c0 8.8 7.2 16 16 16s16-7.2 16-16l0-40 0-40zM192 64s0 0 0 0c18 0 34.6 6 48 16l208 0c35.3 0 64 28.7 64 64s-28.7 64-64 64l-82 0c1.3 5.1 2 10.5 2 16c0 25.3-14.7 47.2-36 57.6c2.6 7 4 14.5 4 22.4c0 20-9.2 37.9-23.6 49.7c4.9 9 7.6 19.4 7.6 30.3c0 35.3-28.7 64-64 64l-64 0-24 0C75.2 448 0 372.8 0 280l0-48C0 139.2 75.2 64 168 64l24 0zm64 336c8.8 0 16-7.2 16-16s-7.2-16-16-16l-48 0-16 0c-8.8 0-16 7.2-16 16s7.2 16 16 16l64 0zm16-176c0 5.5-.7 10.9-2 16l2 0 32 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-32 0 0 16zm-24 64l-40 0c-8.8 0-16 7.2-16 16s7.2 16 16 16l48 0 16 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-24 0z"],
|
||||
"face-smile-beam": [512, 512, [128522, "smile-beam"], "f5b8", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm177.6 62.1C192.8 334.5 218.8 352 256 352s63.2-17.5 78.4-33.9c9-9.7 24.2-10.4 33.9-1.4s10.4 24.2 1.4 33.9c-22 23.8-60 49.4-113.6 49.4s-91.7-25.5-113.6-49.4c-9-9.7-8.4-24.9 1.4-33.9s24.9-8.4 33.9 1.4zm40-89.3l0 0 0 0-.2-.2c-.2-.2-.4-.5-.7-.9c-.6-.8-1.6-2-2.8-3.4c-2.5-2.8-6-6.6-10.2-10.3c-8.8-7.8-18.8-14-27.7-14s-18.9 6.2-27.7 14c-4.2 3.7-7.7 7.5-10.2 10.3c-1.2 1.4-2.2 2.6-2.8 3.4c-.3 .4-.6 .7-.7 .9l-.2 .2 0 0 0 0 0 0c-2.1 2.8-5.7 3.9-8.9 2.8s-5.5-4.1-5.5-7.6c0-17.9 6.7-35.6 16.6-48.8c9.8-13 23.9-23.2 39.4-23.2s29.6 10.2 39.4 23.2c9.9 13.2 16.6 30.9 16.6 48.8c0 3.4-2.2 6.5-5.5 7.6s-6.9 0-8.9-2.8l0 0 0 0zm160 0l0 0-.2-.2c-.2-.2-.4-.5-.7-.9c-.6-.8-1.6-2-2.8-3.4c-2.5-2.8-6-6.6-10.2-10.3c-8.8-7.8-18.8-14-27.7-14s-18.9 6.2-27.7 14c-4.2 3.7-7.7 7.5-10.2 10.3c-1.2 1.4-2.2 2.6-2.8 3.4c-.3 .4-.6 .7-.7 .9l-.2 .2 0 0 0 0 0 0c-2.1 2.8-5.7 3.9-8.9 2.8s-5.5-4.1-5.5-7.6c0-17.9 6.7-35.6 16.6-48.8c9.8-13 23.9-23.2 39.4-23.2s29.6 10.2 39.4 23.2c9.9 13.2 16.6 30.9 16.6 48.8c0 3.4-2.2 6.5-5.5 7.6s-6.9 0-8.9-2.8l0 0 0 0 0 0z"],
|
||||
"face-grin-stars": [512, 512, [129321, "grin-stars"], "f587", "M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM183.2 132.6c-1.3-2.8-4.1-4.6-7.2-4.6s-5.9 1.8-7.2 4.6l-16.6 34.7-38.1 5c-3.1 .4-5.6 2.5-6.6 5.5s-.1 6.2 2.1 8.3l27.9 26.5-7 37.8c-.6 3 .7 6.1 3.2 7.9s5.8 2 8.5 .6L176 240.5l33.8 18.3c2.7 1.5 6 1.3 8.5-.6s3.7-4.9 3.2-7.9l-7-37.8L242.4 186c2.2-2.1 3.1-5.3 2.1-8.3s-3.5-5.1-6.6-5.5l-38.1-5-16.6-34.7zm160 0c-1.3-2.8-4.1-4.6-7.2-4.6s-5.9 1.8-7.2 4.6l-16.6 34.7-38.1 5c-3.1 .4-5.6 2.5-6.6 5.5s-.1 6.2 2.1 8.3l27.9 26.5-7 37.8c-.6 3 .7 6.1 3.2 7.9s5.8 2 8.5 .6L336 240.5l33.8 18.3c2.7 1.5 6 1.3 8.5-.6s3.7-4.9 3.2-7.9l-7-37.8L402.4 186c2.2-2.1 3.1-5.3 2.1-8.3s-3.5-5.1-6.6-5.5l-38.1-5-16.6-34.7zm6.3 175.8c-28.9 6.8-60.5 10.5-93.6 10.5s-64.7-3.7-93.6-10.5c-18.7-4.4-35.9 12-25.5 28.1c24.6 38.1 68.7 63.5 119.1 63.5s94.5-25.4 119.1-63.5c10.4-16.1-6.8-32.5-25.5-28.1z"],
|
||||
"address-book": [512, 512, [62138, "contact-book"], "f2b9", "M384 48c8.8 0 16 7.2 16 16V448c0 8.8-7.2 16-16 16H96c-8.8 0-16-7.2-16-16V64c0-8.8 7.2-16 16-16H384zM96 0C60.7 0 32 28.7 32 64V448c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64H96zM240 256a64 64 0 1 0 0-128 64 64 0 1 0 0 128zm-32 32c-44.2 0-80 35.8-80 80c0 8.8 7.2 16 16 16H336c8.8 0 16-7.2 16-16c0-44.2-35.8-80-80-80H208zM512 80c0-8.8-7.2-16-16-16s-16 7.2-16 16v64c0 8.8 7.2 16 16 16s16-7.2 16-16V80zM496 192c-8.8 0-16 7.2-16 16v64c0 8.8 7.2 16 16 16s16-7.2 16-16V208c0-8.8-7.2-16-16-16zm16 144c0-8.8-7.2-16-16-16s-16 7.2-16 16v64c0 8.8 7.2 16 16 16s16-7.2 16-16V336z"],
|
||||
"comments": [640, 512, [128490, 61670], "f086", "M88.2 309.1c9.8-18.3 6.8-40.8-7.5-55.8C59.4 230.9 48 204 48 176c0-63.5 63.8-128 160-128s160 64.5 160 128s-63.8 128-160 128c-13.1 0-25.8-1.3-37.8-3.6c-10.4-2-21.2-.6-30.7 4.2c-4.1 2.1-8.3 4.1-12.6 6c-16 7.2-32.9 13.5-49.9 18c2.8-4.6 5.4-9.1 7.9-13.6c1.1-1.9 2.2-3.9 3.2-5.9zM0 176c0 41.8 17.2 80.1 45.9 110.3c-.9 1.7-1.9 3.5-2.8 5.1c-10.3 18.4-22.3 36.5-36.6 52.1c-6.6 7-8.3 17.2-4.6 25.9C5.8 378.3 14.4 384 24 384c43 0 86.5-13.3 122.7-29.7c4.8-2.2 9.6-4.5 14.2-6.8c15.1 3 30.9 4.5 47.1 4.5c114.9 0 208-78.8 208-176S322.9 0 208 0S0 78.8 0 176zM432 480c16.2 0 31.9-1.6 47.1-4.5c4.6 2.3 9.4 4.6 14.2 6.8C529.5 498.7 573 512 616 512c9.6 0 18.2-5.7 22-14.5c3.8-8.8 2-19-4.6-25.9c-14.2-15.6-26.2-33.7-36.6-52.1c-.9-1.7-1.9-3.4-2.8-5.1C622.8 384.1 640 345.8 640 304c0-94.4-87.9-171.5-198.2-175.8c4.1 15.2 6.2 31.2 6.2 47.8l0 .6c87.2 6.7 144 67.5 144 127.4c0 28-11.4 54.9-32.7 77.2c-14.3 15-17.3 37.6-7.5 55.8c1.1 2 2.2 4 3.2 5.9c2.5 4.5 5.2 9 7.9 13.6c-17-4.5-33.9-10.7-49.9-18c-4.3-1.9-8.5-3.9-12.6-6c-9.5-4.8-20.3-6.2-30.7-4.2c-12.1 2.4-24.7 3.6-37.8 3.6c-61.7 0-110-26.5-136.8-62.3c-16 5.4-32.8 9.4-50 11.8C279 439.8 350 480 432 480z"],
|
||||
"paste": [512, 512, ["file-clipboard"], "f0ea", "M104.6 48H64C28.7 48 0 76.7 0 112V384c0 35.3 28.7 64 64 64h96V400H64c-8.8 0-16-7.2-16-16V112c0-8.8 7.2-16 16-16H80c0 17.7 14.3 32 32 32h72.4C202 108.4 227.6 96 256 96h62c-7.1-27.6-32.2-48-62-48H215.4C211.6 20.9 188.2 0 160 0s-51.6 20.9-55.4 48zM144 56a16 16 0 1 1 32 0 16 16 0 1 1 -32 0zM448 464H256c-8.8 0-16-7.2-16-16V192c0-8.8 7.2-16 16-16l140.1 0L464 243.9V448c0 8.8-7.2 16-16 16zM256 512H448c35.3 0 64-28.7 64-64V243.9c0-12.7-5.1-24.9-14.1-33.9l-67.9-67.9c-9-9-21.2-14.1-33.9-14.1H256c-35.3 0-64 28.7-64 64V448c0 35.3 28.7 64 64 64z"],
|
||||
"face-grin-tongue-squint": [512, 512, [128541, "grin-tongue-squint"], "f58a", "M464 256c0-114.9-93.1-208-208-208S48 141.1 48 256c0 81.7 47.1 152.4 115.7 186.4c-2.4-8.4-3.7-17.3-3.7-26.4V392.7c-24-17.5-43.1-41.4-54.8-69.2c-5-11.8 7-22.5 19.3-18.7c39.7 12.2 84.5 19 131.8 19s92.1-6.8 131.8-19c12.3-3.8 24.3 6.9 19.3 18.7c-11.8 28-31.1 52-55.4 69.6V416c0 9.2-1.3 18-3.7 26.4C416.9 408.4 464 337.7 464 256zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm116-98.9c0-9 9.6-14.7 17.5-10.5l89.9 47.9c10.7 5.7 10.7 21.1 0 26.8l-89.9 47.9c-7.9 4.2-17.5-1.5-17.5-10.5c0-2.8 1-5.5 2.8-7.6l36-43.2-36-43.2c-1.8-2.1-2.8-4.8-2.8-7.6zm262.5-10.5c7.9-4.2 17.5 1.5 17.5 10.5c0 2.8-1 5.5-2.8 7.6l-36 43.2 36 43.2c1.8 2.1 2.8 4.8 2.8 7.6c0 9-9.6 14.7-17.5 10.5l-89.9-47.9c-10.7-5.7-10.7-21.1 0-26.8l89.9-47.9zM320 416V378.6c0-14.7-11.9-26.6-26.6-26.6h-2c-11.3 0-21.1 7.9-23.6 18.9c-2.8 12.6-20.8 12.6-23.6 0c-2.5-11.1-12.3-18.9-23.6-18.9h-2c-14.7 0-26.6 11.9-26.6 26.6V416c0 35.3 28.7 64 64 64s64-28.7 64-64z"],
|
||||
"face-flushed": [512, 512, [128563, "flushed"], "f579", "M464 256A208 208 0 1 1 48 256a208 208 0 1 1 416 0zM256 0a256 256 0 1 0 0 512A256 256 0 1 0 256 0zM160.4 248a24 24 0 1 0 0-48 24 24 0 1 0 0 48zm216-24a24 24 0 1 0 -48 0 24 24 0 1 0 48 0zM192 336c-13.3 0-24 10.7-24 24s10.7 24 24 24H320c13.3 0 24-10.7 24-24s-10.7-24-24-24H192zM160 176a48 48 0 1 1 0 96 48 48 0 1 1 0-96zm0 128a80 80 0 1 0 0-160 80 80 0 1 0 0 160zm144-80a48 48 0 1 1 96 0 48 48 0 1 1 -96 0zm128 0a80 80 0 1 0 -160 0 80 80 0 1 0 160 0z"],
|
||||
"square-caret-right": [448, 512, ["caret-square-right"], "f152", "M400 96c0-8.8-7.2-16-16-16L64 80c-8.8 0-16 7.2-16 16l0 320c0 8.8 7.2 16 16 16l320 0c8.8 0 16-7.2 16-16l0-320zM384 32c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96C0 60.7 28.7 32 64 32l320 0zM320 256c0 6.7-2.8 13-7.7 17.6l-112 104c-7 6.5-17.2 8.2-25.9 4.4s-14.4-12.5-14.4-22l0-208c0-9.5 5.7-18.2 14.4-22s18.9-2.1 25.9 4.4l112 104c4.9 4.5 7.7 10.9 7.7 17.6z"],
|
||||
"square-minus": [448, 512, [61767, "minus-square"], "f146", "M64 80c-8.8 0-16 7.2-16 16V416c0 8.8 7.2 16 16 16H384c8.8 0 16-7.2 16-16V96c0-8.8-7.2-16-16-16H64zM0 96C0 60.7 28.7 32 64 32H384c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V96zM152 232H296c13.3 0 24 10.7 24 24s-10.7 24-24 24H152c-13.3 0-24-10.7-24-24s10.7-24 24-24z"],
|
||||
"compass": [512, 512, [129517], "f14e", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm306.7 69.1L162.4 380.6c-19.4 7.5-38.5-11.6-31-31l55.5-144.3c3.3-8.5 9.9-15.1 18.4-18.4l144.3-55.5c19.4-7.5 38.5 11.6 31 31L325.1 306.7c-3.2 8.5-9.9 15.1-18.4 18.4zM288 256a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"],
|
||||
"square-caret-down": [448, 512, ["caret-square-down"], "f150", "M384 432c8.8 0 16-7.2 16-16l0-320c0-8.8-7.2-16-16-16L64 80c-8.8 0-16 7.2-16 16l0 320c0 8.8 7.2 16 16 16l320 0zm64-16c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96C0 60.7 28.7 32 64 32l320 0c35.3 0 64 28.7 64 64l0 320zM224 352c-6.7 0-13-2.8-17.6-7.7l-104-112c-6.5-7-8.2-17.2-4.4-25.9s12.5-14.4 22-14.4l208 0c9.5 0 18.2 5.7 22 14.4s2.1 18.9-4.4 25.9l-104 112c-4.5 4.9-10.9 7.7-17.6 7.7z"],
|
||||
"face-kiss-beam": [512, 512, [128537, "kiss-beam"], "f597", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm304.7 41.7c4.3 5.1 7.3 11.4 7.3 18.3s-3.1 13.2-7.3 18.3c-4.3 5.2-10.1 9.7-16.7 13.4c-2.7 1.5-5.7 3-8.7 4.3c3.1 1.3 6 2.7 8.7 4.3c6.6 3.7 12.5 8.2 16.7 13.4c4.3 5.1 7.3 11.4 7.3 18.3s-3.1 13.2-7.3 18.3c-4.3 5.2-10.1 9.7-16.7 13.4C274.7 427.1 257.4 432 240 432c-3.6 0-6.8-2.5-7.7-6s.6-7.2 3.8-9l0 0 0 0 0 0 0 0 .2-.1c.2-.1 .5-.3 .9-.5c.8-.5 2-1.2 3.4-2.1c2.8-1.9 6.5-4.5 10.2-7.6c3.7-3.1 7.2-6.6 9.6-10.1c2.5-3.5 3.5-6.4 3.5-8.6s-1-5-3.5-8.6c-2.5-3.5-5.9-6.9-9.6-10.1c-3.7-3.1-7.4-5.7-10.2-7.6c-1.4-.9-2.6-1.6-3.4-2.1c-.4-.2-.7-.4-.9-.5l-.2-.1 0 0 0 0 0 0c-2.5-1.4-4.1-4.1-4.1-7s1.6-5.6 4.1-7l0 0 0 0 0 0 0 0 0 0 .2-.1c.2-.1 .5-.3 .9-.5c.8-.5 2-1.2 3.4-2.1c2.8-1.9 6.5-4.5 10.2-7.6c3.7-3.1 7.2-6.6 9.6-10.1c2.5-3.5 3.5-6.4 3.5-8.6s-1-5-3.5-8.6c-2.5-3.5-5.9-6.9-9.6-10.1c-3.7-3.1-7.4-5.7-10.2-7.6c-1.4-.9-2.6-1.6-3.4-2.1c-.4-.2-.7-.4-.9-.5l-.2-.1 0 0 0 0 0 0c-3.2-1.8-4.7-5.5-3.8-9s4.1-6 7.7-6c17.4 0 34.7 4.9 47.9 12.3c6.6 3.7 12.5 8.2 16.7 13.4zm-87.1-68.9l0 0 0 0-.2-.2c-.2-.2-.4-.5-.7-.9c-.6-.8-1.6-2-2.8-3.4c-2.5-2.8-6-6.6-10.2-10.3c-8.8-7.8-18.8-14-27.7-14s-18.9 6.2-27.7 14c-4.2 3.7-7.7 7.5-10.2 10.3c-1.2 1.4-2.2 2.6-2.8 3.4c-.3 .4-.6 .7-.7 .9l-.2 .2 0 0 0 0 0 0c-2.1 2.8-5.7 3.9-8.9 2.8s-5.5-4.1-5.5-7.6c0-17.9 6.7-35.6 16.6-48.8c9.8-13 23.9-23.2 39.4-23.2s29.6 10.2 39.4 23.2c9.9 13.2 16.6 30.9 16.6 48.8c0 3.4-2.2 6.5-5.5 7.6s-6.9 0-8.9-2.8l0 0 0 0zm160 0l0 0-.2-.2c-.2-.2-.4-.5-.7-.9c-.6-.8-1.6-2-2.8-3.4c-2.5-2.8-6-6.6-10.2-10.3c-8.8-7.8-18.8-14-27.7-14s-18.9 6.2-27.7 14c-4.2 3.7-7.7 7.5-10.2 10.3c-1.2 1.4-2.2 2.6-2.8 3.4c-.3 .4-.6 .7-.7 .9l-.2 .2 0 0 0 0 0 0c-2.1 2.8-5.7 3.9-8.9 2.8s-5.5-4.1-5.5-7.6c0-17.9 6.7-35.6 16.6-48.8c9.8-13 23.9-23.2 39.4-23.2s29.6 10.2 39.4 23.2c9.9 13.2 16.6 30.9 16.6 48.8c0 3.4-2.2 6.5-5.5 7.6s-6.9 0-8.9-2.8l0 0 0 0 0 0z"],
|
||||
"lightbulb": [384, 512, [128161], "f0eb", "M297.2 248.9C311.6 228.3 320 203.2 320 176c0-70.7-57.3-128-128-128S64 105.3 64 176c0 27.2 8.4 52.3 22.8 72.9c3.7 5.3 8.1 11.3 12.8 17.7l0 0c12.9 17.7 28.3 38.9 39.8 59.8c10.4 19 15.7 38.8 18.3 57.5H109c-2.2-12-5.9-23.7-11.8-34.5c-9.9-18-22.2-34.9-34.5-51.8l0 0 0 0c-5.2-7.1-10.4-14.2-15.4-21.4C27.6 247.9 16 213.3 16 176C16 78.8 94.8 0 192 0s176 78.8 176 176c0 37.3-11.6 71.9-31.4 100.3c-5 7.2-10.2 14.3-15.4 21.4l0 0 0 0c-12.3 16.8-24.6 33.7-34.5 51.8c-5.9 10.8-9.6 22.5-11.8 34.5H226.4c2.6-18.7 7.9-38.6 18.3-57.5c11.5-20.9 26.9-42.1 39.8-59.8l0 0 0 0 0 0c4.7-6.4 9-12.4 12.7-17.7zM192 128c-26.5 0-48 21.5-48 48c0 8.8-7.2 16-16 16s-16-7.2-16-16c0-44.2 35.8-80 80-80c8.8 0 16 7.2 16 16s-7.2 16-16 16zm0 384c-44.2 0-80-35.8-80-80V416H272v16c0 44.2-35.8 80-80 80z"],
|
||||
"flag": [448, 512, [127988, 61725], "f024", "M48 24C48 10.7 37.3 0 24 0S0 10.7 0 24V64 350.5 400v88c0 13.3 10.7 24 24 24s24-10.7 24-24V388l80.3-20.1c41.1-10.3 84.6-5.5 122.5 13.4c44.2 22.1 95.5 24.8 141.7 7.4l34.7-13c12.5-4.7 20.8-16.6 20.8-30V66.1c0-23-24.2-38-44.8-27.7l-9.6 4.8c-46.3 23.2-100.8 23.2-147.1 0c-35.1-17.6-75.4-22-113.5-12.5L48 52V24zm0 77.5l96.6-24.2c27-6.7 55.5-3.6 80.4 8.8c54.9 27.4 118.7 29.7 175 6.8V334.7l-24.4 9.1c-33.7 12.6-71.2 10.7-103.4-5.4c-48.2-24.1-103.3-30.1-155.6-17.1L48 338.5v-237z"],
|
||||
"square-check": [448, 512, [9745, 9989, 61510, "check-square"], "f14a", "M64 80c-8.8 0-16 7.2-16 16V416c0 8.8 7.2 16 16 16H384c8.8 0 16-7.2 16-16V96c0-8.8-7.2-16-16-16H64zM0 96C0 60.7 28.7 32 64 32H384c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V96zM337 209L209 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L303 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"],
|
||||
"circle-dot": [512, 512, [128280, "dot-circle"], "f192", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm256-96a96 96 0 1 1 0 192 96 96 0 1 1 0-192z"],
|
||||
"face-dizzy": [512, 512, ["dizzy"], "f567", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm256 32a64 64 0 1 1 0 128 64 64 0 1 1 0-128zM103 135c9.4-9.4 24.6-9.4 33.9 0l23 23 23-23c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-23 23 23 23c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-23-23-23 23c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l23-23-23-23c-9.4-9.4-9.4-24.6 0-33.9zm192 0c9.4-9.4 24.6-9.4 33.9 0l23 23 23-23c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-23 23 23 23c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-23-23-23 23c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l23-23-23-23c-9.4-9.4-9.4-24.6 0-33.9z"],
|
||||
"futbol": [512, 512, [9917, "futbol-ball", "soccer-ball"], "f1e3", "M435.4 361.3l-89.7-6c-5.2-.3-10.3 1.1-14.5 4.2s-7.2 7.4-8.4 12.5l-22 87.2c-14.4 3.2-29.4 4.8-44.8 4.8s-30.3-1.7-44.8-4.8l-22-87.2c-1.3-5-4.3-9.4-8.4-12.5s-9.3-4.5-14.5-4.2l-89.7 6C61.7 335.9 51.9 307 49 276.2L125 228.3c4.4-2.8 7.6-7 9.2-11.9s1.4-10.2-.5-15L100.4 118c19.9-22.4 44.6-40.5 72.4-52.7l69.1 57.6c4 3.3 9 5.1 14.1 5.1s10.2-1.8 14.1-5.1l69.1-57.6c27.8 12.2 52.5 30.3 72.4 52.7l-33.4 83.4c-1.9 4.8-2.1 10.1-.5 15s4.9 9.1 9.2 11.9L463 276.2c-3 30.8-12.7 59.7-27.6 85.1zM256 48l.9 0h-1.8l.9 0zM56.7 196.2c.9-3 1.9-6.1 2.9-9.1l-2.9 9.1zM132 423l3.8 2.7c-1.3-.9-2.5-1.8-3.8-2.7zm248.1-.1c-1.3 1-2.7 2-4 2.9l4-2.9zm75.2-226.6l-3-9.2c1.1 3 2.1 6.1 3 9.2zM256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zm14.1-325.7c-8.4-6.1-19.8-6.1-28.2 0L194 221c-8.4 6.1-11.9 16.9-8.7 26.8l18.3 56.3c3.2 9.9 12.4 16.6 22.8 16.6h59.2c10.4 0 19.6-6.7 22.8-16.6l18.3-56.3c3.2-9.9-.3-20.7-8.7-26.8l-47.9-34.8z"],
|
||||
"pen-to-square": [512, 512, ["edit"], "f044", "M441 58.9L453.1 71c9.4 9.4 9.4 24.6 0 33.9L424 134.1 377.9 88 407 58.9c9.4-9.4 24.6-9.4 33.9 0zM209.8 256.2L344 121.9 390.1 168 255.8 302.2c-2.9 2.9-6.5 5-10.4 6.1l-58.5 16.7 16.7-58.5c1.1-3.9 3.2-7.5 6.1-10.4zM373.1 25L175.8 222.2c-8.7 8.7-15 19.4-18.3 31.1l-28.6 100c-2.4 8.4-.1 17.4 6.1 23.6s15.2 8.5 23.6 6.1l100-28.6c11.8-3.4 22.5-9.7 31.1-18.3L487 138.9c28.1-28.1 28.1-73.7 0-101.8L474.9 25C446.8-3.1 401.2-3.1 373.1 25zM88 64C39.4 64 0 103.4 0 152V424c0 48.6 39.4 88 88 88H360c48.6 0 88-39.4 88-88V312c0-13.3-10.7-24-24-24s-24 10.7-24 24V424c0 22.1-17.9 40-40 40H88c-22.1 0-40-17.9-40-40V152c0-22.1 17.9-40 40-40H200c13.3 0 24-10.7 24-24s-10.7-24-24-24H88z"],
|
||||
"hourglass-half": [384, 512, ["hourglass-2"], "f252", "M0 24C0 10.7 10.7 0 24 0H360c13.3 0 24 10.7 24 24s-10.7 24-24 24h-8V67c0 40.3-16 79-44.5 107.5L225.9 256l81.5 81.5C336 366 352 404.7 352 445v19h8c13.3 0 24 10.7 24 24s-10.7 24-24 24H24c-13.3 0-24-10.7-24-24s10.7-24 24-24h8V445c0-40.3 16-79 44.5-107.5L158.1 256 76.5 174.5C48 146 32 107.3 32 67V48H24C10.7 48 0 37.3 0 24zM110.5 371.5c-3.9 3.9-7.5 8.1-10.7 12.5H284.2c-3.2-4.4-6.8-8.6-10.7-12.5L192 289.9l-81.5 81.5zM284.2 128C297 110.4 304 89 304 67V48H80V67c0 22.1 7 43.4 19.8 61H284.2z"],
|
||||
"eye-slash": [640, 512, [], "f070", "M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zm151 118.3C226 97.7 269.5 80 320 80c65.2 0 118.8 29.6 159.9 67.7C518.4 183.5 545 226 558.6 256c-12.6 28-36.6 66.8-70.9 100.9l-53.8-42.2c9.1-17.6 14.2-37.5 14.2-58.7c0-70.7-57.3-128-128-128c-32.2 0-61.7 11.9-84.2 31.5l-46.1-36.1zM394.9 284.2l-81.5-63.9c4.2-8.5 6.6-18.2 6.6-28.3c0-5.5-.7-10.9-2-16c.7 0 1.3 0 2 0c44.2 0 80 35.8 80 80c0 9.9-1.8 19.4-5.1 28.2zm9.4 130.3C378.8 425.4 350.7 432 320 432c-65.2 0-118.8-29.6-159.9-67.7C121.6 328.5 95 286 81.4 256c8.3-18.4 21.5-41.5 39.4-64.8L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5l-41.9-33zM192 256c0 70.7 57.3 128 128 128c13.3 0 26.1-2 38.2-5.8L302 334c-23.5-5.4-43.1-21.2-53.7-42.3l-56.1-44.2c-.2 2.8-.3 5.6-.3 8.5z"],
|
||||
"hand": [512, 512, [129306, 9995, "hand-paper"], "f256", "M256 0c-25.3 0-47.2 14.7-57.6 36c-7-2.6-14.5-4-22.4-4c-35.3 0-64 28.7-64 64V261.5l-2.7-2.7c-25-25-65.5-25-90.5 0s-25 65.5 0 90.5L106.5 437c48 48 113.1 75 181 75H296h8c1.5 0 3-.1 4.5-.4c91.7-6.2 165-79.4 171.1-171.1c.3-1.5 .4-3 .4-4.5V160c0-35.3-28.7-64-64-64c-5.5 0-10.9 .7-16 2V96c0-35.3-28.7-64-64-64c-7.9 0-15.4 1.4-22.4 4C303.2 14.7 281.3 0 256 0zM240 96.1c0 0 0-.1 0-.1V64c0-8.8 7.2-16 16-16s16 7.2 16 16V95.9c0 0 0 .1 0 .1V232c0 13.3 10.7 24 24 24s24-10.7 24-24V96c0 0 0 0 0-.1c0-8.8 7.2-16 16-16s16 7.2 16 16v55.9c0 0 0 .1 0 .1v80c0 13.3 10.7 24 24 24s24-10.7 24-24V160.1c0 0 0-.1 0-.1c0-8.8 7.2-16 16-16s16 7.2 16 16V332.9c-.1 .6-.1 1.3-.2 1.9c-3.4 69.7-59.3 125.6-129 129c-.6 0-1.3 .1-1.9 .2H296h-8.5c-55.2 0-108.1-21.9-147.1-60.9L52.7 315.3c-6.2-6.2-6.2-16.4 0-22.6s16.4-6.2 22.6 0L119 336.4c6.9 6.9 17.2 8.9 26.2 5.2s14.8-12.5 14.8-22.2V96c0-8.8 7.2-16 16-16c8.8 0 16 7.1 16 15.9V232c0 13.3 10.7 24 24 24s24-10.7 24-24V96.1z"],
|
||||
"hand-spock": [576, 512, [128406], "f259", "M221.7 25.3L215.6 2.1l6.2 23.2zm48.9 28.4l23.2-6.2v0l-23.2 6.2zM193.3 74.3l-23.2 6.2 0 0 23.2-6.2zm46.5 175.3l-22.1 9.3c4.9 11.6 17.9 17.5 29.9 13.4s18.7-16.7 15.4-28.9l-23.2 6.2zm-51-121.1l-22.1 9.3v0l22.1-9.3zm-52.4-21.3l9.3 22.1h0l-9.3-22.1zm-21.3 52.4L93 168.8h0l22.1-9.3zm5.4 144.9l14.7-18.9h0l-14.7 18.9zm-56.1 7l18.9 14.7 0 0L64.4 311.4zm7 56.1L56.7 386.5h0l14.7-18.9zm92 71.6l-14.7 18.9 14.7-18.9zm300.1-48.5l23.3 5.8-23.3-5.8zm55.2-220.9l23.3 5.8-23.3-5.8zm-29.1-48.5l5.8-23.3-5.8 23.3zm-48.5 29.1l23.3 5.8v0l-23.3-5.8zM415 255l23.3 5.8 0 0L415 255zm-2.6-.5l23.6 4.2 0 0-23.6-4.2zM439.4 103l23.6 4.2v0L439.4 103zM407 56.6l-4.2 23.6L407 56.6zM360.6 89L337 84.8 360.6 89zM331.5 252.6l-23.6-4.2 0 0 23.6 4.2zm-8 .3l23.2-6.2 0 0-23.2 6.2zM336 488l.5-24-.5 24zm-157-138L193.8 331l-14.7 18.9zM227.9 48.5c8.5-2.3 17.3 2.8 19.6 11.4l46.4-12.3c-9.1-34.2-44.1-54.5-78.3-45.4l12.3 46.4zM216.5 68.1c-2.3-8.5 2.8-17.3 11.4-19.6L215.6 2.1c-34.2 9.1-54.5 44.1-45.4 78.3l46.4-12.3zM263 243.4L216.5 68.1 170.1 80.4l46.5 175.3L263 243.4zM166.7 137.8l51 121.1L262 240.2 211 119.2l-44.2 18.6zm-21-8.5c8.1-3.4 17.5 .4 21 8.5L211 119.2C197.3 86.6 159.7 71.3 127.2 85l18.6 44.2zm-8.5 21c-3.4-8.1 .4-17.5 8.5-21L127.2 85C94.6 98.7 79.3 136.3 93 168.8l44.2-18.6zm76.2 181l-76.2-181L93 168.8l76.2 181 44.2-18.6zm-107.6-7.8l58.5 45.5L193.8 331l-58.5-45.5-29.5 37.9zm-22.5 2.8c5.4-7 15.5-8.2 22.5-2.8l29.5-37.9c-27.9-21.7-68.1-16.7-89.8 11.2l37.9 29.5zm2.8 22.5c-7-5.4-8.2-15.5-2.8-22.5L45.5 296.7c-21.7 27.9-16.7 68.1 11.2 89.8l29.5-37.9zm92 71.6l-92-71.6L56.7 386.5l92 71.6 29.5-37.9zM305.9 464c-46.3 0-91.2-15.4-127.7-43.8l-29.5 37.9C193.6 493 248.9 512 305.9 512V464zm30.1 0H305.9v48H336V464zm2.8 0c-.8 0-1.5 0-2.3 0l-1 48c1.1 0 2.2 0 3.3 0V464zm101.5-79.2C428.7 431.3 386.8 464 338.8 464v48c70 0 131.1-47.7 148-115.6l-46.6-11.6zm55.2-220.9L440.3 384.8l46.6 11.6 55.2-220.9-46.6-11.6zm-11.6-19.4c8.6 2.1 13.8 10.8 11.6 19.4l46.6 11.6c8.6-34.3-12.3-69-46.6-77.6l-11.6 46.6zm-19.4 11.6c2.1-8.6 10.8-13.8 19.4-11.6l11.6-46.6c-34.3-8.6-69 12.3-77.6 46.6l46.6 11.6zM438.3 260.8l26.2-104.7-46.6-11.6L391.7 249.2l46.6 11.6zM413.7 280c11.6 0 21.7-7.9 24.6-19.2l-46.6-11.6c2.5-10.1 11.6-17.2 22-17.2v48zm-24.9-29.7c-2.8 15.5 9.2 29.7 24.9 29.7V232c14.1 0 24.8 12.8 22.3 26.7l-47.3-8.4zM415.8 98.8L388.8 250.3l47.3 8.4L463 107.2l-47.3-8.4zm-13-18.6c8.7 1.5 14.5 9.9 13 18.6l47.3 8.4c6.2-34.8-17-68-51.8-74.2l-8.4 47.3zm-18.6 13c1.5-8.7 9.9-14.5 18.6-13L411.2 33c-34.8-6.2-68 17-74.2 51.8l47.3 8.4zM355.2 256.8L384.2 93.2 337 84.8 307.9 248.4l47.3 8.4zM327.5 280c13.6 0 25.3-9.8 27.7-23.2l-47.3-8.4c1.7-9.5 9.9-16.4 19.6-16.4v48zm-27.2-20.9c3.3 12.3 14.4 20.9 27.2 20.9V232c9 0 16.9 6.1 19.2 14.8l-46.4 12.3zM247.5 59.9l52.8 199.2 46.4-12.3L293.9 47.6 247.5 59.9zM360 488c0 13.5-11.1 24.3-24.5 24l1-48c-13.5-.3-24.5 10.5-24.5 24h48zm-24 24c13.3 0 24-10.8 24-24H312c0-13.2 10.7-24 24-24v48zM169.2 349.8c-6.4-15.2 11.6-29 24.6-18.8l-29.5 37.9c26 20.2 61.9-7.3 49.1-37.7l-44.2 18.6z"],
|
||||
"face-kiss": [512, 512, [128535, "kiss"], "f596", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm304.7 25.7c4.3 5.1 7.3 11.4 7.3 18.3s-3.1 13.2-7.3 18.3c-4.3 5.2-10.1 9.7-16.7 13.4c-2.7 1.5-5.7 3-8.7 4.3c3.1 1.3 6 2.7 8.7 4.3c6.6 3.7 12.5 8.2 16.7 13.4c4.3 5.1 7.3 11.4 7.3 18.3s-3.1 13.2-7.3 18.3c-4.3 5.2-10.1 9.7-16.7 13.4C274.7 411.1 257.4 416 240 416c-3.6 0-6.8-2.5-7.7-6s.6-7.2 3.8-9l0 0 0 0 0 0 0 0 .2-.1c.2-.1 .5-.3 .9-.5c.8-.5 2-1.2 3.4-2.1c2.8-1.9 6.5-4.5 10.2-7.6c3.7-3.1 7.2-6.6 9.6-10.1c2.5-3.5 3.5-6.4 3.5-8.6s-1-5-3.5-8.6c-2.5-3.5-5.9-6.9-9.6-10.1c-3.7-3.1-7.4-5.7-10.2-7.6c-1.4-.9-2.6-1.6-3.4-2.1l-.8-.5-.1-.1-.2-.1 0 0 0 0 0 0c-2.5-1.4-4.1-4.1-4.1-7s1.6-5.6 4.1-7l0 0 0 0 0 0 0 0 0 0 .2-.1c.2-.1 .5-.3 .9-.5c.8-.5 2-1.2 3.4-2.1c2.8-1.9 6.5-4.5 10.2-7.6c3.7-3.1 7.2-6.6 9.6-10.1c2.5-3.5 3.5-6.4 3.5-8.6s-1-5-3.5-8.6c-2.5-3.5-5.9-6.9-9.6-10.1c-3.7-3.1-7.4-5.7-10.2-7.6c-1.4-.9-2.6-1.6-3.4-2.1c-.4-.2-.7-.4-.9-.5l-.2-.1 0 0 0 0 0 0c-3.2-1.8-4.7-5.5-3.8-9s4.1-6 7.7-6c17.4 0 34.7 4.9 47.9 12.3c6.6 3.7 12.5 8.2 16.7 13.4zM144.4 208a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zm192-32a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"],
|
||||
"face-grin-tongue": [512, 512, [128539, "grin-tongue"], "f589", "M464 256c0-114.9-93.1-208-208-208S48 141.1 48 256c0 81.7 47.1 152.4 115.7 186.4c-2.4-8.4-3.7-17.3-3.7-26.4V363.6c-8.9-8-16.7-17.1-23.1-27.1c-10.4-16.1 6.8-32.5 25.5-28.1c28.9 6.8 60.5 10.5 93.6 10.5s64.7-3.7 93.6-10.5c18.7-4.4 35.9 12 25.5 28.1c-6.4 9.9-14.2 19-23 27V416c0 9.2-1.3 18-3.7 26.4C416.9 408.4 464 337.7 464 256zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm176.4-80a32 32 0 1 1 0 64 32 32 0 1 1 0-64zm128 32a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zM320 416V378.6c0-14.7-11.9-26.6-26.6-26.6h-2c-11.3 0-21.1 7.9-23.6 18.9c-2.8 12.6-20.8 12.6-23.6 0c-2.5-11.1-12.3-18.9-23.6-18.9h-2c-14.7 0-26.6 11.9-26.6 26.6V416c0 35.3 28.7 64 64 64s64-28.7 64-64z"],
|
||||
"chess-bishop": [320, 512, [9821], "f43a", "M104 0C90.7 0 80 10.7 80 24c0 11.2 7.6 20.6 18 23.2c-7.8 8-16.1 17-24.4 27C38.2 116.7 0 178.8 0 250.9c0 44.8 24.6 72.2 48 87.8V352H96V325c0-9-5-17.2-13-21.3c-18-9.3-35-24.7-35-52.7c0-55.5 29.8-106.8 62.4-145.9c16-19.2 32.1-34.8 44.2-45.5c1.9-1.7 3.7-3.2 5.3-4.6c1.7 1.4 3.4 3 5.3 4.6c12.1 10.7 28.2 26.3 44.2 45.5c5.3 6.3 10.5 13 15.5 20L159 191c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l57.8-57.8c12.8 25.9 21.2 54.3 21.2 83.8c0 28-17 43.4-35 52.7c-8 4.1-13 12.3-13 21.3v27h48V338.7c23.4-15.6 48-42.9 48-87.8c0-72.1-38.2-134.2-73.6-176.7c-8.3-9.9-16.6-19-24.4-27c10.3-2.7 18-12.1 18-23.2c0-13.3-10.7-24-24-24H160 104zM52.7 464l16.6-32H250.8l16.6 32H52.7zm207.9-80H59.5c-12 0-22.9 6.7-28.4 17.3L4.6 452.5c-3 5.8-4.6 12.2-4.6 18.7C0 493.8 18.2 512 40.8 512H279.2c22.5 0 40.8-18.2 40.8-40.8c0-6.5-1.6-12.9-4.6-18.7l-26.5-51.2c-5.5-10.6-16.5-17.3-28.4-17.3z"],
|
||||
"face-grin-wink": [512, 512, ["grin-wink"], "f58c", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm349.5 52.4c18.7-4.4 35.9 12 25.5 28.1C350.4 374.6 306.3 400 255.9 400s-94.5-25.4-119.1-63.5c-10.4-16.1 6.8-32.5 25.5-28.1c28.9 6.8 60.5 10.5 93.6 10.5s64.7-3.7 93.6-10.5zM144.4 208a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zm165.8 21.7c-7.6 8.1-20.2 8.5-28.3 .9s-8.5-20.2-.9-28.3c14.5-15.5 35.2-22.3 54.6-22.3s40.1 6.8 54.6 22.3c7.6 8.1 7.1 20.7-.9 28.3s-20.7 7.1-28.3-.9c-5.5-5.8-14.8-9.7-25.4-9.7s-19.9 3.8-25.4 9.7z"],
|
||||
"face-grin-wide": [512, 512, [128515, "grin-alt"], "f581", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm349.5 52.4c18.7-4.4 35.9 12 25.5 28.1C350.4 374.6 306.3 400 255.9 400s-94.5-25.4-119.1-63.5c-10.4-16.1 6.8-32.5 25.5-28.1c28.9 6.8 60.5 10.5 93.6 10.5s64.7-3.7 93.6-10.5zM224 192c0 35.3-14.3 64-32 64s-32-28.7-32-64s14.3-64 32-64s32 28.7 32 64zm96 64c-17.7 0-32-28.7-32-64s14.3-64 32-64s32 28.7 32 64s-14.3 64-32 64z"],
|
||||
"face-frown-open": [512, 512, [128550, "frown-open"], "f57a", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zM182.4 382.5c-12.4 5.2-26.5-4.1-21.1-16.4c16-36.6 52.4-62.1 94.8-62.1s78.8 25.6 94.8 62.1c5.4 12.3-8.7 21.6-21.1 16.4c-22.4-9.5-47.4-14.8-73.7-14.8s-51.3 5.3-73.7 14.8zM144.4 208a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zm192-32a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"],
|
||||
"hand-point-up": [384, 512, [9757], "f0a6", "M64 64V241.6c5.2-1 10.5-1.6 16-1.6H96V208 64c0-8.8-7.2-16-16-16s-16 7.2-16 16zM80 288c-17.7 0-32 14.3-32 32c0 0 0 0 0 0v24c0 66.3 53.7 120 120 120h48c52.5 0 97.1-33.7 113.4-80.7c-3.1 .5-6.2 .7-9.4 .7c-20 0-37.9-9.2-49.7-23.6c-9 4.9-19.4 7.6-30.3 7.6c-15.1 0-29-5.3-40-14c-11 8.8-24.9 14-40 14H120c-13.3 0-24-10.7-24-24s10.7-24 24-24h40c8.8 0 16-7.2 16-16s-7.2-16-16-16H120 80zM0 320s0 0 0 0c0-18 6-34.6 16-48V64C16 28.7 44.7 0 80 0s64 28.7 64 64v82c5.1-1.3 10.5-2 16-2c25.3 0 47.2 14.7 57.6 36c7-2.6 14.5-4 22.4-4c20 0 37.9 9.2 49.7 23.6c9-4.9 19.4-7.6 30.3-7.6c35.3 0 64 28.7 64 64v64 24c0 92.8-75.2 168-168 168H168C75.2 512 0 436.8 0 344V320zm336-64c0-8.8-7.2-16-16-16s-16 7.2-16 16v48 16c0 8.8 7.2 16 16 16s16-7.2 16-16V256zM160 240c5.5 0 10.9 .7 16 2v-2V208c0-8.8-7.2-16-16-16s-16 7.2-16 16v32h16zm64 24v40c0 8.8 7.2 16 16 16s16-7.2 16-16V256 240c0-8.8-7.2-16-16-16s-16 7.2-16 16v24z"],
|
||||
"bookmark": [384, 512, [128278, 61591], "f02e", "M0 48C0 21.5 21.5 0 48 0l0 48V441.4l130.1-92.9c8.3-6 19.6-6 27.9 0L336 441.4V48H48V0H336c26.5 0 48 21.5 48 48V488c0 9-5 17.2-13 21.3s-17.6 3.4-24.9-1.8L192 397.5 37.9 507.5c-7.3 5.2-16.9 5.9-24.9 1.8S0 497 0 488V48z"],
|
||||
"hand-point-down": [384, 512, [], "f0a7", "M64 448l0-177.6c5.2 1 10.5 1.6 16 1.6l16 0 0 32 0 144c0 8.8-7.2 16-16 16s-16-7.2-16-16zM80 224c-17.7 0-32-14.3-32-32c0 0 0 0 0 0l0-24c0-66.3 53.7-120 120-120l48 0c52.5 0 97.1 33.7 113.4 80.7c-3.1-.5-6.2-.7-9.4-.7c-20 0-37.9 9.2-49.7 23.6c-9-4.9-19.4-7.6-30.3-7.6c-15.1 0-29 5.3-40 14c-11-8.8-24.9-14-40-14l-40 0c-13.3 0-24 10.7-24 24s10.7 24 24 24l40 0c8.8 0 16 7.2 16 16s-7.2 16-16 16l-40 0-40 0zM0 192s0 0 0 0c0 18 6 34.6 16 48l0 208c0 35.3 28.7 64 64 64s64-28.7 64-64l0-82c5.1 1.3 10.5 2 16 2c25.3 0 47.2-14.7 57.6-36c7 2.6 14.5 4 22.4 4c20 0 37.9-9.2 49.7-23.6c9 4.9 19.4 7.6 30.3 7.6c35.3 0 64-28.7 64-64l0-64 0-24C384 75.2 308.8 0 216 0L168 0C75.2 0 0 75.2 0 168l0 24zm336 64c0 8.8-7.2 16-16 16s-16-7.2-16-16l0-48 0-16c0-8.8 7.2-16 16-16s16 7.2 16 16l0 64zM160 272c5.5 0 10.9-.7 16-2l0 2 0 32c0 8.8-7.2 16-16 16s-16-7.2-16-16l0-32 16 0zm64-24l0-40c0-8.8 7.2-16 16-16s16 7.2 16 16l0 48 0 16c0 8.8-7.2 16-16 16s-16-7.2-16-16l0-24z"],
|
||||
"folder": [512, 512, [128193, 128447, 61716, "folder-blank"], "f07b", "M0 96C0 60.7 28.7 32 64 32H196.1c19.1 0 37.4 7.6 50.9 21.1L289.9 96H448c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V96zM64 80c-8.8 0-16 7.2-16 16V416c0 8.8 7.2 16 16 16H448c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16H286.6c-10.6 0-20.8-4.2-28.3-11.7L213.1 87c-4.5-4.5-10.6-7-17-7H64z"],
|
||||
"user": [448, 512, [128100, 62144], "f007", "M304 128a80 80 0 1 0 -160 0 80 80 0 1 0 160 0zM96 128a128 128 0 1 1 256 0A128 128 0 1 1 96 128zM49.3 464H398.7c-8.9-63.3-63.3-112-129-112H178.3c-65.7 0-120.1 48.7-129 112zM0 482.3C0 383.8 79.8 304 178.3 304h91.4C368.2 304 448 383.8 448 482.3c0 16.4-13.3 29.7-29.7 29.7H29.7C13.3 512 0 498.7 0 482.3z"],
|
||||
"square-caret-left": [448, 512, ["caret-square-left"], "f191", "M48 416c0 8.8 7.2 16 16 16l320 0c8.8 0 16-7.2 16-16l0-320c0-8.8-7.2-16-16-16L64 80c-8.8 0-16 7.2-16 16l0 320zm16 64c-35.3 0-64-28.7-64-64L0 96C0 60.7 28.7 32 64 32l320 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480zm64-224c0-6.7 2.8-13 7.7-17.6l112-104c7-6.5 17.2-8.2 25.9-4.4s14.4 12.5 14.4 22l0 208c0 9.5-5.7 18.2-14.4 22s-18.9 2.1-25.9-4.4l-112-104c-4.9-4.5-7.7-10.9-7.7-17.6z"],
|
||||
"star": [576, 512, [11088, 61446], "f005", "M287.9 0c9.2 0 17.6 5.2 21.6 13.5l68.6 141.3 153.2 22.6c9 1.3 16.5 7.6 19.3 16.3s.5 18.1-5.9 24.5L433.6 328.4l26.2 155.6c1.5 9-2.2 18.1-9.6 23.5s-17.3 6-25.3 1.7l-137-73.2L151 509.1c-8.1 4.3-17.9 3.7-25.3-1.7s-11.2-14.5-9.7-23.5l26.2-155.6L31.1 218.2c-6.5-6.4-8.7-15.9-5.9-24.5s10.3-14.9 19.3-16.3l153.2-22.6L266.3 13.5C270.4 5.2 278.7 0 287.9 0zm0 79L235.4 187.2c-3.5 7.1-10.2 12.1-18.1 13.3L99 217.9 184.9 303c5.5 5.5 8.1 13.3 6.8 21L171.4 443.7l105.2-56.2c7.1-3.8 15.6-3.8 22.6 0l105.2 56.2L384.2 324.1c-1.3-7.7 1.2-15.5 6.8-21l85.9-85.1L358.6 200.5c-7.8-1.2-14.6-6.1-18.1-13.3L287.9 79z"],
|
||||
"chess-knight": [448, 512, [9822], "f441", "M226.6 48H117.3l17.1 12.8c6 4.5 9.6 11.6 9.6 19.2s-3.6 14.7-9.6 19.2l-6.5 4.9c-10 7.5-16 19.3-16 31.9l-.3 91c0 10.2 4.9 19.9 13.2 25.8l1.9 1.3c9.9 7.1 23.3 7 33.2-.1l49.9-36.3c10.7-7.8 25.7-5.4 33.5 5.3s5.4 25.7-5.3 33.5l-49.9 36.3-53.8 39.1c-7.3 5.3-13 12.2-16.9 20.1H66.8c5.3-22.1 17.8-41.9 35.9-56.3c-1.3-.8-2.6-1.7-3.8-2.6L97 291.8c-21-15-33.4-39.2-33.3-65l.3-91c.1-19.8 6.7-38.7 18.6-53.9l-.4-.3C70.7 73 64 59.6 64 45.3C64 20.3 84.3 0 109.3 0H226.6C331.2 0 416 84.8 416 189.4c0 11.1-1 22.2-2.9 33.2L390.1 352H341.3l24.5-137.8c1.5-8.2 2.2-16.5 2.2-24.8C368 111.3 304.7 48 226.6 48zM85.2 432L68.7 464H379.3l-16.6-32H85.2zm315.7-30.7l26.5 51.2c3 5.8 4.6 12.2 4.6 18.7c0 22.5-18.2 40.8-40.8 40.8H56.8C34.2 512 16 493.8 16 471.2c0-6.5 1.6-12.9 4.6-18.7l26.5-51.2C52.5 390.7 63.5 384 75.5 384h297c12 0 22.9 6.7 28.4 17.3zM172 128a20 20 0 1 1 0 40 20 20 0 1 1 0-40z"],
|
||||
"face-laugh-squint": [512, 512, ["laugh-squint"], "f59b", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm130.7 57.9c-4.2-13.6 7.1-25.9 21.3-25.9H364.5c14.2 0 25.5 12.4 21.3 25.9C369 368.4 318.2 408 258.2 408s-110.8-39.6-127.5-94.1zm2.8-183.3l89.9 47.9c10.7 5.7 10.7 21.1 0 26.8l-89.9 47.9c-7.9 4.2-17.5-1.5-17.5-10.5c0-2.8 1-5.5 2.8-7.6l36-43.2-36-43.2c-1.8-2.1-2.8-4.8-2.8-7.6c0-9 9.6-14.7 17.5-10.5zM396 141.1c0 2.8-1 5.5-2.8 7.6l-36 43.2 36 43.2c1.8 2.1 2.8 4.8 2.8 7.6c0 9-9.6 14.7-17.5 10.5l-89.9-47.9c-10.7-5.7-10.7-21.1 0-26.8l89.9-47.9c7.9-4.2 17.5 1.5 17.5 10.5z"],
|
||||
"face-laugh": [512, 512, ["laugh"], "f599", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm130.7 57.9c-4.2-13.6 7.1-25.9 21.3-25.9H364.5c14.2 0 25.5 12.4 21.3 25.9C369 368.4 318.2 408 258.2 408s-110.8-39.6-127.5-94.1zM144.4 192a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zm192-32a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"],
|
||||
"folder-open": [576, 512, [128194, 128449, 61717], "f07c", "M384 480h48c11.4 0 21.9-6 27.6-15.9l112-192c5.8-9.9 5.8-22.1 .1-32.1S555.5 224 544 224H144c-11.4 0-21.9 6-27.6 15.9L48 357.1V96c0-8.8 7.2-16 16-16H181.5c4.2 0 8.3 1.7 11.3 4.7l26.5 26.5c21 21 49.5 32.8 79.2 32.8H416c8.8 0 16 7.2 16 16v32h48V160c0-35.3-28.7-64-64-64H298.5c-17 0-33.3-6.7-45.3-18.7L226.7 50.7c-12-12-28.3-18.7-45.3-18.7H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H87.7 384z"],
|
||||
"clipboard": [384, 512, [128203], "f328", "M280 64h40c35.3 0 64 28.7 64 64V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V128C0 92.7 28.7 64 64 64h40 9.6C121 27.5 153.3 0 192 0s71 27.5 78.4 64H280zM64 112c-8.8 0-16 7.2-16 16V448c0 8.8 7.2 16 16 16H320c8.8 0 16-7.2 16-16V128c0-8.8-7.2-16-16-16H304v24c0 13.3-10.7 24-24 24H192 104c-13.3 0-24-10.7-24-24V112H64zm128-8a24 24 0 1 0 0-48 24 24 0 1 0 0 48z"],
|
||||
"chess-queen": [512, 512, [9819], "f445", "M256 96a48 48 0 1 0 0-96 48 48 0 1 0 0 96zm-95.2-8c-18.1 0-31.3 12.8-35.6 26.9c-8 26.2-32.4 45.2-61.2 45.2c-10 0-19.4-2.3-27.7-6.3c-7.6-3.7-16.7-3.3-24 1.2C.7 162.1-3.1 177.1 3.7 188.9L97.6 352H153l-83-144.1c40.5-2.2 75.3-25.9 93.1-59.8c22 26.8 55.4 43.9 92.8 43.9s70.8-17.1 92.8-43.9c17.8 34 52.6 57.7 93.1 59.8L359 352h55.4l93.9-163.1c6.8-11.7 3-26.7-8.6-33.8c-7.3-4.5-16.4-4.9-24-1.2c-8.4 4-17.7 6.3-27.7 6.3c-28.8 0-53.2-19-61.2-45.2C382.5 100.8 369.3 88 351.2 88c-14.5 0-26.3 8.5-32.4 19.3c-12.4 22-35.9 36.7-62.8 36.7s-50.4-14.8-62.8-36.7C187.1 96.5 175.4 88 160.8 88zM133.2 432H378.8l16.6 32H116.7l16.6-32zm283.7-30.7c-5.5-10.6-16.5-17.3-28.4-17.3h-265c-12 0-22.9 6.7-28.4 17.3L68.6 452.5c-3 5.8-4.6 12.2-4.6 18.7c0 22.5 18.2 40.8 40.8 40.8H407.2c22.5 0 40.8-18.2 40.8-40.8c0-6.5-1.6-12.9-4.6-18.7l-26.5-51.2z"],
|
||||
"hand-back-fist": [448, 512, ["hand-rock"], "f255", "M144 64c0-8.8 7.2-16 16-16s16 7.2 16 16c0 9.1 5.1 17.4 13.3 21.5s17.9 3.2 25.1-2.3c2.7-2 6-3.2 9.6-3.2c8.8 0 16 7.2 16 16c0 9.1 5.1 17.4 13.3 21.5s17.9 3.2 25.1-2.3c2.7-2 6-3.2 9.6-3.2c8.8 0 16 7.2 16 16c0 9.1 5.1 17.4 13.3 21.5s17.9 3.2 25.1-2.3c2.7-2 6-3.2 9.6-3.2c8.8 0 16 7.2 16 16V264c0 31.3-20 58-48 67.9c-9.6 3.4-16 12.5-16 22.6V488c0 13.3 10.7 24 24 24s24-10.7 24-24V370.2c38-20.1 64-60.1 64-106.2V160c0-35.3-28.7-64-64-64c-2.8 0-5.6 .2-8.3 .5C332.8 77.1 311.9 64 288 64c-2.8 0-5.6 .2-8.3 .5C268.8 45.1 247.9 32 224 32c-2.8 0-5.6 .2-8.3 .5C204.8 13.1 183.9 0 160 0C124.7 0 96 28.7 96 64v64.3c-11.7 7.4-22.5 16.4-32 26.9l17.8 16.1L64 155.2l-9.4 10.5C40 181.8 32 202.8 32 224.6v12.8c0 49.6 24.2 96.1 64.8 124.5l13.8-19.7L96.8 361.9l8.9 6.2c6.9 4.8 14.4 8.6 22.3 11.3V488c0 13.3 10.7 24 24 24s24-10.7 24-24V359.9c0-12.6-9.8-23.1-22.4-23.9c-7.3-.5-14.3-2.9-20.3-7.1l-13.1 18.7 13.1-18.7-8.9-6.2C96.6 303.1 80 271.3 80 237.4V224.6c0-9.9 3.7-19.4 10.3-26.8l9.4-10.5c3.8-4.2 7.9-8.1 12.3-11.6V208c0 8.8 7.2 16 16 16s16-7.2 16-16V142.3 128 64z"],
|
||||
"square-caret-up": [448, 512, ["caret-square-up"], "f151", "M64 80c-8.8 0-16 7.2-16 16l0 320c0 8.8 7.2 16 16 16l320 0c8.8 0 16-7.2 16-16l0-320c0-8.8-7.2-16-16-16L64 80zM0 96C0 60.7 28.7 32 64 32l320 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zm224 64c6.7 0 13 2.8 17.6 7.7l104 112c6.5 7 8.2 17.2 4.4 25.9s-12.5 14.4-22 14.4l-208 0c-9.5 0-18.2-5.7-22-14.4s-2.1-18.9 4.4-25.9l104-112c4.5-4.9 10.9-7.7 17.6-7.7z"],
|
||||
"chart-bar": [512, 512, ["bar-chart"], "f080", "M24 32c13.3 0 24 10.7 24 24V408c0 13.3 10.7 24 24 24H488c13.3 0 24 10.7 24 24s-10.7 24-24 24H72c-39.8 0-72-32.2-72-72V56C0 42.7 10.7 32 24 32zM128 136c0-13.3 10.7-24 24-24l208 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-208 0c-13.3 0-24-10.7-24-24zm24 72H296c13.3 0 24 10.7 24 24s-10.7 24-24 24H152c-13.3 0-24-10.7-24-24s10.7-24 24-24zm0 96H424c13.3 0 24 10.7 24 24s-10.7 24-24 24H152c-13.3 0-24-10.7-24-24s10.7-24 24-24z"],
|
||||
"window-restore": [512, 512, [], "f2d2", "M432 48H208c-17.7 0-32 14.3-32 32V96H128V80c0-44.2 35.8-80 80-80H432c44.2 0 80 35.8 80 80V304c0 44.2-35.8 80-80 80H416V336h16c17.7 0 32-14.3 32-32V80c0-17.7-14.3-32-32-32zM48 448c0 8.8 7.2 16 16 16H320c8.8 0 16-7.2 16-16V256H48V448zM64 128H320c35.3 0 64 28.7 64 64V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V192c0-35.3 28.7-64 64-64z"],
|
||||
"square-plus": [448, 512, [61846, "plus-square"], "f0fe", "M64 80c-8.8 0-16 7.2-16 16V416c0 8.8 7.2 16 16 16H384c8.8 0 16-7.2 16-16V96c0-8.8-7.2-16-16-16H64zM0 96C0 60.7 28.7 32 64 32H384c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V96zM200 344V280H136c-13.3 0-24-10.7-24-24s10.7-24 24-24h64V168c0-13.3 10.7-24 24-24s24 10.7 24 24v64h64c13.3 0 24 10.7 24 24s-10.7 24-24 24H248v64c0 13.3-10.7 24-24 24s-24-10.7-24-24z"],
|
||||
"image": [512, 512, [], "f03e", "M448 80c8.8 0 16 7.2 16 16V415.8l-5-6.5-136-176c-4.5-5.9-11.6-9.3-19-9.3s-14.4 3.4-19 9.3L202 340.7l-30.5-42.7C167 291.7 159.8 288 152 288s-15 3.7-19.5 10.1l-80 112L48 416.3l0-.3V96c0-8.8 7.2-16 16-16H448zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zm80 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"],
|
||||
"folder-closed": [512, 512, [], "e185", "M251.7 127.6l0 0c10.5 10.5 24.7 16.4 39.6 16.4H448c8.8 0 16 7.2 16 16v32H48V96c0-8.8 7.2-16 16-16H197.5c4.2 0 8.3 1.7 11.3 4.7l33.9-33.9L208.8 84.7l42.9 42.9zM48 240H464V416c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16V240zM285.7 93.7L242.7 50.7c-12-12-28.3-18.7-45.3-18.7H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H291.3c-2.1 0-4.2-.8-5.7-2.3z"],
|
||||
"lemon": [448, 512, [127819], "f094", "M368 80c-3.2 0-6.2 .4-8.9 1.3C340 86.8 313 91.9 284.8 84.6C227.4 69.7 160.2 92 110.1 142.1S37.7 259.4 52.6 316.8c7.3 28.2 2.2 55.2-3.3 74.3c-.8 2.8-1.3 5.8-1.3 8.9c0 17.7 14.3 32 32 32c3.2 0 6.2-.4 8.9-1.3c19.1-5.5 46.1-10.7 74.3-3.3c57.4 14.9 124.6-7.4 174.7-57.5s72.4-117.3 57.5-174.7c-7.3-28.2-2.2-55.2 3.3-74.3c.8-2.8 1.3-5.8 1.3-8.9c0-17.7-14.3-32-32-32zm0-48c44.2 0 80 35.8 80 80c0 7.7-1.1 15.2-3.1 22.3c-4.6 15.8-7.1 32.9-3 48.9c20.1 77.6-10.9 161.5-70 220.7s-143.1 90.2-220.7 70c-16-4.1-33-1.6-48.9 3c-7.1 2-14.6 3.1-22.3 3.1c-44.2 0-80-35.8-80-80c0-7.7 1.1-15.2 3.1-22.3c4.6-15.8 7.1-32.9 3-48.9C-14 251.3 17 167.3 76.2 108.2S219.3 18 296.8 38.1c16 4.1 33 1.6 48.9-3c7.1-2 14.6-3.1 22.3-3.1zM246.7 167c-52 15.2-96.5 59.7-111.7 111.7c-3.7 12.7-17.1 20-29.8 16.3s-20-17.1-16.3-29.8c19.8-67.7 76.6-124.5 144.3-144.3c12.7-3.7 26.1 3.6 29.8 16.3s-3.6 26.1-16.3 29.8z"],
|
||||
"handshake": [640, 512, [], "f2b5", "M272.2 64.6l-51.1 51.1c-15.3 4.2-29.5 11.9-41.5 22.5L153 161.9C142.8 171 129.5 176 115.8 176H96V304c20.4 .6 39.8 8.9 54.3 23.4l35.6 35.6 7 7 0 0L219.9 397c6.2 6.2 16.4 6.2 22.6 0c1.7-1.7 3-3.7 3.7-5.8c2.8-7.7 9.3-13.5 17.3-15.3s16.4 .6 22.2 6.5L296.5 393c11.6 11.6 30.4 11.6 41.9 0c5.4-5.4 8.3-12.3 8.6-19.4c.4-8.8 5.6-16.6 13.6-20.4s17.3-3 24.4 2.1c9.4 6.7 22.5 5.8 30.9-2.6c9.4-9.4 9.4-24.6 0-33.9L340.1 243l-35.8 33c-27.3 25.2-69.2 25.6-97 .9c-31.7-28.2-32.4-77.4-1.6-106.5l70.1-66.2C303.2 78.4 339.4 64 377.1 64c36.1 0 71 13.3 97.9 37.2L505.1 128H544h40 40c8.8 0 16 7.2 16 16V352c0 17.7-14.3 32-32 32H576c-11.8 0-22.2-6.4-27.7-16H463.4c-3.4 6.7-7.9 13.1-13.5 18.7c-17.1 17.1-40.8 23.8-63 20.1c-3.6 7.3-8.5 14.1-14.6 20.2c-27.3 27.3-70 30-100.4 8.1c-25.1 20.8-62.5 19.5-86-4.1L159 404l-7-7-35.6-35.6c-5.5-5.5-12.7-8.7-20.4-9.3C96 369.7 81.6 384 64 384H32c-17.7 0-32-14.3-32-32V144c0-8.8 7.2-16 16-16H56 96h19.8c2 0 3.9-.7 5.3-2l26.5-23.6C175.5 77.7 211.4 64 248.7 64H259c4.4 0 8.9 .2 13.2 .6zM544 320V176H496c-5.9 0-11.6-2.2-15.9-6.1l-36.9-32.8c-18.2-16.2-41.7-25.1-66.1-25.1c-25.4 0-49.8 9.7-68.3 27.1l-70.1 66.2c-10.3 9.8-10.1 26.3 .5 35.7c9.3 8.3 23.4 8.1 32.5-.3l71.9-66.4c9.7-9 24.9-8.4 33.9 1.4s8.4 24.9-1.4 33.9l-.8 .8 74.4 74.4c10 10 16.5 22.3 19.4 35.1H544zM64 336a16 16 0 1 0 -32 0 16 16 0 1 0 32 0zm528 16a16 16 0 1 0 0-32 16 16 0 1 0 0 32z"],
|
||||
"gem": [512, 512, [128142], "f3a5", "M168.5 72L256 165l87.5-93h-175zM383.9 99.1L311.5 176h129L383.9 99.1zm50 124.9H256 78.1L256 420.3 433.9 224zM71.5 176h129L128.1 99.1 71.5 176zm434.3 40.1l-232 256c-4.5 5-11 7.9-17.8 7.9s-13.2-2.9-17.8-7.9l-232-256c-7.7-8.5-8.3-21.2-1.5-30.4l112-152c4.5-6.1 11.7-9.8 19.3-9.8H376c7.6 0 14.8 3.6 19.3 9.8l112 152c6.8 9.2 6.1 21.9-1.5 30.4z"],
|
||||
"circle-play": [512, 512, [61469, "play-circle"], "f144", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zM188.3 147.1c7.6-4.2 16.8-4.1 24.3 .5l144 88c7.1 4.4 11.5 12.1 11.5 20.5s-4.4 16.1-11.5 20.5l-144 88c-7.4 4.5-16.7 4.7-24.3 .5s-12.3-12.2-12.3-20.9V168c0-8.7 4.7-16.7 12.3-20.9z"],
|
||||
"circle-check": [512, 512, [61533, "check-circle"], "f058", "M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-111 111-47-47c-9.4-9.4-24.6-9.4-33.9 0s-9.4 24.6 0 33.9l64 64c9.4 9.4 24.6 9.4 33.9 0L369 209z"],
|
||||
"circle-stop": [512, 512, [62094, "stop-circle"], "f28d", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm192-96H320c17.7 0 32 14.3 32 32V320c0 17.7-14.3 32-32 32H192c-17.7 0-32-14.3-32-32V192c0-17.7 14.3-32 32-32z"],
|
||||
"id-badge": [384, 512, [], "f2c1", "M256 48V64c0 17.7-14.3 32-32 32H160c-17.7 0-32-14.3-32-32V48H64c-8.8 0-16 7.2-16 16V448c0 8.8 7.2 16 16 16H320c8.8 0 16-7.2 16-16V64c0-8.8-7.2-16-16-16H256zM0 64C0 28.7 28.7 0 64 0H320c35.3 0 64 28.7 64 64V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V64zM160 320h64c44.2 0 80 35.8 80 80c0 8.8-7.2 16-16 16H96c-8.8 0-16-7.2-16-16c0-44.2 35.8-80 80-80zm-32-96a64 64 0 1 1 128 0 64 64 0 1 1 -128 0z"],
|
||||
"face-laugh-beam": [512, 512, [128513, "laugh-beam"], "f59a", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm130.7 57.9c-4.2-13.6 7.1-25.9 21.3-25.9H364.5c14.2 0 25.5 12.4 21.3 25.9C369 368.4 318.2 408 258.2 408s-110.8-39.6-127.5-94.1zm86.9-85.1l0 0 0 0-.2-.2c-.2-.2-.4-.5-.7-.9c-.6-.8-1.6-2-2.8-3.4c-2.5-2.8-6-6.6-10.2-10.3c-8.8-7.8-18.8-14-27.7-14s-18.9 6.2-27.7 14c-4.2 3.7-7.7 7.5-10.2 10.3c-1.2 1.4-2.2 2.6-2.8 3.4c-.3 .4-.6 .7-.7 .9l-.2 .2 0 0 0 0 0 0c-2.1 2.8-5.7 3.9-8.9 2.8s-5.5-4.1-5.5-7.6c0-17.9 6.7-35.6 16.6-48.8c9.8-13 23.9-23.2 39.4-23.2s29.6 10.2 39.4 23.2c9.9 13.2 16.6 30.9 16.6 48.8c0 3.4-2.2 6.5-5.5 7.6s-6.9 0-8.9-2.8l0 0 0 0zm160 0l0 0-.2-.2c-.2-.2-.4-.5-.7-.9c-.6-.8-1.6-2-2.8-3.4c-2.5-2.8-6-6.6-10.2-10.3c-8.8-7.8-18.8-14-27.7-14s-18.9 6.2-27.7 14c-4.2 3.7-7.7 7.5-10.2 10.3c-1.2 1.4-2.2 2.6-2.8 3.4c-.3 .4-.6 .7-.7 .9l-.2 .2 0 0 0 0 0 0c-2.1 2.8-5.7 3.9-8.9 2.8s-5.5-4.1-5.5-7.6c0-17.9 6.7-35.6 16.6-48.8c9.8-13 23.9-23.2 39.4-23.2s29.6 10.2 39.4 23.2c9.9 13.2 16.6 30.9 16.6 48.8c0 3.4-2.2 6.5-5.5 7.6s-6.9 0-8.9-2.8l0 0 0 0 0 0z"],
|
||||
"registered": [512, 512, [174], "f25d", "M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM160 152V264v96c0 13.3 10.7 24 24 24s24-10.7 24-24V288h60.9l37.2 81.9c5.5 12.1 19.7 17.4 31.8 11.9s17.4-19.7 11.9-31.8L315.7 275c21.8-14.3 36.3-39 36.3-67c0-44.2-35.8-80-80-80H184c-13.3 0-24 10.7-24 24zm48 88V176h64c17.7 0 32 14.3 32 32s-14.3 32-32 32H208z"],
|
||||
"address-card": [576, 512, [62140, "contact-card", "vcard"], "f2bb", "M512 80c8.8 0 16 7.2 16 16V416c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16V96c0-8.8 7.2-16 16-16H512zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H512c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zM208 256a64 64 0 1 0 0-128 64 64 0 1 0 0 128zm-32 32c-44.2 0-80 35.8-80 80c0 8.8 7.2 16 16 16H304c8.8 0 16-7.2 16-16c0-44.2-35.8-80-80-80H176zM376 144c-13.3 0-24 10.7-24 24s10.7 24 24 24h80c13.3 0 24-10.7 24-24s-10.7-24-24-24H376zm0 96c-13.3 0-24 10.7-24 24s10.7 24 24 24h80c13.3 0 24-10.7 24-24s-10.7-24-24-24H376z"],
|
||||
"face-tired": [512, 512, [128555, "tired"], "f5c8", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm176.5 64.3C196.1 302.1 223.8 288 256 288s59.9 14.1 79.5 32.3C354.5 338.1 368 362 368 384c0 5.4-2.7 10.4-7.2 13.4s-10.2 3.4-15.2 1.3l-17.2-7.5c-22.8-10-47.5-15.1-72.4-15.1s-49.6 5.2-72.4 15.1l-17.2 7.5c-4.9 2.2-10.7 1.7-15.2-1.3s-7.2-8-7.2-13.4c0-22 13.5-45.9 32.5-63.7zm-43-173.6l89.9 47.9c10.7 5.7 10.7 21.1 0 26.8l-89.9 47.9c-7.9 4.2-17.5-1.5-17.5-10.5c0-2.8 1-5.5 2.8-7.6l36-43.2-36-43.2c-1.8-2.1-2.8-4.8-2.8-7.6c0-9 9.6-14.7 17.5-10.5zM396 157.1c0 2.8-1 5.5-2.8 7.6l-36 43.2 36 43.2c1.8 2.1 2.8 4.8 2.8 7.6c0 9-9.6 14.7-17.5 10.5l-89.9-47.9c-10.7-5.7-10.7-21.1 0-26.8l89.9-47.9c7.9-4.2 17.5 1.5 17.5 10.5z"],
|
||||
"font-awesome": [448, 512, [62501, 62694, "font-awesome-flag", "font-awesome-logo-full"], "f2b4", "M48 56c0-13.3-10.7-24-24-24S0 42.7 0 56V456c0 13.3 10.7 24 24 24s24-10.7 24-24V124.2l12.5-2.4c16.7-3.2 31.5-8.5 44.2-13.1l0 0 0 0c3.7-1.3 7.1-2.6 10.4-3.7c15.2-5.2 30.4-9.1 51.2-9.1c25.6 0 43 6 63.5 13.3l.5 .2c20.9 7.4 44.8 15.9 79.1 15.9c32.4 0 53.7-6.8 90.5-19.6V342.9l-9.5 3.3c-41.5 14.4-55.2 19.2-81 19.2c-25.7 0-43.1-6-63.6-13.3l-.6-.2c-20.8-7.4-44.8-15.8-79-15.8c-16.8 0-31 2-43.9 5c-12.9 3-20.9 16-17.9 28.9s16 20.9 28.9 17.9c9.6-2.2 20.1-3.7 32.9-3.7c25.6 0 43 6 63.5 13.3l.5 .2c20.9 7.4 44.8 15.9 79.1 15.9c34.4 0 56.4-7.7 97.8-22.2c7.5-2.6 15.5-5.4 24.4-8.5l16.2-5.5V360 72 38.4L416.2 49.3c-9.7 3.3-18.2 6.3-25.7 8.9c-41.5 14.4-55.2 19.2-81 19.2c-25.7 0-43.1-6-63.6-13.3l-.6-.2c-20.8-7.4-44.8-15.8-79-15.8c-27.8 0-48.5 5.5-66.6 11.6c-4.9 1.7-9.3 3.3-13.6 4.8c-11.9 4.3-22 7.9-34.7 10.3L48 75.4V56z"],
|
||||
"face-smile-wink": [512, 512, [128521, "smile-wink"], "f4da", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm177.6 62.1C192.8 334.5 218.8 352 256 352s63.2-17.5 78.4-33.9c9-9.7 24.2-10.4 33.9-1.4s10.4 24.2 1.4 33.9c-22 23.8-60 49.4-113.6 49.4s-91.7-25.5-113.6-49.4c-9-9.7-8.4-24.9 1.4-33.9s24.9-8.4 33.9 1.4zM144.4 208a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zm165.8 21.7c-7.6 8.1-20.2 8.5-28.3 .9s-8.5-20.2-.9-28.3c14.5-15.5 35.2-22.3 54.6-22.3s40.1 6.8 54.6 22.3c7.6 8.1 7.1 20.7-.9 28.3s-20.7 7.1-28.3-.9c-5.5-5.8-14.8-9.7-25.4-9.7s-19.9 3.8-25.4 9.7z"],
|
||||
"file-word": [384, 512, [], "f1c2", "M48 448V64c0-8.8 7.2-16 16-16H224v80c0 17.7 14.3 32 32 32h80V448c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16zM64 0C28.7 0 0 28.7 0 64V448c0 35.3 28.7 64 64 64H320c35.3 0 64-28.7 64-64V154.5c0-17-6.7-33.3-18.7-45.3L274.7 18.7C262.7 6.7 246.5 0 229.5 0H64zm55 241.1c-3.8-12.7-17.2-19.9-29.9-16.1s-19.9 17.2-16.1 29.9l48 160c3 10.2 12.4 17.1 23 17.1s19.9-7 23-17.1l25-83.4 25 83.4c3 10.2 12.4 17.1 23 17.1s19.9-7 23-17.1l48-160c3.8-12.7-3.4-26.1-16.1-29.9s-26.1 3.4-29.9 16.1l-25 83.4-25-83.4c-3-10.2-12.4-17.1-23-17.1s-19.9 7-23 17.1l-25 83.4-25-83.4z"],
|
||||
"file-powerpoint": [384, 512, [], "f1c4", "M64 464c-8.8 0-16-7.2-16-16V64c0-8.8 7.2-16 16-16H224v80c0 17.7 14.3 32 32 32h80V448c0 8.8-7.2 16-16 16H64zM64 0C28.7 0 0 28.7 0 64V448c0 35.3 28.7 64 64 64H320c35.3 0 64-28.7 64-64V154.5c0-17-6.7-33.3-18.7-45.3L274.7 18.7C262.7 6.7 246.5 0 229.5 0H64zm72 208c-13.3 0-24 10.7-24 24V336v56c0 13.3 10.7 24 24 24s24-10.7 24-24V360h44c42 0 76-34 76-76s-34-76-76-76H136zm68 104H160V256h44c15.5 0 28 12.5 28 28s-12.5 28-28 28z"],
|
||||
"envelope-open": [512, 512, [62135], "f2b6", "M255.4 48.2c.2-.1 .4-.2 .6-.2s.4 .1 .6 .2L460.6 194c2.1 1.5 3.4 3.9 3.4 6.5v13.6L291.5 355.7c-20.7 17-50.4 17-71.1 0L48 214.1V200.5c0-2.6 1.2-5 3.4-6.5L255.4 48.2zM48 276.2L190 392.8c38.4 31.5 93.7 31.5 132 0L464 276.2V456c0 4.4-3.6 8-8 8H56c-4.4 0-8-3.6-8-8V276.2zM256 0c-10.2 0-20.2 3.2-28.5 9.1L23.5 154.9C8.7 165.4 0 182.4 0 200.5V456c0 30.9 25.1 56 56 56H456c30.9 0 56-25.1 56-56V200.5c0-18.1-8.7-35.1-23.4-45.6L284.5 9.1C276.2 3.2 266.2 0 256 0z"],
|
||||
"file-zipper": [384, 512, ["file-archive"], "f1c6", "M64 464c-8.8 0-16-7.2-16-16V64c0-8.8 7.2-16 16-16h48c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16h48v80c0 17.7 14.3 32 32 32h80V448c0 8.8-7.2 16-16 16H64zM64 0C28.7 0 0 28.7 0 64V448c0 35.3 28.7 64 64 64H320c35.3 0 64-28.7 64-64V154.5c0-17-6.7-33.3-18.7-45.3L274.7 18.7C262.7 6.7 246.5 0 229.5 0H64zm48 112c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16s-7.2-16-16-16H128c-8.8 0-16 7.2-16 16zm0 64c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16s-7.2-16-16-16H128c-8.8 0-16 7.2-16 16zm-6.3 71.8L82.1 335.9c-1.4 5.4-2.1 10.9-2.1 16.4c0 35.2 28.8 63.7 64 63.7s64-28.5 64-63.7c0-5.5-.7-11.1-2.1-16.4l-23.5-88.2c-3.7-14-16.4-23.8-30.9-23.8H136.6c-14.5 0-27.2 9.7-30.9 23.8zM128 336h32c8.8 0 16 7.2 16 16s-7.2 16-16 16H128c-8.8 0-16-7.2-16-16s7.2-16 16-16z"],
|
||||
"square": [448, 512, [9632, 9723, 9724, 61590], "f0c8", "M384 80c8.8 0 16 7.2 16 16V416c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16V96c0-8.8 7.2-16 16-16H384zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64z"],
|
||||
"snowflake": [448, 512, [10052, 10054], "f2dc", "M224 0c13.3 0 24 10.7 24 24V70.1l23-23c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-57 57v76.5l66.2-38.2 20.9-77.8c3.4-12.8 16.6-20.4 29.4-17s20.4 16.6 17 29.4L373 142.2l37.1-21.4c11.5-6.6 26.2-2.7 32.8 8.8s2.7 26.2-8.8 32.8L397 183.8l31.5 8.4c12.8 3.4 20.4 16.6 17 29.4s-16.6 20.4-29.4 17l-77.8-20.9L272 256l66.2 38.2 77.8-20.9c12.8-3.4 26 4.2 29.4 17s-4.2 26-17 29.4L397 328.2l37.1 21.4c11.5 6.6 15.4 21.3 8.8 32.8s-21.3 15.4-32.8 8.8L373 369.8l8.4 31.5c3.4 12.8-4.2 26-17 29.4s-26-4.2-29.4-17l-20.9-77.8L248 297.6v76.5l57 57c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-23-23V488c0 13.3-10.7 24-24 24s-24-10.7-24-24V441.9l-23 23c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l57-57V297.6l-66.2 38.2-20.9 77.8c-3.4 12.8-16.6 20.4-29.4 17s-20.4-16.6-17-29.4L75 369.8 37.9 391.2c-11.5 6.6-26.2 2.7-32.8-8.8s-2.7-26.2 8.8-32.8L51 328.2l-31.5-8.4c-12.8-3.4-20.4-16.6-17-29.4s16.6-20.4 29.4-17l77.8 20.9L176 256l-66.2-38.2L31.9 238.6c-12.8 3.4-26-4.2-29.4-17s4.2-26 17-29.4L51 183.8 13.9 162.4c-11.5-6.6-15.4-21.3-8.8-32.8s21.3-15.4 32.8-8.8L75 142.2l-8.4-31.5c-3.4-12.8 4.2-26 17-29.4s26 4.2 29.4 17l20.9 77.8L200 214.4V137.9L143 81c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l23 23V24c0-13.3 10.7-24 24-24z"],
|
||||
"newspaper": [512, 512, [128240], "f1ea", "M168 80c-13.3 0-24 10.7-24 24V408c0 8.4-1.4 16.5-4.1 24H440c13.3 0 24-10.7 24-24V104c0-13.3-10.7-24-24-24H168zM72 480c-39.8 0-72-32.2-72-72V112C0 98.7 10.7 88 24 88s24 10.7 24 24V408c0 13.3 10.7 24 24 24s24-10.7 24-24V104c0-39.8 32.2-72 72-72H440c39.8 0 72 32.2 72 72V408c0 39.8-32.2 72-72 72H72zM176 136c0-13.3 10.7-24 24-24h96c13.3 0 24 10.7 24 24v80c0 13.3-10.7 24-24 24H200c-13.3 0-24-10.7-24-24V136zm200-24h32c13.3 0 24 10.7 24 24s-10.7 24-24 24H376c-13.3 0-24-10.7-24-24s10.7-24 24-24zm0 80h32c13.3 0 24 10.7 24 24s-10.7 24-24 24H376c-13.3 0-24-10.7-24-24s10.7-24 24-24zM200 272H408c13.3 0 24 10.7 24 24s-10.7 24-24 24H200c-13.3 0-24-10.7-24-24s10.7-24 24-24zm0 80H408c13.3 0 24 10.7 24 24s-10.7 24-24 24H200c-13.3 0-24-10.7-24-24s10.7-24 24-24z"],
|
||||
"face-kiss-wink-heart": [512, 512, [128536, "kiss-wink-heart"], "f598", "M338.9 446.8c-25.4 11-53.4 17.2-82.9 17.2C141.1 464 48 370.9 48 256S141.1 48 256 48s208 93.1 208 208c0 22.4-3.5 43.9-10.1 64.1c3.1 4.5 5.7 9.4 7.8 14.6c12.7-1.6 25.1 .4 36.2 5c9.1-26.2 14-54.4 14-83.7C512 114.6 397.4 0 256 0S0 114.6 0 256S114.6 512 256 512c35.4 0 69.1-7.2 99.7-20.2c-4.8-5.5-8.5-12.2-10.4-19.7l-6.5-25.3zM296 316c0-6.9-3.1-13.2-7.3-18.3c-4.3-5.2-10.1-9.7-16.7-13.4C258.7 276.9 241.4 272 224 272c-3.6 0-6.8 2.5-7.7 6s.6 7.2 3.8 9l0 0 0 0 0 0 .2 .1c.2 .1 .5 .3 .9 .5c.8 .5 2 1.2 3.4 2.1c2.8 1.9 6.5 4.5 10.2 7.6c3.7 3.1 7.2 6.6 9.6 10.1c2.5 3.5 3.5 6.4 3.5 8.6s-1 5-3.5 8.6c-2.5 3.5-5.9 6.9-9.6 10.1c-3.7 3.1-7.4 5.7-10.2 7.6c-1.4 .9-2.6 1.6-3.4 2.1c-.4 .2-.7 .4-.9 .5l-.2 .1 0 0 0 0 0 0 0 0 0 0c-2.5 1.4-4.1 4.1-4.1 7s1.6 5.6 4.1 7l0 0 0 0 0 0 .2 .1c.2 .1 .5 .3 .9 .5c.8 .5 2 1.2 3.4 2.1c2.8 1.9 6.5 4.5 10.2 7.6c3.7 3.1 7.2 6.6 9.6 10.1c2.5 3.5 3.5 6.4 3.5 8.6s-1 5-3.5 8.6c-2.5 3.5-5.9 6.9-9.6 10.1c-3.7 3.1-7.4 5.7-10.2 7.6c-1.4 .9-2.6 1.6-3.4 2.1c-.4 .2-.7 .4-.9 .5l-.2 .1 0 0 0 0 0 0 0 0c-3.2 1.8-4.7 5.5-3.8 9s4.1 6 7.7 6c17.4 0 34.7-4.9 47.9-12.3c6.6-3.7 12.5-8.2 16.7-13.4c4.3-5.1 7.3-11.4 7.3-18.3s-3.1-13.2-7.3-18.3c-4.3-5.2-10.1-9.7-16.7-13.4c-2.7-1.5-5.7-3-8.7-4.3c3.1-1.3 6-2.7 8.7-4.3c6.6-3.7 12.5-8.2 16.7-13.4c4.3-5.1 7.3-11.4 7.3-18.3zM176.4 240a32 32 0 1 0 0-64 32 32 0 1 0 0 64zm159.3-20c10.6 0 19.9 3.8 25.4 9.7c7.6 8.1 20.2 8.5 28.3 .9s8.5-20.2 .9-28.3C375.7 186.8 355 180 335.6 180s-40.1 6.8-54.6 22.3c-7.6 8.1-7.1 20.7 .9 28.3s20.7 7.1 28.3-.9c5.5-5.8 14.8-9.7 25.4-9.7zM434 352.3c-6-23.2-28.8-37-51.1-30.8s-35.4 30.1-29.5 53.4l22.9 89.3c2.2 8.7 11.2 13.9 19.8 11.4l84.9-23.8c22.2-6.2 35.4-30.1 29.5-53.4s-28.8-37-51.1-30.8l-20.2 5.6-5.4-21z"],
|
||||
"star-half-stroke": [640, 512, ["star-half-alt"], "f5c0", "M341.5 13.5C337.5 5.2 329.1 0 319.9 0s-17.6 5.2-21.6 13.5L229.7 154.8 76.5 177.5c-9 1.3-16.5 7.6-19.3 16.3s-.5 18.1 5.9 24.5L174.2 328.4 148 483.9c-1.5 9 2.2 18.1 9.7 23.5s17.3 6 25.3 1.7l137-73.2 137 73.2c8.1 4.3 17.9 3.7 25.3-1.7s11.2-14.5 9.7-23.5L465.6 328.4 576.8 218.2c6.5-6.4 8.7-15.9 5.9-24.5s-10.3-14.9-19.3-16.3L410.1 154.8 341.5 13.5zM320 384.7V79.1l52.5 108.1c3.5 7.1 10.2 12.1 18.1 13.3l118.3 17.5L423 303c-5.5 5.5-8.1 13.3-6.8 21l20.2 119.6L331.2 387.5c-3.5-1.9-7.4-2.8-11.2-2.8z"],
|
||||
"file-excel": [384, 512, [], "f1c3", "M48 448V64c0-8.8 7.2-16 16-16H224v80c0 17.7 14.3 32 32 32h80V448c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16zM64 0C28.7 0 0 28.7 0 64V448c0 35.3 28.7 64 64 64H320c35.3 0 64-28.7 64-64V154.5c0-17-6.7-33.3-18.7-45.3L274.7 18.7C262.7 6.7 246.5 0 229.5 0H64zm90.9 233.3c-8.1-10.5-23.2-12.3-33.7-4.2s-12.3 23.2-4.2 33.7L161.6 320l-44.5 57.3c-8.1 10.5-6.3 25.5 4.2 33.7s25.5 6.3 33.7-4.2L192 359.1l37.1 47.6c8.1 10.5 23.2 12.3 33.7 4.2s12.3-23.2 4.2-33.7L222.4 320l44.5-57.3c8.1-10.5 6.3-25.5-4.2-33.7s-25.5-6.3-33.7 4.2L192 280.9l-37.1-47.6z"],
|
||||
"face-grin-beam": [512, 512, [128516, "grin-beam"], "f582", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm349.5 52.4c18.7-4.4 35.9 12 25.5 28.1C350.4 374.6 306.3 400 255.9 400s-94.5-25.4-119.1-63.5c-10.4-16.1 6.8-32.5 25.5-28.1c28.9 6.8 60.5 10.5 93.6 10.5s64.7-3.7 93.6-10.5zM217.6 228.8l0 0 0 0-.2-.2c-.2-.2-.4-.5-.7-.9c-.6-.8-1.6-2-2.8-3.4c-2.5-2.8-6-6.6-10.2-10.3c-8.8-7.8-18.8-14-27.7-14s-18.9 6.2-27.7 14c-4.2 3.7-7.7 7.5-10.2 10.3c-1.2 1.4-2.2 2.6-2.8 3.4c-.3 .4-.6 .7-.7 .9l-.2 .2 0 0 0 0 0 0c-2.1 2.8-5.7 3.9-8.9 2.8s-5.5-4.1-5.5-7.6c0-17.9 6.7-35.6 16.6-48.8c9.8-13 23.9-23.2 39.4-23.2s29.6 10.2 39.4 23.2c9.9 13.2 16.6 30.9 16.6 48.8c0 3.4-2.2 6.5-5.5 7.6s-6.9 0-8.9-2.8l0 0 0 0zm160 0l0 0-.2-.2c-.2-.2-.4-.5-.7-.9c-.6-.8-1.6-2-2.8-3.4c-2.5-2.8-6-6.6-10.2-10.3c-8.8-7.8-18.8-14-27.7-14s-18.9 6.2-27.7 14c-4.2 3.7-7.7 7.5-10.2 10.3c-1.2 1.4-2.2 2.6-2.8 3.4c-.3 .4-.6 .7-.7 .9l-.2 .2 0 0 0 0 0 0c-2.1 2.8-5.7 3.9-8.9 2.8s-5.5-4.1-5.5-7.6c0-17.9 6.7-35.6 16.6-48.8c9.8-13 23.9-23.2 39.4-23.2s29.6 10.2 39.4 23.2c9.9 13.2 16.6 30.9 16.6 48.8c0 3.4-2.2 6.5-5.5 7.6s-6.9 0-8.9-2.8l0 0 0 0 0 0z"],
|
||||
"object-ungroup": [640, 512, [], "f248", "M48.2 66.8c-.1-.8-.2-1.7-.2-2.5c0-.1 0-.1 0-.2c0-8.8 7.2-16 16-16c.9 0 1.9 .1 2.8 .2C74.3 49.5 80 56.1 80 64c0 8.8-7.2 16-16 16c-7.9 0-14.5-5.7-15.8-13.2zM0 64c0 26.9 16.5 49.9 40 59.3V228.7C16.5 238.1 0 261.1 0 288c0 35.3 28.7 64 64 64c26.9 0 49.9-16.5 59.3-40H324.7c9.5 23.5 32.5 40 59.3 40c35.3 0 64-28.7 64-64c0-26.9-16.5-49.9-40-59.3V123.3c23.5-9.5 40-32.5 40-59.3c0-35.3-28.7-64-64-64c-26.9 0-49.9 16.5-59.3 40H123.3C113.9 16.5 90.9 0 64 0C28.7 0 0 28.7 0 64zm368 0a16 16 0 1 1 32 0 16 16 0 1 1 -32 0zM324.7 88c6.5 16 19.3 28.9 35.3 35.3V228.7c-16 6.5-28.9 19.3-35.3 35.3H123.3c-6.5-16-19.3-28.9-35.3-35.3V123.3c16-6.5 28.9-19.3 35.3-35.3H324.7zM384 272a16 16 0 1 1 0 32 16 16 0 1 1 0-32zM80 288c0 7.9-5.7 14.5-13.2 15.8c-.8 .1-1.7 .2-2.5 .2l-.2 0c-8.8 0-16-7.2-16-16c0-.9 .1-1.9 .2-2.8C49.5 277.7 56.1 272 64 272c8.8 0 16 7.2 16 16zm391.3-40h45.4c6.5 16 19.3 28.9 35.3 35.3V388.7c-16 6.5-28.9 19.3-35.3 35.3H315.3c-6.5-16-19.3-28.9-35.3-35.3V352H232v36.7c-23.5 9.5-40 32.5-40 59.3c0 35.3 28.7 64 64 64c26.9 0 49.9-16.5 59.3-40H516.7c9.5 23.5 32.5 40 59.3 40c35.3 0 64-28.7 64-64c0-26.9-16.5-49.9-40-59.3V283.3c23.5-9.5 40-32.5 40-59.3c0-35.3-28.7-64-64-64c-26.9 0-49.9 16.5-59.3 40H448v16.4c9.8 8.8 17.8 19.5 23.3 31.6zm88.9-26.7a16 16 0 1 1 31.5 5.5 16 16 0 1 1 -31.5-5.5zM271.8 450.7a16 16 0 1 1 -31.5-5.5 16 16 0 1 1 31.5 5.5zm301.5 13c-7.5-1.3-13.2-7.9-13.2-15.8c0-8.8 7.2-16 16-16c7.9 0 14.5 5.7 15.8 13.2l0 .1c.1 .9 .2 1.8 .2 2.7c0 8.8-7.2 16-16 16c-.9 0-1.9-.1-2.8-.2z"],
|
||||
"circle-right": [512, 512, [61838, "arrow-alt-circle-right"], "f35a", "M464 256A208 208 0 1 1 48 256a208 208 0 1 1 416 0zM0 256a256 256 0 1 0 512 0A256 256 0 1 0 0 256zM294.6 135.1c-4.2-4.5-10.1-7.1-16.3-7.1C266 128 256 138 256 150.3V208H160c-17.7 0-32 14.3-32 32v32c0 17.7 14.3 32 32 32h96v57.7c0 12.3 10 22.3 22.3 22.3c6.2 0 12.1-2.6 16.3-7.1l99.9-107.1c3.5-3.8 5.5-8.7 5.5-13.8s-2-10.1-5.5-13.8L294.6 135.1z"],
|
||||
"face-rolling-eyes": [512, 512, [128580, "meh-rolling-eyes"], "f5a5", "M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM168 376c0 13.3 10.7 24 24 24H320c13.3 0 24-10.7 24-24s-10.7-24-24-24H192c-13.3 0-24 10.7-24 24zm-8-104c-26.5 0-48-21.5-48-48c0-14.3 6.3-27.2 16.2-36c-.2 1.3-.2 2.6-.2 4c0 17.7 14.3 32 32 32s32-14.3 32-32c0-1.4-.1-2.7-.2-4c10 8.8 16.2 21.7 16.2 36c0 26.5-21.5 48-48 48zm0 32a80 80 0 1 0 0-160 80 80 0 1 0 0 160zm192-32c-26.5 0-48-21.5-48-48c0-14.3 6.3-27.2 16.2-36c-.2 1.3-.2 2.6-.2 4c0 17.7 14.3 32 32 32s32-14.3 32-32c0-1.4-.1-2.7-.2-4c10 8.8 16.2 21.7 16.2 36c0 26.5-21.5 48-48 48zm0 32a80 80 0 1 0 0-160 80 80 0 1 0 0 160z"],
|
||||
"object-group": [576, 512, [], "f247", "M48 115.8C38.2 107 32 94.2 32 80c0-26.5 21.5-48 48-48c14.2 0 27 6.2 35.8 16H460.2c8.8-9.8 21.6-16 35.8-16c26.5 0 48 21.5 48 48c0 14.2-6.2 27-16 35.8V396.2c9.8 8.8 16 21.6 16 35.8c0 26.5-21.5 48-48 48c-14.2 0-27-6.2-35.8-16H115.8c-8.8 9.8-21.6 16-35.8 16c-26.5 0-48-21.5-48-48c0-14.2 6.2-27 16-35.8V115.8zM125.3 96c-4.8 13.6-15.6 24.4-29.3 29.3V386.7c13.6 4.8 24.4 15.6 29.3 29.3H450.7c4.8-13.6 15.6-24.4 29.3-29.3V125.3c-13.6-4.8-24.4-15.6-29.3-29.3H125.3zm2.7 64c0-17.7 14.3-32 32-32H288c17.7 0 32 14.3 32 32v96c0 17.7-14.3 32-32 32H160c-17.7 0-32-14.3-32-32V160zM256 320h32c35.3 0 64-28.7 64-64V224h64c17.7 0 32 14.3 32 32v96c0 17.7-14.3 32-32 32H288c-17.7 0-32-14.3-32-32V320z"],
|
||||
"heart": [512, 512, [128153, 128154, 128155, 128156, 128420, 129293, 129294, 129505, 9829, 10084, 61578], "f004", "M225.8 468.2l-2.5-2.3L48.1 303.2C17.4 274.7 0 234.7 0 192.8v-3.3c0-70.4 50-130.8 119.2-144C158.6 37.9 198.9 47 231 69.6c9 6.4 17.4 13.8 25 22.3c4.2-4.8 8.7-9.2 13.5-13.3c3.7-3.2 7.5-6.2 11.5-9c0 0 0 0 0 0C313.1 47 353.4 37.9 392.8 45.4C462 58.6 512 119.1 512 189.5v3.3c0 41.9-17.4 81.9-48.1 110.4L288.7 465.9l-2.5 2.3c-8.2 7.6-19 11.9-30.2 11.9s-22-4.2-30.2-11.9zM239.1 145c-.4-.3-.7-.7-1-1.1l-17.8-20c0 0-.1-.1-.1-.1c0 0 0 0 0 0c-23.1-25.9-58-37.7-92-31.2C81.6 101.5 48 142.1 48 189.5v3.3c0 28.5 11.9 55.8 32.8 75.2L256 430.7 431.2 268c20.9-19.4 32.8-46.7 32.8-75.2v-3.3c0-47.3-33.6-88-80.1-96.9c-34-6.5-69 5.4-92 31.2c0 0 0 0-.1 .1s0 0-.1 .1l-17.8 20c-.3 .4-.7 .7-1 1.1c-4.5 4.5-10.6 7-16.9 7s-12.4-2.5-16.9-7z"],
|
||||
"face-surprise": [512, 512, [128558, "surprise"], "f5c2", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm176.4-80a32 32 0 1 1 0 64 32 32 0 1 1 0-64zm128 32a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zM256 288a64 64 0 1 1 0 128 64 64 0 1 1 0-128z"],
|
||||
"circle-pause": [512, 512, [62092, "pause-circle"], "f28b", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm224-72V328c0 13.3-10.7 24-24 24s-24-10.7-24-24V184c0-13.3 10.7-24 24-24s24 10.7 24 24zm112 0V328c0 13.3-10.7 24-24 24s-24-10.7-24-24V184c0-13.3 10.7-24 24-24s24 10.7 24 24z"],
|
||||
"circle": [512, 512, [128308, 128309, 128992, 128993, 128994, 128995, 128996, 9679, 9898, 9899, 11044, 61708, 61915], "f111", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256z"],
|
||||
"circle-up": [512, 512, [61467, "arrow-alt-circle-up"], "f35b", "M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM135.1 217.4c-4.5 4.2-7.1 10.1-7.1 16.3c0 12.3 10 22.3 22.3 22.3H208v96c0 17.7 14.3 32 32 32h32c17.7 0 32-14.3 32-32V256h57.7c12.3 0 22.3-10 22.3-22.3c0-6.2-2.6-12.1-7.1-16.3L269.8 117.5c-3.8-3.5-8.7-5.5-13.8-5.5s-10.1 2-13.8 5.5L135.1 217.4z"],
|
||||
"file-audio": [384, 512, [], "f1c7", "M64 464H320c8.8 0 16-7.2 16-16V160H256c-17.7 0-32-14.3-32-32V48H64c-8.8 0-16 7.2-16 16V448c0 8.8 7.2 16 16 16zM0 64C0 28.7 28.7 0 64 0H229.5c17 0 33.3 6.7 45.3 18.7l90.5 90.5c12 12 18.7 28.3 18.7 45.3V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V64zM192 272V400c0 6.5-3.9 12.3-9.9 14.8s-12.9 1.1-17.4-3.5L129.4 376H112c-8.8 0-16-7.2-16-16V312c0-8.8 7.2-16 16-16h17.4l35.3-35.3c4.6-4.6 11.5-5.9 17.4-3.5s9.9 8.3 9.9 14.8zm85.8-4c11.6 20 18.2 43.3 18.2 68s-6.6 48-18.2 68c-6.6 11.5-21.3 15.4-32.8 8.8s-15.4-21.3-8.8-32.8c7.5-12.9 11.8-27.9 11.8-44s-4.3-31.1-11.8-44c-6.6-11.5-2.7-26.2 8.8-32.8s26.2-2.7 32.8 8.8z"],
|
||||
"file-image": [384, 512, [128443], "f1c5", "M64 464c-8.8 0-16-7.2-16-16V64c0-8.8 7.2-16 16-16H224v80c0 17.7 14.3 32 32 32h80V448c0 8.8-7.2 16-16 16H64zM64 0C28.7 0 0 28.7 0 64V448c0 35.3 28.7 64 64 64H320c35.3 0 64-28.7 64-64V154.5c0-17-6.7-33.3-18.7-45.3L274.7 18.7C262.7 6.7 246.5 0 229.5 0H64zm96 256a32 32 0 1 0 -64 0 32 32 0 1 0 64 0zm69.2 46.9c-3-4.3-7.9-6.9-13.2-6.9s-10.2 2.6-13.2 6.9l-41.3 59.7-11.9-19.1c-2.9-4.7-8.1-7.5-13.6-7.5s-10.6 2.8-13.6 7.5l-40 64c-3.1 4.9-3.2 11.1-.4 16.2s8.2 8.2 14 8.2h48 32 40 72c6 0 11.4-3.3 14.2-8.6s2.4-11.6-1-16.5l-72-104z"],
|
||||
"circle-question": [512, 512, [62108, "question-circle"], "f059", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm169.8-90.7c7.9-22.3 29.1-37.3 52.8-37.3h58.3c34.9 0 63.1 28.3 63.1 63.1c0 22.6-12.1 43.5-31.7 54.8L280 264.4c-.2 13-10.9 23.6-24 23.6c-13.3 0-24-10.7-24-24V250.5c0-8.6 4.6-16.5 12.1-20.8l44.3-25.4c4.7-2.7 7.6-7.7 7.6-13.1c0-8.4-6.8-15.1-15.1-15.1H222.6c-3.4 0-6.4 2.1-7.5 5.3l-.4 1.2c-4.4 12.5-18.2 19-30.6 14.6s-19-18.2-14.6-30.6l.4-1.2zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"],
|
||||
"face-meh-blank": [512, 512, [128566, "meh-blank"], "f5a4", "M256 48a208 208 0 1 0 0 416 208 208 0 1 0 0-416zM512 256A256 256 0 1 1 0 256a256 256 0 1 1 512 0zM144.4 208a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zm192-32a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"],
|
||||
"eye": [576, 512, [128065], "f06e", "M288 80c-65.2 0-118.8 29.6-159.9 67.7C89.6 183.5 63 226 49.4 256c13.6 30 40.2 72.5 78.6 108.3C169.2 402.4 222.8 432 288 432s118.8-29.6 159.9-67.7C486.4 328.5 513 286 526.6 256c-13.6-30-40.2-72.5-78.6-108.3C406.8 109.6 353.2 80 288 80zM95.4 112.6C142.5 68.8 207.2 32 288 32s145.5 36.8 192.6 80.6c46.8 43.5 78.1 95.4 93 131.1c3.3 7.9 3.3 16.7 0 24.6c-14.9 35.7-46.2 87.7-93 131.1C433.5 443.2 368.8 480 288 480s-145.5-36.8-192.6-80.6C48.6 356 17.3 304 2.5 268.3c-3.3-7.9-3.3-16.7 0-24.6C17.3 208 48.6 156 95.4 112.6zM288 336c44.2 0 80-35.8 80-80s-35.8-80-80-80c-.7 0-1.3 0-2 0c1.3 5.1 2 10.5 2 16c0 35.3-28.7 64-64 64c-5.5 0-10.9-.7-16-2c0 .7 0 1.3 0 2c0 44.2 35.8 80 80 80zm0-208a128 128 0 1 1 0 256 128 128 0 1 1 0-256z"],
|
||||
"face-sad-cry": [512, 512, [128557, "sad-cry"], "f5b3", "M400 406.1V288c0-13.3-10.7-24-24-24s-24 10.7-24 24V440.6c-28.7 15-61.4 23.4-96 23.4s-67.3-8.5-96-23.4V288c0-13.3-10.7-24-24-24s-24 10.7-24 24V406.1C72.6 368.2 48 315 48 256C48 141.1 141.1 48 256 48s208 93.1 208 208c0 59-24.6 112.2-64 150.1zM256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM159.6 220c10.6 0 19.9 3.8 25.4 9.7c7.6 8.1 20.2 8.5 28.3 .9s8.5-20.2 .9-28.3C199.7 186.8 179 180 159.6 180s-40.1 6.8-54.6 22.3c-7.6 8.1-7.1 20.7 .9 28.3s20.7 7.1 28.3-.9c5.5-5.8 14.8-9.7 25.4-9.7zm166.6 9.7c5.5-5.8 14.8-9.7 25.4-9.7s19.9 3.8 25.4 9.7c7.6 8.1 20.2 8.5 28.3 .9s8.5-20.2 .9-28.3C391.7 186.8 371 180 351.6 180s-40.1 6.8-54.6 22.3c-7.6 8.1-7.1 20.7 .9 28.3s20.7 7.1 28.3-.9zM208 320v32c0 26.5 21.5 48 48 48s48-21.5 48-48V320c0-26.5-21.5-48-48-48s-48 21.5-48 48z"],
|
||||
"file-code": [384, 512, [], "f1c9", "M64 464c-8.8 0-16-7.2-16-16V64c0-8.8 7.2-16 16-16H224v80c0 17.7 14.3 32 32 32h80V448c0 8.8-7.2 16-16 16H64zM64 0C28.7 0 0 28.7 0 64V448c0 35.3 28.7 64 64 64H320c35.3 0 64-28.7 64-64V154.5c0-17-6.7-33.3-18.7-45.3L274.7 18.7C262.7 6.7 246.5 0 229.5 0H64zm97 289c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0L79 303c-9.4 9.4-9.4 24.6 0 33.9l48 48c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-31-31 31-31zM257 255c-9.4-9.4-24.6-9.4-33.9 0s-9.4 24.6 0 33.9l31 31-31 31c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l48-48c9.4-9.4 9.4-24.6 0-33.9l-48-48z"],
|
||||
"window-maximize": [512, 512, [128470], "f2d0", "M.3 89.5C.1 91.6 0 93.8 0 96V224 416c0 35.3 28.7 64 64 64l384 0c35.3 0 64-28.7 64-64V224 96c0-35.3-28.7-64-64-64H64c-2.2 0-4.4 .1-6.5 .3c-9.2 .9-17.8 3.8-25.5 8.2C21.8 46.5 13.4 55.1 7.7 65.5c-3.9 7.3-6.5 15.4-7.4 24zM48 224H464l0 192c0 8.8-7.2 16-16 16L64 432c-8.8 0-16-7.2-16-16l0-192z"],
|
||||
"face-frown": [512, 512, [9785, "frown"], "f119", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zM174.6 384.1c-4.5 12.5-18.2 18.9-30.7 14.4s-18.9-18.2-14.4-30.7C146.9 319.4 198.9 288 256 288s109.1 31.4 126.6 79.9c4.5 12.5-2 26.2-14.4 30.7s-26.2-2-30.7-14.4C328.2 358.5 297.2 336 256 336s-72.2 22.5-81.4 48.1zM144.4 208a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zm192-32a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"],
|
||||
"floppy-disk": [448, 512, [128190, 128426, "save"], "f0c7", "M48 96V416c0 8.8 7.2 16 16 16H384c8.8 0 16-7.2 16-16V170.5c0-4.2-1.7-8.3-4.7-11.3l33.9-33.9c12 12 18.7 28.3 18.7 45.3V416c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V96C0 60.7 28.7 32 64 32H309.5c17 0 33.3 6.7 45.3 18.7l74.5 74.5-33.9 33.9L320.8 84.7c-.3-.3-.5-.5-.8-.8V184c0 13.3-10.7 24-24 24H104c-13.3 0-24-10.7-24-24V80H64c-8.8 0-16 7.2-16 16zm80-16v80H272V80H128zm32 240a64 64 0 1 1 128 0 64 64 0 1 1 -128 0z"],
|
||||
"comment-dots": [512, 512, [128172, 62075, "commenting"], "f4ad", "M168.2 384.9c-15-5.4-31.7-3.1-44.6 6.4c-8.2 6-22.3 14.8-39.4 22.7c5.6-14.7 9.9-31.3 11.3-49.4c1-12.9-3.3-25.7-11.8-35.5C60.4 302.8 48 272 48 240c0-79.5 83.3-160 208-160s208 80.5 208 160s-83.3 160-208 160c-31.6 0-61.3-5.5-87.8-15.1zM26.3 423.8c-1.6 2.7-3.3 5.4-5.1 8.1l-.3 .5c-1.6 2.3-3.2 4.6-4.8 6.9c-3.5 4.7-7.3 9.3-11.3 13.5c-4.6 4.6-5.9 11.4-3.4 17.4c2.5 6 8.3 9.9 14.8 9.9c5.1 0 10.2-.3 15.3-.8l.7-.1c4.4-.5 8.8-1.1 13.2-1.9c.8-.1 1.6-.3 2.4-.5c17.8-3.5 34.9-9.5 50.1-16.1c22.9-10 42.4-21.9 54.3-30.6c31.8 11.5 67 17.9 104.1 17.9c141.4 0 256-93.1 256-208S397.4 32 256 32S0 125.1 0 240c0 45.1 17.7 86.8 47.7 120.9c-1.9 24.5-11.4 46.3-21.4 62.9zM144 272a32 32 0 1 0 0-64 32 32 0 1 0 0 64zm144-32a32 32 0 1 0 -64 0 32 32 0 1 0 64 0zm80 32a32 32 0 1 0 0-64 32 32 0 1 0 0 64z"],
|
||||
"face-grin-squint": [512, 512, [128518, "grin-squint"], "f585", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm349.5 52.4c18.7-4.4 35.9 12 25.5 28.1C350.4 374.6 306.3 400 255.9 400s-94.5-25.4-119.1-63.5c-10.4-16.1 6.8-32.5 25.5-28.1c28.9 6.8 60.5 10.5 93.6 10.5s64.7-3.7 93.6-10.5zm-216-161.7l89.9 47.9c10.7 5.7 10.7 21.1 0 26.8l-89.9 47.9c-7.9 4.2-17.5-1.5-17.5-10.5c0-2.8 1-5.5 2.8-7.6l36-43.2-36-43.2c-1.8-2.1-2.8-4.8-2.8-7.6c0-9 9.6-14.7 17.5-10.5zM396 157.1c0 2.8-1 5.5-2.8 7.6l-36 43.2 36 43.2c1.8 2.1 2.8 4.8 2.8 7.6c0 9-9.6 14.7-17.5 10.5l-89.9-47.9c-10.7-5.7-10.7-21.1 0-26.8l89.9-47.9c7.9-4.2 17.5 1.5 17.5 10.5z"],
|
||||
"hand-pointer": [448, 512, [], "f25a", "M160 64c0-8.8 7.2-16 16-16s16 7.2 16 16V200c0 10.3 6.6 19.5 16.4 22.8s20.6-.1 26.8-8.3c3-3.9 7.6-6.4 12.8-6.4c8.8 0 16 7.2 16 16c0 10.3 6.6 19.5 16.4 22.8s20.6-.1 26.8-8.3c3-3.9 7.6-6.4 12.8-6.4c7.8 0 14.3 5.6 15.7 13c1.6 8.2 7.3 15.1 15.1 18s16.7 1.6 23.3-3.6c2.7-2.1 6.1-3.4 9.9-3.4c8.8 0 16 7.2 16 16l0 16V392c0 39.8-32.2 72-72 72H272 212.3h-.9c-37.4 0-72.4-18.7-93.2-49.9L50.7 312.9c-4.9-7.4-2.9-17.3 4.4-22.2s17.3-2.9 22.2 4.4L116 353.2c5.9 8.8 16.8 12.7 26.9 9.7s17-12.4 17-23V320 64zM176 0c-35.3 0-64 28.7-64 64V261.7C91.2 238 55.5 232.8 28.5 250.7C-.9 270.4-8.9 310.1 10.8 339.5L78.3 440.8c29.7 44.5 79.6 71.2 133.1 71.2h.9H272h56c66.3 0 120-53.7 120-120V288l0-16c0-35.3-28.7-64-64-64c-4.5 0-8.8 .5-13 1.3c-11.7-15.4-30.2-25.3-51-25.3c-6.9 0-13.5 1.1-19.7 3.1C288.7 170.7 269.6 160 248 160c-2.7 0-5.4 .2-8 .5V64c0-35.3-28.7-64-64-64zm48 304c0-8.8-7.2-16-16-16s-16 7.2-16 16v96c0 8.8 7.2 16 16 16s16-7.2 16-16V304zm48-16c-8.8 0-16 7.2-16 16v96c0 8.8 7.2 16 16 16s16-7.2 16-16V304c0-8.8-7.2-16-16-16zm80 16c0-8.8-7.2-16-16-16s-16 7.2-16 16v96c0 8.8 7.2 16 16 16s16-7.2 16-16V304z"],
|
||||
"hand-scissors": [512, 512, [], "f257", "M.2 276.3c-1.2-35.3 26.4-65 61.7-66.2l3.3-.1L57 208.1C22.5 200.5 .7 166.3 8.3 131.8S50.2 75.5 84.7 83.2l173 38.3c2.3-2.9 4.7-5.7 7.1-8.5l18.4-20.3C299.9 74.5 323.5 64 348.3 64l10.2 0c54.1 0 104.1 28.7 131.3 75.4l1.5 2.6c13.6 23.2 20.7 49.7 20.7 76.6L512 344c0 66.3-53.7 120-120 120l-8 0-96 0c-35.3 0-64-28.7-64-64c0-2.8 .2-5.6 .5-8.3c-19.4-11-32.5-31.8-32.5-55.7c0-.8 0-1.6 0-2.4L66.4 338c-35.3 1.2-65-26.4-66.2-61.7zm63.4-18.2c-8.8 .3-15.7 7.7-15.4 16.5s7.7 15.7 16.5 15.4l161.5-5.6c9.8-.3 18.7 5.3 22.7 14.2s2.2 19.3-4.5 26.4c-2.8 2.9-4.4 6.7-4.4 11c0 8.8 7.2 16 16 16c9.1 0 17.4 5.1 21.5 13.3s3.2 17.9-2.3 25.1c-2 2.7-3.2 6-3.2 9.6c0 8.8 7.2 16 16 16l96 0 8 0c39.8 0 72-32.2 72-72l0-125.4c0-18.4-4.9-36.5-14.2-52.4l-1.5-2.6c-18.6-32-52.8-51.6-89.8-51.6l-10.2 0c-11.3 0-22 4.8-29.6 13.1l-17.5-15.9 17.5 15.9-18.4 20.3c-.6 .6-1.1 1.3-1.7 1.9l57 13.2c8.6 2 14 10.6 12 19.2s-10.6 14-19.2 12l-85.6-19.7L74.3 130c-8.6-1.9-17.2 3.5-19.1 12.2s3.5 17.2 12.2 19.1l187.5 41.6c10.2 2.3 17.8 10.9 18.7 21.4l.1 1c.6 6.6-1.5 13.1-5.8 18.1s-10.6 7.9-17.2 8.2L63.6 258.1z"],
|
||||
"face-grin-tears": [640, 512, [128514, "grin-tears"], "f588", "M516.1 325.5c1 3 2.1 6 3.3 8.9c3.3 8.1 8.4 18.5 16.5 26.6c3.9 3.9 8.2 7.4 12.7 10.3C506.4 454.8 419.9 512 320 512s-186.4-57.2-228.6-140.6c4.5-2.9 8.7-6.3 12.7-10.3c8.1-8.1 13.2-18.6 16.5-26.6c1.2-2.9 2.3-5.9 3.3-8.9C152.5 406.2 229.5 464 320 464s167.5-57.8 196.1-138.5zM320 48c-101.4 0-185.8 72.5-204.3 168.5c-6.7-3.1-14.3-4.3-22.3-3.1c-6.8 .9-16.2 2.4-26.6 4.4C85.3 94.5 191.6 0 320 0S554.7 94.5 573.2 217.7c-10.3-2-19.8-3.5-26.6-4.4c-8-1.2-15.7 .1-22.3 3.1C505.8 120.5 421.4 48 320 48zM78.5 341.1C60 356.7 32 355.5 14.3 337.7c-18.7-18.7-19.1-48.8-.7-67.2c8.6-8.6 30.1-15.1 50.5-19.6c13-2.8 25.5-4.8 33.9-6c5.4-.8 9.9 3.7 9 9c-3.1 21.5-11.4 70.2-25.5 84.4c-.9 1-1.9 1.8-2.9 2.7zm483 0c-.8-.6-1.5-1.3-2.3-2c-.2-.2-.5-.4-.7-.7c-14.1-14.1-22.5-62.9-25.5-84.4c-.8-5.4 3.7-9.9 9-9c1 .1 2.2 .3 3.3 .5c8.2 1.2 19.2 3 30.6 5.5c20.4 4.4 41.9 10.9 50.5 19.6c18.4 18.4 18 48.5-.7 67.2c-17.7 17.7-45.7 19-64.2 3.4zM439 336.5C414.4 374.6 370.3 400 319.9 400s-94.5-25.4-119.1-63.5c-10.4-16.1 6.8-32.5 25.5-28.1c28.9 6.8 60.5 10.5 93.6 10.5s64.7-3.7 93.6-10.5c18.7-4.4 35.9 12 25.5 28.1zM281.6 228.8l0 0-.2-.2c-.2-.2-.4-.5-.7-.9c-.6-.8-1.6-2-2.8-3.4c-2.5-2.8-6-6.6-10.2-10.3c-8.8-7.8-18.8-14-27.7-14s-18.9 6.2-27.7 14c-4.2 3.7-7.7 7.5-10.2 10.3c-1.2 1.4-2.2 2.6-2.8 3.4c-.3 .4-.6 .7-.7 .9l-.2 .2 0 0 0 0 0 0c-2.1 2.8-5.7 3.9-8.9 2.8s-5.5-4.1-5.5-7.6c0-17.9 6.7-35.6 16.6-48.8c9.8-13 23.9-23.2 39.4-23.2s29.6 10.2 39.4 23.2c9.9 13.2 16.6 30.9 16.6 48.8c0 3.4-2.2 6.5-5.5 7.6s-6.9 0-8.9-2.8l0 0 0 0 0 0zm160 0l0 0 0 0-.2-.2c-.2-.2-.4-.5-.7-.9c-.6-.8-1.6-2-2.8-3.4c-2.5-2.8-6-6.6-10.2-10.3c-8.8-7.8-18.8-14-27.7-14s-18.9 6.2-27.7 14c-4.2 3.7-7.7 7.5-10.2 10.3c-1.2 1.4-2.2 2.6-2.8 3.4c-.3 .4-.6 .7-.7 .9l-.2 .2 0 0 0 0 0 0c-2.1 2.8-5.7 3.9-8.9 2.8s-5.5-4.1-5.5-7.6c0-17.9 6.7-35.6 16.6-48.8c9.8-13 23.9-23.2 39.4-23.2s29.6 10.2 39.4 23.2c9.9 13.2 16.6 30.9 16.6 48.8c0 3.4-2.2 6.5-5.5 7.6s-6.9 0-8.9-2.8l0 0 0 0z"],
|
||||
"calendar-xmark": [512, 512, ["calendar-times"], "f273", "M160 0c13.3 0 24 10.7 24 24V64H328V24c0-13.3 10.7-24 24-24s24 10.7 24 24V64h40c35.3 0 64 28.7 64 64v16 48V448c0 35.3-28.7 64-64 64H96c-35.3 0-64-28.7-64-64V192 144 128c0-35.3 28.7-64 64-64h40V24c0-13.3 10.7-24 24-24zM432 192H80V448c0 8.8 7.2 16 16 16H416c8.8 0 16-7.2 16-16V192zm-95 89l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"],
|
||||
"file-video": [384, 512, [], "f1c8", "M320 464c8.8 0 16-7.2 16-16V160H256c-17.7 0-32-14.3-32-32V48H64c-8.8 0-16 7.2-16 16V448c0 8.8 7.2 16 16 16H320zM0 64C0 28.7 28.7 0 64 0H229.5c17 0 33.3 6.7 45.3 18.7l90.5 90.5c12 12 18.7 28.3 18.7 45.3V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V64zM80 288c0-17.7 14.3-32 32-32h96c17.7 0 32 14.3 32 32v16l44.9-29.9c2-1.3 4.4-2.1 6.8-2.1c6.8 0 12.3 5.5 12.3 12.3V387.7c0 6.8-5.5 12.3-12.3 12.3c-2.4 0-4.8-.7-6.8-2.1L240 368v16c0 17.7-14.3 32-32 32H112c-17.7 0-32-14.3-32-32V288z"],
|
||||
"file-pdf": [512, 512, [], "f1c1", "M64 464H96v48H64c-35.3 0-64-28.7-64-64V64C0 28.7 28.7 0 64 0H229.5c17 0 33.3 6.7 45.3 18.7l90.5 90.5c12 12 18.7 28.3 18.7 45.3V288H336V160H256c-17.7 0-32-14.3-32-32V48H64c-8.8 0-16 7.2-16 16V448c0 8.8 7.2 16 16 16zM176 352h32c30.9 0 56 25.1 56 56s-25.1 56-56 56H192v32c0 8.8-7.2 16-16 16s-16-7.2-16-16V448 368c0-8.8 7.2-16 16-16zm32 80c13.3 0 24-10.7 24-24s-10.7-24-24-24H192v48h16zm96-80h32c26.5 0 48 21.5 48 48v64c0 26.5-21.5 48-48 48H304c-8.8 0-16-7.2-16-16V368c0-8.8 7.2-16 16-16zm32 128c8.8 0 16-7.2 16-16V400c0-8.8-7.2-16-16-16H320v96h16zm80-112c0-8.8 7.2-16 16-16h48c8.8 0 16 7.2 16 16s-7.2 16-16 16H448v32h32c8.8 0 16 7.2 16 16s-7.2 16-16 16H448v48c0 8.8-7.2 16-16 16s-16-7.2-16-16V432 368z"],
|
||||
"comment": [512, 512, [128489, 61669], "f075", "M123.6 391.3c12.9-9.4 29.6-11.8 44.6-6.4c26.5 9.6 56.2 15.1 87.8 15.1c124.7 0 208-80.5 208-160s-83.3-160-208-160S48 160.5 48 240c0 32 12.4 62.8 35.7 89.2c8.6 9.7 12.8 22.5 11.8 35.5c-1.4 18.1-5.7 34.7-11.3 49.4c17-7.9 31.1-16.7 39.4-22.7zM21.2 431.9c1.8-2.7 3.5-5.4 5.1-8.1c10-16.6 19.5-38.4 21.4-62.9C17.7 326.8 0 285.1 0 240C0 125.1 114.6 32 256 32s256 93.1 256 208s-114.6 208-256 208c-37.1 0-72.3-6.4-104.1-17.9c-11.9 8.7-31.3 20.6-54.3 30.6c-15.1 6.6-32.3 12.6-50.1 16.1c-.8 .2-1.6 .3-2.4 .5c-4.4 .8-8.7 1.5-13.2 1.9c-.2 0-.5 .1-.7 .1c-5.1 .5-10.2 .8-15.3 .8c-6.5 0-12.3-3.9-14.8-9.9c-2.5-6-1.1-12.8 3.4-17.4c4.1-4.2 7.8-8.7 11.3-13.5c1.7-2.3 3.3-4.6 4.8-6.9c.1-.2 .2-.3 .3-.5z"],
|
||||
"envelope": [512, 512, [128386, 9993, 61443], "f0e0", "M64 112c-8.8 0-16 7.2-16 16v22.1L220.5 291.7c20.7 17 50.4 17 71.1 0L464 150.1V128c0-8.8-7.2-16-16-16H64zM48 212.2V384c0 8.8 7.2 16 16 16H448c8.8 0 16-7.2 16-16V212.2L322 328.8c-38.4 31.5-93.7 31.5-132 0L48 212.2zM0 128C0 92.7 28.7 64 64 64H448c35.3 0 64 28.7 64 64V384c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V128z"],
|
||||
"hourglass": [384, 512, [9203, 62032, "hourglass-empty"], "f254", "M24 0C10.7 0 0 10.7 0 24S10.7 48 24 48h8V67c0 40.3 16 79 44.5 107.5L158.1 256 76.5 337.5C48 366 32 404.7 32 445v19H24c-13.3 0-24 10.7-24 24s10.7 24 24 24H360c13.3 0 24-10.7 24-24s-10.7-24-24-24h-8V445c0-40.3-16-79-44.5-107.5L225.9 256l81.5-81.5C336 146 352 107.3 352 67V48h8c13.3 0 24-10.7 24-24s-10.7-24-24-24H24zM192 289.9l81.5 81.5C293 391 304 417.4 304 445v19H80V445c0-27.6 11-54 30.5-73.5L192 289.9zm0-67.9l-81.5-81.5C91 121 80 94.6 80 67V48H304V67c0 27.6-11 54-30.5 73.5L192 222.1z"],
|
||||
"calendar-check": [448, 512, [], "f274", "M128 0c13.3 0 24 10.7 24 24V64H296V24c0-13.3 10.7-24 24-24s24 10.7 24 24V64h40c35.3 0 64 28.7 64 64v16 48V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V192 144 128C0 92.7 28.7 64 64 64h40V24c0-13.3 10.7-24 24-24zM400 192H48V448c0 8.8 7.2 16 16 16H384c8.8 0 16-7.2 16-16V192zM329 297L217 409c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47 95-95c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"],
|
||||
"hard-drive": [512, 512, [128436, "hdd"], "f0a0", "M64 80c-8.8 0-16 7.2-16 16V258c5.1-1.3 10.5-2 16-2H448c5.5 0 10.9 .7 16 2V96c0-8.8-7.2-16-16-16H64zM48 320v96c0 8.8 7.2 16 16 16H448c8.8 0 16-7.2 16-16V320c0-8.8-7.2-16-16-16H64c-8.8 0-16 7.2-16 16zM0 320V96C0 60.7 28.7 32 64 32H448c35.3 0 64 28.7 64 64V320v96c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V320zm280 48a24 24 0 1 1 48 0 24 24 0 1 1 -48 0zm120-24a24 24 0 1 1 0 48 24 24 0 1 1 0-48z"],
|
||||
"face-grin-squint-tears": [512, 512, [129315, "grin-squint-tears"], "f586", "M426.8 14.2C446-5 477.5-4.6 497.1 14.9s20 51 .7 70.3c-14.8 14.8-65.7 23.6-88.3 26.7c-5.6 .9-10.3-3.9-9.5-9.5C403.3 79.9 412 29 426.8 14.2zM75 75C158.2-8.3 284.5-22.2 382.2 33.2c-1.5 4.8-2.9 9.6-4.1 14.3c-3.1 12.2-5.5 24.6-7.3 35c-80.8-53.6-190.7-44.8-261.9 26.4C37.7 180.1 28.9 290 82.5 370.8c-10.5 1.8-22.9 4.2-35 7.3c-4.7 1.2-9.5 2.5-14.3 4.1C-22.2 284.5-8.2 158.2 75 75zm389.6 58.9c4.7-1.2 9.5-2.5 14.3-4.1C534.2 227.5 520.2 353.8 437 437c-83.2 83.2-209.5 97.2-307.2 41.8c1.5-4.8 2.8-9.6 4-14.3c3.1-12.2 5.5-24.6 7.3-35c80.8 53.6 190.7 44.8 261.9-26.4c71.2-71.2 80-181.1 26.4-261.9c10.5-1.8 22.9-4.2 35-7.3zm-105.4 93c10.1-16.3 33.9-16.9 37.9 1.9c9.5 44.4-3.7 93.5-39.3 129.1s-84.8 48.8-129.1 39.3c-18.7-4-18.2-27.8-1.9-37.9c25.2-15.7 50.2-35.4 73.6-58.8s43.1-48.4 58.8-73.6zM92 265.3l97.4-29.7c11.6-3.5 22.5 7.3 19 19l-29.7 97.4c-2.6 8.6-13.4 11.3-19.8 4.9c-2-2-3.2-4.6-3.4-7.3l-5.1-56.1-56.1-5.1c-2.8-.3-5.4-1.5-7.3-3.4c-6.3-6.3-3.6-17.2 4.9-19.8zm193-178.2c2 2 3.2 4.6 3.4 7.3l5.1 56.1 56.1 5.1c2.8 .3 5.4 1.5 7.3 3.4c6.3 6.3 3.6 17.2-4.9 19.8l-97.4 29.7c-11.6 3.5-22.5-7.3-19-19L265.3 92c2.6-8.6 13.4-11.3 19.8-4.9zM14.9 497.1c-19.6-19.6-20-51-.7-70.3C29 412 79.8 403.2 102.4 400.1c5.6-.9 10.3 3.9 9.5 9.5c-3.2 22.5-11.9 73.5-26.7 88.3C66 517 34.5 516.6 14.9 497.1z"],
|
||||
"rectangle-list": [576, 512, ["list-alt"], "f022", "M64 80c-8.8 0-16 7.2-16 16V416c0 8.8 7.2 16 16 16H512c8.8 0 16-7.2 16-16V96c0-8.8-7.2-16-16-16H64zM0 96C0 60.7 28.7 32 64 32H512c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V96zm96 64a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zm104 0c0-13.3 10.7-24 24-24H448c13.3 0 24 10.7 24 24s-10.7 24-24 24H224c-13.3 0-24-10.7-24-24zm0 96c0-13.3 10.7-24 24-24H448c13.3 0 24 10.7 24 24s-10.7 24-24 24H224c-13.3 0-24-10.7-24-24zm0 96c0-13.3 10.7-24 24-24H448c13.3 0 24 10.7 24 24s-10.7 24-24 24H224c-13.3 0-24-10.7-24-24zm-72-64a32 32 0 1 1 0-64 32 32 0 1 1 0 64zM96 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"],
|
||||
"calendar-plus": [512, 512, [], "f271", "M184 24c0-13.3-10.7-24-24-24s-24 10.7-24 24V64H96c-35.3 0-64 28.7-64 64v16 48V448c0 35.3 28.7 64 64 64H416c35.3 0 64-28.7 64-64V192 144 128c0-35.3-28.7-64-64-64H376V24c0-13.3-10.7-24-24-24s-24 10.7-24 24V64H184V24zM80 192H432V448c0 8.8-7.2 16-16 16H96c-8.8 0-16-7.2-16-16V192zm176 40c-13.3 0-24 10.7-24 24v48H184c-13.3 0-24 10.7-24 24s10.7 24 24 24h48v48c0 13.3 10.7 24 24 24s24-10.7 24-24V352h48c13.3 0 24-10.7 24-24s-10.7-24-24-24H280V256c0-13.3-10.7-24-24-24z"],
|
||||
"circle-left": [512, 512, [61840, "arrow-alt-circle-left"], "f359", "M48 256a208 208 0 1 1 416 0A208 208 0 1 1 48 256zm464 0A256 256 0 1 0 0 256a256 256 0 1 0 512 0zM217.4 376.9c4.2 4.5 10.1 7.1 16.3 7.1c12.3 0 22.3-10 22.3-22.3V304h96c17.7 0 32-14.3 32-32V240c0-17.7-14.3-32-32-32H256V150.3c0-12.3-10-22.3-22.3-22.3c-6.2 0-12.1 2.6-16.3 7.1L117.5 242.2c-3.5 3.8-5.5 8.7-5.5 13.8s2 10.1 5.5 13.8l99.9 107.1z"],
|
||||
"money-bill-1": [576, 512, ["money-bill-alt"], "f3d1", "M112 112c0 35.3-28.7 64-64 64V336c35.3 0 64 28.7 64 64H464c0-35.3 28.7-64 64-64V176c-35.3 0-64-28.7-64-64H112zM0 128C0 92.7 28.7 64 64 64H512c35.3 0 64 28.7 64 64V384c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V128zM176 256a112 112 0 1 1 224 0 112 112 0 1 1 -224 0zm80-48c0 8.8 7.2 16 16 16v64h-8c-8.8 0-16 7.2-16 16s7.2 16 16 16h24 24c8.8 0 16-7.2 16-16s-7.2-16-16-16h-8V208c0-8.8-7.2-16-16-16H272c-8.8 0-16 7.2-16 16z"],
|
||||
"clock": [512, 512, [128339, "clock-four"], "f017", "M464 256A208 208 0 1 1 48 256a208 208 0 1 1 416 0zM0 256a256 256 0 1 0 512 0A256 256 0 1 0 0 256zM232 120V256c0 8 4 15.5 10.7 20l96 64c11 7.4 25.9 4.4 33.3-6.7s4.4-25.9-6.7-33.3L280 243.2V120c0-13.3-10.7-24-24-24s-24 10.7-24 24z"],
|
||||
"keyboard": [576, 512, [9000], "f11c", "M64 112c-8.8 0-16 7.2-16 16V384c0 8.8 7.2 16 16 16H512c8.8 0 16-7.2 16-16V128c0-8.8-7.2-16-16-16H64zM0 128C0 92.7 28.7 64 64 64H512c35.3 0 64 28.7 64 64V384c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V128zM176 320H400c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H176c-8.8 0-16-7.2-16-16V336c0-8.8 7.2-16 16-16zm-72-72c0-8.8 7.2-16 16-16h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H120c-8.8 0-16-7.2-16-16V248zm16-96h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H120c-8.8 0-16-7.2-16-16V168c0-8.8 7.2-16 16-16zm64 96c0-8.8 7.2-16 16-16h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H200c-8.8 0-16-7.2-16-16V248zm16-96h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H200c-8.8 0-16-7.2-16-16V168c0-8.8 7.2-16 16-16zm64 96c0-8.8 7.2-16 16-16h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H280c-8.8 0-16-7.2-16-16V248zm16-96h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H280c-8.8 0-16-7.2-16-16V168c0-8.8 7.2-16 16-16zm64 96c0-8.8 7.2-16 16-16h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H360c-8.8 0-16-7.2-16-16V248zm16-96h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H360c-8.8 0-16-7.2-16-16V168c0-8.8 7.2-16 16-16zm64 96c0-8.8 7.2-16 16-16h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H440c-8.8 0-16-7.2-16-16V248zm16-96h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H440c-8.8 0-16-7.2-16-16V168c0-8.8 7.2-16 16-16z"],
|
||||
"closed-captioning": [576, 512, [], "f20a", "M512 80c8.8 0 16 7.2 16 16V416c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16V96c0-8.8 7.2-16 16-16H512zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H512c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zM200 208c14.2 0 27 6.1 35.8 16c8.8 9.9 24 10.7 33.9 1.9s10.7-24 1.9-33.9c-17.5-19.6-43.1-32-71.5-32c-53 0-96 43-96 96s43 96 96 96c28.4 0 54-12.4 71.5-32c8.8-9.9 8-25-1.9-33.9s-25-8-33.9 1.9c-8.8 9.9-21.6 16-35.8 16c-26.5 0-48-21.5-48-48s21.5-48 48-48zm144 48c0-26.5 21.5-48 48-48c14.2 0 27 6.1 35.8 16c8.8 9.9 24 10.7 33.9 1.9s10.7-24 1.9-33.9c-17.5-19.6-43.1-32-71.5-32c-53 0-96 43-96 96s43 96 96 96c28.4 0 54-12.4 71.5-32c8.8-9.9 8-25-1.9-33.9s-25-8-33.9 1.9c-8.8 9.9-21.6 16-35.8 16c-26.5 0-48-21.5-48-48z"],
|
||||
"images": [576, 512, [], "f302", "M160 80H512c8.8 0 16 7.2 16 16V320c0 8.8-7.2 16-16 16H490.8L388.1 178.9c-4.4-6.8-12-10.9-20.1-10.9s-15.7 4.1-20.1 10.9l-52.2 79.8-12.4-16.9c-4.5-6.2-11.7-9.8-19.4-9.8s-14.8 3.6-19.4 9.8L175.6 336H160c-8.8 0-16-7.2-16-16V96c0-8.8 7.2-16 16-16zM96 96V320c0 35.3 28.7 64 64 64H512c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H160c-35.3 0-64 28.7-64 64zM48 120c0-13.3-10.7-24-24-24S0 106.7 0 120V344c0 75.1 60.9 136 136 136H456c13.3 0 24-10.7 24-24s-10.7-24-24-24H136c-48.6 0-88-39.4-88-88V120zm208 24a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"],
|
||||
"face-grin": [512, 512, [128512, "grin"], "f580", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm349.5 52.4c18.7-4.4 35.9 12 25.5 28.1C350.4 374.6 306.3 400 255.9 400s-94.5-25.4-119.1-63.5c-10.4-16.1 6.8-32.5 25.5-28.1c28.9 6.8 60.5 10.5 93.6 10.5s64.7-3.7 93.6-10.5zM144.4 208a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zm192-32a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"],
|
||||
"face-meh": [512, 512, [128528, "meh"], "f11a", "M464 256A208 208 0 1 1 48 256a208 208 0 1 1 416 0zM256 0a256 256 0 1 0 0 512A256 256 0 1 0 256 0zM176.4 240a32 32 0 1 0 0-64 32 32 0 1 0 0 64zm192-32a32 32 0 1 0 -64 0 32 32 0 1 0 64 0zM184 328c-13.3 0-24 10.7-24 24s10.7 24 24 24H328c13.3 0 24-10.7 24-24s-10.7-24-24-24H184z"],
|
||||
"id-card": [576, 512, [62147, "drivers-license"], "f2c2", "M528 160V416c0 8.8-7.2 16-16 16H320c0-44.2-35.8-80-80-80H176c-44.2 0-80 35.8-80 80H64c-8.8 0-16-7.2-16-16V160H528zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H512c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zM272 256a64 64 0 1 0 -128 0 64 64 0 1 0 128 0zm104-48c-13.3 0-24 10.7-24 24s10.7 24 24 24h80c13.3 0 24-10.7 24-24s-10.7-24-24-24H376zm0 96c-13.3 0-24 10.7-24 24s10.7 24 24 24h80c13.3 0 24-10.7 24-24s-10.7-24-24-24H376z"],
|
||||
"sun": [512, 512, [9728], "f185", "M375.7 19.7c-1.5-8-6.9-14.7-14.4-17.8s-16.1-2.2-22.8 2.4L256 61.1 173.5 4.2c-6.7-4.6-15.3-5.5-22.8-2.4s-12.9 9.8-14.4 17.8l-18.1 98.5L19.7 136.3c-8 1.5-14.7 6.9-17.8 14.4s-2.2 16.1 2.4 22.8L61.1 256 4.2 338.5c-4.6 6.7-5.5 15.3-2.4 22.8s9.8 13 17.8 14.4l98.5 18.1 18.1 98.5c1.5 8 6.9 14.7 14.4 17.8s16.1 2.2 22.8-2.4L256 450.9l82.5 56.9c6.7 4.6 15.3 5.5 22.8 2.4s12.9-9.8 14.4-17.8l18.1-98.5 98.5-18.1c8-1.5 14.7-6.9 17.8-14.4s2.2-16.1-2.4-22.8L450.9 256l56.9-82.5c4.6-6.7 5.5-15.3 2.4-22.8s-9.8-12.9-17.8-14.4l-98.5-18.1L375.7 19.7zM269.6 110l65.6-45.2 14.4 78.3c1.8 9.8 9.5 17.5 19.3 19.3l78.3 14.4L402 242.4c-5.7 8.2-5.7 19 0 27.2l45.2 65.6-78.3 14.4c-9.8 1.8-17.5 9.5-19.3 19.3l-14.4 78.3L269.6 402c-8.2-5.7-19-5.7-27.2 0l-65.6 45.2-14.4-78.3c-1.8-9.8-9.5-17.5-19.3-19.3L64.8 335.2 110 269.6c5.7-8.2 5.7-19 0-27.2L64.8 176.8l78.3-14.4c9.8-1.8 17.5-9.5 19.3-19.3l14.4-78.3L242.4 110c8.2 5.7 19 5.7 27.2 0zM256 368a112 112 0 1 0 0-224 112 112 0 1 0 0 224zM192 256a64 64 0 1 1 128 0 64 64 0 1 1 -128 0z"],
|
||||
"face-laugh-wink": [512, 512, ["laugh-wink"], "f59c", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm130.7 57.9c-4.2-13.6 7.1-25.9 21.3-25.9H364.5c14.2 0 25.5 12.4 21.3 25.9C369 368.4 318.2 408 258.2 408s-110.8-39.6-127.5-94.1zM144.4 192a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zm165.8 21.7c-7.6 8.1-20.2 8.5-28.3 .9s-8.5-20.2-.9-28.3c14.5-15.5 35.2-22.3 54.6-22.3s40.1 6.8 54.6 22.3c7.6 8.1 7.1 20.7-.9 28.3s-20.7 7.1-28.3-.9c-5.5-5.8-14.8-9.7-25.4-9.7s-19.9 3.8-25.4 9.7z"],
|
||||
"circle-down": [512, 512, [61466, "arrow-alt-circle-down"], "f358", "M256 464a208 208 0 1 1 0-416 208 208 0 1 1 0 416zM256 0a256 256 0 1 0 0 512A256 256 0 1 0 256 0zM376.9 294.6c4.5-4.2 7.1-10.1 7.1-16.3c0-12.3-10-22.3-22.3-22.3H304V160c0-17.7-14.3-32-32-32l-32 0c-17.7 0-32 14.3-32 32v96H150.3C138 256 128 266 128 278.3c0 6.2 2.6 12.1 7.1 16.3l107.1 99.9c3.8 3.5 8.7 5.5 13.8 5.5s10.1-2 13.8-5.5l107.1-99.9z"],
|
||||
"thumbs-down": [512, 512, [128078, 61576], "f165", "M323.8 477.2c-38.2 10.9-78.1-11.2-89-49.4l-5.7-20c-3.7-13-10.4-25-19.5-35l-51.3-56.4c-8.9-9.8-8.2-25 1.6-33.9s25-8.2 33.9 1.6l51.3 56.4c14.1 15.5 24.4 34 30.1 54.1l5.7 20c3.6 12.7 16.9 20.1 29.7 16.5s20.1-16.9 16.5-29.7l-5.7-20c-5.7-19.9-14.7-38.7-26.6-55.5c-5.2-7.3-5.8-16.9-1.7-24.9s12.3-13 21.3-13L448 288c8.8 0 16-7.2 16-16c0-6.8-4.3-12.7-10.4-15c-7.4-2.8-13-9-14.9-16.7s.1-15.8 5.3-21.7c2.5-2.8 4-6.5 4-10.6c0-7.8-5.6-14.3-13-15.7c-8.2-1.6-15.1-7.3-18-15.2s-1.6-16.7 3.6-23.3c2.1-2.7 3.4-6.1 3.4-9.9c0-6.7-4.2-12.6-10.2-14.9c-11.5-4.5-17.7-16.9-14.4-28.8c.4-1.3 .6-2.8 .6-4.3c0-8.8-7.2-16-16-16H286.5c-12.6 0-25 3.7-35.5 10.7l-61.7 41.1c-11 7.4-25.9 4.4-33.3-6.7s-4.4-25.9 6.7-33.3l61.7-41.1c18.4-12.3 40-18.8 62.1-18.8H384c34.7 0 62.9 27.6 64 62c14.6 11.7 24 29.7 24 50c0 4.5-.5 8.8-1.3 13c15.4 11.7 25.3 30.2 25.3 51c0 6.5-1 12.8-2.8 18.7C504.8 238.3 512 254.3 512 272c0 35.3-28.6 64-64 64l-92.3 0c4.7 10.4 8.7 21.2 11.8 32.2l5.7 20c10.9 38.2-11.2 78.1-49.4 89zM32 384c-17.7 0-32-14.3-32-32V128c0-17.7 14.3-32 32-32H96c17.7 0 32 14.3 32 32V352c0 17.7-14.3 32-32 32H32z"],
|
||||
"chess-pawn": [320, 512, [9823], "f443", "M232 152A72 72 0 1 0 88 152a72 72 0 1 0 144 0zm24 120H243.4l10.7 80H205.7L195 272H160 125l-10.7 80H65.9l10.7-80H64c-13.3 0-24-10.7-24-24s10.7-24 24-24c-15.1-20.1-24-45-24-72C40 85.7 93.7 32 160 32s120 53.7 120 120c0 27-8.9 51.9-24 72c13.3 0 24 10.7 24 24s-10.7 24-24 24zM52.7 464H267.3l-16.6-32H69.2L52.7 464zm207.9-80c12 0 22.9 6.7 28.4 17.3l26.5 51.2c3 5.8 4.6 12.2 4.6 18.7c0 22.5-18.2 40.8-40.8 40.8H40.8C18.2 512 0 493.8 0 471.2c0-6.5 1.6-12.9 4.6-18.7l26.5-51.2C36.5 390.7 47.5 384 59.5 384h201z"],
|
||||
"credit-card": [576, 512, [128179, 62083, "credit-card-alt"], "f09d", "M512 80c8.8 0 16 7.2 16 16v32H48V96c0-8.8 7.2-16 16-16H512zm16 144V416c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16V224H528zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H512c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zm56 304c-13.3 0-24 10.7-24 24s10.7 24 24 24h48c13.3 0 24-10.7 24-24s-10.7-24-24-24H120zm128 0c-13.3 0-24 10.7-24 24s10.7 24 24 24H360c13.3 0 24-10.7 24-24s-10.7-24-24-24H248z"],
|
||||
"bell": [448, 512, [128276, 61602], "f0f3", "M224 0c-17.7 0-32 14.3-32 32V49.9C119.5 61.4 64 124.2 64 200v33.4c0 45.4-15.5 89.5-43.8 124.9L5.3 377c-5.8 7.2-6.9 17.1-2.9 25.4S14.8 416 24 416H424c9.2 0 17.6-5.3 21.6-13.6s2.9-18.2-2.9-25.4l-14.9-18.6C399.5 322.9 384 278.8 384 233.4V200c0-75.8-55.5-138.6-128-150.1V32c0-17.7-14.3-32-32-32zm0 96h8c57.4 0 104 46.6 104 104v33.4c0 47.9 13.9 94.6 39.7 134.6H72.3C98.1 328 112 281.3 112 233.4V200c0-57.4 46.6-104 104-104h8zm64 352H224 160c0 17 6.7 33.3 18.7 45.3s28.3 18.7 45.3 18.7s33.3-6.7 45.3-18.7s18.7-28.3 18.7-45.3z"],
|
||||
"file": [384, 512, [128196, 128459, 61462], "f15b", "M320 464c8.8 0 16-7.2 16-16V160H256c-17.7 0-32-14.3-32-32V48H64c-8.8 0-16 7.2-16 16V448c0 8.8 7.2 16 16 16H320zM0 64C0 28.7 28.7 0 64 0H229.5c17 0 33.3 6.7 45.3 18.7l90.5 90.5c12 12 18.7 28.3 18.7 45.3V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V64z"],
|
||||
"hospital": [640, 512, [127973, 62589, "hospital-alt", "hospital-wide"], "f0f8", "M232 0c-39.8 0-72 32.2-72 72v8H72C32.2 80 0 112.2 0 152V440c0 39.8 32.2 72 72 72h.2 .2 .2 .2 .2H73h.2 .2 .2 .2 .2 .2 .2 .2 .2 .2H75h.2 .2 .2 .2 .2 .2 .2 .2 .2 .2H77h.2 .2 .2 .2 .2 .2 .2 .2 .2 .2H79h.2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2H82h.2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2H85h.2 .2 .2 .2H86h.2 .2 .2 .2H87h.2 .2 .2 .2H88h.2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2H98h.2 .2 .2 .2H99h.2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2v0H456h8v0H568c39.8 0 72-32.2 72-72V152c0-39.8-32.2-72-72-72H480V72c0-39.8-32.2-72-72-72H232zM480 128h88c13.3 0 24 10.7 24 24v40H536c-13.3 0-24 10.7-24 24s10.7 24 24 24h56v48H536c-13.3 0-24 10.7-24 24s10.7 24 24 24h56V440c0 13.3-10.7 24-24 24H480V336 128zM72 128h88V464h-.1-.2-.2-.2H159h-.2-.2-.2H158h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H154h-.2-.2-.2H153h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H150h-.2-.2-.2H149h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H146h-.2-.2-.2H145h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H142h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H139h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H136h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H133h-.2-.2-.2-.2-.2-.2-.2-.2H131h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H128h-.2-.2-.2-.2-.2-.2-.2-.2H126h-.2-.2-.2-.2-.2-.2-.2-.2H124h-.2-.2-.2-.2-.2-.2-.2-.2H122h-.2-.2-.2-.2-.2-.2-.2-.2H120h-.2-.2-.2-.2-.2-.2-.2-.2H118h-.2-.2-.2-.2-.2-.2-.2-.2H116h-.2-.2-.2-.2-.2-.2-.2-.2H114h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H111h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H108h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H105h-.2-.2-.2-.2H104h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H100h-.2-.2-.2-.2H99h-.2-.2-.2-.2H98h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H88h-.2-.2-.2-.2H87h-.2-.2-.2-.2H86h-.2-.2-.2-.2H85h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H82h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H79h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H77h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H75h-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2H73h-.2-.2-.2-.2-.2H72c-13.2 0-24-10.7-24-24V336h56c13.3 0 24-10.7 24-24s-10.7-24-24-24H48V240h56c13.3 0 24-10.7 24-24s-10.7-24-24-24H48V152c0-13.3 10.7-24 24-24zM208 72c0-13.3 10.7-24 24-24H408c13.3 0 24 10.7 24 24V336 464H368V400c0-26.5-21.5-48-48-48s-48 21.5-48 48v64H208V72zm88 24v24H272c-8.8 0-16 7.2-16 16v16c0 8.8 7.2 16 16 16h24v24c0 8.8 7.2 16 16 16h16c8.8 0 16-7.2 16-16V168h24c8.8 0 16-7.2 16-16V136c0-8.8-7.2-16-16-16H344V96c0-8.8-7.2-16-16-16H312c-8.8 0-16 7.2-16 16z"],
|
||||
"chess-rook": [448, 512, [9820], "f447", "M80 80V192c0 2.5 1.2 4.9 3.2 6.4l51.2 38.4c6.8 5.1 10.4 13.4 9.5 21.9L133.5 352H85.2l9.4-85L54.4 236.8C40.3 226.2 32 209.6 32 192V72c0-22.1 17.9-40 40-40H376c22.1 0 40 17.9 40 40V192c0 17.6-8.3 34.2-22.4 44.8L353.4 267l9.4 85H314.5l-10.4-93.3c-.9-8.4 2.7-16.8 9.5-21.9l51.2-38.4c2-1.5 3.2-3.9 3.2-6.4V80H304v24c0 13.3-10.7 24-24 24s-24-10.7-24-24V80H192v24c0 13.3-10.7 24-24 24s-24-10.7-24-24V80H80zm4.7 384H363.3l-16.6-32H101.2L84.7 464zm271.9-80c12 0 22.9 6.7 28.4 17.3l26.5 51.2c3 5.8 4.6 12.2 4.6 18.7c0 22.5-18.2 40.8-40.8 40.8H72.8C50.2 512 32 493.8 32 471.2c0-6.5 1.6-12.9 4.6-18.7l26.5-51.2C68.5 390.7 79.5 384 91.5 384h265zM208 288c-8.8 0-16-7.2-16-16V224c0-17.7 14.3-32 32-32s32 14.3 32 32v48c0 8.8-7.2 16-16 16H208z"],
|
||||
"star-half": [576, 512, [61731], "f089", "M293.3 .6c10.9 2.5 18.6 12.2 18.6 23.4V408.7c0 8.9-4.9 17-12.7 21.2L151 509.1c-8.1 4.3-17.9 3.7-25.3-1.7s-11.2-14.5-9.7-23.5l26.2-155.6L31.1 218.2c-6.5-6.4-8.7-15.9-5.9-24.5s10.3-14.9 19.3-16.3l153.2-22.6L266.3 13.5c4.9-10.1 16.1-15.4 27-12.9zM263.9 128.4l-28.6 58.8c-3.5 7.1-10.2 12.1-18.1 13.3L99 217.9 184.9 303c5.5 5.5 8.1 13.3 6.8 21L171.4 443.7l92.5-49.4V128.4z"],
|
||||
"chess-king": [448, 512, [9818], "f43f", "M248 24c0-13.3-10.7-24-24-24s-24 10.7-24 24V56H168c-13.3 0-24 10.7-24 24s10.7 24 24 24h32v40H59.6C26.7 144 0 170.7 0 203.6c0 8.2 1.7 16.3 4.9 23.8L59.1 352h52.3L49 208.2c-.6-1.5-1-3-1-4.6c0-6.4 5.2-11.6 11.6-11.6H224 388.4c6.4 0 11.6 5.2 11.6 11.6c0 1.6-.3 3.2-1 4.6L336.5 352h52.3l54.2-124.6c3.3-7.5 4.9-15.6 4.9-23.8c0-32.9-26.7-59.6-59.6-59.6H248V104h32c13.3 0 24-10.7 24-24s-10.7-24-24-24H248V24zM101.2 432H346.8l16.6 32H84.7l16.6-32zm283.7-30.7c-5.5-10.6-16.5-17.3-28.4-17.3H91.5c-12 0-22.9 6.7-28.4 17.3L36.6 452.5c-3 5.8-4.6 12.2-4.6 18.7C32 493.8 50.2 512 72.8 512H375.2c22.5 0 40.8-18.2 40.8-40.8c0-6.5-1.6-12.9-4.6-18.7l-26.5-51.2z"],
|
||||
"circle-user": [512, 512, [62142, "user-circle"], "f2bd", "M406.5 399.6C387.4 352.9 341.5 320 288 320H224c-53.5 0-99.4 32.9-118.5 79.6C69.9 362.2 48 311.7 48 256C48 141.1 141.1 48 256 48s208 93.1 208 208c0 55.7-21.9 106.2-57.5 143.6zm-40.1 32.7C334.4 452.4 296.6 464 256 464s-78.4-11.6-110.5-31.7c7.3-36.7 39.7-64.3 78.5-64.3h64c38.8 0 71.2 27.6 78.5 64.3zM256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zm0-272a40 40 0 1 1 0-80 40 40 0 1 1 0 80zm-88-40a88 88 0 1 0 176 0 88 88 0 1 0 -176 0z"],
|
||||
"copy": [512, 512, [], "f0c5", "M448 384H256c-35.3 0-64-28.7-64-64V64c0-35.3 28.7-64 64-64H396.1c12.7 0 24.9 5.1 33.9 14.1l67.9 67.9c9 9 14.1 21.2 14.1 33.9V320c0 35.3-28.7 64-64 64zM64 128h96v48H64c-8.8 0-16 7.2-16 16V448c0 8.8 7.2 16 16 16H256c8.8 0 16-7.2 16-16V416h48v32c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V192c0-35.3 28.7-64 64-64z"],
|
||||
"share-from-square": [576, 512, [61509, "share-square"], "f14d", "M400 255.4V240 208c0-8.8-7.2-16-16-16H352 336 289.5c-50.9 0-93.9 33.5-108.3 79.6c-3.3-9.4-5.2-19.8-5.2-31.6c0-61.9 50.1-112 112-112h48 16 32c8.8 0 16-7.2 16-16V80 64.6L506 160 400 255.4zM336 240h16v48c0 17.7 14.3 32 32 32h3.7c7.9 0 15.5-2.9 21.4-8.2l139-125.1c7.6-6.8 11.9-16.5 11.9-26.7s-4.3-19.9-11.9-26.7L409.9 8.9C403.5 3.2 395.3 0 386.7 0C367.5 0 352 15.5 352 34.7V80H336 304 288c-88.4 0-160 71.6-160 160c0 60.4 34.6 99.1 63.9 120.9c5.9 4.4 11.5 8.1 16.7 11.2c4.4 2.7 8.5 4.9 11.9 6.6c3.4 1.7 6.2 3 8.2 3.9c2.2 1 4.6 1.4 7.1 1.4h2.5c9.8 0 17.8-8 17.8-17.8c0-7.8-5.3-14.7-11.6-19.5l0 0c-.4-.3-.7-.5-1.1-.8c-1.7-1.1-3.4-2.5-5-4.1c-.8-.8-1.7-1.6-2.5-2.6s-1.6-1.9-2.4-2.9c-1.8-2.5-3.5-5.3-5-8.5c-2.6-6-4.3-13.3-4.3-22.4c0-36.1 29.3-65.5 65.5-65.5H304h32zM72 32C32.2 32 0 64.2 0 104V440c0 39.8 32.2 72 72 72H408c39.8 0 72-32.2 72-72V376c0-13.3-10.7-24-24-24s-24 10.7-24 24v64c0 13.3-10.7 24-24 24H72c-13.3 0-24-10.7-24-24V104c0-13.3 10.7-24 24-24h64c13.3 0 24-10.7 24-24s-10.7-24-24-24H72z"],
|
||||
"copyright": [512, 512, [169], "f1f9", "M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM199.4 312.6c-31.2-31.2-31.2-81.9 0-113.1s81.9-31.2 113.1 0c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9c-50-50-131-50-181 0s-50 131 0 181s131 50 181 0c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0c-31.2 31.2-81.9 31.2-113.1 0z"],
|
||||
"map": [576, 512, [128506, 62072], "f279", "M565.6 36.2C572.1 40.7 576 48.1 576 56V392c0 10-6.2 18.9-15.5 22.4l-168 64c-5.2 2-10.9 2.1-16.1 .3L192.5 417.5l-160 61c-7.4 2.8-15.7 1.8-22.2-2.7S0 463.9 0 456V120c0-10 6.1-18.9 15.5-22.4l168-64c5.2-2 10.9-2.1 16.1-.3L383.5 94.5l160-61c7.4-2.8 15.7-1.8 22.2 2.7zM48 136.5V421.2l120-45.7V90.8L48 136.5zM360 422.7V137.3l-144-48V374.7l144 48zm48-1.5l120-45.7V90.8L408 136.5V421.2z"],
|
||||
"bell-slash": [640, 512, [128277, 61943], "f1f6", "M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L542.6 400c2.7-7.8 1.3-16.5-3.9-23l-14.9-18.6C495.5 322.9 480 278.8 480 233.4V200c0-75.8-55.5-138.6-128-150.1V32c0-17.7-14.3-32-32-32s-32 14.3-32 32V49.9c-43.9 7-81.5 32.7-104.4 68.7L38.8 5.1zM221.7 148.4C239.6 117.1 273.3 96 312 96h8 8c57.4 0 104 46.6 104 104v33.4c0 32.7 6.4 64.8 18.7 94.5L221.7 148.4zM406.2 416l-60.9-48H168.3c21.2-32.8 34.4-70.3 38.4-109.1L160 222.1v11.4c0 45.4-15.5 89.5-43.8 124.9L101.3 377c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6H406.2zM384 448H320 256c0 17 6.7 33.3 18.7 45.3s28.3 18.7 45.3 18.7s33.3-6.7 45.3-18.7s18.7-28.3 18.7-45.3z"],
|
||||
"hand-lizard": [512, 512, [], "f258", "M72 112c-13.3 0-24 10.7-24 24s10.7 24 24 24H240c35.3 0 64 28.7 64 64s-28.7 64-64 64H136c-13.3 0-24 10.7-24 24s10.7 24 24 24H288c4.5 0 8.9 1.3 12.7 3.6l64 40c7 4.4 11.3 12.1 11.3 20.4v24c0 13.3-10.7 24-24 24s-24-10.7-24-24V413.3L281.1 384H136c-39.8 0-72-32.2-72-72s32.2-72 72-72H240c8.8 0 16-7.2 16-16s-7.2-16-16-16H72c-39.8 0-72-32.2-72-72S32.2 64 72 64H281.6c46.7 0 90.9 21.5 119.7 58.3l78.4 100.1c20.9 26.7 32.3 59.7 32.3 93.7V424c0 13.3-10.7 24-24 24s-24-10.7-24-24V316.1c0-23.2-7.8-45.8-22.1-64.1L363.5 151.9c-19.7-25.2-49.9-39.9-81.9-39.9H72z"],
|
||||
"face-smile": [512, 512, [128578, "smile"], "f118", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm177.6 62.1C192.8 334.5 218.8 352 256 352s63.2-17.5 78.4-33.9c9-9.7 24.2-10.4 33.9-1.4s10.4 24.2 1.4 33.9c-22 23.8-60 49.4-113.6 49.4s-91.7-25.5-113.6-49.4c-9-9.7-8.4-24.9 1.4-33.9s24.9-8.4 33.9 1.4zM144.4 208a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zm192-32a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"],
|
||||
"hand-peace": [512, 512, [9996], "f25b", "M250.8 1.4c-35.2-3.7-66.6 21.8-70.3 57L174 119 156.7 69.6C145 36.3 108.4 18.8 75.1 30.5S24.2 78.8 35.9 112.1L88.7 262.2C73.5 276.7 64 297.3 64 320v0 24c0 92.8 75.2 168 168 168h48c92.8 0 168-75.2 168-168V272 256 224c0-35.3-28.7-64-64-64c-7.9 0-15.4 1.4-22.4 4c-10.4-21.3-32.3-36-57.6-36c-.7 0-1.5 0-2.2 0l5.9-56.3c3.7-35.2-21.8-66.6-57-70.3zm-.2 155.4C243.9 166.9 240 179 240 192v48c0 .7 0 1.4 0 2c-5.1-1.3-10.5-2-16-2h-7.4l-5.4-15.3 17-161.3c.9-8.8 8.8-15.2 17.6-14.2s15.2 8.8 14.2 17.6l-9.5 90.1zM111.4 85.6L165.7 240H144c-4 0-8 .3-11.9 .9L81.2 96.2c-2.9-8.3 1.5-17.5 9.8-20.4s17.5 1.5 20.4 9.8zM288 192c0-8.8 7.2-16 16-16s16 7.2 16 16v32 16c0 8.8-7.2 16-16 16s-16-7.2-16-16V192zm38.4 108c10.4 21.3 32.3 36 57.6 36c5.5 0 10.9-.7 16-2v10c0 66.3-53.7 120-120 120H232c-66.3 0-120-53.7-120-120l0-24 0 0c0-17.7 14.3-32 32-32h80c8.8 0 16 7.2 16 16s-7.2 16-16 16H184c-13.3 0-24 10.7-24 24s10.7 24 24 24h40c35.3 0 64-28.7 64-64c0-.7 0-1.4 0-2c5.1 1.3 10.5 2 16 2c7.9 0 15.4-1.4 22.4-4zM400 272c0 8.8-7.2 16-16 16s-16-7.2-16-16V240 224c0-8.8 7.2-16 16-16s16 7.2 16 16v32 16z"],
|
||||
"face-grin-hearts": [512, 512, [128525, "grin-hearts"], "f584", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm349.5 52.4c18.7-4.4 35.9 12 25.5 28.1C350.4 374.6 306.3 400 255.9 400s-94.5-25.4-119.1-63.5c-10.4-16.1 6.8-32.5 25.5-28.1c28.9 6.8 60.5 10.5 93.6 10.5s64.7-3.7 93.6-10.5zM215.3 137.1c17.8 4.8 28.4 23.1 23.6 40.8l-17.4 65c-2.3 8.5-11.1 13.6-19.6 11.3l-65.1-17.4c-17.8-4.8-28.4-23.1-23.6-40.8s23.1-28.4 40.8-23.6l16.1 4.3 4.3-16.1c4.8-17.8 23.1-28.4 40.8-23.6zm122.3 23.6l4.3 16.1 16.1-4.3c17.8-4.8 36.1 5.8 40.8 23.6s-5.8 36.1-23.6 40.8l-65.1 17.4c-8.5 2.3-17.3-2.8-19.6-11.3l-17.4-65c-4.8-17.8 5.8-36.1 23.6-40.8s36.1 5.8 40.9 23.6z"],
|
||||
"building": [384, 512, [127970, 61687], "f1ad", "M64 48c-8.8 0-16 7.2-16 16V448c0 8.8 7.2 16 16 16h80V400c0-26.5 21.5-48 48-48s48 21.5 48 48v64h80c8.8 0 16-7.2 16-16V64c0-8.8-7.2-16-16-16H64zM0 64C0 28.7 28.7 0 64 0H320c35.3 0 64 28.7 64 64V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V64zm88 40c0-8.8 7.2-16 16-16h48c8.8 0 16 7.2 16 16v48c0 8.8-7.2 16-16 16H104c-8.8 0-16-7.2-16-16V104zM232 88h48c8.8 0 16 7.2 16 16v48c0 8.8-7.2 16-16 16H232c-8.8 0-16-7.2-16-16V104c0-8.8 7.2-16 16-16zM88 232c0-8.8 7.2-16 16-16h48c8.8 0 16 7.2 16 16v48c0 8.8-7.2 16-16 16H104c-8.8 0-16-7.2-16-16V232zm144-16h48c8.8 0 16 7.2 16 16v48c0 8.8-7.2 16-16 16H232c-8.8 0-16-7.2-16-16V232c0-8.8 7.2-16 16-16z"],
|
||||
"face-grin-beam-sweat": [512, 512, [128517, "grin-beam-sweat"], "f583", "M476.8 126.3C497.1 120.8 512 102.7 512 81c0-20-28.6-60.4-41.6-77.7c-3.2-4.4-9.6-4.4-12.8 0c-9.5 12.6-27.1 37.2-36 57.5c-.3 .7-.6 1.4-.9 2.1C417.8 69.7 416 76 416 81c0 26 21.5 47 48 47c4.4 0 8.7-.6 12.8-1.7zM395.4 41.2C355.3 15.2 307.4 0 256 0C114.6 0 0 114.6 0 256S114.6 512 256 512s256-114.6 256-256c0-35.8-7.3-69.9-20.6-100.8c-8.6 3.1-17.8 4.8-27.4 4.8c-8.9 0-17.6-1.5-25.7-4.2C454.7 185.5 464 219.7 464 256c0 114.9-93.1 208-208 208S48 370.9 48 256S141.1 48 256 48c48.7 0 93.4 16.7 128.9 44.7c-.6-3.8-.9-7.7-.9-11.7c0-11.4 3.8-22.4 7.1-30.5c1.3-3.1 2.7-6.2 4.3-9.3zM375 336.5c10.4-16.1-6.8-32.5-25.5-28.1c-28.9 6.8-60.5 10.5-93.6 10.5s-64.7-3.7-93.6-10.5c-18.7-4.4-35.9 12-25.5 28.1c24.6 38.1 68.7 63.5 119.1 63.5s94.5-25.4 119.1-63.5zM217.6 228.8l0 0 0 0 0 0c2.1 2.8 5.7 3.9 8.9 2.8s5.5-4.1 5.5-7.6c0-17.9-6.7-35.6-16.6-48.8c-9.8-13-23.9-23.2-39.4-23.2s-29.6 10.2-39.4 23.2C126.7 188.4 120 206.1 120 224c0 3.4 2.2 6.5 5.5 7.6s6.9 0 8.9-2.8l0 0 0 0 0 0 .2-.2c.2-.2 .4-.5 .7-.9c.6-.8 1.6-2 2.8-3.4c2.5-2.8 6-6.6 10.2-10.3c8.8-7.8 18.8-14 27.7-14s18.9 6.2 27.7 14c4.2 3.7 7.7 7.5 10.2 10.3c1.2 1.4 2.2 2.6 2.8 3.4c.3 .4 .6 .7 .7 .9l.2 .2 0 0zm160 0l0 0 0 0c2.1 2.8 5.7 3.9 8.9 2.8s5.5-4.1 5.5-7.6c0-17.9-6.7-35.6-16.6-48.8c-9.8-13-23.9-23.2-39.4-23.2s-29.6 10.2-39.4 23.2C286.7 188.4 280 206.1 280 224c0 3.4 2.2 6.5 5.5 7.6s6.9 0 8.9-2.8l0 0 0 0 0 0 .2-.2c.2-.2 .4-.5 .7-.9c.6-.8 1.6-2 2.8-3.4c2.5-2.8 6-6.6 10.2-10.3c8.8-7.8 18.8-14 27.7-14s18.9 6.2 27.7 14c4.2 3.7 7.7 7.5 10.2 10.3c1.2 1.4 2.2 2.6 2.8 3.4c.3 .4 .6 .7 .7 .9l.2 .2 0 0 0 0z"],
|
||||
"moon": [384, 512, [127769, 9214], "f186", "M144.7 98.7c-21 34.1-33.1 74.3-33.1 117.3c0 98 62.8 181.4 150.4 211.7c-12.4 2.8-25.3 4.3-38.6 4.3C126.6 432 48 353.3 48 256c0-68.9 39.4-128.4 96.8-157.3zm62.1-66C91.1 41.2 0 137.9 0 256C0 379.7 100 480 223.5 480c47.8 0 92-15 128.4-40.6c1.9-1.3 3.7-2.7 5.5-4c4.8-3.6 9.4-7.4 13.9-11.4c2.7-2.4 5.3-4.8 7.9-7.3c5-4.9 6.3-12.5 3.1-18.7s-10.1-9.7-17-8.5c-3.7 .6-7.4 1.2-11.1 1.6c-5 .5-10.1 .9-15.3 1c-1.2 0-2.5 0-3.7 0c-.1 0-.2 0-.3 0c-96.8-.2-175.2-78.9-175.2-176c0-54.8 24.9-103.7 64.1-136c1-.9 2.1-1.7 3.2-2.6c4-3.2 8.2-6.2 12.5-9c3.1-2 6.3-4 9.6-5.8c6.1-3.5 9.2-10.5 7.7-17.3s-7.3-11.9-14.3-12.5c-3.6-.3-7.1-.5-10.7-.6c-2.7-.1-5.5-.1-8.2-.1c-3.3 0-6.5 .1-9.8 .2c-2.3 .1-4.6 .2-6.9 .4z"],
|
||||
"calendar": [448, 512, [128197, 128198], "f133", "M152 24c0-13.3-10.7-24-24-24s-24 10.7-24 24V64H64C28.7 64 0 92.7 0 128v16 48V448c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V192 144 128c0-35.3-28.7-64-64-64H344V24c0-13.3-10.7-24-24-24s-24 10.7-24 24V64H152V24zM48 192H400V448c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16V192z"],
|
||||
"face-grin-tongue-wink": [512, 512, [128540, "grin-tongue-wink"], "f58b", "M348.3 442.4c2.4-8.4 3.7-17.3 3.7-26.4V363.5c8.8-8 16.6-17.1 23-27c10.4-16.1-6.8-32.5-25.5-28.1c-28.9 6.8-60.5 10.5-93.6 10.5s-64.7-3.7-93.6-10.5c-18.7-4.4-35.9 12-25.5 28.1c6.5 10 14.3 19.1 23.1 27.1V416c0 9.2 1.3 18 3.7 26.4C95.1 408.4 48 337.7 48 256C48 141.1 141.1 48 256 48s208 93.1 208 208c0 81.7-47.1 152.4-115.7 186.4zM256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM159.6 220c10.6 0 19.9 3.8 25.4 9.7c7.6 8.1 20.2 8.5 28.3 .9s8.5-20.2 .9-28.3C199.7 186.8 179 180 159.6 180s-40.1 6.8-54.6 22.3c-7.6 8.1-7.1 20.7 .9 28.3s20.7 7.1 28.3-.9c5.5-5.8 14.8-9.7 25.4-9.7zm176.7 12a24 24 0 1 0 0-48 24 24 0 1 0 0 48zm-.4-72a48 48 0 1 1 0 96 48 48 0 1 1 0-96zm0 128a80 80 0 1 0 0-160 80 80 0 1 0 0 160zM320 416c0 35.3-28.7 64-64 64s-64-28.7-64-64V378.6c0-14.7 11.9-26.6 26.6-26.6h2c11.3 0 21.1 7.9 23.6 18.9c2.8 12.6 20.8 12.6 23.6 0c2.5-11.1 12.3-18.9 23.6-18.9h2c14.7 0 26.6 11.9 26.6 26.6V416z"],
|
||||
"clone": [512, 512, [], "f24d", "M64 464H288c8.8 0 16-7.2 16-16V384h48v64c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V224c0-35.3 28.7-64 64-64h64v48H64c-8.8 0-16 7.2-16 16V448c0 8.8 7.2 16 16 16zM224 352c-35.3 0-64-28.7-64-64V64c0-35.3 28.7-64 64-64H448c35.3 0 64 28.7 64 64V288c0 35.3-28.7 64-64 64H224z"],
|
||||
"face-angry": [512, 512, [128544, "angry"], "f556", "M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zm72.4-118.5c9.7-9 10.2-24.2 1.2-33.9C315.3 344.3 290.6 328 256 328s-59.3 16.3-73.5 31.6c-9 9.7-8.5 24.9 1.2 33.9s24.9 8.5 33.9-1.2c7.4-7.9 20-16.4 38.5-16.4s31.1 8.5 38.5 16.4c9 9.7 24.2 10.2 33.9 1.2zM176.4 272c17.7 0 32-14.3 32-32c0-1.5-.1-3-.3-4.4l10.9 3.6c8.4 2.8 17.4-1.7 20.2-10.1s-1.7-17.4-10.1-20.2l-96-32c-8.4-2.8-17.4 1.7-20.2 10.1s1.7 17.4 10.1 20.2l30.7 10.2c-5.8 5.8-9.3 13.8-9.3 22.6c0 17.7 14.3 32 32 32zm192-32c0-8.9-3.6-17-9.5-22.8l30.2-10.1c8.4-2.8 12.9-11.9 10.1-20.2s-11.9-12.9-20.2-10.1l-96 32c-8.4 2.8-12.9 11.9-10.1 20.2s11.9 12.9 20.2 10.1l11.7-3.9c-.2 1.5-.3 3.1-.3 4.7c0 17.7 14.3 32 32 32s32-14.3 32-32z"],
|
||||
"rectangle-xmark": [512, 512, [62164, "rectangle-times", "times-rectangle", "window-close"], "f410", "M64 80c-8.8 0-16 7.2-16 16V416c0 8.8 7.2 16 16 16H448c8.8 0 16-7.2 16-16V96c0-8.8-7.2-16-16-16H64zM0 96C0 60.7 28.7 32 64 32H448c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V96zm175 79c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z"],
|
||||
"paper-plane": [512, 512, [61913], "f1d8", "M16.1 260.2c-22.6 12.9-20.5 47.3 3.6 57.3L160 376V479.3c0 18.1 14.6 32.7 32.7 32.7c9.7 0 18.9-4.3 25.1-11.8l62-74.3 123.9 51.6c18.9 7.9 40.8-4.5 43.9-24.7l64-416c1.9-12.1-3.4-24.3-13.5-31.2s-23.3-7.5-34-1.4l-448 256zm52.1 25.5L409.7 90.6 190.1 336l1.2 1L68.2 285.7zM403.3 425.4L236.7 355.9 450.8 116.6 403.3 425.4z"],
|
||||
"life-ring": [512, 512, [], "f1cd", "M385.1 419.1C349.7 447.2 304.8 464 256 464s-93.7-16.8-129.1-44.9l80.4-80.4c14.3 8.4 31 13.3 48.8 13.3s34.5-4.8 48.8-13.3l80.4 80.4zm68.1 .2C489.9 374.9 512 318.1 512 256s-22.1-118.9-58.8-163.3L465 81c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0L419.3 58.8C374.9 22.1 318.1 0 256 0S137.1 22.1 92.7 58.8L81 47c-9.4-9.4-24.6-9.4-33.9 0s-9.4 24.6 0 33.9L58.8 92.7C22.1 137.1 0 193.9 0 256s22.1 118.9 58.8 163.3L47 431c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l11.8-11.8C137.1 489.9 193.9 512 256 512s118.9-22.1 163.3-58.8L431 465c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-11.8-11.8zm-34.1-34.1l-80.4-80.4c8.4-14.3 13.3-31 13.3-48.8s-4.8-34.5-13.3-48.8l80.4-80.4C447.2 162.3 464 207.2 464 256s-16.8 93.7-44.9 129.1zM385.1 92.9l-80.4 80.4c-14.3-8.4-31-13.3-48.8-13.3s-34.5 4.8-48.8 13.3L126.9 92.9C162.3 64.8 207.2 48 256 48s93.7 16.8 129.1 44.9zM173.3 304.8L92.9 385.1C64.8 349.7 48 304.8 48 256s16.8-93.7 44.9-129.1l80.4 80.4c-8.4 14.3-13.3 31-13.3 48.8s4.8 34.5 13.3 48.8zM208 256a48 48 0 1 1 96 0 48 48 0 1 1 -96 0z"],
|
||||
"face-grimace": [512, 512, [128556, "grimace"], "f57f", "M256 48a208 208 0 1 0 0 416 208 208 0 1 0 0-416zM512 256A256 256 0 1 1 0 256a256 256 0 1 1 512 0zM168 320c-13.3 0-24 10.7-24 24s10.7 24 24 24h8V320h-8zm40 48h32V320H208v48zm96 0V320H272v48h32zm32 0h8c13.3 0 24-10.7 24-24s-10.7-24-24-24h-8v48zM168 288H344c30.9 0 56 25.1 56 56s-25.1 56-56 56H168c-30.9 0-56-25.1-56-56s25.1-56 56-56zm-23.6-80a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zm192-32a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"],
|
||||
"calendar-minus": [512, 512, [], "f272", "M160 0c13.3 0 24 10.7 24 24V64H328V24c0-13.3 10.7-24 24-24s24 10.7 24 24V64h40c35.3 0 64 28.7 64 64v16 48V448c0 35.3-28.7 64-64 64H96c-35.3 0-64-28.7-64-64V192 144 128c0-35.3 28.7-64 64-64h40V24c0-13.3 10.7-24 24-24zM432 192H80V448c0 8.8 7.2 16 16 16H416c8.8 0 16-7.2 16-16V192zM328 352H184c-13.3 0-24-10.7-24-24s10.7-24 24-24H328c13.3 0 24 10.7 24 24s-10.7 24-24 24z"],
|
||||
"circle-xmark": [512, 512, [61532, "times-circle", "xmark-circle"], "f057", "M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c-9.4 9.4-9.4 24.6 0 33.9l47 47-47 47c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l47-47 47 47c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-47-47 47-47c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-47 47-47-47c-9.4-9.4-24.6-9.4-33.9 0z"],
|
||||
"thumbs-up": [512, 512, [128077, 61575], "f164", "M323.8 34.8c-38.2-10.9-78.1 11.2-89 49.4l-5.7 20c-3.7 13-10.4 25-19.5 35l-51.3 56.4c-8.9 9.8-8.2 25 1.6 33.9s25 8.2 33.9-1.6l51.3-56.4c14.1-15.5 24.4-34 30.1-54.1l5.7-20c3.6-12.7 16.9-20.1 29.7-16.5s20.1 16.9 16.5 29.7l-5.7 20c-5.7 19.9-14.7 38.7-26.6 55.5c-5.2 7.3-5.8 16.9-1.7 24.9s12.3 13 21.3 13L448 224c8.8 0 16 7.2 16 16c0 6.8-4.3 12.7-10.4 15c-7.4 2.8-13 9-14.9 16.7s.1 15.8 5.3 21.7c2.5 2.8 4 6.5 4 10.6c0 7.8-5.6 14.3-13 15.7c-8.2 1.6-15.1 7.3-18 15.1s-1.6 16.7 3.6 23.3c2.1 2.7 3.4 6.1 3.4 9.9c0 6.7-4.2 12.6-10.2 14.9c-11.5 4.5-17.7 16.9-14.4 28.8c.4 1.3 .6 2.8 .6 4.3c0 8.8-7.2 16-16 16H286.5c-12.6 0-25-3.7-35.5-10.7l-61.7-41.1c-11-7.4-25.9-4.4-33.3 6.7s-4.4 25.9 6.7 33.3l61.7 41.1c18.4 12.3 40 18.8 62.1 18.8H384c34.7 0 62.9-27.6 64-62c14.6-11.7 24-29.7 24-50c0-4.5-.5-8.8-1.3-13c15.4-11.7 25.3-30.2 25.3-51c0-6.5-1-12.8-2.8-18.7C504.8 273.7 512 257.7 512 240c0-35.3-28.6-64-64-64l-92.3 0c4.7-10.4 8.7-21.2 11.8-32.2l5.7-20c10.9-38.2-11.2-78.1-49.4-89zM32 192c-17.7 0-32 14.3-32 32V448c0 17.7 14.3 32 32 32H96c17.7 0 32-14.3 32-32V224c0-17.7-14.3-32-32-32H32z"],
|
||||
"window-minimize": [512, 512, [128469], "f2d1", "M24 432c-13.3 0-24 10.7-24 24s10.7 24 24 24H488c13.3 0 24-10.7 24-24s-10.7-24-24-24H24z"],
|
||||
"square-full": [512, 512, [128997, 128998, 128999, 129000, 129001, 129002, 129003, 11035, 11036], "f45c", "M464 48V464H48V48H464zM48 0H0V48 464v48H48 464h48V464 48 0H464 48z"],
|
||||
"note-sticky": [448, 512, [62026, "sticky-note"], "f249", "M64 80c-8.8 0-16 7.2-16 16V416c0 8.8 7.2 16 16 16H288V352c0-17.7 14.3-32 32-32h80V96c0-8.8-7.2-16-16-16H64zM288 480H64c-35.3 0-64-28.7-64-64V96C0 60.7 28.7 32 64 32H384c35.3 0 64 28.7 64 64V320v5.5c0 17-6.7 33.3-18.7 45.3l-90.5 90.5c-12 12-28.3 18.7-45.3 18.7H288z"],
|
||||
"face-sad-tear": [512, 512, [128546, "sad-tear"], "f5b4", "M175.9 448c-35-.1-65.5-22.6-76-54.6C67.6 356.8 48 308.7 48 256C48 141.1 141.1 48 256 48s208 93.1 208 208s-93.1 208-208 208c-28.4 0-55.5-5.7-80.1-16zM0 256a256 256 0 1 0 512 0A256 256 0 1 0 0 256zM128 369c0 26 21.5 47 48 47s48-21 48-47c0-20-28.4-60.4-41.6-77.7c-3.2-4.4-9.6-4.4-12.8 0C156.6 308.6 128 349 128 369zm128-65c-13.3 0-24 10.7-24 24s10.7 24 24 24c30.7 0 58.7 11.5 80 30.6c9.9 8.8 25 8 33.9-1.9s8-25-1.9-33.9C338.3 320.2 299 304 256 304zm47.6-96a32 32 0 1 0 64 0 32 32 0 1 0 -64 0zm-128 32a32 32 0 1 0 0-64 32 32 0 1 0 0 64z"],
|
||||
"hand-point-left": [512, 512, [], "f0a5", "M64 128l177.6 0c-1 5.2-1.6 10.5-1.6 16l0 16-32 0L64 160c-8.8 0-16-7.2-16-16s7.2-16 16-16zm224 16c0-17.7 14.3-32 32-32c0 0 0 0 0 0l24 0c66.3 0 120 53.7 120 120l0 48c0 52.5-33.7 97.1-80.7 113.4c.5-3.1 .7-6.2 .7-9.4c0-20-9.2-37.9-23.6-49.7c4.9-9 7.6-19.4 7.6-30.3c0-15.1-5.3-29-14-40c8.8-11 14-24.9 14-40l0-40c0-13.3-10.7-24-24-24s-24 10.7-24 24l0 40c0 8.8-7.2 16-16 16s-16-7.2-16-16l0-40 0-40zm32-80s0 0 0 0c-18 0-34.6 6-48 16L64 80C28.7 80 0 108.7 0 144s28.7 64 64 64l82 0c-1.3 5.1-2 10.5-2 16c0 25.3 14.7 47.2 36 57.6c-2.6 7-4 14.5-4 22.4c0 20 9.2 37.9 23.6 49.7c-4.9 9-7.6 19.4-7.6 30.3c0 35.3 28.7 64 64 64l64 0 24 0c92.8 0 168-75.2 168-168l0-48c0-92.8-75.2-168-168-168l-24 0zM256 400c-8.8 0-16-7.2-16-16s7.2-16 16-16l48 0 16 0c8.8 0 16 7.2 16 16s-7.2 16-16 16l-64 0zM240 224c0 5.5 .7 10.9 2 16l-2 0-32 0c-8.8 0-16-7.2-16-16s7.2-16 16-16l32 0 0 16zm24 64l40 0c8.8 0 16 7.2 16 16s-7.2 16-16 16l-48 0-16 0c-8.8 0-16-7.2-16-16s7.2-16 16-16l24 0z"]
|
||||
};
|
||||
|
||||
bunker(function () {
|
||||
defineIcons('far', icons);
|
||||
defineIcons('fa-regular', icons);
|
||||
});
|
||||
|
||||
}());
|
||||
6
js/regular.min.js
vendored
Normal file
6
js/regular.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1672
js/solid.js
Normal file
1672
js/solid.js
Normal file
File diff suppressed because it is too large
Load Diff
6
js/solid.min.js
vendored
Normal file
6
js/solid.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
225
js/v4-shims.js
Normal file
225
js/v4-shims.js
Normal file
File diff suppressed because one or more lines are too long
6
js/v4-shims.min.js
vendored
Normal file
6
js/v4-shims.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
152
less/_animated.less
Normal file
152
less/_animated.less
Normal file
@@ -0,0 +1,152 @@
|
||||
// animating icons
|
||||
// --------------------------
|
||||
|
||||
.@{fa-css-prefix}-beat {
|
||||
animation-name: ~'@{fa-css-prefix}-beat';
|
||||
animation-delay: ~'var(--@{fa-css-prefix}-animation-delay, 0s)';
|
||||
animation-direction: ~'var(--@{fa-css-prefix}-animation-direction, normal)';
|
||||
animation-duration: ~'var(--@{fa-css-prefix}-animation-duration, 1s)';
|
||||
animation-iteration-count: ~'var(--@{fa-css-prefix}-animation-iteration-count, infinite)';
|
||||
animation-timing-function: ~'var(--@{fa-css-prefix}-animation-timing, ease-in-out)';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-bounce {
|
||||
animation-name: ~'@{fa-css-prefix}-beat';
|
||||
animation-delay: ~'var(--@{fa-css-prefix}-animation-delay, 0s)';
|
||||
animation-direction: ~'var(--@{fa-css-prefix}-animation-direction, normal)';
|
||||
animation-duration: ~'var(--@{fa-css-prefix}-animation-duration, 1s)';
|
||||
animation-iteration-count: ~'var(--@{fa-css-prefix}-animation-iteration-count, infinite)';
|
||||
animation-timing-function: ~'var(--@{fa-css-prefix}-animation-timing, cubic-bezier(0.280, 0.840, 0.420, 1))';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-fade {
|
||||
animation-name: ~'@{fa-css-prefix}-fade';
|
||||
animation-delay: ~'var(--@{fa-css-prefix}-animation-delay, 0s)';
|
||||
animation-direction: ~'var(--@{fa-css-prefix}-animation-direction, normal)';
|
||||
animation-duration: ~'var(--@{fa-css-prefix}-animation-duration, 1s)';
|
||||
animation-iteration-count: ~'var(--@{fa-css-prefix}-animation-iteration-count, infinite)';
|
||||
animation-timing-function: ~'var(--@{fa-css-prefix}-animation-timing, cubic-bezier(.4,0,.6,1))';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-beat-fade {
|
||||
animation-name: ~'@{fa-css-prefix}-beat-fade';
|
||||
animation-delay: ~'var(--@{fa-css-prefix}-animation-delay, 0s)';
|
||||
animation-direction: ~'var(--@{fa-css-prefix}-animation-direction, normal)';
|
||||
animation-duration: ~'var(--@{fa-css-prefix}-animation-duration, 1s)';
|
||||
animation-iteration-count: ~'var(--@{fa-css-prefix}-animation-iteration-count, infinite)';
|
||||
animation-timing-function: ~'var(--@{fa-css-prefix}-animation-timing, cubic-bezier(.4,0,.6,1))';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-flip {
|
||||
animation-name: ~'@{fa-css-prefix}-flip';
|
||||
animation-delay: ~'var(--@{fa-css-prefix}-animation-delay, 0s)';
|
||||
animation-direction: ~'var(--@{fa-css-prefix}-animation-direction, normal)';
|
||||
animation-duration: ~'var(--@{fa-css-prefix}-animation-duration, 1s)';
|
||||
animation-iteration-count: ~'var(--@{fa-css-prefix}-animation-iteration-count, infinite)';
|
||||
animation-timing-function: ~'var(--@{fa-css-prefix}-animation-timing, ease-in-out)';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-shake {
|
||||
animation-name: ~'@{fa-css-prefix}-shake';
|
||||
animation-delay: ~'var(--@{fa-css-prefix}-animation-delay, 0s)';
|
||||
animation-direction: ~'var(--@{fa-css-prefix}-animation-direction, normal)';
|
||||
animation-duration: ~'var(--@{fa-css-prefix}-animation-duration, 1s)';
|
||||
animation-iteration-count: ~'var(--@{fa-css-prefix}-animation-iteration-count, infinite)';
|
||||
animation-timing-function: ~'var(--@{fa-css-prefix}-animation-timing, ease-in-out)';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-spin {
|
||||
animation-name: ~'@{fa-css-prefix}-spin';
|
||||
animation-delay: ~'var(--@{fa-css-prefix}-animation-delay, 0s)';
|
||||
animation-direction: ~'var(--@{fa-css-prefix}-animation-direction, normal)';
|
||||
animation-duration: ~'var(--@{fa-css-prefix}-animation-duration, 2s)';
|
||||
animation-iteration-count: ~'var(--@{fa-css-prefix}-animation-iteration-count, infinite)';
|
||||
animation-timing-function: ~'var(--@{fa-css-prefix}-animation-timing, linear)';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-spin-reverse {
|
||||
--@{fa-css-prefix}-animation-direction: reverse;
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-pulse,
|
||||
.@{fa-css-prefix}-spin-pulse {
|
||||
animation-name: ~'@{fa-css-prefix}-spin';
|
||||
animation-direction: ~'var(--@{fa-css-prefix}-animation-direction, normal)';
|
||||
animation-duration: ~'var(--@{fa-css-prefix}-animation-duration, 1s)';
|
||||
animation-iteration-count: ~'var(--@{fa-css-prefix}-animation-iteration-count, infinite)';
|
||||
animation-timing-function: ~'var(--@{fa-css-prefix}-animation-timing, steps(8));';
|
||||
}
|
||||
|
||||
// if agent or operating system prefers reduced motion, disable animations
|
||||
// see: https://www.smashingmagazine.com/2020/09/design-reduced-motion-sensitivities/
|
||||
// see: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.@{fa-css-prefix}-beat,
|
||||
.@{fa-css-prefix}-bounce,
|
||||
.@{fa-css-prefix}-fade,
|
||||
.@{fa-css-prefix}-beat-fade,
|
||||
.@{fa-css-prefix}-flip,
|
||||
.@{fa-css-prefix}-pulse,
|
||||
.@{fa-css-prefix}-shake,
|
||||
.@{fa-css-prefix}-spin,
|
||||
.@{fa-css-prefix}-spin-pulse {
|
||||
animation-delay: -1ms;
|
||||
animation-duration: 1ms;
|
||||
animation-iteration-count: 1;
|
||||
transition-delay: 0s;
|
||||
transition-duration: 0s;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ~'@{fa-css-prefix}-beat' {
|
||||
0%, 90% { transform: scale(1); }
|
||||
45% { transform: ~'scale(var(--@{fa-css-prefix}-beat-scale, 1.25))'; }
|
||||
}
|
||||
|
||||
@keyframes ~'@{fa-css-prefix}-bounce' {
|
||||
0% { transform: scale(1,1) translateY(0); }
|
||||
10% { transform: ~'scale(var(--#{$fa-css-prefix}-bounce-start-scale-x, 1.1),var(--#{$fa-css-prefix}-bounce-start-scale-y, 0.9))' translateY(0); }
|
||||
30% { transform: ~'scale(var(--#{$fa-css-prefix}-bounce-jump-scale-x, 0.9),var(--#{$fa-css-prefix}-bounce-jump-scale-y, 1.1))' ~'translateY(var(--#{$fa-css-prefix}-bounce-height, -0.5em))'; }
|
||||
50% { transform: ~'scale(var(--#{$fa-css-prefix}-bounce-land-scale-x, 1.05),var(--#{$fa-css-prefix}-bounce-land-scale-y, 0.95))' translateY(0); }
|
||||
57% { transform: ~'scale(1,1) translateY(var(--#{$fa-css-prefix}-bounce-rebound, -0.125em))'; }
|
||||
64% { transform: scale(1,1) translateY(0); }
|
||||
100% { transform: scale(1,1) translateY(0); }
|
||||
}
|
||||
|
||||
@keyframes ~'@{fa-css-prefix}-fade' {
|
||||
50% { opacity: ~'var(--@{fa-css-prefix}-fade-opacity, 0.4)'; }
|
||||
}
|
||||
|
||||
@keyframes ~'@{fa-css-prefix}-beat-fade' {
|
||||
0%, 100% {
|
||||
opacity: ~'var(--@{fa-css-prefix}-beat-fade-opacity, 0.4)';
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
transform: ~'scale(var(--@{fa-css-prefix}-beat-fade-scale, 1.125))';
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ~'@{fa-css-prefix}-flip' {
|
||||
50% {
|
||||
transform: ~'rotate3d(var(--@{fa-css-prefix}-flip-x, 0), var(--@{fa-css-prefix}-flip-y, 1), var(--@{fa-css-prefix}-flip-z, 0), var(--@{fa-css-prefix}-flip-angle, -180deg))';
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ~'@{fa-css-prefix}-shake' {
|
||||
0% { transform: rotate(-15deg); }
|
||||
4% { transform: rotate(15deg); }
|
||||
8%, 24% { transform: rotate(-18deg); }
|
||||
12%, 28% { transform: rotate(18deg); }
|
||||
16% { transform: rotate(-22deg); }
|
||||
20% { transform: rotate(22deg); }
|
||||
32% { transform: rotate(-12deg); }
|
||||
36% { transform: rotate(12deg); }
|
||||
40%, 100% { transform: rotate(0deg); }
|
||||
}
|
||||
|
||||
@keyframes ~'@{fa-css-prefix}-spin' {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
20
less/_bordered-pulled.less
Normal file
20
less/_bordered-pulled.less
Normal file
@@ -0,0 +1,20 @@
|
||||
// bordered + pulled icons
|
||||
// -------------------------
|
||||
|
||||
.@{fa-css-prefix}-border {
|
||||
border-color: ~'var(--@{fa-css-prefix}-border-color, @{fa-border-color})';
|
||||
border-radius: ~'var(--@{fa-css-prefix}-border-radius, @{fa-border-radius})';
|
||||
border-style: ~'var(--@{fa-css-prefix}-border-style, @{fa-border-style})';
|
||||
border-width: ~'var(--@{fa-css-prefix}-border-width, @{fa-border-width})';
|
||||
padding: ~'var(--@{fa-css-prefix}-border-padding, @{fa-border-padding})';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-pull-left {
|
||||
float: left;
|
||||
margin-right: ~'var(--@{fa-css-prefix}-pull-margin, @{fa-pull-margin})';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-pull-right {
|
||||
float: right;
|
||||
margin-left: ~'var(--@{fa-css-prefix}-pull-margin, @{fa-pull-margin})';
|
||||
}
|
||||
38
less/_core.less
Normal file
38
less/_core.less
Normal file
@@ -0,0 +1,38 @@
|
||||
// base icon class definition
|
||||
// -------------------------
|
||||
|
||||
.@{fa-css-prefix} {
|
||||
font-family: ~"var(--@{fa-css-prefix}-style-family, '@{fa-style-family}')";
|
||||
font-weight: ~'var(--@{fa-css-prefix}-style, @{fa-style})';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix},
|
||||
.fas,
|
||||
.@{fa-css-prefix}-solid,
|
||||
.fass,
|
||||
.@{fa-css-prefix}-sharp,
|
||||
.far,
|
||||
.@{fa-css-prefix}-regular,
|
||||
.fab,
|
||||
.@{fa-css-prefix}-brands {
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
display: ~'var(--@{fa-css-prefix}-display, @{fa-display})';
|
||||
font-style: normal;
|
||||
font-variant: normal;
|
||||
text-rendering: auto;
|
||||
}
|
||||
|
||||
.fas,
|
||||
.@{fa-css-prefix}-classic,
|
||||
.@{fa-css-prefix}-solid,
|
||||
.far,
|
||||
.@{fa-css-prefix}-regular {
|
||||
font-family: 'Font Awesome 6 Free';
|
||||
}
|
||||
|
||||
.fab,
|
||||
.@{fa-css-prefix}-brands {
|
||||
font-family: 'Font Awesome 6 Brands';
|
||||
}
|
||||
|
||||
7
less/_fixed-width.less
Normal file
7
less/_fixed-width.less
Normal file
@@ -0,0 +1,7 @@
|
||||
// fixed-width icons
|
||||
// -------------------------
|
||||
|
||||
.@{fa-css-prefix}-fw {
|
||||
text-align: center;
|
||||
width: @fa-fw-width;
|
||||
}
|
||||
9
less/_icons.less
Normal file
9
less/_icons.less
Normal file
@@ -0,0 +1,9 @@
|
||||
// specific icon class definition
|
||||
// -------------------------
|
||||
|
||||
/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
|
||||
readers do not read off random characters that represent icons */
|
||||
|
||||
each(.fa-icons(), {
|
||||
.@{fa-css-prefix}-@{key}::before { content: @value; }
|
||||
});
|
||||
18
less/_list.less
Normal file
18
less/_list.less
Normal file
@@ -0,0 +1,18 @@
|
||||
// icons in a list
|
||||
// -------------------------
|
||||
|
||||
.@{fa-css-prefix}-ul {
|
||||
list-style-type: none;
|
||||
margin-left: ~'var(--@{fa-css-prefix}-li-margin, @{fa-li-margin})';
|
||||
padding-left: 0;
|
||||
|
||||
> li { position: relative; }
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-li {
|
||||
left: calc(~'var(--@{fa-css-prefix}-li-width, @{fa-li-width})' * -1);
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: ~'var(--@{fa-css-prefix}-li-width, @{fa-li-width})';
|
||||
line-height: inherit;
|
||||
}
|
||||
78
less/_mixins.less
Normal file
78
less/_mixins.less
Normal file
@@ -0,0 +1,78 @@
|
||||
// mixins
|
||||
// --------------------------
|
||||
|
||||
// base rendering for an icon
|
||||
.fa-icon() {
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
display: inline-block;
|
||||
font-style: normal;
|
||||
font-variant: normal;
|
||||
font-weight: normal;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
// sets relative font-sizing and alignment (in _sizing)
|
||||
.fa-size(@font-size) {
|
||||
font-size: (@font-size / @fa-size-scale-base) * 1em; // converts step in sizing scale into an em-based value that's relative to the scale's base
|
||||
line-height: (1 / @font-size) * 1em; // sets the line-height of the icon back to that of it's parent
|
||||
vertical-align: ((6 / @font-size) - (3 / 8)) * 1em; // vertically centers the icon taking into account the surrounding text's descender
|
||||
}
|
||||
|
||||
// only display content to screen readers
|
||||
// see: https://www.a11yproject.com/posts/2013-01-11-how-to-hide-content/
|
||||
// see: https://hugogiraudel.com/2016/10/13/css-hide-and-seek/
|
||||
.fa-sr-only() {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
// use in conjunction with .sr-only to only display content when it's focused
|
||||
.fa-sr-only-focusable() {
|
||||
&:not(:focus) {
|
||||
.fa-sr-only();
|
||||
}
|
||||
}
|
||||
|
||||
// sets a specific icon family to use alongside style + icon mixins
|
||||
.fa-family-classic() {
|
||||
font-family: 'Font Awesome 6 Free';
|
||||
}
|
||||
|
||||
// convenience mixins for declaring pseudo-elements by CSS variable,
|
||||
// including all style-specific font properties, and both the ::before
|
||||
// and ::after elements in the duotone case.
|
||||
.fa-icon-solid(@fa-var) {
|
||||
.fa-icon;
|
||||
.fa-solid;
|
||||
|
||||
&::before {
|
||||
content: @fa-var;
|
||||
}
|
||||
}
|
||||
|
||||
.fa-icon-regular(@fa-var) {
|
||||
.fa-icon;
|
||||
.fa-regular;
|
||||
|
||||
&::before {
|
||||
content: @fa-var;
|
||||
}
|
||||
}
|
||||
|
||||
.fa-icon-brands(@fa-var) {
|
||||
.fa-icon;
|
||||
.fa-brands;
|
||||
|
||||
&::before {
|
||||
content: @fa-var;
|
||||
}
|
||||
}
|
||||
|
||||
31
less/_rotated-flipped.less
Normal file
31
less/_rotated-flipped.less
Normal file
@@ -0,0 +1,31 @@
|
||||
// rotating + flipping icons
|
||||
// -------------------------
|
||||
|
||||
.@{fa-css-prefix}-rotate-90 {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-rotate-180 {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-rotate-270 {
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-flip-horizontal {
|
||||
transform: scale(-1, 1);
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-flip-vertical {
|
||||
transform: scale(1, -1);
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-flip-both,
|
||||
.@{fa-css-prefix}-flip-horizontal.@{fa-css-prefix}-flip-vertical {
|
||||
transform: scale(-1, -1);
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-rotate-by {
|
||||
transform: rotate(~'var(--@{fa-css-prefix}-rotate-angle, none)');
|
||||
}
|
||||
14
less/_screen-reader.less
Normal file
14
less/_screen-reader.less
Normal file
@@ -0,0 +1,14 @@
|
||||
// screen-reader utilities
|
||||
// -------------------------
|
||||
|
||||
// only display content to screen readers
|
||||
.sr-only,
|
||||
.@{fa-css-prefix}-sr-only {
|
||||
.fa-sr-only();
|
||||
}
|
||||
|
||||
// use in conjunction with .sr-only to only display content when it's focused
|
||||
.sr-only-focusable,
|
||||
.@{fa-css-prefix}-sr-only-focusable {
|
||||
.fa-sr-only-focusable();
|
||||
}
|
||||
2042
less/_shims.less
Normal file
2042
less/_shims.less
Normal file
File diff suppressed because it is too large
Load Diff
19
less/_sizing.less
Normal file
19
less/_sizing.less
Normal file
@@ -0,0 +1,19 @@
|
||||
// sizing icons
|
||||
// -------------------------
|
||||
|
||||
// literal magnification scale
|
||||
.sizes-literal(@factor) when (@factor > 0) {
|
||||
.sizes-literal((@factor - 1));
|
||||
|
||||
.@{fa-css-prefix}-@{factor}x {
|
||||
font-size: (@factor * 1em);
|
||||
}
|
||||
}
|
||||
.sizes-literal(10);
|
||||
|
||||
// step-based scale (with alignment)
|
||||
each(.fa-sizes(), {
|
||||
.@{fa-css-prefix}-@{key} {
|
||||
.fa-size(@value);
|
||||
}
|
||||
});
|
||||
31
less/_stacked.less
Normal file
31
less/_stacked.less
Normal file
@@ -0,0 +1,31 @@
|
||||
// stacking icons
|
||||
// -------------------------
|
||||
|
||||
.@{fa-css-prefix}-stack {
|
||||
display: inline-block;
|
||||
height: 2em;
|
||||
line-height: 2em;
|
||||
position: relative;
|
||||
vertical-align: @fa-stack-vertical-align;
|
||||
width: @fa-stack-width;
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
z-index: ~'var(--@{fa-css-prefix}-stack-z-index, @{fa-stack-z-index})';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-stack-1x {
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-stack-2x {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-inverse {
|
||||
color: ~'var(--@{fa-css-prefix}-inverse, @{fa-inverse})';
|
||||
}
|
||||
4962
less/_variables.less
Normal file
4962
less/_variables.less
Normal file
File diff suppressed because it is too large
Load Diff
29
less/brands.less
Normal file
29
less/brands.less
Normal file
@@ -0,0 +1,29 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
@import "_variables.less";
|
||||
|
||||
:root, :host {
|
||||
--@{fa-css-prefix}-style-family-brands: 'Font Awesome 6 Brands';
|
||||
--@{fa-css-prefix}-font-brands: normal 400 1em/1 'Font Awesome 6 Brands';
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 6 Brands';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: @fa-font-display;
|
||||
src: url('@{fa-font-path}/fa-brands-400.woff2') format('woff2'),
|
||||
url('@{fa-font-path}/fa-brands-400.ttf') format('truetype');
|
||||
}
|
||||
|
||||
.fab,
|
||||
.@{fa-css-prefix}-brands {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
each(.fa-brand-icons(), {
|
||||
.@{fa-css-prefix}-@{key}:before { content: @value; }
|
||||
});
|
||||
20
less/fontawesome.less
vendored
Normal file
20
less/fontawesome.less
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
// Font Awesome core compile (Web Fonts-based)
|
||||
// -------------------------
|
||||
|
||||
@import "_variables.less";
|
||||
@import "_mixins.less";
|
||||
@import "_core.less";
|
||||
@import "_sizing.less";
|
||||
@import "_fixed-width.less";
|
||||
@import "_list.less";
|
||||
@import "_bordered-pulled.less";
|
||||
@import "_animated.less";
|
||||
@import "_rotated-flipped.less";
|
||||
@import "_stacked.less";
|
||||
@import "_icons.less";
|
||||
@import "_screen-reader.less";
|
||||
25
less/regular.less
Normal file
25
less/regular.less
Normal file
@@ -0,0 +1,25 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
@import "_variables.less";
|
||||
|
||||
:root, :host {
|
||||
--@{fa-css-prefix}-style-family-classic: '@{fa-style-family}';
|
||||
--@{fa-css-prefix}-font-regular: normal 400 1em/1 '@{fa-style-family}';
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 6 Free';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: @fa-font-display;
|
||||
src: url('@{fa-font-path}/fa-regular-400.woff2') format('woff2'),
|
||||
url('@{fa-font-path}/fa-regular-400.ttf') format('truetype');
|
||||
}
|
||||
|
||||
.far,
|
||||
.@{fa-css-prefix}-regular {
|
||||
font-weight: 400;
|
||||
}
|
||||
26
less/solid.less
Normal file
26
less/solid.less
Normal file
@@ -0,0 +1,26 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
@import "_variables.less";
|
||||
|
||||
:root, :host {
|
||||
--@{fa-css-prefix}-style-family-classic: '@{fa-style-family}';
|
||||
--@{fa-css-prefix}-font-solid: normal 900 1em/1 '@{fa-style-family}';
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 6 Free';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: @fa-font-display;
|
||||
src: url('@{fa-font-path}/fa-solid-900.woff2') format('woff2'),
|
||||
url('@{fa-font-path}/fa-solid-900.ttf') format('truetype');
|
||||
}
|
||||
|
||||
|
||||
.fas,
|
||||
.@{fa-css-prefix}-solid {
|
||||
font-weight: 900;
|
||||
}
|
||||
10
less/v4-shims.less
Normal file
10
less/v4-shims.less
Normal file
@@ -0,0 +1,10 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
// V4 shims compile (Web Fonts-based)
|
||||
// -------------------------
|
||||
|
||||
@import '_variables.less';
|
||||
@import '_shims.less';
|
||||
39
mail/verification_template.php
Normal file
39
mail/verification_template.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* 邮箱验证模板
|
||||
* 变量说明:
|
||||
* - {username}: 用户名
|
||||
* - {verification_link}: 验证链接
|
||||
*/
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>邮箱验证 - <?= APP_STORE_NAME ?></title>
|
||||
<style>
|
||||
body { font-family: 'Microsoft YaHei', sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px; }
|
||||
.container { background-color: #f9f9f9; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
|
||||
.logo { font-size: 24px; font-weight: bold; color: #2c3e50; margin-bottom: 20px; }
|
||||
.greeting { font-size: 18px; margin-bottom: 15px; }
|
||||
.content { margin-bottom: 25px; }
|
||||
.verification-btn { display: inline-block; padding: 12px 24px; background-color: #3498db; color: white; text-decoration: none; border-radius: 4px; font-weight: bold; }
|
||||
.verification-btn:hover { background-color: #2980b9; }
|
||||
.footer { margin-top: 30px; color: #7f8c8d; font-size: 14px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="logo"><?= APP_STORE_NAME ?></div>
|
||||
<div class="greeting">您好,{username}!</div>
|
||||
<div class="content">
|
||||
<p>感谢您注册成为开发者!请点击下方链接验证您的邮箱:</p>
|
||||
<p style="margin: 30px 0;"><a href="{verification_link}" class="verification-btn">验证邮箱</a></p>
|
||||
<p>如果您没有注册过我们的服务,请忽略此邮件。</p>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<p>此邮件由系统自动发送,请勿回复。</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
3059
metadata/categories.yml
Normal file
3059
metadata/categories.yml
Normal file
File diff suppressed because it is too large
Load Diff
111505
metadata/icon-families.json
Normal file
111505
metadata/icon-families.json
Normal file
File diff suppressed because one or more lines are too long
51019
metadata/icon-families.yml
Normal file
51019
metadata/icon-families.yml
Normal file
File diff suppressed because it is too large
Load Diff
91961
metadata/icons.json
Normal file
91961
metadata/icons.json
Normal file
File diff suppressed because one or more lines are too long
41247
metadata/icons.yml
Normal file
41247
metadata/icons.yml
Normal file
File diff suppressed because it is too large
Load Diff
4052
metadata/shims.json
Normal file
4052
metadata/shims.json
Normal file
File diff suppressed because it is too large
Load Diff
646
metadata/shims.yml
Normal file
646
metadata/shims.yml
Normal file
@@ -0,0 +1,646 @@
|
||||
area-chart:
|
||||
name: chart-area
|
||||
arrow-circle-o-down:
|
||||
prefix: far
|
||||
name: circle-down
|
||||
arrow-circle-o-left:
|
||||
prefix: far
|
||||
name: circle-left
|
||||
arrow-circle-o-right:
|
||||
prefix: far
|
||||
name: circle-right
|
||||
arrow-circle-o-up:
|
||||
prefix: far
|
||||
name: circle-up
|
||||
arrows:
|
||||
name: up-down-left-right
|
||||
arrows-alt:
|
||||
name: maximize
|
||||
arrows-h:
|
||||
name: left-right
|
||||
arrows-v:
|
||||
name: up-down
|
||||
asl-interpreting:
|
||||
name: hands-asl-interpreting
|
||||
automobile:
|
||||
name: car
|
||||
bank:
|
||||
name: building-columns
|
||||
bar-chart:
|
||||
name: chart-column
|
||||
bar-chart-o:
|
||||
name: chart-column
|
||||
bathtub:
|
||||
name: bath
|
||||
battery:
|
||||
name: battery-full
|
||||
battery-0:
|
||||
name: battery-empty
|
||||
battery-1:
|
||||
name: battery-quarter
|
||||
battery-2:
|
||||
name: battery-half
|
||||
battery-3:
|
||||
name: battery-three-quarters
|
||||
battery-4:
|
||||
name: battery-full
|
||||
behance-square:
|
||||
prefix: fab
|
||||
name: square-behance
|
||||
bitbucket-square:
|
||||
prefix: fab
|
||||
name: bitbucket
|
||||
bitcoin:
|
||||
prefix: fab
|
||||
name: btc
|
||||
cab:
|
||||
name: taxi
|
||||
calendar:
|
||||
name: calendar-days
|
||||
calendar-times-o:
|
||||
prefix: far
|
||||
name: calendar-xmark
|
||||
caret-square-o-down:
|
||||
prefix: far
|
||||
name: square-caret-down
|
||||
caret-square-o-left:
|
||||
prefix: far
|
||||
name: square-caret-left
|
||||
caret-square-o-right:
|
||||
prefix: far
|
||||
name: square-caret-right
|
||||
caret-square-o-up:
|
||||
prefix: far
|
||||
name: square-caret-up
|
||||
cc:
|
||||
prefix: far
|
||||
name: closed-captioning
|
||||
chain:
|
||||
name: link
|
||||
chain-broken:
|
||||
name: link-slash
|
||||
check-circle-o:
|
||||
prefix: far
|
||||
name: circle-check
|
||||
check-square-o:
|
||||
prefix: far
|
||||
name: square-check
|
||||
circle-o-notch:
|
||||
name: circle-notch
|
||||
circle-thin:
|
||||
prefix: far
|
||||
name: circle
|
||||
clipboard:
|
||||
name: paste
|
||||
clone:
|
||||
prefix: far
|
||||
close:
|
||||
name: xmark
|
||||
cloud-download:
|
||||
name: cloud-arrow-down
|
||||
cloud-upload:
|
||||
name: cloud-arrow-up
|
||||
cny:
|
||||
name: yen-sign
|
||||
code-fork:
|
||||
name: code-branch
|
||||
commenting:
|
||||
name: comment-dots
|
||||
commenting-o:
|
||||
prefix: far
|
||||
name: comment-dots
|
||||
compass:
|
||||
prefix: far
|
||||
compress:
|
||||
name: down-left-and-up-right-to-center
|
||||
copyright:
|
||||
prefix: far
|
||||
credit-card:
|
||||
prefix: far
|
||||
credit-card-alt:
|
||||
name: credit-card
|
||||
cut:
|
||||
name: scissors
|
||||
cutlery:
|
||||
name: utensils
|
||||
dashboard:
|
||||
name: gauge-high
|
||||
deafness:
|
||||
name: ear-deaf
|
||||
dedent:
|
||||
name: outdent
|
||||
diamond:
|
||||
prefix: far
|
||||
name: gem
|
||||
dollar:
|
||||
name: dollar-sign
|
||||
dot-circle-o:
|
||||
prefix: far
|
||||
name: circle-dot
|
||||
drivers-license:
|
||||
name: id-card
|
||||
drivers-license-o:
|
||||
prefix: far
|
||||
name: id-card
|
||||
edit:
|
||||
prefix: far
|
||||
name: pen-to-square
|
||||
eercast:
|
||||
prefix: fab
|
||||
name: sellcast
|
||||
eur:
|
||||
name: euro-sign
|
||||
euro:
|
||||
name: euro-sign
|
||||
exchange:
|
||||
name: right-left
|
||||
expand:
|
||||
name: up-right-and-down-left-from-center
|
||||
external-link:
|
||||
name: up-right-from-square
|
||||
external-link-square:
|
||||
name: square-up-right
|
||||
eye:
|
||||
prefix: far
|
||||
eye-slash:
|
||||
prefix: far
|
||||
eyedropper:
|
||||
name: eye-dropper
|
||||
fa:
|
||||
prefix: fab
|
||||
name: font-awesome
|
||||
facebook:
|
||||
prefix: fab
|
||||
name: facebook-f
|
||||
facebook-f:
|
||||
prefix: fab
|
||||
name: facebook-f
|
||||
facebook-official:
|
||||
prefix: fab
|
||||
name: facebook
|
||||
facebook-square:
|
||||
prefix: fab
|
||||
name: square-facebook
|
||||
feed:
|
||||
name: rss
|
||||
file-archive-o:
|
||||
prefix: far
|
||||
name: file-zipper
|
||||
file-movie-o:
|
||||
prefix: far
|
||||
name: file-video
|
||||
file-photo-o:
|
||||
prefix: far
|
||||
name: file-image
|
||||
file-picture-o:
|
||||
prefix: far
|
||||
name: file-image
|
||||
file-sound-o:
|
||||
prefix: far
|
||||
name: file-audio
|
||||
file-text:
|
||||
name: file-lines
|
||||
file-text-o:
|
||||
prefix: far
|
||||
name: file-lines
|
||||
file-zip-o:
|
||||
prefix: far
|
||||
name: file-zipper
|
||||
files-o:
|
||||
prefix: far
|
||||
name: copy
|
||||
flash:
|
||||
name: bolt
|
||||
floppy-o:
|
||||
prefix: far
|
||||
name: floppy-disk
|
||||
frown-o:
|
||||
prefix: far
|
||||
name: face-frown
|
||||
gbp:
|
||||
name: sterling-sign
|
||||
ge:
|
||||
prefix: fab
|
||||
name: empire
|
||||
gear:
|
||||
name: gear
|
||||
gears:
|
||||
name: gears
|
||||
git-square:
|
||||
prefix: fab
|
||||
name: square-git
|
||||
github-square:
|
||||
prefix: fab
|
||||
name: square-github
|
||||
gittip:
|
||||
prefix: fab
|
||||
name: gratipay
|
||||
glass:
|
||||
name: martini-glass-empty
|
||||
globe:
|
||||
name: earth-americas
|
||||
google-plus:
|
||||
prefix: fab
|
||||
name: google-plus-g
|
||||
google-plus-circle:
|
||||
prefix: fab
|
||||
name: google-plus
|
||||
google-plus-official:
|
||||
prefix: fab
|
||||
name: google-plus
|
||||
google-plus-square:
|
||||
prefix: fab
|
||||
name: square-google-plus
|
||||
group:
|
||||
name: users
|
||||
hand-grab-o:
|
||||
prefix: far
|
||||
name: hand-back-fist
|
||||
hand-o-down:
|
||||
prefix: far
|
||||
name: hand-point-down
|
||||
hand-o-left:
|
||||
prefix: far
|
||||
name: hand-point-left
|
||||
hand-o-right:
|
||||
prefix: far
|
||||
name: hand-point-right
|
||||
hand-o-up:
|
||||
prefix: far
|
||||
name: hand-point-up
|
||||
hand-paper-o:
|
||||
prefix: far
|
||||
name: hand
|
||||
hand-rock-o:
|
||||
prefix: far
|
||||
name: hand-back-fist
|
||||
hand-stop-o:
|
||||
prefix: far
|
||||
name: hand
|
||||
hard-of-hearing:
|
||||
name: ear-deaf
|
||||
hdd-o:
|
||||
prefix: far
|
||||
name: hard-drive
|
||||
header:
|
||||
name: heading
|
||||
home:
|
||||
name: house
|
||||
hotel:
|
||||
name: bed
|
||||
hourglass-1:
|
||||
name: hourglass-start
|
||||
hourglass-2:
|
||||
name: hourglass-half
|
||||
hourglass-3:
|
||||
name: hourglass-end
|
||||
hourglass-o:
|
||||
name: hourglass
|
||||
id-badge:
|
||||
prefix: far
|
||||
ils:
|
||||
name: shekel-sign
|
||||
image:
|
||||
prefix: far
|
||||
name: image
|
||||
inr:
|
||||
name: indian-rupee-sign
|
||||
institution:
|
||||
name: building-columns
|
||||
intersex:
|
||||
name: mars-and-venus
|
||||
jpy:
|
||||
name: yen-sign
|
||||
krw:
|
||||
name: won-sign
|
||||
lastfm-square:
|
||||
prefix: fab
|
||||
name: square-lastfm
|
||||
legal:
|
||||
name: gavel
|
||||
level-down:
|
||||
name: turn-down
|
||||
level-up:
|
||||
name: turn-up
|
||||
life-bouy:
|
||||
name: life-ring
|
||||
life-buoy:
|
||||
name: life-ring
|
||||
life-saver:
|
||||
name: life-ring
|
||||
line-chart:
|
||||
name: chart-line
|
||||
linkedin:
|
||||
prefix: fab
|
||||
name: linkedin-in
|
||||
linkedin-square:
|
||||
prefix: fab
|
||||
name: linkedin
|
||||
list-alt:
|
||||
prefix: far
|
||||
name: rectangle-list
|
||||
long-arrow-down:
|
||||
name: down-long
|
||||
long-arrow-left:
|
||||
name: left-long
|
||||
long-arrow-right:
|
||||
name: right-long
|
||||
long-arrow-up:
|
||||
name: up-long
|
||||
magic:
|
||||
name: wand-magic-sparkles
|
||||
mail-forward:
|
||||
name: share
|
||||
mail-reply:
|
||||
name: reply
|
||||
mail-reply-all:
|
||||
name: reply-all
|
||||
map-marker:
|
||||
name: location-dot
|
||||
meh-o:
|
||||
prefix: far
|
||||
name: face-meh
|
||||
minus-square-o:
|
||||
prefix: far
|
||||
name: square-minus
|
||||
mobile:
|
||||
name: mobile-screen-button
|
||||
mobile-phone:
|
||||
name: mobile-screen-button
|
||||
money:
|
||||
name: money-bill-1
|
||||
mortar-board:
|
||||
name: graduation-cap
|
||||
navicon:
|
||||
name: bars
|
||||
object-group:
|
||||
prefix: far
|
||||
object-ungroup:
|
||||
prefix: far
|
||||
odnoklassniki-square:
|
||||
prefix: fab
|
||||
name: square-odnoklassniki
|
||||
pause-circle-o:
|
||||
prefix: far
|
||||
name: circle-pause
|
||||
pencil-square:
|
||||
name: square-pen
|
||||
pencil-square-o:
|
||||
prefix: far
|
||||
name: pen-to-square
|
||||
photo:
|
||||
prefix: far
|
||||
name: image
|
||||
picture-o:
|
||||
prefix: far
|
||||
name: image
|
||||
pie-chart:
|
||||
name: chart-pie
|
||||
pinterest-square:
|
||||
prefix: fab
|
||||
name: square-pinterest
|
||||
play-circle-o:
|
||||
prefix: far
|
||||
name: circle-play
|
||||
plus-square-o:
|
||||
prefix: far
|
||||
name: square-plus
|
||||
question-circle-o:
|
||||
prefix: far
|
||||
name: circle-question
|
||||
ra:
|
||||
prefix: fab
|
||||
name: rebel
|
||||
reddit-square:
|
||||
prefix: fab
|
||||
name: square-reddit
|
||||
refresh:
|
||||
name: arrows-rotate
|
||||
registered:
|
||||
prefix: far
|
||||
remove:
|
||||
name: xmark
|
||||
reorder:
|
||||
name: bars
|
||||
repeat:
|
||||
name: arrow-rotate-right
|
||||
resistance:
|
||||
prefix: fab
|
||||
name: rebel
|
||||
rmb:
|
||||
name: yen-sign
|
||||
rotate-left:
|
||||
name: arrow-rotate-left
|
||||
rotate-right:
|
||||
name: arrow-rotate-right
|
||||
rouble:
|
||||
name: ruble-sign
|
||||
rub:
|
||||
name: ruble-sign
|
||||
ruble:
|
||||
name: ruble-sign
|
||||
rupee:
|
||||
name: indian-rupee-sign
|
||||
s15:
|
||||
name: bath
|
||||
save:
|
||||
prefix: far
|
||||
name: floppy-disk
|
||||
send:
|
||||
name: paper-plane
|
||||
send-o:
|
||||
prefix: far
|
||||
name: paper-plane
|
||||
share-square-o:
|
||||
name: share-from-square
|
||||
shekel:
|
||||
name: shekel-sign
|
||||
sheqel:
|
||||
name: shekel-sign
|
||||
sign-in:
|
||||
name: right-to-bracket
|
||||
sign-out:
|
||||
name: right-from-bracket
|
||||
signing:
|
||||
name: hands
|
||||
smile-o:
|
||||
prefix: far
|
||||
name: face-smile
|
||||
snapchat-ghost:
|
||||
prefix: fab
|
||||
name: snapchat
|
||||
snapchat-square:
|
||||
prefix: fab
|
||||
name: square-snapchat
|
||||
soccer-ball-o:
|
||||
prefix: far
|
||||
name: futbol
|
||||
sort-alpha-asc:
|
||||
name: arrow-down-a-z
|
||||
sort-alpha-desc:
|
||||
name: arrow-down-z-a
|
||||
sort-amount-asc:
|
||||
name: arrow-down-short-wide
|
||||
sort-amount-desc:
|
||||
name: arrow-down-wide-short
|
||||
sort-asc:
|
||||
name: sort-up
|
||||
sort-desc:
|
||||
name: sort-down
|
||||
sort-numeric-asc:
|
||||
name: arrow-down-1-9
|
||||
sort-numeric-desc:
|
||||
name: arrow-down-9-1
|
||||
star-half-empty:
|
||||
prefix: far
|
||||
name: star-half-stroke
|
||||
star-half-full:
|
||||
prefix: far
|
||||
name: star-half-stroke
|
||||
star-half-o:
|
||||
prefix: far
|
||||
name: star-half-stroke
|
||||
steam-square:
|
||||
prefix: fab
|
||||
name: square-steam
|
||||
sticky-note-o:
|
||||
prefix: far
|
||||
name: note-sticky
|
||||
stop-circle-o:
|
||||
prefix: far
|
||||
name: circle-stop
|
||||
support:
|
||||
name: life-ring
|
||||
tablet:
|
||||
name: tablet-screen-button
|
||||
tachometer:
|
||||
name: gauge-high
|
||||
tasks:
|
||||
name: bars-progress
|
||||
television:
|
||||
name: tv
|
||||
thermometer:
|
||||
name: temperature-full
|
||||
thermometer-0:
|
||||
name: temperature-empty
|
||||
thermometer-1:
|
||||
name: temperature-quarter
|
||||
thermometer-2:
|
||||
name: temperature-half
|
||||
thermometer-3:
|
||||
name: temperature-three-quarters
|
||||
thermometer-4:
|
||||
name: temperature-full
|
||||
thumb-tack:
|
||||
name: thumbtack
|
||||
thumbs-o-down:
|
||||
prefix: far
|
||||
name: thumbs-down
|
||||
thumbs-o-up:
|
||||
prefix: far
|
||||
name: thumbs-up
|
||||
times-circle-o:
|
||||
prefix: far
|
||||
name: circle-xmark
|
||||
times-rectangle:
|
||||
name: rectangle-xmark
|
||||
times-rectangle-o:
|
||||
prefix: far
|
||||
name: rectangle-xmark
|
||||
toggle-down:
|
||||
prefix: far
|
||||
name: square-caret-down
|
||||
toggle-left:
|
||||
prefix: far
|
||||
name: square-caret-left
|
||||
toggle-right:
|
||||
prefix: far
|
||||
name: square-caret-right
|
||||
toggle-up:
|
||||
prefix: far
|
||||
name: square-caret-up
|
||||
transgender:
|
||||
name: mars-and-venus
|
||||
transgender-alt:
|
||||
name: transgender
|
||||
trash:
|
||||
name: trash-can
|
||||
trash-o:
|
||||
prefix: far
|
||||
name: trash-can
|
||||
try:
|
||||
name: turkish-lira-sign
|
||||
tumblr-square:
|
||||
prefix: fab
|
||||
name: square-tumblr
|
||||
turkish-lira:
|
||||
name: turkish-lira-sign
|
||||
twitter-square:
|
||||
prefix: fab
|
||||
name: square-twitter
|
||||
unlink:
|
||||
name: link-slash
|
||||
unlock-alt:
|
||||
name: unlock
|
||||
unsorted:
|
||||
name: sort
|
||||
usd:
|
||||
name: dollar-sign
|
||||
user-circle-o:
|
||||
prefix: far
|
||||
name: circle-user
|
||||
vcard:
|
||||
name: address-card
|
||||
vcard-o:
|
||||
prefix: far
|
||||
name: address-card
|
||||
viadeo-square:
|
||||
prefix: fab
|
||||
name: square-viadeo
|
||||
video-camera:
|
||||
name: video
|
||||
vimeo:
|
||||
prefix: fab
|
||||
name: vimeo-v
|
||||
vimeo-square:
|
||||
prefix: fab
|
||||
name: square-vimeo
|
||||
volume-control-phone:
|
||||
name: phone-volume
|
||||
warning:
|
||||
name: triangle-exclamation
|
||||
wechat:
|
||||
prefix: fab
|
||||
name: weixin
|
||||
wheelchair-alt:
|
||||
prefix: fab
|
||||
name: accessible-icon
|
||||
window-close-o:
|
||||
prefix: far
|
||||
name: rectangle-xmark
|
||||
window-maximize:
|
||||
prefix: far
|
||||
window-restore:
|
||||
prefix: far
|
||||
won:
|
||||
name: won-sign
|
||||
xing-square:
|
||||
prefix: fab
|
||||
name: square-xing
|
||||
y-combinator-square:
|
||||
prefix: fab
|
||||
name: hacker-news
|
||||
yc:
|
||||
prefix: fab
|
||||
name: y-combinator
|
||||
yc-square:
|
||||
prefix: fab
|
||||
name: hacker-news
|
||||
yen:
|
||||
name: yen-sign
|
||||
youtube-play:
|
||||
prefix: fab
|
||||
name: youtube
|
||||
youtube-square:
|
||||
prefix: fab
|
||||
name: square-youtube
|
||||
1403
metadata/sponsors.yml
Normal file
1403
metadata/sponsors.yml
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user