Skip to content

Commit 3676935

Browse files
committed
feat: jump to the flake just edited
1 parent 45bb330 commit 3676935

9 files changed

Lines changed: 82 additions & 23 deletions

File tree

README.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
An Obsidian plugin to put small notes / stickies / cards in a dedicated file, and manage them in masonry layout.
44

5-
A "flake" means a small piece of note, and a "flakepile" is a pile of those flakes.
5+
A "flake" refers to a small piece of note, and a "flakepile" is a pile of those flakes.
66

7-
Can be used to store ideas, diaries, code snippets, and more.
7+
Can be used to collect ideas, diaries, code snippets, and more.
88

99
*The preview image is in horizontal layout. You can change this to vertical layout.*
1010

@@ -20,7 +20,9 @@ I don't want 100 `.md` files with 1 sentence each.
2020

2121
## Installation
2222

23-
The plugin is not published as Obsidian's community plugin yet. Please use [BRAT](https://github.com/TfTHacker/obsidian42-brat) to install the plugin, or copy the files under the release tag to the plugin folder of your Obsidian application. You can also [build it from source](#build-from-source).
23+
The plugin is not published as Obsidian's community plugin [yet](https://github.com/obsidianmd/obsidian-releases/pull/9533).
24+
25+
Please use [BRAT](https://github.com/TfTHacker/obsidian42-brat) to install the plugin, or copy the files under the release tag to the plugin folder of your Obsidian application. You can also [build it from source](#build-from-source).
2426

2527
## Tech Stack
2628

@@ -57,10 +59,10 @@ Inside a flakepile:
5759

5860
Obsidian-wise:
5961

60-
- [x] "Create new flakepile" file menu option
62+
- [x] "New flakepile" command & file menu option.
6163
- [x] "Flake count" status bar item [1]
6264
- Limited support to internal plugins
63-
- [x] Preview other markdown file
65+
- [x] Preview other markdown files via `[[file link]]`
6466
- [x] Jump to global search when clicking on a tag
6567

6668
[1] Due to the nature of this plugin, other status bar items are hidden in flakepile view. Please let me know if you think some status bar item should be displayed.
@@ -103,6 +105,10 @@ npm run build // Build for production
103105

104106
WHen running `npm run build`, the output files will be copied to `dist` folder.
105107

108+
## Changelog
109+
110+
[Changelog for pre-1.0 versions](docs/changelog_pre1.0.md)
111+
106112
## License
107113

108114
MIT © i'DLisT 2026

docs/changelog_pre1.0.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Changelog (pre 1.0)
2+
3+
## 0.1.4
4+
5+
- When finish editing, jump to the flake just edited when finish editing (so that the flake is still trackable when reflow happens).
6+
- Adjusted the style of lists in rendered markdown. Disabled the toggling behavior of task items (`- []`) as it is not meant to be live editable.
7+
- Added "New flakepile" command to command palette. (#1)

src/app.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ export class FlakepileApp extends TextFileView {
120120
hydrateMarkdown(rendered: HTMLElement) {
121121
const sourcePath = this.file!.path
122122

123+
// Disable input of task item checkbox.
124+
const taskItemChechboxes = rendered.querySelectorAll('.task-list-item>input')
125+
126+
taskItemChechboxes.forEach((element) => {
127+
element.setAttrs({ disabled: true })
128+
})
129+
123130
// Support internal links.
124131
rendered.on('click', 'a.internal-link', (e, target) => {
125132
const linktext = target.getAttribute('data-href')

src/globals.scss

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,22 @@
5959
.fp-markdown {
6060

6161
p,
62-
pre {
62+
pre,
63+
ul,
64+
ol {
6365
margin: 0.5rem 0;
6466
}
6567

68+
ul,
69+
ol {
70+
padding-inline-start: 2rem;
71+
}
72+
73+
li.task-list-item>input {
74+
vertical-align: middle;
75+
transform: translateY(-2px);
76+
}
77+
6678
h1,
6779
h2,
6880
h3,

src/main.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,23 @@ export default class Flakepiles extends Plugin {
2222

2323
menu.addItem((item) => {
2424
item
25-
.setTitle('Create new flakepile')
25+
.setTitle('New flakepile')
2626
.setIcon('sticker')
2727
.onClick(async () => {
2828
await this.createFlakepileFile(file)
2929
})
3030
})
3131
}))
3232

33+
// Register "New flakepile" command.
34+
this.addCommand({
35+
id: 'new',
36+
name: 'Create a new flakepile',
37+
callback: async () => {
38+
await this.createFlakepileFile()
39+
},
40+
})
41+
3342
// Register status bar item.
3443
this.flakeCount = this.addStatusBarItem()
3544

src/utils.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@ export const useElementBorderSize = (target: MaybeComputedElementRef) => {
2626
return useElementSize(target, { width: 0, height: 0 }, { box: 'border-box' })
2727
}
2828

29-
export const noopAsync = async () => {
30-
await new Promise<void>((resolve) => resolve())
31-
}
29+
export const noopAsync = async () => await Promise.resolve()
3230

3331
export class CausedError<T> extends Error {
3432
cause: string

src/vue/FlakeView.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ watchEffect(async () => {
130130
})
131131
132132
const height = computed(() => {
133-
return 2 // Slightly larger than border size
133+
return 2 // Slightly larger than the border size
134134
+ nameSize.height.value
135135
+ contentHeight.value
136136
+ footerSize.height.value

src/vue/FlakepileView.vue

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type { FileRef, PileActions, PileRef } from '@/app'
88
import { ObIcon, ObSearch } from '@/components'
99
import { useCssIf, useCssWith } from '@/utils'
1010
import { searchFlakes, sortFlakes } from './flake-filters'
11+
import type { MasonryOptions } from './masonry-common'
1112
1213
import MenuButton from './MenuButton.vue'
1314
import MasonryUnified from './MasonryUnified.vue'
@@ -77,6 +78,18 @@ const scrollY = computed(() => {
7778
return canvasBounding.top.value - masonryBounding.top.value
7879
})
7980
81+
const masonryOptions = computed<MasonryOptions>(() => {
82+
return {
83+
width: pile.value.width,
84+
elasticWidth: pile.value.elasticWidth,
85+
enableMaxHeight: pile.value.enableMaxHeight,
86+
maxHeight: pile.value.maxHeight,
87+
elasticHeight: pile.value.elasticHeight,
88+
canvasWidth: canvasSize.width.value,
89+
canvasHeight: canvasSize.height.value,
90+
}
91+
})
92+
8093
type MenuState = 'shrink' | 'normal' | 'expand'
8194
8295
const menuState = ref<MenuState>('normal')
@@ -263,7 +276,7 @@ const cssNoLabel = useCssIf(isViewportSmall, '-nolabel')
263276
<MenuButton ref="el-size-options-button"
264277
class="fp-btn-icon-label"
265278
icon="scaling"
266-
label="Size Options"
279+
label="Size options"
267280
@click="showSizeOptions = !showSizeOptions" />
268281
</template>
269282
</div>
@@ -283,15 +296,7 @@ const cssNoLabel = useCssIf(isViewportSmall, '-nolabel')
283296
:flow="adaptiveFlow"
284297
:scroll-x="scrollX"
285298
:scroll-y="scrollY"
286-
:options="{
287-
width: pile.width,
288-
elasticWidth: pile.elasticWidth,
289-
enableMaxHeight: pile.enableMaxHeight,
290-
maxHeight: pile.maxHeight,
291-
elasticHeight: pile.elasticHeight,
292-
canvasWidth: canvasSize.width.value,
293-
canvasHeight: canvasSize.height.value,
294-
}" />
299+
:options="masonryOptions" />
295300
</div>
296301
</div>
297302
</div>

src/vue/MasonryUnified.vue

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import { computed, inject, reactive, ref, shallowRef, useTemplateRef, watch, type StyleValue } from 'vue'
2+
import { computed, inject, nextTick, reactive, ref, shallowRef, useTemplateRef, watch, type StyleValue } from 'vue'
33
import { until, useThrottleFn } from '@vueuse/core'
44
import type { EditingRef, Flake, PileAdaptiveFlow } from '@/data'
55
import { PAD_Y, type MasonryOptions, type ResolvedMasonry, type ResolvedRect, type ResolvedMasonrySize, getUnsetWidth as getFlakeWidth } from './masonry-common'
@@ -22,7 +22,6 @@ const props = withDefaults(defineProps<{
2222
})
2323
2424
const masonryRef = useTemplateRef('el-masonry')
25-
// const flakeIds = computed(() => new Set(props.flakes.map((f) => f.id)))
2625
2726
const editing = inject('editing') as EditingRef
2827
const editingHeightCache = ref<number>(0)
@@ -32,8 +31,13 @@ const onEditBegin = (id: string) => {
3231
editingHeightCache.value = 0
3332
}
3433
34+
const lastEdited = ref<string | null>(null)
35+
3536
const onEditFinish = () => {
37+
lastEdited.value = editing.value
3638
editing.value = null
39+
40+
resolveMasonryThrottled()
3741
}
3842
3943
const heightMap = reactive<Map<string, number>>(new Map())
@@ -200,6 +204,16 @@ const resolveMasonry = () => {
200204
)
201205
updateStyles(styles)
202206
}
207+
208+
tryScrollToLastEdited()
209+
}
210+
211+
const tryScrollToLastEdited = async () => {
212+
if (!lastEdited.value) return
213+
214+
await nextTick()
215+
requestScroll(lastEdited.value)
216+
lastEdited.value = null
203217
}
204218
205219
const resolveMasonryThrottled = useThrottleFn(resolveMasonry, 10, true)
@@ -217,6 +231,7 @@ watch(() => props.id, () => {
217231
218232
watch([
219233
() => props.flow,
234+
() => props.flakes,
220235
() => props.options,
221236
heightMap,
222237
], () => {

0 commit comments

Comments
 (0)