├── .editorconfig
├── .github
├── FUNDING.yml
├── contributing
│ ├── oxford-comma.jpg
│ └── writing-guide.md
├── dependabot.yml
├── pull_request_template.md
├── scripts
│ └── tag-alert-blocks.js
└── workflows
│ └── automerge.yml
├── .gitignore
├── .prettierrc
├── .vitepress
├── config.ts
├── headerMdPlugin.ts
├── inlined-scripts
│ └── restorePreference.js
├── textAdMdPlugin.ts
└── theme
│ ├── components
│ ├── Banner.vue
│ ├── Home.vue
│ ├── NewsLetter.vue
│ ├── PreferenceSwitch.vue
│ ├── PreferenceTooltip.vue
│ ├── ReplLoading.vue
│ ├── SiteMap.vue
│ ├── SponsorsAside.vue
│ ├── SponsorsGroup.vue
│ ├── TextAd.vue
│ ├── VueJobs.vue
│ ├── VueMasteryBanner.vue
│ ├── VueMasteryModal.vue
│ ├── VueSchoolLink.vue
│ ├── preferences.ts
│ └── sponsors.ts
│ ├── index.ts
│ └── styles
│ ├── badges.css
│ ├── index.css
│ ├── inline-demo.css
│ ├── options-boxes.css
│ ├── pages.css
│ ├── style-guide.css
│ ├── utilities.css
│ └── vue-mastery.css
├── LICENSE
├── README.md
├── env.d.ts
├── netlify.toml
├── package-lock.json
├── package.json
├── pnpm-lock.yaml
├── src
├── about
│ ├── coc.md
│ ├── community-guide.md
│ ├── faq.md
│ ├── images
│ │ ├── ben-hong.jpeg
│ │ └── evan-you.jpeg
│ ├── releases.md
│ ├── team.md
│ └── team
│ │ ├── Member.ts
│ │ ├── TeamHero.vue
│ │ ├── TeamList.vue
│ │ ├── TeamMember.vue
│ │ ├── TeamPage.vue
│ │ ├── members-core.json
│ │ ├── members-emeriti.json
│ │ └── members-partner.json
├── api
│ ├── ApiIndex.vue
│ ├── api.data.ts
│ ├── application.md
│ ├── built-in-components.md
│ ├── built-in-directives.md
│ ├── built-in-special-attributes.md
│ ├── built-in-special-elements.md
│ ├── component-instance.md
│ ├── composition-api-dependency-injection.md
│ ├── composition-api-lifecycle.md
│ ├── composition-api-setup.md
│ ├── custom-renderer.md
│ ├── general.md
│ ├── index.md
│ ├── options-composition.md
│ ├── options-lifecycle.md
│ ├── options-misc.md
│ ├── options-rendering.md
│ ├── options-state.md
│ ├── reactivity-advanced.md
│ ├── reactivity-core.md
│ ├── reactivity-utilities.md
│ ├── render-function.md
│ ├── sfc-css-features.md
│ ├── sfc-script-setup.md
│ ├── sfc-spec.md
│ ├── ssr.md
│ └── utility-types.md
├── ecosystem
│ ├── newsletters.md
│ ├── themes.md
│ └── themes
│ │ ├── ThemeContact.vue
│ │ ├── ThemeHero.vue
│ │ ├── ThemeList.vue
│ │ ├── ThemeListItem.vue
│ │ ├── ThemePage.vue
│ │ ├── ThemeProduct.vue
│ │ └── themes.json
├── examples
│ ├── ExampleRepl.vue
│ ├── examples.data.ts
│ ├── index.md
│ ├── src
│ │ ├── attribute-bindings
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ ├── style.css
│ │ │ │ └── template.html
│ │ │ └── description.txt
│ │ ├── cells
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ ├── style.css
│ │ │ │ └── template.html
│ │ │ ├── Cell
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ ├── style.css
│ │ │ │ └── template.html
│ │ │ ├── description.txt
│ │ │ └── store.js
│ │ ├── circle-drawer
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ ├── style.css
│ │ │ │ └── template.html
│ │ │ └── description.txt
│ │ ├── conditionals-and-loops
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ │ └── description.txt
│ │ ├── counter
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ │ └── description.txt
│ │ ├── crud
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ ├── style.css
│ │ │ │ └── template.html
│ │ │ └── description.txt
│ │ ├── fetching-data
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ ├── style.css
│ │ │ │ └── template.html
│ │ │ └── description.txt
│ │ ├── flight-booker
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ ├── style.css
│ │ │ │ └── template.html
│ │ │ └── description.txt
│ │ ├── form-bindings
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ │ └── description.txt
│ │ ├── grid
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ │ ├── Grid
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ ├── style.css
│ │ │ │ └── template.html
│ │ │ └── description.txt
│ │ ├── handling-input
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ ├── style.css
│ │ │ │ └── template.html
│ │ │ └── description.txt
│ │ ├── hello-world
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ │ └── description.txt
│ │ ├── list-transition
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ ├── style.css
│ │ │ │ └── template.html
│ │ │ ├── description.txt
│ │ │ └── import-map.json
│ │ ├── markdown
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ ├── style.css
│ │ │ │ └── template.html
│ │ │ ├── description.txt
│ │ │ └── import-map.json
│ │ ├── modal
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ │ ├── Modal
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ ├── style.css
│ │ │ │ └── template.html
│ │ │ └── description.txt
│ │ ├── simple-component
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ │ ├── TodoItem
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ │ └── description.txt
│ │ ├── svg
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ ├── style.css
│ │ │ │ └── template.html
│ │ │ ├── AxisLabel
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ │ ├── PolyGraph
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ │ ├── description.txt
│ │ │ └── util.js
│ │ ├── temperature-converter
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ │ └── description.txt
│ │ ├── timer
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ ├── style.css
│ │ │ │ └── template.html
│ │ │ └── description.txt
│ │ ├── todomvc
│ │ │ ├── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ ├── style.css
│ │ │ │ └── template.html
│ │ │ └── description.txt
│ │ └── tree
│ │ │ ├── App
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ ├── style.css
│ │ │ └── template.html
│ │ │ ├── TreeItem
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ └── template.html
│ │ │ └── description.txt
│ └── utils.ts
├── glossary
│ └── index.md
├── guide
│ ├── best-practices
│ │ ├── accessibility.md
│ │ ├── images
│ │ │ ├── AccessibilityChromeDeveloperTools.png
│ │ │ ├── AccessibleARIAdescribedby.png
│ │ │ ├── AccessibleARIAlabelDevTools.png
│ │ │ ├── AccessibleARIAlabelledbyDevTools.png
│ │ │ ├── AccessibleLabelChromeDevTools.png
│ │ │ └── AccessiblePlaceholder.png
│ │ ├── performance.md
│ │ ├── production-deployment.md
│ │ └── security.md
│ ├── built-ins
│ │ ├── images
│ │ │ └── transition-classes.png
│ │ ├── keep-alive-demos
│ │ │ ├── CompA.vue
│ │ │ ├── CompB.vue
│ │ │ └── SwitchComponent.vue
│ │ ├── keep-alive.md
│ │ ├── suspense.md
│ │ ├── teleport.md
│ │ ├── transition-demos
│ │ │ ├── Basic.vue
│ │ │ ├── BetweenComponents.vue
│ │ │ ├── BetweenElements.vue
│ │ │ ├── CssAnimation.vue
│ │ │ ├── JsHooks.vue
│ │ │ ├── ListBasic.vue
│ │ │ ├── ListMove.vue
│ │ │ ├── ListStagger.vue
│ │ │ ├── NestedTransitions.vue
│ │ │ └── SlideFade.vue
│ │ ├── transition-group.md
│ │ └── transition.md
│ ├── components
│ │ ├── async.md
│ │ ├── attrs.md
│ │ ├── events.md
│ │ ├── images
│ │ │ ├── named-slots.png
│ │ │ ├── prop-drilling.png
│ │ │ ├── provide-inject.png
│ │ │ ├── scoped-slots.svg
│ │ │ └── slots.png
│ │ ├── props.md
│ │ ├── provide-inject.md
│ │ ├── registration.md
│ │ ├── slots.md
│ │ └── v-model.md
│ ├── essentials
│ │ ├── application.md
│ │ ├── class-and-style.md
│ │ ├── component-basics.md
│ │ ├── computed.md
│ │ ├── conditional.md
│ │ ├── event-handling.md
│ │ ├── forms.md
│ │ ├── images
│ │ │ ├── components.png
│ │ │ ├── directive.png
│ │ │ └── lifecycle.png
│ │ ├── lifecycle.md
│ │ ├── list.md
│ │ ├── reactivity-fundamentals.md
│ │ ├── template-refs.md
│ │ ├── template-syntax.md
│ │ └── watchers.md
│ ├── extras
│ │ ├── animation.md
│ │ ├── composition-api-faq.md
│ │ ├── demos
│ │ │ ├── AnimateWatcher.vue
│ │ │ ├── Colors.vue
│ │ │ ├── DisabledButton.vue
│ │ │ ├── ElasticHeader.vue
│ │ │ ├── SpreadSheet.vue
│ │ │ ├── SpreadSheetCell.vue
│ │ │ └── spreadSheetStore.js
│ │ ├── images
│ │ │ ├── composition-api-after.png
│ │ │ ├── options-api.png
│ │ │ └── render-pipeline.png
│ │ ├── reactivity-in-depth.md
│ │ ├── reactivity-transform.md
│ │ ├── render-function.md
│ │ ├── rendering-mechanism.md
│ │ ├── ways-of-using-vue.md
│ │ └── web-components.md
│ ├── introduction.md
│ ├── quick-start.md
│ ├── reusability
│ │ ├── composables.md
│ │ ├── custom-directives.md
│ │ ├── mouse.js
│ │ └── plugins.md
│ ├── scaling-up
│ │ ├── images
│ │ │ └── state-flow.png
│ │ ├── routing.md
│ │ ├── sfc.md
│ │ ├── ssr.md
│ │ ├── state-management.md
│ │ ├── testing.md
│ │ └── tooling.md
│ └── typescript
│ │ ├── composition-api.md
│ │ ├── images
│ │ └── takeover-mode.png
│ │ ├── options-api.md
│ │ └── overview.md
├── index.md
├── partners
│ ├── [partnerId].md
│ ├── [partnerId].paths.ts
│ ├── all.md
│ ├── components
│ │ ├── PartnerAll.vue
│ │ ├── PartnerCard.vue
│ │ ├── PartnerHero.vue
│ │ ├── PartnerJoin.vue
│ │ ├── PartnerLanding.vue
│ │ ├── PartnerList.vue
│ │ ├── PartnerLocation.vue
│ │ ├── PartnerPage.vue
│ │ ├── type.ts
│ │ └── utils.ts
│ ├── index.md
│ └── partners.json
├── public
│ ├── _headers
│ ├── _redirects
│ ├── glossary.json
│ ├── images
│ │ ├── logo.png
│ │ ├── partners
│ │ │ ├── 64robots-hero.jpg
│ │ │ ├── 64robots.svg
│ │ │ ├── curotec-hero.jpg
│ │ │ ├── curotec.png
│ │ │ ├── epicmax.png
│ │ │ ├── epicmax.svg
│ │ │ ├── herodevs-dark.png
│ │ │ ├── herodevs-hero.png
│ │ │ ├── herodevs.png
│ │ │ ├── jump24-dark.svg
│ │ │ ├── jump24-hero.jpg
│ │ │ ├── jump24.svg
│ │ │ ├── monterail-dark.png
│ │ │ ├── monterail-hero.png
│ │ │ ├── monterail.png
│ │ │ ├── passionatepeople-dark.png
│ │ │ ├── passionatepeople-hero.jpg
│ │ │ ├── passionatepeople.png
│ │ │ ├── redberry-hero.jpg
│ │ │ ├── redberry.png
│ │ │ ├── tighten-dark.svg
│ │ │ ├── tighten-hero.jpg
│ │ │ ├── tighten.svg
│ │ │ ├── vehikl-dark.svg
│ │ │ ├── vehikl-hero.jpg
│ │ │ ├── vehikl.svg
│ │ │ ├── webreinvent-hero.jpg
│ │ │ └── webreinvent.png
│ │ └── paypal.png
│ ├── logo.svg
│ ├── service-worker.js
│ └── vuemastery
│ │ ├── background-bubbles-vuemastery.svg
│ │ ├── lock-vuemastery.svg
│ │ ├── unlock-vuemastery.svg
│ │ └── vuemastery-white.svg
├── sponsor
│ └── index.md
├── style-guide
│ ├── index.md
│ ├── rules-essential.md
│ ├── rules-recommended.md
│ ├── rules-strongly-recommended.md
│ └── rules-use-with-caution.md
├── translations
│ └── index.md
└── tutorial
│ ├── TutorialRepl.vue
│ ├── index.md
│ ├── src
│ ├── step-1
│ │ ├── App
│ │ │ └── template.html
│ │ └── description.md
│ ├── step-10
│ │ ├── App
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ └── template.html
│ │ ├── _hint
│ │ │ └── App
│ │ │ │ ├── composition.js
│ │ │ │ └── options.js
│ │ └── description.md
│ ├── step-11
│ │ ├── App
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ └── template.html
│ │ ├── ChildComp
│ │ │ └── template.html
│ │ ├── _hint
│ │ │ └── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ └── description.md
│ ├── step-12
│ │ ├── App
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ └── template.html
│ │ ├── ChildComp
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ └── template.html
│ │ ├── _hint
│ │ │ └── App
│ │ │ │ └── template.html
│ │ └── description.md
│ ├── step-13
│ │ ├── App
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ └── template.html
│ │ ├── ChildComp
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ └── template.html
│ │ ├── _hint
│ │ │ └── App
│ │ │ │ └── template.html
│ │ └── description.md
│ ├── step-14
│ │ ├── App
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ └── template.html
│ │ ├── ChildComp
│ │ │ └── template.html
│ │ ├── _hint
│ │ │ └── App
│ │ │ │ └── template.html
│ │ └── description.md
│ ├── step-15
│ │ ├── App
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ ├── style.css
│ │ │ └── template.html
│ │ ├── description.md
│ │ └── import-map.json
│ ├── step-2
│ │ ├── App
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ └── template.html
│ │ ├── _hint
│ │ │ └── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ └── description.md
│ ├── step-3
│ │ ├── App
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ ├── style.css
│ │ │ └── template.html
│ │ ├── _hint
│ │ │ └── App
│ │ │ │ └── template.html
│ │ └── description.md
│ ├── step-4
│ │ ├── App
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ └── template.html
│ │ ├── _hint
│ │ │ └── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ └── description.md
│ ├── step-5
│ │ ├── App
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ └── template.html
│ │ ├── _hint
│ │ │ └── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ └── description.md
│ ├── step-6
│ │ ├── App
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ └── template.html
│ │ ├── _hint
│ │ │ └── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ └── description.md
│ ├── step-7
│ │ ├── App
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ └── template.html
│ │ ├── _hint
│ │ │ └── App
│ │ │ │ ├── composition.js
│ │ │ │ └── options.js
│ │ └── description.md
│ ├── step-8
│ │ ├── App
│ │ │ ├── composition.js
│ │ │ ├── options.js
│ │ │ ├── style.css
│ │ │ └── template.html
│ │ ├── _hint
│ │ │ └── App
│ │ │ │ ├── composition.js
│ │ │ │ ├── options.js
│ │ │ │ └── template.html
│ │ └── description.md
│ └── step-9
│ │ ├── App
│ │ ├── composition.js
│ │ ├── options.js
│ │ └── template.html
│ │ ├── _hint
│ │ └── App
│ │ │ ├── composition.js
│ │ │ └── options.js
│ │ └── description.md
│ └── tutorial.data.ts
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | charset = utf-8
3 | indent_style = space
4 | indent_size = 2
5 | end_of_line = lf
6 | insert_final_newline = true
7 | trim_trailing_whitespace = true
8 |
9 | [*.md]
10 | trim_trailing_whitespace = false
11 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | # github: matrunchyk,dddarkasss
4 | patreon: vuejsorgua
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 | # lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
13 | # custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
14 |
--------------------------------------------------------------------------------
/.github/contributing/oxford-comma.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/.github/contributing/oxford-comma.jpg
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | # Enable version updates for npm
4 | - package-ecosystem: 'npm'
5 | # Look for `package.json` and `lock` files in the `root` directory
6 | directory: '/'
7 | # Check the npm registry for updates every day (weekdays)
8 | schedule:
9 | interval: 'daily'
10 | open-pull-requests-limit: 10
11 | versioning-strategy: lockfile-only
12 | allow:
13 | - dependency-name: 'vue'
14 | - dependency-name: 'vitepress'
15 | - dependency-name: '@vue/theme'
16 | - dependency-name: '@vue/repl'
17 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | - [ ] Я ознайомлений(а) з [Правилами спільноти](https://github.com/vuejs-translations/docs-uk/wiki/Правила-спільноти) та зобов'язуюсь їх дотримуватись.
2 |
--------------------------------------------------------------------------------
/.github/scripts/tag-alert-blocks.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const { exec } = require('child_process')
4 |
5 | /**
6 | * Execute a command and return stdout as string.
7 | * @param {string} command
8 | * @returns {Promise}
9 | */
10 | function run(command) {
11 | return new Promise((resolve, reject) => {
12 | exec(command, { encoding: 'utf-8' }, (error, stdout) =>
13 | error ? reject(error) : resolve(stdout)
14 | )
15 | })
16 | }
17 |
18 | const ALERT_BLOCK = /^\+\s*:::\s?(\w+)/m
19 |
20 | async function isUsingAlertBlock(base = 'origin/master') {
21 | const result = await run(`git diff --name-only ${base}`)
22 | const files = (
23 | await Promise.all(
24 | result
25 | .trim()
26 | .split(/\r?\n/)
27 | .map(file =>
28 | run(`git diff ${base} -- ${file}`)
29 | .then(diff => ALERT_BLOCK.test(diff))
30 | .then(usesAlertBlock => (usesAlertBlock ? file : ''))
31 | )
32 | )
33 | ).filter(Boolean)
34 |
35 | if (files.length) {
36 | return true
37 | }
38 |
39 | return false
40 | }
41 |
42 | module.exports = { isUsingAlertBlock }
43 |
--------------------------------------------------------------------------------
/.github/workflows/automerge.yml:
--------------------------------------------------------------------------------
1 | name: Dependabot auto-merge
2 | on: pull_request
3 |
4 | permissions:
5 | pull-requests: write
6 | contents: write
7 |
8 | jobs:
9 | dependabot:
10 | runs-on: ubuntu-latest
11 | if: ${{ github.actor == 'dependabot[bot]' }}
12 | steps:
13 | - name: Dependabot metadata
14 | id: metadata
15 | uses: dependabot/fetch-metadata@v1.1.1
16 | with:
17 | github-token: '${{ secrets.GITHUB_TOKEN }}'
18 | - name: Enable auto-merge for theme
19 | if: ${{contains(steps.metadata.outputs.dependency-names, '@vue/theme') && steps.metadata.outputs.update-type != 'version-update:semver-major'}}
20 | run: gh pr merge --auto --merge "$PR_URL"
21 | env:
22 | PR_URL: ${{github.event.pull_request.html_url}}
23 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### OSX ###
2 | # General
3 | .DS_Store
4 | .AppleDouble
5 | .LSOverride
6 |
7 | # Thumbnails
8 | ._*
9 |
10 | # Files that might appear in the root of a volume
11 | .DocumentRevisions-V100
12 | .fseventsd
13 | .Spotlight-V100
14 | .TemporaryItems
15 | .Trashes
16 | .VolumeIcon.icns
17 | .com.apple.timemachine.donotpresent
18 |
19 | # Directories potentially created on remote AFP share
20 | .AppleDB
21 | .AppleDesktop
22 | Network Trash Folder
23 | Temporary Items
24 | .apdisk
25 |
26 | ### Node ###
27 | # Logs
28 | logs
29 | *.log
30 | npm-debug.log*
31 | yarn-debug.log*
32 | yarn-error.log*
33 | lerna-debug.log*
34 |
35 | # Diagnostic reports (https://nodejs.org/api/report.html)
36 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
37 |
38 | # Runtime data
39 | pids
40 | *.pid
41 | *.seed
42 | *.pid.lock
43 |
44 | # Directory for instrumented libs generated by jscoverage/JSCover
45 | lib-cov
46 |
47 | # Coverage directory used by tools like istanbul
48 | coverage
49 | *.lcov
50 |
51 | # nyc test coverage
52 | .nyc_output
53 |
54 | # node-waf configuration
55 | .lock-wscript
56 |
57 | # Compiled binary addons (https://nodejs.org/api/addons.html)
58 | build/Release
59 |
60 | # Dependency directories
61 | node_modules/
62 | jspm_packages/
63 |
64 | # TypeScript v1 declaration files
65 | typings/
66 |
67 | # TypeScript cache
68 | *.tsbuildinfo
69 |
70 | # Optional npm cache directory
71 | .npm
72 |
73 | # Optional eslint cache
74 | .eslintcache
75 |
76 | # Optional REPL history
77 | .node_repl_history
78 |
79 | # Output of 'npm pack'
80 | *.tgz
81 |
82 | # Yarn Integrity file
83 | .yarn-integrity
84 |
85 | # pnpm link folder
86 | pnpm-global
87 |
88 | # dotenv environment variables file
89 | .env
90 | .env.test
91 |
92 | # parcel-bundler cache (https://parceljs.org/)
93 | .cache
94 |
95 | # rollup.js default build output
96 | dist/
97 |
98 | # vitepress build output
99 | .vitepress/dist
100 | .vitepress/cache
101 |
102 | # Serverless directories
103 | .serverless/
104 |
105 | # Temporary folders
106 | tmp/
107 | temp/
108 | TODOs.md
109 | src/api/index.json
110 | src/examples/data.json
111 | src/tutorial/data.json
112 | draft.md
113 |
114 | .idea
115 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "singleQuote": true,
4 | "trailingComma": "none",
5 | "printWidth": 75
6 | }
7 |
--------------------------------------------------------------------------------
/.vitepress/headerMdPlugin.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * A markdown-it plugin to support custom header metadata
3 | * Headers that end with * are Options API only
4 | * Headers that end with ** are Composition API only
5 | * This plugin strips the markers and augments the extracted header data,
6 | * which can be then used by the theme to filter headers.
7 | *
8 | * TODO: we will likely also need special syntax for preserving the same anchor
9 | * links across translations similar to the one at
10 | * https://github.com/vitejs/docs-cn/tree/main/.vitepress/markdown-it-custom-anchor
11 | */
12 |
13 | import MarkdownIt from 'markdown-it'
14 | import { Header } from 'vitepress'
15 |
16 | export interface AugmentedHeader extends Header {
17 | compositionOnly?: boolean
18 | optionsOnly?: boolean
19 | }
20 |
21 | export const headerPlugin = (md: MarkdownIt) => {
22 | md.renderer.rules.heading_open = (tokens, i, options, env, self) => {
23 | for (const child of tokens[i + 1].children!) {
24 | if (child.type === 'text' && child.content.endsWith('*')) {
25 | child.content = child.content.replace(/\s*\*+$/, '')
26 | }
27 | }
28 | return self.renderToken(tokens, i, options)
29 | }
30 |
31 | const render = md.render
32 | md.render = (content, env) => {
33 | const res = render(content, env)
34 |
35 | if (env && env.headers) {
36 | processHeaders(env.headers)
37 | }
38 |
39 | return res
40 | }
41 | }
42 |
43 | function processHeaders(headers: AugmentedHeader[]) {
44 | for (const h of headers) {
45 | if (h.title.endsWith('*')) {
46 | if (h.title.endsWith('**')) {
47 | h.compositionOnly = true
48 | } else {
49 | h.optionsOnly = true
50 | }
51 | h.title = h.title.replace(/\s*\*+$/, '')
52 | }
53 | if (h.children) {
54 | processHeaders(h.children)
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/.vitepress/inlined-scripts/restorePreference.js:
--------------------------------------------------------------------------------
1 | ;(() => {
2 | const restore = (key, cls, def = false) => {
3 | const saved = localStorage.getItem(key)
4 | if (saved ? saved !== 'false' : def) {
5 | document.documentElement.classList.add(cls)
6 | }
7 | }
8 | restore('vue-docs-prefer-composition', 'prefer-composition', true)
9 | restore('vue-docs-prefer-sfc', 'prefer-sfc', true)
10 |
11 | window.__VUE_BANNER_ID__ = 'herodevs-vue2-nes'
12 | restore(`vue-docs-banner-${__VUE_BANNER_ID__}`, 'banner-dismissed')
13 | })()
14 |
--------------------------------------------------------------------------------
/.vitepress/textAdMdPlugin.ts:
--------------------------------------------------------------------------------
1 | import MarkdownIt from 'markdown-it'
2 |
3 | const excludedPages = [
4 | 'guide/introduction.md',
5 | // 'guide/quick-start.md',
6 | // 'guide/essentials/computed.md',
7 | // 'guide/essentials/conditional.md',
8 | // 'guide/essentials/list.md',
9 | // 'guide/essentials/event-handling.md',
10 | // 'guide/essentials/forms.md',
11 | // 'guide/components/registration.md',
12 | // 'guide/components/props.md',
13 | // 'guide/components/events.md',
14 | // 'guide/components/slots.md',
15 | // 'guide/built-ins/teleport.md',
16 | 'about/faq.md',
17 | 'about/team.md',
18 | 'about/releases.md',
19 | 'about/community-guide.md',
20 | 'about/coc.md',
21 | 'sponsor/index.md',
22 | 'translations/index.md'
23 | ]
24 |
25 | export const textAdPlugin = (md: MarkdownIt) => {
26 | md.renderer.rules.heading_close = (tokens, i, options, env, self) => {
27 | const relativePath = env.relativePath
28 | const renderedContent = self.renderToken(tokens, i, options)
29 |
30 | return excludedPages.includes(relativePath)
31 | ? renderedContent
32 | : renderedContent.replace(/<\/h1>/, ' ')
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/.vitepress/theme/components/ReplLoading.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
Repl is loading...
10 |
11 |
12 |
13 |
60 |
--------------------------------------------------------------------------------
/.vitepress/theme/components/SiteMap.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
{{ col.text }}
18 |
19 |
20 | {{ row.text }}
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
68 |
--------------------------------------------------------------------------------
/.vitepress/theme/components/SponsorsAside.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
26 |
--------------------------------------------------------------------------------
/.vitepress/theme/components/TextAd.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
18 |
19 |
20 |
54 |
--------------------------------------------------------------------------------
/.vitepress/theme/components/VueSchoolLink.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
21 |
60 |
--------------------------------------------------------------------------------
/.vitepress/theme/components/preferences.ts:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 | import { AugmentedHeader } from '../../headerMdPlugin'
3 |
4 | export const inBrowser = typeof window !== 'undefined'
5 | const get = (key: string, defaultValue = false): boolean =>
6 | inBrowser
7 | ? JSON.parse(localStorage.getItem(key) || String(defaultValue))
8 | : defaultValue
9 |
10 | export const preferCompositionKey = 'vue-docs-prefer-composition'
11 | export const preferComposition = ref(get(preferCompositionKey, true))
12 |
13 | export const preferSFCKey = 'vue-docs-prefer-sfc'
14 | export const preferSFC = ref(get(preferSFCKey, true))
15 |
16 | export function filterHeadersByPreference(h: AugmentedHeader) {
17 | return preferComposition.value ? !h.optionsOnly : !h.compositionOnly
18 | }
19 |
--------------------------------------------------------------------------------
/.vitepress/theme/components/sponsors.ts:
--------------------------------------------------------------------------------
1 | // shared data across instances so we load only once
2 |
3 | import { ref } from 'vue'
4 |
5 | declare global {
6 | const fathom: {
7 | trackGoal: (id: string, value: number) => any
8 | }
9 | }
10 |
11 | export interface Sponsor {
12 | url: string
13 | img: string
14 | name: string
15 | description?: string
16 | priority?: boolean
17 | }
18 |
19 | export interface SponsorData {
20 | special: Sponsor[]
21 | platinum: Sponsor[]
22 | platinum_china: Sponsor[]
23 | gold: Sponsor[]
24 | silver: Sponsor[]
25 | bronze: Sponsor[]
26 | }
27 |
28 | export const data = ref()
29 | export const pending = ref(false)
30 |
31 | export const base = `https://sponsors.vuejs.org`
32 |
33 | export const load = async () => {
34 | if (!pending.value) {
35 | pending.value = true
36 | data.value = await (await fetch(`${base}/data.json`)).json()
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/.vitepress/theme/index.ts:
--------------------------------------------------------------------------------
1 | import './styles/index.css'
2 | import { h, App } from 'vue'
3 | import { VPTheme } from '@vue/theme'
4 | import PreferenceSwitch from './components/PreferenceSwitch.vue'
5 | import {
6 | preferComposition,
7 | preferSFC,
8 | filterHeadersByPreference
9 | } from './components/preferences'
10 | import SponsorsAside from './components/SponsorsAside.vue'
11 | import VueSchoolLink from './components/VueSchoolLink.vue'
12 | import Banner from './components/Banner.vue'
13 | import VueMasteryBanner from './components/VueMasteryBanner.vue'
14 | // import TextAd from './components/TextAd.vue'
15 |
16 | export default Object.assign({}, VPTheme, {
17 | Layout: () => {
18 | // @ts-ignore
19 | return h(VPTheme.Layout, null, {
20 | // banner: () => h(Banner),
21 | banner: () => h(VueMasteryBanner),
22 | 'sidebar-top': () => h(PreferenceSwitch),
23 | 'aside-mid': () => h(SponsorsAside)
24 | })
25 | },
26 | enhanceApp({ app }: { app: App }) {
27 | app.provide('prefer-composition', preferComposition)
28 | app.provide('prefer-sfc', preferSFC)
29 | app.provide('filter-headers', filterHeadersByPreference)
30 | app.component('VueSchoolLink', VueSchoolLink)
31 | // app.component('TextAd', TextAd)
32 | }
33 | })
34 |
--------------------------------------------------------------------------------
/.vitepress/theme/styles/badges.css:
--------------------------------------------------------------------------------
1 | .vt-badge.wip:before {
2 | content: 'WIP';
3 | }
4 |
5 | .vt-badge.ts {
6 | background-color: #3178c6;
7 | }
8 | .vt-badge.ts:before {
9 | content: 'TS';
10 | }
11 |
12 | .vt-badge.dev-only,
13 | .vt-badge.experimental {
14 | color: var(--vt-c-text-light-1);
15 | background-color: var(--vt-c-yellow);
16 | }
17 |
18 | .vt-badge.dev-only:before {
19 | content: 'Dev only';
20 | }
21 |
22 | .vt-badge.experimental:before {
23 | content: 'Experimental';
24 | }
25 |
26 | .vt-badge[data-text]:before {
27 | content: attr(data-text);
28 | }
29 |
--------------------------------------------------------------------------------
/.vitepress/theme/styles/index.css:
--------------------------------------------------------------------------------
1 | @import "./pages.css";
2 | @import "./badges.css";
3 | @import "./options-boxes.css";
4 | @import "./inline-demo.css";
5 | @import "./utilities.css";
6 | @import "./style-guide.css";
7 |
8 | /* vitepress rc.31 migrated to shijiki and need this to apply code styles */
9 | .vp-code span {
10 | color: var(--shiki-dark, inherit);
11 | }
12 |
--------------------------------------------------------------------------------
/.vitepress/theme/styles/inline-demo.css:
--------------------------------------------------------------------------------
1 | .vt-doc a[href^="https://play.vuejs.org"]:before
2 | {
3 | content: '▶';
4 | width: 20px;
5 | height: 20px;
6 | display: inline-block;
7 | border-radius: 10px;
8 | vertical-align: middle;
9 | position: relative;
10 | top: -2px;
11 | color: var(--vt-c-green);
12 | border: 2px solid var(--vt-c-green);
13 | margin-right: 8px;
14 | margin-left: 4px;
15 | line-height: 15px;
16 | padding-left: 4.5px;
17 | font-size: 11px;
18 | }
19 |
20 | .demo {
21 | padding: 22px 24px;
22 | border-radius: 8px;
23 | box-shadow: var(--vt-shadow-2);
24 | margin-bottom: 1.2em;
25 | transition: background-color 0.5s ease;
26 | }
27 |
28 | .dark .demo {
29 | background-color: var(--vt-c-bg-soft);
30 | }
31 |
32 | .demo p {
33 | margin: 0;
34 | }
35 |
36 | .demo button {
37 | background-color: var(--vt-c-bg-mute);
38 | transition: background-color 0.5s;
39 | padding: 5px 12px;
40 | border: 1px solid var(--vt-c-divider);
41 | border-radius: 8px;
42 | font-size: 0.9em;
43 | font-weight: 600;
44 | }
45 |
46 | .demo button + button {
47 | margin-left: 1em;
48 | }
49 |
50 | .demo input,
51 | .demo textarea,
52 | .demo select {
53 | border: 1px solid var(--vt-c-divider);
54 | border-radius: 4px;
55 | padding: 0.2em 0.6em;
56 | margin-top: 10px;
57 | background: transparent;
58 | transition: background-color 0.5s;
59 | }
60 |
61 | .dark .demo select {
62 | background: var(--vt-c-bg-soft);
63 | }
64 |
65 | .dark .demo select option {
66 | background: transparent;
67 | }
68 |
69 | .demo input:not([type]):focus,
70 | .demo textarea:focus,
71 | .demo select:focus {
72 | outline: 1px solid blue;
73 | }
74 |
75 | .demo select {
76 | /* this was set by normalize.css */
77 | -webkit-appearance: listbox;
78 | }
79 |
80 | .demo label {
81 | margin: 0 1em 0 0.4em;
82 | }
83 |
84 | .demo select[multiple] {
85 | width: 100px;
86 | }
87 |
88 | .demo h1 {
89 | margin: 10px 0 0;
90 | }
91 |
--------------------------------------------------------------------------------
/.vitepress/theme/styles/options-boxes.css:
--------------------------------------------------------------------------------
1 | .next-steps {
2 | margin-top: 3rem;
3 | }
4 |
5 | .next-steps .vt-box {
6 | border: 1px solid var(--vt-c-bg-soft);
7 | }
8 |
9 | .next-steps .vt-box:hover {
10 | border-color: var(--vt-c-green-light);
11 | transition: border-color 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
12 | }
13 |
14 | .vt-doc .next-steps-link {
15 | font-size: 20px;
16 | line-height: 1.4;
17 | letter-spacing: -0.02em;
18 | margin-bottom: 0.75em;
19 | display: block;
20 | color: var(--vt-c-green);
21 | }
22 |
23 | .vt-doc .next-steps-caption {
24 | margin-bottom: 0;
25 | color: var(--vt-c-text-2);
26 | transition: color 0.5s;
27 | }
28 |
--------------------------------------------------------------------------------
/.vitepress/theme/styles/pages.css:
--------------------------------------------------------------------------------
1 | /* always show anchors on /api/ and /style-guide/ pages */
2 | .vt-doc.api h2 .header-anchor,
3 | .vt-doc.style-guide h2 .header-anchor {
4 | opacity: 1;
5 | }
6 |
7 | .vt-doc.sponsor h3 {
8 | text-align: center;
9 | padding-bottom: 1em;
10 | border-bottom: 1px solid var(--vt-c-divider-light);
11 | }
12 |
13 | .vt-doc.sponsor h3 .header-anchor {
14 | display: none;
15 | }
16 |
--------------------------------------------------------------------------------
/.vitepress/theme/styles/style-guide.css:
--------------------------------------------------------------------------------
1 | .style-example {
2 | border-radius: 8px 8px 12px 12px;
3 | margin: 1.6em 0;
4 | padding: 1.6em 1.6em 0.1px;
5 | position: relative;
6 | border: 1px solid transparent;
7 | transition: background-color 0.25s ease, border-color 0.25s ease;
8 | }
9 |
10 | .vt-doc .style-example h3 {
11 | margin: 0;
12 | font-size: 1.1em;
13 | }
14 |
15 | .style-example-bad {
16 | background: #f7e8e8;
17 | }
18 | .dark .style-example-bad {
19 | background: transparent;
20 | border-color: var(--vt-c-red);
21 | }
22 |
23 | .style-example-bad h3 {
24 | color: var(--vt-c-red);
25 | }
26 |
27 | .style-example-good {
28 | background: #ecfaf7;
29 | }
30 | .dark .style-example-good {
31 | background: transparent;
32 | border-color: var(--vt-c-green);
33 | }
34 |
35 | .style-example-good h3 {
36 | color: var(--vt-c-green);
37 | }
38 |
39 | .details summary {
40 | font-weight: bold !important;
41 | }
42 |
43 | .style-verb {
44 | font-size: 0.6em;
45 | display: inline-block;
46 | border-radius: 6px;
47 | font-size: 0.65em;
48 | line-height: 1;
49 | font-weight: 600;
50 | padding: 0.35em 0.4em 0.3em;
51 | position: relative;
52 | top: -0.15em;
53 | margin-right: 0.5em;
54 | color: var(--vt-c-bg);
55 | transition: color 0.5s;
56 | background-color: var(--vt-c-brand);
57 | }
58 |
59 | .style-verb.avoid {
60 | background-color: var(--vt-c-red);
61 | }
62 |
--------------------------------------------------------------------------------
/.vitepress/theme/styles/utilities.css:
--------------------------------------------------------------------------------
1 | .nowrap {
2 | white-space: nowrap;
3 | }
4 |
5 | .sr-only {
6 | position: absolute;
7 | width: 1px;
8 | height: 1px;
9 | padding: 0;
10 | margin: -1px;
11 | overflow: hidden;
12 | clip: rect(0, 0, 0, 0);
13 | border: 0;
14 | }
15 |
--------------------------------------------------------------------------------
/.vitepress/theme/styles/vue-mastery.css:
--------------------------------------------------------------------------------
1 | .vue-mastery-link {
2 | background-color: var(--vt-c-bg-soft);
3 | border-radius: 8px;
4 | padding: 8px 16px 8px 8px;
5 | transition: color 0.5s, background-color 0.5s;
6 | }
7 |
8 | .vue-mastery-link a {
9 | display: flex;
10 | align-items: center;
11 | }
12 |
13 | .vue-mastery-link .banner {
14 | background-color: var(--vt-c-white-soft);
15 | border-radius: 4px;
16 | width: 96px;
17 | height: 56px;
18 | object-fit: cover;
19 | }
20 |
21 | .vue-mastery-link .description {
22 | flex: 1;
23 | font-weight: 500;
24 | font-size: 14px;
25 | line-height: 20px;
26 | color: var(--vt-c-text-1);
27 | margin: 0 0 0 16px;
28 | transition: color 0.5s;
29 | }
30 |
31 | .vue-mastery-link .description span {
32 | color: var(--vt-c-brand);
33 | }
34 |
35 | .vue-mastery-link .logo-wrapper {
36 | position: relative;
37 | width: 48px;
38 | height: 48px;
39 | border-radius: 50%;
40 | background-color: var(--vt-c-white);
41 | display: flex;
42 | justify-content: center;
43 | align-items: center;
44 | }
45 |
46 | .vue-mastery-link .logo-wrapper img {
47 | width: 25px;
48 | object-fit: contain;
49 | }
50 |
51 | @media (max-width: 576px) {
52 | .vue-mastery-link .banner {
53 | width: 56px;
54 | }
55 |
56 | .vue-mastery-link .description {
57 | font-size: 12px;
58 | line-height: 18px;
59 | }
60 | .vue-mastery-link .logo-wrapper {
61 | position: relative;
62 | width: 32px;
63 | height: 32px;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 vuejs
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 |
--------------------------------------------------------------------------------
/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module '@vue/theme/config' {
4 | import { UserConfig } from 'vitepress'
5 | const config: () => Promise
6 | export default config
7 | }
8 |
9 | declare module '@vue/theme/highlight' {
10 | const createHighlighter: () => Promise<(input: string) => string>
11 | export default createHighlighter
12 | }
13 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build.environment]
2 | NODE_VERSION = "16"
3 |
4 | [build]
5 | publish = ".vitepress/dist"
6 | command = "pnpm run build"
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "engines": {
3 | "node": ">=14.0.0"
4 | },
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vitepress",
8 | "build": "vitepress build",
9 | "preview": "vitepress preview",
10 | "preinstall": "npx only-allow pnpm"
11 | },
12 | "dependencies": {
13 | "@vue/repl": "^3.0.0",
14 | "@vue/theme": "^2.2.5",
15 | "dynamics.js": "^1.1.5",
16 | "gsap": "^3.9.0",
17 | "vitepress": "1.0.0-rc.33",
18 | "vue": "^3.4.0-rc.3"
19 | },
20 | "devDependencies": {
21 | "@types/markdown-it": "^12.2.3",
22 | "@types/node": "^20.10.1",
23 | "terser": "^5.14.2"
24 | },
25 | "pnpm": {
26 | "overrides": {
27 | "@vitejs/plugin-vue": "5.0.0-beta.1"
28 | },
29 | "peerDependencyRules": {
30 | "ignoreMissing": [
31 | "@algolia/client-search",
32 | "react",
33 | "react-dom",
34 | "@types/react",
35 | "search-insights"
36 | ]
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/about/images/ben-hong.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/about/images/ben-hong.jpeg
--------------------------------------------------------------------------------
/src/about/images/evan-you.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/about/images/evan-you.jpeg
--------------------------------------------------------------------------------
/src/about/team.md:
--------------------------------------------------------------------------------
1 | ---
2 | page: true
3 | title: Meet the Team
4 | ---
5 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/about/team/Member.ts:
--------------------------------------------------------------------------------
1 | export interface Member {
2 | name: string
3 | avatarPic?: string
4 | title: string
5 | company?: string
6 | companyLink?: string
7 | projects: Link[]
8 | location: string
9 | languages: string[]
10 | website?: Link
11 | socials: Socials
12 | sponsor?: boolean | string
13 | reposPersonal?: string[]
14 | }
15 |
16 | export interface Link {
17 | label: string
18 | url: string
19 | }
20 |
21 | export interface Socials {
22 | github: string
23 | twitter?: string
24 | linkedin?: string
25 | codepen?: string
26 | }
27 |
--------------------------------------------------------------------------------
/src/about/team/TeamHero.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
76 |
--------------------------------------------------------------------------------
/src/api/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: API Reference
3 | sidebar: false
4 | page: true
5 | footer: false
6 | ---
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/ecosystem/newsletters.md:
--------------------------------------------------------------------------------
1 | # Інформаційні бюлетені спільноти {#community-newsletters}
2 |
3 | Є багато чудових інформаційних бюлетенів / блогів, присвячених Vue, від спільноти, які повідомляють вам останні новини та події в екосистемі Vue. Ось неповний список активних, на які ми натрапили:
4 |
5 | - [Vue.js Feed](https://vuejsfeed.com/)
6 | - [Michael Thiessen](https://michaelnthiessen.com/newsletter)
7 | - [Jakub Andrzejewski](https://dev.to/jacobandrewsky)
8 | - [Weekly Vue News](https://weekly-vue.news/)
9 | - [Vue.js Developers Newsletter](https://vuejsdevelopers.com/newsletter/)
10 | - [VueDose](https://vuedose.tips/articles#newsletter)
11 |
12 | Якщо ви знаєте чудовий, якого ще немає, надішліть запит на отримання за посиланням нижче!
13 |
--------------------------------------------------------------------------------
/src/ecosystem/themes.md:
--------------------------------------------------------------------------------
1 | ---
2 | page: true
3 | ---
4 |
5 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/ecosystem/themes/ThemeContact.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
50 |
--------------------------------------------------------------------------------
/src/ecosystem/themes/ThemeHero.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
56 |
--------------------------------------------------------------------------------
/src/ecosystem/themes/ThemeList.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
14 |
15 |
16 |
42 |
--------------------------------------------------------------------------------
/src/ecosystem/themes/ThemePage.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 | Теми
11 | Перегляньте теми, комплекти інтерфейсу користувача та плагіни. Ви можете побачити, як наші партнери створюють реальну програму за допомогою Vue.
12 |
13 |
14 |
15 |
16 |
17 | Хочете розмістити тут свої теми? Зв'яжіться з нами!
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/ecosystem/themes/ThemeProduct.vue:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
{{ product.name }}
19 |
{{ product.description }}
20 |
21 |
22 |
23 |
${{ product.price }}
24 |
FREE
25 |
26 |
27 |
28 |
29 |
30 |
31 |
99 |
--------------------------------------------------------------------------------
/src/examples/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | page: true
3 | title: Examples
4 | aside: false
5 | footer: false
6 | outline: false
7 | ---
8 |
9 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/examples/src/attribute-bindings/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const message = ref('Привіт, світе!')
6 | const isRed = ref(true)
7 | const color = ref('green')
8 |
9 | function toggleRed() {
10 | isRed.value = !isRed.value
11 | }
12 |
13 | function toggleColor() {
14 | color.value = color.value === 'green' ? 'blue' : 'green'
15 | }
16 |
17 | return {
18 | message,
19 | isRed,
20 | color,
21 | toggleRed,
22 | toggleColor
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/examples/src/attribute-bindings/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | message: 'Привіт, світе!',
5 | isRed: true,
6 | color: 'green'
7 | }
8 | },
9 | methods: {
10 | toggleRed() {
11 | this.isRed = !this.isRed
12 | },
13 | toggleColor() {
14 | this.color = this.color === 'green' ? 'blue' : 'green'
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/examples/src/attribute-bindings/App/style.css:
--------------------------------------------------------------------------------
1 | .red {
2 | color: red;
3 | }
--------------------------------------------------------------------------------
/src/examples/src/attribute-bindings/App/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Наведіть на мене вказівник миші на кілька секунд, щоб побачити мій
4 | динамічно пов'язаний заголовок!
5 |
6 |
7 |
8 |
12 |
13 | Це має бути червоним... але натисніть мене, щоб перемкнути це.
14 |
15 |
16 |
17 |
18 | Це має бути зеленим і має перемикатися між зеленим і синім після
19 | натискання.
20 |
21 |
--------------------------------------------------------------------------------
/src/examples/src/attribute-bindings/description.txt:
--------------------------------------------------------------------------------
1 | Тут ми прив'язуємо реактивно атрибути / властивості елемента до стану.
2 | Синтаксис :title є скороченням від v-bind:title.
3 |
--------------------------------------------------------------------------------
/src/examples/src/cells/App/composition.js:
--------------------------------------------------------------------------------
1 | import Cell from './Cell.vue'
2 | import { cells } from './store.js'
3 |
4 | export default {
5 | components: {
6 | Cell
7 | },
8 | setup() {
9 | const cols = cells.map((_, i) => String.fromCharCode(65 + i))
10 | return {
11 | cols,
12 | cells
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/examples/src/cells/App/options.js:
--------------------------------------------------------------------------------
1 | import Cell from './Cell.vue'
2 | import { cells } from './store.js'
3 |
4 | export default {
5 | components: {
6 | Cell
7 | },
8 | data() {
9 | return {
10 | cols: cells.map((_, i) => String.fromCharCode(65 + i)),
11 | cells
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/examples/src/cells/App/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | }
4 |
5 | table {
6 | border-collapse: collapse;
7 | table-layout: fixed;
8 | width: 100%;
9 | }
10 |
11 | th {
12 | background-color: #eee;
13 | }
14 |
15 | tr:first-of-type th {
16 | width: 100px;
17 | }
18 |
19 | tr:first-of-type th:first-of-type {
20 | width: 25px;
21 | }
22 |
23 | td {
24 | border: 1px solid #ccc;
25 | height: 1.5em;
26 | overflow: hidden;
27 | }
28 |
--------------------------------------------------------------------------------
/src/examples/src/cells/App/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ c }}
6 |
7 |
8 |
9 |
10 | {{ i - 1 }}
11 |
12 | |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/examples/src/cells/Cell/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 | import { cells, evalCell } from './store.js'
3 |
4 | export default {
5 | props: {
6 | c: Number,
7 | r: Number
8 | },
9 | setup(props) {
10 | const editing = ref(false)
11 |
12 | function update(e) {
13 | editing.value = false
14 | cells[props.c][props.r] = e.target.value.trim()
15 | }
16 |
17 | return {
18 | cells,
19 | editing,
20 | evalCell,
21 | update
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/examples/src/cells/Cell/options.js:
--------------------------------------------------------------------------------
1 | import { cells, evalCell } from './store.js'
2 |
3 | export default {
4 | props: {
5 | c: Number,
6 | r: Number
7 | },
8 | data() {
9 | return {
10 | editing: false,
11 | cells
12 | }
13 | },
14 | methods: {
15 | evalCell,
16 | update(e) {
17 | this.editing = false
18 | cells[this.c][this.r] = e.target.value.trim()
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/examples/src/cells/Cell/style.css:
--------------------------------------------------------------------------------
1 | .cell, .cell input {
2 | height: 1.5em;
3 | line-height: 1.5;
4 | font-size: 15px;
5 | }
6 |
7 | .cell span {
8 | padding: 0 6px;
9 | }
10 |
11 | .cell input {
12 | width: 100%;
13 | box-sizing: border-box;
14 | }
--------------------------------------------------------------------------------
/src/examples/src/cells/Cell/template.html:
--------------------------------------------------------------------------------
1 |
2 | el.focus()"
8 | >
9 | {{ evalCell(cells[c][r]) }}
10 |
11 |
--------------------------------------------------------------------------------
/src/examples/src/cells/description.txt:
--------------------------------------------------------------------------------
1 | https://eugenkiss.github.io/7guis/tasks/#cells
--------------------------------------------------------------------------------
/src/examples/src/cells/store.js:
--------------------------------------------------------------------------------
1 | import { reactive } from 'vue'
2 |
3 | const COLS = 5
4 | const ROWS = 20
5 |
6 | export const cells = reactive(
7 | Array.from(Array(COLS).keys()).map((i) =>
8 | Array.from(Array(ROWS).keys()).map((i) => '')
9 | )
10 | )
11 |
12 | // adapted from https://codesandbox.io/s/jotai-7guis-task7-cells-mzoit?file=/src/atoms.ts
13 | // by @dai-shi
14 | export function evalCell(exp) {
15 | if (!exp.startsWith('=')) {
16 | return exp
17 | }
18 |
19 | // = A1 + B2 ---> get(0,1) + get(1,2)
20 | exp = exp
21 | .slice(1)
22 | .replace(
23 | /\b([A-Z])(\d{1,2})\b/g,
24 | (_, c, r) => `get(${c.charCodeAt(0) - 65},${r})`
25 | )
26 |
27 | try {
28 | return new Function('get', `return ${exp}`)(getCellValue)
29 | } catch (e) {
30 | return `#ERROR ${e}`
31 | }
32 | }
33 |
34 | function getCellValue(c, r) {
35 | const val = evalCell(cells[c][r])
36 | const num = Number(val)
37 | return Number.isFinite(num) ? num : val
38 | }
39 |
--------------------------------------------------------------------------------
/src/examples/src/circle-drawer/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref, shallowReactive, toRaw } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const history = shallowReactive([[]])
6 | const index = ref(0)
7 | const circles = ref([])
8 | const selected = ref()
9 | const adjusting = ref(false)
10 |
11 | function onClick({ clientX: x, clientY: y }) {
12 | if (adjusting.value) {
13 | adjusting.value = false
14 | selected.value = null
15 | push()
16 | return
17 | }
18 |
19 | selected.value = [...circles.value].reverse().find(({ cx, cy, r }) => {
20 | const dx = cx - x
21 | const dy = cy - y
22 | return Math.sqrt(dx * dx + dy * dy) <= r
23 | })
24 |
25 | if (!selected.value) {
26 | circles.value.push({
27 | cx: x,
28 | cy: y,
29 | r: 50
30 | })
31 | push()
32 | }
33 | }
34 |
35 | function adjust(circle) {
36 | selected.value = circle
37 | adjusting.value = true
38 | }
39 |
40 | function push() {
41 | history.length = ++index.value
42 | history.push(clone(circles.value))
43 | console.log(toRaw(history))
44 | }
45 |
46 | function undo() {
47 | circles.value = clone(history[--index.value])
48 | }
49 |
50 | function redo() {
51 | circles.value = clone(history[++index.value])
52 | }
53 |
54 | function clone(circles) {
55 | return circles.map((c) => ({ ...c }))
56 | }
57 |
58 | return {
59 | history,
60 | index,
61 | circles,
62 | selected,
63 | adjusting,
64 | onClick,
65 | adjust,
66 | undo,
67 | redo
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/examples/src/circle-drawer/App/options.js:
--------------------------------------------------------------------------------
1 | function clone(circles) {
2 | return circles.map((c) => ({ ...c }))
3 | }
4 |
5 | export default {
6 | data() {
7 | return {
8 | history: [[]],
9 | index: 0,
10 | circles: [],
11 | selected: null,
12 | adjusting: false
13 | }
14 | },
15 | methods: {
16 | onClick({ clientX: x, clientY: y }) {
17 | if (this.adjusting) {
18 | this.adjusting = false
19 | this.selected = null
20 | this.push()
21 | return
22 | }
23 |
24 | this.selected = [...this.circles].reverse().find(({ cx, cy, r }) => {
25 | const dx = cx - x
26 | const dy = cy - y
27 | return Math.sqrt(dx * dx + dy * dy) <= r
28 | })
29 |
30 | if (!this.selected) {
31 | this.circles.push({
32 | cx: x,
33 | cy: y,
34 | r: 50
35 | })
36 | this.push()
37 | }
38 | },
39 |
40 | adjust(circle) {
41 | this.selected = circle
42 | this.adjusting = true
43 | },
44 |
45 | push() {
46 | this.history.length = ++this.index
47 | this.history.push(clone(this.circles))
48 | },
49 |
50 | undo() {
51 | this.circles = clone(this.history[--this.index])
52 | },
53 |
54 | redo() {
55 | this.circles = clone(this.history[++this.index])
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/examples/src/circle-drawer/App/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | overflow: hidden;
4 | }
5 |
6 | svg {
7 | width: 100vw;
8 | height: 100vh;
9 | background-color: #eee;
10 | }
11 |
12 | circle {
13 | stroke: #000;
14 | }
15 |
16 | .controls {
17 | position: fixed;
18 | top: 10px;
19 | left: 0;
20 | right: 0;
21 | text-align: center;
22 | }
23 |
24 | .controls button + button {
25 | margin-left: 6px;
26 | }
27 |
28 | .dialog {
29 | position: fixed;
30 | top: calc(50% - 50px);
31 | left: calc(50% - 175px);
32 | background: #fff;
33 | width: 350px;
34 | height: 100px;
35 | padding: 5px 20px;
36 | box-sizing: border-box;
37 | border-radius: 4px;
38 | text-align: center;
39 | box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.25);
40 | }
41 |
42 | .dialog input {
43 | display: block;
44 | width: 200px;
45 | margin: 0px auto;
46 | }
47 |
48 | .tip {
49 | text-align: center;
50 | padding: 0 50px;
51 | color: #bbb;
52 | }
--------------------------------------------------------------------------------
/src/examples/src/circle-drawer/App/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Клікніть на полотні, щоб намалювати коло. Клікніть на колі, щоб виділити його.
5 | Клікніть правою кнопкою миші на полотні, щоб змінити радіус вибраного кола.
6 |
7 |
8 |
17 |
18 |
19 |
20 | Відмінити
21 | Повернути
22 |
23 |
24 |
25 |
Відрегулюйте радіус кола на ({{ selected.cx }}, {{ selected.cy }})
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/examples/src/circle-drawer/description.txt:
--------------------------------------------------------------------------------
1 | https://eugenkiss.github.io/7guis/tasks/#circle
--------------------------------------------------------------------------------
/src/examples/src/conditionals-and-loops/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const show = ref(true)
6 | const list = ref([1, 2, 3])
7 |
8 | return {
9 | show,
10 | list
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/examples/src/conditionals-and-loops/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | show: true,
5 | list: [1, 2, 3]
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/src/examples/src/conditionals-and-loops/App/template.html:
--------------------------------------------------------------------------------
1 | Сховати/показати список
2 | Додати число
3 | Забрати число
4 | Зробити список зворотнім
5 |
6 |
9 | Список не порожній, але прихований.
10 | Список порожній.
11 |
--------------------------------------------------------------------------------
/src/examples/src/conditionals-and-loops/description.txt:
--------------------------------------------------------------------------------
1 | Ми можемо відтворювати вміст умовно або в циклі за допомогою директив v-if і v-for.
2 |
--------------------------------------------------------------------------------
/src/examples/src/counter/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const count = ref(0)
6 |
7 | return {
8 | count
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/examples/src/counter/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | count: 0
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/src/examples/src/counter/App/template.html:
--------------------------------------------------------------------------------
1 | {{ count }}
2 | Рахунок
3 |
--------------------------------------------------------------------------------
/src/examples/src/counter/description.txt:
--------------------------------------------------------------------------------
1 | https://eugenkiss.github.io/7guis/tasks/#counter
--------------------------------------------------------------------------------
/src/examples/src/crud/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref, reactive, computed, watch } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const names = reactive(['Шевченко, Ірина', 'Матрунчик, Сергій', 'Федоренко, Роман'])
6 | const selected = ref('')
7 | const prefix = ref('')
8 | const first = ref('')
9 | const last = ref('')
10 |
11 | const filteredNames = computed(() =>
12 | names.filter((n) =>
13 | n.toLowerCase().startsWith(prefix.value.toLowerCase())
14 | )
15 | )
16 |
17 | watch(selected, (name) => {
18 | ;[last.value, first.value] = name.split(', ')
19 | })
20 |
21 | function create() {
22 | if (hasValidInput()) {
23 | const fullName = `${last.value}, ${first.value}`
24 | if (!names.includes(fullName)) {
25 | names.push(fullName)
26 | first.value = last.value = ''
27 | }
28 | }
29 | }
30 |
31 | function update() {
32 | if (hasValidInput() && selected.value) {
33 | const i = names.indexOf(selected.value)
34 | names[i] = selected.value = `${last.value}, ${first.value}`
35 | }
36 | }
37 |
38 | function del() {
39 | if (selected.value) {
40 | const i = names.indexOf(selected.value)
41 | names.splice(i, 1)
42 | selected.value = first.value = last.value = ''
43 | }
44 | }
45 |
46 | function hasValidInput() {
47 | return first.value.trim() && last.value.trim()
48 | }
49 |
50 | return {
51 | filteredNames,
52 | selected,
53 | prefix,
54 | first,
55 | last,
56 | create,
57 | update,
58 | del
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/examples/src/crud/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | names: ['Вознюк, Володимир', 'Матрунчик, Сергій', 'Федоренко, Роман'],
5 | selected: '',
6 | prefix: '',
7 | first: '',
8 | last: ''
9 | }
10 | },
11 | computed: {
12 | filteredNames() {
13 | return this.names.filter((n) =>
14 | n.toLowerCase().startsWith(this.prefix.toLowerCase())
15 | )
16 | }
17 | },
18 | watch: {
19 | selected(name) {
20 | ;[this.last, this.first] = name.split(', ')
21 | }
22 | },
23 | methods: {
24 | create() {
25 | if (this.hasValidInput()) {
26 | const fullName = `${this.last}, ${this.first}`
27 | if (!this.names.includes(fullName)) {
28 | this.names.push(fullName)
29 | this.first = this.last = ''
30 | }
31 | }
32 | },
33 | update() {
34 | if (this.hasValidInput() && this.selected) {
35 | const i = this.names.indexOf(this.selected)
36 | this.names[i] = this.selected = `${this.last}, ${this.first}`
37 | }
38 | },
39 | del() {
40 | if (this.selected) {
41 | const i = this.names.indexOf(this.selected)
42 | this.names.splice(i, 1)
43 | this.selected = this.first = this.last = ''
44 | }
45 | },
46 | hasValidInput() {
47 | return this.first.trim() && this.last.trim()
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/examples/src/crud/App/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | font-size: inherit;
3 | }
4 |
5 | input {
6 | display: block;
7 | margin-bottom: 10px;
8 | }
9 |
10 | select {
11 | float: left;
12 | margin: 0 1em 1em 0;
13 | width: 14em;
14 | }
15 |
16 | .buttons {
17 | clear: both;
18 | }
19 |
20 | button + button {
21 | margin-left: 5px;
22 | }
23 |
--------------------------------------------------------------------------------
/src/examples/src/crud/App/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ name }}
5 |
6 |
7 | Ім'я:
8 | Прізвище:
9 |
10 |
11 | Створити
12 | Оновити
13 | Видалити
14 |
15 |
--------------------------------------------------------------------------------
/src/examples/src/crud/description.txt:
--------------------------------------------------------------------------------
1 | https://eugenkiss.github.io/7guis/tasks/#crud
--------------------------------------------------------------------------------
/src/examples/src/fetching-data/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref, watchEffect } from 'vue'
2 |
3 | const API_URL = `https://api.github.com/repos/vuejs/core/commits?per_page=3&sha=`
4 | const branches = ['main', 'v2-compat']
5 |
6 | export default {
7 | setup() {
8 | const currentBranch = ref(branches[0])
9 | const commits = ref(null)
10 |
11 | watchEffect(async () => {
12 | // цей метод буде запускатися негайно і потім
13 | // перезапускатися, коли змінюється currentBranch.value
14 | const url = `${API_URL}${currentBranch.value}`
15 | commits.value = await (await fetch(url)).json()
16 | })
17 |
18 | function truncate(v) {
19 | const newline = v.indexOf('\n')
20 | return newline > 0 ? v.slice(0, newline) : v
21 | }
22 |
23 | function formatDate(v) {
24 | return v.replace(/T|Z/g, ' ')
25 | }
26 |
27 | return {
28 | branches,
29 | currentBranch,
30 | commits,
31 | truncate,
32 | formatDate
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/examples/src/fetching-data/App/options.js:
--------------------------------------------------------------------------------
1 | const API_URL = `https://api.github.com/repos/vuejs/core/commits?per_page=3&sha=`
2 |
3 | export default {
4 | data: () => ({
5 | branches: ['main', 'v2-compat'],
6 | currentBranch: 'main',
7 | commits: null
8 | }),
9 |
10 | created() {
11 | // отримання даних при ініціалізації
12 | this.fetchData()
13 | },
14 |
15 | watch: {
16 | // отримання дані щоразу, коли змінюється currentBranch
17 | currentBranch: 'fetchData'
18 | },
19 |
20 | methods: {
21 | async fetchData() {
22 | const url = `${API_URL}${this.currentBranch}`
23 | this.commits = await (await fetch(url)).json()
24 | },
25 | truncate(v) {
26 | const newline = v.indexOf('\n')
27 | return newline > 0 ? v.slice(0, newline) : v
28 | },
29 | formatDate(v) {
30 | return v.replace(/T|Z/g, ' ')
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/examples/src/fetching-data/App/style.css:
--------------------------------------------------------------------------------
1 | a {
2 | text-decoration: none;
3 | color: #42b883;
4 | }
5 | li {
6 | line-height: 1.5em;
7 | margin-bottom: 20px;
8 | }
9 | .author,
10 | .date {
11 | font-weight: bold;
12 | }
13 |
--------------------------------------------------------------------------------
/src/examples/src/fetching-data/App/template.html:
--------------------------------------------------------------------------------
1 | Останні комміти ядра Vue
2 |
3 |
8 | {{ branch }}
9 |
10 | vuejs/vue@{{ currentBranch }}
11 |
21 |
--------------------------------------------------------------------------------
/src/examples/src/fetching-data/description.txt:
--------------------------------------------------------------------------------
1 | Цей приклад отримує останні дані про комміти Vue.js з API GitHub і відображає їх у вигляді списку.
2 | Ви можете переключати дані між двома гілками.
3 |
--------------------------------------------------------------------------------
/src/examples/src/flight-booker/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref, computed } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const flightType = ref('one-way flight')
6 | const departureDate = ref(dateToString(new Date()))
7 | const returnDate = ref(departureDate.value)
8 |
9 | const isReturn = computed(() => flightType.value === 'return flight')
10 |
11 | const canBook = computed(
12 | () =>
13 | !isReturn.value ||
14 | stringToDate(returnDate.value) > stringToDate(departureDate.value)
15 | )
16 |
17 | function book() {
18 | alert(
19 | isReturn.value
20 | ? `Ви забронювали рейс з вильотом ${departureDate.value} та поверненням ${returnDate.value}.`
21 | : `Ви забронювали рейс в один бік на ${departureDate.value}.`
22 | )
23 | }
24 |
25 | function stringToDate(str) {
26 | const [y, m, d] = str.split('-')
27 | return new Date(+y, m - 1, +d)
28 | }
29 |
30 | function dateToString(date) {
31 | return (
32 | date.getFullYear() +
33 | '-' +
34 | pad(date.getMonth() + 1) +
35 | '-' +
36 | pad(date.getDate())
37 | )
38 | }
39 |
40 | function pad(n, s = String(n)) {
41 | return s.length < 2 ? `0${s}` : s
42 | }
43 |
44 | return {
45 | flightType,
46 | departureDate,
47 | returnDate,
48 | isReturn,
49 | canBook,
50 | book
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/examples/src/flight-booker/App/options.js:
--------------------------------------------------------------------------------
1 | function stringToDate(str) {
2 | const [y, m, d] = str.split('-')
3 | return new Date(+y, m - 1, +d)
4 | }
5 |
6 | function dateToString(date) {
7 | return (
8 | date.getFullYear() +
9 | '-' +
10 | pad(date.getMonth() + 1) +
11 | '-' +
12 | pad(date.getDate())
13 | )
14 | }
15 |
16 | function pad(n, s = String(n)) {
17 | return s.length < 2 ? `0${s}` : s
18 | }
19 |
20 | export default {
21 | data() {
22 | return {
23 | flightType: 'one-way flight',
24 | departureDate: dateToString(new Date()),
25 | returnDate: dateToString(new Date())
26 | }
27 | },
28 | computed: {
29 | isReturn() {
30 | return this.flightType === 'return flight'
31 | },
32 | canBook() {
33 | return (
34 | !this.isReturn ||
35 | stringToDate(this.returnDate) > stringToDate(this.departureDate)
36 | )
37 | }
38 | },
39 | methods: {
40 | book() {
41 | alert(
42 | this.isReturn
43 | ? `You have booked a return flight leaving on ${this.departureDate} and returning on ${this.returnDate}.`
44 | : `You have booked a one-way flight leaving on ${this.departureDate}.`
45 | )
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/examples/src/flight-booker/App/style.css:
--------------------------------------------------------------------------------
1 | select,
2 | input,
3 | button {
4 | display: block;
5 | margin: 0.5em 0;
6 | font-size: 15px;
7 | }
8 |
9 | input[disabled] {
10 | color: #999;
11 | }
12 |
13 | p {
14 | color: red;
15 | }
--------------------------------------------------------------------------------
/src/examples/src/flight-booker/App/template.html:
--------------------------------------------------------------------------------
1 |
2 | В один бік
3 | В обидва боки
4 |
5 |
6 |
7 |
8 |
9 | Забронювати
10 |
11 | {{ canBook ? '' : 'Дата повернення повинна бути після дати вильоту..' }}
12 |
--------------------------------------------------------------------------------
/src/examples/src/flight-booker/description.txt:
--------------------------------------------------------------------------------
1 | https://eugenkiss.github.io/7guis/tasks/#flight
--------------------------------------------------------------------------------
/src/examples/src/form-bindings/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const text = ref('Редагувати мене')
6 | const checked = ref(true)
7 | const checkedNames = ref(['Петро'])
8 | const picked = ref('Один')
9 | const selected = ref('А')
10 | const multiSelected = ref(['А'])
11 |
12 | return {
13 | text,
14 | checked,
15 | checkedNames,
16 | picked,
17 | selected,
18 | multiSelected
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/examples/src/form-bindings/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | text: 'Редагувати мене',
5 | checked: true,
6 | checkedNames: ['Петро'],
7 | picked: 'Один',
8 | selected: 'А',
9 | multiSelected: ['А']
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/examples/src/form-bindings/App/template.html:
--------------------------------------------------------------------------------
1 | Введення тексту
2 | {{ text }}
3 |
4 | Прапорець
5 |
6 | Відмічено: {{ checked }}
7 |
8 |
12 | Прапорці декількох значень
13 |
14 | Петро
15 |
16 | Марічка
17 |
18 | Ірина
19 | Відмічені імена:
{{ checkedNames }}
20 |
21 | Радіобокс
22 |
23 | Один
24 |
25 |
26 | Два
27 |
28 | Обрано: {{ picked }}
29 |
30 | Вибирання
31 |
32 | Виберіть один, будь ласка
33 | А
34 | Б
35 | В
36 |
37 | Обрано: {{ selected }}
38 |
39 | Вибирання декількох значень
40 |
41 | А
42 | Б
43 | В
44 |
45 | Обрано: {{ multiSelected }}
46 |
--------------------------------------------------------------------------------
/src/examples/src/form-bindings/description.txt:
--------------------------------------------------------------------------------
1 | Ми можемо створювати двосторонні зв'язки між вхідними даними стану та форми за допомогою директиви v-model.
2 |
--------------------------------------------------------------------------------
/src/examples/src/grid/App/composition.js:
--------------------------------------------------------------------------------
1 | import DemoGrid from './Grid.vue'
2 | import { ref } from 'vue'
3 |
4 | export default {
5 | components: {
6 | DemoGrid
7 | },
8 | setup() {
9 | const searchQuery = ref('')
10 | const gridColumns = ['імя', 'сила']
11 | const gridData = [
12 | { 'імя': 'Чак Норріс', 'сила': Infinity },
13 | { 'імя': 'Брюс Лі', 'сила': 9000 },
14 | { 'імя': 'Джекі Чан', 'сила': 7000 },
15 | { 'імя': 'Джет Лі', 'сила': 8000 }
16 | ]
17 |
18 | return {
19 | searchQuery,
20 | gridColumns,
21 | gridData
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/examples/src/grid/App/options.js:
--------------------------------------------------------------------------------
1 | import DemoGrid from './Grid.vue'
2 |
3 | export default {
4 | components: {
5 | DemoGrid
6 | },
7 | data: () => ({
8 | searchQuery: '',
9 | gridColumns: ['імя', 'сила'],
10 | gridData: [
11 | { 'імя': 'Чак Норріс', 'сила': Infinity },
12 | { 'імя': 'Брюс Лі', 'сила': 9000 },
13 | { 'імя': 'Джекі Чан', 'сила': 7000 },
14 | { 'імя': 'Джет Лі', 'сила': 8000 }
15 | ]
16 | })
17 | }
18 |
--------------------------------------------------------------------------------
/src/examples/src/grid/App/template.html:
--------------------------------------------------------------------------------
1 |
4 |
8 |
9 |
--------------------------------------------------------------------------------
/src/examples/src/grid/Grid/composition.js:
--------------------------------------------------------------------------------
1 | import { ref, computed } from 'vue'
2 |
3 | export default {
4 | props: {
5 | data: Array,
6 | columns: Array,
7 | filterKey: String
8 | },
9 | setup(props) {
10 | const sortKey = ref('')
11 | const sortOrders = ref(
12 | props.columns.reduce((o, key) => ((o[key] = 1), o), {})
13 | )
14 |
15 | const filteredData = computed(() => {
16 | let { data, filterKey } = props
17 | if (filterKey) {
18 | filterKey = filterKey.toLowerCase()
19 | data = data.filter((row) => {
20 | return Object.keys(row).some((key) => {
21 | return String(row[key]).toLowerCase().indexOf(filterKey) > -1
22 | })
23 | })
24 | }
25 | const key = sortKey.value
26 | if (key) {
27 | const order = sortOrders.value[key]
28 | data = data.slice().sort((a, b) => {
29 | a = a[key]
30 | b = b[key]
31 | return (a === b ? 0 : a > b ? 1 : -1) * order
32 | })
33 | }
34 | return data
35 | })
36 |
37 | function sortBy(key) {
38 | sortKey.value = key
39 | sortOrders.value[key] *= -1
40 | }
41 |
42 | function capitalize(str) {
43 | return str.charAt(0).toUpperCase() + str.slice(1)
44 | }
45 |
46 | return {
47 | sortKey,
48 | sortOrders,
49 | filteredData,
50 | sortBy,
51 | capitalize
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/examples/src/grid/Grid/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | data: Array,
4 | columns: Array,
5 | filterKey: String
6 | },
7 | data() {
8 | return {
9 | sortKey: '',
10 | sortOrders: this.columns.reduce((o, key) => ((o[key] = 1), o), {})
11 | }
12 | },
13 | computed: {
14 | filteredData() {
15 | const sortKey = this.sortKey
16 | const filterKey = this.filterKey && this.filterKey.toLowerCase()
17 | const order = this.sortOrders[sortKey] || 1
18 | let data = this.data
19 | if (filterKey) {
20 | data = data.filter((row) => {
21 | return Object.keys(row).some((key) => {
22 | return String(row[key]).toLowerCase().indexOf(filterKey) > -1
23 | })
24 | })
25 | }
26 | if (sortKey) {
27 | data = data.slice().sort((a, b) => {
28 | a = a[sortKey]
29 | b = b[sortKey]
30 | return (a === b ? 0 : a > b ? 1 : -1) * order
31 | })
32 | }
33 | return data
34 | }
35 | },
36 | methods: {
37 | sortBy(key) {
38 | this.sortKey = key
39 | this.sortOrders[key] = this.sortOrders[key] * -1
40 | },
41 | capitalize(str) {
42 | return str.charAt(0).toUpperCase() + str.slice(1)
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/examples/src/grid/Grid/style.css:
--------------------------------------------------------------------------------
1 | table {
2 | border: 2px solid #42b983;
3 | border-radius: 3px;
4 | background-color: #fff;
5 | }
6 |
7 | th {
8 | background-color: #42b983;
9 | color: rgba(255, 255, 255, 0.66);
10 | cursor: pointer;
11 | user-select: none;
12 | }
13 |
14 | td {
15 | background-color: #f9f9f9;
16 | }
17 |
18 | th,
19 | td {
20 | min-width: 120px;
21 | padding: 10px 20px;
22 | }
23 |
24 | th.active {
25 | color: #fff;
26 | }
27 |
28 | th.active .arrow {
29 | opacity: 1;
30 | }
31 |
32 | .arrow {
33 | display: inline-block;
34 | vertical-align: middle;
35 | width: 0;
36 | height: 0;
37 | margin-left: 5px;
38 | opacity: 0.66;
39 | }
40 |
41 | .arrow.asc {
42 | border-left: 4px solid transparent;
43 | border-right: 4px solid transparent;
44 | border-bottom: 4px solid #fff;
45 | }
46 |
47 | .arrow.dsc {
48 | border-left: 4px solid transparent;
49 | border-right: 4px solid transparent;
50 | border-top: 4px solid #fff;
51 | }
52 |
--------------------------------------------------------------------------------
/src/examples/src/grid/Grid/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 | {{ capitalize(key) }}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {{entry[key]}}
17 |
18 |
19 |
20 |
21 | Співпадінь не знайдено.
22 |
--------------------------------------------------------------------------------
/src/examples/src/grid/description.txt:
--------------------------------------------------------------------------------
1 | Приклад створення багаторазового компонента таблиці та його використання із зовнішніми даними.
2 |
--------------------------------------------------------------------------------
/src/examples/src/handling-input/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const message = ref('Привіт світ!')
6 |
7 | function reverseMessage() {
8 | // Доступ/зміна значення реквізиту через
9 | // його властивість .value.
10 | message.value = message.value.split('').reverse().join('')
11 | }
12 |
13 | function notify() {
14 | alert('навігацію було припинено.')
15 | }
16 |
17 | return {
18 | message,
19 | reverseMessage,
20 | notify
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/examples/src/handling-input/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | message: 'Привіт світ!'
5 | }
6 | },
7 | methods: {
8 | reverseMessage() {
9 | this.message = this.message.split('').reverse().join('')
10 | },
11 | notify() {
12 | alert('навігацію було припинено.')
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/examples/src/handling-input/App/style.css:
--------------------------------------------------------------------------------
1 | button, a {
2 | display: block;
3 | margin-bottom: 1em;
4 | }
--------------------------------------------------------------------------------
/src/examples/src/handling-input/App/template.html:
--------------------------------------------------------------------------------
1 |
6 | {{ message }}
7 |
8 |
12 | Повідомлення навиворіт
13 |
14 |
15 | Додати "!"
16 |
17 |
21 |
22 | Посилання з e.preventDefault()
23 |
24 |
--------------------------------------------------------------------------------
/src/examples/src/handling-input/description.txt:
--------------------------------------------------------------------------------
1 | Цей приклад демонструє обробку введення користувача за допомогою директиви v-on.
2 |
--------------------------------------------------------------------------------
/src/examples/src/hello-world/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | // A "ref" is a reactive data source that stores a value.
6 | // Technically, we don't need to wrap the string with ref()
7 | // in order to display it, but we will see in the next
8 | // example why it is needed if we ever intend to change
9 | // the value.
10 | const message = ref('Привіт, світе!')
11 |
12 | return {
13 | message
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/examples/src/hello-world/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | message: 'Привіт, світе!'
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/examples/src/hello-world/App/template.html:
--------------------------------------------------------------------------------
1 | {{ message }}
--------------------------------------------------------------------------------
/src/examples/src/hello-world/description.txt:
--------------------------------------------------------------------------------
1 | Скажіть "Привіт, світе" разом з Vue!
2 |
--------------------------------------------------------------------------------
/src/examples/src/list-transition/App/composition.js:
--------------------------------------------------------------------------------
1 | import { shuffle as _shuffle } from 'lodash-es'
2 | import { ref } from 'vue'
3 |
4 | export default {
5 | setup() {
6 | const getInitialItems = () => [1, 2, 3, 4, 5]
7 | const items = ref(getInitialItems())
8 | let id = items.value.length + 1
9 |
10 | function insert() {
11 | const i = Math.round(Math.random() * items.value.length)
12 | items.value.splice(i, 0, id++)
13 | }
14 |
15 | function reset() {
16 | items.value = getInitialItems()
17 | id = items.value.length + 1
18 | }
19 |
20 | function shuffle() {
21 | items.value = _shuffle(items.value)
22 | }
23 |
24 | function remove(item) {
25 | const i = items.value.indexOf(item)
26 | if (i > -1) {
27 | items.value.splice(i, 1)
28 | }
29 | }
30 |
31 | return {
32 | items,
33 | insert,
34 | reset,
35 | shuffle,
36 | remove
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/examples/src/list-transition/App/options.js:
--------------------------------------------------------------------------------
1 | import { shuffle } from 'lodash-es'
2 |
3 | const getInitialItems = () => [1, 2, 3, 4, 5]
4 | let id = getInitialItems().length + 1
5 |
6 | export default {
7 | data() {
8 | return {
9 | items: getInitialItems()
10 | }
11 | },
12 | methods: {
13 | insert() {
14 | const i = Math.round(Math.random() * this.items.length)
15 | this.items.splice(i, 0, id++)
16 | },
17 | reset() {
18 | this.items = getInitialItems()
19 | id = getInitialItems().length + 1
20 | },
21 | shuffle() {
22 | this.items = shuffle(this.items)
23 | },
24 | remove(item) {
25 | const i = this.items.indexOf(item)
26 | if (i > -1) {
27 | this.items.splice(i, 1)
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/examples/src/list-transition/App/style.css:
--------------------------------------------------------------------------------
1 | .container {
2 | position: relative;
3 | padding: 0;
4 | }
5 |
6 | .item {
7 | width: 100%;
8 | height: 30px;
9 | background-color: #f3f3f3;
10 | border: 1px solid #666;
11 | box-sizing: border-box;
12 | }
13 |
14 | /* 1. Оголошення переходу */
15 | .fade-move,
16 | .fade-enter-active,
17 | .fade-leave-active {
18 | transition: all 0.5s cubic-bezier(0.55, 0, 0.1, 1);
19 | }
20 |
21 | /* 2. Оголошення входу і виходу зі стану */
22 | .fade-enter-from,
23 | .fade-leave-to {
24 | opacity: 0;
25 | transform: scaleY(0.01) translate(30px, 0);
26 | }
27 |
28 | /* 3. Переконайтеся, що елементи, які вилучаються з потоку макету
29 | є видалені, щоб анімації були розраховані коректно. */
30 | .fade-leave-active {
31 | position: absolute;
32 | }
33 |
--------------------------------------------------------------------------------
/src/examples/src/list-transition/App/template.html:
--------------------------------------------------------------------------------
1 | Вставити за довільним індексом
2 | Скинути
3 | Перетасувати
4 |
5 |
6 |
7 | {{ item }}
8 | x
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/examples/src/list-transition/description.txt:
--------------------------------------------------------------------------------
1 | FLIP переходи списку із вбудованим .
2 | https://aerotwist.com/blog/flip-your-animations/
3 |
--------------------------------------------------------------------------------
/src/examples/src/list-transition/import-map.json:
--------------------------------------------------------------------------------
1 | {
2 | "imports": {
3 | "lodash-es": "https://cdn.jsdelivr.net/npm/lodash-es/+esm"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/examples/src/markdown/App/composition.js:
--------------------------------------------------------------------------------
1 | import { marked } from 'marked'
2 | import { debounce } from 'lodash-es'
3 | import { ref, computed } from 'vue'
4 |
5 | export default {
6 | setup() {
7 | const input = ref('# привіт')
8 |
9 | const output = computed(() => marked(input.value))
10 |
11 | const update = debounce((e) => {
12 | input.value = e.target.value
13 | }, 100)
14 |
15 | return {
16 | input,
17 | output,
18 | update
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/examples/src/markdown/App/options.js:
--------------------------------------------------------------------------------
1 | import { marked } from 'marked'
2 | import { debounce } from 'lodash-es'
3 |
4 | export default {
5 | data: () => ({
6 | input: '# привіт'
7 | }),
8 | computed: {
9 | output() {
10 | return marked(this.input)
11 | }
12 | },
13 | methods: {
14 | update: debounce(function (e) {
15 | this.input = e.target.value
16 | }, 100)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/examples/src/markdown/App/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | }
4 |
5 | .editor {
6 | height: 100vh;
7 | display: flex;
8 | }
9 |
10 | .input,
11 | .output {
12 | overflow: auto;
13 | width: 50%;
14 | height: 100%;
15 | box-sizing: border-box;
16 | padding: 0 20px;
17 | }
18 |
19 | .input {
20 | border: none;
21 | border-right: 1px solid #ccc;
22 | resize: none;
23 | outline: none;
24 | background-color: #f6f6f6;
25 | font-size: 14px;
26 | font-family: 'Monaco', courier, monospace;
27 | padding: 20px;
28 | }
29 |
30 | code {
31 | color: #f66;
32 | }
33 |
--------------------------------------------------------------------------------
/src/examples/src/markdown/App/template.html:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/examples/src/markdown/description.txt:
--------------------------------------------------------------------------------
1 | Простий редактор коду.
2 |
--------------------------------------------------------------------------------
/src/examples/src/markdown/import-map.json:
--------------------------------------------------------------------------------
1 | {
2 | "imports": {
3 | "marked": "https://cdn.jsdelivr.net/npm/marked/+esm",
4 | "lodash-es": "https://cdn.jsdelivr.net/npm/lodash-es/+esm"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/examples/src/modal/App/composition.js:
--------------------------------------------------------------------------------
1 | import Modal from './Modal.vue'
2 | import { ref } from 'vue'
3 |
4 | export default {
5 | components: {
6 | Modal
7 | },
8 | setup() {
9 | const showModal = ref(false)
10 |
11 | return {
12 | showModal
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/examples/src/modal/App/options.js:
--------------------------------------------------------------------------------
1 | import Modal from './Modal.vue'
2 |
3 | export default {
4 | components: {
5 | Modal
6 | },
7 | data() {
8 | return {
9 | showModal: false
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/examples/src/modal/App/template.html:
--------------------------------------------------------------------------------
1 | Показати модальне вікно
2 |
3 |
4 |
5 |
6 |
7 | користувацький заголовок
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/examples/src/modal/Modal/composition.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | show: Boolean
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/examples/src/modal/Modal/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | show: Boolean
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/examples/src/modal/Modal/style.css:
--------------------------------------------------------------------------------
1 | .modal-mask {
2 | position: fixed;
3 | z-index: 9998;
4 | top: 0;
5 | left: 0;
6 | width: 100%;
7 | height: 100%;
8 | background-color: rgba(0, 0, 0, 0.5);
9 | display: flex;
10 | transition: opacity 0.3s ease;
11 | }
12 |
13 | .modal-container {
14 | width: 300px;
15 | margin: auto;
16 | padding: 20px 30px;
17 | background-color: #fff;
18 | border-radius: 2px;
19 | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
20 | transition: all 0.3s ease;
21 | }
22 |
23 | .modal-header h3 {
24 | margin-top: 0;
25 | color: #42b983;
26 | }
27 |
28 | .modal-body {
29 | margin: 20px 0;
30 | }
31 |
32 | .modal-default-button {
33 | float: right;
34 | }
35 |
36 | /*
37 | * Наступні стилі застосовуються автоматично
38 | * до елементів з transition="modal",
39 | * коли їх видимість переключається Vue.js.
40 | *
41 | * Ви з легкістю можете пограти з появою
42 | * модального вікна, редагуючи ці стилі.
43 | */
44 |
45 | .modal-enter-from {
46 | opacity: 0;
47 | }
48 |
49 | .modal-leave-to {
50 | opacity: 0;
51 | }
52 |
53 | .modal-enter-from .modal-container,
54 | .modal-leave-to .modal-container {
55 | -webkit-transform: scale(1.1);
56 | transform: scale(1.1);
57 | }
58 |
--------------------------------------------------------------------------------
/src/examples/src/modal/Modal/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 | тіло за замовчуванням
10 |
11 |
12 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/examples/src/modal/description.txt:
--------------------------------------------------------------------------------
1 | Модальний компонент із настроюваними слотами та переходами CSS.
2 |
--------------------------------------------------------------------------------
/src/examples/src/simple-component/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 | import TodoItem from './TodoItem.vue'
3 |
4 | export default {
5 | components: {
6 | TodoItem
7 | },
8 | setup() {
9 | const groceryList = ref([
10 | { id: 0, text: 'Овочі' },
11 | { id: 1, text: 'Сир' },
12 | { id: 2, text: 'Щось інше, що їдять люди' }
13 | ])
14 |
15 | return {
16 | groceryList
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/examples/src/simple-component/App/options.js:
--------------------------------------------------------------------------------
1 | import TodoItem from './TodoItem.vue'
2 |
3 | export default {
4 | components: {
5 | TodoItem
6 | },
7 | data() {
8 | return {
9 | groceryList: [
10 | { id: 0, text: 'Овочі' },
11 | { id: 1, text: 'Сир' },
12 | { id: 2, text: 'Щось інше, що їдять люди' }
13 | ]
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/examples/src/simple-component/App/template.html:
--------------------------------------------------------------------------------
1 |
2 |
8 |
13 |
14 |
--------------------------------------------------------------------------------
/src/examples/src/simple-component/TodoItem/composition.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | todo: Object
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/examples/src/simple-component/TodoItem/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | todo: Object
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/examples/src/simple-component/TodoItem/template.html:
--------------------------------------------------------------------------------
1 | {{ todo.text }}
--------------------------------------------------------------------------------
/src/examples/src/simple-component/description.txt:
--------------------------------------------------------------------------------
1 | Тут ми показуємо найпростіший можливий компонент, який приймає реквізит і рендерить його.
2 | Дізнайтеся більше про компоненти в посібнику!
3 |
--------------------------------------------------------------------------------
/src/examples/src/svg/App/composition.js:
--------------------------------------------------------------------------------
1 | import PolyGraph from './PolyGraph.vue'
2 | import { ref, reactive } from 'vue'
3 |
4 | export default {
5 | components: {
6 | PolyGraph
7 | },
8 | setup() {
9 | const newLabel = ref('')
10 | const stats = reactive([
11 | { label: 'A', value: 100 },
12 | { label: 'B', value: 100 },
13 | { label: 'C', value: 100 },
14 | { label: 'D', value: 100 },
15 | { label: 'E', value: 100 },
16 | { label: 'F', value: 100 }
17 | ])
18 |
19 | function add(e) {
20 | e.preventDefault()
21 | if (!newLabel.value) return
22 | stats.push({
23 | label: newLabel.value,
24 | value: 100
25 | })
26 | newLabel.value = ''
27 | }
28 |
29 | function remove(stat) {
30 | if (stats.length > 3) {
31 | stats.splice(stats.indexOf(stat), 1)
32 | } else {
33 | alert("Більше видалити неможливо!")
34 | }
35 | }
36 |
37 | return {
38 | newLabel,
39 | stats,
40 | add,
41 | remove
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/examples/src/svg/App/options.js:
--------------------------------------------------------------------------------
1 | import PolyGraph from './PolyGraph.vue'
2 |
3 | export default {
4 | components: {
5 | PolyGraph
6 | },
7 | data: () => ({
8 | newLabel: '',
9 | stats: [
10 | { label: 'A', value: 100 },
11 | { label: 'B', value: 100 },
12 | { label: 'C', value: 100 },
13 | { label: 'D', value: 100 },
14 | { label: 'E', value: 100 },
15 | { label: 'F', value: 100 }
16 | ]
17 | }),
18 | methods: {
19 | add(e) {
20 | e.preventDefault()
21 | if (!this.newLabel) return
22 | this.stats.push({
23 | label: this.newLabel,
24 | value: 100
25 | })
26 | this.newLabel = ''
27 | },
28 | remove(stat) {
29 | if (this.stats.length > 3) {
30 | this.stats.splice(this.stats.indexOf(stat), 1)
31 | } else {
32 | alert("Більше видалити неможливо!")
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/examples/src/svg/App/style.css:
--------------------------------------------------------------------------------
1 | polygon {
2 | fill: #42b983;
3 | opacity: 0.75;
4 | }
5 |
6 | circle {
7 | fill: transparent;
8 | stroke: #999;
9 | }
10 |
11 | text {
12 | font-size: 10px;
13 | fill: #666;
14 | }
15 |
16 | label {
17 | display: inline-block;
18 | margin-left: 10px;
19 | width: 20px;
20 | }
21 |
22 | #raw {
23 | position: absolute;
24 | top: 0;
25 | left: 300px;
26 | }
27 |
--------------------------------------------------------------------------------
/src/examples/src/svg/App/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{stat.label}}
8 |
9 | {{stat.value}}
10 | X
11 |
12 |
13 |
17 |
18 | {{ stats }}
19 |
--------------------------------------------------------------------------------
/src/examples/src/svg/AxisLabel/composition.js:
--------------------------------------------------------------------------------
1 | import { computed } from 'vue'
2 | import { valueToPoint } from './util.js'
3 |
4 | export default {
5 | props: {
6 | stat: Object,
7 | index: Number,
8 | total: Number
9 | },
10 | setup(props) {
11 | const point = computed(() =>
12 | valueToPoint(+props.stat.value + 10, props.index, props.total)
13 | )
14 |
15 | return {
16 | point
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/examples/src/svg/AxisLabel/options.js:
--------------------------------------------------------------------------------
1 | import { valueToPoint } from './util.js'
2 |
3 | export default {
4 | props: {
5 | stat: Object,
6 | index: Number,
7 | total: Number
8 | },
9 | computed: {
10 | point: function () {
11 | return valueToPoint(+this.stat.value + 10, this.index, this.total)
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/examples/src/svg/AxisLabel/template.html:
--------------------------------------------------------------------------------
1 | {{stat.label}}
2 |
--------------------------------------------------------------------------------
/src/examples/src/svg/PolyGraph/composition.js:
--------------------------------------------------------------------------------
1 | import AxisLabel from './AxisLabel.vue'
2 | import { computed } from 'vue'
3 | import { valueToPoint } from './util.js'
4 |
5 | export default {
6 | components: {
7 | AxisLabel
8 | },
9 | props: {
10 | stats: Array
11 | },
12 | setup(props) {
13 | const points = computed(() => {
14 | const total = props.stats.length
15 | return props.stats
16 | .map((stat, i) => {
17 | const { x, y } = valueToPoint(stat.value, i, total)
18 | return `${x},${y}`
19 | })
20 | .join(' ')
21 | })
22 |
23 | return {
24 | points
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/examples/src/svg/PolyGraph/options.js:
--------------------------------------------------------------------------------
1 | import AxisLabel from './AxisLabel.vue'
2 | import { valueToPoint } from './util.js'
3 |
4 | export default {
5 | components: {
6 | AxisLabel
7 | },
8 | props: {
9 | stats: Array
10 | },
11 | computed: {
12 | // обчислювана властивість для точок багатокутника
13 | points() {
14 | const total = this.stats.length
15 | return this.stats
16 | .map((stat, i) => {
17 | const { x, y } = valueToPoint(stat.value, i, total)
18 | return `${x},${y}`
19 | })
20 | .join(' ')
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/examples/src/svg/PolyGraph/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/examples/src/svg/description.txt:
--------------------------------------------------------------------------------
1 | Графік SVG
2 |
--------------------------------------------------------------------------------
/src/examples/src/svg/util.js:
--------------------------------------------------------------------------------
1 | export function valueToPoint(value, index, total) {
2 | const x = 0
3 | const y = -value * 0.8
4 | const angle = ((Math.PI * 2) / total) * index
5 | const cos = Math.cos(angle)
6 | const sin = Math.sin(angle)
7 | const tx = x * cos - y * sin + 100
8 | const ty = x * sin + y * cos + 100
9 | return {
10 | x: tx,
11 | y: ty
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/examples/src/temperature-converter/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const c = ref(0)
6 | const f = ref(32)
7 |
8 | function setC(e, v = +e.target.value) {
9 | c.value = v
10 | f.value = v * (9 / 5) + 32
11 | }
12 |
13 | function setF(e, v = +e.target.value) {
14 | f.value = v
15 | c.value = (v - 32) * (5 / 9)
16 | }
17 |
18 | return {
19 | c,
20 | f,
21 | setC,
22 | setF
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/examples/src/temperature-converter/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | c: 0,
5 | f: 32
6 | }
7 | },
8 | methods: {
9 | setC(e, c = +e.target.value) {
10 | this.c = c
11 | this.f = c * (9 / 5) + 32
12 | },
13 | setF(e, f = +e.target.value) {
14 | this.f = f
15 | this.c = (f - 32) * (5 / 9)
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/examples/src/temperature-converter/App/template.html:
--------------------------------------------------------------------------------
1 | за Цельсієм =
2 | по Фаренгейту
3 |
--------------------------------------------------------------------------------
/src/examples/src/temperature-converter/description.txt:
--------------------------------------------------------------------------------
1 | https://eugenkiss.github.io/7guis/tasks/#temp
--------------------------------------------------------------------------------
/src/examples/src/timer/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref, onUnmounted, computed } from 'vue'
2 | export default {
3 | setup() {
4 | const duration = ref(15 * 1000)
5 | const elapsed = ref(0)
6 |
7 | let lastTime
8 | let handle
9 |
10 | const update = () => {
11 | elapsed.value = performance.now() - lastTime
12 | if (elapsed.value >= duration.value) {
13 | cancelAnimationFrame(handle)
14 | } else {
15 | handle = requestAnimationFrame(update)
16 | }
17 | }
18 |
19 | const reset = () => {
20 | elapsed.value = 0
21 | lastTime = performance.now()
22 | update()
23 | }
24 |
25 | const progressRate = computed(() =>
26 | Math.min(elapsed.value / duration.value, 1)
27 | )
28 |
29 | reset()
30 |
31 | onUnmounted(() => {
32 | cancelAnimationFrame(handle)
33 | })
34 | return {
35 | duration,
36 | elapsed,
37 | progressRate,
38 | reset
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/examples/src/timer/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | duration: 15 * 1000,
5 | elapsed: 0
6 | }
7 | },
8 | created() {
9 | this.reset()
10 | },
11 | unmounted() {
12 | cancelAnimationFrame(this.handle)
13 | },
14 | computed: {
15 | progressRate() {
16 | return Math.min(this.elapsed / this.duration, 1)
17 | }
18 | },
19 | methods: {
20 | update() {
21 | this.elapsed = performance.now() - this.lastTime
22 | if (this.elapsed >= this.duration) {
23 | cancelAnimationFrame(this.handle)
24 | } else {
25 | this.handle = requestAnimationFrame(this.update)
26 | }
27 | },
28 | reset() {
29 | this.elapsed = 0
30 | this.lastTime = performance.now()
31 | this.update()
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/examples/src/timer/App/style.css:
--------------------------------------------------------------------------------
1 | .elapsed-container {
2 | width: 300px;
3 | }
4 |
5 | .elapsed-bar {
6 | background-color: red;
7 | height: 10px;
8 | }
--------------------------------------------------------------------------------
/src/examples/src/timer/App/template.html:
--------------------------------------------------------------------------------
1 | Пройдений час:
4 |
5 | {{ (elapsed / 1000).toFixed(1) }}s
6 |
7 |
8 | Тривалість:
9 | {{ (duration / 1000).toFixed(1) }}s
10 |
11 |
12 | Скинути
13 |
--------------------------------------------------------------------------------
/src/examples/src/timer/description.txt:
--------------------------------------------------------------------------------
1 | https://eugenkiss.github.io/7guis/tasks/#timer
--------------------------------------------------------------------------------
/src/examples/src/todomvc/App/style.css:
--------------------------------------------------------------------------------
1 | @import "https://unpkg.com/todomvc-app-css@2.4.1/index.css";
--------------------------------------------------------------------------------
/src/examples/src/todomvc/description.txt:
--------------------------------------------------------------------------------
1 | Повністю сумісна зі специфікаціями реалізація списку завдань
2 | https://todomvc.com/
3 |
--------------------------------------------------------------------------------
/src/examples/src/tree/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 | import TreeItem from './TreeItem.vue'
3 |
4 | export default {
5 | components: {
6 | TreeItem
7 | },
8 | setup() {
9 | const treeData = ref({
10 | name: 'Моє дерево',
11 | children: [
12 | { name: 'привіт' },
13 | { name: 'світ' },
14 | {
15 | name: 'дочірня папка',
16 | children: [
17 | {
18 | name: 'дочірня папка',
19 | children: [{ name: 'привіт' }, { name: 'світ' }]
20 | },
21 | { name: 'привіт' },
22 | { name: 'світ' },
23 | {
24 | name: 'дочірня папка',
25 | children: [{ name: 'привіт' }, { name: 'світ' }]
26 | }
27 | ]
28 | }
29 | ]
30 | })
31 |
32 | return {
33 | treeData
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/examples/src/tree/App/options.js:
--------------------------------------------------------------------------------
1 | import TreeItem from './TreeItem.vue'
2 |
3 | const treeData = {
4 | name: 'Моє дерево',
5 | children: [
6 | { name: 'привіт' },
7 | { name: 'світ' },
8 | {
9 | name: 'дочірня папка',
10 | children: [
11 | {
12 | name: 'дочірня папка',
13 | children: [{ name: 'привіт' }, { name: 'світ' }]
14 | },
15 | { name: 'привіт' },
16 | { name: 'світ' },
17 | {
18 | name: 'дочірня папка',
19 | children: [{ name: 'привіт' }, { name: 'світ' }]
20 | }
21 | ]
22 | }
23 | ]
24 | }
25 |
26 | export default {
27 | components: {
28 | TreeItem
29 | },
30 | data() {
31 | return {
32 | treeData
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/examples/src/tree/App/style.css:
--------------------------------------------------------------------------------
1 | .item {
2 | cursor: pointer;
3 | line-height: 1.5;
4 | }
5 | .bold {
6 | font-weight: bold;
7 | }
--------------------------------------------------------------------------------
/src/examples/src/tree/App/template.html:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/examples/src/tree/TreeItem/composition.js:
--------------------------------------------------------------------------------
1 | import { ref, computed } from 'vue'
2 |
3 | export default {
4 | name: 'TreeItem', // необхідні для референції на самого себе
5 | props: {
6 | model: Object
7 | },
8 | setup(props) {
9 | const isOpen = ref(false)
10 | const isFolder = computed(() => {
11 | return props.model.children && props.model.children.length
12 | })
13 |
14 | function toggle() {
15 | isOpen.value = !isOpen.value
16 | }
17 |
18 | function changeType() {
19 | if (!isFolder.value) {
20 | props.model.children = []
21 | addChild()
22 | isOpen.value = true
23 | }
24 | }
25 |
26 | function addChild() {
27 | props.model.children.push({ name: 'нова папка' })
28 | }
29 |
30 | return {
31 | isOpen,
32 | isFolder,
33 | toggle,
34 | changeType,
35 | addChild
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/examples/src/tree/TreeItem/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'TreeItem', // необхідні для референції на самого себе
3 | props: {
4 | model: Object
5 | },
6 | data() {
7 | return {
8 | isOpen: false
9 | }
10 | },
11 | computed: {
12 | isFolder() {
13 | return this.model.children && this.model.children.length
14 | }
15 | },
16 | methods: {
17 | toggle() {
18 | if (this.isFolder) {
19 | this.isOpen = !this.isOpen
20 | }
21 | },
22 | changeType() {
23 | if (!this.isFolder) {
24 | this.model.children = []
25 | this.addChild()
26 | this.isOpen = true
27 | }
28 | },
29 | addChild() {
30 | this.model.children.push({
31 | name: 'нова папка'
32 | })
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/examples/src/tree/TreeItem/template.html:
--------------------------------------------------------------------------------
1 |
2 |
6 | {{ model.name }}
7 | [{{ isOpen ? '-' : '+' }}]
8 |
9 |
10 |
14 |
18 |
19 | +
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/examples/src/tree/description.txt:
--------------------------------------------------------------------------------
1 | Вкладений компонент дерева, який рекурсивно рендерить сам себе.
2 | За допомогою подвійного натиску лівої кнопки миші, ви можете перетворити елемент на папку.
3 |
--------------------------------------------------------------------------------
/src/guide/best-practices/images/AccessibilityChromeDeveloperTools.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/best-practices/images/AccessibilityChromeDeveloperTools.png
--------------------------------------------------------------------------------
/src/guide/best-practices/images/AccessibleARIAdescribedby.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/best-practices/images/AccessibleARIAdescribedby.png
--------------------------------------------------------------------------------
/src/guide/best-practices/images/AccessibleARIAlabelDevTools.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/best-practices/images/AccessibleARIAlabelDevTools.png
--------------------------------------------------------------------------------
/src/guide/best-practices/images/AccessibleARIAlabelledbyDevTools.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/best-practices/images/AccessibleARIAlabelledbyDevTools.png
--------------------------------------------------------------------------------
/src/guide/best-practices/images/AccessibleLabelChromeDevTools.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/best-practices/images/AccessibleLabelChromeDevTools.png
--------------------------------------------------------------------------------
/src/guide/best-practices/images/AccessiblePlaceholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/best-practices/images/AccessiblePlaceholder.png
--------------------------------------------------------------------------------
/src/guide/built-ins/images/transition-classes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/built-ins/images/transition-classes.png
--------------------------------------------------------------------------------
/src/guide/built-ins/keep-alive-demos/CompA.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 | Компонент: A
8 | Рахунок: {{ count }}
9 | +
10 |
11 |
--------------------------------------------------------------------------------
/src/guide/built-ins/keep-alive-demos/CompB.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 | Компонент: B
8 | Повідомлення: {{ msg }}
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/guide/built-ins/keep-alive-demos/SwitchComponent.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 | A
14 | Б
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/guide/built-ins/transition-demos/Basic.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
Перемкнути зникнення
9 |
10 | Привіт
11 |
12 |
13 |
14 |
15 |
26 |
--------------------------------------------------------------------------------
/src/guide/built-ins/transition-demos/BetweenComponents.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 | A
14 |
15 |
16 | Б
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/guide/built-ins/transition-demos/BetweenElements.vue:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
Натисніть, щоб циклічно переходити між станами:
12 |
13 |
14 |
15 | Редагувати
16 |
17 |
18 | Зберегти
19 |
20 |
21 | Скасувати
22 |
23 |
24 |
25 |
26 |
27 |
28 |
63 |
--------------------------------------------------------------------------------
/src/guide/built-ins/transition-demos/CssAnimation.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
Переключити
9 |
10 |
11 | Привіт, ось якийсь стрибучий текст!
12 |
13 |
14 |
15 |
16 |
17 |
36 |
--------------------------------------------------------------------------------
/src/guide/built-ins/transition-demos/JsHooks.vue:
--------------------------------------------------------------------------------
1 |
41 |
42 |
43 |
44 |
Переключити
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
66 |
--------------------------------------------------------------------------------
/src/guide/built-ins/transition-demos/ListBasic.vue:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 | Додати випадковий індекс
23 | Видалити випадковий індекс
24 |
25 |
26 | {{ item }}
27 |
28 |
29 |
30 |
31 |
32 |
43 |
--------------------------------------------------------------------------------
/src/guide/built-ins/transition-demos/ListMove.vue:
--------------------------------------------------------------------------------
1 |
32 |
33 |
34 |
35 | Додати
36 | Видалити
37 | Перетасувати
38 |
39 |
40 | {{ item }}
41 |
42 |
43 |
44 |
45 |
46 |
65 |
--------------------------------------------------------------------------------
/src/guide/built-ins/transition-demos/ListStagger.vue:
--------------------------------------------------------------------------------
1 |
42 |
43 |
44 |
45 |
46 |
53 |
58 | {{ item.msg }}
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/src/guide/built-ins/transition-demos/NestedTransitions.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
Переключити
9 |
10 |
13 |
14 |
15 |
16 |
17 |
65 |
--------------------------------------------------------------------------------
/src/guide/built-ins/transition-demos/SlideFade.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
Переключити слайд + зникнути
9 |
10 | Привіт
11 |
12 |
13 |
14 |
15 |
30 |
--------------------------------------------------------------------------------
/src/guide/components/images/named-slots.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/components/images/named-slots.png
--------------------------------------------------------------------------------
/src/guide/components/images/prop-drilling.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/components/images/prop-drilling.png
--------------------------------------------------------------------------------
/src/guide/components/images/provide-inject.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/components/images/provide-inject.png
--------------------------------------------------------------------------------
/src/guide/components/images/slots.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/components/images/slots.png
--------------------------------------------------------------------------------
/src/guide/essentials/images/components.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/essentials/images/components.png
--------------------------------------------------------------------------------
/src/guide/essentials/images/directive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/essentials/images/directive.png
--------------------------------------------------------------------------------
/src/guide/essentials/images/lifecycle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/essentials/images/lifecycle.png
--------------------------------------------------------------------------------
/src/guide/extras/demos/AnimateWatcher.vue:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 | Введіть число:
21 |
{{ tweened.number.toFixed(0) }}
22 |
23 |
24 |
25 |
31 |
--------------------------------------------------------------------------------
/src/guide/extras/demos/Colors.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
17 |
Перемістіть курсор миші по цьому div...
18 |
x: {{ x }}
19 |
20 |
21 |
22 |
29 |
--------------------------------------------------------------------------------
/src/guide/extras/demos/DisabledButton.vue:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 | Натисніть мене
18 | Ця функція вимкнена!
21 |
22 |
23 |
24 |
25 |
54 |
--------------------------------------------------------------------------------
/src/guide/extras/demos/SpreadSheet.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | {{ c }}
14 |
15 |
16 |
17 |
18 | {{ i - 1 }}
19 |
20 | |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
47 |
--------------------------------------------------------------------------------
/src/guide/extras/demos/SpreadSheetCell.vue:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 | el.focus()"
26 | />
27 | {{ evalCell(cells[c][r]) }}
28 |
29 |
30 |
31 |
54 |
--------------------------------------------------------------------------------
/src/guide/extras/demos/spreadSheetStore.js:
--------------------------------------------------------------------------------
1 | import { reactive } from 'vue'
2 |
3 | const COLS = 3
4 | const ROWS = 3
5 |
6 | export const cells = reactive(
7 | Array.from(Array(COLS).keys()).map((i) =>
8 | Array.from(Array(ROWS).keys()).map((i) => '')
9 | )
10 | )
11 |
12 | // initial state for demo
13 | cells[0][0] = '1'
14 | cells[0][1] = '2'
15 | cells[0][2] = '= A0 + A1'
16 |
17 | // adapted from https://codesandbox.io/s/jotai-7guis-task7-cells-mzoit?file=/src/atoms.ts
18 | // by @dai-shi
19 | export function evalCell(exp) {
20 | if (!exp.startsWith('=')) {
21 | return exp
22 | }
23 |
24 | // = A1 + B2 ---> get(0,1) + get(1,2)
25 | exp = exp
26 | .slice(1)
27 | .replace(
28 | /\b([A-Z])(\d{1,2})\b/g,
29 | (_, c, r) => `get(${c.charCodeAt(0) - 65},${r})`
30 | )
31 |
32 | try {
33 | return new Function('get', `return ${exp}`)(getCellValue)
34 | } catch (e) {
35 | return `#ERROR ${e}`
36 | }
37 | }
38 |
39 | function getCellValue(c, r) {
40 | const val = evalCell(cells[c][r])
41 | const num = Number(val)
42 | return Number.isFinite(num) ? num : val
43 | }
44 |
--------------------------------------------------------------------------------
/src/guide/extras/images/composition-api-after.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/extras/images/composition-api-after.png
--------------------------------------------------------------------------------
/src/guide/extras/images/options-api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/extras/images/options-api.png
--------------------------------------------------------------------------------
/src/guide/extras/images/render-pipeline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/extras/images/render-pipeline.png
--------------------------------------------------------------------------------
/src/guide/reusability/mouse.js:
--------------------------------------------------------------------------------
1 | import { ref, onMounted, onUnmounted } from 'vue'
2 |
3 | export function useMouse() {
4 | const x = ref(0)
5 | const y = ref(0)
6 |
7 | function update(event) {
8 | x.value = event.pageX
9 | y.value = event.pageY
10 | }
11 |
12 | onMounted(() => window.addEventListener('mousemove', update))
13 | onUnmounted(() => window.removeEventListener('mousemove', update))
14 |
15 | return { x, y }
16 | }
17 |
--------------------------------------------------------------------------------
/src/guide/scaling-up/images/state-flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/scaling-up/images/state-flow.png
--------------------------------------------------------------------------------
/src/guide/typescript/images/takeover-mode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/guide/typescript/images/takeover-mode.png
--------------------------------------------------------------------------------
/src/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | page: true
3 | title: Vue.js - Прогресивний JavaScript фреймворк
4 | ---
5 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/partners/[partnerId].md:
--------------------------------------------------------------------------------
1 | ---
2 | page: true
3 | footer: false
4 | ---
5 |
6 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/partners/[partnerId].paths.ts:
--------------------------------------------------------------------------------
1 | import partners from './partners.json'
2 | import { normalizeName } from './components/utils'
3 |
4 | export default {
5 | paths: partners.map((p) => {
6 | return {
7 | params: {
8 | partnerId: normalizeName(p.name)
9 | }
10 | }
11 | })
12 | }
13 |
--------------------------------------------------------------------------------
/src/partners/all.md:
--------------------------------------------------------------------------------
1 | ---
2 | page: true
3 | footer: false
4 | ---
5 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/partners/components/PartnerAll.vue:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 |
25 |
33 |
34 |
35 |
36 |
58 |
--------------------------------------------------------------------------------
/src/partners/components/PartnerHero.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
{{ title || 'Партнери Vue' }}
8 |
9 | Партнери Vue – це агенції, схвалені командою Vue, які пропонують першокласні
10 | консалтингові послуги та послуги з розробки на Vue. Якщо ви зацікавлені, щоб
11 | ваша компанія була в списку партнерів, будь ласка
12 | подайте свою заявку тут .
15 |
16 |
17 |
18 |
19 |
72 |
--------------------------------------------------------------------------------
/src/partners/components/PartnerJoin.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Розвивайте свій бізнес із Vue
5 |
6 | Залучайте потенційних клієнтів для нових проєктів, підвищуйте довіру до ваших
7 | клієнтів і підтримуйте довгострокову стійкість Vue.js і його
8 | екосистеми.
9 |
10 |
Стати партнером
16 |
17 |
18 |
19 |
71 |
--------------------------------------------------------------------------------
/src/partners/components/PartnerLanding.vue:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
Партнери в центрі уваги
26 |
27 |
28 |
29 |
30 |
35 |
36 |
37 |
38 |
39 |
40 |
92 |
--------------------------------------------------------------------------------
/src/partners/components/PartnerLocation.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
17 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/partners/components/type.ts:
--------------------------------------------------------------------------------
1 | export interface Partner {
2 | name: string
3 | logo: string
4 | hero?: string
5 | flipLogo?: boolean
6 | intro: string
7 | description: string[]
8 | proficiencies: string[]
9 | region: string[]
10 | location: string[]
11 | website: {
12 | text: string
13 | url: string
14 | }
15 | contact: string
16 | hiring?: string
17 | platinum?: boolean
18 | }
19 |
--------------------------------------------------------------------------------
/src/partners/components/utils.ts:
--------------------------------------------------------------------------------
1 | export function track() {
2 | fathom.trackGoal('TTDUIE6G', 0)
3 | }
4 |
5 | export function normalizeName(name: string) {
6 | return name.toLowerCase().replace(/\s+/g, '')
7 | }
8 |
9 | export function getHero(img: string | undefined, name: string) {
10 | return `/images/partners/${img || `${normalizeName(name)}-hero.jpg`}`
11 | }
12 |
13 | export function getLogo(img: string, flip = false) {
14 | if (flip) img = img.replace(/(\.\w+$)/, '-dark$1')
15 | return `/images/partners/${img}`
16 | }
17 |
--------------------------------------------------------------------------------
/src/partners/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | page: true
3 | footer: false
4 | ---
5 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/public/_headers:
--------------------------------------------------------------------------------
1 | /*
2 | X-Frame-Options: ALLOW-FROM https://staging.certification.vuejs.org https://certification.vuejs.org https://certificates.dev https://staging.certificates.dev https://alemira.com https://*.alemira.com
3 | Content-Security-Policy: frame-ancestors https://staging.certification.vuejs.org https://certification.vuejs.org https://certificates.dev https://staging.certificates.dev https://alemira.com https://*.alemira.com
4 |
5 | /assets/*
6 | cache-control: max-age=31536000
7 | cache-control: immutable
8 |
--------------------------------------------------------------------------------
/src/public/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/logo.png
--------------------------------------------------------------------------------
/src/public/images/partners/64robots-hero.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/64robots-hero.jpg
--------------------------------------------------------------------------------
/src/public/images/partners/curotec-hero.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/curotec-hero.jpg
--------------------------------------------------------------------------------
/src/public/images/partners/curotec.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/curotec.png
--------------------------------------------------------------------------------
/src/public/images/partners/epicmax.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/epicmax.png
--------------------------------------------------------------------------------
/src/public/images/partners/herodevs-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/herodevs-dark.png
--------------------------------------------------------------------------------
/src/public/images/partners/herodevs-hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/herodevs-hero.png
--------------------------------------------------------------------------------
/src/public/images/partners/herodevs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/herodevs.png
--------------------------------------------------------------------------------
/src/public/images/partners/jump24-dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/public/images/partners/jump24-hero.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/jump24-hero.jpg
--------------------------------------------------------------------------------
/src/public/images/partners/jump24.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/public/images/partners/monterail-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/monterail-dark.png
--------------------------------------------------------------------------------
/src/public/images/partners/monterail-hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/monterail-hero.png
--------------------------------------------------------------------------------
/src/public/images/partners/monterail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/monterail.png
--------------------------------------------------------------------------------
/src/public/images/partners/passionatepeople-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/passionatepeople-dark.png
--------------------------------------------------------------------------------
/src/public/images/partners/passionatepeople-hero.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/passionatepeople-hero.jpg
--------------------------------------------------------------------------------
/src/public/images/partners/passionatepeople.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/passionatepeople.png
--------------------------------------------------------------------------------
/src/public/images/partners/redberry-hero.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/redberry-hero.jpg
--------------------------------------------------------------------------------
/src/public/images/partners/redberry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/redberry.png
--------------------------------------------------------------------------------
/src/public/images/partners/tighten-hero.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/tighten-hero.jpg
--------------------------------------------------------------------------------
/src/public/images/partners/vehikl-hero.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/vehikl-hero.jpg
--------------------------------------------------------------------------------
/src/public/images/partners/webreinvent-hero.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/webreinvent-hero.jpg
--------------------------------------------------------------------------------
/src/public/images/partners/webreinvent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/partners/webreinvent.png
--------------------------------------------------------------------------------
/src/public/images/paypal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs-translations/docs-uk/28b6af923ac4631b49938b25a8a240ad80fe1b21/src/public/images/paypal.png
--------------------------------------------------------------------------------
/src/public/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/public/service-worker.js:
--------------------------------------------------------------------------------
1 | // force clearing previous service worker
2 | self.addEventListener('install', function (e) {
3 | self.skipWaiting()
4 | })
5 |
6 | self.addEventListener('activate', function (e) {
7 | self.registration
8 | .unregister()
9 | .then(function () {
10 | return self.clients.matchAll()
11 | })
12 | .then(function (clients) {
13 | clients.forEach((client) => client.navigate(client.url))
14 | })
15 | })
16 |
--------------------------------------------------------------------------------
/src/translations/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | aside: false
3 | ---
4 |
5 | # Переклади {#translations}
6 |
7 | ## Доступні мови {#available-languages}
8 |
9 | - [English / Англійська](https://vuejs.org/) [[джерело](https://github.com/vuejs/docs)]
10 | - [简体中文 / Спрощена Китайська](https://cn.vuejs.org/) [[джерело](https://github.com/vuejs-translations/docs-zh-cn)]
11 | - [日本語 / Японська](https://ja.vuejs.org/) [[джерело](https://github.com/vuejs-translations/docs-ja)]
12 | - [Українська](https://ua.vuejs.org) [[джерело](https://github.com/vuejs-translations/docs-ua)]
13 | - [Français / Французька](https://fr.vuejs.org) [[джерело](https://github.com/vuejs-translations/docs-fr)]
14 | - [한국어 / Корейська](https://ko.vuejs.org) [[джерело](https://github.com/vuejs-translations/docs-ko)]
15 | - [Português / Португальська](https://pt.vuejs.org) [[джерело](https://github.com/vuejs-translations/docs-pt)]
16 | - [বাংলা / Бенгальська](https://bn.vuejs.org) [[джерело](https://github.com/vuejs-translations/docs-bn)]
17 | - [Italiano / Італійська](https://it.vuejs.org) [[джерело](https://github.com/vuejs-translations/docs-it)]
18 |
19 | ## Work in Progress Languages {#work-in-progress-languages}
20 |
21 | - [فارسی / Persian](https://fa.vuejs.org/) [[source](https://github.com/vuejs-translations/docs-fa)]
22 |
23 | ## Початок нового перекладу {#starting-a-new-translation}
24 |
25 | Документація Vue нещодавно зазнала значних змін, тож переклади іншими мовами досі відсутні або в процесі перекладу.
26 |
27 | Ми вітаємо зусилля спільноти щодо надання більше перекладів. Роботою з перекладу керує організація [vuejs-translations](https://github.com/vuejs-translations/) на GitHub. Якщо ви зацікавлені зробити свій внесок, перегляньте [Інструкції з перекладу](https://github.com/vuejs-translations/guidelines/blob/main/README.md), щоб почати.
28 |
--------------------------------------------------------------------------------
/src/tutorial/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | page: true
3 | title: Посібник
4 | sidebar: false
5 | aside: false
6 | footer: false
7 | returnToTop: false
8 | ---
9 |
10 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-1/App/template.html:
--------------------------------------------------------------------------------
1 | Привіт, світе!
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-1/description.md:
--------------------------------------------------------------------------------
1 | # Початок {#getting-started}
2 |
3 | Ласкаво просимо до підручника Vue!
4 |
5 | Мета цього підручника — швидко надати вам досвід роботи з Vue прямо в браузері. Він не має на меті бути вичерпним, і вам не потрібно все розуміти, перш ніж рухатися далі. Однак після його завершення обов'язково також прочитайте Гід , який докладніше розглядає кожну тему.
6 |
7 | ## Передумови {#prerequisites}
8 |
9 | Посібник передбачає базове знайомство з HTML, CSS і JavaScript. Якщо ви зовсім новачок у фронтенд розробці, можливо, як ваш перший крок переходити безпосередньо до фреймворку буде не найкращою ідеєю – осягніть основи, а потім повертайтеся! Попередній досвід роботи з іншими фреймворками допомагає, але не є обов'язковим.
10 |
11 | ## Як користуватися цим посібником {#how-to-use-this-tutorial}
12 |
13 | Ви можете відредагувати код праворуч нижче та миттєво побачити оновлений результат. Кожен крок представлятиме основну функцію Vue, і від вас очікується завершення коду, щоб запустити демонстрацію. Якщо ви застрягли, у вас буде кнопка "Покажи мені!", яка відкриває для вас робочий код. Намагайтеся не надто покладатися на це - ви навчитеся швидше, з'ясовуючи все самостійно.
14 |
15 | Якщо ви досвідчений розробник із Vue 2 або інших фреймворків, є кілька налаштувань, які ви можете підправити, щоб якнайкраще використовувати цей посібник. Якщо ви новачок, рекомендуємо використовувати значення за промовчуванням.
16 |
17 |
18 | Деталі налаштування підручника
19 |
20 | - Vue пропонує два стилі API: опційний та композиційний. Цей підручник призначений для обох – ви можете вибрати бажаний стиль за допомогою перемикачів параметрів API у верхній частині. Докладніше про стилі API .
21 |
22 | - Ви також можете перемикатися між режимом SFC або HTML. У першому буде показано приклади коду у форматі одно-файлових компонентів (SFC), який використовують більшість розробників із етапом збірки Vue. HTML-режим показує використання без етапу збірки.
23 |
24 |
25 |
26 | Готові? Натисніть «Далі», щоб почати.
27 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-10/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const todoId = ref(1)
6 | const todoData = ref(null)
7 |
8 | async function fetchData() {
9 | todoData.value = null
10 | const res = await fetch(
11 | `https://jsonplaceholder.typicode.com/todos/${todoId.value}`
12 | )
13 | todoData.value = await res.json()
14 | }
15 |
16 | fetchData()
17 |
18 | return {
19 | todoId,
20 | todoData
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-10/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | todoId: 1,
5 | todoData: null
6 | }
7 | },
8 | methods: {
9 | async fetchData() {
10 | this.todoData = null
11 | const res = await fetch(
12 | `https://jsonplaceholder.typicode.com/todos/${this.todoId}`
13 | )
14 | this.todoData = await res.json()
15 | }
16 | },
17 | mounted() {
18 | this.fetchData()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-10/App/template.html:
--------------------------------------------------------------------------------
1 | Завдання: {{ todoId }}
2 | Отримати наступне завдання
3 | Завантажується...
4 | {{ todoData }}
5 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-10/_hint/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref, watch } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const todoId = ref(1)
6 | const todoData = ref(null)
7 |
8 | async function fetchData() {
9 | todoData.value = null
10 | const res = await fetch(
11 | `https://jsonplaceholder.typicode.com/todos/${todoId.value}`
12 | )
13 | todoData.value = await res.json()
14 | }
15 |
16 | fetchData()
17 |
18 | watch(todoId, fetchData)
19 |
20 | return {
21 | todoId,
22 | todoData
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-10/_hint/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | todoId: 1,
5 | todoData: null
6 | }
7 | },
8 | methods: {
9 | async fetchData() {
10 | this.todoData = null
11 | const res = await fetch(
12 | `https://jsonplaceholder.typicode.com/todos/${this.todoId}`
13 | )
14 | this.todoData = await res.json()
15 | }
16 | },
17 | mounted() {
18 | this.fetchData()
19 | },
20 | watch: {
21 | todoId() {
22 | this.fetchData()
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-10/description.md:
--------------------------------------------------------------------------------
1 | # Спостерігачі {#watchers}
2 |
3 | Іноді нам потрібно виконати реактивно "побічні ефекти" - наприклад, вивести рахунок до консолі, коли він змінюється. Ми можемо досягти цього за допомогою спостерігачів:
4 |
5 |
6 |
7 | ```js
8 | import { ref, watch } from 'vue'
9 |
10 | const count = ref(0)
11 |
12 | watch(count, (newCount) => {
13 | // так, console.log() це побічний ефект
14 | console.log(`Новий рахунок: ${newCount}`)
15 | })
16 | ```
17 |
18 | `watch()` може безпосередньо спостерігати за референцією і функція зворотного виклику запускається щоразу, коли змінюється значення `count`. `watch()` також може спостерігати за іншими типами даних - більш детальну інформацію можна знайти в
гіді про спостерігачі .
19 |
20 |
21 |
22 |
23 | ```js
24 | export default {
25 | data() {
26 | return {
27 | count: 0
28 | }
29 | },
30 | watch: {
31 | count(newCount) {
32 | // так, console.log() це побічний ефект
33 | console.log(`Новий рахунок: ${newCount}`)
34 | }
35 | }
36 | }
37 | ```
38 |
39 | Тут ми використовуємо опцію `watch`, щоб спостерігати за властивістю `count`. Зворотній виклик спостерігача викликається тоді, коли змінюється `count` і отримує нове значення як аргумент. Більш детальну інформацію можна знайти в
гіді про спостерігачі .
40 |
41 |
42 |
43 | Більш практичним прикладом за виведення в консоль, було б отримання нових даних, коли змінюється ID. Код, який ми маємо, отримує дані про завдання з фіктивного API під час монтування компонента. Існує також кнопка, яка збільшує ID завдання, яке має бути отримане. Спробуйте реалізувати спостерігач, який буде отримувати нове завдання, якщо натиснути кнопку.
44 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-11/App/composition.js:
--------------------------------------------------------------------------------
1 | export default {
2 | // зареєструйте компонент
3 | }
4 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-11/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | // зареєструйте дочірній компонент
3 | }
4 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-11/App/template.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-11/ChildComp/template.html:
--------------------------------------------------------------------------------
1 | Дочірній компонент!
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-11/_hint/App/composition.js:
--------------------------------------------------------------------------------
1 | import ChildComp from './ChildComp.vue'
2 |
3 | export default {
4 | components: {
5 | ChildComp
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-11/_hint/App/options.js:
--------------------------------------------------------------------------------
1 | import ChildComp from './ChildComp.vue'
2 |
3 | export default {
4 | components: {
5 | ChildComp
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-11/_hint/App/template.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-11/description.md:
--------------------------------------------------------------------------------
1 | # Компоненти {#components}
2 |
3 | Досі ми працювали лише з одним компонентом. Справжні додатки Vue зазвичай створюються за допомогою вкладених компонентів.
4 |
5 | Батьківський компонент може рендерити інший компонент у своєму шаблоні як дочірній. Щоб використовувати дочірній компонент, нам потрібно спочатку його імпортувати:
6 |
7 |
8 |
9 |
10 | ```js
11 | import ChildComp from './ChildComp.vue'
12 | ```
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ```js
21 | import ChildComp from './ChildComp.vue'
22 |
23 | export default {
24 | components: {
25 | ChildComp
26 | }
27 | }
28 | ```
29 |
30 | Нам також потрібно зареєструвати компонент за допомогою опції `components`. Тут ми використовуємо скорочення властивостей об'єкта, щоб зареєструвати компонент `ChildComp` під ключем `ChildComp`.
31 |
32 |
33 |
34 |
35 |
36 |
37 | Потім ми можемо використовувати компонент у шаблоні як:
38 |
39 | ```vue-html
40 |
41 | ```
42 |
43 |
44 |
45 |
46 |
47 | ```js
48 | import ChildComp from './ChildComp.js'
49 |
50 | createApp({
51 | components: {
52 | ChildComp
53 | }
54 | })
55 | ```
56 |
57 | Нам також потрібно зареєструвати компонент за допомогою опції `components`. Тут ми використовуємо скорочення властивостей об'єкта, щоб зареєструвати компонент `ChildComp` під ключем `ChildComp`.
58 |
59 | Оскільки ми пишемо шаблон в DOM, він буде підпорядкований правилам парсингу браузера, які не враховують регістр для імен тегів. Тому для посилання на дочірній компонент нам потрібно використовувати ім'я в стилі `kebab-cased`:
60 |
61 | ```vue-html
62 |
63 | ```
64 |
65 |
66 |
67 |
68 | Тепер спробуйте самі - імпортуйте дочірній компонент і виведіть його в шаблоні.
69 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-12/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 | import ChildComp from './ChildComp.vue'
3 |
4 | export default {
5 | components: {
6 | ChildComp
7 | },
8 | setup() {
9 | const greeting = ref('Привіт від батьківського компонента!')
10 |
11 | return {
12 | greeting
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-12/App/options.js:
--------------------------------------------------------------------------------
1 | import ChildComp from './ChildComp.vue'
2 |
3 | export default {
4 | components: {
5 | ChildComp
6 | },
7 | data() {
8 | return {
9 | greeting: 'Привіт від батьківського компонента!'
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-12/App/template.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-12/ChildComp/composition.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | msg: String
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-12/ChildComp/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | msg: String
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-12/ChildComp/template.html:
--------------------------------------------------------------------------------
1 | {{ msg || 'Реквізит ще не переданий' }}
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-12/_hint/App/template.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-12/description.md:
--------------------------------------------------------------------------------
1 | # Реквізити {#props}
2 |
3 | Дочірній компонент може приймати вхідні дані від батьківського компонента через **реквізити**. Спочатку йому потрібно оголосити реквізити, які він приймає:
4 |
5 |
6 |
7 |
8 | ```vue
9 |
10 |
15 | ```
16 |
17 | Зверніть увагу, що `defineProps()` - це попередньо встановлений макрос, тому його не потрібно імпортувати. Після оголошення, реквізит `msg` стає доступним в `this` і може бути використаний у шаблоні дочірнього компонента. До нього також можна отримати доступ у JavaScript через повернутий об’єкт `defineProps()`.
18 |
19 |
20 |
21 |
22 |
23 | ```js
24 | // в дочірньому компоненті
25 | export default {
26 | props: {
27 | msg: String
28 | },
29 | setup(props) {
30 | // доступ до props.msg
31 | }
32 | }
33 | ```
34 |
35 | Після оголошення, реквізит `msg` стає доступним в `this` і може бути використаний у шаблоні дочірнього компонента. Отримані реквізити передаються в `setup()` як перший аргумент.
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | ```js
44 | // в дочірньому компоненті
45 | export default {
46 | props: {
47 | msg: String
48 | }
49 | }
50 | ```
51 |
52 | Після оголошення, реквізит `msg` стає доступним в `this` і може бути використаний у шаблоні дочірнього компонента.
53 |
54 |
55 |
56 | Батьки можуть передавати реквізити дочірньому елементу так само як і атрибути. Щоб передати динамічне значення, ми також можемо використовувати синтаксис `v-bind`:
57 |
58 |
59 |
60 | ```vue-html
61 |
62 | ```
63 |
64 |
65 |
66 |
67 | ```vue-html
68 |
69 | ```
70 |
71 |
72 |
73 | А тепер спробуйте самі в редакторі.
74 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-13/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 | import ChildComp from './ChildComp.vue'
3 |
4 | export default {
5 | components: {
6 | ChildComp
7 | },
8 | setup() {
9 | const childMsg = ref('Поки що немає повідомлення від дочірнього компонента')
10 |
11 | return {
12 | childMsg
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-13/App/options.js:
--------------------------------------------------------------------------------
1 | import ChildComp from './ChildComp.vue'
2 |
3 | export default {
4 | components: {
5 | ChildComp
6 | },
7 | data() {
8 | return {
9 | childMsg: 'Поки що немає повідомлення від дочірнього компонента'
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-13/App/template.html:
--------------------------------------------------------------------------------
1 |
2 | {{ childMsg }}
3 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-13/ChildComp/composition.js:
--------------------------------------------------------------------------------
1 | export default {
2 | emits: ['response'],
3 | setup(props, { emit }) {
4 | emit('response', 'привіт від дочірнього компонента')
5 | return {}
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-13/ChildComp/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | emits: ['response'],
3 | created() {
4 | this.$emit('response', 'привіт від дочірнього компонента')
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-13/ChildComp/template.html:
--------------------------------------------------------------------------------
1 | Дочірній компонент
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-13/_hint/App/template.html:
--------------------------------------------------------------------------------
1 | childMsg = msg" />
2 | {{ childMsg }}
3 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-13/description.md:
--------------------------------------------------------------------------------
1 | # Випромінювання подій {#emits}
2 |
3 | Окрім отримання реквізитів, дочірній компонент також може випромінювати події батьківському компоненту:
4 |
5 |
6 |
7 |
8 | ```vue
9 |
16 | ```
17 |
18 |
19 |
20 |
21 |
22 | ```js
23 | export default {
24 | // оголосіть випромінювані події
25 | emits: ['response'],
26 | setup(props, { emit }) {
27 | // передайте аргумент
28 | emit('response', 'привіт від дочірнього компонента')
29 | }
30 | }
31 | ```
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | ```js
40 | export default {
41 | // оголосіть випромінювані події
42 | emits: ['response'],
43 | created() {
44 | // передайте аргумент
45 | this.$emit('response', 'привіт від дочірнього компонента')
46 | }
47 | }
48 | ```
49 |
50 |
51 |
52 | Першим аргументом функції `this.$emit()` `emit()` є назва події. Будь-які додаткові аргументи передаються слухачу події.
53 |
54 | Батьківський компонент може прослуховувати події дочірніх компонентів за допомогою `v-on` - тут обробник отримує додатковий аргумент від виклику дочірнього компонента і присвоює його локальному стану:
55 |
56 |
57 |
58 | ```vue-html
59 | childMsg = msg" />
60 | ```
61 |
62 |
63 |
64 |
65 | ```vue-html
66 | childMsg = msg">
67 | ```
68 |
69 |
70 |
71 | Тепер спробуйте самі в редакторі.
72 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-14/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 | import ChildComp from './ChildComp.vue'
3 |
4 | export default {
5 | components: {
6 | ChildComp
7 | },
8 | setup() {
9 | const msg = ref('з батьківського компонента')
10 |
11 | return {
12 | msg
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-14/App/options.js:
--------------------------------------------------------------------------------
1 | import ChildComp from './ChildComp.vue'
2 |
3 | export default {
4 | components: {
5 | ChildComp
6 | },
7 | data() {
8 | return {
9 | msg: 'з батьківського компонента'
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-14/App/template.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-14/ChildComp/template.html:
--------------------------------------------------------------------------------
1 | Запасний контент
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-14/_hint/App/template.html:
--------------------------------------------------------------------------------
1 | Повідомлення: {{ msg }}
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-14/description.md:
--------------------------------------------------------------------------------
1 | # Слоти {#slots}
2 |
3 | Окрім передачі даних через реквізити, батьківський компонент може також передавати фрагменти шаблону дочірньому компоненту через **слоти**:
4 |
5 |
6 |
7 | ```vue-html
8 |
9 | Це деякий слот контент!
10 |
11 | ```
12 |
13 |
14 |
15 |
16 | ```vue-html
17 |
18 | Це деякий слот контент!
19 |
20 | ```
21 |
22 |
23 |
24 | У дочірньому компоненті він може виводити контент слоту з батьківського, використовуючи елемент `` як вивід:
25 |
26 |
27 |
28 | ```vue-html
29 |
30 |
31 | ```
32 |
33 |
34 |
35 |
36 | ```vue-html
37 |
38 |
39 | ```
40 |
41 |
42 |
43 | Контент всередині `` буде розглядатися як "запасний": він буде показаний, якщо батьківський компонент не передав жодного контенту:
44 |
45 | ```vue-html
46 | Запасний контент
47 | ```
48 |
49 | Наразі ми не передаємо жодного контенту слоту до ``, тому ви маєте бачити запасний контент. Надайте деякий контент слоту дочірньому компоненту, використовуючи для цього стан `msg` батьківського компонента.
50 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-15/App/composition.js:
--------------------------------------------------------------------------------
1 | import JSConfetti from 'js-confetti'
2 |
3 | const confetti = new JSConfetti()
4 |
5 | export default {
6 | setup() {
7 | function showConfetti() {
8 | confetti.addConfetti()
9 | }
10 |
11 | showConfetti()
12 |
13 | return {
14 | showConfetti
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-15/App/options.js:
--------------------------------------------------------------------------------
1 | import JSConfetti from 'js-confetti'
2 |
3 | const confetti = new JSConfetti()
4 |
5 | export default {
6 | mounted() {
7 | this.showConfetti()
8 | },
9 | methods: {
10 | showConfetti() {
11 | confetti.addConfetti()
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-15/App/style.css:
--------------------------------------------------------------------------------
1 | h1 {
2 | text-align: center;
3 | cursor: pointer;
4 | margin-top: 3em;
5 | }
6 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-15/App/template.html:
--------------------------------------------------------------------------------
1 | 🎉 Вітаємо!
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-15/description.md:
--------------------------------------------------------------------------------
1 | # Ви зробили це! {#you-did-it}
2 |
3 | Ви закінчили тренувальний курс!
4 |
5 | На цьому етапі ви повинні мати уявлення про те, як працювати з Vue. Однак ми розглянули багато речей дуже швидко і не зупинилися на деталях, тому обов'язково продовжуйте вчитися! Наступне, що ви можете зробити:
6 |
7 | - Створіть справжній проєкт Vue на своєму комп'ютері, дотримуючись інструкцій [швидкого старту](/guide/quick-start).
8 |
9 | - Перегляньте [основний гід](/guide/essentials/application), який більш детально охоплює всі теми, які ми вивчили до цього часу, і багато іншого.
10 |
11 | - Ознайомтесь ще з іншими [практичними прикладами](/examples/).
12 |
13 | Ми вже не можемо дочекатися, щоб побачити, що ви побудуєте далі!
14 |
15 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-15/import-map.json:
--------------------------------------------------------------------------------
1 | {
2 | "imports": {
3 | "js-confetti": "https://cdn.jsdelivr.net/npm/js-confetti/+esm"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-2/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | // логіка компонента
6 | // оголосіть тут якийсь реактивний стан.
7 |
8 | return {
9 | // відкрийте для шаблону
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-2/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | // опції компоненти
3 | // оголосіть тут якийсь реактивний стан.
4 | }
5 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-2/App/template.html:
--------------------------------------------------------------------------------
1 | Зроби мене динамічним!
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-2/_hint/App/composition.js:
--------------------------------------------------------------------------------
1 | import { reactive, ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const counter = reactive({ count: 0 })
6 | const message = ref('Привіт, світе!')
7 |
8 | return {
9 | counter,
10 | message
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-2/_hint/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | message: 'Привіт, світе!',
5 | counter: {
6 | count: 0
7 | }
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-2/_hint/App/template.html:
--------------------------------------------------------------------------------
1 | {{ message }}
2 | Рахунок: {{ counter.count }}
3 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-3/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const titleClass = ref('title')
6 |
7 | return {
8 | titleClass
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-3/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | titleClass: 'title'
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-3/App/style.css:
--------------------------------------------------------------------------------
1 | .title {
2 | color: red;
3 | }
4 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-3/App/template.html:
--------------------------------------------------------------------------------
1 | Зробіть мене червоним
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-3/_hint/App/template.html:
--------------------------------------------------------------------------------
1 | Зробіть мене червоним
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-3/description.md:
--------------------------------------------------------------------------------
1 | # Прив'язування атрибутів {#attribute-bindings}
2 |
3 | Хвилясті дужки у Vue використовуються лише для інтерполяції тексту. Для того, щоб прив'язати атрибут до динамічного значення, ми використовуємо директиву `v-bind`:
4 |
5 | ```vue-html
6 |
7 | ```
8 |
9 | **Директива** - це спеціальний атрибут, який починається з префікса `v-`. Вона є частиною синтаксу темплейта Vue. Подібно до інтерполяції тексту, значеннями директив є вирази JavaScript, які мають доступ до стану компонента. Більш детально про `v-bind` та синтаксис директиви можна знайти в гіді про синтаксис шаблона .
10 |
11 | Частина, що після двокрапки (`:id`), є "аргументом" директиви. Тут атрибут `id` елемента буде синхронізовано з властивістю `dynamicId` зі стану компонента.
12 |
13 | Оскільки `v-bind` використовується дуже часто, він має спеціальний скорочений синтаксис:
14 |
15 | ```vue-html
16 |
17 | ```
18 |
19 | Тепер спробуйте додати динамічний `class`, прив'язавши його до ``, використовуючи властивість `titleClass` опції `data` референцію `titleClass` як її значення. Якщо він прив'язаний вірно, тоді текст стане червоним.
20 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-4/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const count = ref(0)
6 |
7 | return {
8 | count
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-4/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | count: 0
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-4/App/template.html:
--------------------------------------------------------------------------------
1 |
2 | Рахунок: {{ count }}
3 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-4/_hint/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const count = ref(0)
6 |
7 | function increment() {
8 | count.value++
9 | }
10 |
11 | return {
12 | count,
13 | increment
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-4/_hint/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | count: 0
5 | }
6 | },
7 | methods: {
8 | increment() {
9 | this.count++
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-4/_hint/App/template.html:
--------------------------------------------------------------------------------
1 | Рахунок: {{ count }}
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-5/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const text = ref('')
6 |
7 | function onInput(e) {
8 | text.value = e.target.value
9 | }
10 |
11 | return {
12 | text,
13 | onInput
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-5/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | text: ''
5 | }
6 | },
7 | methods: {
8 | onInput(e) {
9 | this.text = e.target.value
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-5/App/template.html:
--------------------------------------------------------------------------------
1 |
2 | {{ text }}
3 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-5/_hint/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const text = ref('')
6 |
7 | return {
8 | text
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-5/_hint/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | text: ''
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-5/_hint/App/template.html:
--------------------------------------------------------------------------------
1 |
2 | {{ text }}
3 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-5/description.md:
--------------------------------------------------------------------------------
1 | # Прив'язування елементів форми {#form-bindings}
2 |
3 | Використовуючи `v-bind` та `v-on` разом, ми можемо створити двосторонні прив'язки до полів введення форми:
4 |
5 | ```vue-html
6 |
7 | ```
8 |
9 |
10 |
11 | ```js
12 | methods: {
13 | onInput(e) {
14 | // v-on обробник отримує нативну подію DOM як аргумент.
15 | this.text = e.target.value
16 | }
17 | }
18 | ```
19 |
20 |
21 |
22 |
23 |
24 | ```js
25 | function onInput(e) {
26 | // v-on обробник отримує нативну подію DOM як аргумент
27 | text.value = e.target.value
28 | }
29 | ```
30 |
31 |
32 |
33 | Спробуйте вписати щось в полі введення - ви повинні бачити текст в ``, який оновлюється під час введення.
34 |
35 | Щоб спростити двостороннє прив’язування, Vue надає директиву `v-model`, яка, по суті, є синтетичним цукром для вищесказаного:
36 |
37 | ```vue-html
38 |
39 | ```
40 |
41 | `v-model` автоматично синхронізує значення ` ` з прив'язаним станом, тож для цього нам не потрібно більше використовувати обробника подій.
42 |
43 | `v-model` працює не лише з текстовими полями вводу, а також з іншими елементами такими як чекбокси, радіо кнопки та випадаючі списки. Більш детально ми це описали в гіді про прив'язку елементів введення .
44 |
45 | Тепер спробуйте змінити код, використовуючи `v-model`.
46 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-6/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const awesome = ref(true)
6 |
7 | function toggle() {
8 | // ...
9 | }
10 |
11 | return {
12 | awesome,
13 | toggle
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-6/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | awesome: true
5 | }
6 | },
7 | methods: {
8 | toggle() {
9 | // ...
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-6/App/template.html:
--------------------------------------------------------------------------------
1 | Перемкнути
2 |
Vue - це круто!
3 | Ой, ні 😢
4 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-6/_hint/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const awesome = ref(true)
6 |
7 | function toggle() {
8 | awesome.value = !awesome.value
9 | }
10 |
11 | return {
12 | awesome,
13 | toggle
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-6/_hint/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | awesome: true
5 | }
6 | },
7 | methods: {
8 | toggle() {
9 | this.awesome = !this.awesome
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-6/_hint/App/template.html:
--------------------------------------------------------------------------------
1 | Перемкнути
2 | Vue - це круто!
3 | Ой, ні 😢
4 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-6/description.md:
--------------------------------------------------------------------------------
1 | # Умовний рендеринг {#conditional-rendering}
2 |
3 | Ми можемо використовувати `v-if` директиву для умовного рендерингу елемента:
4 |
5 | ```vue-html
6 | Vue - це круто!
7 | ```
8 |
9 | Цей елемент `` буде згенеровано лише якщо значення `awesome` є [правдивим](https://developer.mozilla.org/en-US/docs/Glossary/Truthy). Якщо ж `awesome` змінюється на [неправдиве значення](https://developer.mozilla.org/en-US/docs/Glossary/Falsy), тоді цей елемент буде видалено з DOM.
10 |
11 | Також можливо використовувати `v-else` та `v-else-if`, щоб вказати альтернативні варіанти умови:
12 |
13 | ```vue-html
14 | Vue - це круто!
15 | Ой, ні 😢
16 | ```
17 |
18 | Наразі, демо показує обидва елементи `` одночасно, і кнопка нічого не робить. Спробуйте додати директиви `v-if` та `v-else` і напишіть метод `toggle()` таким чином, щоб кнопка перемикала ці елементи.
19 |
20 | Більш детально про `v-if` в гіді про умовний рендеринг .
21 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-7/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | // надай кожному завданню унікальний id
6 | let id = 0
7 |
8 | const newTodo = ref('')
9 | const todos = ref([
10 | { id: id++, text: 'Вивчити HTML' },
11 | { id: id++, text: 'Вивчити JavaScript' },
12 | { id: id++, text: 'Вивчити Vue' }
13 | ])
14 |
15 | function addTodo() {
16 | // ...
17 | newTodo.value = ''
18 | }
19 |
20 | function removeTodo(todo) {
21 | // ...
22 | }
23 |
24 | return {
25 | newTodo,
26 | todos,
27 | addTodo,
28 | removeTodo
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-7/App/options.js:
--------------------------------------------------------------------------------
1 | // надай кожному завданню унікальний id
2 | let id = 0
3 |
4 | export default {
5 | data() {
6 | return {
7 | newTodo: '',
8 | todos: [
9 | { id: id++, text: 'Вивчити HTML' },
10 | { id: id++, text: 'Вивчити JavaScript' },
11 | { id: id++, text: 'Вивчити Vue' }
12 | ]
13 | }
14 | },
15 | methods: {
16 | addTodo() {
17 | // ...
18 | this.newTodo = ''
19 | },
20 | removeTodo(todo) {
21 | // ...
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-7/App/template.html:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 | {{ todo.text }}
8 | X
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-7/_hint/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | // надай кожному завданню унікальний id
6 | let id = 0
7 |
8 | const newTodo = ref('')
9 | const todos = ref([
10 | { id: id++, text: 'Вивчити HTML' },
11 | { id: id++, text: 'Вивчити JavaScript' },
12 | { id: id++, text: 'Вивчити Vue' }
13 | ])
14 |
15 | function addTodo() {
16 | todos.value.push({ id: id++, text: newTodo.value })
17 | newTodo.value = ''
18 | }
19 |
20 | function removeTodo(todo) {
21 | todos.value = todos.value.filter((t) => t !== todo)
22 | }
23 |
24 | return {
25 | newTodo,
26 | todos,
27 | addTodo,
28 | removeTodo
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-7/_hint/App/options.js:
--------------------------------------------------------------------------------
1 | // надай кожному завданню унікальний id
2 | let id = 0
3 |
4 | export default {
5 | data() {
6 | return {
7 | newTodo: '',
8 | todos: [
9 | { id: id++, text: 'Вивчити HTML' },
10 | { id: id++, text: 'Вивчити JavaScript' },
11 | { id: id++, text: 'Вивчити Vue' }
12 | ]
13 | }
14 | },
15 | methods: {
16 | addTodo() {
17 | this.todos.push({ id: id++, text: this.newTodo })
18 | this.newTodo = ''
19 | },
20 | removeTodo(todo) {
21 | this.todos = this.todos.filter((t) => t !== todo)
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-7/description.md:
--------------------------------------------------------------------------------
1 | # Рендеринг списків {#list-rendering}
2 |
3 | Ми можемо використовувати директиву `v-for` для рендерингу списку елементів на основі вихідного масиву
4 |
5 | ```vue-html
6 |
7 |
8 | {{ todo.text }}
9 |
10 |
11 | ```
12 |
13 | Тут `todo` — це локальна змінна, що представляє собою елемент масиву, над яким відбувається ітерація. Вона доступна лише в елементі `v-for` або всередині нього, подібно до області видимості функції.
14 |
15 | Зверніть увагу, що ми також надаємо кожному об’єкту todo унікальний `id` і прив’язуємо його як спеціальний атрибут `key` для кожного ``. `key` дозволяє Vue точно переміщувати кожен ` ` відповідно до позиції його відповідного об’єкта в масиві.
16 |
17 | Оновити список можна двома способами:
18 |
19 | 1. Викликати [методи мутації](https://stackoverflow.com/questions/9009879/which-javascript-array-functions-are-mutating) вихідного масиву:
20 |
21 |
22 |
23 | ```js
24 | todos.value.push(newTodo)
25 | ```
26 |
27 |
28 |
29 |
30 | ```js
31 | this.todos.push(newTodo)
32 | ```
33 |
34 |
35 |
36 | 2. Замінити масив на новий:
37 |
38 |
39 |
40 | ```js
41 | todos.value = todos.value.filter(/* ... */)
42 | ```
43 |
44 |
45 |
46 |
47 | ```js
48 | this.todos = this.todos.filter(/* ... */)
49 | ```
50 |
51 |
52 |
53 | У нас є простий список завдань — спробуйте реалізувати логіку для методів `addTodo()` та `removeTodo()`, щоб він запрацював!
54 |
55 | Більш детально про `v-for` у гіді про рендеринг списків .
56 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-8/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | let id = 0
6 |
7 | const newTodo = ref('')
8 | const hideCompleted = ref(false)
9 | const todos = ref([
10 | { id: id++, text: 'Вивчити HTML', done: true },
11 | { id: id++, text: 'Вивчити JavaScript', done: true },
12 | { id: id++, text: 'Вивчити Vue', done: false }
13 | ])
14 |
15 | function addTodo() {
16 | todos.value.push({ id: id++, text: newTodo.value, done: false })
17 | newTodo.value = ''
18 | }
19 |
20 | function removeTodo(todo) {
21 | todos.value = todos.value.filter((t) => t !== todo)
22 | }
23 |
24 | return {
25 | newTodo,
26 | hideCompleted,
27 | todos,
28 | addTodo,
29 | removeTodo
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-8/App/options.js:
--------------------------------------------------------------------------------
1 | let id = 0
2 |
3 | export default {
4 | data() {
5 | return {
6 | newTodo: '',
7 | hideCompleted: false,
8 | todos: [
9 | { id: id++, text: 'Вивчити HTML', done: true },
10 | { id: id++, text: 'Вивчити JavaScript', done: true },
11 | { id: id++, text: 'Вивчити Vue', done: false }
12 | ]
13 | }
14 | },
15 | computed: {
16 | // ...
17 | },
18 | methods: {
19 | addTodo() {
20 | this.todos.push({ id: id++, text: this.newTodo, done: false })
21 | this.newTodo = ''
22 | },
23 | removeTodo(todo) {
24 | this.todos = this.todos.filter((t) => t !== todo)
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-8/App/style.css:
--------------------------------------------------------------------------------
1 | .done {
2 | text-decoration: line-through;
3 | }
4 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-8/App/template.html:
--------------------------------------------------------------------------------
1 |
5 |
12 |
13 | {{ hideCompleted ? 'Показати всі' : 'Сховати виконані' }}
14 |
15 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-8/_hint/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref, computed } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | let id = 0
6 |
7 | const newTodo = ref('')
8 | const hideCompleted = ref(false)
9 | const todos = ref([
10 | { id: id++, text: 'Вивчити HTML', done: true },
11 | { id: id++, text: 'Вивчити JavaScript', done: true },
12 | { id: id++, text: 'Вивчити Vue', done: false }
13 | ])
14 |
15 | const filteredTodos = computed(() => {
16 | return hideCompleted.value
17 | ? todos.value.filter((t) => !t.done)
18 | : todos.value
19 | })
20 |
21 | function addTodo() {
22 | todos.value.push({ id: id++, text: newTodo.value, done: false })
23 | newTodo.value = ''
24 | }
25 |
26 | function removeTodo(todo) {
27 | todos.value = todos.value.filter((t) => t !== todo)
28 | }
29 |
30 | return {
31 | newTodo,
32 | hideCompleted,
33 | todos,
34 | filteredTodos,
35 | addTodo,
36 | removeTodo
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-8/_hint/App/options.js:
--------------------------------------------------------------------------------
1 | let id = 0
2 |
3 | export default {
4 | data() {
5 | return {
6 | newTodo: '',
7 | hideCompleted: false,
8 | todos: [
9 | { id: id++, text: 'Вивчити HTML', done: true },
10 | { id: id++, text: 'Вивчити JavaScript', done: true },
11 | { id: id++, text: 'Вивчити Vue', done: false }
12 | ]
13 | }
14 | },
15 | computed: {
16 | filteredTodos() {
17 | return this.hideCompleted
18 | ? this.todos.filter((t) => !t.done)
19 | : this.todos
20 | }
21 | },
22 | methods: {
23 | addTodo() {
24 | this.todos.push({ id: id++, text: this.newTodo, done: false })
25 | this.newTodo = ''
26 | },
27 | removeTodo(todo) {
28 | this.todos = this.todos.filter((t) => t !== todo)
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-8/_hint/App/template.html:
--------------------------------------------------------------------------------
1 |
5 |
12 |
13 | {{ hideCompleted ? 'Показати всі' : 'Сховати виконані' }}
14 |
15 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-9/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const pElementRef = ref(null)
6 |
7 | return {
8 | pElementRef
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-9/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | // ...
3 | }
4 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-9/App/template.html:
--------------------------------------------------------------------------------
1 | Привіт
2 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-9/_hint/App/composition.js:
--------------------------------------------------------------------------------
1 | import { ref, onMounted } from 'vue'
2 |
3 | export default {
4 | setup() {
5 | const pElementRef = ref(null)
6 |
7 | onMounted(() => {
8 | pElementRef.value.textContent = 'Змонтовано!'
9 | })
10 |
11 | return {
12 | pElementRef
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/tutorial/src/step-9/_hint/App/options.js:
--------------------------------------------------------------------------------
1 | export default {
2 | mounted() {
3 | this.$refs.pElementRef.textContent = 'Змонтовано!'
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/tutorial/tutorial.data.ts:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { createMarkdownRenderer } from 'vitepress'
3 | import { readExamples, ExampleData } from '../examples/examples.data'
4 |
5 | export declare const data: Record
6 |
7 | export default {
8 | watch: './src/**',
9 | async load() {
10 | const md = await createMarkdownRenderer(process.cwd(), undefined, '/')
11 | const files = readExamples(path.resolve(__dirname, './src'))
12 | for (const step in files) {
13 | const stepFiles = files[step]
14 | const desc = stepFiles['description.md'] as string
15 | if (desc) {
16 | stepFiles['description.md'] = md.render(desc)
17 | }
18 | }
19 | return files
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "dist",
4 | "target": "esnext",
5 | "module": "esnext",
6 | "moduleResolution": "node",
7 | "esModuleInterop": true,
8 | "resolveJsonModule": true,
9 | "allowJs": true,
10 | "strict": true,
11 | "jsx": "preserve",
12 | "baseUrl": ".",
13 | "paths": {
14 | "@theme/*": [".vitepress/theme/*"]
15 | }
16 | },
17 | "include": ["env.d.ts", "src/**/*", ".vitepress/**/*"]
18 | }
19 |
--------------------------------------------------------------------------------