Compare commits
2 Commits
41d6cf0dac
...
141ceab7e6
| Author | SHA1 | Date | |
|---|---|---|---|
| 141ceab7e6 | |||
| d03f9668ad |
@@ -18,8 +18,8 @@ var allowedExtensions = map[string]bool{
|
||||
}
|
||||
|
||||
var extensionToMIMEPrefix = map[string]string{
|
||||
".jpg": "image/", ".jpeg": "image/", ".png": "image/png", ".gif": "image/gif", ".webp": "image/webp",
|
||||
".mp4": "video/", ".webm": "video/webm", ".mp3": "audio/", ".ogg": "audio/",
|
||||
".jpg": "image/", ".jpeg": "image/", ".png": "image/", ".gif": "image/", ".webp": "image/",
|
||||
".mp4": "video/", ".webm": "video/",
|
||||
".pdf": "application/pdf", ".txt": "text/",
|
||||
}
|
||||
|
||||
@@ -49,8 +49,12 @@ func (store *Store) UploadMessageFile(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
buf := make([]byte, 512)
|
||||
n, _ := f.Read(buf)
|
||||
n, err := f.Read(buf)
|
||||
f.Close()
|
||||
if err != nil && n == 0 {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": "failed to read file content"})
|
||||
return
|
||||
}
|
||||
detectedType := http.DetectContentType(buf[:n])
|
||||
|
||||
expectedPrefix, ok := extensionToMIMEPrefix[ext]
|
||||
|
||||
@@ -5,21 +5,31 @@ const container = useTemplateRef("container");
|
||||
const item1 = useTemplateRef("item1");
|
||||
|
||||
let offset = 0;
|
||||
let cachedWidth = 0;
|
||||
|
||||
let rafId;
|
||||
|
||||
const speed = 0.5; // pixels per frame
|
||||
|
||||
function animate() {
|
||||
function measureWidth() {
|
||||
const ctnr = container.value;
|
||||
const it1 = item1.value;
|
||||
if (ctnr && it1) {
|
||||
cachedWidth = Math.max(ctnr.offsetWidth, it1.scrollWidth);
|
||||
}
|
||||
}
|
||||
|
||||
const width = Math.max(ctnr.offsetWidth, it1.scrollWidth);
|
||||
function animate() {
|
||||
const ctnr = container.value;
|
||||
if (!ctnr || cachedWidth === 0) {
|
||||
rafId = requestAnimationFrame(animate);
|
||||
return;
|
||||
}
|
||||
|
||||
offset -= speed;
|
||||
|
||||
if (offset <= -width) {
|
||||
offset += width;
|
||||
if (offset <= -cachedWidth) {
|
||||
offset += cachedWidth;
|
||||
}
|
||||
|
||||
ctnr.style.transform = `translateX(${offset}px)`;
|
||||
@@ -27,12 +37,19 @@ function animate() {
|
||||
rafId = requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
let resizeObserver;
|
||||
|
||||
onMounted(() => {
|
||||
measureWidth();
|
||||
rafId = requestAnimationFrame(animate);
|
||||
|
||||
resizeObserver = new ResizeObserver(measureWidth);
|
||||
resizeObserver.observe(container.value);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
cancelAnimationFrame(rafId);
|
||||
resizeObserver?.disconnect();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -16,6 +16,12 @@ let pos = 0;
|
||||
let direction = 1; // 1 = down, -1 = up
|
||||
let timeoutId;
|
||||
let timeoutId2;
|
||||
let cachedScrollHeight = 0;
|
||||
|
||||
function measureScrollHeight() {
|
||||
const el = container.value;
|
||||
if (el) cachedScrollHeight = el.scrollHeight;
|
||||
}
|
||||
|
||||
function handleHover() {
|
||||
cancelAnimationFrame(timeoutId);
|
||||
@@ -28,6 +34,10 @@ function handleHover() {
|
||||
|
||||
function tick() {
|
||||
const el = container.value;
|
||||
if (!el || cachedScrollHeight === 0) {
|
||||
timeoutId = requestAnimationFrame(tick);
|
||||
return;
|
||||
}
|
||||
|
||||
const reachedBottom = pos <= 0;
|
||||
const reachedTop = pos >= 1;
|
||||
@@ -46,16 +56,23 @@ function tick() {
|
||||
|
||||
pos += direction * SPEED;
|
||||
|
||||
el.scrollTop = pos * el.scrollHeight;
|
||||
el.scrollTop = pos * cachedScrollHeight;
|
||||
|
||||
timeoutId = requestAnimationFrame(tick);
|
||||
}
|
||||
|
||||
let resizeObserver;
|
||||
|
||||
onMounted(() => {
|
||||
measureScrollHeight();
|
||||
timeoutId = requestAnimationFrame(tick);
|
||||
|
||||
resizeObserver = new ResizeObserver(measureScrollHeight);
|
||||
resizeObserver.observe(container.value);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
cancelAnimationFrame(timeoutId);
|
||||
resizeObserver?.disconnect();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -23,49 +23,83 @@ const phrases = [
|
||||
"I like anime, all kinds of music and sci fic",
|
||||
];
|
||||
|
||||
const items = ref<Item[]>(
|
||||
phrases.map((text, i) => ({
|
||||
// Non-reactive animation state to avoid triggering Vue re-renders every frame
|
||||
const animState = phrases.map((text, i) => ({
|
||||
x: i * 20,
|
||||
y: i * 20,
|
||||
dx: rand(0, 30) / 100,
|
||||
dy: 0.5,
|
||||
content: text,
|
||||
cachedW: 0,
|
||||
cachedH: 0,
|
||||
}));
|
||||
|
||||
// Reactive items only for initial render
|
||||
const items = ref<Item[]>(
|
||||
animState.map((s) => ({
|
||||
x: s.x,
|
||||
y: s.y,
|
||||
dx: s.dx,
|
||||
dy: s.dy,
|
||||
content: s.content,
|
||||
})),
|
||||
);
|
||||
|
||||
let rafId = 0;
|
||||
let cachedCW = 0;
|
||||
let cachedCH = 0;
|
||||
|
||||
function measureSizes() {
|
||||
const c = container.value;
|
||||
if (c) {
|
||||
cachedCW = c.clientWidth;
|
||||
cachedCH = c.clientHeight;
|
||||
}
|
||||
itemEls.value.forEach((el, i) => {
|
||||
if (el && animState[i]) {
|
||||
animState[i].cachedW = el.offsetWidth;
|
||||
animState[i].cachedH = el.offsetHeight;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function animate() {
|
||||
const c = container.value;
|
||||
if (!c) return;
|
||||
if (!cachedCW || !cachedCH) {
|
||||
rafId = requestAnimationFrame(animate);
|
||||
return;
|
||||
}
|
||||
|
||||
const cw = c.clientWidth;
|
||||
const ch = c.clientHeight;
|
||||
|
||||
items.value.forEach((item, i) => {
|
||||
for (let i = 0; i < animState.length; i++) {
|
||||
const s = animState[i];
|
||||
const el = itemEls.value[i];
|
||||
if (!el) return;
|
||||
if (!el) continue;
|
||||
|
||||
const ew = el.offsetWidth;
|
||||
const eh = el.offsetHeight;
|
||||
s.x += s.dx;
|
||||
s.y += s.dy;
|
||||
|
||||
item.x += item.dx;
|
||||
item.y += item.dy;
|
||||
if (s.x < 0 || s.x > cachedCW - s.cachedW) s.dx *= -1;
|
||||
if (s.y < 0 || s.y > cachedCH - s.cachedH) s.dy *= -1;
|
||||
|
||||
if (item.x < 0 || item.x > cw - ew) item.dx *= -1;
|
||||
if (item.y < 0 || item.y > ch - eh) item.dy *= -1;
|
||||
});
|
||||
el.style.transform = `translate(${s.x}px, ${s.y}px)`;
|
||||
}
|
||||
|
||||
rafId = requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
let resizeObserver: ResizeObserver;
|
||||
|
||||
onMounted(async () => {
|
||||
await nextTick();
|
||||
measureSizes();
|
||||
rafId = requestAnimationFrame(animate);
|
||||
|
||||
resizeObserver = new ResizeObserver(measureSizes);
|
||||
resizeObserver.observe(container.value!);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
cancelAnimationFrame(rafId);
|
||||
resizeObserver?.disconnect();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -79,9 +113,6 @@ onUnmounted(() => {
|
||||
:key="i"
|
||||
ref="itemEls"
|
||||
class="absolute w-fit h-fit"
|
||||
:style="{
|
||||
transform: `translate(${item.x}px, ${item.y}px)`,
|
||||
}"
|
||||
>
|
||||
<h1>
|
||||
{{ item.content }}
|
||||
|
||||
Reference in New Issue
Block a user