how to master cursor

-

what’s the cursor

现代AI编程工具,最强copilot,甚至是driver

basic info

address: cursor link platform supported: Windows/MacOS/Linux pricing: $20(可以走外币信用卡) / $0

equipment

  1. payment
  2. doing well in English ? example
  3. being lazy
  4. fast proxy speed

master in cursor

configuration

model choosing

at this time, please use claude-3-5-sonnet-20241022 only

usage

  1. auto generation just tab it! (50% percent tab engineer) comment usage

  2. ctrl+K selection to ask question (选中提问) when to use: very simple problem with no need for context

  3. ctrl+L just chat ask some knowledge without coding

  4. composer(ctrl+I/ctrl+shift+I) the most important/powerfull part! add file/context/all the context you need to provide info to cursor

  5. image generation
  6. review component

most important

prompt

talk is cheap, show you the code

  1. zero to start prompts: I am a frontend developer and a cursor newbie, and I want to know how to quickly use cursor(the AI IDE) for development, please make a tutorial project ( use vite / vue framwork) and tell me step by step

    Answers:

I’ll help you create a simple Vue 3 project using Vite and show you how to effectively use Cursor’s AI capabilities. Let’s build a simple task management application.

Tutorial: Building a Task Manager with Vue 3 + Cursor AI

Step 1: Project Setup

First, open your terminal and create a new Vite + Vue project:

npm create vite@latest cursor-task-manager -- --template vue

cd cursor-task-manager

npm install

Step 2: Understanding Cursor’s Key Features

Before we start coding, let’s understand some key Cursor commands:

Step 3: Creating Components

Let’s create our first component. In Cursor, you can use AI to help generate components. Create a new file:

TaskInput.vue1/1

<template>

  <div class="task-input">

    <input

      type="text"

      v-model="newTask"

      @keyup.enter="addTask"

      placeholder="Enter a new task..."

    >

    <button @click="addTask">Add Task</button>

  </div>

</template>



<script setup>

import { ref } from 'vue'



const newTask = ref('')

const emit = defineEmits(['add-task'])



const addTask = () => {

  if (newTask.value.trim()) {

    emit('add-task', newTask.value)

    newTask.value = ''

  }

}

</script>



<style scoped>

.task-input {

  margin: 20px 0;

  display: flex;

  gap: 10px;

}



input {

  flex: 1;

  padding: 8px;

  border: 1px solid #ddd;

  border-radius: 4px;

}



button {

  padding: 8px 16px;

  background-color: #4CAF50;

  color: white;

  border: none;

  border-radius: 4px;

  cursor: pointer;

}



button:hover {

  background-color: #45a049;

}

</style>

Now create a TaskList component:

TaskList.vue1/1

<template>

  <div class="task-list">

    <div v-for="task in tasks" :key="task.id" class="task-item">

      <input

        type="checkbox"

        :checked="task.completed"

        @change="toggleTask(task.id)"

      >

      <span :class="{ completed: task.completed }"></span>

      <button @click="deleteTask(task.id)" class="delete-btn">×</button>

    </div>

  </div>

</template>



<script setup>

defineProps({

  tasks: {

    type: Array,

    required: true

  }

})



const emit = defineEmits(['toggle-task', 'delete-task'])



const toggleTask = (id) => {

  emit('toggle-task', id)

}



const deleteTask = (id) => {

  emit('delete-task', id)

}

</script>



<style scoped>

.task-list {

  margin-top: 20px;

}



.task-item {

  display: flex;

  align-items: center;

  padding: 10px;

  border-bottom: 1px solid #eee;

  gap: 10px;

}



.completed {

  text-decoration: line-through;

  color: #888;

}



.delete-btn {

  margin-left: auto;

  background-color: #ff4444;

  color: white;

  border: none;

  border-radius: 50%;

  width: 24px;

  height: 24px;

  cursor: pointer;

}



.delete-btn:hover {

  background-color: #cc0000;

}

</style>

Update the App.vue file:

App.vue1/1

<template>

  <div class="task-input">

    <input

      type="text"

      v-model="newTask"

      @keyup.enter="addTask"

      placeholder="Enter a new task..."

    >

    <button @click="addTask">Add Task</button>

  </div>

</template>



<script setup>

import { ref } from 'vue'



const newTask = ref('')

const emit = defineEmits(['add-task'])



const addTask = () => {

  if (newTask.value.trim()) {

    emit('add-task', newTask.value)

    newTask.value = ''

  }

}

</script>



<style scoped>

.task-input {

  margin: 20px 0;

  display: flex;

  gap: 10px;

}



input {

  flex: 1;

  padding: 8px;

  border: 1px solid #ddd;

  border-radius: 4px;

}



button {

  padding: 8px 16px;

  background-color: #4CAF50;

  color: white;

  border: none;

  border-radius: 4px;

  cursor: pointer;

}



button:hover {

  background-color: #45a049;

}

</style>

Step 4: Using Cursor AI Features

Now let’s explore how to use Cursor’s AI features effectively:

<script setup>
import { ref, onMounted, watch } from 'vue'
// ... existing imports ...

const tasks = ref([])

// Load tasks from localStorage when app starts
onMounted(() => {
  const savedTasks = localStorage.getItem('tasks')
  if (savedTasks) {
    tasks.value = JSON.parse(savedTasks)
  }
})

// Watch tasks for changes and save to localStorage
watch(tasks.value, () => {
  localStorage.setItem('tasks', JSON.stringify(tasks.value))
}, { deep: true })

// ... rest of your existing code ...
</script>

Here’s what these changes do:

  1. Import onMounted and watch from Vue
  2. onMounted hook loads saved tasks when the app starts
  3. watch saves tasks to localStorage whenever they change
    • deep: true ensures we watch for changes in nested properties
    • We use JSON.stringify/parse because localStorage only stores strings

Note: If you want to be extra safe with localStorage, you could wrap the operations in try-catch blocks:

<script setup>
import { ref, onMounted, watch } from 'vue'
// ... existing imports ...

const tasks = ref([])

onMounted(() => {
  try {
    const savedTasks = localStorage.getItem('tasks')
    if (savedTasks) {
      tasks.value = JSON.parse(savedTasks)
    }
  } catch (e) {
    console.error('Error loading tasks:', e)
  }
})

watch(tasks.value, () => {
  try {
    localStorage.setItem('tasks', JSON.stringify(tasks.value))
  } catch (e) {
    console.error('Error saving tasks:', e)
  }
}, { deep: true })

// ... rest of your existing code ...
</script>

Now your tasks will persist even when the browser is closed and reopened!

I’ll help you add drag and drop functionality using Vue Draggable (which is a Vue wrapper for Sortable.js). First, you’ll need to install the package for Vue 3:

npm install vuedraggable@next

Then, here are the changes needed:

<template>
  <div class="task-list">
    <draggable
      v-model="taskList"
      item-key="id"
      handle=".drag-handle"
      @change="emitUpdate"
    >
      <template #item="{ element }">
        <div class="task-item">
          <span class="drag-handle">⋮⋮</span>
          <input
            type="checkbox"
            :checked="element.completed"
            @change="$emit('toggle-task', element.id)"
          >
          <span :class="{ completed: element.completed }">
            
          </span>
          <button @click="$emit('delete-task', element.id)">Delete</button>
        </div>
      </template>
    </draggable>
  </div>
</template>

<script setup>
import { computed } from 'vue'
import draggable from 'vuedraggable'

const props = defineProps({
  tasks: {
    type: Array,
    required: true
  }
})

const emit = defineEmits(['toggle-task', 'delete-task', 'update-tasks'])

// Create computed property for two-way binding
const taskList = computed({
  get: () => props.tasks,
  set: (value) => emit('update-tasks', value)
})

// Emit changes when drag ends
const emitUpdate = () => {
  emit('update-tasks', taskList.value)
}
</script>

<style scoped>
.task-item {
  display: flex;
  align-items: center;
  padding: 10px;
  margin: 5px 0;
  background: #f5f5f5;
  border-radius: 4px;
}

.drag-handle {
  cursor: move;
  padding: 0 10px;
  color: #999;
  user-select: none;
}

.completed {
  text-decoration: line-through;
  color: #999;
}
</style>

And update your App.vue to handle the new event:

<template>
  <div class="app">
    <h1>Task Manager</h1>
    <TaskInput @add-task="addTask" />
    <TaskList
      :tasks="tasks"
      @toggle-task="toggleTask"
      @delete-task="deleteTask"
      @update-tasks="updateTasks"
    />
  </div>
</template>

<script setup>
// ... existing imports and code ...

// Add this new function
const updateTasks = (newTasks) => {
  tasks.value = newTasks
}

// ... rest of your existing code ...
</script>

Here’s what these changes do:

  1. We’re using vuedraggable component to wrap our task items
  2. The drag handle (⋮⋮) provides a visual indicator for draggable areas
  3. item-key prop is required for Vue 3 to track items
  4. We use a computed property taskList for two-way binding
  5. The @change event emits updates to the parent when tasks are reordered
  6. New styling makes the list more visually appealing and draggable

Key features:

You might also want to add some transition animations. Here’s optional CSS you can add to the TaskList component:

<style scoped>
/* ... existing styles ... */

.task-item.sortable-ghost {
  opacity: 0.5;
  background: #c8ebfb;
}

.task-item.sortable-drag {
  cursor: grabbing;
  background: #fff;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
</style>

This will add nice visual feedback during dragging operations. The ghost shows where the item will be dropped, and the dragged item gets a shadow effect.

Remember to handle the items carefully in your localStorage implementation - the new order will automatically be saved thanks to your existing watch setup.

  1. Improve Type Safety
    • Add TypeScript support to get better type checking and IDE support
    • Define interfaces for the task structure
  2. Local Storage Management
    • Move localStorage logic into a separate composable for better reusability and separation of concerns
    • Add error handling for quota exceeded cases

Here’s how we could implement these improvements:

First, create a new composable for localStorage management:

import { ref, watch } from 'vue'

export function useLocalStorage<T>(key: string, defaultValue: T) {
  const data = ref<T>(defaultValue)

  // Load initial data
  try {
    const saved = localStorage.getItem(key)
    if (saved) {
      data.value = JSON.parse(saved)
    }
  } catch (e) {
    console.error(`Error loading ${key} from localStorage:`, e)
  }

  // Watch for changes
  watch(
    () => data.value,
    (newValue) => {
      try {
        localStorage.setItem(key, JSON.stringify(newValue))
      } catch (e) {
        if (e.name === 'QuotaExceededError') {
          console.error('localStorage quota exceeded')
          // Handle quota exceeded (e.g., clear old data or notify user)
        } else {
          console.error(`Error saving ${key} to localStorage:`, e)
        }
      }
    },
    { deep: true }
  )

  return data
}
  1. Add Task Type Definitions:
export interface Task {
  id: number
  text: string
  completed: boolean
}
  1. Improve Error Handling in TaskList.vue
    • Add validation for the draggable operations
    • Improve prop type definitions

Here’s the improved TaskList component:

<script setup lang="ts">
import { computed } from 'vue'
import draggable from 'vuedraggable'
import type { Task } from '../types/task'

const props = defineProps<{
  tasks: Task[]
}>()

const emit = defineEmits<{
  'toggle-task': [id: number]
  'delete-task': [id: number]
  'update-tasks': [tasks: Task[]]
}>()

const taskList = computed({
  get: () => props.tasks,
  set: (value) => {
    // Validate the new task list before emitting
    if (Array.isArray(value) && value.every(task =>
      typeof task.id === 'number' &&
      typeof task.text === 'string' &&
      typeof task.completed === 'boolean'
    )) {
      emit('update-tasks', value)
    } else {
      console.error('Invalid task list structure')
    }
  }
})

const emitUpdate = () => {
  emit('update-tasks', taskList.value)
}
</script>
  1. Improve App.vue State Management Replace the current state management with the new composable:
<script setup lang="ts">
import { useLocalStorage } from './composables/useLocalStorage'
import type { Task } from './types/task'
import TaskInput from './components/TaskInput.vue'
import TaskList from './components/TaskList.vue'

const tasks = useLocalStorage<Task[]>('tasks', [])

const addTask = (text: string) => {
  tasks.value.push({
    id: Date.now(),
    text,
    completed: false
  })
}

// ... rest of the component logic
</script>
  1. Additional Improvements:
  1. Performance Improvements:
    • Add virtual scrolling for large task lists
    • Implement pagination or infinite scroll
    • Add debouncing for save operations
    • Use v-once for static content
    • Consider using v-show instead of v-if for frequently toggled elements

These improvements would make the application more robust, maintainable, and user-friendly while following Vue.js best practices.

Would you like me to elaborate on any of these improvements or provide more specific implementation details for any particular aspect?

Step 5: Running the Project

Run the development server:

npm run dev

Tips for Using Cursor Effectively

Practice Exercises

Try these exercises to get familiar with Cursor:

For each exercise, try using different Cursor AI features to help you implement the solution.

This tutorial project provides a foundation for understanding how to use Cursor effectively in your Vue development workflow. As you become more comfortable with the AI features, you’ll find that they can significantly speed up your development process.

Would you like me to explain any part in more detail or help you implement any of the practice exercises?

project refactor

Question: @open-light-youling the code is equipped with FSD(feature sliced design), so please help me practice the fsd principle @Web

Answers: I’ll help you understand and practice FSD (Feature-Sliced Design) principles based on the provided codebase. Let’s analyze the current structure and make recommendations.

Current FSD Structure Analysis

From the codebase, I can see that the project already follows some FSD principles, particularly in the layer organization. Let’s break down the key FSD concepts:

  1. Layers (Слои) From the README:
**app**:这是应用程序逻辑初始化的地方。提供者、路由器、全局样式、全局类型声明等都在这里定义。它充当应用程序的入口点。
**pages**: 这个很容易理解,就是应用程序中的页面,与路由挂钩
**widgets**: 这个是页面上使用的独立 UI 组件,比如按钮(带防抖的按钮,带 loading 的按钮)、表单(能够遍历表单项的表单)等,或者通用表格(能够请求后端结构完成表格基本配置的组件)。与业务无关与整个应用的有关。会在很多个功能或模块中使用
**feature** 这一层

The project follows the main FSD layers:

  1. Project Structure The current structure follows FSD’s layer organization:
    src/
      ├── app/          # Application layer
      ├── pages/        # Pages layer
      ├── widgets/      # Widgets layer
      ├── features/     # Features layer
      ├── entities/     # Entities layer
      ├── shared/       # Shared layer
    

Recommendations for Better FSD Implementation

  1. Proper Segment Organization Each slice should have standard segments:
    feature/
      ├── ui/          # UI components
      ├── model/       # Business logic
      ├── lib/         # Utils/helpers
      ├── api/         # API requests
      ├── config/      # Configuration
    
  2. Public API Pattern Each feature/entity should expose its public API through an index.ts file:
// feature/index.ts
export * from './ui'
export * from './model'
export * from './lib'
// Only expose what's needed
  1. Layer Dependencies Follow the strict dependency rule:
    app → pages → widgets → features → entities → shared
    
  2. Example Implementation Let’s take the dialog feature as an example:
// src/features/dialog/
├── ui/
   ├── dialog-window/
   ├── dialog-input/
   └── index.ts
├── model/
   ├── store/
   ├── types.ts
   └── index.ts
├── api/
   ├── send-message.ts
   └── index.ts
└── index.ts
  1. Shared Layer Organization The shared layer should be organized by type:
// src/shared/
├── api/           # API utilities
├── ui/            # UI components
├── lib/           # Utilities
└── config/        # Configurations

Practical Recommendations

  1. Move Business Logic to Model Instead of keeping logic in components, move it to the model segment:
// features/dialog/model/use-dialog.ts
export function useDialog() {
  const sendMessage = () => {
    // Message sending logic
  }

  const handleResponse = () => {
    // Response handling logic
  }

  return {
    sendMessage,
    handleResponse
  }
}
  1. Implement Public API Pattern For each feature:
// features/dialog/index.ts
export { DialogWindow } from './ui/dialog-window'
export { useDialog } from './model/use-dialog'
export type { DialogMessage } from './model/types'
  1. Use Composition API with FSD Keep components focused on presentation:
<script setup lang="ts">
import { useDialog } from '../model/use-dialog'

const { sendMessage, handleResponse } = useDialog()
</script>
  1. Proper Type Organization Keep types in their respective segments:
// entities/dialog/model/types.ts
export interface DialogMessage {
  id: string
  content: string
  timestamp: number
}

By following these principles, you’ll have a more maintainable and scalable application architecture. The key is to maintain proper layer isolation and clear public APIs for each slice.

Would you like me to elaborate on any of these points or provide more specific examples for your codebase?

by using composer, it provide the information as below:

I’ll help you improve the codebase according to Feature-Sliced Design (FSD) principles. Here are the key recommendations:

The current structure has some FSD layers but needs better organization. Here’s how we can improve it:

index.ts1/2

// Create an app entry point that composes all providers
import { createApp } from 'vue'

import { setupProviders } from './providers'

import { App } from './app.vue'



export function initApp() {

  const app = createApp(App)

  setupProviders(app)

  return app

}

my change: move the main.ts’s content into app/index.ts

Create better separation in shared layer:

index.ts1/2

Restructure dialog feature:

index.ts1/2

Better organize business entities:

index.ts1/2

Improve page organization:

index.ts1/2

Add reusable complex components:

index.ts1/2

Key Principles to Follow:

Additional Recommendations:

Would you like me to provide more specific examples for any of these areas or focus on a particular part of the codebase?

Ran capabilities

Iterate on Lints

I’ll help fix the linter errors. The main issues are missing modules and incorrect import syntax. Let’s fix each file:

Additionally, you’ll need to create some missing files:

index.ts1/1

The key principles to fix these errors are:

Would you like me to provide more details about implementing any of these files or additional fixes?

questions:

please help me for Additional Recommendations you have provided

Answers:

I’ll help provide more detailed recommendations for improving the codebase according to FSD principles:

Key Implementation Guidelines:

Would you like me to provide more specific examples for any of these areas or focus on implementing a particular part?

Ran capabilities

Iterate on Lints

I’ll help fix the linter errors by creating the missing files and fixing the type declarations:

These changes should resolve the linter errors by:

Would you like me to explain any of these changes in more detail or help with implementing other parts of the codebase?

questions:

why you add providers in app directory, is it really needed for FSD project? I just put the plugins/router/store plainly in app directory, what’s the best practice for managing app folders?

Answers:

You raise a good point about the app directory organization. In FSD, the app layer should be kept minimal and focused on application initialization and configuration. Let me explain the best practices:

Here’s a more FSD-aligned structure for the app layer:

src/app/

├── index.ts              # Main app initialization

├── app.vue              # Root component

├── styles/              # Global styles

├── router/              # Router configuration

├── store/               # Store initialization

├── plugins/             # Plugin setup

└── config/              # App-wide configuration

The key principles for organizing the app layer:

Your current approach of having plugins/router/store directly in the app directory is actually more aligned with FSD principles than my earlier suggestion with providers. The key is to keep the app layer as simple and focused as possible.

Question

@pages @Codebase for FSD(feature sliced design) I now have a problem, I have found that my pages have too much ui in their slice subdirectory, and I don’t have the widgets layer. Because I think the widgets layer need to be reusable, and the pages’ ui is not reusable, so I don’t need to move some ui/logic into widget part. Is it right? shall I build widgets layer? what’s the best practice of it?

Answer Based on your codebase and FSD principles, let me help clarify the distinction between pages and widgets layers and provide recommendations:

Your pages layer currently contains a lot of UI components that could potentially be abstracted. For example:

index.vue1/2

Some components from your pages that could be moved to widgets:

index.ts1/2

index.ts1/2

Pages should only contain:

Example of a cleaner page:

index.vue2/2

Key Principles for Widgets:

Recommendations for Your Project:

Would you like me to provide more specific examples of how to refactor any particular part of your codebase into widgets?

Ran capabilities

Iterate on Lints

Let me help fix these linter errors by creating and updating the necessary files:

These changes should resolve the linter errors by:

Would you like me to provide more details about any of these changes or help with implementing other parts?

  1. source code reading