Skip to content

Commit fc6505f

Browse files
committed
feat: support some frameworks
1 parent 7700eaa commit fc6505f

28 files changed

+1313
-133
lines changed

README.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22
一款AI驱动的祖传代码炼金师,将优雅代码『精心』重构为屎山💩。An AI-powered legacy code alchemist that carefully transforms clean code into shit code.
33

44
## 简介
5-
> 还在担心 AI 时代抢走你的饭碗? 那就用魔法打败魔法。
6-
-- 鲁迅
7-
8-
ShitCodify是一个能够将正常、易读、易维护的代码转换为难以理解、难以维护但仍然能够正常工作的"屎山代码"的工具。它利用大型语言模型(如GPT-4)来分析你的代码,并应用各种"反模式"和不良实践来降低代码的可读性和可维护性,同时保持代码的功能不变。
5+
ShitCodify是一个能够将正常、易读、易维护的代码转换为难以理解、难以维护但仍然能够正常工作的"屎山代码"的工具。
6+
它利用大型语言模型(如GPT-4)来分析你的代码,并应用各种"反模式"和不良实践来降低代码的可读性和可维护性,同时保持代码的功能不变。
97

108
## 为什么需要这个工具?
119
- 工作保障计划: 确保你的代码像谜题一样存在, 提升你在公司不可替代的地位
@@ -26,13 +24,19 @@ ShitCodify是一个能够将正常、易读、易维护的代码转换为难以
2624

2725
## 如何使用?
2826
当前 ShitCodify 还不支持像 cursor, trae 那样的 AI Agent 模式, 现在的实现仅仅只是通过codebase生成一段Prompt。
29-
直接访问 https://stepfenshawn.github.io/ShitCodify/#/ 生成 Prompt 后将其复制给大模型使用。
27+
直接访问 https://stepfenshawn.github.io/ShitCodify/#/ 生成 Prompt 后将其复制给大模型使用。
28+
![截图](img/screenshot3.png)
3029

3130

3231
## "屎山"程度配置
3332
可以根据需要自定义"屎山"程度:
34-
![配置示例](img/screenshot1.png)
35-
33+
![配置示例](img/screenshot1.png)
34+
自定义跳转到的大模型网页:
35+
![配置示例](img/screenshot2.png)
36+
示例:
37+
![正常代码](img/example1.png)
38+
通过gpt-4o转化后:
39+
![屎山代码](img/shit1.png)
3640
## Build
3741
```sh
3842
git clone [email protected]:StepfenShawn/ShitCodify.git
@@ -70,7 +74,7 @@ npm run build
7074
4. 构建项目
7175
5. 将构建结果部署到 gh-pages 分支
7276

73-
这样,您只需要关注代码开发,无需手动部署。项目会自动部署到 GitHub Pages 上,访问地址为:https://stepfenshawn.github.io/ShitCodify/
77+
这样,您只需要关注代码开发,无需手动部署。项目会自动部署到 GitHub Pages 上,访问地址为:https://stepfenshawn.github.io/ShitCodify/#/
7478

7579
## 许可证
7680
本项目采用MIT许可证。

img/example1.png

174 KB
Loading

img/screenshot2.png

23.5 KB
Loading

img/screenshot3.png

161 KB
Loading

img/shit1.png

279 KB
Loading

src/App.vue

Lines changed: 103 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import FileTree from './components/FileTree.vue';
66
import ConfigPanel from './components/ConfigPanel.vue';
77
import Toolbar from './components/Toolbar.vue';
88
import { generatePrompt, copyToClipboard, filesToTree, fileToNode, type FileNode } from './utils/promptGenerator';
9+
import { generateCursorRules } from './utils/cursorRulesGenerator';
910
1011
// 状态
1112
const sourceCode = ref('');
1213
const generatedPrompt = ref('');
13-
const selectedLanguage = ref('javascript');
14+
const generatedCursorRules = ref('');
15+
const selectedLanguage = ref('python');
1416
const projectFiles = ref<FileNode[]>([]);
1517
const selectedFile = ref<FileNode | null>(null);
1618
const showConfigModal = ref(false);
@@ -34,6 +36,7 @@ const config = reactive({
3436
'readability'
3537
],
3638
language_specific_techniques: true,
39+
framework: '',
3740
preserve_functionality: true,
3841
add_easter_eggs: true,
3942
add_comments: true,
@@ -47,7 +50,7 @@ const config = reactive({
4750
}
4851
});
4952
50-
// 自动更新生成的 prompt
53+
// 自动更新生成的 prompt 和 cursorrules
5154
const updatePrompt = () => {
5255
if (sourceCode.value.trim().length > 0) {
5356
const prompt = generatePrompt(
@@ -57,6 +60,13 @@ const updatePrompt = () => {
5760
projectFiles.value.length > 0 ? projectFiles.value : undefined
5861
);
5962
generatedPrompt.value = prompt;
63+
64+
// 生成 .cursorrules 文件内容
65+
const cursorRules = generateCursorRules(
66+
selectedLanguage.value,
67+
config
68+
);
69+
generatedCursorRules.value = cursorRules;
6070
}
6171
};
6272
@@ -224,10 +234,9 @@ const closeConfigModal = () => {
224234
@open-config="showConfigModal = true"
225235
/>
226236

227-
<!-- 主内容区域 -->
228237
<div class="main-content">
229238
<!-- 侧边栏 -->
230-
<div class="sidebar" v-if="hasSidebar">
239+
<div v-if="hasSidebar" class="sidebar">
231240
<div class="sidebar-header">
232241
<h3>项目文件</h3>
233242
<button class="sidebar-toggle" @click="toggleSidebar" title="隐藏侧边栏">
@@ -251,21 +260,54 @@ const closeConfigModal = () => {
251260
<span>▶</span>
252261
</button>
253262

254-
<!-- 编辑器区域 -->
255-
<div class="editors" :class="{ 'with-sidebar': hasSidebar }">
256-
<div class="editor-container">
263+
<!-- 内容区域 -->
264+
<div class="content-area" :class="{ 'with-sidebar': hasSidebar }">
265+
<!-- 编辑器部分 -->
266+
<div class="editor-section">
267+
<div class="section-header">
268+
<h3>源代码</h3>
269+
<div class="language-selector">
270+
<label for="language-select">语言:</label>
271+
<select
272+
id="language-select"
273+
v-model="selectedLanguage"
274+
@change="updatePrompt"
275+
>
276+
<option value="javascript">JavaScript</option>
277+
<option value="typescript">TypeScript</option>
278+
<option value="python">Python</option>
279+
<option value="java">Java</option>
280+
<option value="csharp">C#</option>
281+
<option value="cpp">C++</option>
282+
<option value="go">Go</option>
283+
<option value="rust">Rust</option>
284+
<option value="php">PHP</option>
285+
<option value="ruby">Ruby</option>
286+
<option value="swift">Swift</option>
287+
<option value="kotlin">Kotlin</option>
288+
<option value="scala">Scala</option>
289+
<option value="html">HTML</option>
290+
<option value="css">CSS</option>
291+
<option value="sql">SQL</option>
292+
</select>
293+
</div>
294+
</div>
257295
<CodeEditor
258296
v-model="sourceCode"
259-
:language="selectedLanguage"
260-
:showUpload="true"
261-
title="源代码"
297+
:language="selectedLanguage"
298+
:show-upload="true"
262299
@file-upload="handleFileUpload"
263300
/>
264301
</div>
265-
<div class="editor-container">
302+
303+
<!-- 预览部分 -->
304+
<div class="preview-section">
305+
<div class="section-header">
306+
<h3>生成的提示</h3>
307+
</div>
266308
<MarkdownPreview
267309
v-model="generatedPrompt"
268-
title="生成的提示"
310+
:cursor-rules="generatedCursorRules"
269311
/>
270312
</div>
271313
</div>
@@ -303,7 +345,9 @@ html, body {
303345
width: 100%;
304346
overflow: hidden;
305347
}
348+
</style>
306349

350+
<style scoped>
307351
.app {
308352
display: flex;
309353
flex-direction: column;
@@ -322,42 +366,36 @@ html, body {
322366
display: flex;
323367
flex: 1;
324368
overflow: hidden;
325-
width: 100%;
326-
height: calc(100vh - 60px);
327-
position: relative;
328369
}
329370
330371
.sidebar {
331372
width: 250px;
332-
min-width: 200px;
333-
overflow: hidden;
373+
background-color: #252526;
334374
border-right: 1px solid #333;
335375
background-color: #1e1e1e;
336376
height: 100%;
337377
display: flex;
338378
flex-direction: column;
339-
transition: width 0.3s ease;
379+
overflow: hidden;
340380
}
341381
342382
.sidebar-header {
343383
display: flex;
344384
justify-content: space-between;
345385
align-items: center;
346-
padding: 10px 16px;
347-
background-color: #2a2a2a;
386+
padding: 10px;
348387
border-bottom: 1px solid #333;
349388
}
350389
351390
.sidebar-header h3 {
352391
margin: 0;
353392
font-size: 16px;
354-
font-weight: 500;
355393
}
356394
357395
.sidebar-toggle {
358396
background: none;
359397
border: none;
360-
color: #888;
398+
color: #e0e0e0;
361399
cursor: pointer;
362400
font-size: 14px;
363401
padding: 4px;
@@ -378,60 +416,66 @@ html, body {
378416
left: 0;
379417
top: 50%;
380418
transform: translateY(-50%);
381-
background-color: #2a2a2a;
382-
border: none;
383-
border-right: 1px solid #333;
384-
color: #888;
419+
background-color: #252526;
420+
border: 1px solid #333;
421+
border-left: none;
422+
color: #e0e0e0;
423+
padding: 10px 5px;
385424
cursor: pointer;
386-
font-size: 14px;
387-
padding: 8px 4px;
425+
z-index: 10;
426+
}
427+
428+
.content-area {
429+
flex: 1;
388430
display: flex;
389-
align-items: center;
390-
justify-content: center;
391-
border-top-right-radius: 4px;
392-
border-bottom-right-radius: 4px;
393-
z-index: 5;
394-
transition: all 0.2s ease;
395-
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.2);
431+
flex-direction: column;
432+
overflow: hidden;
396433
}
397434
398-
.sidebar-show-button:hover {
399-
color: #e0e0e0;
400-
background-color: #3a3a3a;
435+
@media (min-width: 768px) {
436+
.content-area {
437+
flex-direction: row;
438+
}
439+
}
440+
441+
.content-area.with-sidebar {
442+
margin-left: 0;
401443
}
402444
403-
.editor-container {
445+
.editor-section, .preview-section {
404446
flex: 1;
405447
display: flex;
406448
flex-direction: column;
407449
overflow: hidden;
408-
padding: 16px;
409-
height: 100%;
410-
box-sizing: border-box;
450+
padding: 10px;
451+
border-bottom: 1px solid #333;
452+
}
453+
454+
@media (min-width: 768px) {
455+
.editor-section, .preview-section {
456+
border-bottom: none;
457+
}
458+
459+
.editor-section {
460+
border-right: 1px solid #333;
461+
}
411462
}
412463
413-
.editors {
464+
.section-header {
414465
display: flex;
415-
flex: 1;
416-
gap: 16px;
417-
overflow: hidden;
418-
height: 100%;
419-
width: 100%;
420-
transition: width 0.3s ease, margin-left 0.3s ease;
421-
padding-left: 0;
466+
justify-content: space-between;
467+
align-items: center;
468+
margin-bottom: 10px;
422469
}
423470
424-
.editors.with-sidebar {
425-
width: calc(100% - 250px);
471+
.section-header h3 {
472+
margin: 0;
473+
font-size: 16px;
426474
}
427475
428-
.editor-panel {
429-
flex: 1;
476+
.language-selector {
430477
display: flex;
431-
flex-direction: column;
432-
overflow: hidden;
433-
min-width: 400px;
434-
height: 100%;
478+
align-items: center;
435479
}
436480
437481
/* 弹窗样式 */
@@ -491,7 +535,7 @@ html, body {
491535
.close-button {
492536
background: none;
493537
border: none;
494-
color: #888;
538+
color: #e0e0e0;
495539
font-size: 24px;
496540
cursor: pointer;
497541
padding: 0;

src/components/ConfigPanel.vue

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@
3535
</div>
3636
</div>
3737

38+
<div class="config-section">
39+
<h4>框架</h4>
40+
<div class="config-option">
41+
<select v-model="localConfig.shitty_code_settings.framework">
42+
<option value="">无</option>
43+
<option v-for="framework in availableFrameworks" :key="framework.value" :value="framework.value">
44+
{{ framework.label }}
45+
</option>
46+
</select>
47+
</div>
48+
</div>
49+
3850
<div class="config-section">
3951
<h4>注释风格</h4>
4052
<div class="config-option">
@@ -122,6 +134,7 @@ const props = defineProps({
122134
'readability'
123135
],
124136
language_specific_techniques: true,
137+
framework: '',
125138
preserve_functionality: true,
126139
add_easter_eggs: true,
127140
add_comments: true,
@@ -159,6 +172,23 @@ const availableTechniques = [
159172
{ label: '性能', value: 'performance' },
160173
{ label: '可读性', value: 'readability' }
161174
];
175+
176+
const availableFrameworks = [
177+
{ label: 'Angular', value: 'angular' },
178+
{ label: 'ASP.NET Core', value: 'asp.net core' },
179+
{ label: 'Django', value: 'django' },
180+
{ label: 'Express', value: 'express' },
181+
{ label: 'FastAPI', value: 'fastapi' },
182+
{ label: 'Flask', value: 'flask' },
183+
{ label: 'Laravel', value: 'laravel' },
184+
{ label: 'NestJS', value: 'nestjs' },
185+
{ label: 'Next.js', value: 'next.js' },
186+
{ label: 'React', value: 'react' },
187+
{ label: 'Ruby on Rails', value: 'ruby on rails' },
188+
{ label: 'Spring Boot', value: 'spring boot' },
189+
{ label: 'Svelte/SvelteKit', value: 'svelte' },
190+
{ label: 'Vue.js', value: 'vue.js' }
191+
];
162192
</script>
163193

164194
<style scoped>

0 commit comments

Comments
 (0)