├── .VSCodeCounter
└── 2021-04-28_21-38-47
│ ├── details.md
│ ├── results.csv
│ ├── results.md
│ └── results.txt
├── .gitignore
├── .metadata
├── .vscode
├── launch.json
└── settings.json
├── LICENSE
├── README.md
├── assets
├── fonts
│ ├── MySocialIcons.ttf
│ ├── Ubuntu-Bold.ttf
│ ├── Ubuntu-Medium.ttf
│ └── Ubuntu-Regular.ttf
├── images
│ └── logo
│ │ ├── logo.png
│ │ └── me.png
└── resume
│ └── resume.pdf
├── deploy.sh
├── lib
├── constants
│ ├── colors.dart
│ ├── routes.dart
│ └── types.dart
├── controllers
│ └── main-controller.dart
├── main.dart
├── models
│ ├── change-page.dart
│ ├── responsive
│ │ ├── layout_wrapper.dart
│ │ ├── responsive_builder.dart
│ │ ├── screen_type_layout.dart
│ │ └── sizing_information.dart
│ ├── social_icons.dart
│ ├── typewriter.dart
│ └── url_helper.dart
└── screens
│ ├── body
│ ├── body.dart
│ └── mobile-body.dart
│ ├── pages
│ ├── about
│ │ ├── about.dart
│ │ ├── about_mobile.dart
│ │ └── about_widgets.dart
│ ├── home
│ │ ├── home.dart
│ │ ├── home_mobile.dart
│ │ └── home_widgets.dart
│ ├── portfolio
│ │ ├── portfolio.dart
│ │ ├── portfolio_box.dart
│ │ ├── portfolio_mobile.dart
│ │ └── portfolio_widgets.dart
│ └── skills
│ │ ├── skill_box.dart
│ │ ├── skills.dart
│ │ ├── skills_mobile.dart
│ │ └── skills_widgets.dart
│ └── shared
│ ├── drawer.dart
│ ├── nav_bar.dart
│ ├── navbar
│ ├── item.dart
│ └── navbar.dart
│ └── social_media_bar.dart
├── pubspec.lock
├── pubspec.yaml
└── web
├── icons
├── android-icon-144x144.png
├── android-icon-192x192.png
├── android-icon-36x36.png
├── android-icon-48x48.png
├── android-icon-72x72.png
├── android-icon-96x96.png
├── apple-icon-114x114.png
├── apple-icon-120x120.png
├── apple-icon-144x144.png
├── apple-icon-152x152.png
├── apple-icon-180x180.png
├── apple-icon-57x57.png
├── apple-icon-60x60.png
├── apple-icon-72x72.png
├── apple-icon-76x76.png
├── apple-icon-precomposed.png
├── apple-icon.png
├── browserconfig.xml
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon-96x96.png
├── ms-icon-144x144.png
├── ms-icon-150x150.png
├── ms-icon-310x310.png
└── ms-icon-70x70.png
├── index.html
├── manifest.json
└── spinkit.css
/.VSCodeCounter/2021-04-28_21-38-47/details.md:
--------------------------------------------------------------------------------
1 | # Details
2 |
3 | Date : 2021-04-28 21:38:47
4 |
5 | Directory c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib
6 |
7 | Total : 23 files, 1789 codes, 55 comments, 167 blanks, all 2011 lines
8 |
9 | [summary](results.md)
10 |
11 | ## Files
12 | | filename | language | code | comment | blank | total |
13 | | :--- | :--- | ---: | ---: | ---: | ---: |
14 | | [lib/main.dart](/lib/main.dart) | Dart | 19 | 0 | 3 | 22 |
15 | | [lib/models/social_icons.dart](/lib/models/social_icons.dart) | Dart | 26 | 15 | 4 | 45 |
16 | | [lib/models/typewriter.dart](/lib/models/typewriter.dart) | Dart | 69 | 0 | 14 | 83 |
17 | | [lib/models/url_helper.dart](/lib/models/url_helper.dart) | Dart | 18 | 3 | 5 | 26 |
18 | | [lib/screens/about/about.dart](/lib/screens/about/about.dart) | Dart | 29 | 1 | 3 | 33 |
19 | | [lib/screens/about/about_mobile.dart](/lib/screens/about/about_mobile.dart) | Dart | 22 | 0 | 2 | 24 |
20 | | [lib/screens/about/about_widgets.dart](/lib/screens/about/about_widgets.dart) | Dart | 134 | 1 | 7 | 142 |
21 | | [lib/screens/home/home.dart](/lib/screens/home/home.dart) | Dart | 30 | 0 | 2 | 32 |
22 | | [lib/screens/home/home_mobile.dart](/lib/screens/home/home_mobile.dart) | Dart | 25 | 0 | 2 | 27 |
23 | | [lib/screens/home/home_widgets.dart](/lib/screens/home/home_widgets.dart) | Dart | 209 | 10 | 15 | 234 |
24 | | [lib/screens/main/body.dart](/lib/screens/main/body.dart) | Dart | 32 | 0 | 6 | 38 |
25 | | [lib/screens/main/main_page.dart](/lib/screens/main/main_page.dart) | Dart | 74 | 2 | 15 | 91 |
26 | | [lib/screens/responsive/layout_wrapper.dart](/lib/screens/responsive/layout_wrapper.dart) | Dart | 30 | 0 | 5 | 35 |
27 | | [lib/screens/responsive/responsive_builder.dart](/lib/screens/responsive/responsive_builder.dart) | Dart | 38 | 0 | 11 | 49 |
28 | | [lib/screens/responsive/screen_type_layout.dart](/lib/screens/responsive/screen_type_layout.dart) | Dart | 29 | 1 | 6 | 36 |
29 | | [lib/screens/responsive/sizing_information.dart](/lib/screens/responsive/sizing_information.dart) | Dart | 18 | 0 | 5 | 23 |
30 | | [lib/screens/skills/skill_box.dart](/lib/screens/skills/skill_box.dart) | Dart | 122 | 1 | 9 | 132 |
31 | | [lib/screens/skills/skills.dart](/lib/screens/skills/skills.dart) | Dart | 27 | 2 | 3 | 32 |
32 | | [lib/screens/skills/skills_mobile.dart](/lib/screens/skills/skills_mobile.dart) | Dart | 22 | 0 | 2 | 24 |
33 | | [lib/screens/skills/skills_widgets.dart](/lib/screens/skills/skills_widgets.dart) | Dart | 313 | 0 | 12 | 325 |
34 | | [lib/shared/drawer.dart](/lib/shared/drawer.dart) | Dart | 136 | 9 | 14 | 159 |
35 | | [lib/shared/nav_bar.dart](/lib/shared/nav_bar.dart) | Dart | 270 | 10 | 20 | 300 |
36 | | [lib/shared/social_media_bar.dart](/lib/shared/social_media_bar.dart) | Dart | 97 | 0 | 2 | 99 |
37 |
38 | [summary](results.md)
--------------------------------------------------------------------------------
/.VSCodeCounter/2021-04-28_21-38-47/results.csv:
--------------------------------------------------------------------------------
1 | "filename", "language", "Dart", "comment", "blank", "total"
2 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\main.dart", "Dart", 19, 0, 3, 22
3 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\models\social_icons.dart", "Dart", 26, 15, 4, 45
4 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\models\typewriter.dart", "Dart", 69, 0, 14, 83
5 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\models\url_helper.dart", "Dart", 18, 3, 5, 26
6 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\about\about.dart", "Dart", 29, 1, 3, 33
7 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\about\about_mobile.dart", "Dart", 22, 0, 2, 24
8 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\about\about_widgets.dart", "Dart", 134, 1, 7, 142
9 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\home\home.dart", "Dart", 30, 0, 2, 32
10 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\home\home_mobile.dart", "Dart", 25, 0, 2, 27
11 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\home\home_widgets.dart", "Dart", 209, 10, 15, 234
12 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\main\body.dart", "Dart", 32, 0, 6, 38
13 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\main\main_page.dart", "Dart", 74, 2, 15, 91
14 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\responsive\layout_wrapper.dart", "Dart", 30, 0, 5, 35
15 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\responsive\responsive_builder.dart", "Dart", 38, 0, 11, 49
16 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\responsive\screen_type_layout.dart", "Dart", 29, 1, 6, 36
17 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\responsive\sizing_information.dart", "Dart", 18, 0, 5, 23
18 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\skills\skill_box.dart", "Dart", 122, 1, 9, 132
19 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\skills\skills.dart", "Dart", 27, 2, 3, 32
20 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\skills\skills_mobile.dart", "Dart", 22, 0, 2, 24
21 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\skills\skills_widgets.dart", "Dart", 313, 0, 12, 325
22 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\shared\drawer.dart", "Dart", 136, 9, 14, 159
23 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\shared\nav_bar.dart", "Dart", 270, 10, 20, 300
24 | "c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\shared\social_media_bar.dart", "Dart", 97, 0, 2, 99
25 | "Total", "-", 1789, 55, 167, 2011
--------------------------------------------------------------------------------
/.VSCodeCounter/2021-04-28_21-38-47/results.md:
--------------------------------------------------------------------------------
1 | # Summary
2 |
3 | Date : 2021-04-28 21:38:47
4 |
5 | Directory c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib
6 |
7 | Total : 23 files, 1789 codes, 55 comments, 167 blanks, all 2011 lines
8 |
9 | [details](details.md)
10 |
11 | ## Languages
12 | | language | files | code | comment | blank | total |
13 | | :--- | ---: | ---: | ---: | ---: | ---: |
14 | | Dart | 23 | 1,789 | 55 | 167 | 2,011 |
15 |
16 | ## Directories
17 | | path | files | code | comment | blank | total |
18 | | :--- | ---: | ---: | ---: | ---: | ---: |
19 | | . | 23 | 1,789 | 55 | 167 | 2,011 |
20 | | models | 3 | 113 | 18 | 23 | 154 |
21 | | screens | 16 | 1,154 | 18 | 105 | 1,277 |
22 | | screens\about | 3 | 185 | 2 | 12 | 199 |
23 | | screens\home | 3 | 264 | 10 | 19 | 293 |
24 | | screens\main | 2 | 106 | 2 | 21 | 129 |
25 | | screens\responsive | 4 | 115 | 1 | 27 | 143 |
26 | | screens\skills | 4 | 484 | 3 | 26 | 513 |
27 | | shared | 3 | 503 | 19 | 36 | 558 |
28 |
29 | [details](details.md)
--------------------------------------------------------------------------------
/.VSCodeCounter/2021-04-28_21-38-47/results.txt:
--------------------------------------------------------------------------------
1 | Date : 2021-04-28 21:38:47
2 | Directory : c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib
3 | Total : 23 files, 1789 codes, 55 comments, 167 blanks, all 2011 lines
4 |
5 | Languages
6 | +----------+------------+------------+------------+------------+------------+
7 | | language | files | code | comment | blank | total |
8 | +----------+------------+------------+------------+------------+------------+
9 | | Dart | 23 | 1,789 | 55 | 167 | 2,011 |
10 | +----------+------------+------------+------------+------------+------------+
11 |
12 | Directories
13 | +---------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
14 | | path | files | code | comment | blank | total |
15 | +---------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
16 | | . | 23 | 1,789 | 55 | 167 | 2,011 |
17 | | models | 3 | 113 | 18 | 23 | 154 |
18 | | screens | 16 | 1,154 | 18 | 105 | 1,277 |
19 | | screens\about | 3 | 185 | 2 | 12 | 199 |
20 | | screens\home | 3 | 264 | 10 | 19 | 293 |
21 | | screens\main | 2 | 106 | 2 | 21 | 129 |
22 | | screens\responsive | 4 | 115 | 1 | 27 | 143 |
23 | | screens\skills | 4 | 484 | 3 | 26 | 513 |
24 | | shared | 3 | 503 | 19 | 36 | 558 |
25 | +---------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
26 |
27 | Files
28 | +---------------------------------------------------------------------------------------------------------+----------+------------+------------+------------+------------+
29 | | filename | language | code | comment | blank | total |
30 | +---------------------------------------------------------------------------------------------------------+----------+------------+------------+------------+------------+
31 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\main.dart | Dart | 19 | 0 | 3 | 22 |
32 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\models\social_icons.dart | Dart | 26 | 15 | 4 | 45 |
33 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\models\typewriter.dart | Dart | 69 | 0 | 14 | 83 |
34 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\models\url_helper.dart | Dart | 18 | 3 | 5 | 26 |
35 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\about\about.dart | Dart | 29 | 1 | 3 | 33 |
36 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\about\about_mobile.dart | Dart | 22 | 0 | 2 | 24 |
37 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\about\about_widgets.dart | Dart | 134 | 1 | 7 | 142 |
38 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\home\home.dart | Dart | 30 | 0 | 2 | 32 |
39 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\home\home_mobile.dart | Dart | 25 | 0 | 2 | 27 |
40 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\home\home_widgets.dart | Dart | 209 | 10 | 15 | 234 |
41 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\main\body.dart | Dart | 32 | 0 | 6 | 38 |
42 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\main\main_page.dart | Dart | 74 | 2 | 15 | 91 |
43 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\responsive\layout_wrapper.dart | Dart | 30 | 0 | 5 | 35 |
44 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\responsive\responsive_builder.dart | Dart | 38 | 0 | 11 | 49 |
45 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\responsive\screen_type_layout.dart | Dart | 29 | 1 | 6 | 36 |
46 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\responsive\sizing_information.dart | Dart | 18 | 0 | 5 | 23 |
47 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\skills\skill_box.dart | Dart | 122 | 1 | 9 | 132 |
48 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\skills\skills.dart | Dart | 27 | 2 | 3 | 32 |
49 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\skills\skills_mobile.dart | Dart | 22 | 0 | 2 | 24 |
50 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\screens\skills\skills_widgets.dart | Dart | 313 | 0 | 12 | 325 |
51 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\shared\drawer.dart | Dart | 136 | 9 | 14 | 159 |
52 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\shared\nav_bar.dart | Dart | 270 | 10 | 20 | 300 |
53 | | c:\Users\imanr\Erfan\FlutterProjects\My-Personal-Website\lib\shared\social_media_bar.dart | Dart | 97 | 0 | 2 | 99 |
54 | | Total | | 1,789 | 55 | 167 | 2,011 |
55 | +---------------------------------------------------------------------------------------------------------+----------+------------+------------+------------+------------+
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 | lib/generated_plugin_registrant.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
43 | # Non-Web platforms
44 | /android/
45 | /ios/
46 | /linux/
47 |
48 | # Android Studio will place build artifacts here
49 | /android/app/debug
50 | /android/app/profile
51 | /android/app/release
52 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: eefcff900c3cdf4aff43751c1b32a3aa65c91a4d
8 | channel: master
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "personal_web",
9 | "request": "launch",
10 | "type": "dart"
11 | }
12 | ]
13 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "git.ignoreLimitWarning": true
3 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | Copyright [2021] [Erfan Rahmati]
179 |
180 | Licensed under the Apache License, Version 2.0 (the "License");
181 | you may not use this file except in compliance with the License.
182 | You may obtain a copy of the License at
183 |
184 | http://www.apache.org/licenses/LICENSE-2.0
185 |
186 | Unless required by applicable law or agreed to in writing, software
187 | distributed under the License is distributed on an "AS IS" BASIS,
188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
189 | See the License for the specific language governing permissions and
190 | limitations under the License.
191 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 👤 My personal website
2 |
3 | > ### Checkout Website at https://ErfanRht.github.io/
4 | > ### Deployed using [Github Pages](https://pages.github.com/)
5 |
6 | ## Technologies Used
7 |
8 | - #### Flutter
9 | - #### Dart
10 | - #### HTML
11 | - #### Illustration (for images)
12 |
13 | ## Contributing
14 |
15 | Feel free to dive in! [Open an issue](https://github.com/ErfanRht/My-Personal-Website/issues/new) or submit PRs
16 |
17 | ## Issues
18 |
19 | Please file any issues, bugs or feature request [here](https://github.com/ErfanRht/My-Personal-Website/issues).
20 |
21 | ## License
22 |
23 | This project is licensed under the [Apache-2.0 License](https://github.com/ErfanRht/My-Personal-Website/blob/master/LICENSE).
24 |
25 | ## Author
26 |
27 | This Flutter project is developed by [Erfan Rahmati](https://github.com/ErfanRht).
28 |
29 | ---
30 |
31 |
32 |
33 | ### Show some ❤️ by starring 🌟 the repository!
34 |
35 |
36 |
--------------------------------------------------------------------------------
/assets/fonts/MySocialIcons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/assets/fonts/MySocialIcons.ttf
--------------------------------------------------------------------------------
/assets/fonts/Ubuntu-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/assets/fonts/Ubuntu-Bold.ttf
--------------------------------------------------------------------------------
/assets/fonts/Ubuntu-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/assets/fonts/Ubuntu-Medium.ttf
--------------------------------------------------------------------------------
/assets/fonts/Ubuntu-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/assets/fonts/Ubuntu-Regular.ttf
--------------------------------------------------------------------------------
/assets/images/logo/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/assets/images/logo/logo.png
--------------------------------------------------------------------------------
/assets/images/logo/me.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/assets/images/logo/me.png
--------------------------------------------------------------------------------
/assets/resume/resume.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/assets/resume/resume.pdf
--------------------------------------------------------------------------------
/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/bash
2 |
3 | # Get commit message
4 | if [ -z "$1" ]
5 | then
6 | message="Update"
7 | else
8 | message=$1
9 | fi
10 |
11 | # Clean up the build
12 | flutter clean
13 |
14 | # Get the dependencies
15 | pub get
16 |
17 | # Analyze for errors
18 | flutter analyze
19 |
20 | # Run web build
21 | flutter build web
22 |
23 | # Copy the generated files into the Github pages repo directory
24 | cp -R build/web/. ../../ErfanRht.github.io
25 |
26 | echo "Pushing with commit message: $message"
27 |
28 | # Change into the Github pages repo directory, commit the changes and push
29 | cd ../../ErfanRht.github.io
30 | git add .
31 | git commit -m "$message"
32 | git push
33 |
--------------------------------------------------------------------------------
/lib/constants/colors.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | const kPrimaryColor = Colors.teal;
4 |
--------------------------------------------------------------------------------
/lib/constants/routes.dart:
--------------------------------------------------------------------------------
1 | // Desktop routes
2 | const HomeRoute = "/home";
3 | const AboutRoute = "/about";
4 | const SkillsRoute = "/skills";
5 | const PortfolioRoute = "/portfolio";
6 | const ProjectsRoute = "/projects";
7 |
8 | // Mobile routes
9 | const HomeMobileRoute = "/home-mobile";
10 | const AboutMobileRoute = "/about-mobile";
11 | const SkillsMobileRoute = "/skills-mobile";
12 | const PortfolioMobileRoute = "/portfolio-mobile";
13 |
--------------------------------------------------------------------------------
/lib/constants/types.dart:
--------------------------------------------------------------------------------
1 | enum Pages { HOME, ABOUT, SKILLS, PORTFOLIO, RESUME }
2 |
--------------------------------------------------------------------------------
/lib/controllers/main-controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 | import 'package:personal_web/constants/types.dart';
3 |
4 | class MainController extends GetxController {
5 | Pages selectedPage = Pages.HOME;
6 | int selectedPageNum = 0;
7 |
8 | updatePage({Pages page, int pageNum}) {
9 | selectedPage = page!=null?page:selectedPage;
10 | selectedPageNum = pageNum!=null?pageNum:selectedPageNum;
11 | update();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 | import 'package:personal_web/constants/colors.dart';
3 | import 'package:personal_web/constants/routes.dart';
4 | import 'package:personal_web/constants/types.dart';
5 | import 'package:personal_web/controllers/main-controller.dart';
6 | import 'package:personal_web/models/responsive/layout_wrapper.dart';
7 | import 'package:flutter/material.dart';
8 | import 'package:personal_web/screens/pages/about/about.dart';
9 | import 'package:personal_web/screens/pages/about/about_mobile.dart';
10 | import 'package:personal_web/screens/pages/home/home.dart';
11 | import 'package:personal_web/screens/pages/home/home_mobile.dart';
12 | import 'package:personal_web/screens/pages/portfolio/portfolio.dart';
13 | import 'package:personal_web/screens/pages/portfolio/portfolio_mobile.dart';
14 | import 'package:personal_web/screens/pages/skills/skills.dart';
15 | import 'package:personal_web/screens/pages/skills/skills_mobile.dart';
16 |
17 | void main() {
18 | // ignore: unused_local_variable
19 | MainController mainController = Get.put(MainController());
20 | runApp(MyApp());
21 | }
22 |
23 | class MyApp extends StatelessWidget {
24 | @override
25 | Widget build(BuildContext context) {
26 | return GetMaterialApp(
27 | title: 'Erfan Rahmati',
28 | debugShowCheckedModeBanner: false,
29 | theme: ThemeData(
30 | primarySwatch: kPrimaryColor,
31 | fontFamily: 'Ubuntu',
32 | ),
33 | initialRoute: HomeRoute,
34 | routes: {
35 | HomeRoute: (context) => LayoutWrapper(
36 | page: HomeSection(),
37 | mobilePage: HomeSectionMobile(),
38 | selectedPage: Pages.HOME,
39 | ),
40 | AboutRoute: (context) => LayoutWrapper(
41 | page: AboutSection(),
42 | mobilePage: AboutSectionMobile(),
43 | selectedPage: Pages.ABOUT,
44 | ),
45 | SkillsRoute: (context) => LayoutWrapper(
46 | page: SkillsSection(),
47 | mobilePage: SkillsSectionMobile(),
48 | selectedPage: Pages.SKILLS,
49 | ),
50 | PortfolioRoute: (context) => LayoutWrapper(
51 | page: PortfolioSection(),
52 | mobilePage: PortfolioSectionMobile(),
53 | selectedPage: Pages.PORTFOLIO,
54 | ),
55 | },
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/models/change-page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:get/get.dart';
3 | import 'package:personal_web/constants/routes.dart';
4 | import 'package:personal_web/constants/types.dart';
5 | import 'package:personal_web/controllers/main-controller.dart';
6 |
7 | changePage(BuildContext context, Pages page) {
8 | String pageRoute;
9 | int pageNum;
10 | if (page == Pages.HOME) {
11 | pageRoute = HomeRoute;
12 | pageNum = 0;
13 | } else if (page == Pages.ABOUT) {
14 | pageRoute = AboutRoute;
15 | pageNum = 1;
16 | } else if (page == Pages.SKILLS) {
17 | pageRoute = SkillsRoute;
18 | pageNum = 2;
19 | } else if (page == Pages.PORTFOLIO) {
20 | pageRoute = PortfolioRoute;
21 | pageNum = 3;
22 | }
23 | Get.find().updatePage(page: page, pageNum: pageNum);
24 | Navigator.pushReplacementNamed(context, pageRoute);
25 | }
26 |
--------------------------------------------------------------------------------
/lib/models/responsive/layout_wrapper.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/constants/types.dart';
3 | import 'package:personal_web/models/responsive/screen_type_layout.dart';
4 | import 'package:personal_web/screens/body/body.dart';
5 | import 'package:personal_web/screens/body/mobile-body.dart';
6 |
7 | class LayoutWrapper extends StatelessWidget {
8 | Widget page;
9 | Widget mobilePage;
10 | Pages selectedPage;
11 | LayoutWrapper({@required this.page, @required this.mobilePage,@required this.selectedPage});
12 | @override
13 | Widget build(BuildContext context) {
14 | return ScreenTypeLayout(
15 | mobile: MobileBody(page: mobilePage, selectedPage: selectedPage),
16 | tablet: PageBody(page: page, selectedPage: selectedPage)
17 | );
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/models/responsive/responsive_builder.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'screen_type_layout.dart';
3 | import 'sizing_information.dart';
4 |
5 | class ResponsiveBuilder extends StatelessWidget {
6 | final Widget Function(
7 | BuildContext context,
8 | SizingInformation sizingInformation,
9 | ) builder;
10 |
11 | const ResponsiveBuilder({
12 | Key key,
13 | @required this.builder,
14 | }) : super(key: key);
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | final mediaQuery = MediaQuery.of(context);
19 |
20 | return LayoutBuilder(
21 | builder: (context, constraints) {
22 | final sizingInformation = SizingInformation(
23 | orientation: mediaQuery.orientation,
24 | deviceType: getDeviceType(mediaQuery),
25 | screenSize: mediaQuery.size,
26 | localWidgetSize: Size(constraints.maxWidth, constraints.maxHeight),
27 | );
28 |
29 | return builder(context, sizingInformation);
30 | },
31 | );
32 | }
33 |
34 | DeviceScreenType getDeviceType(MediaQueryData mediaQuery) {
35 | double deviceWidth = mediaQuery.size.shortestSide;
36 |
37 | if (deviceWidth > 950) {
38 | return DeviceScreenType.Desktop;
39 | }
40 |
41 | if (deviceWidth > 600) {
42 | return DeviceScreenType.Tablet;
43 | }
44 |
45 | return DeviceScreenType.Mobile;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lib/models/responsive/screen_type_layout.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'responsive_builder.dart';
4 |
5 | enum DeviceScreenType { Mobile, Tablet, Desktop }
6 |
7 | class ScreenTypeLayout extends StatelessWidget {
8 | // Mobile will be returned by default
9 | final Widget mobile;
10 | final Widget tablet;
11 | final Widget desktop;
12 |
13 | const ScreenTypeLayout({
14 | Key key,
15 | @required this.mobile,
16 | this.tablet,
17 | this.desktop,
18 | }) : super(key: key);
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | return ResponsiveBuilder(
23 | builder: (context, sizingInformation) {
24 | switch (sizingInformation.deviceType) {
25 | case DeviceScreenType.Tablet:
26 | case DeviceScreenType.Desktop:
27 | return tablet;
28 | break;
29 | default:
30 | return mobile;
31 | }
32 | },
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/models/responsive/sizing_information.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'screen_type_layout.dart';
4 |
5 | class SizingInformation {
6 | final Orientation orientation;
7 | final DeviceScreenType deviceType;
8 | final Size screenSize;
9 | final Size localWidgetSize;
10 |
11 | SizingInformation({
12 | this.orientation,
13 | this.deviceType,
14 | this.screenSize,
15 | this.localWidgetSize,
16 | });
17 |
18 | @override
19 | String toString() {
20 | return 'Orientation:$orientation DeviceType:$deviceType ScreenSize:$screenSize LocalWidgetSize:$localWidgetSize';
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/models/social_icons.dart:
--------------------------------------------------------------------------------
1 | /// Flutter icons SocialIcons
2 | /// Copyright (C) 2020 by original authors @ fluttericon.com, fontello.com
3 | /// This font was generated by FlutterIcon.com, which is derived from Fontello.
4 | ///
5 | /// To use this font, place it in your fonts/ directory and include the
6 | /// following in your pubspec.yaml
7 | ///
8 | /// flutter:
9 | /// fonts:
10 | /// - family: MySocialIcons
11 | /// fonts:
12 | /// - asset: fonts/MySocialIcons.ttf
13 | ///
14 | ///
15 | ///
16 | import 'package:flutter/widgets.dart';
17 |
18 | class SocialIcons {
19 | SocialIcons._();
20 |
21 | static const _kFontFam = 'MySocialIcons';
22 | static const _kFontPkg = null;
23 |
24 | static const IconData github =
25 | IconData(0xe800, fontFamily: _kFontFam, fontPackage: _kFontPkg);
26 | static const IconData facebook =
27 | IconData(0xe801, fontFamily: _kFontFam, fontPackage: _kFontPkg);
28 | static const IconData twitter =
29 | IconData(0xe802, fontFamily: _kFontFam, fontPackage: _kFontPkg);
30 | static const IconData play_store =
31 | IconData(0xe803, fontFamily: _kFontFam, fontPackage: _kFontPkg);
32 | static const IconData instagram =
33 | IconData(0xe804, fontFamily: _kFontFam, fontPackage: _kFontPkg);
34 | static const IconData medium =
35 | IconData(0xe805, fontFamily: _kFontFam, fontPackage: _kFontPkg);
36 | static const IconData linkedin =
37 | IconData(0xe806, fontFamily: _kFontFam, fontPackage: _kFontPkg);
38 | static const IconData whatsapp =
39 | IconData(0xe808, fontFamily: _kFontFam, fontPackage: _kFontPkg);
40 | static const IconData envelope =
41 | IconData(0xe809, fontFamily: _kFontFam, fontPackage: _kFontPkg);
42 | static const IconData cloud_download =
43 | IconData(0xe80a, fontFamily: _kFontFam, fontPackage: _kFontPkg);
44 | }
45 |
--------------------------------------------------------------------------------
/lib/models/typewriter.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class Typewriter extends StatefulWidget {
4 | final String text;
5 | final Curve curve;
6 | final TextStyle textStyle;
7 | final VoidCallback onEnd;
8 | final Duration duration;
9 | final bool animate;
10 |
11 | Typewriter(
12 | this.text, {
13 | this.curve = Curves.easeInOut,
14 | this.textStyle,
15 | this.onEnd,
16 | this.animate = true,
17 | this.duration = const Duration(seconds: 2),
18 | });
19 |
20 | @override
21 | _TypewriterState createState() => _TypewriterState();
22 | }
23 |
24 | class _TypewriterState extends State with TickerProviderStateMixin {
25 | Animation _characterCount;
26 | AnimationController controller;
27 |
28 | int _stringIndex;
29 |
30 | @override
31 | void initState() {
32 | super.initState();
33 | controller = AnimationController(
34 | duration: widget.duration,
35 | vsync: this,
36 | );
37 |
38 | _stringIndex = _stringIndex == null ? 0 : _stringIndex + 1;
39 |
40 | _characterCount = StepTween(begin: 0, end: widget.text.length).animate(
41 | CurvedAnimation(
42 | parent: controller,
43 | curve: widget.curve,
44 | ),
45 | )..addListener(() {
46 | setState(() {});
47 | });
48 |
49 | if (widget.animate) controller.forward();
50 |
51 | controller.addListener(() {
52 | if (widget.onEnd != null &&
53 | controller.status == AnimationStatus.completed) {
54 | widget.onEnd();
55 | }
56 | });
57 | }
58 |
59 | @override
60 | void dispose() {
61 | controller.dispose();
62 | super.dispose();
63 | }
64 |
65 | @override
66 | Widget build(BuildContext context) {
67 | return Container(
68 | child: _characterCount == null
69 | ? null
70 | : AnimatedBuilder(
71 | animation: _characterCount,
72 | builder: (BuildContext context, Widget child) {
73 | String text = !widget.animate
74 | ? widget.text
75 | : widget.text.substring(0, _characterCount.value);
76 |
77 | return Text(text, style: widget.textStyle);
78 | },
79 | ),
80 | );
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/lib/models/url_helper.dart:
--------------------------------------------------------------------------------
1 | // ignore: avoid_web_libraries_in_flutter
2 | import 'dart:js' as js;
3 | // ignore: avoid_web_libraries_in_flutter
4 | import 'dart:html' as html;
5 |
6 | import 'package:flutter/services.dart';
7 | import 'package:url_launcher/url_launcher.dart';
8 |
9 | class UrlHelper {
10 | static Future launchUrl(String url) async {
11 | if (await canLaunch(url)) {
12 | await launch(url, enableJavaScript: true);
13 | }
14 | }
15 |
16 | static Future downloadResume() async {
17 | final readValue = await rootBundle.load('assets/DKB_CV.pdf');
18 |
19 | // Call the "saveAs" method from the FileSaver.js libray
20 | js.context.callMethod("saveAs", [
21 | html.Blob([readValue]),
22 | "DKB Resume.pdf",
23 | ]);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/screens/body/body.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/constants/colors.dart';
3 | import 'package:personal_web/constants/types.dart';
4 | import 'package:personal_web/screens/shared/navbar/navbar.dart';
5 | import 'package:personal_web/screens/shared/social_media_bar.dart';
6 |
7 | class PageBody extends StatelessWidget {
8 | Widget page;
9 | Pages selectedPage;
10 | PageBody({@required this.page, @required this.selectedPage});
11 | @override
12 | Widget build(BuildContext context) {
13 | return Scaffold(
14 | //backgroundColor: Color(0xfffafafa),
15 | body: Stack(
16 | children: [
17 | CustomPaint(painter: _BackgroundPainter(), size: Size.infinite),
18 | Column(
19 | children: [Navbar(selectedPage: selectedPage), Expanded(child: page)],
20 | ),
21 | Align(alignment: Alignment.centerLeft, child: SocialMediaBar()),
22 | ],
23 | ),
24 | );
25 | }
26 | }
27 |
28 | class _BackgroundPainter extends CustomPainter {
29 | @override
30 | void paint(Canvas canvas, Size size) {
31 | final path = Path();
32 |
33 | path.moveTo(size.width * 0.4, 0);
34 | path.lineTo(size.width, 0);
35 | path.lineTo(size.width, size.height);
36 | path.lineTo(size.width * 0.6, size.height);
37 | path.close();
38 |
39 | final paint = Paint()
40 | ..color = kPrimaryColor
41 | ..style = PaintingStyle.fill;
42 |
43 | canvas.drawPath(path, paint);
44 | }
45 |
46 | @override
47 | bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
48 | }
49 |
--------------------------------------------------------------------------------
/lib/screens/body/mobile-body.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/constants/types.dart';
3 | import 'package:personal_web/screens/shared/drawer.dart';
4 | import 'package:personal_web/screens/shared/nav_bar.dart';
5 | import 'package:personal_web/screens/shared/navbar/navbar.dart';
6 | import 'package:personal_web/screens/shared/social_media_bar.dart';
7 |
8 | class MobileBody extends StatelessWidget {
9 | Widget page;
10 | Pages selectedPage;
11 | MobileBody({@required this.page, @required this.selectedPage});
12 | @override
13 | Widget build(BuildContext context) {
14 | return Scaffold(
15 | appBar: MobileNavbar(),
16 | endDrawer: AppDrawer(
17 | selectedPage: selectedPage
18 | ),
19 | body: page
20 | );
21 | }
22 | }
--------------------------------------------------------------------------------
/lib/screens/pages/about/about.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/screens/pages/about/about_widgets.dart';
3 |
4 | class AboutSection extends StatefulWidget {
5 | @override
6 | _AboutSectionState createState() => _AboutSectionState();
7 | }
8 |
9 | class _AboutSectionState extends State {
10 | @override
11 | Widget build(BuildContext context) {
12 | return Center(
13 | child: Row(
14 | children: [
15 | Spacer(flex: 1),
16 | //SizedBox(width: 32),
17 | Expanded(
18 | flex: 7,
19 | child: AboutManImage(),
20 | ),
21 | Spacer(flex: 2),
22 | //SizedBox(width: 36),
23 | Expanded(
24 | flex: 6,
25 | child: AboutContent(),
26 | ),
27 | Spacer(flex: 2),
28 | ],
29 | ),
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/screens/pages/about/about_mobile.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/constants/colors.dart';
3 | import 'package:personal_web/screens/pages/about/about_widgets.dart';
4 |
5 | class AboutSectionMobile extends StatelessWidget {
6 | @override
7 | Widget build(BuildContext context) {
8 | return Center(
9 | child: SingleChildScrollView(
10 | padding: const EdgeInsets.fromLTRB(30, 4, 30, 24),
11 | child: Column(
12 | mainAxisAlignment: MainAxisAlignment.center,
13 | mainAxisSize: MainAxisSize.min,
14 | crossAxisAlignment: CrossAxisAlignment.start,
15 | children: [
16 | Image.asset('assets/images/illustration/about.png'),
17 | SizedBox(height: 32),
18 | AboutContent(color: kPrimaryColor, isMobile: true),
19 | ],
20 | ),
21 | ),
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/screens/pages/about/about_widgets.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:ms_undraw/ms_undraw.dart';
3 | import 'package:personal_web/constants/colors.dart';
4 | import 'package:personal_web/models/typewriter.dart';
5 |
6 | class AboutManImage extends StatelessWidget {
7 | @override
8 | Widget build(BuildContext context) {
9 | return UnDraw(
10 | color: kPrimaryColor,
11 | illustration: UnDrawIllustration.programming,
12 | placeholder: Text(
13 | "Illustration is loading...",
14 | style: TextStyle(
15 | color: kPrimaryColor,
16 | fontSize: 20,
17 | ),
18 | ),
19 | errorWidget: Icon(Icons.error_outline, color: kPrimaryColor, size: 50),
20 | );
21 | }
22 | }
23 |
24 | class AboutContent extends StatefulWidget {
25 | final Color color;
26 | final bool isMobile;
27 |
28 | const AboutContent({this.color = Colors.white, this.isMobile = false});
29 | @override
30 | _AboutContentState createState() => _AboutContentState();
31 | }
32 |
33 | class _AboutContentState extends State
34 | with TickerProviderStateMixin {
35 | static bool showAbout = false;
36 | static bool showStack1 = false;
37 | static bool showStack2 = false;
38 |
39 | static bool whoSeen = false;
40 | static bool aboutSeen = false;
41 | static bool stack1Seen = false;
42 | static bool stack2Seen = false;
43 |
44 | @override
45 | Widget build(BuildContext context) {
46 | return AnimatedSize(
47 | vsync: this,
48 | duration: kThemeAnimationDuration,
49 | alignment: Alignment.topCenter,
50 | child: Column(
51 | crossAxisAlignment: CrossAxisAlignment.start,
52 | mainAxisAlignment: MainAxisAlignment.center,
53 | mainAxisSize: MainAxisSize.min,
54 | children: [
55 | Typewriter(
56 | 'Who am I?',
57 | animate: !whoSeen,
58 | duration: const Duration(seconds: 1),
59 | textStyle: TextStyle(
60 | color: widget.color,
61 | fontSize: 24,
62 | fontWeight: FontWeight.w700,
63 | letterSpacing: 1.4,
64 | ),
65 | onEnd: () {
66 | if (mounted) {
67 | setState(() {
68 | showAbout = true;
69 | whoSeen = true;
70 | });
71 | }
72 | },
73 | ),
74 | Container(
75 | width: 60,
76 | height: 2,
77 | margin: const EdgeInsets.only(top: 4, bottom: 16),
78 | color: widget.color,
79 | ),
80 | if (showAbout)
81 | Typewriter(
82 | "Hello! I'm Erfan Rahmati, A teen software developer.\n\n"
83 | "I love to create performant and interesting stuff that are beneficial to the community.\n"
84 | "I enjoy learning and exploring new areas in the technologies I work with and even the ones outside my stack.\n\n",
85 | //"Currently I am working with Dart, Python and Framework languages.",
86 | animate: !aboutSeen,
87 | duration: const Duration(seconds: 10),
88 | textStyle: TextStyle(
89 | color: widget.color,
90 | fontSize: 16,
91 | letterSpacing: 1.2,
92 | height: 1.3,
93 | ),
94 | onEnd: () {
95 | if (mounted) {
96 | setState(() {
97 | showStack1 = true;
98 | aboutSeen = true;
99 | });
100 | }
101 | },
102 | ),
103 | if (showStack1) ...[
104 | SizedBox(height: 54),
105 | Typewriter(
106 | 'What things is I use to get stuff done?',
107 | animate: !stack1Seen,
108 | duration: const Duration(seconds: 2),
109 | textStyle: TextStyle(
110 | color: widget.color,
111 | fontSize: 24,
112 | fontWeight: FontWeight.w700,
113 | letterSpacing: 1.4,
114 | ),
115 | onEnd: () {
116 | if (mounted) {
117 | setState(() {
118 | showStack2 = true;
119 | stack1Seen = true;
120 | });
121 | }
122 | },
123 | ),
124 | Container(
125 | width: 60,
126 | height: 2,
127 | margin: const EdgeInsets.only(top: 4, bottom: 16),
128 | color: widget.color,
129 | ),
130 | if (showStack2)
131 | Typewriter(
132 | 'OS: Ubuntu 20.04\nBrowser: Chorme Web Browser\nTerminal: ZSH: Oh My Zsh (PowerLevel10k)\nCode Editor: VSCode - The best editor out there.\nTo Stay Updated: Medium, Virgool, Telegram and Twitter.',
133 | animate: !stack2Seen,
134 | duration: const Duration(seconds: 6),
135 | textStyle: TextStyle(
136 | color: widget.color,
137 | fontSize: 16,
138 | letterSpacing: 1.2,
139 | height: 1.3,
140 | ),
141 | onEnd: () {
142 | if (mounted) {
143 | setState(() {
144 | stack2Seen = true;
145 | });
146 | }
147 | },
148 | ),
149 | ],
150 | ],
151 | ),
152 | );
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/lib/screens/pages/home/home.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/screens/pages/home/home_widgets.dart';
3 |
4 | class HomeSection extends StatelessWidget {
5 | @override
6 | Widget build(BuildContext context) {
7 | return Center(
8 | child: Row(
9 | children: [
10 | Spacer(flex: 2),
11 | SizedBox(width: 32),
12 | Expanded(
13 | flex: 6,
14 | child: Introduction(),
15 | ),
16 | SizedBox(width: 36),
17 | Expanded(
18 | flex: 8,
19 | child: Padding(
20 | padding: EdgeInsets.only(left: 150),
21 | child: HeroImage(
22 | widgetColor: Color(0xfffafafa),
23 | ),
24 | ),
25 | ),
26 | Spacer(flex: 2),
27 | ],
28 | ),
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/screens/pages/home/home_mobile.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/constants/colors.dart';
3 | import 'package:personal_web/screens/pages/home/home_widgets.dart';
4 |
5 | class HomeSectionMobile extends StatelessWidget {
6 | @override
7 | Widget build(BuildContext context) {
8 | return Center(
9 | child: SingleChildScrollView(
10 | padding: const EdgeInsets.fromLTRB(30, 4, 30, 12),
11 | child: Column(
12 | mainAxisAlignment: MainAxisAlignment.center,
13 | mainAxisSize: MainAxisSize.min,
14 | crossAxisAlignment: CrossAxisAlignment.start,
15 | children: [
16 | HeroImage(
17 | backgroundColor: kPrimaryColor,
18 | widgetColor: kPrimaryColor
19 | ),
20 | SizedBox(height: 32),
21 | Introduction(),
22 | ],
23 | ),
24 | ),
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/screens/pages/home/home_widgets.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/constants/colors.dart';
3 | import 'package:personal_web/models/typewriter.dart';
4 | import 'package:personal_web/models/url_helper.dart';
5 |
6 | /// Introductory texts with the Hire Me button as well
7 | class Introduction extends StatefulWidget {
8 | @override
9 | _IntroductionState createState() => _IntroductionState();
10 | }
11 |
12 | class _IntroductionState extends State
13 | with SingleTickerProviderStateMixin {
14 | static bool helloSeen = false;
15 | static bool nameSeen = false;
16 | static bool positionSeen = false;
17 | static bool abstractSeen = false;
18 |
19 | static bool showName = false;
20 | static bool showPosition = false;
21 | static bool showAbstract = false;
22 | static bool showHireMe = false;
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | return AnimatedSize(
27 | vsync: this,
28 | duration: kThemeAnimationDuration,
29 | alignment: Alignment.topCenter,
30 | child: Column(
31 | crossAxisAlignment: CrossAxisAlignment.start,
32 | mainAxisAlignment: MainAxisAlignment.center,
33 | mainAxisSize: MainAxisSize.min,
34 | children: [
35 | Typewriter(
36 | "Hey! I'm...",
37 | animate: !helloSeen,
38 | textStyle: TextStyle(
39 | color: kPrimaryColor,
40 | fontSize: 24,
41 | fontWeight: FontWeight.w700,
42 | letterSpacing: 1.4,
43 | ),
44 | onEnd: () {
45 | if (mounted) {
46 | setState(() {
47 | showName = true;
48 | helloSeen = true;
49 | });
50 | }
51 | },
52 | ),
53 | if (showName) ...[
54 | SizedBox(height: 16),
55 | Typewriter(
56 | 'Erfan Rahmati',
57 | animate: !nameSeen,
58 | textStyle: TextStyle(
59 | color: Colors.blueGrey[900],
60 | fontSize: 40,
61 | fontWeight: FontWeight.w700,
62 | ),
63 | onEnd: () {
64 | if (mounted) {
65 | setState(() {
66 | showPosition = true;
67 | nameSeen = true;
68 | });
69 | }
70 | },
71 | ),
72 | ],
73 | if (showPosition) ...[
74 | SizedBox(height: 16),
75 | Typewriter(
76 | 'Mobile & Web Developer',
77 | animate: !positionSeen,
78 | textStyle: TextStyle(
79 | color: Colors.blueGrey[900],
80 | fontSize: 20,
81 | fontWeight: FontWeight.w500,
82 | ),
83 | onEnd: () {
84 | if (mounted) {
85 | setState(() {
86 | showAbstract = true;
87 | positionSeen = true;
88 | });
89 | }
90 | },
91 | ),
92 | ],
93 | if (showAbstract) ...[
94 | SizedBox(height: 24),
95 | Typewriter(
96 | "I build neat, cool and scalable mobile apps with Flutter and I'm an aspiring deep learning engineer.\n"
97 | 'I love to learn and build new stuff that are beneficial to the community and cool to work on.\n'
98 | 'I also have great interest in the open source community.',
99 | animate: !abstractSeen,
100 | textStyle: TextStyle(
101 | color: Colors.grey,
102 | fontSize: 16,
103 | letterSpacing: 1.2,
104 | height: 1.3,
105 | ),
106 | onEnd: () {
107 | Future.delayed(Duration(milliseconds: 500), () {
108 | if (mounted) {
109 | setState(() {
110 | showHireMe = true;
111 | abstractSeen = true;
112 | });
113 | }
114 | });
115 | },
116 | ),
117 | ],
118 | if (showHireMe) ...[
119 | SizedBox(height: 30),
120 | _HireMeButton(),
121 | ],
122 | ],
123 | ),
124 | );
125 | }
126 | }
127 |
128 | class _HireMeButton extends StatefulWidget {
129 | @override
130 | __HireMeButtonState createState() => __HireMeButtonState();
131 | }
132 |
133 | class __HireMeButtonState extends State<_HireMeButton> {
134 | bool hovered = false;
135 |
136 | @override
137 | Widget build(BuildContext context) {
138 | return InkWell(
139 | hoverColor: Colors.transparent,
140 | splashColor: Colors.transparent,
141 | onTap: () {
142 | UrlHelper.launchUrl("mailto:ErfanRht1384.com@gmail.com");
143 | },
144 | onHover: (value) {
145 | if (mounted) {
146 | setState(() {
147 | hovered = value;
148 | });
149 | }
150 | },
151 | child: AnimatedContainer(
152 | height: 50,
153 | width: 160,
154 | duration: kThemeAnimationDuration,
155 | alignment: Alignment.center,
156 | decoration: BoxDecoration(
157 | border: Border.all(width: 1.4, color: kPrimaryColor),
158 | borderRadius: BorderRadius.all(Radius.circular(50)),
159 | color: hovered ? kPrimaryColor.withOpacity(1.0) : Colors.transparent,
160 | ),
161 | child: AnimatedDefaultTextStyle(
162 | duration: kThemeAnimationDuration,
163 | style: TextStyle(
164 | color: hovered ? Colors.white : kPrimaryColor,
165 | fontSize: 17,
166 | fontWeight: FontWeight.w500,
167 | fontFamily: 'Ubuntu',
168 | ),
169 | child: Text(
170 | 'Hire Me',
171 | ),
172 | ),
173 | ),
174 | );
175 | }
176 | }
177 |
178 | class HeroImage extends StatefulWidget {
179 | final Color borderColor;
180 | final Color backgroundColor;
181 | final Color widgetColor;
182 |
183 | HeroImage({
184 | this.borderColor = Colors.white,
185 | this.backgroundColor = Colors.transparent,
186 | this.widgetColor = Colors.white,
187 | });
188 |
189 | @override
190 | _HeroImageState createState() => _HeroImageState();
191 | }
192 |
193 | class _HeroImageState extends State {
194 | bool showLogo;
195 |
196 | wait() async {
197 | await Future.delayed(Duration(milliseconds: 250));
198 | setState(() {
199 | showLogo = !showLogo;
200 | });
201 | }
202 |
203 | @override
204 | void initState() {
205 | super.initState();
206 | showLogo = false;
207 | wait();
208 | }
209 |
210 | @override
211 | Widget build(BuildContext context) {
212 | return AnimatedOpacity(
213 | opacity: showLogo ? 1 : 0,
214 | duration: Duration(milliseconds: 250),
215 | child: Container(
216 | width: 300,
217 | height: 300,
218 | child: Image.asset(
219 | 'assets/images/logo/me.png',
220 | color: widget.widgetColor,
221 | ),
222 | ),
223 | );
224 | }
225 | }
226 |
--------------------------------------------------------------------------------
/lib/screens/pages/portfolio/portfolio.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/screens/pages/portfolio/portfolio_widgets.dart';
3 |
4 | class PortfolioSection extends StatefulWidget {
5 | @override
6 | _PortfolioSectionState createState() => _PortfolioSectionState();
7 | }
8 |
9 | class _PortfolioSectionState extends State {
10 | @override
11 | Widget build(BuildContext context) {
12 | return Center(
13 | child: Row(
14 | children: [
15 | Spacer(flex: 1),
16 | SizedBox(width: 10),
17 | Expanded(
18 | flex: 10,
19 | child: PortfolioManImage(false),
20 | ),
21 | //SizedBox(width: 36),
22 | Expanded(
23 | flex: 8,
24 | child: PortfolioContent(),
25 | ),
26 | //Spacer(flex: 2),
27 | ],
28 | ),
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/screens/pages/portfolio/portfolio_box.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/models/typewriter.dart';
3 |
4 | class PortfolioBox extends StatefulWidget {
5 | final String name;
6 | final Color color;
7 | final bool isMobile, seen;
8 | final double score;
9 | final int waitTime;
10 |
11 | const PortfolioBox(
12 | {this.name,
13 | this.color = Colors.white,
14 | this.isMobile = false,
15 | this.score = 0,
16 | this.seen = false,
17 | this.waitTime = 0});
18 | @override
19 | _PortfolioBoxState createState() => _PortfolioBoxState();
20 | }
21 |
22 | class _PortfolioBoxState extends State
23 | with TickerProviderStateMixin {
24 | double widgetWidth, insideWidgetWidth, space;
25 | int showSpeed;
26 | bool start;
27 | @override
28 | void initState() {
29 | super.initState();
30 | showSpeed = 750;
31 | if (widget.seen) {
32 | start = true;
33 | widgetWidth = 200;
34 | insideWidgetWidth = widget.score * 2;
35 | } else {
36 | start = false;
37 | widgetWidth = 0;
38 | insideWidgetWidth = 0;
39 | }
40 |
41 | if (widget.name == 'Dart ') {
42 | space = 7.0;
43 | } else if (widget.name == 'PhP ') {
44 | space = 8.5;
45 | } else if (widget.name == 'Git ') {
46 | space = 9;
47 | } else if (widget.name == 'MySQL ') {
48 | space = 6.5;
49 | } else if (widget.name == 'Linux ') {
50 | space = 11.5;
51 | } else if (widget.name == 'HTML ') {
52 | space = 8;
53 | } else {
54 | space = 5;
55 | }
56 |
57 | startWidget();
58 | //updateValues();
59 | }
60 |
61 | @override
62 | Widget build(BuildContext context) {
63 | return Stack(
64 | children: [
65 | if (start)
66 | Row(
67 | children: [
68 | Typewriter(
69 | widget.name,
70 | animate: true,
71 | duration: Duration(milliseconds: widget.seen ? 0 : 350),
72 | textStyle: TextStyle(
73 | color: widget.color,
74 | fontSize: 15,
75 | fontWeight: FontWeight.w700,
76 | letterSpacing: 1.4,
77 | ),
78 | onEnd: () async {
79 | if (mounted) {
80 | await Future.delayed(Duration(milliseconds: 250));
81 | updateValues();
82 | }
83 | },
84 | ),
85 | ],
86 | ),
87 | AnimatedContainer(
88 | margin: EdgeInsets.only(left: 70),
89 | duration: Duration(milliseconds: widget.seen ? 0 : showSpeed),
90 | decoration: BoxDecoration(
91 | color: widget.isMobile ? Color(0xffd3d3d3) : Color(0xfffafafa),
92 | borderRadius: BorderRadius.circular(8)),
93 | height: 17.5,
94 | width: widgetWidth,
95 | child: Center(
96 | child: Row(
97 | children: [
98 | SizedBox(
99 | width: 2.5,
100 | ),
101 | AnimatedContainer(
102 | duration: Duration(milliseconds: widget.seen ? 0 : showSpeed),
103 | decoration: BoxDecoration(
104 | color: Colors.blue,
105 | borderRadius: BorderRadius.circular(6)),
106 | height: 12.5,
107 | width: insideWidgetWidth,
108 | ),
109 | ],
110 | ),
111 | ),
112 | ),
113 | ],
114 | );
115 | }
116 |
117 | startWidget() async {
118 | if (!widget.seen) {
119 | await Future.delayed(Duration(milliseconds: widget.waitTime));
120 | setState(() {
121 | start = true;
122 | });
123 | }
124 | }
125 |
126 | updateValues() async {
127 | setState(() {
128 | widgetWidth = 200;
129 | });
130 | if (!widget.seen) {
131 | await Future.delayed(Duration(milliseconds: showSpeed));
132 | setState(() {
133 | insideWidgetWidth = widget.score * 2;
134 | });
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/lib/screens/pages/portfolio/portfolio_mobile.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/constants/colors.dart';
3 | import 'package:personal_web/screens/pages/portfolio/portfolio_widgets.dart';
4 |
5 | class PortfolioSectionMobile extends StatelessWidget {
6 | @override
7 | Widget build(BuildContext context) {
8 | return Center(
9 | child: SingleChildScrollView(
10 | padding: const EdgeInsets.fromLTRB(30, 4, 30, 24),
11 | child: Column(
12 | mainAxisAlignment: MainAxisAlignment.center,
13 | mainAxisSize: MainAxisSize.min,
14 | crossAxisAlignment: CrossAxisAlignment.start,
15 | children: [
16 | PortfolioManImage(true),
17 | SizedBox(height: 32),
18 | PortfolioContent(color: kPrimaryColor, isMobile: true),
19 | ],
20 | ),
21 | ),
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/screens/pages/portfolio/portfolio_widgets.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/rendering.dart';
3 | import 'package:personal_web/models/typewriter.dart';
4 |
5 | class PortfolioManImage extends StatelessWidget {
6 | final bool isMobile;
7 | const PortfolioManImage(this.isMobile);
8 | @override
9 | Widget build(BuildContext context) {
10 | return Padding(
11 | padding: EdgeInsets.only(right: isMobile ? 0 : 150),
12 | child: Image.asset(
13 | 'assets/images/illustration/Portfolios.png',
14 | height: 450,
15 | ),
16 | );
17 | }
18 | }
19 |
20 | class PortfolioContent extends StatefulWidget {
21 | final Color color;
22 | final bool isMobile;
23 |
24 | const PortfolioContent({this.color = Colors.white, this.isMobile = false});
25 | @override
26 | _PortfolioContentState createState() => _PortfolioContentState();
27 | }
28 |
29 | class _PortfolioContentState extends State
30 | with TickerProviderStateMixin {
31 | static bool showPortfolio = false;
32 | static bool portfolioSeen = false;
33 | static bool whatSeen = false;
34 | static double space, widthSpace;
35 |
36 | List portfolio;
37 | List scores;
38 | int showSpeed, portfolioNumber;
39 |
40 | @override
41 | void initState() {
42 | super.initState();
43 | space = 30;
44 | widthSpace = 50;
45 | showSpeed = 750;
46 | portfolioNumber = -2;
47 | portfolio = [
48 | 'Flutter',
49 | 'Python',
50 | 'Dart',
51 | 'PHP',
52 | 'Git',
53 | 'Linux',
54 | 'HTML',
55 | 'MySQL',
56 | 'Regex',
57 | 'JSON'
58 | ];
59 |
60 | scores = [90.0, 80.0, 85.0, 60.0, 90.0, 85.0, 75.0, 80.0, 75.0, 85];
61 | endPage();
62 | }
63 |
64 | @override
65 | Widget build(BuildContext context) {
66 | return AnimatedSize(
67 | vsync: this,
68 | duration: kThemeAnimationDuration,
69 | alignment: Alignment.topCenter,
70 | child: Column(
71 | crossAxisAlignment: CrossAxisAlignment.start,
72 | mainAxisAlignment: MainAxisAlignment.center,
73 | mainAxisSize: MainAxisSize.min,
74 | children: [],
75 | ),
76 | );
77 | }
78 |
79 | endPage() async {
80 | await Future.delayed(
81 | Duration(milliseconds: (portfolio.length + 1) * 3 * showSpeed));
82 | setState(() {
83 | portfolioSeen = true;
84 | });
85 | }
86 |
87 | Widget sizedBox(double height, double width) {
88 | return SizedBox(
89 | height: height,
90 | width: width,
91 | );
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/lib/screens/pages/skills/skill_box.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/models/typewriter.dart';
3 |
4 | class SkillBox extends StatefulWidget {
5 | final String name;
6 | final Color color;
7 | final bool isMobile, seen;
8 | final double score;
9 | final int waitTime;
10 |
11 | const SkillBox(
12 | {this.name,
13 | this.color = Colors.white,
14 | this.isMobile = false,
15 | this.score = 0,
16 | this.seen = false,
17 | this.waitTime = 0});
18 | @override
19 | _SkillBoxState createState() => _SkillBoxState();
20 | }
21 |
22 | class _SkillBoxState extends State with TickerProviderStateMixin {
23 | double widgetWidth, insideWidgetWidth, space;
24 | int showSpeed;
25 | bool start;
26 | @override
27 | void initState() {
28 | super.initState();
29 | showSpeed = 750;
30 | if (widget.seen) {
31 | start = true;
32 | widgetWidth = 200;
33 | insideWidgetWidth = widget.score * 2;
34 | } else {
35 | start = false;
36 | widgetWidth = 0;
37 | insideWidgetWidth = 0;
38 | }
39 |
40 | if (widget.name == 'Dart ') {
41 | space = 7.0;
42 | } else if (widget.name == 'PhP ') {
43 | space = 8.5;
44 | } else if (widget.name == 'Git ') {
45 | space = 9;
46 | } else if (widget.name == 'MySQL ') {
47 | space = 6.5;
48 | } else if (widget.name == 'Linux ') {
49 | space = 11.5;
50 | } else if (widget.name == 'HTML ') {
51 | space = 8;
52 | } else {
53 | space = 5;
54 | }
55 |
56 | startWidget();
57 | //updateValues();
58 | }
59 |
60 | @override
61 | Widget build(BuildContext context) {
62 | return Stack(
63 | children: [
64 | if (start)
65 | Row(
66 | children: [
67 | Typewriter(
68 | widget.name,
69 | animate: true,
70 | duration: Duration(milliseconds: widget.seen ? 0 : 350),
71 | textStyle: TextStyle(
72 | color: widget.color,
73 | fontSize: 15,
74 | fontWeight: FontWeight.w700,
75 | letterSpacing: 1.4,
76 | ),
77 | onEnd: () async {
78 | if (mounted) {
79 | await Future.delayed(Duration(milliseconds: 250));
80 | updateValues();
81 | }
82 | },
83 | ),
84 | ],
85 | ),
86 | AnimatedContainer(
87 | margin: EdgeInsets.only(left: 70),
88 | duration: Duration(milliseconds: widget.seen ? 0 : showSpeed),
89 | decoration: BoxDecoration(
90 | color: widget.isMobile ? Color(0xffd3d3d3) : Color(0xfffafafa),
91 | borderRadius: BorderRadius.circular(8)),
92 | height: 17.5,
93 | width: widgetWidth,
94 | child: Center(
95 | child: Row(
96 | children: [
97 | SizedBox(
98 | width: 2.5,
99 | ),
100 | AnimatedContainer(
101 | duration: Duration(milliseconds: widget.seen ? 0 : showSpeed),
102 | decoration: BoxDecoration(
103 | color: Colors.blue,
104 | borderRadius: BorderRadius.circular(6)),
105 | height: 12.5,
106 | width: insideWidgetWidth,
107 | ),
108 | ],
109 | ),
110 | ),
111 | ),
112 | ],
113 | );
114 | }
115 |
116 | startWidget() async {
117 | if (!widget.seen) {
118 | await Future.delayed(Duration(milliseconds: widget.waitTime));
119 | setState(() {
120 | start = true;
121 | });
122 | }
123 | }
124 |
125 | updateValues() async {
126 | setState(() {
127 | widgetWidth = 200;
128 | });
129 | if (!widget.seen) {
130 | await Future.delayed(Duration(milliseconds: showSpeed));
131 | setState(() {
132 | insideWidgetWidth = widget.score * 2;
133 | });
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/lib/screens/pages/skills/skills.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/screens/pages/skills/skills_widgets.dart';
3 |
4 | class SkillsSection extends StatefulWidget {
5 | @override
6 | _SkillsSectionState createState() => _SkillsSectionState();
7 | }
8 |
9 | class _SkillsSectionState extends State {
10 | @override
11 | Widget build(BuildContext context) {
12 | return Center(
13 | child: Row(
14 | children: [
15 | Spacer(flex: 1),
16 | Expanded(
17 | flex: 7,
18 | child: SkillsManImage(false),
19 | ),
20 | Spacer(flex: 2),
21 | Expanded(
22 | flex: 8,
23 | child: SkillsContent(),
24 | ),
25 | //Spacer(flex: 2),
26 | ],
27 | ),
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/screens/pages/skills/skills_mobile.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/constants/colors.dart';
3 | import 'package:personal_web/screens/pages/skills/skills_widgets.dart';
4 |
5 | class SkillsSectionMobile extends StatelessWidget {
6 | @override
7 | Widget build(BuildContext context) {
8 | return Center(
9 | child: SingleChildScrollView(
10 | padding: const EdgeInsets.fromLTRB(30, 4, 30, 24),
11 | child: Column(
12 | mainAxisAlignment: MainAxisAlignment.center,
13 | mainAxisSize: MainAxisSize.min,
14 | crossAxisAlignment: CrossAxisAlignment.start,
15 | children: [
16 | SkillsManImage(true),
17 | SizedBox(height: 32),
18 | SkillsContent(color: kPrimaryColor, isMobile: true),
19 | ],
20 | ),
21 | ),
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/screens/pages/skills/skills_widgets.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/rendering.dart';
3 | import 'package:ms_undraw/ms_undraw.dart';
4 | import 'package:personal_web/constants/colors.dart';
5 | import 'package:personal_web/models/typewriter.dart';
6 | import 'package:personal_web/screens/pages/skills/skill_box.dart';
7 |
8 | class SkillsManImage extends StatelessWidget {
9 | final bool isMobile;
10 | const SkillsManImage(this.isMobile);
11 | @override
12 | Widget build(BuildContext context) {
13 | return UnDraw(
14 | color: kPrimaryColor,
15 | illustration: UnDrawIllustration.profile,
16 | placeholder: Text(
17 | "Illustration is loading...",
18 | style: TextStyle(
19 | color:kPrimaryColor,
20 | fontSize: 20,
21 | ),
22 | ),
23 | errorWidget: Icon(Icons.error_outline, color: kPrimaryColor, size: 50),
24 | );
25 | }
26 | }
27 |
28 | class SkillsContent extends StatefulWidget {
29 | final Color color;
30 | final bool isMobile;
31 |
32 | const SkillsContent({this.color = Colors.white, this.isMobile = false});
33 | @override
34 | _SkillsContentState createState() => _SkillsContentState();
35 | }
36 |
37 | class _SkillsContentState extends State
38 | with TickerProviderStateMixin {
39 | static bool showSkills = false;
40 | static bool skillsSeen = false;
41 | static bool whatSeen = false;
42 | static double space, widthSpace;
43 |
44 | List skills;
45 | List scores;
46 | int showSpeed, skillNumber;
47 |
48 | @override
49 | void initState() {
50 | super.initState();
51 | space = 30;
52 | widthSpace = 50;
53 | showSpeed = 750;
54 | skillNumber = -2;
55 | skills = [
56 | 'Flutter',
57 | 'Python',
58 | 'Dart',
59 | 'PHP',
60 | 'Git',
61 | 'Linux',
62 | 'HTML',
63 | 'MySQL',
64 | 'Regex',
65 | 'JSON'
66 | ];
67 |
68 | scores = [90.0, 80.0, 85.0, 60.0, 90.0, 85.0, 75.0, 80.0, 75.0, 85];
69 | endPage();
70 | }
71 |
72 | @override
73 | Widget build(BuildContext context) {
74 | return AnimatedSize(
75 | vsync: this,
76 | duration: kThemeAnimationDuration,
77 | alignment: Alignment.topCenter,
78 | child: Column(
79 | crossAxisAlignment: CrossAxisAlignment.start,
80 | mainAxisAlignment: MainAxisAlignment.center,
81 | mainAxisSize: MainAxisSize.min,
82 | children: [
83 | Typewriter(
84 | 'What are my skills?',
85 | animate: !whatSeen,
86 | duration: const Duration(milliseconds: 750),
87 | textStyle: TextStyle(
88 | color: widget.color,
89 | fontSize: 24,
90 | fontWeight: FontWeight.w700,
91 | letterSpacing: 1.4,
92 | ),
93 | onEnd: () {
94 | if (mounted) {
95 | setState(() {
96 | showSkills = true;
97 | whatSeen = true;
98 | });
99 | }
100 | },
101 | ),
102 | Container(
103 | width: 60,
104 | height: 2,
105 | margin: const EdgeInsets.only(top: 4, bottom: 16),
106 | color: widget.color,
107 | ),
108 | if (!widget.isMobile) ...[
109 | if (showSkills) ...[
110 | sizedBox(space / 2, 0),
111 | Row(
112 | children: [
113 | skillBoxShower(0),
114 | sizedBox(0, widthSpace),
115 | skillBoxShower(1),
116 | ],
117 | ),
118 | sizedBox(space, 0),
119 | Row(
120 | children: [
121 | skillBoxShower(2),
122 | sizedBox(0, widthSpace),
123 | skillBoxShower(3),
124 | ],
125 | ),
126 | sizedBox(space, 0),
127 | Row(
128 | children: [
129 | skillBoxShower(4),
130 | sizedBox(0, widthSpace),
131 | skillBoxShower(5),
132 | ],
133 | ),
134 | sizedBox(space, 0),
135 | Row(
136 | children: [
137 | skillBoxShower(6),
138 | sizedBox(0, widthSpace),
139 | skillBoxShower(7),
140 | ],
141 | ),
142 | sizedBox(space, 0),
143 | Row(
144 | children: [
145 | skillBoxShower(8),
146 | sizedBox(0, widthSpace),
147 | skillBoxShower(9),
148 | ],
149 | ),
150 | ]
151 | ] else ...[
152 | Column(
153 | children: [
154 | sizedBox(15, 0),
155 | skillBoxShower(0),
156 | sizedBox(15, 0),
157 | skillBoxShower(1),
158 | sizedBox(15, 0),
159 | skillBoxShower(2),
160 | sizedBox(15, 0),
161 | skillBoxShower(3),
162 | sizedBox(15, 0),
163 | skillBoxShower(4),
164 | sizedBox(15, 0),
165 | skillBoxShower(5),
166 | sizedBox(15, 0),
167 | skillBoxShower(6),
168 | sizedBox(15, 0),
169 | skillBoxShower(7),
170 | sizedBox(15, 0),
171 | skillBoxShower(8),
172 | sizedBox(15, 0),
173 | skillBoxShower(9),
174 | sizedBox(15, 0),
175 | ],
176 | )
177 | ]
178 | ],
179 | ),
180 | );
181 | }
182 |
183 | endPage() async {
184 | await Future.delayed(
185 | Duration(milliseconds: (skills.length + 1) * 3 * showSpeed));
186 | setState(() {
187 | skillsSeen = true;
188 | });
189 | }
190 |
191 | Widget sizedBox(double height, double width) {
192 | return SizedBox(
193 | height: height,
194 | width: width,
195 | );
196 | }
197 |
198 | Widget skillRow() {
199 | setState(() {
200 | skillNumber++;
201 | skillNumber++;
202 | });
203 | return Column(
204 | children: [
205 | Row(
206 | children: [
207 | skillBoxShower(skillNumber - 1),
208 | sizedBox(0, widthSpace),
209 | skillBoxShower(skillNumber),
210 | ],
211 | ),
212 | sizedBox(space, 0),
213 | ],
214 | );
215 | }
216 |
217 | Widget skillBoxShower(int index) {
218 | return SkillBox(
219 | name: skills[index],
220 | color: widget.color,
221 | isMobile: widget.isMobile,
222 | score: scores[index],
223 | seen: skillsSeen,
224 | waitTime: index * 3 * showSpeed,
225 | );
226 | }
227 | }
228 |
--------------------------------------------------------------------------------
/lib/screens/shared/drawer.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/constants/colors.dart';
3 | import 'package:personal_web/constants/types.dart';
4 | import 'package:personal_web/models/change-page.dart';
5 | import 'package:personal_web/screens/shared/nav_bar.dart';
6 | import 'package:personal_web/models/url_helper.dart';
7 |
8 | class AppDrawer extends StatelessWidget {
9 | Pages selectedPage;
10 | AppDrawer({@required this.selectedPage});
11 |
12 | final textStyle = TextStyle(
13 | color: Colors.white,
14 | fontSize: 17,
15 | fontWeight: FontWeight.w700,
16 | );
17 |
18 | final items = [
19 | 'Home',
20 | 'About',
21 | 'Skills',
22 | 'Experience',
23 | 'Projects',
24 | 'Resume',
25 | ];
26 |
27 | final page = [
28 | Pages.HOME,
29 | Pages.ABOUT,
30 | Pages.SKILLS,
31 | Pages.PORTFOLIO,
32 | Pages.RESUME
33 | ];
34 |
35 | @override
36 | Widget build(BuildContext context) {
37 | return Drawer(
38 | child: Container(
39 | color: kPrimaryColor,
40 | child: Stack(
41 | alignment: Alignment.center,
42 | children: [
43 | Positioned(
44 | left: 8,
45 | top: 8,
46 | child: IconButton(
47 | color: Colors.white,
48 | icon: Icon(Icons.close),
49 | onPressed: () {
50 | Navigator.pop(context);
51 | },
52 | ),
53 | ),
54 | Column(
55 | children: [
56 | Container(
57 | height: 100,
58 | width: 100,
59 | margin: EdgeInsets.only(top: 75),
60 | child: Image.asset(
61 | 'assets/images/logo/me.png',
62 | color: Color(0xfffafafa),
63 | ),
64 | ),
65 | ],
66 | ),
67 | Column(
68 | mainAxisAlignment: MainAxisAlignment.center,
69 | mainAxisSize: MainAxisSize.min,
70 | children: items.map((item) {
71 | return InkWell(
72 | onTap: () {
73 | switch (item) {
74 | case 'Home':
75 | if (selectedPage != Pages.HOME) {
76 | changePage(context, Pages.HOME);
77 | }
78 | break;
79 | case 'About':
80 | if (selectedPage != Pages.ABOUT) {
81 | changePage(context, Pages.ABOUT);
82 | }
83 | break;
84 | case 'Skills':
85 | if (selectedPage != Pages.SKILLS) {
86 | changePage(context, Pages.SKILLS);
87 | }
88 | break;
89 | case 'Portfolio':
90 | if (selectedPage != Pages.PORTFOLIO) {
91 | changePage(context, Pages.PORTFOLIO);
92 | }
93 | break;
94 | case 'Resume':
95 | break;
96 | case 'Skills':
97 | break;
98 | default:
99 |
100 | }
101 |
102 | Navigator.pop(context);
103 | },
104 | child: item == 'Resume'
105 | ? SizedBox(width: 160, child: ResumeButton())
106 | : Column(
107 | mainAxisAlignment: MainAxisAlignment.center,
108 | children: [
109 | Text(
110 | item,
111 | style: textStyle.copyWith(
112 | fontWeight: FontWeight.w500,
113 | color: textStyle.color.withOpacity(
114 | selectedPage == page[items.indexOf(item)]
115 | ? 1.0
116 | : 0.75,
117 | ),
118 | ),
119 | ),
120 | SizedBox(height: 4),
121 | if (item != 'Resume')
122 | AnimatedContainer(
123 | duration: Duration(milliseconds: 300),
124 | height: 2,
125 | width: 20,
126 | color: selectedPage == page[items.indexOf(item)]
127 | ? Colors.white
128 | : Colors.transparent,
129 | ),
130 | SizedBox(height: 20),
131 | ],
132 | ),
133 | );
134 | }).toList(),
135 | ),
136 | ],
137 | ),
138 | ),
139 | );
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/lib/screens/shared/nav_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 | import 'package:personal_web/constants/colors.dart';
4 | import 'package:personal_web/constants/types.dart';
5 | import 'package:personal_web/controllers/main-controller.dart';
6 | import 'package:personal_web/models/change-page.dart';
7 | import 'package:personal_web/models/url_helper.dart';
8 |
9 | class MobileNavbar extends StatelessWidget implements PreferredSizeWidget {
10 | final textStyle = TextStyle(
11 | color: Colors.white,
12 | fontSize: 17,
13 | fontWeight: FontWeight.w700,
14 | );
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return AppBar(
19 | backgroundColor: Theme.of(context).scaffoldBackgroundColor,
20 | elevation: 0,
21 | actions: [
22 | IconButton(
23 | color: kPrimaryColor,
24 | highlightColor: Colors.transparent,
25 | hoverColor: Colors.transparent,
26 | splashColor: Colors.transparent,
27 | icon: Icon(Icons.menu),
28 | onPressed: () {
29 | Scaffold.of(context).openEndDrawer();
30 | },
31 | )
32 | ],
33 | title: Row(
34 | mainAxisAlignment: MainAxisAlignment.center,
35 | mainAxisSize: MainAxisSize.min,
36 | children: [
37 | CircleAvatar(
38 | backgroundColor: kPrimaryColor,
39 | radius: 15,
40 | child: Image.asset(
41 | 'assets/images/logo/logo.png',
42 | height: 20,
43 | //'web/icons/favicon-32x32',
44 | color: Colors.white,
45 | )),
46 | SizedBox(width: 10),
47 | RichText(
48 | textAlign: TextAlign.center,
49 | text: TextSpan(
50 | text: 'Erfan',
51 | style: textStyle.copyWith(
52 | color: Colors.black.withOpacity(0.75),
53 | fontSize: 18,
54 | fontFamily: 'Ubuntu',
55 | ),
56 | children: [
57 | TextSpan(
58 | text: 'Rahmati',
59 | style: textStyle.copyWith(
60 | color: kPrimaryColor,
61 | fontSize: 18,
62 | fontFamily: 'Ubuntu',
63 | ),
64 | ),
65 | ],
66 | ),
67 | ),
68 | ],
69 | ),
70 | );
71 | }
72 |
73 | @override
74 | Size get preferredSize => Size.fromHeight(56.0);
75 | }
76 |
77 | class Navbar extends StatefulWidget {
78 | @override
79 | _NavbarState createState() => _NavbarState();
80 | }
81 |
82 | class _NavbarState extends State {
83 | final MainController mainController = Get.find();
84 | int selectedIndex;
85 | final textStyle = TextStyle(
86 | color: Colors.white,
87 | fontSize: 17,
88 | fontWeight: FontWeight.w700,
89 | );
90 |
91 | final items = [
92 | 'Home',
93 | 'About',
94 | 'Skills',
95 | 'Portfolio',
96 | 'Projects',
97 | 'Resume',
98 | ];
99 |
100 | @override
101 | void initState() {
102 | super.initState();
103 | if (mainController.selectedPage == Pages.HOME) {
104 | selectedIndex=0;
105 | } else if (mainController.selectedPage == Pages.ABOUT) {
106 | selectedIndex=1;
107 | } else if (mainController.selectedPage == Pages.SKILLS) {
108 | selectedIndex=2;
109 | } else if (mainController.selectedPage == Pages.PORTFOLIO) {
110 | selectedIndex=3;
111 | }
112 | }
113 |
114 | @override
115 | Widget build(BuildContext context) {
116 | return GetBuilder(builder: (_) {
117 | return Container(
118 | height: 72,
119 | width: double.infinity,
120 | child: Row(
121 | children: [
122 | Expanded(
123 | child: Row(
124 | mainAxisAlignment: MainAxisAlignment.center,
125 | mainAxisSize: MainAxisSize.min,
126 | children: [
127 | CircleAvatar(
128 | backgroundColor: kPrimaryColor,
129 | radius: 15,
130 | child: Image.asset(
131 | 'assets/images/logo/logo.png',
132 | height: 20,
133 | color: Colors.white,
134 | )),
135 | SizedBox(width: 8),
136 | RichText(
137 | textAlign: TextAlign.center,
138 | text: TextSpan(
139 | text: 'Erfan',
140 | style: textStyle.copyWith(
141 | color: Colors.black.withOpacity(0.75),
142 | fontSize: 18,
143 | fontFamily: 'Ubuntu',
144 | ),
145 | children: [
146 | TextSpan(
147 | text: 'Rahmati',
148 | style: textStyle.copyWith(
149 | color: kPrimaryColor,
150 | fontSize: 18,
151 | fontFamily: 'Ubuntu',
152 | ),
153 | ),
154 | ],
155 | ),
156 | ),
157 | ],
158 | ),
159 | ),
160 | Expanded(
161 | child: Row(
162 | mainAxisAlignment: MainAxisAlignment.spaceAround,
163 | children: items.map((item) {
164 | return InkWell(
165 | onTap: () {
166 | switch (item) {
167 | case 'Home':
168 | if (mounted) {
169 | changePage(context, Pages.HOME);
170 | }
171 | setState(() {
172 | selectedIndex = items.indexOf(item);
173 | });
174 | break;
175 | case 'About':
176 | if (mounted) {
177 | changePage(context, Pages.ABOUT);
178 | }
179 | setState(() {
180 | selectedIndex = items.indexOf(item);
181 | });
182 | break;
183 | case 'Skills':
184 | if (mounted) {
185 | changePage(context, Pages.SKILLS);
186 | }
187 | setState(() {
188 | selectedIndex = items.indexOf(item);
189 | });
190 | break;
191 | case 'Portfolio':
192 | if (mounted) {
193 | changePage(context, Pages.PORTFOLIO);
194 | }
195 | setState(() {
196 | selectedIndex = items.indexOf(item);
197 | });
198 | break;
199 | case 'Resume':
200 | break;
201 | case 'Skills':
202 | // UrlHelper.launchUrl(
203 | // 'https://medium.com/@debrahkwesibuabeng2',
204 | // );
205 | break;
206 | default:
207 | setState(() {
208 | selectedIndex = items.indexOf(item);
209 | });
210 |
211 | // if (widget.onItemSelected != null) {
212 | // widget.onItemSelected(selectedIndex);
213 | // }
214 | }
215 | },
216 | child: item == 'Resume'
217 | ? ResumeButton()
218 | : Column(
219 | mainAxisAlignment: MainAxisAlignment.center,
220 | children: [
221 | Text(
222 | item,
223 | style: textStyle.copyWith(
224 | fontWeight: FontWeight.w500,
225 | color: textStyle.color.withOpacity(
226 | _.selectedPageNum == items.indexOf(item)
227 | ? 1.0
228 | : 0.75,
229 | ),
230 | ),
231 | ),
232 | SizedBox(height: 4),
233 | if (item != 'Resume')
234 | AnimatedContainer(
235 | duration: Duration(milliseconds: 300),
236 | height: 2,
237 | width: 20,
238 | color: _.selectedPageNum == items.indexOf(item)
239 | ? Colors.white
240 | : Colors.transparent,
241 | ),
242 | ],
243 | ),
244 | );
245 | }).toList(),
246 | ),
247 | ),
248 | ],
249 | ),
250 | );
251 | });
252 | }
253 | }
254 |
255 | class ResumeButton extends StatefulWidget {
256 | @override
257 | _ResumeButtonState createState() => _ResumeButtonState();
258 | }
259 |
260 | class _ResumeButtonState extends State {
261 | bool hovered = false;
262 |
263 | @override
264 | Widget build(BuildContext context) {
265 | return InkWell(
266 | hoverColor: Colors.transparent,
267 | splashColor: Colors.transparent,
268 | onTap: () {
269 | UrlHelper.downloadResume();
270 | },
271 | onHover: (value) {
272 | if (mounted) {
273 | setState(() {
274 | hovered = value;
275 | });
276 | }
277 | },
278 | child: AnimatedContainer(
279 | height: 40,
280 | duration: kThemeAnimationDuration,
281 | alignment: Alignment.center,
282 | padding: const EdgeInsets.symmetric(
283 | vertical: 6,
284 | horizontal: 10,
285 | ),
286 | decoration: BoxDecoration(
287 | border: Border.all(color: Colors.white, width: 2),
288 | borderRadius: BorderRadius.all(Radius.circular(30)),
289 | color: hovered ? Colors.white.withOpacity(0.92) : kPrimaryColor,
290 | ),
291 | child: AnimatedDefaultTextStyle(
292 | duration: kThemeAnimationDuration,
293 | style: TextStyle(
294 | color: hovered ? kPrimaryColor : Colors.white,
295 | fontSize: 17,
296 | fontWeight: FontWeight.w500,
297 | fontFamily: 'Ubuntu',
298 | ),
299 | child: Text(
300 | 'Resume',
301 | ),
302 | ),
303 | ),
304 | );
305 | }
306 | }
307 |
--------------------------------------------------------------------------------
/lib/screens/shared/navbar/item.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/constants/types.dart';
3 |
4 | class NavbarItem extends StatelessWidget {
5 |
6 | Pages selectedPage, item;
7 | String itemName;
8 | NavbarItem({@required this.item,@required this.itemName ,@required this.selectedPage});
9 |
10 | final textStyle = TextStyle(
11 | color: Colors.white,
12 | fontSize: 17,
13 | fontWeight: FontWeight.w700,
14 | );
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return Column(
19 | mainAxisAlignment: MainAxisAlignment.center,
20 | children: [
21 | Text(
22 | itemName,
23 | style: textStyle.copyWith(
24 | fontWeight: FontWeight.w500,
25 | color: textStyle.color.withOpacity(
26 | item==selectedPage
27 | ? 1.0
28 | : 0.75,
29 | ),
30 | ),
31 | ),
32 | SizedBox(height: 4),
33 |
34 | AnimatedContainer(
35 | duration: Duration(milliseconds: 300),
36 | height: 2,
37 | width: 20,
38 | color: item==selectedPage
39 | ? Colors.white
40 | : Colors.transparent,
41 | ),
42 | ],
43 | );
44 | }
45 | }
--------------------------------------------------------------------------------
/lib/screens/shared/navbar/navbar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 | import 'package:personal_web/constants/colors.dart';
4 | import 'package:personal_web/constants/types.dart';
5 | import 'package:personal_web/controllers/main-controller.dart';
6 | import 'package:personal_web/models/change-page.dart';
7 | import 'package:personal_web/models/url_helper.dart';
8 | import 'package:personal_web/screens/shared/navbar/item.dart';
9 |
10 | class Navbar extends StatelessWidget {
11 | Pages selectedPage;
12 | Navbar({@required this.selectedPage});
13 |
14 | final textStyle = TextStyle(
15 | color: Colors.white,
16 | fontSize: 17,
17 | fontWeight: FontWeight.w700,
18 | );
19 |
20 | final items = [
21 | 'Home',
22 | 'About',
23 | 'Skills',
24 | 'Portfolio',
25 | 'Projects',
26 | 'Resume',
27 | ];
28 |
29 | final pages = [
30 | Pages.HOME,
31 | Pages.ABOUT,
32 | Pages.SKILLS,
33 | Pages.PORTFOLIO,
34 | Pages.RESUME
35 | ];
36 |
37 | @override
38 | Widget build(BuildContext context) {
39 | return GetBuilder(builder: (_) {
40 | return Container(
41 | height: 72,
42 | width: double.infinity,
43 | child: Row(
44 | children: [
45 | Expanded(
46 | child: Row(
47 | mainAxisAlignment: MainAxisAlignment.center,
48 | mainAxisSize: MainAxisSize.min,
49 | children: [
50 | CircleAvatar(
51 | backgroundColor: kPrimaryColor,
52 | radius: 15,
53 | child: Image.asset(
54 | 'assets/images/logo/logo.png',
55 | height: 20,
56 | color: Colors.white,
57 | )),
58 | SizedBox(width: 8),
59 | RichText(
60 | textAlign: TextAlign.center,
61 | text: TextSpan(
62 | text: 'Erfan',
63 | style: textStyle.copyWith(
64 | color: Colors.black.withOpacity(0.75),
65 | fontSize: 18,
66 | fontFamily: 'Ubuntu',
67 | ),
68 | children: [
69 | TextSpan(
70 | text: 'Rahmati',
71 | style: textStyle.copyWith(
72 | color: kPrimaryColor,
73 | fontSize: 18,
74 | fontFamily: 'Ubuntu',
75 | ),
76 | ),
77 | ],
78 | ),
79 | ),
80 | ],
81 | ),
82 | ),
83 | Expanded(
84 | child: Row(
85 | mainAxisAlignment: MainAxisAlignment.spaceAround,
86 | children: items.map((item) {
87 | return InkWell(
88 | onTap: () {
89 | switch (item) {
90 | case 'Home':
91 | if (selectedPage != Pages.HOME) {
92 | changePage(context, Pages.HOME);
93 | }
94 | break;
95 | case 'About':
96 | if (selectedPage != Pages.ABOUT) {
97 | changePage(context, Pages.ABOUT);
98 | }
99 | break;
100 | case 'Skills':
101 | if (selectedPage != Pages.SKILLS) {
102 | changePage(context, Pages.SKILLS);
103 | }
104 | break;
105 | case 'Portfolio':
106 | if (selectedPage != Pages.PORTFOLIO) {
107 | changePage(context, Pages.PORTFOLIO);
108 | }
109 | break;
110 | case 'Resume':
111 | break;
112 | case 'Skills':
113 | break;
114 | default:
115 | }
116 | },
117 | child: item == 'Resume'
118 | ? ResumeButton()
119 | : NavbarItem(item: pages[items.indexOf(item)], itemName: item, selectedPage: selectedPage)
120 | );
121 | }).toList(),
122 | ),
123 | ),
124 | ],
125 | ),
126 | );
127 | });
128 | }
129 | }
130 |
131 |
132 |
133 | class ResumeButton extends StatefulWidget {
134 | @override
135 | _ResumeButtonState createState() => _ResumeButtonState();
136 | }
137 |
138 | class _ResumeButtonState extends State {
139 | bool hovered = false;
140 |
141 | @override
142 | Widget build(BuildContext context) {
143 | return InkWell(
144 | hoverColor: Colors.transparent,
145 | splashColor: Colors.transparent,
146 | onTap: () {
147 | UrlHelper.downloadResume();
148 | },
149 | onHover: (value) {
150 | if (mounted) {
151 | setState(() {
152 | hovered = value;
153 | });
154 | }
155 | },
156 | child: AnimatedContainer(
157 | height: 40,
158 | duration: kThemeAnimationDuration,
159 | alignment: Alignment.center,
160 | padding: const EdgeInsets.symmetric(
161 | vertical: 6,
162 | horizontal: 10,
163 | ),
164 | decoration: BoxDecoration(
165 | border: Border.all(color: Colors.white, width: 2),
166 | borderRadius: BorderRadius.all(Radius.circular(30)),
167 | color: hovered ? Colors.white.withOpacity(0.92) : kPrimaryColor,
168 | ),
169 | child: AnimatedDefaultTextStyle(
170 | duration: kThemeAnimationDuration,
171 | style: TextStyle(
172 | color: hovered ? kPrimaryColor: Colors.white,
173 | fontSize: 17,
174 | fontWeight: FontWeight.w500,
175 | fontFamily: 'Ubuntu',
176 | ),
177 | child: Text(
178 | 'Resume',
179 | ),
180 | ),
181 | ),
182 | );
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/lib/screens/shared/social_media_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:personal_web/constants/colors.dart';
3 | import 'package:personal_web/models/social_icons.dart';
4 | import 'package:personal_web/models/url_helper.dart';
5 |
6 | class SocialMediaBar extends StatelessWidget {
7 | @override
8 | Widget build(BuildContext context) {
9 | return Container(
10 | padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 12),
11 | margin: const EdgeInsets.only(left: 32),
12 | decoration: BoxDecoration(
13 | border: Border.all(color:kPrimaryColor.withOpacity(0.3), width: 1.4),
14 | borderRadius: BorderRadius.all(Radius.circular(35)),
15 | ),
16 | child: Column(
17 | mainAxisSize: MainAxisSize.min,
18 | children: [
19 | InkWell(
20 | hoverColor: Colors.transparent,
21 | splashColor: Colors.transparent,
22 | onTap: () {
23 | UrlHelper.launchUrl('https://github.com/ErfanRht');
24 | },
25 | child: Icon(
26 | SocialIcons.github,
27 | color: kPrimaryColor.withOpacity(0.75),
28 | ),
29 | ),
30 | SizedBox(height: 30),
31 | InkWell(
32 | hoverColor: Colors.transparent,
33 | splashColor: Colors.transparent,
34 | onTap: () {
35 | UrlHelper.launchUrl(
36 | 'https://www.linkedin.com/in/ErfanRahmati/',
37 | );
38 | },
39 | child: Icon(
40 | SocialIcons.linkedin,
41 | color: kPrimaryColor.withOpacity(0.75),
42 | ),
43 | ),
44 | SizedBox(height: 30),
45 | InkWell(
46 | hoverColor: Colors.transparent,
47 | splashColor: Colors.transparent,
48 | onTap: () {
49 | UrlHelper.launchUrl(
50 | "mailto:ErfanRht1384.com@gmail.com?subject=Hello%20DKB",
51 | );
52 | },
53 | child: Icon(
54 | SocialIcons.envelope,
55 | color: kPrimaryColor.withOpacity(0.75),
56 | ),
57 | ),
58 | SizedBox(height: 30),
59 | InkWell(
60 | hoverColor: Colors.transparent,
61 | splashColor: Colors.transparent,
62 | onTap: () {
63 | UrlHelper.launchUrl('https://twitter.com/ErfanRht');
64 | },
65 | child: Icon(
66 | SocialIcons.twitter,
67 | color: kPrimaryColor.withOpacity(0.75),
68 | ),
69 | ),
70 | SizedBox(height: 30),
71 | InkWell(
72 | hoverColor: Colors.transparent,
73 | splashColor: Colors.transparent,
74 | onTap: () {
75 | UrlHelper.launchUrl('https://www.instagram.com/ErfanRahmatei/');
76 | },
77 | child: Icon(
78 | SocialIcons.instagram,
79 | color: kPrimaryColor.withOpacity(0.75),
80 | ),
81 | ),
82 | SizedBox(height: 30),
83 | InkWell(
84 | hoverColor: Colors.transparent,
85 | splashColor: Colors.transparent,
86 | onTap: () {
87 | UrlHelper.launchUrl(
88 | 'https://web.facebook.com/ErfanRahmati',
89 | );
90 | },
91 | child: Icon(
92 | SocialIcons.facebook,
93 | color: kPrimaryColor.withOpacity(0.75),
94 | ),
95 | ),
96 | SizedBox(height: 30),
97 | InkWell(
98 | hoverColor: Colors.transparent,
99 | splashColor: Colors.transparent,
100 | onTap: () {
101 | UrlHelper.launchUrl(
102 | 'https://api.whatsapp.com/send?phone=0989397288246');
103 | },
104 | child: Icon(
105 | SocialIcons.whatsapp,
106 | color: kPrimaryColor.withOpacity(0.75),
107 | ),
108 | ),
109 | ],
110 | ),
111 | );
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | async:
5 | dependency: transitive
6 | description:
7 | name: async
8 | url: "https://pub.dartlang.org"
9 | source: hosted
10 | version: "2.6.1"
11 | boolean_selector:
12 | dependency: transitive
13 | description:
14 | name: boolean_selector
15 | url: "https://pub.dartlang.org"
16 | source: hosted
17 | version: "2.1.0"
18 | characters:
19 | dependency: transitive
20 | description:
21 | name: characters
22 | url: "https://pub.dartlang.org"
23 | source: hosted
24 | version: "1.1.0"
25 | charcode:
26 | dependency: transitive
27 | description:
28 | name: charcode
29 | url: "https://pub.dartlang.org"
30 | source: hosted
31 | version: "1.2.0"
32 | clock:
33 | dependency: transitive
34 | description:
35 | name: clock
36 | url: "https://pub.dartlang.org"
37 | source: hosted
38 | version: "1.1.0"
39 | collection:
40 | dependency: transitive
41 | description:
42 | name: collection
43 | url: "https://pub.dartlang.org"
44 | source: hosted
45 | version: "1.15.0"
46 | cupertino_icons:
47 | dependency: "direct main"
48 | description:
49 | name: cupertino_icons
50 | url: "https://pub.dartlang.org"
51 | source: hosted
52 | version: "1.0.0"
53 | fake_async:
54 | dependency: transitive
55 | description:
56 | name: fake_async
57 | url: "https://pub.dartlang.org"
58 | source: hosted
59 | version: "1.2.0"
60 | flutter:
61 | dependency: "direct main"
62 | description: flutter
63 | source: sdk
64 | version: "0.0.0"
65 | flutter_spinkit:
66 | dependency: "direct main"
67 | description:
68 | name: flutter_spinkit
69 | url: "https://pub.dartlang.org"
70 | source: hosted
71 | version: "5.0.0"
72 | flutter_svg:
73 | dependency: transitive
74 | description:
75 | name: flutter_svg
76 | url: "https://pub.dartlang.org"
77 | source: hosted
78 | version: "0.22.0"
79 | flutter_test:
80 | dependency: "direct dev"
81 | description: flutter
82 | source: sdk
83 | version: "0.0.0"
84 | flutter_web_plugins:
85 | dependency: transitive
86 | description: flutter
87 | source: sdk
88 | version: "0.0.0"
89 | get:
90 | dependency: "direct main"
91 | description:
92 | name: get
93 | url: "https://pub.dartlang.org"
94 | source: hosted
95 | version: "4.3.8"
96 | http:
97 | dependency: transitive
98 | description:
99 | name: http
100 | url: "https://pub.dartlang.org"
101 | source: hosted
102 | version: "0.13.2"
103 | http_parser:
104 | dependency: transitive
105 | description:
106 | name: http_parser
107 | url: "https://pub.dartlang.org"
108 | source: hosted
109 | version: "4.0.0"
110 | js:
111 | dependency: transitive
112 | description:
113 | name: js
114 | url: "https://pub.dartlang.org"
115 | source: hosted
116 | version: "0.6.3"
117 | matcher:
118 | dependency: transitive
119 | description:
120 | name: matcher
121 | url: "https://pub.dartlang.org"
122 | source: hosted
123 | version: "0.12.10"
124 | meta:
125 | dependency: transitive
126 | description:
127 | name: meta
128 | url: "https://pub.dartlang.org"
129 | source: hosted
130 | version: "1.3.0"
131 | ms_undraw:
132 | dependency: "direct main"
133 | description:
134 | name: ms_undraw
135 | url: "https://pub.dartlang.org"
136 | source: hosted
137 | version: "3.0.0+0"
138 | page_transition:
139 | dependency: "direct main"
140 | description:
141 | name: page_transition
142 | url: "https://pub.dartlang.org"
143 | source: hosted
144 | version: "1.1.7+6"
145 | path:
146 | dependency: transitive
147 | description:
148 | name: path
149 | url: "https://pub.dartlang.org"
150 | source: hosted
151 | version: "1.8.0"
152 | path_drawing:
153 | dependency: transitive
154 | description:
155 | name: path_drawing
156 | url: "https://pub.dartlang.org"
157 | source: hosted
158 | version: "0.5.0"
159 | path_parsing:
160 | dependency: transitive
161 | description:
162 | name: path_parsing
163 | url: "https://pub.dartlang.org"
164 | source: hosted
165 | version: "0.2.0"
166 | pedantic:
167 | dependency: transitive
168 | description:
169 | name: pedantic
170 | url: "https://pub.dartlang.org"
171 | source: hosted
172 | version: "1.11.0"
173 | petitparser:
174 | dependency: transitive
175 | description:
176 | name: petitparser
177 | url: "https://pub.dartlang.org"
178 | source: hosted
179 | version: "4.1.0"
180 | plugin_platform_interface:
181 | dependency: transitive
182 | description:
183 | name: plugin_platform_interface
184 | url: "https://pub.dartlang.org"
185 | source: hosted
186 | version: "1.0.3"
187 | sky_engine:
188 | dependency: transitive
189 | description: flutter
190 | source: sdk
191 | version: "0.0.99"
192 | source_span:
193 | dependency: transitive
194 | description:
195 | name: source_span
196 | url: "https://pub.dartlang.org"
197 | source: hosted
198 | version: "1.8.1"
199 | stack_trace:
200 | dependency: transitive
201 | description:
202 | name: stack_trace
203 | url: "https://pub.dartlang.org"
204 | source: hosted
205 | version: "1.10.0"
206 | stream_channel:
207 | dependency: transitive
208 | description:
209 | name: stream_channel
210 | url: "https://pub.dartlang.org"
211 | source: hosted
212 | version: "2.1.0"
213 | string_scanner:
214 | dependency: transitive
215 | description:
216 | name: string_scanner
217 | url: "https://pub.dartlang.org"
218 | source: hosted
219 | version: "1.1.0"
220 | term_glyph:
221 | dependency: transitive
222 | description:
223 | name: term_glyph
224 | url: "https://pub.dartlang.org"
225 | source: hosted
226 | version: "1.2.0"
227 | test_api:
228 | dependency: transitive
229 | description:
230 | name: test_api
231 | url: "https://pub.dartlang.org"
232 | source: hosted
233 | version: "0.3.0"
234 | typed_data:
235 | dependency: transitive
236 | description:
237 | name: typed_data
238 | url: "https://pub.dartlang.org"
239 | source: hosted
240 | version: "1.3.0"
241 | url_launcher:
242 | dependency: "direct main"
243 | description:
244 | name: url_launcher
245 | url: "https://pub.dartlang.org"
246 | source: hosted
247 | version: "5.7.10"
248 | url_launcher_linux:
249 | dependency: transitive
250 | description:
251 | name: url_launcher_linux
252 | url: "https://pub.dartlang.org"
253 | source: hosted
254 | version: "0.0.1+4"
255 | url_launcher_macos:
256 | dependency: transitive
257 | description:
258 | name: url_launcher_macos
259 | url: "https://pub.dartlang.org"
260 | source: hosted
261 | version: "0.0.1+9"
262 | url_launcher_platform_interface:
263 | dependency: transitive
264 | description:
265 | name: url_launcher_platform_interface
266 | url: "https://pub.dartlang.org"
267 | source: hosted
268 | version: "1.0.9"
269 | url_launcher_web:
270 | dependency: transitive
271 | description:
272 | name: url_launcher_web
273 | url: "https://pub.dartlang.org"
274 | source: hosted
275 | version: "0.1.5+1"
276 | url_launcher_windows:
277 | dependency: transitive
278 | description:
279 | name: url_launcher_windows
280 | url: "https://pub.dartlang.org"
281 | source: hosted
282 | version: "0.0.1+3"
283 | vector_math:
284 | dependency: transitive
285 | description:
286 | name: vector_math
287 | url: "https://pub.dartlang.org"
288 | source: hosted
289 | version: "2.1.0"
290 | xml:
291 | dependency: transitive
292 | description:
293 | name: xml
294 | url: "https://pub.dartlang.org"
295 | source: hosted
296 | version: "5.1.0"
297 | sdks:
298 | dart: ">=2.12.0 <3.0.0"
299 | flutter: ">=2.0.0"
300 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: personal_web
2 | description: Erfan Rahmati portfolio website.
3 |
4 | publish_to: "none"
5 |
6 | version: 1.0.0+1
7 |
8 | environment:
9 | sdk: ">=2.7.0 <3.0.0"
10 |
11 | dependencies:
12 | flutter:
13 | sdk: flutter
14 |
15 | cupertino_icons: ^1.0.0
16 | url_launcher: ^5.7.10
17 | ms_undraw: ^3.0.0+0
18 | get: ^4.3.8
19 | flutter_spinkit: ^5.0.0
20 | page_transition: ^1.1.7+6
21 |
22 | dev_dependencies:
23 | flutter_test:
24 | sdk: flutter
25 |
26 | flutter:
27 | uses-material-design: true
28 |
29 | assets:
30 | - assets/resume/
31 | - assets/images/logo/
32 |
33 | fonts:
34 | - family: MySocialIcons
35 | fonts:
36 | - asset: assets/fonts/MySocialIcons.ttf
37 | - family: Ubuntu
38 | fonts:
39 | - asset: assets/fonts/Ubuntu-Regular.ttf
40 | - asset: assets/fonts/Ubuntu-Medium.ttf
41 | weight: 500
42 | - asset: assets/fonts/Ubuntu-Bold.ttf
43 | weight: 700
44 |
--------------------------------------------------------------------------------
/web/icons/android-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/android-icon-144x144.png
--------------------------------------------------------------------------------
/web/icons/android-icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/android-icon-192x192.png
--------------------------------------------------------------------------------
/web/icons/android-icon-36x36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/android-icon-36x36.png
--------------------------------------------------------------------------------
/web/icons/android-icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/android-icon-48x48.png
--------------------------------------------------------------------------------
/web/icons/android-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/android-icon-72x72.png
--------------------------------------------------------------------------------
/web/icons/android-icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/android-icon-96x96.png
--------------------------------------------------------------------------------
/web/icons/apple-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/apple-icon-114x114.png
--------------------------------------------------------------------------------
/web/icons/apple-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/apple-icon-120x120.png
--------------------------------------------------------------------------------
/web/icons/apple-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/apple-icon-144x144.png
--------------------------------------------------------------------------------
/web/icons/apple-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/apple-icon-152x152.png
--------------------------------------------------------------------------------
/web/icons/apple-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/apple-icon-180x180.png
--------------------------------------------------------------------------------
/web/icons/apple-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/apple-icon-57x57.png
--------------------------------------------------------------------------------
/web/icons/apple-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/apple-icon-60x60.png
--------------------------------------------------------------------------------
/web/icons/apple-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/apple-icon-72x72.png
--------------------------------------------------------------------------------
/web/icons/apple-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/apple-icon-76x76.png
--------------------------------------------------------------------------------
/web/icons/apple-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/apple-icon-precomposed.png
--------------------------------------------------------------------------------
/web/icons/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/apple-icon.png
--------------------------------------------------------------------------------
/web/icons/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 | #ffffff
--------------------------------------------------------------------------------
/web/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/web/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/web/icons/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/favicon-96x96.png
--------------------------------------------------------------------------------
/web/icons/ms-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/ms-icon-144x144.png
--------------------------------------------------------------------------------
/web/icons/ms-icon-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/ms-icon-150x150.png
--------------------------------------------------------------------------------
/web/icons/ms-icon-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/ms-icon-310x310.png
--------------------------------------------------------------------------------
/web/icons/ms-icon-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErfanRht/Flutter-Personal-Website/0b34020b40bc9e1903fd88f0219603d4b98dea81/web/icons/ms-icon-70x70.png
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Erfan Rahmati
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | Erfan Rahmati
52 |
53 |
54 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Erfan Rahmati",
3 | "short_name": "Erfan Rahmati",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "Erfan Rahmati's portfolio website.",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "\/android-icon-36x36.png",
14 | "sizes": "36x36",
15 | "type": "image\/png",
16 | "density": "0.75"
17 | },
18 | {
19 | "src": "\/android-icon-48x48.png",
20 | "sizes": "48x48",
21 | "type": "image\/png",
22 | "density": "1.0"
23 | },
24 | {
25 | "src": "\/android-icon-72x72.png",
26 | "sizes": "72x72",
27 | "type": "image\/png",
28 | "density": "1.5"
29 | },
30 | {
31 | "src": "\/android-icon-96x96.png",
32 | "sizes": "96x96",
33 | "type": "image\/png",
34 | "density": "2.0"
35 | },
36 | {
37 | "src": "\/android-icon-144x144.png",
38 | "sizes": "144x144",
39 | "type": "image\/png",
40 | "density": "3.0"
41 | },
42 | {
43 | "src": "\/android-icon-192x192.png",
44 | "sizes": "192x192",
45 | "type": "image\/png",
46 | "density": "4.0"
47 | }
48 | ]
49 | }
--------------------------------------------------------------------------------
/web/spinkit.css:
--------------------------------------------------------------------------------
1 | /* Config */
2 | :root {
3 | --sk-size: 90px;
4 | --sk-color: #333;
5 |
6 | display: flex;
7 | justify-content: center;
8 | align-items: center;
9 | position: absolute;
10 | top: 50%;
11 | left: 50%;
12 | }
13 |
14 |
15 | /* Utility class for centering */
16 | .sk-center { margin: auto; }
17 |
18 |
19 | /* Plane
20 |
21 | */
22 | .sk-plane {
23 | width: var(--sk-size);
24 | height: var(--sk-size);
25 | background-color: var(--sk-color);
26 | animation: sk-plane 1.2s infinite ease-in-out;
27 | }
28 |
29 | @keyframes sk-plane {
30 | 0% {
31 | transform: perspective(120px) rotateX(0deg) rotateY(0deg);
32 | } 50% {
33 | transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
34 | } 100% {
35 | transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
36 | }
37 | }
38 |
39 |
40 | /* Chase
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | */
50 | .sk-chase {
51 | width: var(--sk-size);
52 | height: var(--sk-size);
53 | position: relative;
54 | animation: sk-chase 2.5s infinite linear both;
55 | }
56 |
57 | .sk-chase-dot {
58 | width: 100%;
59 | height: 100%;
60 | position: absolute;
61 | left: 0;
62 | top: 0;
63 | animation: sk-chase-dot 2.0s infinite ease-in-out both;
64 | }
65 |
66 | .sk-chase-dot:before {
67 | content: '';
68 | display: block;
69 | width: 25%;
70 | height: 25%;
71 | background-color: var(--sk-color);
72 | border-radius: 100%;
73 | animation: sk-chase-dot-before 2.0s infinite ease-in-out both;
74 | }
75 |
76 | .sk-chase-dot:nth-child(1) { animation-delay: -1.1s; }
77 | .sk-chase-dot:nth-child(2) { animation-delay: -1.0s; }
78 | .sk-chase-dot:nth-child(3) { animation-delay: -0.9s; }
79 | .sk-chase-dot:nth-child(4) { animation-delay: -0.8s; }
80 | .sk-chase-dot:nth-child(5) { animation-delay: -0.7s; }
81 | .sk-chase-dot:nth-child(6) { animation-delay: -0.6s; }
82 | .sk-chase-dot:nth-child(1):before { animation-delay: -1.1s; }
83 | .sk-chase-dot:nth-child(2):before { animation-delay: -1.0s; }
84 | .sk-chase-dot:nth-child(3):before { animation-delay: -0.9s; }
85 | .sk-chase-dot:nth-child(4):before { animation-delay: -0.8s; }
86 | .sk-chase-dot:nth-child(5):before { animation-delay: -0.7s; }
87 | .sk-chase-dot:nth-child(6):before { animation-delay: -0.6s; }
88 |
89 | @keyframes sk-chase {
90 | 100% { transform: rotate(360deg); }
91 | }
92 |
93 | @keyframes sk-chase-dot {
94 | 80%, 100% { transform: rotate(360deg); }
95 | }
96 |
97 | @keyframes sk-chase-dot-before {
98 | 50% {
99 | transform: scale(0.4);
100 | } 100%, 0% {
101 | transform: scale(1.0);
102 | }
103 | }
104 |
105 |
106 | /* Bounce
107 |
111 | */
112 | .sk-bounce {
113 | width: var(--sk-size);
114 | height: var(--sk-size);
115 | position: relative;
116 | }
117 |
118 | .sk-bounce-dot {
119 | width: 100%;
120 | height: 100%;
121 | border-radius: 50%;
122 | background-color: var(--sk-color);
123 | opacity: 0.6;
124 | position: absolute;
125 | top: 0;
126 | left: 0;
127 | animation: sk-bounce 2s infinite cubic-bezier(0.455, 0.03, 0.515, 0.955);
128 | }
129 |
130 | .sk-bounce-dot:nth-child(2) { animation-delay: -1.0s; }
131 |
132 | @keyframes sk-bounce {
133 | 0%, 100% {
134 | transform: scale(0);
135 | } 45%, 55% {
136 | transform: scale(1);
137 | }
138 | }
139 |
140 |
141 | /* Wave
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 | */
150 | .sk-wave {
151 | width: var(--sk-size);
152 | height: var(--sk-size);
153 | display: flex;
154 | justify-content: space-between;
155 | }
156 |
157 | .sk-wave-rect {
158 | background-color: var(--sk-color);
159 | height: 100%;
160 | width: 15%;
161 | animation: sk-wave 1.2s infinite ease-in-out;
162 | }
163 |
164 | .sk-wave-rect:nth-child(1) { animation-delay: -1.2s; }
165 | .sk-wave-rect:nth-child(2) { animation-delay: -1.1s; }
166 | .sk-wave-rect:nth-child(3) { animation-delay: -1.0s; }
167 | .sk-wave-rect:nth-child(4) { animation-delay: -0.9s; }
168 | .sk-wave-rect:nth-child(5) { animation-delay: -0.8s; }
169 |
170 | @keyframes sk-wave {
171 | 0%, 40%, 100% {
172 | transform: scaleY(0.4);
173 | } 20% {
174 | transform: scaleY(1);
175 | }
176 | }
177 |
178 |
179 | /* Pulse
180 |
181 | */
182 | .sk-pulse {
183 | width: var(--sk-size);
184 | height: var(--sk-size);
185 | background-color: var(--sk-color);
186 | border-radius: 100%;
187 | animation: sk-pulse 1.2s infinite cubic-bezier(0.455, 0.03, 0.515, 0.955);
188 | }
189 |
190 | @keyframes sk-pulse {
191 | 0% {
192 | transform: scale(0);
193 | } 100% {
194 | transform: scale(1);
195 | opacity: 0;
196 | }
197 | }
198 |
199 |
200 | /* Flow
201 |
206 | */
207 | .sk-flow {
208 | width: calc(var(--sk-size) * 1.3);
209 | height: calc(var(--sk-size) * 1.3);
210 | display: flex;
211 | justify-content: space-between;
212 | }
213 |
214 | .sk-flow-dot {
215 | width: 25%;
216 | height: 25%;
217 | background-color: var(--sk-color);
218 | border-radius: 50%;
219 | animation: sk-flow 1.4s cubic-bezier(0.455, 0.03, 0.515, 0.955) 0s infinite both;
220 | }
221 |
222 | .sk-flow-dot:nth-child(1) { animation-delay: -0.30s; }
223 | .sk-flow-dot:nth-child(2) { animation-delay: -0.15s; }
224 |
225 | @keyframes sk-flow {
226 | 0%, 80%, 100% {
227 | transform: scale(0.3); }
228 | 40% {
229 | transform: scale(1);
230 | }
231 | }
232 |
233 |
234 | /* Swing
235 |
239 | */
240 | .sk-swing {
241 | width: var(--sk-size);
242 | height: var(--sk-size);
243 | position: relative;
244 | animation: sk-swing 1.8s infinite linear;
245 | }
246 |
247 | .sk-swing-dot {
248 | width: 45%;
249 | height: 45%;
250 | position: absolute;
251 | top: 0;
252 | left: 0;
253 | right: 0;
254 | margin: auto;
255 | background-color: var(--sk-color);
256 | border-radius: 100%;
257 | animation: sk-swing-dot 2s infinite ease-in-out;
258 | }
259 |
260 | .sk-swing-dot:nth-child(2) {
261 | top: auto;
262 | bottom: 0;
263 | animation-delay: -1s;
264 | }
265 |
266 | @keyframes sk-swing {
267 | 100% {
268 | transform: rotate(360deg);
269 | }
270 | }
271 |
272 | @keyframes sk-swing-dot {
273 | 0%, 100% {
274 | transform: scale(0.2); }
275 | 50% {
276 | transform: scale(1);
277 | }
278 | }
279 |
280 |
281 | /* Circle
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 | */
297 | .sk-circle {
298 | width: var(--sk-size);
299 | height: var(--sk-size);
300 | position: relative;
301 | }
302 |
303 | .sk-circle-dot {
304 | width: 100%;
305 | height: 100%;
306 | position: absolute;
307 | left: 0;
308 | top: 0;
309 | }
310 |
311 | .sk-circle-dot:before {
312 | content: '';
313 | display: block;
314 | width: 15%;
315 | height: 15%;
316 | background-color: var(--sk-color);
317 | border-radius: 100%;
318 | animation: sk-circle 1.2s infinite ease-in-out both;
319 | }
320 |
321 | .sk-circle-dot:nth-child(1) { transform: rotate(30deg); }
322 | .sk-circle-dot:nth-child(2) { transform: rotate(60deg); }
323 | .sk-circle-dot:nth-child(3) { transform: rotate(90deg); }
324 | .sk-circle-dot:nth-child(4) { transform: rotate(120deg); }
325 | .sk-circle-dot:nth-child(5) { transform: rotate(150deg); }
326 | .sk-circle-dot:nth-child(6) { transform: rotate(180deg); }
327 | .sk-circle-dot:nth-child(7) { transform: rotate(210deg); }
328 | .sk-circle-dot:nth-child(8) { transform: rotate(240deg); }
329 | .sk-circle-dot:nth-child(9) { transform: rotate(270deg); }
330 | .sk-circle-dot:nth-child(10) { transform: rotate(300deg); }
331 | .sk-circle-dot:nth-child(11) { transform: rotate(330deg); }
332 | .sk-circle-dot:nth-child(1):before { animation-delay: -1.1s; }
333 | .sk-circle-dot:nth-child(2):before { animation-delay: -1s; }
334 | .sk-circle-dot:nth-child(3):before { animation-delay: -0.9s; }
335 | .sk-circle-dot:nth-child(4):before { animation-delay: -0.8s; }
336 | .sk-circle-dot:nth-child(5):before { animation-delay: -0.7s; }
337 | .sk-circle-dot:nth-child(6):before { animation-delay: -0.6s; }
338 | .sk-circle-dot:nth-child(7):before { animation-delay: -0.5s; }
339 | .sk-circle-dot:nth-child(8):before { animation-delay: -0.4s; }
340 | .sk-circle-dot:nth-child(9):before { animation-delay: -0.3s; }
341 | .sk-circle-dot:nth-child(10):before { animation-delay: -0.2s; }
342 | .sk-circle-dot:nth-child(11):before { animation-delay: -0.1s; }
343 |
344 | @keyframes sk-circle {
345 | 0%, 80%, 100% {
346 | transform: scale(0); }
347 | 40% {
348 | transform: scale(1);
349 | }
350 | }
351 |
352 |
353 | /* Circle Fade
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 | */
369 | .sk-circle-fade {
370 | width: var(--sk-size);
371 | height: var(--sk-size);
372 | position: relative;
373 | }
374 |
375 | .sk-circle-fade-dot {
376 | width: 100%;
377 | height: 100%;
378 | position: absolute;
379 | left: 0;
380 | top: 0;
381 | }
382 |
383 | .sk-circle-fade-dot:before {
384 | content: '';
385 | display: block;
386 | width: 15%;
387 | height: 15%;
388 | background-color: var(--sk-color);
389 | border-radius: 100%;
390 | animation: sk-circle-fade 1.2s infinite ease-in-out both;
391 | }
392 |
393 | .sk-circle-fade-dot:nth-child(1) { transform: rotate(30deg); }
394 | .sk-circle-fade-dot:nth-child(2) { transform: rotate(60deg); }
395 | .sk-circle-fade-dot:nth-child(3) { transform: rotate(90deg); }
396 | .sk-circle-fade-dot:nth-child(4) { transform: rotate(120deg); }
397 | .sk-circle-fade-dot:nth-child(5) { transform: rotate(150deg); }
398 | .sk-circle-fade-dot:nth-child(6) { transform: rotate(180deg); }
399 | .sk-circle-fade-dot:nth-child(7) { transform: rotate(210deg); }
400 | .sk-circle-fade-dot:nth-child(8) { transform: rotate(240deg); }
401 | .sk-circle-fade-dot:nth-child(9) { transform: rotate(270deg); }
402 | .sk-circle-fade-dot:nth-child(10) { transform: rotate(300deg); }
403 | .sk-circle-fade-dot:nth-child(11) { transform: rotate(330deg); }
404 | .sk-circle-fade-dot:nth-child(1):before { animation-delay: -1.1s; }
405 | .sk-circle-fade-dot:nth-child(2):before { animation-delay: -1.0s; }
406 | .sk-circle-fade-dot:nth-child(3):before { animation-delay: -0.9s; }
407 | .sk-circle-fade-dot:nth-child(4):before { animation-delay: -0.8s; }
408 | .sk-circle-fade-dot:nth-child(5):before { animation-delay: -0.7s; }
409 | .sk-circle-fade-dot:nth-child(6):before { animation-delay: -0.6s; }
410 | .sk-circle-fade-dot:nth-child(7):before { animation-delay: -0.5s; }
411 | .sk-circle-fade-dot:nth-child(8):before { animation-delay: -0.4s; }
412 | .sk-circle-fade-dot:nth-child(9):before { animation-delay: -0.3s; }
413 | .sk-circle-fade-dot:nth-child(10):before { animation-delay: -0.2s; }
414 | .sk-circle-fade-dot:nth-child(11):before { animation-delay: -0.1s; }
415 |
416 | @keyframes sk-circle-fade {
417 | 0%, 39%, 100% {
418 | opacity: 0;
419 | transform: scale(0.6);
420 | } 40% {
421 | opacity: 1;
422 | transform: scale(1);
423 | }
424 | }
425 |
426 |
427 | /* Grid
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 | */
440 | .sk-grid {
441 | width: var(--sk-size);
442 | height: var(--sk-size);
443 | /* Cube positions
444 | * 1 2 3
445 | * 4 5 6
446 | * 7 8 9
447 | */
448 | }
449 | .sk-grid-cube {
450 | width: 33.33%;
451 | height: 33.33%;
452 | background-color: var(--sk-color);
453 | float: left;
454 | animation: sk-grid 1.3s infinite ease-in-out;
455 | }
456 | .sk-grid-cube:nth-child(1) { animation-delay: 0.2s; }
457 | .sk-grid-cube:nth-child(2) { animation-delay: 0.3s; }
458 | .sk-grid-cube:nth-child(3) { animation-delay: 0.4s; }
459 | .sk-grid-cube:nth-child(4) { animation-delay: 0.1s; }
460 | .sk-grid-cube:nth-child(5) { animation-delay: 0.2s; }
461 | .sk-grid-cube:nth-child(6) { animation-delay: 0.3s; }
462 | .sk-grid-cube:nth-child(7) { animation-delay: 0.0s; }
463 | .sk-grid-cube:nth-child(8) { animation-delay: 0.1s; }
464 | .sk-grid-cube:nth-child(9) { animation-delay: 0.2s; }
465 |
466 | @keyframes sk-grid {
467 | 0%, 70%, 100% {
468 | transform: scale3D(1, 1, 1);
469 | } 35% {
470 | transform: scale3D(0, 0, 1);
471 | }
472 | }
473 |
474 |
475 | /* Fold
476 |
477 |
478 |
479 |
480 |
481 |
482 | */
483 | .sk-fold {
484 | width: var(--sk-size);
485 | height: var(--sk-size);
486 | position: relative;
487 | transform: rotateZ(45deg);
488 | }
489 | .sk-fold-cube {
490 | float: left;
491 | width: 50%;
492 | height: 50%;
493 | position: relative;
494 | transform: scale(1.1);
495 | }
496 |
497 | .sk-fold-cube:before {
498 | content: '';
499 | position: absolute;
500 | top: 0;
501 | left: 0;
502 | width: 100%;
503 | height: 100%;
504 | background-color: var(--sk-color);
505 | animation: sk-fold 2.4s infinite linear both;
506 | transform-origin: 100% 100%;
507 | }
508 | .sk-fold-cube:nth-child(2) { transform: scale(1.1) rotateZ(90deg); }
509 | .sk-fold-cube:nth-child(4) { transform: scale(1.1) rotateZ(180deg); }
510 | .sk-fold-cube:nth-child(3) { transform: scale(1.1) rotateZ(270deg); }
511 | .sk-fold-cube:nth-child(2):before { animation-delay: 0.3s; }
512 | .sk-fold-cube:nth-child(4):before { animation-delay: 0.6s; }
513 | .sk-fold-cube:nth-child(3):before { animation-delay: 0.9s; }
514 |
515 | @keyframes sk-fold {
516 | 0%, 10% {
517 | transform: perspective(140px) rotateX(-180deg);
518 | opacity: 0;
519 | } 25%, 75% {
520 | transform: perspective(140px) rotateX(0deg);
521 | opacity: 1;
522 | } 90%, 100% {
523 | transform: perspective(140px) rotateY(180deg);
524 | opacity: 0;
525 | }
526 | }
527 |
528 |
529 | /* Wander
530 |
531 |
532 |
533 |
534 |
535 |
536 | */
537 | .sk-wander {
538 | width: var(--sk-size);
539 | height: var(--sk-size);
540 | position: relative;
541 | }
542 |
543 | .sk-wander-cube {
544 | background-color: var(--sk-color);
545 | width: 20%;
546 | height: 20%;
547 | position: absolute;
548 | top: 0;
549 | left: 0;
550 | --sk-wander-distance: calc(var(--sk-size) * 0.75);
551 | animation: sk-wander 2.0s ease-in-out -2.0s infinite both;
552 | }
553 | .sk-wander-cube:nth-child(2) { animation-delay: -0.5s; }
554 | .sk-wander-cube:nth-child(3) { animation-delay: -1.0s; }
555 |
556 | @keyframes sk-wander {
557 | 0% {
558 | transform: rotate(0deg);
559 | } 25% {
560 | transform: translateX(var(--sk-wander-distance)) rotate(-90deg) scale(0.6);
561 | } 50% { /* Make FF rotate in the right direction */
562 | transform: translateX(var(--sk-wander-distance)) translateY(var(--sk-wander-distance)) rotate(-179deg);
563 | } 50.1% {
564 | transform: translateX(var(--sk-wander-distance)) translateY(var(--sk-wander-distance)) rotate(-180deg);
565 | } 75% {
566 | transform: translateX(0) translateY(var(--sk-wander-distance)) rotate(-270deg) scale(0.6);
567 | } 100% {
568 | transform: rotate(-360deg);
569 | }
570 | }
571 |
572 | .sk-folding-cube {
573 | margin: 20px auto;
574 | width: 40px;
575 | height: 40px;
576 | position: relative;
577 | -webkit-transform: rotateZ(45deg);
578 | transform: rotateZ(45deg);
579 | }
580 |
581 | .sk-folding-cube .sk-cube {
582 | float: left;
583 | width: 50%;
584 | height: 50%;
585 | position: relative;
586 | -webkit-transform: scale(1.1);
587 | -ms-transform: scale(1.1);
588 | transform: scale(1.1);
589 | }
590 | .sk-folding-cube .sk-cube:before {
591 | content: '';
592 | position: absolute;
593 | top: 0;
594 | left: 0;
595 | width: 100%;
596 | height: 100%;
597 | background-color: #333;
598 | -webkit-animation: sk-foldCubeAngle 2.4s infinite linear both;
599 | animation: sk-foldCubeAngle 2.4s infinite linear both;
600 | -webkit-transform-origin: 100% 100%;
601 | -ms-transform-origin: 100% 100%;
602 | transform-origin: 100% 100%;
603 | }
604 | .sk-folding-cube .sk-cube2 {
605 | -webkit-transform: scale(1.1) rotateZ(90deg);
606 | transform: scale(1.1) rotateZ(90deg);
607 | }
608 | .sk-folding-cube .sk-cube3 {
609 | -webkit-transform: scale(1.1) rotateZ(180deg);
610 | transform: scale(1.1) rotateZ(180deg);
611 | }
612 | .sk-folding-cube .sk-cube4 {
613 | -webkit-transform: scale(1.1) rotateZ(270deg);
614 | transform: scale(1.1) rotateZ(270deg);
615 | }
616 | .sk-folding-cube .sk-cube2:before {
617 | -webkit-animation-delay: 0.3s;
618 | animation-delay: 0.3s;
619 | }
620 | .sk-folding-cube .sk-cube3:before {
621 | -webkit-animation-delay: 0.6s;
622 | animation-delay: 0.6s;
623 | }
624 | .sk-folding-cube .sk-cube4:before {
625 | -webkit-animation-delay: 0.9s;
626 | animation-delay: 0.9s;
627 | }
628 | @-webkit-keyframes sk-foldCubeAngle {
629 | 0%, 10% {
630 | -webkit-transform: perspective(140px) rotateX(-180deg);
631 | transform: perspective(140px) rotateX(-180deg);
632 | opacity: 0;
633 | } 25%, 75% {
634 | -webkit-transform: perspective(140px) rotateX(0deg);
635 | transform: perspective(140px) rotateX(0deg);
636 | opacity: 1;
637 | } 90%, 100% {
638 | -webkit-transform: perspective(140px) rotateY(180deg);
639 | transform: perspective(140px) rotateY(180deg);
640 | opacity: 0;
641 | }
642 | }
643 |
644 | @keyframes sk-foldCubeAngle {
645 | 0%, 10% {
646 | -webkit-transform: perspective(140px) rotateX(-180deg);
647 | transform: perspective(140px) rotateX(-180deg);
648 | opacity: 0;
649 | } 25%, 75% {
650 | -webkit-transform: perspective(140px) rotateX(0deg);
651 | transform: perspective(140px) rotateX(0deg);
652 | opacity: 1;
653 | } 90%, 100% {
654 | -webkit-transform: perspective(140px) rotateY(180deg);
655 | transform: perspective(140px) rotateY(180deg);
656 | opacity: 0;
657 | }
658 | }
--------------------------------------------------------------------------------