├── .github └── FUNDING.yml ├── .gitignore ├── Gifs ├── gridview.gif ├── instasearch.gif ├── sorting.gif ├── sudoku.gif └── todo.gif ├── Gridview ├── app.js ├── images │ ├── a.jpg │ ├── b.jpg │ ├── c.jpg │ ├── d.jpg │ └── e.jpg ├── index.html └── style.css ├── Instant search ├── app.js ├── index.html └── style.css ├── LICENSE.MD ├── README.md ├── Sorting ├── app.js ├── index.html ├── sorting.js └── style.css ├── Sudoku ├── app.js ├── fail.gif ├── index.html ├── style.css ├── success.gif └── sudoku.js └── Todo list application ├── app.js ├── index.html └── style.css /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: https://paypal.me/fbonizzi?locale.x=it_IT 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.svclog 86 | *.scc 87 | 88 | # Chutzpah Test files 89 | _Chutzpah* 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | *.VC.db 100 | *.VC.VC.opendb 101 | 102 | # Visual Studio profiler 103 | *.psess 104 | *.vsp 105 | *.vspx 106 | *.sap 107 | 108 | # Visual Studio Trace Files 109 | *.e2e 110 | 111 | # TFS 2012 Local Workspace 112 | $tf/ 113 | 114 | # Guidance Automation Toolkit 115 | *.gpState 116 | 117 | # ReSharper is a .NET coding add-in 118 | _ReSharper*/ 119 | *.[Rr]e[Ss]harper 120 | *.DotSettings.user 121 | 122 | # JustCode is a .NET coding add-in 123 | .JustCode 124 | 125 | # TeamCity is a build add-in 126 | _TeamCity* 127 | 128 | # DotCover is a Code Coverage Tool 129 | *.dotCover 130 | 131 | # AxoCover is a Code Coverage Tool 132 | .axoCover/* 133 | !.axoCover/settings.json 134 | 135 | # Visual Studio code coverage results 136 | *.coverage 137 | *.coveragexml 138 | 139 | # NCrunch 140 | _NCrunch_* 141 | .*crunch*.local.xml 142 | nCrunchTemp_* 143 | 144 | # MightyMoose 145 | *.mm.* 146 | AutoTest.Net/ 147 | 148 | # Web workbench (sass) 149 | .sass-cache/ 150 | 151 | # Installshield output folder 152 | [Ee]xpress/ 153 | 154 | # DocProject is a documentation generator add-in 155 | DocProject/buildhelp/ 156 | DocProject/Help/*.HxT 157 | DocProject/Help/*.HxC 158 | DocProject/Help/*.hhc 159 | DocProject/Help/*.hhk 160 | DocProject/Help/*.hhp 161 | DocProject/Help/Html2 162 | DocProject/Help/html 163 | 164 | # Click-Once directory 165 | publish/ 166 | 167 | # Publish Web Output 168 | *.[Pp]ublish.xml 169 | *.azurePubxml 170 | # Note: Comment the next line if you want to checkin your web deploy settings, 171 | # but database connection strings (with potential passwords) will be unencrypted 172 | *.pubxml 173 | *.publishproj 174 | 175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 176 | # checkin your Azure Web App publish settings, but sensitive information contained 177 | # in these scripts will be unencrypted 178 | PublishScripts/ 179 | 180 | # NuGet Packages 181 | *.nupkg 182 | # The packages folder can be ignored because of Package Restore 183 | **/[Pp]ackages/* 184 | # except build/, which is used as an MSBuild target. 185 | !**/[Pp]ackages/build/ 186 | # Uncomment if necessary however generally it will be regenerated when needed 187 | #!**/[Pp]ackages/repositories.config 188 | # NuGet v3's project.json files produces more ignorable files 189 | *.nuget.props 190 | *.nuget.targets 191 | 192 | # Microsoft Azure Build Output 193 | csx/ 194 | *.build.csdef 195 | 196 | # Microsoft Azure Emulator 197 | ecf/ 198 | rcf/ 199 | 200 | # Windows Store app package directories and files 201 | AppPackages/ 202 | BundleArtifacts/ 203 | Package.StoreAssociation.xml 204 | _pkginfo.txt 205 | *.appx 206 | 207 | # Visual Studio cache files 208 | # files ending in .cache can be ignored 209 | *.[Cc]ache 210 | # but keep track of directories ending in .cache 211 | !*.[Cc]ache/ 212 | 213 | # Others 214 | ClientBin/ 215 | ~$* 216 | *~ 217 | *.dbmdl 218 | *.dbproj.schemaview 219 | *.jfm 220 | *.pfx 221 | *.publishsettings 222 | orleans.codegen.cs 223 | 224 | # Including strong name files can present a security risk 225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 226 | #*.snk 227 | 228 | # Since there are multiple workflows, uncomment next line to ignore bower_components 229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 230 | #bower_components/ 231 | 232 | # RIA/Silverlight projects 233 | Generated_Code/ 234 | 235 | # Backup & report files from converting an old project file 236 | # to a newer Visual Studio version. Backup files are not needed, 237 | # because we have git ;-) 238 | _UpgradeReport_Files/ 239 | Backup*/ 240 | UpgradeLog*.XML 241 | UpgradeLog*.htm 242 | ServiceFabricBackup/ 243 | *.rptproj.bak 244 | 245 | # SQL Server files 246 | *.mdf 247 | *.ldf 248 | *.ndf 249 | 250 | # Business Intelligence projects 251 | *.rdl.data 252 | *.bim.layout 253 | *.bim_*.settings 254 | *.rptproj.rsuser 255 | 256 | # Microsoft Fakes 257 | FakesAssemblies/ 258 | 259 | # GhostDoc plugin setting file 260 | *.GhostDoc.xml 261 | 262 | # Node.js Tools for Visual Studio 263 | .ntvs_analysis.dat 264 | node_modules/ 265 | 266 | # Visual Studio 6 build log 267 | *.plg 268 | 269 | # Visual Studio 6 workspace options file 270 | *.opt 271 | 272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 273 | *.vbw 274 | 275 | # Visual Studio LightSwitch build output 276 | **/*.HTMLClient/GeneratedArtifacts 277 | **/*.DesktopClient/GeneratedArtifacts 278 | **/*.DesktopClient/ModelManifest.xml 279 | **/*.Server/GeneratedArtifacts 280 | **/*.Server/ModelManifest.xml 281 | _Pvt_Extensions 282 | 283 | # Paket dependency manager 284 | .paket/paket.exe 285 | paket-files/ 286 | 287 | # FAKE - F# Make 288 | .fake/ 289 | 290 | # JetBrains Rider 291 | .idea/ 292 | *.sln.iml 293 | 294 | # CodeRush 295 | .cr/ 296 | 297 | # Python Tools for Visual Studio (PTVS) 298 | __pycache__/ 299 | *.pyc 300 | 301 | # Cake - Uncomment if you are using it 302 | # tools/** 303 | # !tools/packages.config 304 | 305 | # Tabs Studio 306 | *.tss 307 | 308 | # Telerik's JustMock configuration file 309 | *.jmconfig 310 | 311 | # BizTalk build output 312 | *.btp.cs 313 | *.btm.cs 314 | *.odx.cs 315 | *.xsd.cs 316 | 317 | # OpenCover UI analysis results 318 | OpenCover/ 319 | 320 | # Azure Stream Analytics local run output 321 | ASALocalRun/ 322 | 323 | # MSBuild Binary and Structured Log 324 | *.binlog 325 | 326 | # NVidia Nsight GPU debugger configuration file 327 | *.nvuser 328 | 329 | # MFractors (Xamarin productivity tool) working folder 330 | .mfractor/ 331 | -------------------------------------------------------------------------------- /Gifs/gridview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrancescoBonizzi/VueJs-Experiments/34c2386b461e326c77d04778f06244a7ca406853/Gifs/gridview.gif -------------------------------------------------------------------------------- /Gifs/instasearch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrancescoBonizzi/VueJs-Experiments/34c2386b461e326c77d04778f06244a7ca406853/Gifs/instasearch.gif -------------------------------------------------------------------------------- /Gifs/sorting.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrancescoBonizzi/VueJs-Experiments/34c2386b461e326c77d04778f06244a7ca406853/Gifs/sorting.gif -------------------------------------------------------------------------------- /Gifs/sudoku.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrancescoBonizzi/VueJs-Experiments/34c2386b461e326c77d04778f06244a7ca406853/Gifs/sudoku.gif -------------------------------------------------------------------------------- /Gifs/todo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrancescoBonizzi/VueJs-Experiments/34c2386b461e326c77d04778f06244a7ca406853/Gifs/todo.gif -------------------------------------------------------------------------------- /Gridview/app.js: -------------------------------------------------------------------------------- 1 | var cartData = { 2 | columns: [ 3 | "Id", 4 | "Quantity", 5 | "Name", 6 | "Seller", 7 | "Price" 8 | ], 9 | data: [ 10 | { Id: 1, Quantity: 1, Name: "SSD Super Fast 1TB", Seller: "Elektro Sell", Price: "123.00$", ImagePath: "images/a.jpg" }, 11 | { Id: 2, Quantity: 1, Name: "Bottle of 1998 Barolo", Seller: "Very Nice Shop", Price: "50.00$", ImagePath: "images/b.jpg" }, 12 | { Id: 3, Quantity: 3, Name: "Car Radio Player", Seller: "Elektro Sell", Price: "78.10$", ImagePath: "images/c.jpg" }, 13 | { Id: 4, Quantity: 1, Name: "Video Game Console Super Powerful", Seller: "Elektro Sell", Price: "99.99$", ImagePath: "images/d.jpg" }, 14 | { Id: 5, Quantity: 5, Name: "Book about vegetarianism", Seller: "Your Library", Price: "41.20$", ImagePath: "images/e.jpg" } 15 | ] 16 | }; 17 | 18 | var booksData = { 19 | columns: [ 20 | "Id", 21 | "Name", 22 | "Author", 23 | "Theme", 24 | "Rating" 25 | ], 26 | data: [ 27 | { Id: 1, Name: "The look of love", Author: "George Blue", Theme: "Drama", Rating: "*****", ImagePath: "images/a.jpg" }, 28 | { Id: 2, Name: "20 vegetarian dishes", Author: "Francesco Bonizzi", Theme: "Cooking", Rating: "****", ImagePath: "images/b.jpg" }, 29 | { Id: 3, Name: "How to be happy", Author: "Asdrubale Anselmi", Theme: "Self help", Rating: "*", ImagePath: "images/c.jpg" }, 30 | { Id: 4, Name: "The last bee", Author: "John Dorian", Theme: "Nature", Rating: "****", ImagePath: "images/d.jpg" } 31 | ] 32 | }; 33 | 34 | var gridviewApp = new Vue({ 35 | 36 | el: '#app-gridview', 37 | 38 | data: { 39 | gridData: cartData, 40 | buttonSwitchViewText: "Switch to ListView", 41 | buttonSwitchDataText: "Switch to books data", 42 | isGridView: true, 43 | isBookData: false 44 | }, 45 | 46 | methods: { 47 | 48 | switchView: function() { 49 | 50 | if (this.isGridView) { 51 | this.buttonSwitchViewText = "Switch to GridView"; 52 | } 53 | else { 54 | this.buttonSwitchViewText = "Switch to ListView"; 55 | } 56 | 57 | this.isGridView = !this.isGridView; 58 | }, 59 | 60 | switchData: function () { 61 | 62 | if (this.isBookData) { 63 | this.buttonSwitchDataText = "Switch to books data"; 64 | this.gridData = cartData; 65 | } 66 | else { 67 | this.buttonSwitchDataText = "Switch to shop data"; 68 | this.gridData = booksData; 69 | } 70 | 71 | this.isBookData = !this.isBookData; 72 | } 73 | 74 | } 75 | 76 | }); -------------------------------------------------------------------------------- /Gridview/images/a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrancescoBonizzi/VueJs-Experiments/34c2386b461e326c77d04778f06244a7ca406853/Gridview/images/a.jpg -------------------------------------------------------------------------------- /Gridview/images/b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrancescoBonizzi/VueJs-Experiments/34c2386b461e326c77d04778f06244a7ca406853/Gridview/images/b.jpg -------------------------------------------------------------------------------- /Gridview/images/c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrancescoBonizzi/VueJs-Experiments/34c2386b461e326c77d04778f06244a7ca406853/Gridview/images/c.jpg -------------------------------------------------------------------------------- /Gridview/images/d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrancescoBonizzi/VueJs-Experiments/34c2386b461e326c77d04778f06244a7ca406853/Gridview/images/d.jpg -------------------------------------------------------------------------------- /Gridview/images/e.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrancescoBonizzi/VueJs-Experiments/34c2386b461e326c77d04778f06244a7ca406853/Gridview/images/e.jpg -------------------------------------------------------------------------------- /Gridview/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | Vue.js in action 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |

Gridview - Listview

20 |
21 | 22 |
23 | 24 |
25 | 26 | 27 |
28 | 29 |
30 | 31 |
32 |
{{ name }}
33 |
34 | 35 | 36 |
37 |
38 |
{{ row[name] }}
39 |
40 |
41 | 42 | 43 |
44 | 45 |
46 |
47 |
{{ name }}
48 |
{{ row[name] }}
49 |
50 |
51 |
52 | 53 |
54 | 55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /Gridview/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | input:focus, 7 | select:focus, 8 | textarea:focus, 9 | button:focus { 10 | outline: none; 11 | } 12 | 13 | html { 14 | overflow-y:scroll; 15 | } 16 | 17 | body { 18 | display: grid; 19 | grid-template-rows: 120px 1fr; 20 | font-family: 'Lato', sans-serif; 21 | margin-bottom: 10px; 22 | background: #f6f6f6; 23 | } 24 | 25 | header { 26 | display: grid; 27 | color: black; 28 | box-shadow: 0 0 1px rgba(0,0,0,0.25); 29 | background: white; 30 | } 31 | 32 | header h1 { 33 | place-self: center; 34 | font-size: 42px; 35 | font-weight: lighter; 36 | } 37 | 38 | #app-gridview { 39 | place-self: center; 40 | margin-top: 30px; 41 | display: grid; 42 | justify-items: center; 43 | } 44 | 45 | .grid-wrapper { 46 | display: table; 47 | border: 4px solid #336699; 48 | border-radius: 6px; 49 | transition: all ease 0.5s; 50 | } 51 | 52 | .list-wrapper { 53 | transition: all ease 0.5s; 54 | } 55 | 56 | .grid-header { 57 | font-weight: bold; 58 | background: #336699; 59 | color: white; 60 | border-bottom: 4px solid #f6f6f6; 61 | } 62 | 63 | .grid-row { 64 | display: table-row; 65 | } 66 | 67 | .grid-row > div { 68 | display: table-cell; 69 | padding: 10px 20px; 70 | } 71 | 72 | .grid-wrapper > div:nth-child(even) { 73 | background: #f6f6f6; 74 | transition: all ease 0.4s; 75 | } 76 | 77 | .grid-wrapper > div:nth-child(odd) { 78 | background: #fafafa; 79 | transition: all ease 0.4s; 80 | } 81 | 82 | .grid-wrapper > div:hover { 83 | background: #a9d6ff; 84 | transition: all ease 0.4s; 85 | } 86 | 87 | .list-row { 88 | padding: 10px; 89 | margin: 10px; 90 | background: white; 91 | border-radius: 6px; 92 | -webkit-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.37); 93 | -moz-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.37); 94 | box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.37); 95 | display: grid; 96 | grid-template-columns: auto 1fr; 97 | width: 600px; 98 | } 99 | 100 | .list-row-item { 101 | display: grid; 102 | grid-template-columns: 150px 1fr; 103 | padding: 4px; 104 | transition: all 0.5s; 105 | } 106 | 107 | .list-property { 108 | display: flex; 109 | flex-direction: column; 110 | justify-content: space-between; 111 | } 112 | 113 | .list-property-name { 114 | font-weight: bold; 115 | transition: all 0.5s; 116 | } 117 | 118 | .list-image { 119 | width: 150px; 120 | border-radius: 6px; 121 | margin-right: 10px; 122 | } 123 | 124 | .button { 125 | display: inline-block; 126 | border-radius: 6px; 127 | background-color: #0095ff; 128 | border: none; 129 | color: #FFFFFF; 130 | text-align: center; 131 | font-size: 16px; 132 | padding: 10px; 133 | width: 230px; 134 | transition: all 0.5s; 135 | cursor: pointer; 136 | margin: 0px 0px 25px 0px; 137 | } 138 | 139 | .button span { 140 | cursor: pointer; 141 | display: inline-block; 142 | position: relative; 143 | transition: 0.5s; 144 | } 145 | 146 | .button span:after { 147 | content: '\00bb'; 148 | position: absolute; 149 | opacity: 0; 150 | top: 0; 151 | right: -20px; 152 | transition: 0.5s; 153 | } 154 | 155 | .button:hover span { 156 | padding-right: 25px; 157 | } 158 | 159 | .button:hover span:after { 160 | opacity: 1; 161 | right: 0; 162 | } -------------------------------------------------------------------------------- /Instant search/app.js: -------------------------------------------------------------------------------- 1 | var instasearchApp = new Vue({ 2 | 3 | el: '#app-instasearch', 4 | 5 | data: { 6 | authorNameSearchString: "", 7 | photoFeed: null 8 | }, 9 | 10 | mounted() { 11 | axios 12 | .get('https://picsum.photos/v2/list?page=2&limit=10') 13 | .then(response => { 14 | this.photoFeed = response.data; 15 | }) 16 | .catch(error => console.log(error)) 17 | }, 18 | 19 | computed: { 20 | 21 | filteredPhotoFeed: function () { 22 | 23 | var photos = this.photoFeed; 24 | var authorNameSearchString = this.authorNameSearchString; 25 | 26 | if(!authorNameSearchString){ 27 | return photos; 28 | } 29 | 30 | searchString = authorNameSearchString.trim().toLowerCase(); 31 | 32 | photos = photos.filter(function(item){ 33 | if(item.author.toLowerCase().indexOf(authorNameSearchString) !== -1){ 34 | return item; 35 | } 36 | }) 37 | 38 | return photos; 39 | } 40 | } 41 | 42 | }); -------------------------------------------------------------------------------- /Instant search/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Vue.js in action 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |

Photo finder

21 |
22 | 23 |
24 | 25 |
26 | 27 |
28 | 29 | 30 | 31 |
  • 32 | 33 | {{ photo.author }} 34 |
  • 35 | 36 |
    37 | 38 |
    39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Instant search/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | input:focus, 7 | select:focus, 8 | textarea:focus, 9 | button:focus { 10 | outline: none; 11 | } 12 | 13 | html { 14 | overflow-y:scroll; 15 | } 16 | 17 | body { 18 | display: grid; 19 | grid-template-rows: 150px 1fr; 20 | background-color: #f5f5f5; 21 | font-family: 'Roboto Slab', serif; 22 | margin-bottom: 10px; 23 | } 24 | 25 | header { 26 | display: grid; 27 | color: white; 28 | background: #6D25BC; 29 | } 30 | 31 | header h1 { 32 | place-self: center; 33 | font-size: 42px; 34 | } 35 | 36 | #app-instasearch { 37 | place-self: center; 38 | margin-top: 30px; 39 | width: 600px; 40 | } 41 | 42 | .input-container { 43 | border-radius: 5px; 44 | background: #677482; 45 | padding: 10px; 46 | } 47 | 48 | .input-container input { 49 | border: none; 50 | background: transparent; 51 | color: white; 52 | padding: 6px 15px; 53 | font-size: 18px; 54 | } 55 | 56 | ::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */ 57 | color: #a6b0ba; 58 | opacity: 1; /* Firefox */ 59 | } 60 | 61 | .photo { 62 | list-style: none; 63 | display: grid; 64 | grid-template-columns: 200px auto; 65 | margin-top: 20px; 66 | align-items: center; 67 | background-color: #e9edf0; 68 | padding: 30px 50px; 69 | border-radius: 5px; 70 | border: 1px solid #e3e3e3; 71 | } 72 | 73 | .author { 74 | font-size: 25px; 75 | margin-left: 20px; 76 | color: #75818e; 77 | } 78 | 79 | .photo img { 80 | border-radius: 5px; 81 | width: 200px; 82 | } 83 | 84 | .photo-animated { 85 | transition: all 0.5s; 86 | } 87 | 88 | .list-animation-enter, .list-animation-leave-to { 89 | opacity: 0; 90 | transform: translateY(30px); 91 | } 92 | 93 | .list-animation-leave-active { 94 | position: absolute; 95 | } -------------------------------------------------------------------------------- /LICENSE.MD: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Francesco 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VueJs-Experiments 2 | This repository contains some experiments with Vue.js framework. 3 | 4 |   5 | 6 | ## Todo list application 7 | 8 | An interactive to-do list with style and animations: add a todo item, set completed, remove it 9 | 10 | [The article with step-by-step tutorial](https://medium.com/better-programming/how-to-build-your-first-vue-js-application-469ed1ec4fde) 11 | 12 | ![The application flow](Gifs/todo.gif) 13 | 14 |   15 | 16 | ## Instant search application 17 | 18 | Fetch data from a Web API and add a dynamic filter with computed properties 19 | 20 | [The article with step-by-step tutorial](https://medium.com/better-programming/instant-search-with-vue-js-and-axios-5b78a3a59f01) 21 | 22 | ![The application flow](Gifs/instasearch.gif) 23 | 24 |   25 | 26 | ## Switchable GridView ListView 27 | 28 | Represent any array of data and switch between visualizations 29 | 30 | [The article with step-by-step tutorial](https://medium.com/better-programming/switching-between-grid-view-and-list-view-with-vue-js-90fcd578bbdf) 31 | 32 | ![The application flow](Gifs/gridview.gif) 33 | 34 |   35 | 36 | ## Sudoku 37 | 38 | How to code this simple game from A to Z 39 | 40 | [The article with step-by-step tutorial](https://medium.com/better-programming/how-to-build-sudoku-in-vue-js-f97509b523ed) 41 | 42 | ![The application flow](Gifs/sudoku.gif) 43 | 44 | ## Visual representation of sorting Algorithms 45 | 46 | A little guide to animations with Vue.js 47 | 48 | [The article with step-by-step tutorial](https://medium.com/better-programming/a-visual-representation-of-sorting-algorithms-with-vue-js-f79b903fabbe) 49 | 50 | ![The application flow](Gifs/sorting.gif) 51 | -------------------------------------------------------------------------------- /Sorting/app.js: -------------------------------------------------------------------------------- 1 | var sortingApp = new Vue({ 2 | 3 | el: '#app-sorting', 4 | 5 | data: { 6 | 7 | arrayToBeSorted: [1, 2, 3, 4, 5, 6, 7, 8], 8 | isManipulatingArray: false, 9 | 10 | shuffleButtonText: "Shuffle!", 11 | 12 | sortAlgorithms: [ 13 | { name: "Bubble sort", fn: bubbleSort }, 14 | { name: "Selection sort", fn: selectionSort }, 15 | { name: "Insertion sort", fn: insertionSort } 16 | ] 17 | 18 | }, 19 | 20 | methods: { 21 | 22 | shuffle: function () { 23 | this.isManipulatingArray = true; 24 | shuffle(this.arrayToBeSorted).then(() => this.isManipulatingArray = false); 25 | }, 26 | 27 | sort: function (sortAlgorithm) { 28 | this.isManipulatingArray = true; 29 | sortAlgorithm.fn(this.arrayToBeSorted).then(() => this.isManipulatingArray = false); 30 | } 31 | 32 | } 33 | 34 | }); 35 | -------------------------------------------------------------------------------- /Sorting/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | Vue.js in action 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
    19 |

    Visual sorting

    20 |
    21 | 22 |
    23 | 24 |
    25 | 26 |
    27 | 28 | 29 |
    30 |
    31 |
    32 | 33 | 34 |
    35 | {{ num }} 36 |
    37 |
    38 | 39 |
    40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Sorting/sorting.js: -------------------------------------------------------------------------------- 1 | function sleep() { 2 | return new Promise(resolve => setTimeout(resolve, 550)); 3 | } 4 | 5 | function arraySetWithoutIndexes(array, index, value) { 6 | array.splice(index, 1, value); 7 | } 8 | 9 | function arraySwap(array, indexA, indexB) { 10 | 11 | var x = array[indexA]; 12 | arraySetWithoutIndexes(array, indexA, array[indexB]); 13 | arraySetWithoutIndexes(array, indexB, x); 14 | 15 | } 16 | 17 | async function shuffle(a) { 18 | 19 | var j, i; 20 | for (i = a.length - 1; i > 0; i--) { 21 | j = Math.floor(Math.random() * (i + 1)); 22 | arraySwap(a, i, j); 23 | await sleep(); 24 | } 25 | 26 | } 27 | 28 | async function bubbleSort(a) { 29 | 30 | var len = a.length; 31 | for (var i = len - 1; i >= 0; i--) { 32 | for (var j = 1; j <= i; j++) { 33 | if (a[j - 1] > a[j]) { 34 | arraySwap(a, j - 1, j); 35 | await sleep(); 36 | } 37 | } 38 | } 39 | 40 | } 41 | 42 | async function selectionSort(a) { 43 | 44 | var minIdx, temp, 45 | len = a.length; 46 | 47 | for (var i = 0; i < len; i++) { 48 | minIdx = i; 49 | for (var j = i + 1; j < len; j++) { 50 | if (a[j] < a[minIdx]) { 51 | minIdx = j; 52 | } 53 | } 54 | 55 | arraySwap(a, i, minIdx); 56 | await sleep(); 57 | } 58 | 59 | } 60 | 61 | async function insertionSort(a) { 62 | 63 | var i, len = a.length, el, j; 64 | 65 | for (i = 1; i < len; i++) { 66 | el = a[i]; 67 | j = i; 68 | 69 | while (j > 0 && a[j - 1] > el) { 70 | a[j] = a[j - 1]; 71 | j--; 72 | } 73 | 74 | arraySetWithoutIndexes(a, j, el); 75 | await sleep(); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /Sorting/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | input:focus, 7 | select:focus, 8 | textarea:focus, 9 | button:focus { 10 | outline: none; 11 | } 12 | 13 | html { 14 | overflow-y: scroll; 15 | } 16 | 17 | body { 18 | display: grid; 19 | grid-template-rows: 80px 1fr; 20 | background-color: #fdef78; 21 | font-family: 'Roboto Slab', serif; 22 | margin-bottom: 10px; 23 | } 24 | 25 | header { 26 | display: grid; 27 | color: white; 28 | background: #2f2e2a; 29 | } 30 | 31 | header h1 { 32 | place-self: center; 33 | font-size: 42px; 34 | } 35 | 36 | #app-sorting { 37 | place-self: center; 38 | margin-top: 30px; 39 | display: grid; 40 | justify-items: center; 41 | align-items: center; 42 | grid-template-rows: 60px 1fr; 43 | justify-items: center; 44 | } 45 | 46 | .buttons-container { 47 | height: 60px; 48 | } 49 | 50 | .array-to-be-sorted { 51 | margin: 50px; 52 | display: grid; 53 | grid-template-columns: repeat(8, auto); 54 | justify-items: center; 55 | align-items: center; 56 | } 57 | 58 | .even { 59 | background-color: #f96167; 60 | } 61 | 62 | .odd { 63 | background-color: #2f2e2a; 64 | } 65 | 66 | .list-item { 67 | display: grid; 68 | justify-items: center; 69 | align-items: center; 70 | padding: 15px; 71 | width: 50px; 72 | height: 50px; 73 | border-radius: 100px; 74 | color: white; 75 | margin: 10px; 76 | font-size: 30px; 77 | font-family: 'Roboto Slab', serif; 78 | font-weight: bold; 79 | text-align: center; 80 | } 81 | 82 | .list-animation-item { 83 | transition: all ease 0.5s; 84 | } 85 | 86 | .fade-enter-active, .fade-leave-active { 87 | transition: all ease 1s; 88 | } 89 | 90 | .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { 91 | opacity: 0; 92 | transform: translateY(-30px) scale(0.9); 93 | } 94 | 95 | .button { 96 | box-shadow: 0px 1px 0px 0px #f0f7fa; 97 | background-color: #33bdef; 98 | border-radius: 6px; 99 | border: 1px solid #057fd0; 100 | display: inline-block; 101 | cursor: pointer; 102 | color: #ffffff; 103 | font-family: Arial; 104 | font-size: 15px; 105 | font-weight: bold; 106 | padding: 6px 24px; 107 | text-decoration: none; 108 | text-shadow: 0px -1px 0px #5b6178; 109 | margin: 10px; 110 | } 111 | 112 | .button:hover { 113 | background-color: #019ad2; 114 | } 115 | 116 | .button:active { 117 | position: relative; 118 | top: 1px; 119 | } 120 | 121 | -------------------------------------------------------------------------------- /Sudoku/app.js: -------------------------------------------------------------------------------- 1 | var sudokuApp = new Vue({ 2 | 3 | el: '#app-sudoku', 4 | 5 | data: { 6 | 7 | sudokuMatrix: [], 8 | initializeGameText: "Start!", 9 | evaluateGameText: "Verify!", 10 | answerImage: "", 11 | isGameStarted: false, 12 | showAnswer: false 13 | }, 14 | 15 | methods: { 16 | 17 | initializeGame() { 18 | 19 | var defaultSudokuMatrix = [ 20 | [{ num: 5 }, { num: 3 }, { num: 4 }, { num: 6 }, { num: 7 }, { num: 8 }, { num: 9 }, { num: 1 }, { num: 2 }], 21 | [{ num: 6 }, { num: 7 }, { num: 2 }, { num: 1 }, { num: 9 }, { num: 5 }, { num: 3 }, { num: 4 }, { num: 8 }], 22 | [{ num: 1 }, { num: 9 }, { num: 8 }, { num: 3 }, { num: 4 }, { num: 2 }, { num: 5 }, { num: 6 }, { num: 7 }], 23 | [{ num: 8 }, { num: 5 }, { num: 9 }, { num: 7 }, { num: 6 }, { num: 1 }, { num: 4 }, { num: 2 }, { num: 3 }], 24 | [{ num: 4 }, { num: 2 }, { num: 6 }, { num: 8 }, { num: 5 }, { num: 3 }, { num: 7 }, { num: 9 }, { num: 1 }], 25 | [{ num: 7 }, { num: 1 }, { num: 3 }, { num: 9 }, { num: 2 }, { num: 4 }, { num: 8 }, { num: 5 }, { num: 6 }], 26 | [{ num: 9 }, { num: 6 }, { num: 1 }, { num: 5 }, { num: 3 }, { num: 7 }, { num: 2 }, { num: 8 }, { num: 4 }], 27 | [{ num: 2 }, { num: 8 }, { num: 7 }, { num: 4 }, { num: 1 }, { num: 9 }, { num: 6 }, { num: 3 }, { num: 5 }], 28 | [{ num: 3 }, { num: 4 }, { num: 5 }, { num: 2 }, { num: 8 }, { num: 6 }, { num: 1 }, { num: 7 }, { num: 9 }] 29 | ]; 30 | 31 | // Empty two random cells per row 32 | for (var i = 0; i < defaultSudokuMatrix.length; ++i) { 33 | for (var k = 0; k < 2; ++k) { 34 | var randomColumnIndex = Math.floor(Math.random() * defaultSudokuMatrix.length); 35 | defaultSudokuMatrix[i][randomColumnIndex].num = ""; 36 | } 37 | } 38 | 39 | this.sudokuMatrix = defaultSudokuMatrix; 40 | this.initializeGameText = "Restart"; 41 | this.isGameStarted = true; 42 | }, 43 | 44 | evaluateGame() { 45 | 46 | var copyOfSudokuMatrix = []; 47 | for (var i = 0; i < this.sudokuMatrix.length; ++i) { 48 | 49 | if (!copyOfSudokuMatrix[i]) 50 | copyOfSudokuMatrix[i] = []; 51 | 52 | for (var k = 0; k < this.sudokuMatrix[i].length; ++k) { 53 | copyOfSudokuMatrix[i][k] = this.sudokuMatrix[i][k].num; 54 | } 55 | 56 | } 57 | 58 | var sudokuSolver = Sudoku.init(copyOfSudokuMatrix); 59 | 60 | if (sudokuSolver.isValid()) { 61 | 62 | this.answerImage = "success.gif"; 63 | this.showAnswer = true; 64 | this.isGameStarted = false; 65 | 66 | setTimeout(() => { 67 | this.showAnswer = false; 68 | this.isGameStarted = true; 69 | }, 2000); 70 | 71 | } 72 | else { 73 | 74 | this.answerImage = "fail.gif"; 75 | this.showAnswer = true; 76 | this.isGameStarted = false; 77 | 78 | setTimeout(() => { 79 | this.showAnswer = false; 80 | this.isGameStarted = true; 81 | }, 2000); 82 | 83 | } 84 | 85 | } 86 | 87 | } 88 | }); 89 | -------------------------------------------------------------------------------- /Sudoku/fail.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrancescoBonizzi/VueJs-Experiments/34c2386b461e326c77d04778f06244a7ca406853/Sudoku/fail.gif -------------------------------------------------------------------------------- /Sudoku/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | Vue.js in action 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
    19 |

    Sudoku

    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 | 52 |
    53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Sudoku/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | input:focus, 7 | select:focus, 8 | textarea:focus, 9 | button:focus { 10 | outline: none; 11 | } 12 | 13 | body { 14 | display: grid; 15 | grid-template-rows: 150px 1fr; 16 | background-color: #ff5252; 17 | font-family: 'Dosis', sans-serif; 18 | } 19 | 20 | header { 21 | display: grid; 22 | color: white; 23 | } 24 | 25 | header h1 { 26 | place-self: center; 27 | } 28 | 29 | #app-sudoku { 30 | place-self: center; 31 | display: grid; 32 | grid-template-rows: auto 1fr; 33 | justify-items: center; 34 | } 35 | 36 | .buttons-container { 37 | display: grid; 38 | grid-template-rows: auto auto; 39 | } 40 | 41 | .button { 42 | display: inline-block; 43 | border-radius: 6px; 44 | background-color: whitesmoke; 45 | border: none; 46 | color: black; 47 | text-align: center; 48 | font-size: 16px; 49 | padding: 10px; 50 | width: 230px; 51 | transition: all 0.5s; 52 | cursor: pointer; 53 | margin: 0px 0px 25px 0px; 54 | font-family: 'Dosis', sans-serif; 55 | font-weight: bold; 56 | } 57 | 58 | .button span { 59 | cursor: pointer; 60 | display: inline-block; 61 | position: relative; 62 | transition: 0.5s; 63 | } 64 | 65 | .button span:after { 66 | content: '\00bb'; 67 | position: absolute; 68 | opacity: 0; 69 | top: 0; 70 | right: -20px; 71 | transition: 0.5s; 72 | } 73 | 74 | .button:hover span { 75 | padding-right: 25px; 76 | } 77 | 78 | .button:hover span:after { 79 | opacity: 1; 80 | right: 0; 81 | } 82 | 83 | .grid-sudoku { 84 | display: table; 85 | background: white; 86 | border: 3px solid black; 87 | } 88 | 89 | .grid-sudoku > div:nth-child(3), .grid-sudoku > div:nth-child(6) { 90 | border-bottom: 3px solid black; 91 | } 92 | 93 | .grid-row > div:nth-child(3), .grid-row > div:nth-child(6) { 94 | border-right: 3px solid black; 95 | } 96 | 97 | .grid-cell { 98 | display: table-cell; 99 | padding: 10px; 100 | border: 1px solid gray; 101 | } 102 | 103 | .grid-cell-editor { 104 | border: none; 105 | width: 20px; 106 | height: 20px; 107 | font-family: 'Dosis', sans-serif; 108 | font-weight: bold; 109 | text-align: center; 110 | font-size: 18px; 111 | transition: all ease 1.0s; 112 | } 113 | 114 | .answer { 115 | position: absolute; 116 | top: 0; 117 | left: 0; 118 | right: 0; 119 | bottom: 0; 120 | display: flex; 121 | justify-content: center; 122 | align-items: center; 123 | } 124 | 125 | .answer-image { 126 | border: 2px solid black; 127 | width: 300px; 128 | height: 300px; 129 | } 130 | 131 | .list-animation-enter, .list-animation-leave-to { 132 | opacity: 0; 133 | transform: translateY(20px) translateX(20px) rotate(200deg) scale(0.5); 134 | } 135 | 136 | .list-animation-leave-active { 137 | position: absolute; 138 | } 139 | 140 | .fade-enter-active, .fade-leave-active { 141 | transition: opacity .5s; 142 | } 143 | 144 | .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { 145 | opacity: 0; 146 | } -------------------------------------------------------------------------------- /Sudoku/success.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrancescoBonizzi/VueJs-Experiments/34c2386b461e326c77d04778f06244a7ca406853/Sudoku/success.gif -------------------------------------------------------------------------------- /Sudoku/sudoku.js: -------------------------------------------------------------------------------- 1 | var Sudoku = ( function (){ 2 | 3 | var _rows, _cols, _grid; 4 | 5 | // initialize the module with input data 6 | init = function(data){ 7 | _reorganizeData(data); 8 | return this; 9 | }; 10 | 11 | // return true if sudoku is valid 12 | isValid = function(){ 13 | return (_validate(_rows) && _validate(_cols) && _validate(_grid)); 14 | }; 15 | 16 | // validate rows 17 | _validate = function(data){ 18 | 19 | for (var row = 0; row < 9; row++) { 20 | 21 | data[row].sort(); 22 | 23 | for (var col = 0; col < 9; col++) { 24 | 25 | var value = data[row][col], next_value = data[row][col + 1]; 26 | 27 | // check if value exists and is a valid number 28 | if (!(value && value > 0 && value < 10)){ 29 | return false; 30 | } 31 | 32 | // check if numbers are unique 33 | if (col !== 8 && value === next_value){ 34 | return false; 35 | } 36 | 37 | } 38 | } 39 | return true; 40 | }; 41 | 42 | // reorganize data into three structures 43 | _reorganizeData = function(data){ 44 | _rows = data; 45 | _cols = []; 46 | _grid = []; 47 | 48 | // Prefilling the structures with empty array objects 49 | for (var i = 0; i < 9; i++) { 50 | _cols.push([]); 51 | _grid.push([]); 52 | } 53 | 54 | for (var row = 0; row < 9; row++) { 55 | 56 | for (var col = 0; col < 9; col++) { 57 | 58 | // Save each column in a new row 59 | _cols[col][row] = data[row][col]; 60 | 61 | // Calculate grid identifiers 62 | gridRow = Math.floor( row / 3 ); 63 | gridCol = Math.floor( col / 3 ); 64 | gridIndex = gridRow * 3 + gridCol; 65 | 66 | // Save each grid in a new row 67 | _grid[gridIndex].push(data[row][col]); 68 | 69 | } 70 | } 71 | 72 | }; 73 | 74 | // make functions public 75 | return { 76 | init: init, 77 | isValid: isValid 78 | }; 79 | })(); 80 | -------------------------------------------------------------------------------- /Todo list application/app.js: -------------------------------------------------------------------------------- 1 | var itemIndex = 0; 2 | 3 | function GetFreeItemIndex() { 4 | itemIndex++; 5 | return itemIndex; 6 | } 7 | 8 | var testData = [ 9 | { Id: GetFreeItemIndex(), Text: "Lorem ipsum dolor sit amet", IsDone: false }, 10 | { Id: GetFreeItemIndex(), Text: "Sed fringilla tellus nec finibus maximus. Duis venenatis risus purus. Duis magna odio, eleifend vitae dignissim gravida, semper volutpat nisl", IsDone: false }, 11 | { Id: GetFreeItemIndex(), Text: "Ut nec erat non nulla ultricies condimentum", IsDone: true } 12 | ]; 13 | 14 | var todoListApp = new Vue({ 15 | 16 | el: '#app-todolist', 17 | 18 | data: { 19 | todoItems: testData, 20 | newTodoText: "" 21 | }, 22 | 23 | methods: { 24 | 25 | addTodo: function() { 26 | 27 | if (this.newTodoText.trim() === "") 28 | return; 29 | 30 | this.todoItems.push({ Id: GetFreeItemIndex(), Text: this.newTodoText, IsDone: false}); 31 | this.newTodoText = ""; 32 | 33 | }, 34 | 35 | removeTodo: function(todo) { 36 | this.todoItems.splice(this.todoItems.indexOf(todo), 1); 37 | } 38 | } 39 | }); 40 | -------------------------------------------------------------------------------- /Todo list application/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Vue.js in action 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
    19 |

    Things to do

    20 |
    21 | 22 |
    23 | 24 |
    25 | 26 | + 27 |
    28 | 29 |
    30 | 31 | 32 |
  • 33 | 34 | 38 | 39 | {{ todo.Text }} 40 | 41 | x 42 | 43 |
  • 44 |
    45 | 46 |
    47 | 48 |
    49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Todo list application/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | input:focus, 7 | select:focus, 8 | textarea:focus, 9 | button:focus { 10 | outline: none; 11 | } 12 | 13 | body { 14 | display: grid; 15 | grid-template-rows: 150px 1fr; 16 | background-color: #202124; 17 | font-family: 'Ubuntu Mono', monospace; 18 | } 19 | 20 | header { 21 | display: grid; 22 | border-bottom: 1px solid #5f6368; 23 | color: white; 24 | } 25 | 26 | header h1 { 27 | place-self: center; 28 | } 29 | 30 | #app-todolist { 31 | place-self: center; 32 | } 33 | 34 | #commands { 35 | place-self: center; 36 | display: grid; 37 | grid-template-columns: 1fr auto; 38 | padding: 10px; 39 | margin-top: 30px; 40 | box-shadow: 0 1px 2px 0 rgba(0,0,0,0.6), 0 2px 6px 2px rgba(0,0,0,0.302); 41 | } 42 | 43 | #commands input { 44 | border: none; 45 | background: #2d2e30; 46 | color: white; 47 | padding-left: 5px; 48 | font-size: 18px; 49 | } 50 | 51 | a { 52 | color: #5f6368; 53 | text-decoration: none; 54 | padding: 2px; 55 | margin-left: 5px; 56 | font-weight: bold; 57 | font-size: 22px; 58 | transition: color 0.5s ease; 59 | } 60 | 61 | a:active { 62 | color: #5f6368; 63 | } 64 | 65 | a:hover { 66 | color: white; 67 | } 68 | 69 | #main-content { 70 | place-self: center; 71 | margin-top: 30px; 72 | } 73 | 74 | .todo-item, #commands { 75 | background: #2d2e30; 76 | width: 450px; 77 | border-radius: 8px; 78 | border: 1px solid #5f6368; 79 | align-items: center; 80 | } 81 | 82 | .todo-item { 83 | list-style: none; 84 | color: white; 85 | padding: 10px 10px; 86 | margin-bottom: 10px; 87 | display: grid; 88 | grid-template-columns: auto 1fr auto; 89 | } 90 | 91 | .todo-text span { 92 | overflow-wrap: break-word; 93 | } 94 | 95 | .completed { 96 | text-decoration: line-through; 97 | color: #5f6368; 98 | transition: color 0.4s ease; 99 | } 100 | 101 | .todo-check { 102 | margin-right: 10px; 103 | place-self: center; 104 | display: block; 105 | user-select: none; 106 | -webkit-user-select: none; 107 | -moz-user-select: none; 108 | -ms-user-select: none; 109 | cursor: pointer; 110 | } 111 | 112 | .todo-check input { 113 | position: absolute; 114 | opacity: 0; 115 | cursor: pointer; 116 | height: 0; 117 | width: 0; 118 | } 119 | 120 | .checkmark { 121 | display: block; 122 | height: 18px; 123 | width: 18px; 124 | background-color: transparent; 125 | border: 2px solid #5f6368; 126 | border-radius: 3px; 127 | transition: all 0.5s ease; 128 | } 129 | 130 | .todo-check:hover, .checkmark:hover, .checkmark:hover:after { 131 | color: white; 132 | border-color: white !important; 133 | transition: all 0.5s ease; 134 | } 135 | 136 | .checkmark:after { 137 | content: ""; 138 | position: relative; 139 | display: none; 140 | } 141 | 142 | .todo-check input:checked ~ .checkmark:after { 143 | display: block; 144 | } 145 | 146 | .todo-check .checkmark:after { 147 | left: 5px; 148 | top: 1px; 149 | width: 5px; 150 | height: 10px; 151 | border: solid #5f6368; 152 | border-width: 0 3px 3px 0; 153 | -webkit-transform: rotate(45deg); 154 | -ms-transform: rotate(45deg); 155 | transform: rotate(45deg); 156 | transition: all 0.5s ease; 157 | } 158 | 159 | .todo-item-animated { 160 | transition: all 0.5s; 161 | } 162 | 163 | .list-animation-enter, .list-animation-leave-to { 164 | opacity: 0; 165 | transform: translateY(30px); 166 | } 167 | 168 | .list-animation-leave-active { 169 | position: absolute; 170 | } --------------------------------------------------------------------------------